diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -1,5 +1,3 @@
-# app.py
-
import streamlit as st
from streamlit_option_menu import option_menu
from langchain_groq import ChatGroq
@@ -14,9 +12,9 @@ from datetime import datetime, timedelta
from streamlit_chat import message
import streamlit_authenticator as stauth
import yaml
+import json
import os
-# Ensure API keys are stored securely using secrets.toml
GROQ_API_KEY = st.secrets["GROQ_API_KEY"]
RAPIDAPI_KEY = st.secrets["RAPIDAPI_KEY"]
@@ -27,1150 +25,1180 @@ llm = ChatGroq(
)
def load_authentication():
+ """
+ Loads and parses authentication configurations from Streamlit secrets.
+
+ Returns:
+ dict: Parsed authentication configurations with 'credentials' and 'cookie' as dictionaries.
+ """
# Load authentication config from secrets.toml
config = st.secrets["auth"]
+
+ # Parse credentials from YAML string to dict
+ try:
+ config['credentials'] = yaml.safe_load(config['credentials'])
+ except yaml.YAMLError as e:
+ st.error(f"Error parsing credentials: {e}")
+ return {}
+
+ # Parse cookie from JSON string to dict
+ try:
+ config['cookie'] = json.loads(config['cookie'])
+ except json.JSONDecodeError as e:
+ st.error(f"Error parsing cookie configuration: {e}")
+ return {}
+
return config
config = load_authentication()
-authenticator = stauth.Authenticate(
- config['credentials'],
- config['cookie']['name'],
- config['cookie']['key'],
- config['cookie']['expiry_days']
-)
-
-name, authentication_status, username = authenticator.login('Login', 'main')
-
-if authentication_status:
- authenticator.logout('Logout', 'sidebar')
- st.sidebar.success(f'Welcome *{name}*')
-
-
- @st.cache_data(ttl=3600)
- 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 ""
-
- @st.cache_data(ttl=3600)
- def extract_job_description(job_link):
- """
- Fetches and extracts job description text from a given URL.
- """
- try:
+if config:
+ authenticator = stauth.Authenticate(
+ config['credentials'],
+ config['cookie']['name'],
+ config['cookie']['key'],
+ config['cookie']['expiry_days']
+ )
+
+ name, authentication_status, username = authenticator.login('Login', 'main')
+
+ if authentication_status:
+ authenticator.logout('Logout', 'sidebar')
+ st.sidebar.success(f'Welcome *{name}*')
+
+ # Proceed with the rest of the app
+ # -------------------------------
+ # Define Helper Functions with Caching
+ # -------------------------------
+
+ @st.cache_data(ttl=3600)
+ 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 ""
+
+ @st.cache_data(ttl=3600)
+ 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 ""
+
+ @st.cache_data(ttl=3600)
+ 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 ""
+
+ @st.cache_data(ttl=3600)
+ 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 ""
+
+ @st.cache_data(ttl=3600)
+ 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 ""
+
+ @st.cache_data(ttl=3600)
+ 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 []
+
+ @st.cache_data(ttl=3600)
+ 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 []
+
+ @st.cache_data(ttl=3600)
+ 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 = {
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
+ "x-rapidapi-key": RAPIDAPI_KEY, # Securely access the API key
+ "x-rapidapi-host": "job-salary-data.p.rapidapi.com"
}
- 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 ""
-
- @st.cache_data(ttl=3600)
- 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 ""
-
- @st.cache_data(ttl=3600)
- 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 ""
-
- @st.cache_data(ttl=3600)
- 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 ""
-
- @st.cache_data(ttl=3600)
- 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 []
-
- @st.cache_data(ttl=3600)
- 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 []
-
- @st.cache_data(ttl=3600)
- 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.")
+
+ 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 {}
-
- 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:
+ 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
- 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:
+
+ 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
- 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.")
+
+ # -------------------------------
+ # 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
-
- # Extract resume text
- resume_text = extract_text_from_pdf(uploaded_file)
- if not resume_text:
- st.error("Failed to extract text from resume.")
+ if not uploaded_file:
+ st.error("Please upload your 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.")
+
+ 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
-
- # Extract requirements
- requirements = extract_requirements(job_description)
- if not requirements:
- st.error("Failed to extract requirements.")
+ if not uploaded_file:
+ st.error("Please upload your resume.")
return
-
- # Extract resume text
+
+ 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 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)
+ 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.write("**Experience Timeline:** Not enough data to generate a timeline.")
-
- # Save the resume and analysis to the database
- if st.button("Save Resume Analysis"):
+ 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="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",
+ 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("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',
)
- 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)
+
+ # 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("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}.
+ 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:
- tips = llm.invoke(tips_prompt).content.strip()
- st.subheader("Negotiation Tips:")
- st.write(tips)
+ suggestions = llm.invoke(prompt).content.strip()
+ st.subheader("Recommended Networking Groups and Events:")
+ st.write(suggestions)
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])
+ 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:
- try:
- st.image(user["image"], width=100)
- except:
- st.write("")
+ job_title = st.text_input("Enter the job title:")
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?"):
+ 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("""
- 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**.
+ We value your feedback! Let us know how we can improve your experience.
""")
-
- with st.expander("How do I track my applications?"):
+
+ 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("""
- Use the **Application Tracking** dashboard to add new applications, update their status, and monitor deadlines.
+ Stay motivated by earning badges and tracking your progress!
""")
-
- with st.expander("How can I optimize my resume?"):
+
+ # 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("""
- Upload your resume in the **Resume Analysis** section to extract skills and receive optimization suggestions.
+ Access a collection of templates and guides to enhance your job search.
""")
-
- with st.expander("How do I import my applications?"):
+
+ 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("""
- 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.
+ Hear from our users who have successfully landed their dream jobs with our assistance!
""")
-
- with st.expander("How do I provide feedback?"):
+
+ # 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("""
- Navigate to the **Feedback and Continuous Improvement** section, fill out the form, and submit your feedback.
+ Have questions or need assistance? Chat with our AI-powered assistant!
""")
-
- 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}
+
+ # 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(
"""
- 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")
-
-
- def main_app():
- # Apply a consistent theme or style
- st.markdown(
- """
-
- """,
- 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,
+
+ """,
+ unsafe_allow_html=True
)
-
- # 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()
-
-elif authentication_status == False:
- st.error('Username/password is incorrect')
-elif authentication_status == None:
- st.warning('Please enter your username and password')
+
+ # 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()
+
+ elif authentication_status == False:
+ st.error('Username/password is incorrect')
+ elif authentication_status == None:
+ st.warning('Please enter your username and password')
\ No newline at end of file