siddhartharya commited on
Commit
f18b18e
·
verified ·
1 Parent(s): e1218a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -94
app.py CHANGED
@@ -18,7 +18,6 @@ class AutonomousEmailAgent:
18
  self.experiences = []
19
  self.company_info = None
20
  self.role_description = None
21
- self.company_url = None
22
  self.attempts = 0 # Counter for iterations
23
 
24
  # Fetch LinkedIn data via Proxycurl
@@ -41,10 +40,20 @@ class AutonomousEmailAgent:
41
  self.experiences = data.get("experiences", [])
42
  print("LinkedIn data fetched successfully.")
43
  else:
44
- print("Error: Unable to fetch LinkedIn profile. Using default bio.")
45
- self.bio = "A professional with diverse experience."
46
- self.skills = ["Adaptable", "Hardworking"]
47
- self.experiences = ["Worked across various industries"]
 
 
 
 
 
 
 
 
 
 
48
 
49
  # Reason and Act via LLM: Let the LLM control reasoning and actions dynamically
50
  def autonomous_reasoning(self):
@@ -60,13 +69,10 @@ class AutonomousEmailAgent:
60
  - Candidate's Bio: {self.bio}
61
  - Candidate's Skills: {', '.join(self.skills)}
62
  - Candidate's Experiences: {', '.join([exp['title'] for exp in self.experiences])}
63
- - Company Information: {self.company_info}
64
- - Role Description: {self.role_description}
65
-
66
  Based on this data, decide if it is sufficient to generate the email. If some information is missing or insufficient, respond with:
67
- 1. "scrape" to fetch more data from the company website.
68
- 2. "generate_email" to proceed with the email generation.
69
- 3. "fallback" to use default values.
70
 
71
  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.
72
  """
@@ -86,7 +92,7 @@ class AutonomousEmailAgent:
86
  "Content-Type": "application/json"
87
  }
88
  data = {
89
- "model": "llama-3.1-70b-versatile", # Model name
90
  "messages": [{"role": "user", "content": prompt}]
91
  }
92
  response = requests.post("https://api.groq.com/openai/v1/chat/completions", headers=headers, json=data)
@@ -94,10 +100,8 @@ class AutonomousEmailAgent:
94
  print(f"Status Code: {response.status_code}")
95
  if response.status_code == 200:
96
  try:
97
- result = response.json() # Parse the response as JSON
98
- print(f"LLM Response: {json.dumps(result, indent=2)}") # Print the full response for debugging
99
-
100
- # Check if 'choices' and the content are correctly structured in the response
101
  choices = result.get("choices", [])
102
  if choices and "message" in choices[0]:
103
  content = choices[0]["message"]["content"]
@@ -110,110 +114,46 @@ class AutonomousEmailAgent:
110
  print("Error: Response from Groq Cloud LLM is not valid JSON.")
111
  return "Error: Response is not in JSON format."
112
  else:
113
- print(f"Error: Unable to connect to Groq Cloud LLM. Status Code: {response.status_code}, Response: {response.text}")
114
  return "Error: Unable to generate response."
115
 
116
  # Function to act on the LLM's structured instructions
117
  def act_on_llm_instructions(self, reasoning_output):
118
- print(f"LLM Instruction: {reasoning_output}") # Print the LLM's instruction for debugging
119
  instruction = reasoning_output.lower().strip()
120
 
121
- if "scrape" in instruction:
122
- if self.attempts >= 5:
123
- print("Max attempts reached. Proceeding with fallback option.")
124
- return self.generate_fallback_email()
125
- self.attempts += 1
126
- self.fetch_company_url()
127
- if self.company_url:
128
- self.fetch_company_info_with_firecrawl(self.company_url)
129
- return self.autonomous_reasoning()
130
-
131
- elif "generate_email" in instruction:
132
  return self.generate_email()
133
 
134
- elif "fallback" in instruction or self.attempts >= 5:
135
  print("Action: Using fallback values for missing data.")
136
- if not self.company_info:
137
- self.company_info = "A leading company in its field."
138
- if not self.role_description:
139
- self.role_description = f"The role of {self.role} involves leadership and team management."
140
  return self.generate_email()
141
 
142
  else:
143
  print("Error: Unrecognized instruction from LLM. Proceeding with available data.")
144
  return self.generate_email()
145
 
146
- # Fetch company URL using SERP API
147
- def fetch_company_url(self):
148
- serp_api_key = os.getenv("SERP_API_KEY")
149
- print(f"Fetching company URL for {self.company_name} using SERP API...")
150
- serp_url = f"https://serpapi.com/search.json?q={self.company_name}&api_key={serp_api_key}&num=1"
151
- response = requests.get(serp_url)
152
-
153
- if response.status_code == 200:
154
- serp_data = response.json()
155
- if 'organic_results' in serp_data and len(serp_data['organic_results']) > 0:
156
- self.company_url = serp_data['organic_results'][0]['link']
157
- print(f"Found company URL: {self.company_url}")
158
- else:
159
- print("No URL found for the company via SERP API.")
160
- self.company_url = None
161
- else:
162
- print(f"Error fetching company URL: {response.status_code}")
163
-
164
- # Fetch company information via Firecrawl API using company URL
165
- def fetch_company_info_with_firecrawl(self, company_url):
166
- firecrawl_api_key = os.getenv("FIRECRAWL_API_KEY")
167
- print(f"Fetching company info for {company_url} using Firecrawl.")
168
- headers = {"Authorization": f"Bearer {firecrawl_api_key}"}
169
- firecrawl_url = "https://api.firecrawl.dev/v1/scrape"
170
- data = {"url": company_url, "patterns": ["description", "about", "careers", "company overview"]}
171
-
172
- response = requests.post(firecrawl_url, json=data, headers=headers)
173
- if response.status_code == 200:
174
- firecrawl_data = response.json()
175
- self.company_info = firecrawl_data.get("description", "No detailed company info available.")
176
- print(f"Company info fetched: {self.company_info}")
177
- else:
178
- print(f"Error: Unable to fetch company info via Firecrawl. Status code: {response.status_code}")
179
- self.company_info = "A leading company in its field."
180
-
181
- # Final Action: Generate the email using Groq Cloud LLM
182
  def generate_email(self):
183
- print("Action: Generating the email using Groq Cloud LLM with the gathered information.")
184
-
185
- prompt = f"""
186
- Write a professional job application email applying for the {self.role} position at {self.company_name}.
 
187
 
188
- The email should follow the "Start with Why" approach:
189
- 1. **Why**: Explain why the candidate is passionate about this role and company.
190
- 2. **How**: Highlight the candidate’s skills and experiences.
191
- 3. **What**: Provide examples of past achievements.
192
- 4. **Call to Action**: Request a meeting or discussion.
193
 
194
- - LinkedIn bio: {self.bio}
195
- - Skills: {', '.join(self.skills)}
196
- - Experience: {', '.join([exp['title'] for exp in self.experiences])}
197
- - Company information: {self.company_info}
198
 
199
- Signature:
200
  Best regards,
201
  {self.user_name}
202
  Email: {self.email}
203
  Phone: {self.phone}
204
  LinkedIn: {self.linkedin}
205
-
206
- Limit the email to {self.word_limit} words.
207
  """
 
208
 
209
- return self.send_request_to_llm(prompt)
210
-
211
- # Main loop following ReAct pattern
212
- def run(self):
213
- self.fetch_linkedin_data()
214
- return self.autonomous_reasoning()
215
-
216
- # Gradio UI setup remains the same
217
  def gradio_ui():
218
  name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
219
  company_input = gr.Textbox(label="Company Name or URL", placeholder="Enter the company name or website URL")
 
18
  self.experiences = []
19
  self.company_info = None
20
  self.role_description = None
 
21
  self.attempts = 0 # Counter for iterations
22
 
23
  # Fetch LinkedIn data via Proxycurl
 
40
  self.experiences = data.get("experiences", [])
41
  print("LinkedIn data fetched successfully.")
42
  else:
43
+ print("Error: Unable to fetch LinkedIn profile. Status Code:", response.status_code)
44
+ self.use_default_profile()
45
+
46
+ # Set default profile information if LinkedIn scraping fails
47
+ def use_default_profile(self):
48
+ print("Using default profile values.")
49
+ self.bio = "A professional with a versatile background and extensive experience."
50
+ self.skills = ["Leadership", "Communication", "Problem-solving"]
51
+ self.experiences = [{"title": "Project Manager"}, {"title": "Team Leader"}]
52
+
53
+ # Main loop following ReAct pattern
54
+ def run(self):
55
+ self.fetch_linkedin_data()
56
+ return self.autonomous_reasoning()
57
 
58
  # Reason and Act via LLM: Let the LLM control reasoning and actions dynamically
59
  def autonomous_reasoning(self):
 
69
  - Candidate's Bio: {self.bio}
70
  - Candidate's Skills: {', '.join(self.skills)}
71
  - Candidate's Experiences: {', '.join([exp['title'] for exp in self.experiences])}
72
+
 
 
73
  Based on this data, decide if it is sufficient to generate the email. If some information is missing or insufficient, respond with:
74
+ 1. "generate_email" to proceed with the email generation using available data.
75
+ 2. "fallback" to use default values.
 
76
 
77
  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.
78
  """
 
92
  "Content-Type": "application/json"
93
  }
94
  data = {
95
+ "model": "llama-3.1-70b-versatile",
96
  "messages": [{"role": "user", "content": prompt}]
97
  }
98
  response = requests.post("https://api.groq.com/openai/v1/chat/completions", headers=headers, json=data)
 
100
  print(f"Status Code: {response.status_code}")
101
  if response.status_code == 200:
102
  try:
103
+ result = response.json()
104
+ print(f"LLM Response: {json.dumps(result, indent=2)}")
 
 
105
  choices = result.get("choices", [])
106
  if choices and "message" in choices[0]:
107
  content = choices[0]["message"]["content"]
 
114
  print("Error: Response from Groq Cloud LLM is not valid JSON.")
115
  return "Error: Response is not in JSON format."
116
  else:
117
+ print(f"Error: Unable to connect to Groq Cloud LLM. Status Code: {response.status_code}")
118
  return "Error: Unable to generate response."
119
 
120
  # Function to act on the LLM's structured instructions
121
  def act_on_llm_instructions(self, reasoning_output):
122
+ print(f"LLM Instruction: {reasoning_output}")
123
  instruction = reasoning_output.lower().strip()
124
 
125
+ if "generate_email" in instruction:
 
 
 
 
 
 
 
 
 
 
126
  return self.generate_email()
127
 
128
+ elif "fallback" in instruction:
129
  print("Action: Using fallback values for missing data.")
 
 
 
 
130
  return self.generate_email()
131
 
132
  else:
133
  print("Error: Unrecognized instruction from LLM. Proceeding with available data.")
134
  return self.generate_email()
135
 
136
+ # Generate email based on the collected data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  def generate_email(self):
138
+ print("Generating email based on the provided and/or fallback data...")
139
+ email_content = f"""
140
+ Subject: Application for {self.role} at {self.company_name}
141
+
142
+ Dear Hiring Manager,
143
 
144
+ I am excited to apply for the {self.role} role at {self.company_name}. With a strong background in {self.bio}, I believe my skills in {', '.join(self.skills)} would make me a valuable addition to your team.
 
 
 
 
145
 
146
+ Please find my LinkedIn profile for more details: {self.linkedin}
 
 
 
147
 
 
148
  Best regards,
149
  {self.user_name}
150
  Email: {self.email}
151
  Phone: {self.phone}
152
  LinkedIn: {self.linkedin}
 
 
153
  """
154
+ return email_content
155
 
156
+ # Gradio UI setup remains unchanged
 
 
 
 
 
 
 
157
  def gradio_ui():
158
  name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
159
  company_input = gr.Textbox(label="Company Name or URL", placeholder="Enter the company name or website URL")