Update app.py
Browse files
app.py
CHANGED
@@ -1,13 +1,7 @@
|
|
1 |
import gradio as gr
|
2 |
import requests
|
3 |
import os
|
4 |
-
|
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
|
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 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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")
|
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}
|
116 |
|
117 |
# Fetch LinkedIn data via Proxycurl
|
118 |
def fetch_linkedin_data(self):
|
119 |
-
proxycurl_api_key = os.getenv("PROXYCURL_API_KEY")
|
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")
|
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.
|
160 |
self.company_info = "A leading company in its field."
|
161 |
|
162 |
-
# Final Action: Generate the email using Groq Cloud LLM
|
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**:
|
171 |
-
2. **How**:
|
172 |
-
3. **What**: Provide
|
173 |
-
4. **Call to Action**:
|
174 |
-
|
175 |
-
|
176 |
-
-
|
177 |
-
-
|
178 |
-
-
|
179 |
-
|
180 |
-
|
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 |
-
|
190 |
"""
|
191 |
|
192 |
-
|
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()
|
212 |
-
return self.autonomous_reasoning()
|
213 |
|
214 |
-
#
|
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()
|