# app.py 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 GROQ_API_KEY = "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" RAPIDAPI_KEY = "2a4a8a38a9msh97ce530a89589a6p1d0106jsn1acc0a5ea6bc" 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 JSearch API based on the job title and location. """ url = "https://jsearch.p.rapidapi.com/estimated-salary" querystring = { "job_title": job_title.strip(), "location": location.strip(), "radius": "100" # Adjust radius as needed } headers = { "x-rapidapi-key": RAPIDAPI_KEY, # Embedded API key "x-rapidapi-host": "jsearch.p.rapidapi.com" } try: response = requests.get(url, headers=headers, params=querystring) response.raise_for_status() salary_data = response.json() # Extract relevant data min_salary = salary_data.get("min_salary") avg_salary = salary_data.get("avg_salary") max_salary = salary_data.get("max_salary") 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 e: st.error(f"Error fetching salary data: {e}") 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 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. """) # Input fields job_link = st.text_input("Enter the job link:") 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. """) # Input fields job_link = st.text_input("Enter the job link:") 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) # 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. """) # Input fields job_title = st.text_input("Enter the job title you're applying for:") 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. """) # Input fields career_goal = st.text_input("Enter your career goal (e.g., Data Scientist, Machine Learning Engineer):") 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. """) user_skills = st.text_input("Enter your key skills (comma-separated):") 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. """) # Input fields job_title = st.text_input("Enter the job title:") 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..."): # JSearch 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: 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) 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=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("![User Image](https://via.placeholder.com/100)") with col2: st.write(f"**{user['name']}**") st.write(f"*{user['position']}*") st.write(f"\"{user['testimonial']}\"") st.write("---") 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 = st.text_input("You:", key="user_input") if st.button("Send"): if user_input: st.session_state['chat_history'].append(f"You: {user_input}") 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: response = llm.invoke(prompt).content.strip() st.session_state['chat_history'].append(f"Assistant: {response}") except Exception as e: st.session_state['chat_history'].append(f"Assistant: Sorry, I encountered an error while processing your request.") st.error(f"Error in chatbot: {e}") # Display chat history for message in st.session_state['chat_history']: if message.startswith("You:"): st.markdown(f"

{message}

", unsafe_allow_html=True) else: st.markdown(f"

{message}

", unsafe_allow_html=True) def main(): st.set_page_config(page_title="Job Application Assistant", layout="wide") # Initialize database early to ensure tables exist init_db() # 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"], icons=["envelope", "file-earmark-text", "file-person", "briefcase", "gear", "book", "people", "currency-dollar", "chat-left-text", "trophy", "collection", "star", "chat"], menu_icon="cast", default_index=0, ) 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() if __name__ == "__main__": main()