siddhartharya commited on
Commit
0c3b71f
·
verified ·
1 Parent(s): bc40ada

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -39
app.py CHANGED
@@ -7,7 +7,7 @@ proxycurl_api_key = os.getenv("PROXYCURL_API_KEY") # Proxycurl API key
7
  groq_api_key = os.getenv("GROQ_CLOUD_API_KEY") # Groq Cloud API key
8
  firecrawl_api_key = os.getenv("FIRECRAWL_API_KEY") # Firecrawl API key
9
 
10
- class EmailAgent:
11
  def __init__(self, linkedin_url, company_name, role, word_limit, user_name, email, phone, linkedin):
12
  self.linkedin_url = linkedin_url
13
  self.company_name = company_name
@@ -23,38 +23,33 @@ class EmailAgent:
23
  self.company_info = None
24
  self.role_description = None
25
 
26
- # Use the LLM to reason and reflect on the provided data
27
- def reason_with_llm(self):
28
- print("Reasoning: Using LLM to reason about available data...")
29
 
30
- # LLM reasoning prompt that evaluates the current data and reflects on next actions
31
  reasoning_prompt = f"""
32
- You are a reasoning agent tasked with generating a job application email. Here's what we have:
33
 
34
- 1. Candidate's LinkedIn profile URL: {self.linkedin_url}
35
- 2. Company Name: {self.company_name}
36
- 3. Role: {self.role}
37
- 4. Word Limit: {self.word_limit}
38
- 5. Candidate's Name: {self.user_name}
39
- 6. Candidate's Email: {self.email}
40
- 7. Candidate's Phone: {self.phone}
41
- 8. Candidate's LinkedIn: {self.linkedin}
42
-
43
- Candidate's Bio: {self.bio}
44
- Candidate's Skills: {', '.join(self.skills)}
45
- Candidate's Experiences: {', '.join([exp['title'] for exp in self.experiences])}
46
-
47
- Company Information: {self.company_info}
48
- Role Description: {self.role_description}
49
-
50
- Evaluate the completeness of the data. If some key data is missing, determine whether we should:
51
- - Scrape for more data (e.g., company info, role descriptions).
52
- - Proceed with the available information and generate the email using default logic.
53
-
54
- Reflect on whether we need more data or if the current information is sufficient to proceed.
55
- """
56
 
57
- # Send this reasoning prompt to the LLM
 
 
 
 
 
 
 
58
  url = "https://api.groq.com/openai/v1/chat/completions"
59
  headers = {
60
  "Authorization": f"Bearer {groq_api_key}",
@@ -70,12 +65,30 @@ class EmailAgent:
70
  if response.status_code == 200:
71
  reasoning_output = response.json()["choices"][0]["message"]["content"].strip()
72
  print("LLM Reasoning Output:", reasoning_output)
73
- return reasoning_output
 
 
74
  else:
75
  print(f"Error: {response.status_code}, {response.text}")
76
  return "Error: Unable to complete reasoning."
77
 
78
- # Action: Fetch LinkedIn data via Proxycurl (acting based on reasoning)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  def fetch_linkedin_data(self):
80
  if not self.linkedin_url:
81
  print("Action: No LinkedIn URL provided, using default bio.")
@@ -121,11 +134,10 @@ class EmailAgent:
121
  print(f"Error: Unable to fetch company info via Firecrawl. Using default info.")
122
  self.company_info = "A leading company in its field."
123
 
124
- # Final Action: Generate the email using Groq Cloud LLM based on gathered data
125
  def generate_email(self):
126
  print("Action: Generating the email with the gathered information.")
127
 
128
- # Use the LinkedIn profile link dynamically in the body
129
  linkedin_text = f"Please find my LinkedIn profile at {self.linkedin}" if self.linkedin else ""
130
 
131
  # Dynamic LLM prompt
@@ -175,13 +187,9 @@ class EmailAgent:
175
 
176
  # Main loop following ReAct pattern
177
  def run(self):
178
- reasoning_output = self.reason_with_llm() # LLM performs reasoning and reflection
179
- print("LLM Reflection:", reasoning_output)
180
-
181
  self.fetch_linkedin_data() # Fetch LinkedIn data
182
- self.fetch_company_info_with_firecrawl() # Fetch company data using Firecrawl
183
-
184
- return self.generate_email() # Final action: generate email
185
 
186
  # Define the Gradio interface and the main app logic
187
  def gradio_ui():
@@ -197,3 +205,24 @@ def gradio_ui():
197
  # Output field
198
  email_output = gr.Textbox(label="Generated Email", placeholder="Your generated email will appear here", lines=10)
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  groq_api_key = os.getenv("GROQ_CLOUD_API_KEY") # Groq Cloud API key
8
  firecrawl_api_key = os.getenv("FIRECRAWL_API_KEY") # Firecrawl API key
9
 
10
+ class AutonomousEmailAgent:
11
  def __init__(self, linkedin_url, company_name, role, word_limit, user_name, email, phone, linkedin):
12
  self.linkedin_url = linkedin_url
13
  self.company_name = company_name
 
23
  self.company_info = None
24
  self.role_description = None
25
 
26
+ # Reason and Act via LLM: Let the LLM control reasoning and actions dynamically
27
+ def autonomous_reasoning(self):
28
+ print("Autonomous Reasoning: Letting the LLM fully reason and act on available data...")
29
 
30
+ # LLM reasoning prompt that evaluates the current data and issues actions autonomously
31
  reasoning_prompt = f"""
32
+ You are an autonomous agent responsible for generating a job application email.
33
 
34
+ Here's the current data:
35
+
36
+ - LinkedIn profile: {self.linkedin_url}
37
+ - Company Name: {self.company_name}
38
+ - Role: {self.role}
39
+ - Candidate's Bio: {self.bio}
40
+ - Candidate's Skills: {', '.join(self.skills)}
41
+ - Candidate's Experiences: {', '.join([exp['title'] for exp in self.experiences])}
42
+ - Company Information: {self.company_info}
43
+ - Role Description: {self.role_description}
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ Based on this data, decide if it is sufficient to generate the email. If some information is missing or insufficient:
46
+ - Decide whether to scrape the company's website for more information or use a fallback.
47
+ - If the scraping fails, decide what next steps to take.
48
+
49
+ Once the information is complete, proceed to generate the email. After generating the email, reflect on whether the content aligns with the role and company and whether any improvements are needed.
50
+ """
51
+
52
+ # Send the reasoning prompt to the LLM
53
  url = "https://api.groq.com/openai/v1/chat/completions"
54
  headers = {
55
  "Authorization": f"Bearer {groq_api_key}",
 
65
  if response.status_code == 200:
66
  reasoning_output = response.json()["choices"][0]["message"]["content"].strip()
67
  print("LLM Reasoning Output:", reasoning_output)
68
+
69
+ # Now the LLM takes action based on the reflection
70
+ return self.act_on_llm_instructions(reasoning_output)
71
  else:
72
  print(f"Error: {response.status_code}, {response.text}")
73
  return "Error: Unable to complete reasoning."
74
 
75
+ # Function to act on the LLM's instructions
76
+ def act_on_llm_instructions(self, reasoning_output):
77
+ # Parse the LLM's instructions (assume it's structured with action steps)
78
+ if "scrape the company's website" in reasoning_output:
79
+ # Action: Scrape the company's website for more information
80
+ self.fetch_company_info_with_firecrawl()
81
+ # Reflect again by invoking the LLM to reassess
82
+ return self.autonomous_reasoning()
83
+
84
+ elif "generate the email" in reasoning_output:
85
+ # Action: Proceed to generate the email
86
+ return self.generate_email()
87
+
88
+ else:
89
+ return "Error: Unrecognized instruction from LLM."
90
+
91
+ # Action: Fetch LinkedIn data via Proxycurl
92
  def fetch_linkedin_data(self):
93
  if not self.linkedin_url:
94
  print("Action: No LinkedIn URL provided, using default bio.")
 
134
  print(f"Error: Unable to fetch company info via Firecrawl. Using default info.")
135
  self.company_info = "A leading company in its field."
136
 
137
+ # Final Action: Generate the email using Groq Cloud LLM
138
  def generate_email(self):
139
  print("Action: Generating the email with the gathered information.")
140
 
 
141
  linkedin_text = f"Please find my LinkedIn profile at {self.linkedin}" if self.linkedin else ""
142
 
143
  # Dynamic LLM prompt
 
187
 
188
  # Main loop following ReAct pattern
189
  def run(self):
 
 
 
190
  self.fetch_linkedin_data() # Fetch LinkedIn data
191
+ # Let LLM autonomously decide and act
192
+ return self.autonomous_reasoning()
 
193
 
194
  # Define the Gradio interface and the main app logic
195
  def gradio_ui():
 
205
  # Output field
206
  email_output = gr.Textbox(label="Generated Email", placeholder="Your generated email will appear here", lines=10)
207
 
208
+ # Function to create and run the email agent
209
+ def create_email(name, company_name, role, email, phone, linkedin_url, word_limit):
210
+ agent = AutonomousEmailAgent(linkedin_url, company_name, role, word_limit, name, email, phone, linkedin_url)
211
+ return agent.run()
212
+
213
+ # Gradio interface
214
+ demo = gr.Interface(
215
+ fn=create_email,
216
+ inputs=[name_input, company_input, role_input, email_input, phone_input, linkedin_input, word_limit_slider],
217
+ outputs=[email_output],
218
+ title="Email Writing AI Agent with ReAct",
219
+ description="Generate a professional email for a job application using LinkedIn data, company info, and role description.",
220
+ allow_flagging="never"
221
+ )
222
+
223
+ # Launch the Gradio app
224
+ demo.launch()
225
+
226
+ # Start the Gradio app when running the script
227
+ if __name__ == "__main__":
228
+ gradio_ui()