Update app.py
Browse files
app.py
CHANGED
@@ -19,13 +19,14 @@ class AutonomousEmailAgent:
|
|
19 |
self.company_info = None
|
20 |
self.role_description = None
|
21 |
self.attempts = 0 # Counter for iterations
|
22 |
-
self.max_attempts = 5 # Set maximum number of iterations
|
23 |
|
24 |
def fetch_linkedin_data(self):
|
25 |
proxycurl_api_key = os.getenv("PROXYCURL_API_KEY")
|
26 |
if not self.linkedin_url:
|
27 |
print("Action: No LinkedIn URL provided, using default bio.")
|
28 |
-
self.
|
|
|
|
|
29 |
else:
|
30 |
print("Action: Fetching LinkedIn data via Proxycurl.")
|
31 |
headers = {"Authorization": f"Bearer {proxycurl_api_key}"}
|
@@ -55,10 +56,10 @@ class AutonomousEmailAgent:
|
|
55 |
print("Autonomous Reasoning: Letting the LLM fully reason and act on available data...")
|
56 |
|
57 |
reasoning_prompt = f"""
|
58 |
-
You are an AI agent tasked with generating a
|
59 |
-
The email must
|
60 |
experience align with the company and role, and finally describe specific achievements that demonstrate their
|
61 |
-
capabilities.
|
62 |
|
63 |
Here’s the current data:
|
64 |
- LinkedIn profile: {self.linkedin_url}
|
@@ -68,7 +69,7 @@ class AutonomousEmailAgent:
|
|
68 |
- Candidate's Skills: {', '.join(self.skills)}
|
69 |
- Candidate's Experiences: {', '.join([exp['title'] for exp in self.experiences])}
|
70 |
|
71 |
-
|
72 |
"""
|
73 |
|
74 |
return self.send_request_to_llm(reasoning_prompt)
|
@@ -99,7 +100,7 @@ class AutonomousEmailAgent:
|
|
99 |
if choices and "message" in choices[0]:
|
100 |
content = choices[0]["message"]["content"]
|
101 |
print(f"Content: {content}")
|
102 |
-
return self.
|
103 |
else:
|
104 |
print("Error: Unrecognized format in LLM response.")
|
105 |
return "Error: Unrecognized response format."
|
@@ -110,25 +111,6 @@ class AutonomousEmailAgent:
|
|
110 |
print(f"Error: Unable to connect to Groq Cloud LLM. Status Code: {response.status_code}")
|
111 |
return "Error: Unable to generate response."
|
112 |
|
113 |
-
def act_on_llm_instructions(self, llm_response):
|
114 |
-
if self.attempts >= self.max_attempts:
|
115 |
-
print("Max attempts reached. Proceeding with fallback option.")
|
116 |
-
return self.generate_fallback_email()
|
117 |
-
|
118 |
-
print(f"LLM Instruction: {llm_response}")
|
119 |
-
if "scrape" in llm_response.lower():
|
120 |
-
self.attempts += 1
|
121 |
-
print(f"Scraping attempt {self.attempts}...")
|
122 |
-
return self.autonomous_reasoning()
|
123 |
-
elif "generate_email" in llm_response.lower():
|
124 |
-
return self.format_email(llm_response)
|
125 |
-
elif "fallback" in llm_response.lower():
|
126 |
-
return self.generate_fallback_email()
|
127 |
-
else:
|
128 |
-
print("Error: Unrecognized instruction from LLM. Proceeding with available data.")
|
129 |
-
self.attempts += 1
|
130 |
-
return self.autonomous_reasoning()
|
131 |
-
|
132 |
def format_email(self, llm_response):
|
133 |
# Clean and format the email
|
134 |
lines = [line.strip() for line in llm_response.split("\n") if line.strip()]
|
@@ -140,17 +122,20 @@ class AutonomousEmailAgent:
|
|
140 |
truncated_email = " ".join(words[:self.word_limit]) + "..."
|
141 |
formatted_email = truncated_email
|
142 |
|
143 |
-
# Add a call to action
|
144 |
closing_section = (
|
145 |
-
"\n\nI would
|
146 |
-
|
147 |
-
"Thank you for considering my application. I look forward to
|
148 |
)
|
149 |
|
150 |
# Prepare the signature
|
151 |
signature = (
|
152 |
-
f"Best regards,\n
|
153 |
-
f"
|
|
|
|
|
|
|
154 |
)
|
155 |
|
156 |
# Ensure only one "Best regards" section and remove any duplicate signatures
|
@@ -159,23 +144,6 @@ class AutonomousEmailAgent:
|
|
159 |
|
160 |
return f"{formatted_email}{closing_section}\n{signature}"
|
161 |
|
162 |
-
def generate_fallback_email(self):
|
163 |
-
# Generate a more impactful fallback email if max attempts are reached
|
164 |
-
return f"""Subject: Application for {self.role} at {self.company_name}
|
165 |
-
|
166 |
-
Dear Hiring Manager,
|
167 |
-
|
168 |
-
I am excited to apply for the {self.role} position at {self.company_name}. My experience in business development and leadership has prepared me to make a significant impact in this role. I have led global marketing efforts, managed international teams, and developed strategic initiatives that align closely with the goals of your organization.
|
169 |
-
|
170 |
-
I would appreciate the opportunity to discuss how my skills can contribute to {self.company_name}'s mission and success. Please feel free to contact me at your earliest convenience.
|
171 |
-
|
172 |
-
Best regards,
|
173 |
-
{self.user_name}
|
174 |
-
Email: {self.email}
|
175 |
-
Phone: {self.phone}
|
176 |
-
LinkedIn: {self.linkedin}
|
177 |
-
"""
|
178 |
-
|
179 |
# Gradio UI setup remains unchanged
|
180 |
def gradio_ui():
|
181 |
name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
|
@@ -197,8 +165,10 @@ def gradio_ui():
|
|
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="
|
|
|
201 |
)
|
|
|
202 |
demo.launch()
|
203 |
|
204 |
if __name__ == "__main__":
|
|
|
19 |
self.company_info = None
|
20 |
self.role_description = None
|
21 |
self.attempts = 0 # Counter for iterations
|
|
|
22 |
|
23 |
def fetch_linkedin_data(self):
|
24 |
proxycurl_api_key = os.getenv("PROXYCURL_API_KEY")
|
25 |
if not self.linkedin_url:
|
26 |
print("Action: No LinkedIn URL provided, using default bio.")
|
27 |
+
self.bio = "A professional with diverse experience."
|
28 |
+
self.skills = ["Adaptable", "Hardworking"]
|
29 |
+
self.experiences = ["Worked across various industries"]
|
30 |
else:
|
31 |
print("Action: Fetching LinkedIn data via Proxycurl.")
|
32 |
headers = {"Authorization": f"Bearer {proxycurl_api_key}"}
|
|
|
56 |
print("Autonomous Reasoning: Letting the LLM fully reason and act on available data...")
|
57 |
|
58 |
reasoning_prompt = f"""
|
59 |
+
You are an AI agent tasked with generating a job application email using Simon Sinek's Start with Why model.
|
60 |
+
The email must begin with why the candidate is passionate about the role, then explain how their skills and
|
61 |
experience align with the company and role, and finally describe specific achievements that demonstrate their
|
62 |
+
capabilities.
|
63 |
|
64 |
Here’s the current data:
|
65 |
- LinkedIn profile: {self.linkedin_url}
|
|
|
69 |
- Candidate's Skills: {', '.join(self.skills)}
|
70 |
- Candidate's Experiences: {', '.join([exp['title'] for exp in self.experiences])}
|
71 |
|
72 |
+
Generate the email using this structure and ensure it is within {self.word_limit} words.
|
73 |
"""
|
74 |
|
75 |
return self.send_request_to_llm(reasoning_prompt)
|
|
|
100 |
if choices and "message" in choices[0]:
|
101 |
content = choices[0]["message"]["content"]
|
102 |
print(f"Content: {content}")
|
103 |
+
return self.format_email(content)
|
104 |
else:
|
105 |
print("Error: Unrecognized format in LLM response.")
|
106 |
return "Error: Unrecognized response format."
|
|
|
111 |
print(f"Error: Unable to connect to Groq Cloud LLM. Status Code: {response.status_code}")
|
112 |
return "Error: Unable to generate response."
|
113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
def format_email(self, llm_response):
|
115 |
# Clean and format the email
|
116 |
lines = [line.strip() for line in llm_response.split("\n") if line.strip()]
|
|
|
122 |
truncated_email = " ".join(words[:self.word_limit]) + "..."
|
123 |
formatted_email = truncated_email
|
124 |
|
125 |
+
# Add the closing section with a call to action
|
126 |
closing_section = (
|
127 |
+
"\n\nI would appreciate the opportunity to discuss how my background, skills, and passion align with the goals "
|
128 |
+
"of 100xEngineers. I am eager to contribute to your mission and support the development of future leaders in technology.\n\n"
|
129 |
+
"Thank you for considering my application. I look forward to the possibility of discussing this role further.\n"
|
130 |
)
|
131 |
|
132 |
# Prepare the signature
|
133 |
signature = (
|
134 |
+
f"Best regards,\n"
|
135 |
+
f"{self.user_name}\n"
|
136 |
+
f"Email: {self.email}\n"
|
137 |
+
f"Phone: {self.phone}\n"
|
138 |
+
f"LinkedIn: {self.linkedin}"
|
139 |
)
|
140 |
|
141 |
# Ensure only one "Best regards" section and remove any duplicate signatures
|
|
|
144 |
|
145 |
return f"{formatted_email}{closing_section}\n{signature}"
|
146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
# Gradio UI setup remains unchanged
|
148 |
def gradio_ui():
|
149 |
name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
|
|
|
165 |
inputs=[name_input, company_input, role_input, email_input, phone_input, linkedin_input, word_limit_slider],
|
166 |
outputs=[email_output],
|
167 |
title="Email Writing AI Agent with ReAct",
|
168 |
+
description="Generate a professional email for a job application using LinkedIn data, company info, and role description.",
|
169 |
+
allow_flagging="never"
|
170 |
)
|
171 |
+
|
172 |
demo.launch()
|
173 |
|
174 |
if __name__ == "__main__":
|