siddhartharya commited on
Commit
0707373
·
verified ·
1 Parent(s): 729192c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -132
app.py CHANGED
@@ -3,152 +3,142 @@ import requests
3
  import os
4
 
5
  # Load API keys securely from environment variables
6
- proxycurl_api_key = os.getenv("PROXYCURL_API_KEY") # Add your Proxycurl API key to your environment variables
7
- groq_api_key = os.getenv("GROQ_CLOUD_API_KEY")
8
 
9
- # Function to use Proxycurl API to get the LinkedIn profile data
10
- def get_linkedin_profile_via_proxycurl(linkedin_profile_url):
11
- headers = {
12
- "Authorization": f"Bearer {proxycurl_api_key}",
13
- }
14
- url = f"https://nubela.co/proxycurl/api/v2/linkedin?url={linkedin_profile_url}"
15
-
16
- response = requests.get(url, headers=headers)
17
-
18
- if response.status_code == 200:
19
- data = response.json()
20
- # Extract relevant skills and experiences from LinkedIn profile
21
- bio = data.get("summary", "No bio available")
22
- skills = data.get("skills", []) # List of skills from the LinkedIn profile
23
- experiences = data.get("experiences", []) # List of experiences from the LinkedIn profile
24
- return bio, skills, experiences
25
- else:
26
- return "Error: Unable to fetch LinkedIn profile", [], []
27
-
28
- # Function to get company information via Proxycurl Company API
29
- def get_company_info(company_name):
30
- headers = {
31
- "Authorization": f"Bearer {proxycurl_api_key}",
32
- }
33
- url = f"https://nubela.co/proxycurl/api/v2/linkedin/company?company_name={company_name}"
34
-
35
- response = requests.get(url, headers=headers)
36
-
37
- if response.status_code == 200:
38
- data = response.json()
39
- company_info = data.get("description", "No detailed company info available.")
40
- return company_info
41
- else:
42
- return "Error: Unable to fetch company information."
43
-
44
- # Placeholder for role description; could be enhanced to scrape or fetch real role data
45
- def get_role_description(role_name, company_name):
46
- return f"The role of {role_name} at {company_name} involves..."
47
-
48
- # Helper function to call Groq Cloud LLM API to generate and correct the email
49
- def generate_and_correct_email(bio, company_name, role, company_info, role_description, skills, experiences):
50
- url = "https://api.groq.com/openai/v1/chat/completions"
51
- headers = {
52
- "Authorization": f"Bearer {groq_api_key}",
53
- "Content-Type": "application/json",
54
- }
55
-
56
- # New, detailed prompt with emphasis on correlating LinkedIn skills and experience to the job role
57
- prompt = f"""
58
- Write a professional email applying for the {role} position at {company_name}.
59
-
60
- The candidate’s bio is: {bio}.
61
-
62
- The candidate's LinkedIn profile highlights the following skills: {', '.join(skills)}.
63
- The candidate has the following experiences relevant to the job: {', '.join([exp['title'] for exp in experiences])}.
64
-
65
- The email should:
66
- - Be professional, engaging, and customized to the company's culture and the role’s requirements.
67
- - Include relevant company details: {company_info}.
68
- - Highlight the candidate’s skills and experiences from LinkedIn, mapping them directly to the job's requirements. The role description is: {role_description}.
69
- - Emphasize how the candidate’s background aligns with the company’s values and mission.
70
- - Attract the company's attention by focusing on how the candidate's background can bring value to the role and the company's future goals.
71
- - Use a tone that is persuasive but not overly promotional.
72
- - End with a strong call to action, encouraging the company to schedule an interview to discuss how the candidate can contribute to their success.
73
-
74
- Structure the email as follows:
75
- 1. **Introduction**: Briefly introduce the candidate and state the role they are applying for.
76
- 2. **Skills & Experience**: Map the candidate’s skills and experience from LinkedIn to the job's key requirements.
77
- 3. **Alignment with the Company**: Emphasize how the candidate’s background fits with the company's mission, values, and goals.
78
- 4. **Call to Action**: Encourage the company to schedule an interview to further discuss the candidate’s fit for the role.
79
-
80
- Ensure that redundant sign-offs like 'Best regards' or 'Sincerely' are not included.
81
- """
82
-
83
- # Construct the data payload for the API request
84
- data = {
85
- "messages": [
86
- {
87
- "role": "user",
88
- "content": prompt
89
- }
90
- ],
91
- "model": "llama3-8b-8192"
92
- }
93
-
94
- response = requests.post(url, headers=headers, json=data)
95
-
96
- if response.status_code == 200:
97
- return response.json()["choices"][0]["message"]["content"].strip()
98
- else:
99
- print(f"Error: {response.status_code}, {response.text}")
100
- return "Error generating email. Please check your API key or try again later."
101
 
102
- # Main function to create the email and allow for saving, editing, or copying
103
- def create_email(name, company_name, role, email, phone, linkedin_profile_url):
104
- # Step 1: Fetch LinkedIn profile using Proxycurl API if LinkedIn URL is provided
105
- if linkedin_profile_url:
106
- bio, skills, experiences = get_linkedin_profile_via_proxycurl(linkedin_profile_url)
107
- else:
108
- bio = f"{name} is a professional." # Default bio if no LinkedIn URL is provided
109
- skills, experiences = [], []
110
-
111
- # Step 2: Fetch company information and role description
112
- company_info = get_company_info(company_name)
113
- role_description = get_role_description(role, company_name)
114
-
115
- # Step 3: Generate the email using Groq Cloud LLM
116
- generated_email = generate_and_correct_email(bio, company_name, role, company_info, role_description, skills, experiences)
117
-
118
- # Step 4: Add the user's email, phone number, and LinkedIn profile to the signature
119
- signature = f"\n\nBest regards,\n{name}\nEmail: {email}\nPhone: {phone}\nLinkedIn: {linkedin_profile_url if linkedin_profile_url else 'Not provided'}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
- # Ensure the body doesn't include any redundant 'Best regards' or 'Sincerely' and just append our signature
122
- for phrase in ["Best regards", "Sincerely"]:
123
- if phrase in generated_email:
124
- generated_email = generated_email.split(phrase)[0].strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
- # Return the final polished email with the signature
127
- return generated_email + signature
 
 
 
 
 
 
 
 
128
 
129
- # Define interface with Gradio
130
  def gradio_ui():
131
- # Define inputs
132
  name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
133
-
134
- company_name_input = gr.Textbox(label="Company Name or URL", placeholder="Enter the company name or website URL")
135
  role_input = gr.Textbox(label="Role Applying For", placeholder="Enter the role you are applying for")
136
-
137
  email_input = gr.Textbox(label="Your Email Address", placeholder="Enter your email address")
138
  phone_input = gr.Textbox(label="Your Phone Number", placeholder="Enter your phone number")
139
- linkedin_input = gr.Textbox(label="Your LinkedIn URL", placeholder="Enter your LinkedIn profile URL") # New field for LinkedIn URL
 
140
 
141
- # Define output for the generated email
142
  email_output = gr.Textbox(label="Generated Email", placeholder="Your generated email will appear here", lines=10)
143
-
144
- # Create the Gradio interface
 
 
 
 
 
145
  demo = gr.Interface(
146
- fn=create_email, # Function to call when the user submits
147
- inputs=[name_input, company_name_input, role_input, email_input, phone_input, linkedin_input],
148
  outputs=[email_output],
149
- title="Email Writing AI Agent",
150
- description="Generate a professional email for a job application by providing your basic info.",
151
- allow_flagging="never" # Disable flagging
152
  )
153
 
154
  # Launch the Gradio app
 
3
  import os
4
 
5
  # Load API keys securely from environment variables
6
+ 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
 
9
+ class EmailAgent:
10
+ def __init__(self, linkedin_url, company_name, role, word_limit):
11
+ self.linkedin_url = linkedin_url
12
+ self.company_name = company_name
13
+ self.role = role
14
+ self.word_limit = word_limit
15
+ self.bio = None
16
+ self.skills = []
17
+ self.experiences = []
18
+ self.company_info = None
19
+ self.role_description = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
+ # Reason: Decide what information is needed
22
+ def reason_about_data(self):
23
+ print("Reasoning: I need LinkedIn data, company info, and role description.")
24
+ if not self.linkedin_url:
25
+ print("Missing LinkedIn URL. Request from the user.")
26
+ if not self.company_name:
27
+ print("Missing company name. Request from the user.")
28
+
29
+ # Action: Fetch LinkedIn data via Proxycurl
30
+ def fetch_linkedin_data(self):
31
+ print("Action: Fetching LinkedIn data from Proxycurl.")
32
+ headers = {
33
+ "Authorization": f"Bearer {proxycurl_api_key}",
34
+ }
35
+ url = f"https://nubela.co/proxycurl/api/v2/linkedin?url={self.linkedin_url}"
36
+ response = requests.get(url, headers=headers)
37
+ if response.status_code == 200:
38
+ data = response.json()
39
+ self.bio = data.get("summary", "No bio available")
40
+ self.skills = data.get("skills", [])
41
+ self.experiences = data.get("experiences", [])
42
+ else:
43
+ print("Error: Unable to fetch LinkedIn profile.")
44
+
45
+ # Action: Fetch company information via Proxycurl
46
+ def fetch_company_info(self):
47
+ print(f"Action: Fetching company info for {self.company_name}.")
48
+ headers = {
49
+ "Authorization": f"Bearer {proxycurl_api_key}",
50
+ }
51
+ url = f"https://nubela.co/proxycurl/api/v2/linkedin/company?company_name={self.company_name}"
52
+ response = requests.get(url, headers=headers)
53
+ if response.status_code == 200:
54
+ data = response.json()
55
+ self.company_info = data.get("description", "No detailed company info available.")
56
+ else:
57
+ print(f"Error: Unable to fetch company info for {self.company_name}.")
58
+
59
+ # Action: Fetch role description
60
+ def fetch_role_description(self):
61
+ print(f"Action: Fetching role description for {self.role}.")
62
+ self.role_description = f"The role of {self.role} at {self.company_name} involves..."
63
 
64
+ # Reflection: Check if the data is sufficient to generate an email
65
+ def reflect_on_data(self):
66
+ print("Reflection: Do I have enough data to generate the email?")
67
+ if not self.bio or not self.skills or not self.company_info:
68
+ print("Missing some critical information. Need to gather more data.")
69
+ return False
70
+ return True
71
+
72
+ # Action: Generate the email using Groq Cloud LLM
73
+ def generate_email(self):
74
+ print("Action: Generating the email with the gathered information.")
75
+ prompt = f"""
76
+ Write a professional email applying for the {self.role} position at {self.company_name}.
77
+ The candidate’s bio is: {self.bio}.
78
+ The candidate's LinkedIn profile highlights the following skills: {', '.join(self.skills)}.
79
+ The candidate has the following experiences relevant to the job: {', '.join([exp['title'] for exp in self.experiences])}.
80
+ The email should be professional, concise, and tailored to the company's culture.
81
+ Use relevant company details: {self.company_info}.
82
+ Highlight the candidate’s skills and experiences from LinkedIn, and map them to the job's requirements: {self.role_description}.
83
+ The email should not exceed {self.word_limit} words.
84
+ """
85
+
86
+ url = "https://api.groq.com/openai/v1/chat/completions"
87
+ headers = {
88
+ "Authorization": f"Bearer {groq_api_key}",
89
+ "Content-Type": "application/json",
90
+ }
91
+
92
+ data = {
93
+ "messages": [{"role": "user", "content": prompt}],
94
+ "model": "llama3-8b-8192"
95
+ }
96
+
97
+ response = requests.post(url, headers=headers, json=data)
98
+ if response.status_code == 200:
99
+ return response.json()["choices"][0]["message"]["content"].strip()
100
+ else:
101
+ print(f"Error: {response.status_code}, {response.text}")
102
+ return "Error generating email. Please check your API key or try again later."
103
 
104
+ # Main loop following ReAct pattern
105
+ def run(self):
106
+ self.reason_about_data() # Reason
107
+ self.fetch_linkedin_data() # Action
108
+ self.fetch_company_info() # Action
109
+ self.fetch_role_description() # Action
110
+ if self.reflect_on_data(): # Reflection
111
+ return self.generate_email() # Final Action
112
+ else:
113
+ return "Error: Not enough data to generate the email."
114
 
115
+ # Define the Gradio interface and the main app logic
116
  def gradio_ui():
117
+ # Input fields
118
  name_input = gr.Textbox(label="Your Name", placeholder="Enter your name")
119
+ company_input = gr.Textbox(label="Company Name or URL", placeholder="Enter the company name or website URL")
 
120
  role_input = gr.Textbox(label="Role Applying For", placeholder="Enter the role you are applying for")
 
121
  email_input = gr.Textbox(label="Your Email Address", placeholder="Enter your email address")
122
  phone_input = gr.Textbox(label="Your Phone Number", placeholder="Enter your phone number")
123
+ linkedin_input = gr.Textbox(label="Your LinkedIn URL", placeholder="Enter your LinkedIn profile URL")
124
+ word_limit_slider = gr.Slider(minimum=50, maximum=300, step=10, label="Email Word Limit", value=150) # New slider for word limit
125
 
126
+ # Output field
127
  email_output = gr.Textbox(label="Generated Email", placeholder="Your generated email will appear here", lines=10)
128
+
129
+ # Function to create and run the email agent
130
+ def create_email(name, company_name, role, email, phone, linkedin_profile_url, word_limit):
131
+ agent = EmailAgent(linkedin_profile_url, company_name, role, word_limit)
132
+ return agent.run()
133
+
134
+ # Gradio interface
135
  demo = gr.Interface(
136
+ fn=create_email,
137
+ inputs=[name_input, company_input, role_input, email_input, phone_input, linkedin_input, word_limit_slider],
138
  outputs=[email_output],
139
+ title="Email Writing AI Agent with ReAct",
140
+ description="Generate a professional email for a job application using LinkedIn data, company info, and role description.",
141
+ allow_flagging="never"
142
  )
143
 
144
  # Launch the Gradio app