Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| from streamlit_option_menu import option_menu | |
| from langchain_groq import ChatGroq | |
| import fitz # PyMuPDF | |
| import requests | |
| from bs4 import BeautifulSoup | |
| import plotly.express as px | |
| import re | |
| import pandas as pd | |
| import sqlite3 | |
| from datetime import datetime, timedelta | |
| from streamlit_chat import message | |
| import os | |
| GROQ_API_KEY = st.secrets["GROQ_API_KEY"] | |
| RAPIDAPI_KEY = st.secrets["RAPIDAPI_KEY"] | |
| llm = ChatGroq( | |
| temperature=0, | |
| groq_api_key=GROQ_API_KEY, | |
| model_name="llama-3.1-70b-versatile" | |
| ) | |
| def extract_text_from_pdf(pdf_file): | |
| """ | |
| Extracts text from an uploaded PDF file. | |
| """ | |
| text = "" | |
| try: | |
| with fitz.open(stream=pdf_file.read(), filetype="pdf") as doc: | |
| for page in doc: | |
| text += page.get_text() | |
| return text | |
| except Exception as e: | |
| st.error(f"Error extracting text from PDF: {e}") | |
| return "" | |
| def extract_job_description(job_link): | |
| """ | |
| Fetches and extracts job description text from a given URL. | |
| """ | |
| try: | |
| headers = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" | |
| } | |
| response = requests.get(job_link, headers=headers) | |
| response.raise_for_status() | |
| soup = BeautifulSoup(response.text, 'html.parser') | |
| # You might need to adjust the selectors based on the website's structure | |
| job_description = soup.get_text(separator='\n') | |
| return job_description.strip() | |
| except Exception as e: | |
| st.error(f"Error fetching job description: {e}") | |
| return "" | |
| def extract_requirements(job_description): | |
| """ | |
| Uses Groq to extract job requirements from the job description. | |
| """ | |
| prompt = f""" | |
| The following is a job description: | |
| {job_description} | |
| Extract the list of job requirements, qualifications, and skills from the job description. Provide them as a numbered list. | |
| Requirements: | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| requirements = response.content.strip() | |
| return requirements | |
| except Exception as e: | |
| st.error(f"Error extracting requirements: {e}") | |
| return "" | |
| def generate_email(job_description, requirements, resume_text): | |
| """ | |
| Generates a personalized cold email using Groq based on the job description, requirements, and resume. | |
| """ | |
| prompt = f""" | |
| You are Adithya S Nair, a recent Computer Science graduate specializing in Artificial Intelligence and Machine Learning. Craft a concise and professional cold email to a potential employer based on the following information: | |
| **Job Description:** | |
| {job_description} | |
| **Extracted Requirements:** | |
| {requirements} | |
| **Your Resume:** | |
| {resume_text} | |
| **Email Requirements:** | |
| - **Introduction:** Briefly introduce yourself and mention the specific job you are applying for. | |
| - **Body:** Highlight your relevant skills, projects, internships, and leadership experiences that align with the job requirements. | |
| - **Value Proposition:** Explain how your fresh perspective and recent academic knowledge can add value to the company. | |
| - **Closing:** Express enthusiasm for the opportunity, mention your willingness for an interview, and thank the recipient for their time. | |
| **Email:** | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| email_text = response.content.strip() | |
| return email_text | |
| except Exception as e: | |
| st.error(f"Error generating email: {e}") | |
| return "" | |
| def generate_cover_letter(job_description, requirements, resume_text): | |
| """ | |
| Generates a personalized cover letter using Groq based on the job description, requirements, and resume. | |
| """ | |
| prompt = f""" | |
| You are Adithya S Nair, a recent Computer Science graduate specializing in Artificial Intelligence and Machine Learning. Compose a personalized and professional cover letter based on the following information: | |
| **Job Description:** | |
| {job_description} | |
| **Extracted Requirements:** | |
| {requirements} | |
| **Your Resume:** | |
| {resume_text} | |
| **Cover Letter Requirements:** | |
| 1. **Greeting:** Address the hiring manager by name if available; otherwise, use a generic greeting such as "Dear Hiring Manager." | |
| 2. **Introduction:** Begin with an engaging opening that mentions the specific position you are applying for and conveys your enthusiasm. | |
| 3. **Body:** | |
| - **Skills and Experiences:** Highlight relevant technical skills, projects, internships, and leadership roles that align with the job requirements. | |
| - **Alignment:** Demonstrate how your academic background and hands-on experiences make you a suitable candidate for the role. | |
| 4. **Value Proposition:** Explain how your fresh perspective, recent academic knowledge, and eagerness to learn can contribute to the company's success. | |
| 5. **Conclusion:** End with a strong closing statement expressing your interest in an interview, your availability, and gratitude for the hiring manager’s time and consideration. | |
| 6. **Professional Tone:** Maintain a respectful and professional tone throughout the letter. | |
| **Cover Letter:** | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| cover_letter = response.content.strip() | |
| return cover_letter | |
| except Exception as e: | |
| st.error(f"Error generating cover letter: {e}") | |
| return "" | |
| def extract_skills(text): | |
| """ | |
| Extracts a list of skills from the resume text using Groq. | |
| """ | |
| prompt = f""" | |
| Extract a comprehensive list of technical and soft skills from the following resume text. Provide the skills as a comma-separated list. | |
| Resume Text: | |
| {text} | |
| Skills: | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| skills = response.content.strip() | |
| # Clean and split the skills | |
| skills_list = [skill.strip() for skill in re.split(',|\n', skills) if skill.strip()] | |
| return skills_list | |
| except Exception as e: | |
| st.error(f"Error extracting skills: {e}") | |
| return [] | |
| def suggest_keywords(resume_text, job_description=None): | |
| """ | |
| Suggests additional relevant keywords to enhance resume compatibility with ATS. | |
| """ | |
| prompt = f""" | |
| Analyze the following resume text and suggest additional relevant keywords that can enhance its compatibility with Applicant Tracking Systems (ATS). If a job description is provided, tailor the keywords to align with the job requirements. | |
| Resume Text: | |
| {resume_text} | |
| Job Description: | |
| {job_description if job_description else "N/A"} | |
| Suggested Keywords: | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| keywords = response.content.strip() | |
| keywords_list = [keyword.strip() for keyword in re.split(',|\n', keywords) if keyword.strip()] | |
| return keywords_list | |
| except Exception as e: | |
| st.error(f"Error suggesting keywords: {e}") | |
| return [] | |
| def get_job_recommendations(job_title, location="India"): | |
| """ | |
| Fetches salary estimates using the Job Salary Data API based on the job title and location. | |
| """ | |
| url = "https://job-salary-data.p.rapidapi.com/job-salary" | |
| querystring = { | |
| "job_title": job_title.strip(), | |
| "location": location.strip(), | |
| "radius": "100" # Adjust radius as needed | |
| } | |
| headers = { | |
| "x-rapidapi-key": RAPIDAPI_KEY, # Securely access the API key | |
| "x-rapidapi-host": "job-salary-data.p.rapidapi.com" | |
| } | |
| try: | |
| response = requests.get(url, headers=headers, params=querystring) | |
| response.raise_for_status() | |
| salary_data = response.json() | |
| # Adjust the keys based on the API's response structure | |
| min_salary = salary_data.get("min_salary") | |
| avg_salary = salary_data.get("avg_salary") | |
| max_salary = salary_data.get("max_salary") | |
| if not all([min_salary, avg_salary, max_salary]): | |
| st.error("Incomplete salary data received from the API.") | |
| return {} | |
| return { | |
| "min_salary": min_salary, | |
| "avg_salary": avg_salary, | |
| "max_salary": max_salary | |
| } | |
| except requests.exceptions.HTTPError as http_err: | |
| st.error(f"HTTP error occurred: {http_err}") | |
| return {} | |
| except Exception as err: | |
| st.error(f"An error occurred: {err}") | |
| return {} | |
| def create_skill_distribution_chart(skills): | |
| """ | |
| Creates a bar chart showing the distribution of skills. | |
| """ | |
| skill_counts = {} | |
| for skill in skills: | |
| skill_counts[skill] = skill_counts.get(skill, 0) + 1 | |
| df = pd.DataFrame(list(skill_counts.items()), columns=['Skill', 'Count']) | |
| fig = px.bar(df, x='Skill', y='Count', title='Skill Distribution') | |
| return fig | |
| def create_experience_timeline(resume_text): | |
| """ | |
| Creates an experience timeline from the resume text. | |
| """ | |
| # Extract work experience details using Groq | |
| prompt = f""" | |
| From the following resume text, extract the job titles, companies, and durations of employment. Provide the information in a table format with columns: Job Title, Company, Duration (in years). | |
| Resume Text: | |
| {resume_text} | |
| Table: | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| table_text = response.content.strip() | |
| # Parse the table_text to create a DataFrame | |
| data = [] | |
| for line in table_text.split('\n'): | |
| if line.strip() and not line.lower().startswith("job title"): | |
| parts = line.split('|') | |
| if len(parts) == 3: | |
| job_title = parts[0].strip() | |
| company = parts[1].strip() | |
| duration = parts[2].strip() | |
| # Convert duration to a float representing years | |
| duration_years = parse_duration(duration) | |
| data.append({"Job Title": job_title, "Company": company, "Duration (years)": duration_years}) | |
| df = pd.DataFrame(data) | |
| if not df.empty: | |
| # Create a cumulative duration for timeline | |
| df['Start Year'] = df['Duration (years)'].cumsum() - df['Duration (years)'] | |
| df['End Year'] = df['Duration (years)'].cumsum() | |
| fig = px.timeline(df, x_start="Start Year", x_end="End Year", y="Job Title", color="Company", title="Experience Timeline") | |
| fig.update_yaxes(categoryorder="total ascending") | |
| return fig | |
| else: | |
| return None | |
| except Exception as e: | |
| st.error(f"Error creating experience timeline: {e}") | |
| return None | |
| def parse_duration(duration_str): | |
| """ | |
| Parses duration strings like '2 years' or '6 months' into float years. | |
| """ | |
| try: | |
| if 'year' in duration_str.lower(): | |
| years = float(re.findall(r'\d+\.?\d*', duration_str)[0]) | |
| return years | |
| elif 'month' in duration_str.lower(): | |
| months = float(re.findall(r'\d+\.?\d*', duration_str)[0]) | |
| return months / 12 | |
| else: | |
| return 0 | |
| except: | |
| return 0 | |
| # ------------------------------- | |
| # Database Functions | |
| # ------------------------------- | |
| def init_db(): | |
| """ | |
| Initializes the SQLite database for application tracking. | |
| """ | |
| conn = sqlite3.connect('applications.db') | |
| c = conn.cursor() | |
| c.execute(''' | |
| CREATE TABLE IF NOT EXISTS applications ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| job_title TEXT, | |
| company TEXT, | |
| application_date TEXT, | |
| status TEXT, | |
| deadline TEXT, | |
| notes TEXT, | |
| job_description TEXT, | |
| resume_text TEXT, | |
| skills TEXT | |
| ) | |
| ''') | |
| conn.commit() | |
| conn.close() | |
| def add_application(job_title, company, application_date, status, deadline, notes, job_description, resume_text, skills): | |
| """ | |
| Adds a new application to the database. | |
| """ | |
| conn = sqlite3.connect('applications.db') | |
| c = conn.cursor() | |
| c.execute(''' | |
| INSERT INTO applications (job_title, company, application_date, status, deadline, notes, job_description, resume_text, skills) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) | |
| ''', (job_title, company, application_date, status, deadline, notes, job_description, resume_text, ', '.join(skills))) | |
| conn.commit() | |
| conn.close() | |
| def fetch_applications(): | |
| """ | |
| Fetches all applications from the database. | |
| """ | |
| conn = sqlite3.connect('applications.db') | |
| c = conn.cursor() | |
| c.execute('SELECT * FROM applications') | |
| data = c.fetchall() | |
| conn.close() | |
| applications = [] | |
| for app in data: | |
| applications.append({ | |
| "ID": app[0], | |
| "Job Title": app[1], | |
| "Company": app[2], | |
| "Application Date": app[3], | |
| "Status": app[4], | |
| "Deadline": app[5], | |
| "Notes": app[6], | |
| "Job Description": app[7], | |
| "Resume Text": app[8], | |
| "Skills": app[9].split(', ') if app[9] else [] | |
| }) | |
| return applications | |
| def update_application_status(app_id, new_status): | |
| """ | |
| Updates the status of an application. | |
| """ | |
| conn = sqlite3.connect('applications.db') | |
| c = conn.cursor() | |
| c.execute('UPDATE applications SET status = ? WHERE id = ?', (new_status, app_id)) | |
| conn.commit() | |
| conn.close() | |
| def delete_application(app_id): | |
| """ | |
| Deletes an application from the database. | |
| """ | |
| conn = sqlite3.connect('applications.db') | |
| c = conn.cursor() | |
| c.execute('DELETE FROM applications WHERE id = ?', (app_id,)) | |
| conn.commit() | |
| conn.close() | |
| def generate_learning_path(career_goal, current_skills): | |
| """ | |
| Generates a personalized learning path using Groq based on career goal and current skills. | |
| """ | |
| prompt = f""" | |
| Based on the following career goal and current skills, create a personalized learning path that includes recommended courses, projects, and milestones to achieve the career goal. | |
| **Career Goal:** | |
| {career_goal} | |
| **Current Skills:** | |
| {current_skills} | |
| **Learning Path:** | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| learning_path = response.content.strip() | |
| return learning_path | |
| except Exception as e: | |
| st.error(f"Error generating learning path: {e}") | |
| return "" | |
| # ------------------------------- | |
| # Page Functions | |
| # ------------------------------- | |
| def email_generator_page(): | |
| st.header("Automated Email Generator") | |
| st.write(""" | |
| Generate personalized cold emails based on job postings and your resume. | |
| """) | |
| # Create two columns for input fields | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| job_link = st.text_input("Enter the job link:") | |
| with col2: | |
| uploaded_file = st.file_uploader("Upload your resume (PDF format):", type="pdf") | |
| if st.button("Generate Email"): | |
| if not job_link: | |
| st.error("Please enter a job link.") | |
| return | |
| if not uploaded_file: | |
| st.error("Please upload your resume.") | |
| return | |
| with st.spinner("Processing..."): | |
| # Extract job description | |
| job_description = extract_job_description(job_link) | |
| if not job_description: | |
| st.error("Failed to extract job description.") | |
| return | |
| # Extract requirements | |
| requirements = extract_requirements(job_description) | |
| if not requirements: | |
| st.error("Failed to extract requirements.") | |
| return | |
| # Extract resume text | |
| resume_text = extract_text_from_pdf(uploaded_file) | |
| if not resume_text: | |
| st.error("Failed to extract text from resume.") | |
| return | |
| # Generate email | |
| email_text = generate_email(job_description, requirements, resume_text) | |
| if email_text: | |
| st.subheader("Generated Email:") | |
| st.write(email_text) | |
| # Provide download option | |
| st.download_button( | |
| label="Download Email", | |
| data=email_text, | |
| file_name="generated_email.txt", | |
| mime="text/plain" | |
| ) | |
| else: | |
| st.error("Failed to generate email.") | |
| def cover_letter_generator_page(): | |
| st.header("Automated Cover Letter Generator") | |
| st.write(""" | |
| Generate personalized cover letters based on job postings and your resume. | |
| """) | |
| # Create two columns for input fields | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| job_link = st.text_input("Enter the job link:") | |
| with col2: | |
| uploaded_file = st.file_uploader("Upload your resume (PDF format):", type="pdf") | |
| if st.button("Generate Cover Letter"): | |
| if not job_link: | |
| st.error("Please enter a job link.") | |
| return | |
| if not uploaded_file: | |
| st.error("Please upload your resume.") | |
| return | |
| with st.spinner("Processing..."): | |
| # Extract job description | |
| job_description = extract_job_description(job_link) | |
| if not job_description: | |
| st.error("Failed to extract job description.") | |
| return | |
| # Extract requirements | |
| requirements = extract_requirements(job_description) | |
| if not requirements: | |
| st.error("Failed to extract requirements.") | |
| return | |
| # Extract resume text | |
| resume_text = extract_text_from_pdf(uploaded_file) | |
| if not resume_text: | |
| st.error("Failed to extract text from resume.") | |
| return | |
| # Generate cover letter | |
| cover_letter = generate_cover_letter(job_description, requirements, resume_text) | |
| if cover_letter: | |
| st.subheader("Generated Cover Letter:") | |
| st.write(cover_letter) | |
| # Provide download option | |
| st.download_button( | |
| label="Download Cover Letter", | |
| data=cover_letter, | |
| file_name="generated_cover_letter.txt", | |
| mime="text/plain" | |
| ) | |
| else: | |
| st.error("Failed to generate cover letter.") | |
| def resume_analysis_page(): | |
| st.header("Resume Analysis and Optimization") | |
| uploaded_file = st.file_uploader("Upload your resume (PDF format):", type="pdf") | |
| if uploaded_file: | |
| resume_text = extract_text_from_pdf(uploaded_file) | |
| if resume_text: | |
| st.success("Resume uploaded successfully!") | |
| # Perform analysis | |
| st.subheader("Extracted Information") | |
| # Extracted skills | |
| skills = extract_skills(resume_text) | |
| st.write("**Skills:**", ', '.join(skills) if skills else "No skills extracted.") | |
| # Extract keywords | |
| keywords = suggest_keywords(resume_text) | |
| st.write("**Suggested Keywords for ATS Optimization:**", ', '.join(keywords) if keywords else "No keywords suggested.") | |
| # Provide optimization suggestions | |
| st.subheader("Optimization Suggestions") | |
| if keywords: | |
| st.write("- **Keyword Optimization:** Incorporate the suggested keywords to improve ATS compatibility.") | |
| else: | |
| st.write("- **Keyword Optimization:** No keywords suggested.") | |
| st.write("- **Formatting:** Ensure consistent formatting for headings and bullet points to enhance readability.") | |
| st.write("- **Experience Details:** Provide specific achievements and quantify your accomplishments where possible.") | |
| # Visual Resume Analytics | |
| st.subheader("Visual Resume Analytics") | |
| # Skill Distribution Chart | |
| if skills: | |
| st.write("**Skill Distribution:**") | |
| fig_skills = create_skill_distribution_chart(skills) | |
| st.plotly_chart(fig_skills) | |
| else: | |
| st.write("**Skill Distribution:** No skills to display.") | |
| # Experience Timeline (if applicable) | |
| fig_experience = create_experience_timeline(resume_text) | |
| if fig_experience: | |
| st.write("**Experience Timeline:**") | |
| st.plotly_chart(fig_experience) | |
| else: | |
| st.write("**Experience Timeline:** Not enough data to generate a timeline.") | |
| # Save the resume and analysis to the database | |
| if st.button("Save Resume Analysis"): | |
| add_application( | |
| job_title="N/A", | |
| company="N/A", | |
| application_date=datetime.now().strftime("%Y-%m-%d"), | |
| status="N/A", | |
| deadline="N/A", | |
| notes="Resume Analysis", | |
| job_description="N/A", | |
| resume_text=resume_text, | |
| skills=skills | |
| ) | |
| st.success("Resume analysis saved successfully!") | |
| else: | |
| st.error("Failed to extract text from resume.") | |
| def application_tracking_dashboard(): | |
| st.header("Application Tracking Dashboard") | |
| # Initialize database | |
| init_db() | |
| # Form to add a new application | |
| st.subheader("Add New Application") | |
| with st.form("add_application"): | |
| job_title = st.text_input("Job Title") | |
| company = st.text_input("Company") | |
| application_date = st.date_input("Application Date", datetime.today()) | |
| status = st.selectbox("Status", ["Applied", "Interviewing", "Offered", "Rejected"]) | |
| deadline = st.date_input("Application Deadline", datetime.today() + timedelta(days=30)) | |
| notes = st.text_area("Notes") | |
| uploaded_file = st.file_uploader("Upload Job Description (PDF)", type="pdf") | |
| uploaded_resume = st.file_uploader("Upload Resume (PDF)", type="pdf") | |
| submitted = st.form_submit_button("Add Application") | |
| if submitted: | |
| if uploaded_file: | |
| job_description = extract_text_from_pdf(uploaded_file) | |
| else: | |
| job_description = "" | |
| if uploaded_resume: | |
| resume_text = extract_text_from_pdf(uploaded_resume) | |
| skills = extract_skills(resume_text) | |
| else: | |
| resume_text = "" | |
| skills = [] | |
| add_application( | |
| job_title=job_title, | |
| company=company, | |
| application_date=application_date.strftime("%Y-%m-%d"), | |
| status=status, | |
| deadline=deadline.strftime("%Y-%m-%d"), | |
| notes=notes, | |
| job_description=job_description, | |
| resume_text=resume_text, | |
| skills=skills | |
| ) | |
| st.success("Application added successfully!") | |
| # Display applications | |
| st.subheader("Your Applications") | |
| applications = fetch_applications() | |
| if applications: | |
| df = pd.DataFrame(applications) | |
| df = df.drop(columns=["Job Description", "Resume Text", "Skills"]) | |
| st.dataframe(df) | |
| # Export Button | |
| csv = df.to_csv(index=False).encode('utf-8') | |
| st.download_button( | |
| label="Download Applications as CSV", | |
| data=csv, | |
| file_name='applications.csv', | |
| mime='text/csv', | |
| ) | |
| # Import Button | |
| st.subheader("Import Applications") | |
| uploaded_csv = st.file_uploader("Upload a CSV file", type="csv") | |
| if uploaded_csv: | |
| try: | |
| imported_df = pd.read_csv(uploaded_csv) | |
| # Validate required columns | |
| required_columns = {"Job Title", "Company", "Application Date", "Status", "Deadline", "Notes"} | |
| if not required_columns.issubset(imported_df.columns): | |
| st.error("Uploaded CSV is missing required columns.") | |
| else: | |
| for index, row in imported_df.iterrows(): | |
| job_title = row.get("Job Title", "N/A") | |
| company = row.get("Company", "N/A") | |
| application_date = row.get("Application Date", datetime.now().strftime("%Y-%m-%d")) | |
| status = row.get("Status", "Applied") | |
| deadline = row.get("Deadline", "") | |
| notes = row.get("Notes", "") | |
| job_description = row.get("Job Description", "") | |
| resume_text = row.get("Resume Text", "") | |
| skills = row.get("Skills", "").split(', ') if row.get("Skills") else [] | |
| add_application( | |
| job_title=job_title, | |
| company=company, | |
| application_date=application_date, | |
| status=status, | |
| deadline=deadline, | |
| notes=notes, | |
| job_description=job_description, | |
| resume_text=resume_text, | |
| skills=skills | |
| ) | |
| st.success("Applications imported successfully!") | |
| except Exception as e: | |
| st.error(f"Error importing applications: {e}") | |
| # Actions: Update Status or Delete | |
| for app in applications: | |
| with st.expander(f"{app['Job Title']} at {app['Company']}"): | |
| st.write(f"**Application Date:** {app['Application Date']}") | |
| st.write(f"**Deadline:** {app['Deadline']}") | |
| st.write(f"**Status:** {app['Status']}") | |
| st.write(f"**Notes:** {app['Notes']}") | |
| if app['Job Description']: | |
| st.write("**Job Description:**") | |
| st.write(app['Job Description'][:500] + "...") | |
| if app['Skills']: | |
| st.write("**Skills:**", ', '.join(app['Skills'])) | |
| # Update status | |
| new_status = st.selectbox("Update Status:", ["Applied", "Interviewing", "Offered", "Rejected"], key=f"status_{app['ID']}") | |
| if st.button("Update Status", key=f"update_{app['ID']}"): | |
| update_application_status(app['ID'], new_status) | |
| st.success("Status updated successfully!") | |
| # Delete application | |
| if st.button("Delete Application", key=f"delete_{app['ID']}"): | |
| delete_application(app['ID']) | |
| st.success("Application deleted successfully!") | |
| else: | |
| st.write("No applications found.") | |
| def interview_preparation_module(): | |
| st.header("Interview Preparation") | |
| st.write(""" | |
| Prepare for your interviews with tailored mock questions and expert tips. | |
| """) | |
| # Create two columns for input fields | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| job_title = st.text_input("Enter the job title you're applying for:") | |
| with col2: | |
| company = st.text_input("Enter the company name:") | |
| if st.button("Generate Mock Interview Questions"): | |
| if not job_title or not company: | |
| st.error("Please enter both job title and company name.") | |
| return | |
| with st.spinner("Generating questions..."): | |
| prompt = f""" | |
| Generate a list of 10 interview questions for a {job_title} position at {company}. Include a mix of technical and behavioral questions. | |
| """ | |
| try: | |
| questions = llm.invoke(prompt).content.strip() | |
| st.subheader("Mock Interview Questions:") | |
| st.write(questions) | |
| # Optionally, provide sample answers or tips | |
| if st.checkbox("Show Sample Answers"): | |
| sample_prompt = f""" | |
| Provide sample answers for the following interview questions for a {job_title} position at {company}. | |
| Questions: | |
| {questions} | |
| Sample Answers: | |
| """ | |
| try: | |
| sample_answers = llm.invoke(sample_prompt).content.strip() | |
| st.subheader("Sample Answers:") | |
| st.write(sample_answers) | |
| except Exception as e: | |
| st.error(f"Error generating sample answers: {e}") | |
| except Exception as e: | |
| st.error(f"Error generating interview questions: {e}") | |
| def personalized_learning_paths_module(): | |
| st.header("Personalized Learning Paths") | |
| st.write(""" | |
| Receive tailored learning plans to help you acquire the skills needed for your desired career. | |
| """) | |
| # Create two columns for input fields | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| career_goal = st.text_input("Enter your career goal (e.g., Data Scientist, Machine Learning Engineer):") | |
| with col2: | |
| current_skills = st.text_input("Enter your current skills (comma-separated):") | |
| if st.button("Generate Learning Path"): | |
| if not career_goal or not current_skills: | |
| st.error("Please enter both career goal and current skills.") | |
| return | |
| with st.spinner("Generating your personalized learning path..."): | |
| learning_path = generate_learning_path(career_goal, current_skills) | |
| if learning_path: | |
| st.subheader("Your Personalized Learning Path:") | |
| st.write(learning_path) | |
| else: | |
| st.error("Failed to generate learning path.") | |
| def networking_opportunities_module(): | |
| st.header("Networking Opportunities") | |
| st.write(""" | |
| Expand your professional network by connecting with relevant industry peers and joining professional groups. | |
| """) | |
| # Create two columns for input fields | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| user_skills = st.text_input("Enter your key skills (comma-separated):") | |
| with col2: | |
| industry = st.text_input("Enter your industry (e.g., Technology, Finance):") | |
| if st.button("Find Networking Opportunities"): | |
| if not user_skills or not industry: | |
| st.error("Please enter both key skills and industry.") | |
| return | |
| with st.spinner("Fetching networking opportunities..."): | |
| # Suggest LinkedIn groups or connections based on skills and industry | |
| prompt = f""" | |
| Based on the following skills: {user_skills}, and industry: {industry}, suggest relevant LinkedIn groups, professional organizations, and industry events for networking. | |
| """ | |
| try: | |
| suggestions = llm.invoke(prompt).content.strip() | |
| st.subheader("Recommended Networking Groups and Events:") | |
| st.write(suggestions) | |
| except Exception as e: | |
| st.error(f"Error fetching networking opportunities: {e}") | |
| def salary_estimation_module(): | |
| st.header("Salary Estimation and Negotiation Tips") | |
| st.write(""" | |
| Understand the salary expectations for your desired roles and learn effective negotiation strategies. | |
| """) | |
| # Create two columns for input fields | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| job_title = st.text_input("Enter the job title:") | |
| with col2: | |
| location = st.text_input("Enter the location (e.g., New York, NY, USA):") | |
| if st.button("Get Salary Estimate"): | |
| if not job_title or not location: | |
| st.error("Please enter both job title and location.") | |
| return | |
| with st.spinner("Fetching salary data..."): | |
| # Job Salary Data API Integration | |
| salary_data = get_job_recommendations(job_title, location) | |
| if salary_data: | |
| min_salary = salary_data.get("min_salary") | |
| avg_salary = salary_data.get("avg_salary") | |
| max_salary = salary_data.get("max_salary") | |
| if min_salary and avg_salary and max_salary: | |
| st.subheader("Salary Estimate:") | |
| st.write(f"**Minimum Salary:** ${min_salary:,}") | |
| st.write(f"**Average Salary:** ${avg_salary:,}") | |
| st.write(f"**Maximum Salary:** ${max_salary:,}") | |
| # Visualization | |
| salary_df = pd.DataFrame({ | |
| "Salary Range": ["Minimum", "Average", "Maximum"], | |
| "Amount": [min_salary, avg_salary, max_salary] | |
| }) | |
| fig = px.bar(salary_df, x="Salary Range", y="Amount", | |
| title=f"Salary Estimates for {job_title} in {location}", | |
| labels={"Amount": "Salary (USD)"}, | |
| text_auto=True) | |
| st.plotly_chart(fig) | |
| else: | |
| st.error("Salary data not available for the provided job title and location.") | |
| # Generate negotiation tips using Groq | |
| tips_prompt = f""" | |
| Provide a list of 5 effective tips for negotiating a salary for a {job_title} position in {location}. | |
| """ | |
| try: | |
| tips = llm.invoke(tips_prompt).content.strip() | |
| st.subheader("Negotiation Tips:") | |
| st.write(tips) | |
| except Exception as e: | |
| st.error(f"Error generating negotiation tips: {e}") | |
| else: | |
| st.error("Failed to retrieve salary data.") | |
| def feedback_and_improvement_module(): | |
| st.header("Feedback and Continuous Improvement") | |
| st.write(""" | |
| We value your feedback! Let us know how we can improve your experience. | |
| """) | |
| with st.form("feedback_form"): | |
| name = st.text_input("Your Name") | |
| email = st.text_input("Your Email") | |
| feedback_type = st.selectbox("Type of Feedback", ["Bug Report", "Feature Request", "General Feedback"]) | |
| feedback = st.text_area("Your Feedback") | |
| submitted = st.form_submit_button("Submit") | |
| if submitted: | |
| if not name or not email or not feedback: | |
| st.error("Please fill in all the fields.") | |
| else: | |
| # Here you can implement logic to store feedback, e.g., in a database or send via email | |
| # For demonstration, we'll print to the console | |
| print(f"Feedback from {name} ({email}): {feedback_type} - {feedback}") | |
| st.success("Thank you for your feedback!") | |
| def gamification_module(): | |
| st.header("Gamification and Achievements") | |
| st.write(""" | |
| Stay motivated by earning badges and tracking your progress! | |
| """) | |
| # Initialize database | |
| init_db() | |
| # Example achievements | |
| applications = fetch_applications() | |
| num_apps = len(applications) | |
| achievements = { | |
| "First Application": num_apps >= 1, | |
| "5 Applications": num_apps >= 5, | |
| "10 Applications": num_apps >= 10, | |
| "Resume Optimized": any(app['Skills'] for app in applications), | |
| "Interview Scheduled": any(app['Status'] == 'Interviewing' for app in applications) | |
| } | |
| for achievement, earned in achievements.items(): | |
| if earned: | |
| st.success(f"🎉 {achievement}") | |
| else: | |
| st.info(f"🔜 {achievement}") | |
| # Progress Bar | |
| progress = min(num_apps / 10, 1.0) # Ensure progress is between 0.0 and 1.0 | |
| st.write("**Overall Progress:**") | |
| st.progress(progress) | |
| st.write(f"{progress * 100:.0f}% complete") | |
| def resource_library_page(): | |
| st.header("Resource Library") | |
| st.write(""" | |
| Access a collection of templates and guides to enhance your job search. | |
| """) | |
| resources = [ | |
| { | |
| "title": "Resume Template", | |
| "description": "A professional resume template in DOCX format.", | |
| "file": "./resume_template.docx" | |
| }, | |
| { | |
| "title": "Cover Letter Template", | |
| "description": "A customizable cover letter template.", | |
| "file": "./cover_letter_template.docx" | |
| }, | |
| { | |
| "title": "Job Application Checklist", | |
| "description": "Ensure you have all the necessary steps covered during your job search.", | |
| "file": "./application_checklist.pdf" | |
| } | |
| ] | |
| for resource in resources: | |
| st.markdown(f"### {resource['title']}") | |
| st.write(resource['description']) | |
| try: | |
| with open(resource['file'], "rb") as file: | |
| btn = st.download_button( | |
| label="Download", | |
| data=file, | |
| file_name=os.path.basename(resource['file']), | |
| mime="application/octet-stream" | |
| ) | |
| except FileNotFoundError: | |
| st.error(f"File {resource['file']} not found. Please ensure the file is in the correct directory.") | |
| st.write("---") | |
| def success_stories_page(): | |
| st.header("Success Stories") | |
| st.write(""" | |
| Hear from our users who have successfully landed their dream jobs with our assistance! | |
| """) | |
| # Example testimonials | |
| testimonials = [ | |
| { | |
| "name": "Rahul Sharma", | |
| "position": "Data Scientist at TechCorp", | |
| "testimonial": "This app transformed my job search process. The resume analysis and personalized emails were game-changers!", | |
| "image": "images/user1.jpg" # Replace with actual image paths | |
| }, | |
| { | |
| "name": "Priya Mehta", | |
| "position": "Machine Learning Engineer at InnovateX", | |
| "testimonial": "The interview preparation module helped me ace my interviews with confidence. Highly recommended!", | |
| "image": "images/user2.jpg" | |
| } | |
| ] | |
| for user in testimonials: | |
| col1, col2 = st.columns([1, 3]) | |
| with col1: | |
| try: | |
| st.image(user["image"], width=100) | |
| except: | |
| st.write("") | |
| with col2: | |
| st.write(f"**{user['name']}**") | |
| st.write(f"*{user['position']}*") | |
| st.write(f"\"{user['testimonial']}\"") | |
| st.write("---") | |
| def help_page(): | |
| st.header("Help & FAQ") | |
| with st.expander("How do I generate a cover letter?"): | |
| st.write(""" | |
| To generate a cover letter, navigate to the **Cover Letter Generator** section, enter the job link, upload your resume, and click on **Generate Cover Letter**. | |
| """) | |
| with st.expander("How do I track my applications?"): | |
| st.write(""" | |
| Use the **Application Tracking** dashboard to add new applications, update their status, and monitor deadlines. | |
| """) | |
| with st.expander("How can I optimize my resume?"): | |
| st.write(""" | |
| Upload your resume in the **Resume Analysis** section to extract skills and receive optimization suggestions. | |
| """) | |
| with st.expander("How do I import my applications?"): | |
| st.write(""" | |
| In the **Application Tracking** dashboard, use the **Import Applications** section to upload a CSV file containing your applications. Ensure the CSV has the required columns. | |
| """) | |
| with st.expander("How do I provide feedback?"): | |
| st.write(""" | |
| Navigate to the **Feedback and Continuous Improvement** section, fill out the form, and submit your feedback. | |
| """) | |
| def chatbot_support_page(): | |
| st.header("AI-Powered Chatbot Support") | |
| st.write(""" | |
| Have questions or need assistance? Chat with our AI-powered assistant! | |
| """) | |
| # Initialize session state for chatbot | |
| if 'chat_history' not in st.session_state: | |
| st.session_state['chat_history'] = [] | |
| # User input | |
| user_input = st.text_input("You:", key="user_input") | |
| if st.button("Send"): | |
| if user_input: | |
| # Append user message to chat history | |
| st.session_state['chat_history'].append({"message": user_input, "is_user": True}) | |
| prompt = f""" | |
| You are a helpful assistant for a Job Application Assistant app. Answer the user's query based on the following context: | |
| {user_input} | |
| """ | |
| try: | |
| # Invoke the LLM to get a response | |
| response = llm.invoke(prompt).content.strip() | |
| # Append assistant response to chat history | |
| st.session_state['chat_history'].append({"message": response, "is_user": False}) | |
| except Exception as e: | |
| error_message = "Sorry, I encountered an error while processing your request." | |
| st.session_state['chat_history'].append({"message": error_message, "is_user": False}) | |
| st.error(f"Error in chatbot: {e}") | |
| # Display chat history using streamlit-chat | |
| for chat in st.session_state['chat_history']: | |
| if chat['is_user']: | |
| message(chat['message'], is_user=True, avatar_style="thumbs") | |
| else: | |
| message(chat['message'], is_user=False, avatar_style="bottts") | |
| # ------------------------------- | |
| # Main App Function | |
| # ------------------------------- | |
| def main_app(): | |
| # Apply a consistent theme or style | |
| st.markdown( | |
| """ | |
| <style> | |
| .reportview-container { | |
| background-color: #f5f5f5; | |
| } | |
| .sidebar .sidebar-content { | |
| background-image: linear-gradient(#2e7bcf, #2e7bcf); | |
| color: white; | |
| } | |
| </style> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # Sidebar Navigation | |
| with st.sidebar: | |
| selected = option_menu( | |
| "Main Menu", | |
| ["Email Generator", "Cover Letter Generator", "Resume Analysis", "Application Tracking", | |
| "Interview Preparation", "Personalized Learning Paths", "Networking Opportunities", | |
| "Salary Estimation", "Feedback", "Gamification", "Resource Library", "Success Stories", "Chatbot Support", "Help"], | |
| icons=["envelope", "file-earmark-text", "file-person", "briefcase", "gear", | |
| "book", "people", "currency-dollar", "chat-left-text", "trophy", "collection", "star", "chat", "question-circle"], | |
| menu_icon="cast", | |
| default_index=0, | |
| ) | |
| # Route to the selected page | |
| if selected == "Email Generator": | |
| email_generator_page() | |
| elif selected == "Cover Letter Generator": | |
| cover_letter_generator_page() | |
| elif selected == "Resume Analysis": | |
| resume_analysis_page() | |
| elif selected == "Application Tracking": | |
| application_tracking_dashboard() | |
| elif selected == "Interview Preparation": | |
| interview_preparation_module() | |
| elif selected == "Personalized Learning Paths": | |
| personalized_learning_paths_module() | |
| elif selected == "Networking Opportunities": | |
| networking_opportunities_module() | |
| elif selected == "Salary Estimation": | |
| salary_estimation_module() | |
| elif selected == "Feedback": | |
| feedback_and_improvement_module() | |
| elif selected == "Gamification": | |
| gamification_module() | |
| elif selected == "Resource Library": | |
| resource_library_page() | |
| elif selected == "Success Stories": | |
| success_stories_page() | |
| elif selected == "Chatbot Support": | |
| chatbot_support_page() | |
| elif selected == "Help": | |
| help_page() | |
| if __name__ == "__main__": | |
| main_app() | |