import gradio as gr import requests import os from bs4 import BeautifulSoup # For scraping company and role info # Load API keys securely from environment variables proxycurl_api_key = os.getenv("PROXYCURL_API_KEY") # Proxycurl API key groq_api_key = os.getenv("GROQ_CLOUD_API_KEY") # Groq Cloud API key class EmailAgent: def __init__(self, linkedin_url, company_name, role, word_limit, user_name, email, phone, linkedin): self.linkedin_url = linkedin_url self.company_name = company_name self.role = role self.word_limit = word_limit self.user_name = user_name self.email = email self.phone = phone self.linkedin = linkedin self.bio = None self.skills = [] self.experiences = [] self.company_info = None self.role_description = None # Reason: Decide what information is needed and if we need to take additional steps def reason_about_data(self): print("Reasoning: Deciding what data we need...") if not self.linkedin_url: print("Warning: LinkedIn URL missing. Proceeding with default bio.") if not self.company_name: print("Warning: Company name missing. Proceeding with default company info.") if not self.role: print("Warning: Role missing. We will use general logic for the role.") # Action: Fetch LinkedIn data via Proxycurl (acting based on reasoning) def fetch_linkedin_data(self): if not self.linkedin_url: print("Action: No LinkedIn URL provided, using default bio.") self.bio = "A professional with diverse experience." self.skills = ["Adaptable", "Hardworking"] self.experiences = ["Worked across various industries"] else: print("Action: Fetching LinkedIn data via Proxycurl.") headers = {"Authorization": f"Bearer {proxycurl_api_key}"} url = f"https://nubela.co/proxycurl/api/v2/linkedin?url={self.linkedin_url}" response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() self.bio = data.get("summary", "No bio available") self.skills = data.get("skills", []) self.experiences = data.get("experiences", []) else: print("Error: Unable to fetch LinkedIn profile. Using default bio.") self.bio = "A professional with diverse experience." self.skills = ["Adaptable", "Hardworking"] self.experiences = ["Worked across various industries"] # Action: Fetch company information via Proxycurl or use defaults def fetch_company_info(self): if not self.company_name: print("Action: No company name provided, using default company info.") self.company_info = "A leading company in its field, offering innovative solutions." else: print(f"Action: Fetching company info for {self.company_name}.") headers = {"Authorization": f"Bearer {proxycurl_api_key}"} url = f"https://nubela.co/proxycurl/api/v2/linkedin/company?company_name={self.company_name}" response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() self.company_info = data.get("description", "No detailed company info available.") else: print(f"Error: Unable to fetch company info for {self.company_name}. Using default info.") self.company_info = "A leading company in its field, offering innovative solutions." # Action: Scrape the company's website for role-specific information or use defaults def scrape_role_from_website(self): print(f"Action: Scraping role description from the company's website for {self.role}.") if not self.company_name: print("Error: No company name or URL provided for scraping.") return False # Try scraping the website for role descriptions try: response = requests.get(f"https://{self.company_name}.com/careers") if response.status_code == 200: soup = BeautifulSoup(response.text, 'html.parser') role_descriptions = soup.find_all(string=lambda text: self.role.lower() in text.lower()) if role_descriptions: self.role_description = role_descriptions[0] print(f"Found role description: {self.role_description}") return True else: print(f"No specific role description found on the website for {self.role}.") return False else: print(f"Error: Unable to reach company's website at {self.company_name}.com.") return False except Exception as e: print(f"Error during scraping: {e}") return False # Action: Use default logic for role description if no role is available def use_default_role_description(self): print(f"Action: Using default logic for the role of {self.role}.") self.role_description = f"The role of {self.role} at {self.company_name} involves mentoring and leading teams in innovative technology solutions." # Reflection: Check if we have enough data to generate the email def reflect_on_data(self): print("Reflection: Do we have enough data?") if not self.bio or not self.skills or not self.company_info: print("Warning: Some critical information is missing. Proceeding with default values.") return True # Final Action: Generate the email using Groq Cloud LLM based on gathered data def generate_email(self): print("Action: Generating the email with the gathered information.") prompt = f""" Write a professional email applying for the {self.role} position at {self.company_name}. The candidate’s bio is: {self.bio}. Focus on relevant skills and experiences from LinkedIn, such as {', '.join(self.skills)}, that directly align with the role of {self.role}. Highlight only the skills and experiences that relate to leadership, mentoring, technology, and innovation. The company info is: {self.company_info}. The role involves: {self.role_description}. End the email with this signature: Best regards, {self.user_name} Email: {self.email} Phone: {self.phone} LinkedIn: {self.linkedin} The email should not exceed {self.word_limit} words. """ url = "https://api.groq.com/openai/v1/chat/completions" headers = {"Authorization": f"Bearer {groq_api_key}", "Content-Type": "application/json"} data = { "messages": [{"role": "user", "content": prompt}], "model": "llama3-8b