siddhartharya commited on
Commit
bd877a9
·
verified ·
1 Parent(s): 4a2f000

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -93
app.py CHANGED
@@ -1,7 +1,7 @@
1
  import gradio as gr
2
  import requests
3
  import os
4
- from bs4 import BeautifulSoup # Add BeautifulSoup for scraping
5
 
6
  # Load API keys securely from environment variables
7
  proxycurl_api_key = os.getenv("PROXYCURL_API_KEY") # Proxycurl API key
@@ -23,15 +23,17 @@ class EmailAgent:
23
  self.company_info = None
24
  self.role_description = None
25
 
26
- # Reason: Decide what information is needed
27
  def reason_about_data(self):
28
- print("Reasoning: I need LinkedIn data, company info, and role description.")
29
  if not self.linkedin_url:
30
- print("Warning: LinkedIn URL missing. Will proceed with default bio.")
31
  if not self.company_name:
32
- print("Warning: Company name missing. Will proceed with default company info.")
33
-
34
- # Action: Fetch LinkedIn data via Proxycurl
 
 
35
  def fetch_linkedin_data(self):
36
  if not self.linkedin_url:
37
  print("Action: No LinkedIn URL provided, using default bio.")
@@ -39,10 +41,8 @@ class EmailAgent:
39
  self.skills = ["Adaptable", "Hardworking"]
40
  self.experiences = ["Worked across various industries"]
41
  else:
42
- print("Action: Fetching LinkedIn data from Proxycurl.")
43
- headers = {
44
- "Authorization": f"Bearer {proxycurl_api_key}",
45
- }
46
  url = f"https://nubela.co/proxycurl/api/v2/linkedin?url={self.linkedin_url}"
47
  response = requests.get(url, headers=headers)
48
  if response.status_code == 200:
@@ -55,17 +55,15 @@ class EmailAgent:
55
  self.bio = "A professional with diverse experience."
56
  self.skills = ["Adaptable", "Hardworking"]
57
  self.experiences = ["Worked across various industries"]
58
-
59
- # Action: Fetch company information via Proxycurl
60
  def fetch_company_info(self):
61
  if not self.company_name:
62
  print("Action: No company name provided, using default company info.")
63
  self.company_info = "A leading company in its field, offering innovative solutions."
64
  else:
65
  print(f"Action: Fetching company info for {self.company_name}.")
66
- headers = {
67
- "Authorization": f"Bearer {proxycurl_api_key}",
68
- }
69
  url = f"https://nubela.co/proxycurl/api/v2/linkedin/company?company_name={self.company_name}"
70
  response = requests.get(url, headers=headers)
71
  if response.status_code == 200:
@@ -75,24 +73,22 @@ class EmailAgent:
75
  print(f"Error: Unable to fetch company info for {self.company_name}. Using default info.")
76
  self.company_info = "A leading company in its field, offering innovative solutions."
77
 
78
- # Action: Scrape the company's website for role-specific information
79
  def scrape_role_from_website(self):
80
  print(f"Action: Scraping role description from the company's website for {self.role}.")
81
  if not self.company_name:
82
  print("Error: No company name or URL provided for scraping.")
83
  return False
84
 
85
- # Attempt to scrape the company's website
86
  try:
87
  response = requests.get(f"https://{self.company_name}.com/careers")
88
  if response.status_code == 200:
89
  soup = BeautifulSoup(response.text, 'html.parser')
90
- # Look for any sections that might contain role descriptions
91
  role_descriptions = soup.find_all(string=lambda text: self.role.lower() in text.lower())
92
  if role_descriptions:
93
- # If we find relevant role descriptions, use the first match
94
  self.role_description = role_descriptions[0]
95
- print(f"Found role description on company's website: {self.role_description}")
96
  return True
97
  else:
98
  print(f"No specific role description found on the website for {self.role}.")
@@ -104,20 +100,19 @@ class EmailAgent:
104
  print(f"Error during scraping: {e}")
105
  return False
106
 
107
- # Action: Use default logic to infer role description if scraping fails
108
  def use_default_role_description(self):
109
  print(f"Action: Using default logic for the role of {self.role}.")
110
- self.role_description = f"The role of {self.role} at {self.company_name} involves mentoring AI and technology students to develop their skills and progress their careers."
111
 
112
- # Reflection: Check if the data is sufficient to generate an email
113
  def reflect_on_data(self):
114
- print("Reflection: Do I have enough data to generate the email?")
115
- # Allow the email to be generated with default values if data is missing
116
  if not self.bio or not self.skills or not self.company_info:
117
  print("Warning: Some critical information is missing. Proceeding with default values.")
118
  return True
119
-
120
- # Action: Generate the email using Groq Cloud LLM
121
  def generate_email(self):
122
  print("Action: Generating the email with the gathered information.")
123
  prompt = f"""
@@ -126,7 +121,7 @@ class EmailAgent:
126
 
127
  Focus on relevant skills and experiences from LinkedIn, such as {', '.join(self.skills)},
128
  that directly align with the role of {self.role}.
129
- Highlight only the skills and experiences that relate to mentoring, AI, technology, and leadership.
130
 
131
  The company info is: {self.company_info}.
132
  The role involves: {self.role_description}.
@@ -142,70 +137,8 @@ class EmailAgent:
142
  """
143
 
144
  url = "https://api.groq.com/openai/v1/chat/completions"
145
- headers = {
146
- "Authorization": f"Bearer {groq_api_key}",
147
- "Content-Type": "application/json",
148
- }
149
 
150
  data = {
151
  "messages": [{"role": "user", "content": prompt}],
152
- "model": "llama3-8b-8192"
153
- }
154
-
155
- response = requests.post(url, headers=headers, json=data)
156
- if response.status_code == 200:
157
- return response.json()["choices"][0]["message"]["content"].strip()
158
- else:
159
- print(f"Error: {response.status_code}, {response.text}")
160
- return "Error generating email. Please check your API key or try again later."
161
-
162
- # Main loop following ReAct pattern
163
- def run(self):
164
- self.reason_about_data() # Reason
165
- self.fetch_linkedin_data() # Action
166
- self.fetch_company_info() # Action
167
- # Try to scrape the company's website for role-specific information
168
- if not self.scrape_role_from_website():
169
- self.use_default_role_description() # Use default logic if scraping fails
170
- if self.reflect_on_data(): # Reflection
171
- return self.generate_email() # Final Action
172
- else:
173
- return "Error: Not enough data to generate the email."
174
-
175
- # Define the Gradio interface and the main app logic
176
- def gradio_ui():
177
- # Input fields
178
- name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
179
- company_input = gr.Textbox(label="Company Name or URL", placeholder="Enter the company name or website URL")
180
- role_input = gr.Textbox(label="Role Applying For", placeholder="Enter the role you are applying for")
181
- email_input = gr.Textbox(label="Your Email Address", placeholder="Enter your email address")
182
- phone_input = gr.Textbox(label="Your Phone Number", placeholder="Enter your phone number")
183
- linkedin_input = gr.Textbox(label="Your LinkedIn URL", placeholder="Enter your LinkedIn profile URL")
184
- word_limit_slider = gr.Slider(minimum=50, maximum=300, step=10, label="Email Word Limit", value=150) # New slider for word limit
185
-
186
- # Output field
187
- email_output = gr.Textbox(label="Generated Email", placeholder="Your generated email will appear here", lines=10)
188
-
189
- # Function to create and run the email agent
190
- def create_email(name, company_name, role, email, phone, linkedin_url, word_limit):
191
- agent = EmailAgent(linkedin_url, company_name, role, word_limit, name, email, phone, linkedin_url)
192
- return agent.run()
193
-
194
- # Gradio interface
195
- demo = gr.Interface(
196
- fn=create_email,
197
- inputs=[name_input, company_input, role_input, email_input, phone_input, linkedin_input, word_limit_slider],
198
- outputs=[email_output],
199
- title="Email Writing AI Agent with ReAct",
200
- description="Generate a professional email for a job application using LinkedIn data, company info, and role description.",
201
- allow_flagging="never"
202
- )
203
-
204
- # Launch the Gradio app
205
- demo.launch()
206
-
207
- # Start the Gradio app when running the script
208
- if __name__ == "__main__":
209
- gradio_ui()
210
-
211
-
 
1
  import gradio as gr
2
  import requests
3
  import os
4
+ from bs4 import BeautifulSoup # For scraping company and role info
5
 
6
  # Load API keys securely from environment variables
7
  proxycurl_api_key = os.getenv("PROXYCURL_API_KEY") # Proxycurl API key
 
23
  self.company_info = None
24
  self.role_description = None
25
 
26
+ # Reason: Decide what information is needed and if we need to take additional steps
27
  def reason_about_data(self):
28
+ print("Reasoning: Deciding what data we need...")
29
  if not self.linkedin_url:
30
+ print("Warning: LinkedIn URL missing. Proceeding with default bio.")
31
  if not self.company_name:
32
+ print("Warning: Company name missing. Proceeding with default company info.")
33
+ if not self.role:
34
+ print("Warning: Role missing. We will use general logic for the role.")
35
+
36
+ # Action: Fetch LinkedIn data via Proxycurl (acting based on reasoning)
37
  def fetch_linkedin_data(self):
38
  if not self.linkedin_url:
39
  print("Action: No LinkedIn URL provided, using default bio.")
 
41
  self.skills = ["Adaptable", "Hardworking"]
42
  self.experiences = ["Worked across various industries"]
43
  else:
44
+ print("Action: Fetching LinkedIn data via Proxycurl.")
45
+ headers = {"Authorization": f"Bearer {proxycurl_api_key}"}
 
 
46
  url = f"https://nubela.co/proxycurl/api/v2/linkedin?url={self.linkedin_url}"
47
  response = requests.get(url, headers=headers)
48
  if response.status_code == 200:
 
55
  self.bio = "A professional with diverse experience."
56
  self.skills = ["Adaptable", "Hardworking"]
57
  self.experiences = ["Worked across various industries"]
58
+
59
+ # Action: Fetch company information via Proxycurl or use defaults
60
  def fetch_company_info(self):
61
  if not self.company_name:
62
  print("Action: No company name provided, using default company info.")
63
  self.company_info = "A leading company in its field, offering innovative solutions."
64
  else:
65
  print(f"Action: Fetching company info for {self.company_name}.")
66
+ headers = {"Authorization": f"Bearer {proxycurl_api_key}"}
 
 
67
  url = f"https://nubela.co/proxycurl/api/v2/linkedin/company?company_name={self.company_name}"
68
  response = requests.get(url, headers=headers)
69
  if response.status_code == 200:
 
73
  print(f"Error: Unable to fetch company info for {self.company_name}. Using default info.")
74
  self.company_info = "A leading company in its field, offering innovative solutions."
75
 
76
+ # Action: Scrape the company's website for role-specific information or use defaults
77
  def scrape_role_from_website(self):
78
  print(f"Action: Scraping role description from the company's website for {self.role}.")
79
  if not self.company_name:
80
  print("Error: No company name or URL provided for scraping.")
81
  return False
82
 
83
+ # Try scraping the website for role descriptions
84
  try:
85
  response = requests.get(f"https://{self.company_name}.com/careers")
86
  if response.status_code == 200:
87
  soup = BeautifulSoup(response.text, 'html.parser')
 
88
  role_descriptions = soup.find_all(string=lambda text: self.role.lower() in text.lower())
89
  if role_descriptions:
 
90
  self.role_description = role_descriptions[0]
91
+ print(f"Found role description: {self.role_description}")
92
  return True
93
  else:
94
  print(f"No specific role description found on the website for {self.role}.")
 
100
  print(f"Error during scraping: {e}")
101
  return False
102
 
103
+ # Action: Use default logic for role description if no role is available
104
  def use_default_role_description(self):
105
  print(f"Action: Using default logic for the role of {self.role}.")
106
+ self.role_description = f"The role of {self.role} at {self.company_name} involves mentoring and leading teams in innovative technology solutions."
107
 
108
+ # Reflection: Check if we have enough data to generate the email
109
  def reflect_on_data(self):
110
+ print("Reflection: Do we have enough data?")
 
111
  if not self.bio or not self.skills or not self.company_info:
112
  print("Warning: Some critical information is missing. Proceeding with default values.")
113
  return True
114
+
115
+ # Final Action: Generate the email using Groq Cloud LLM based on gathered data
116
  def generate_email(self):
117
  print("Action: Generating the email with the gathered information.")
118
  prompt = f"""
 
121
 
122
  Focus on relevant skills and experiences from LinkedIn, such as {', '.join(self.skills)},
123
  that directly align with the role of {self.role}.
124
+ Highlight only the skills and experiences that relate to leadership, mentoring, technology, and innovation.
125
 
126
  The company info is: {self.company_info}.
127
  The role involves: {self.role_description}.
 
137
  """
138
 
139
  url = "https://api.groq.com/openai/v1/chat/completions"
140
+ headers = {"Authorization": f"Bearer {groq_api_key}", "Content-Type": "application/json"}
 
 
 
141
 
142
  data = {
143
  "messages": [{"role": "user", "content": prompt}],
144
+ "model": "llama3-8b