siddhartharya commited on
Commit
8d271f0
·
verified ·
1 Parent(s): 9973a6f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -76
app.py CHANGED
@@ -1,13 +1,7 @@
1
  import gradio as gr
2
  import requests
3
  import os
4
- from openai import OpenAI
5
-
6
- # Initialize the Groq Cloud LLM client
7
- client = OpenAI(
8
- base_url="https://api.groq.com/openai/v1",
9
- api_key=os.getenv("GROQ_API_KEY") # Use your Groq Cloud API key
10
- )
11
 
12
  class AutonomousEmailAgent:
13
  def __init__(self, linkedin_url, company_name, role, word_limit, user_name, email, phone, linkedin):
@@ -24,13 +18,12 @@ class AutonomousEmailAgent:
24
  self.experiences = []
25
  self.company_info = None
26
  self.role_description = None
27
- self.company_url = None # Add company URL for scraping
28
 
29
  # Reason and Act via LLM: Let the LLM control reasoning and actions dynamically
30
  def autonomous_reasoning(self):
31
  print("Autonomous Reasoning: Letting the LLM fully reason and act on available data...")
32
 
33
- # Modify LLM reasoning prompt to ask for clear, structured instructions
34
  reasoning_prompt = f"""
35
  You are an autonomous agent responsible for generating a job application email.
36
 
@@ -52,23 +45,30 @@ class AutonomousEmailAgent:
52
  After generating the email, reflect on whether the content aligns with the role and company and whether any improvements are needed. Respond clearly with one of the above options.
53
  """
54
 
55
- # Send the reasoning prompt to the Groq Cloud LLM
56
- completion = client.chat.completions.create(
57
- model="llama3-8b-8192", # Adjust model if necessary
58
- messages=[{"role": "user", "content": reasoning_prompt}],
59
- temperature=0.5,
60
- top_p=1,
61
- max_tokens=1024,
62
- stream=True
63
- )
64
-
65
- reasoning_output = ""
66
- for chunk in completion:
67
- if chunk.choices[0].delta.content is not None:
68
- print(chunk.choices[0].delta.content, end="")
69
- reasoning_output += chunk.choices[0].delta.content
70
-
71
- return self.act_on_llm_instructions(reasoning_output)
 
 
 
 
 
 
 
72
 
73
  # Function to act on the LLM's structured instructions
74
  def act_on_llm_instructions(self, reasoning_output):
@@ -97,9 +97,8 @@ class AutonomousEmailAgent:
97
 
98
  # Fetch company URL using SERP API
99
  def fetch_company_url(self):
100
- serp_api_key = os.getenv("SERP_API_KEY") # Fetch the SERP API key from the environment
101
  print(f"Fetching company URL for {self.company_name} using SERP API...")
102
-
103
  serp_url = f"https://serpapi.com/search.json?q={self.company_name}&api_key={serp_api_key}&num=1"
104
  response = requests.get(serp_url)
105
 
@@ -112,11 +111,11 @@ class AutonomousEmailAgent:
112
  print("No URL found for the company via SERP API.")
113
  self.company_url = None
114
  else:
115
- print(f"Error fetching company URL: {response.status_code}. Retrying with fallback or alternative...")
116
 
117
  # Fetch LinkedIn data via Proxycurl
118
  def fetch_linkedin_data(self):
119
- proxycurl_api_key = os.getenv("PROXYCURL_API_KEY") # Fetch API key from environment
120
  if not self.linkedin_url:
121
  print("Action: No LinkedIn URL provided, using default bio.")
122
  self.bio = "A professional with diverse experience."
@@ -140,15 +139,11 @@ class AutonomousEmailAgent:
140
 
141
  # Fetch company information via Firecrawl API using company URL
142
  def fetch_company_info_with_firecrawl(self, company_url):
143
- firecrawl_api_key = os.getenv("FIRECRAWL_API_KEY") # Fetch the Firecrawl API key from the environment
144
  print(f"Fetching company info for {company_url} using Firecrawl.")
145
-
146
  headers = {"Authorization": f"Bearer {firecrawl_api_key}"}
147
  firecrawl_url = "https://api.firecrawl.dev/v1/scrape"
148
- data = {
149
- "url": company_url,
150
- "patterns": ["description", "about", "careers", "company overview"]
151
- }
152
 
153
  response = requests.post(firecrawl_url, json=data, headers=headers)
154
  if response.status_code == 200:
@@ -156,10 +151,10 @@ class AutonomousEmailAgent:
156
  self.company_info = firecrawl_data.get("description", "No detailed company info available.")
157
  print(f"Company info fetched: {self.company_info}")
158
  else:
159
- print(f"Error: Unable to fetch company info via Firecrawl. Retrying or using fallback...")
160
  self.company_info = "A leading company in its field."
161
 
162
- # Final Action: Generate the email using Groq Cloud LLM with "Start with Why" framework
163
  def generate_email(self):
164
  print("Action: Generating the email using Groq Cloud LLM with the gathered information.")
165
 
@@ -167,51 +162,34 @@ class AutonomousEmailAgent:
167
  Write a professional job application email applying for the {self.role} position at {self.company_name}.
168
 
169
  The email should follow the "Start with Why" approach:
170
- 1. **Why**: Begin with the candidate’s **purpose** or **belief**—why they are passionate about this role and the company. What motivates them to apply for this role? Connect their personal mission to the company's values, mission, or goals.
171
- 2. **How**: Explain how the candidate’s skills, experience, and approach align with both their "why" and the company’s mission. This should show how they are uniquely qualified to contribute to the company’s success.
172
- 3. **What**: Provide concrete examples of the candidate’s past achievements that support their qualifications for this role. These examples should demonstrate the candidate’s ability to succeed based on their skills and experience.
173
- 4. **Call to Action**: End with a polite request for a meeting or further discussion to explore how the candidate can contribute to the company's success.
174
-
175
- Use the following information to craft the email:
176
- - The candidate’s LinkedIn bio: {self.bio}.
177
- - The candidate’s most relevant skills: {', '.join(self.skills)}.
178
- - The candidate’s professional experience: {', '.join([exp['title'] for exp in self.experiences])}.
179
- - Company information: {self.company_info}.
180
- - Role description: {self.role_description}.
181
-
182
- End the email with this signature:
183
  Best regards,
184
  {self.user_name}
185
  Email: {self.email}
186
  Phone: {self.phone}
187
  LinkedIn: {self.linkedin}
188
 
189
- The email should not exceed {self.word_limit} words.
190
  """
191
 
192
- completion = client.chat.completions.create(
193
- model="llama3-8b-8192",
194
- messages=[{"role": "user", "content": prompt}],
195
- temperature=0.5,
196
- top_p=1,
197
- max_tokens=1024,
198
- stream=True
199
- )
200
-
201
- generated_email = ""
202
- for chunk in completion:
203
- if chunk.choices[0].delta.content is not None:
204
- print(chunk.choices[0].delta.content, end="")
205
- generated_email += chunk.choices[0].delta.content
206
-
207
- return generated_email
208
 
209
  # Main loop following ReAct pattern
210
  def run(self):
211
- self.fetch_linkedin_data() # Fetch LinkedIn data
212
- return self.autonomous_reasoning() # Let the LLM autonomously decide and act
213
 
214
- # Define the Gradio interface and the main app logic
215
  def gradio_ui():
216
  # Input fields
217
  name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
@@ -222,15 +200,12 @@ def gradio_ui():
222
  linkedin_input = gr.Textbox(label="Your LinkedIn URL", placeholder="Enter your LinkedIn profile URL")
223
  word_limit_slider = gr.Slider(minimum=50, maximum=300, step=10, label="Email Word Limit", value=150)
224
 
225
- # Output field
226
  email_output = gr.Textbox(label="Generated Email", placeholder="Your generated email will appear here", lines=10)
227
 
228
- # Function to create and run the email agent
229
  def create_email(name, company_name, role, email, phone, linkedin_url, word_limit):
230
  agent = AutonomousEmailAgent(linkedin_url, company_name, role, word_limit, name, email, phone, linkedin_url)
231
  return agent.run()
232
 
233
- # Gradio interface
234
  demo = gr.Interface(
235
  fn=create_email,
236
  inputs=[name_input, company_input, role_input, email_input, phone_input, linkedin_input, word_limit_slider],
@@ -240,9 +215,7 @@ def gradio_ui():
240
  allow_flagging="never"
241
  )
242
 
243
- # Launch the Gradio app
244
  demo.launch()
245
 
246
- # Start the Gradio app when running the script
247
  if __name__ == "__main__":
248
  gradio_ui()
 
1
  import gradio as gr
2
  import requests
3
  import os
4
+ import json
 
 
 
 
 
 
5
 
6
  class AutonomousEmailAgent:
7
  def __init__(self, linkedin_url, company_name, role, word_limit, user_name, email, phone, linkedin):
 
18
  self.experiences = []
19
  self.company_info = None
20
  self.role_description = None
21
+ self.company_url = None
22
 
23
  # Reason and Act via LLM: Let the LLM control reasoning and actions dynamically
24
  def autonomous_reasoning(self):
25
  print("Autonomous Reasoning: Letting the LLM fully reason and act on available data...")
26
 
 
27
  reasoning_prompt = f"""
28
  You are an autonomous agent responsible for generating a job application email.
29
 
 
45
  After generating the email, reflect on whether the content aligns with the role and company and whether any improvements are needed. Respond clearly with one of the above options.
46
  """
47
 
48
+ return self.send_request_to_llm(reasoning_prompt)
49
+
50
+ # Send request to Groq Cloud LLM
51
+ def send_request_to_llm(self, prompt):
52
+ print("Sending request to Groq Cloud LLM...")
53
+ api_key = os.getenv("GROQ_API_KEY")
54
+ headers = {
55
+ "Authorization": f"Bearer {api_key}",
56
+ "Content-Type": "application/json"
57
+ }
58
+ data = {
59
+ "model": "llama-3.1-70b-versatile", # Updated model name
60
+ "messages": [{"role": "user", "content": prompt}]
61
+ }
62
+ response = requests.post("https://api.groq.com/openai/v1/chat/completions", headers=headers, json=data)
63
+
64
+ if response.status_code == 200:
65
+ result = response.json()
66
+ content = "".join([chunk.get("choices", [{}])[0].get("delta", {}).get("content", "") for chunk in result])
67
+ print(content)
68
+ return self.act_on_llm_instructions(content)
69
+ else:
70
+ print(f"Error: Unable to connect to Groq Cloud LLM. Status Code: {response.status_code}")
71
+ return "Error: Unable to generate response."
72
 
73
  # Function to act on the LLM's structured instructions
74
  def act_on_llm_instructions(self, reasoning_output):
 
97
 
98
  # Fetch company URL using SERP API
99
  def fetch_company_url(self):
100
+ serp_api_key = os.getenv("SERP_API_KEY")
101
  print(f"Fetching company URL for {self.company_name} using SERP API...")
 
102
  serp_url = f"https://serpapi.com/search.json?q={self.company_name}&api_key={serp_api_key}&num=1"
103
  response = requests.get(serp_url)
104
 
 
111
  print("No URL found for the company via SERP API.")
112
  self.company_url = None
113
  else:
114
+ print(f"Error fetching company URL: {response.status_code}")
115
 
116
  # Fetch LinkedIn data via Proxycurl
117
  def fetch_linkedin_data(self):
118
+ proxycurl_api_key = os.getenv("PROXYCURL_API_KEY")
119
  if not self.linkedin_url:
120
  print("Action: No LinkedIn URL provided, using default bio.")
121
  self.bio = "A professional with diverse experience."
 
139
 
140
  # Fetch company information via Firecrawl API using company URL
141
  def fetch_company_info_with_firecrawl(self, company_url):
142
+ firecrawl_api_key = os.getenv("FIRECRAWL_API_KEY")
143
  print(f"Fetching company info for {company_url} using Firecrawl.")
 
144
  headers = {"Authorization": f"Bearer {firecrawl_api_key}"}
145
  firecrawl_url = "https://api.firecrawl.dev/v1/scrape"
146
+ data = {"url": company_url, "patterns": ["description", "about", "careers", "company overview"]}
 
 
 
147
 
148
  response = requests.post(firecrawl_url, json=data, headers=headers)
149
  if response.status_code == 200:
 
151
  self.company_info = firecrawl_data.get("description", "No detailed company info available.")
152
  print(f"Company info fetched: {self.company_info}")
153
  else:
154
+ print(f"Error: Unable to fetch company info via Firecrawl. Status code: {response.status_code}")
155
  self.company_info = "A leading company in its field."
156
 
157
+ # Final Action: Generate the email using Groq Cloud LLM
158
  def generate_email(self):
159
  print("Action: Generating the email using Groq Cloud LLM with the gathered information.")
160
 
 
162
  Write a professional job application email applying for the {self.role} position at {self.company_name}.
163
 
164
  The email should follow the "Start with Why" approach:
165
+ 1. **Why**: Explain why the candidate is passionate about this role and company.
166
+ 2. **How**: Highlight the candidate’s skills and experiences.
167
+ 3. **What**: Provide examples of past achievements.
168
+ 4. **Call to Action**: Request a meeting or discussion.
169
+
170
+ - LinkedIn bio: {self.bio}
171
+ - Skills: {', '.join(self.skills)}
172
+ - Experience: {', '.join([exp['title'] for exp in self.experiences])}
173
+ - Company information: {self.company_info}
174
+
175
+ Signature:
 
 
176
  Best regards,
177
  {self.user_name}
178
  Email: {self.email}
179
  Phone: {self.phone}
180
  LinkedIn: {self.linkedin}
181
 
182
+ Limit the email to {self.word_limit} words.
183
  """
184
 
185
+ return self.send_request_to_llm(prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
  # Main loop following ReAct pattern
188
  def run(self):
189
+ self.fetch_linkedin_data()
190
+ return self.autonomous_reasoning()
191
 
192
+ # Gradio UI setup remains the same
193
  def gradio_ui():
194
  # Input fields
195
  name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
 
200
  linkedin_input = gr.Textbox(label="Your LinkedIn URL", placeholder="Enter your LinkedIn profile URL")
201
  word_limit_slider = gr.Slider(minimum=50, maximum=300, step=10, label="Email Word Limit", value=150)
202
 
 
203
  email_output = gr.Textbox(label="Generated Email", placeholder="Your generated email will appear here", lines=10)
204
 
 
205
  def create_email(name, company_name, role, email, phone, linkedin_url, word_limit):
206
  agent = AutonomousEmailAgent(linkedin_url, company_name, role, word_limit, name, email, phone, linkedin_url)
207
  return agent.run()
208
 
 
209
  demo = gr.Interface(
210
  fn=create_email,
211
  inputs=[name_input, company_input, role_input, email_input, phone_input, linkedin_input, word_limit_slider],
 
215
  allow_flagging="never"
216
  )
217
 
 
218
  demo.launch()
219
 
 
220
  if __name__ == "__main__":
221
  gradio_ui()