AdithyaSNair commited on
Commit
9d2803a
·
verified ·
1 Parent(s): 83001db

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +370 -237
app.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import streamlit as st
2
  from streamlit_option_menu import option_menu
3
  from langchain_groq import ChatGroq
@@ -10,6 +12,9 @@ import plotly.express as px
10
  import re
11
  import pandas as pd
12
  import json
 
 
 
13
 
14
  # Initialize the LLM with your Groq API key from Streamlit secrets
15
  llm = ChatGroq(
@@ -30,7 +35,7 @@ def extract_text_from_pdf(pdf_file):
30
  text += page.get_text()
31
  return text
32
  except Exception as e:
33
- st.error(f"Error extracting text from resume: {e}")
34
  return ""
35
 
36
  def extract_job_description(job_link):
@@ -159,7 +164,7 @@ def extract_skills(text):
159
 
160
  skills = response.content.strip()
161
  # Clean and split the skills
162
- skills_list = [skill.strip() for skill in re.split(',|\\n', skills) if skill.strip()]
163
  return skills_list
164
 
165
  def suggest_keywords(resume_text, job_description=None):
@@ -183,7 +188,7 @@ def suggest_keywords(resume_text, job_description=None):
183
  response = chain.invoke({})
184
 
185
  keywords = response.content.strip()
186
- keywords_list = [keyword.strip() for keyword in re.split(',|\\n', keywords) if keyword.strip()]
187
  return keywords_list
188
 
189
  def get_job_recommendations(resume_text, location="India"):
@@ -211,7 +216,7 @@ def get_job_recommendations(resume_text, location="India"):
211
  "title": job.get("title"),
212
  "company": job.get("company_name"),
213
  "link": job.get("url"),
214
- "job_description": job.get("description")
215
  }
216
  job_list.append(job_info)
217
  return job_list
@@ -288,265 +293,393 @@ def parse_duration(duration_str):
288
  except:
289
  return 0
290
 
291
- # -------------------------------
292
- # Page Functions
293
- # -------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
 
295
- def email_generator_page():
296
- st.header("Automated Email Generator")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
  st.write("""
299
- This application generates a personalized cold email based on a job posting and your resume.
300
  """)
301
 
302
  # Input fields
303
- job_link = st.text_input("Enter the job link:")
304
- uploaded_file = st.file_uploader("Upload your resume (PDF format):", type="pdf")
305
 
306
- if st.button("Generate Email"):
307
- if not job_link:
308
- st.error("Please enter a job link.")
309
- return
310
- if not uploaded_file:
311
- st.error("Please upload your resume.")
312
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
 
314
- with st.spinner("Processing..."):
315
- # Extract job description
316
- job_description = extract_job_description(job_link)
317
- if not job_description:
318
- st.error("Failed to extract job description.")
319
- return
320
-
321
- # Extract requirements
322
- requirements = extract_requirements(job_description)
323
- if not requirements:
324
- st.error("Failed to extract requirements.")
325
- return
326
-
327
- # Extract resume text
328
- resume_text = extract_text_from_pdf(uploaded_file)
329
- if not resume_text:
330
- st.error("Failed to extract text from resume.")
331
- return
332
-
333
- # Generate email
334
- email_text = generate_email(job_description, requirements, resume_text)
335
- if email_text:
336
- st.subheader("Generated Email:")
337
- st.write(email_text)
338
- # Provide download option
339
- st.download_button(
340
- label="Download Email",
341
- data=email_text,
342
- file_name="generated_email.txt",
343
- mime="text/plain"
344
- )
345
- else:
346
- st.error("Failed to generate email.")
347
 
348
- def cover_letter_generator_page():
349
- st.header("Automated Cover Letter Generator")
 
 
 
 
 
 
 
 
 
350
 
351
  st.write("""
352
- This application generates a personalized cover letter based on a job posting and your resume.
353
  """)
354
 
355
- # Input fields
356
- job_link = st.text_input("Enter the job link:")
357
- uploaded_file = st.file_uploader("Upload your resume (PDF format):", type="pdf")
358
 
359
- if st.button("Generate Cover Letter"):
360
- if not job_link:
361
- st.error("Please enter a job link.")
362
  return
363
- if not uploaded_file:
364
- st.error("Please upload your resume.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
- with st.spinner("Processing..."):
368
- # Extract job description
369
- job_description = extract_job_description(job_link)
370
- if not job_description:
371
- st.error("Failed to extract job description.")
372
- return
373
-
374
- # Extract requirements
375
- requirements = extract_requirements(job_description)
376
- if not requirements:
377
- st.error("Failed to extract requirements.")
378
- return
379
-
380
- # Extract resume text
381
- resume_text = extract_text_from_pdf(uploaded_file)
382
- if not resume_text:
383
- st.error("Failed to extract text from resume.")
384
- return
385
-
386
- # Generate cover letter
387
- cover_letter = generate_cover_letter(job_description, requirements, resume_text)
388
- if cover_letter:
389
- st.subheader("Generated Cover Letter:")
390
- st.write(cover_letter)
391
- # Provide download option
392
- st.download_button(
393
- label="Download Cover Letter",
394
- data=cover_letter,
395
- file_name="generated_cover_letter.txt",
396
- mime="text/plain"
397
- )
398
- else:
399
- st.error("Failed to generate cover letter.")
400
-
401
- def resume_analysis_page():
402
- import pandas as pd # Importing here to prevent unnecessary imports if not used
403
-
404
- st.header("Resume Analysis and Optimization")
405
-
406
- uploaded_file = st.file_uploader("Upload your resume (PDF format):", type="pdf")
407
-
408
- if uploaded_file:
409
- resume_text = extract_text_from_pdf(uploaded_file)
410
- if resume_text:
411
- st.success("Resume uploaded successfully!")
412
- # Perform analysis
413
- st.subheader("Extracted Information")
414
- # Extracted skills
415
- skills = extract_skills(resume_text)
416
- st.write("**Skills:**", ', '.join(skills))
417
- # Extract keywords
418
- keywords = suggest_keywords(resume_text)
419
- st.write("**Suggested Keywords for ATS Optimization:**", ', '.join(keywords))
420
- # Provide optimization suggestions
421
- st.subheader("Optimization Suggestions")
422
- st.write("- **Keyword Optimization:** Incorporate the suggested keywords to improve ATS compatibility.")
423
- st.write("- **Formatting:** Ensure consistent formatting for headings and bullet points to enhance readability.")
424
- st.write("- **Experience Details:** Provide specific achievements and quantify your accomplishments where possible.")
425
-
426
- # Visual Resume Analytics
427
- st.subheader("Visual Resume Analytics")
428
- # Skill Distribution Chart
429
- if skills:
430
- st.write("**Skill Distribution:**")
431
- fig_skills = create_skill_distribution_chart(skills)
432
- st.plotly_chart(fig_skills)
433
-
434
- # Experience Timeline (if applicable)
435
- fig_experience = create_experience_timeline(resume_text)
436
- if fig_experience:
437
- st.write("**Experience Timeline:**")
438
- st.plotly_chart(fig_experience)
439
- else:
440
- st.write("**Experience Timeline:** Not enough data to generate a timeline.")
441
- else:
442
- st.error("Failed to extract text from resume.")
443
-
444
- def job_recommendations_page():
445
- st.header("Job Recommendations")
446
-
447
- uploaded_file = st.file_uploader("Upload your resume (PDF format):", type="pdf")
448
-
449
- if uploaded_file:
450
- resume_text = extract_text_from_pdf(uploaded_file)
451
- if resume_text:
452
- st.success("Resume uploaded successfully!")
453
- # Fetch job recommendations
454
- st.subheader("Recommended Jobs")
455
- jobs = get_job_recommendations(resume_text)
456
- if jobs:
457
- for idx, job in enumerate(jobs, 1):
458
- st.markdown(f"### Job {idx}")
459
- st.write(f"**{job['title']}** at **{job['company']}**")
460
- st.markdown(f"[Apply Here]({job['link']})")
461
- st.write("---")
462
- else:
463
- st.write("No job recommendations found based on your skills.")
464
- else:
465
- st.error("Failed to extract text from resume.")
466
-
467
- def skill_matching_page():
468
- st.header("Skill Matching and Gap Analysis")
469
-
470
- uploaded_file = st.file_uploader("Upload your resume (PDF format):", type="pdf")
471
-
472
- # Fetch job recommendations once resume is uploaded
473
- if uploaded_file:
474
- resume_text = extract_text_from_pdf(uploaded_file)
475
- if resume_text:
476
- st.success("Resume uploaded successfully!")
477
- # Fetch job recommendations
478
- jobs = get_job_recommendations(resume_text)
479
- if jobs:
480
- # Display job recommendations with selection
481
- job_titles = [f"{job['title']} at {job['company']}" for job in jobs]
482
- selected_job = st.selectbox("Select a job for Skill Matching:", job_titles)
483
- if selected_job:
484
- # Find the selected job's details
485
- selected_index = job_titles.index(selected_job)
486
- selected_job_info = jobs[selected_index]
487
- job_description = selected_job_info['job_description']
488
-
489
- # Extract requirements
490
- requirements = extract_requirements(job_description)
491
- if not requirements:
492
- st.error("Failed to extract requirements.")
493
- return
494
-
495
- # Extract skills from resume
496
- resume_skills = extract_skills(resume_text)
497
- job_skills = extract_skills(job_description)
498
-
499
- # Find matches and gaps
500
- matching_skills = set(resume_skills).intersection(set(job_skills))
501
- missing_skills = set(job_skills) - set(resume_skills)
502
-
503
- # Display results
504
- st.subheader("Matching Skills")
505
- st.write(', '.join(matching_skills) if matching_skills else "No matching skills found.")
506
-
507
- st.subheader("Missing Skills")
508
- st.write(', '.join(missing_skills) if missing_skills else "No missing skills.")
509
-
510
- # Provide suggestions
511
- st.subheader("Suggestions for Improvement")
512
- if missing_skills:
513
- st.write("- **Acquire Missing Skills:** Consider pursuing courses or certifications in the following areas:")
514
- for skill in missing_skills:
515
- st.write(f" - {skill}")
516
- else:
517
- st.write("You have all the required skills for this job!")
518
 
 
 
 
519
  else:
520
- st.write("No job recommendations found based on your skills.")
521
- else:
522
- st.error("Failed to extract text from resume.")
523
- else:
524
- st.write("Please upload your resume to perform Skill Matching.")
 
 
 
 
 
 
 
 
 
 
 
 
 
525
 
 
 
526
 
 
 
 
527
 
528
  def main():
529
  st.set_page_config(page_title="Job Application Assistant", layout="wide")
530
 
531
- with st.sidebar:
532
- selected = option_menu(
533
- "Main Menu",
534
- ["Email Generator", "Cover Letter Generator", "Resume Analysis", "Job Recommendations", "Skill Matching"],
535
- icons=["envelope", "file-earmark-text", "file-person", "briefcase", "bar-chart"],
536
- menu_icon="cast",
537
- default_index=0,
538
- )
539
-
540
- if selected == "Email Generator":
541
- email_generator_page()
542
- elif selected == "Cover Letter Generator":
543
- cover_letter_generator_page()
544
- elif selected == "Resume Analysis":
545
- resume_analysis_page()
546
- elif selected == "Job Recommendations":
547
- job_recommendations_page()
548
- elif selected == "Skill Matching":
549
- skill_matching_page()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
 
551
  if __name__ == "__main__":
552
  main()
 
1
+ # app.py
2
+
3
  import streamlit as st
4
  from streamlit_option_menu import option_menu
5
  from langchain_groq import ChatGroq
 
12
  import re
13
  import pandas as pd
14
  import json
15
+ import sqlite3
16
+ import streamlit_authenticator as stauth
17
+ from datetime import datetime, timedelta
18
 
19
  # Initialize the LLM with your Groq API key from Streamlit secrets
20
  llm = ChatGroq(
 
35
  text += page.get_text()
36
  return text
37
  except Exception as e:
38
+ st.error(f"Error extracting text from PDF: {e}")
39
  return ""
40
 
41
  def extract_job_description(job_link):
 
164
 
165
  skills = response.content.strip()
166
  # Clean and split the skills
167
+ skills_list = [skill.strip() for skill in re.split(',|\n', skills) if skill.strip()]
168
  return skills_list
169
 
170
  def suggest_keywords(resume_text, job_description=None):
 
188
  response = chain.invoke({})
189
 
190
  keywords = response.content.strip()
191
+ keywords_list = [keyword.strip() for keyword in re.split(',|\n', keywords) if keyword.strip()]
192
  return keywords_list
193
 
194
  def get_job_recommendations(resume_text, location="India"):
 
216
  "title": job.get("title"),
217
  "company": job.get("company_name"),
218
  "link": job.get("url"),
219
+ "job_description": job.get("description") # Including job description for Skill Matching
220
  }
221
  job_list.append(job_info)
222
  return job_list
 
293
  except:
294
  return 0
295
 
296
+ def init_db():
297
+ """
298
+ Initializes the SQLite database for application tracking.
299
+ """
300
+ conn = sqlite3.connect('applications.db')
301
+ c = conn.cursor()
302
+ c.execute('''
303
+ CREATE TABLE IF NOT EXISTS applications (
304
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
305
+ job_title TEXT,
306
+ company TEXT,
307
+ application_date TEXT,
308
+ status TEXT,
309
+ deadline TEXT,
310
+ notes TEXT,
311
+ job_description TEXT,
312
+ resume_text TEXT,
313
+ skills TEXT
314
+ )
315
+ ''')
316
+ conn.commit()
317
+ conn.close()
318
+
319
+ def add_application(job_title, company, application_date, status, deadline, notes, job_description, resume_text, skills):
320
+ """
321
+ Adds a new application to the database.
322
+ """
323
+ conn = sqlite3.connect('applications.db')
324
+ c = conn.cursor()
325
+ c.execute('''
326
+ INSERT INTO applications (job_title, company, application_date, status, deadline, notes, job_description, resume_text, skills)
327
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
328
+ ''', (job_title, company, application_date, status, deadline, notes, job_description, resume_text, ', '.join(skills)))
329
+ conn.commit()
330
+ conn.close()
331
+
332
+ def fetch_applications():
333
+ """
334
+ Fetches all applications from the database.
335
+ """
336
+ conn = sqlite3.connect('applications.db')
337
+ c = conn.cursor()
338
+ c.execute('SELECT * FROM applications')
339
+ data = c.fetchall()
340
+ conn.close()
341
+ applications = []
342
+ for app in data:
343
+ applications.append({
344
+ "ID": app[0],
345
+ "Job Title": app[1],
346
+ "Company": app[2],
347
+ "Application Date": app[3],
348
+ "Status": app[4],
349
+ "Deadline": app[5],
350
+ "Notes": app[6],
351
+ "Job Description": app[7],
352
+ "Resume Text": app[8],
353
+ "Skills": app[9].split(', ')
354
+ })
355
+ return applications
356
+
357
+ def update_application_status(app_id, new_status):
358
+ """
359
+ Updates the status of an application.
360
+ """
361
+ conn = sqlite3.connect('applications.db')
362
+ c = conn.cursor()
363
+ c.execute('UPDATE applications SET status = ? WHERE id = ?', (new_status, app_id))
364
+ conn.commit()
365
+ conn.close()
366
+
367
+ def delete_application(app_id):
368
+ """
369
+ Deletes an application from the database.
370
+ """
371
+ conn = sqlite3.connect('applications.db')
372
+ c = conn.cursor()
373
+ c.execute('DELETE FROM applications WHERE id = ?', (app_id,))
374
+ conn.commit()
375
+ conn.close()
376
 
377
+ def generate_learning_path(career_goal, current_skills):
378
+ """
379
+ Generates a personalized learning path using Groq based on career goal and current skills.
380
+ """
381
+ prompt = f"""
382
+ 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.
383
+
384
+ **Career Goal:**
385
+ {career_goal}
386
+
387
+ **Current Skills:**
388
+ {current_skills}
389
+
390
+ **Learning Path:**
391
+ """
392
+
393
+ response = llm.invoke({"input": prompt})
394
+ learning_path = response.content.strip()
395
+ return learning_path
396
+
397
+ def setup_authentication():
398
+ """
399
+ Sets up user authentication using streamlit-authenticator.
400
+ """
401
+ # In a real application, retrieve user data from a secure database
402
+ names = ["Adithya S Nair"] # Replace with dynamic user data
403
+ usernames = ["adithya"]
404
+ # Passwords should be hashed in a real application
405
+ passwords = ["$2b$12$KIXvUq2YdZ19FWJGzTqFUeAewH1/gO7xmD2z77Qvxh3A1F1C9KdaW"] # "password" hashed
406
+
407
+ authenticator = stauth.Authenticate(names, usernames, passwords, "job_app_assistant", "abcdef", cookie_expiry_days=30)
408
+ return authenticator
409
+
410
+ def application_tracking_dashboard():
411
+ st.header("Application Tracking Dashboard")
412
+
413
+ # Initialize database
414
+ init_db()
415
+
416
+ # Form to add a new application
417
+ st.subheader("Add New Application")
418
+ with st.form("add_application"):
419
+ job_title = st.text_input("Job Title")
420
+ company = st.text_input("Company")
421
+ application_date = st.date_input("Application Date", datetime.today())
422
+ status = st.selectbox("Status", ["Applied", "Interviewing", "Offered", "Rejected"])
423
+ deadline = st.date_input("Application Deadline", datetime.today() + timedelta(days=30))
424
+ notes = st.text_area("Notes")
425
+ uploaded_file = st.file_uploader("Upload Job Description (PDF)", type="pdf")
426
+ uploaded_resume = st.file_uploader("Upload Resume (PDF)", type="pdf")
427
+ submitted = st.form_submit_button("Add Application")
428
+ if submitted:
429
+ if uploaded_file:
430
+ job_description = extract_text_from_pdf(uploaded_file)
431
+ else:
432
+ job_description = ""
433
+ if uploaded_resume:
434
+ resume_text = extract_text_from_pdf(uploaded_resume)
435
+ skills = extract_skills(resume_text)
436
+ else:
437
+ resume_text = ""
438
+ skills = []
439
+ add_application(
440
+ job_title=job_title,
441
+ company=company,
442
+ application_date=application_date.strftime("%Y-%m-%d"),
443
+ status=status,
444
+ deadline=deadline.strftime("%Y-%m-%d"),
445
+ notes=notes,
446
+ job_description=job_description,
447
+ resume_text=resume_text,
448
+ skills=skills
449
+ )
450
+ st.success("Application added successfully!")
451
+
452
+ # Display applications
453
+ st.subheader("Your Applications")
454
+ applications = fetch_applications()
455
+ if applications:
456
+ df = pd.DataFrame(applications)
457
+ df = df.drop(columns=["Job Description", "Resume Text", "Skills"])
458
+ st.dataframe(df)
459
+
460
+ # Actions: Update Status or Delete
461
+ for app in applications:
462
+ with st.expander(f"{app['Job Title']} at {app['Company']}"):
463
+ st.write(f"**Application Date:** {app['Application Date']}")
464
+ st.write(f"**Deadline:** {app['Deadline']}")
465
+ st.write(f"**Status:** {app['Status']}")
466
+ st.write(f"**Notes:** {app['Notes']}")
467
+ if app['Job Description']:
468
+ st.write("**Job Description:**")
469
+ st.write(app['Job Description'][:500] + "...")
470
+ if app['Skills']:
471
+ st.write("**Skills:**", ', '.join(app['Skills']))
472
+ # Update status
473
+ new_status = st.selectbox("Update Status:", ["Applied", "Interviewing", "Offered", "Rejected"], key=f"status_{app['ID']}")
474
+ if st.button("Update Status", key=f"update_{app['ID']}"):
475
+ update_application_status(app['ID'], new_status)
476
+ st.success("Status updated successfully!")
477
+ # Delete application
478
+ if st.button("Delete Application", key=f"delete_{app['ID']}"):
479
+ delete_application(app['ID'])
480
+ st.success("Application deleted successfully!")
481
+ else:
482
+ st.write("No applications found.")
483
+
484
+ def interview_preparation_module():
485
+ st.header("Interview Preparation")
486
 
487
  st.write("""
488
+ Prepare for your interviews with tailored mock questions and expert tips.
489
  """)
490
 
491
  # Input fields
492
+ job_title = st.text_input("Enter the job title you're applying for:")
493
+ company = st.text_input("Enter the company name:")
494
 
495
+ if st.button("Generate Mock Interview Questions"):
496
+ if not job_title or not company:
497
+ st.error("Please enter both job title and company name.")
 
 
 
498
  return
499
+ with st.spinner("Generating questions..."):
500
+ prompt = f"""
501
+ Generate a list of 10 interview questions for a {job_title} position at {company}. Include a mix of technical and behavioral questions.
502
+ """
503
+ questions = llm.invoke({"input": prompt}).content.strip()
504
+ st.subheader("Mock Interview Questions:")
505
+ st.write(questions)
506
+
507
+ # Optionally, provide sample answers or tips
508
+ if st.checkbox("Show Sample Answers"):
509
+ sample_prompt = f"""
510
+ Provide sample answers for the following interview questions for a {job_title} position at {company}.
511
+
512
+ Questions:
513
+ {questions}
514
+
515
+ Sample Answers:
516
+ """
517
+ sample_answers = llm.invoke({"input": sample_prompt}).content.strip()
518
+ st.subheader("Sample Answers:")
519
+ st.write(sample_answers)
520
+
521
+ def personalized_learning_paths_module():
522
+ st.header("Personalized Learning Paths")
523
 
524
+ st.write("""
525
+ Receive tailored learning plans to help you acquire the skills needed for your desired career.
526
+ """)
527
+
528
+ # Input fields
529
+ career_goal = st.text_input("Enter your career goal (e.g., Data Scientist, Machine Learning Engineer):")
530
+ current_skills = st.text_input("Enter your current skills (comma-separated):")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531
 
532
+ if st.button("Generate Learning Path"):
533
+ if not career_goal or not current_skills:
534
+ st.error("Please enter both career goal and current skills.")
535
+ return
536
+ with st.spinner("Generating your personalized learning path..."):
537
+ learning_path = generate_learning_path(career_goal, current_skills)
538
+ st.subheader("Your Personalized Learning Path:")
539
+ st.write(learning_path)
540
+
541
+ def networking_opportunities_module():
542
+ st.header("Networking Opportunities")
543
 
544
  st.write("""
545
+ Expand your professional network by connecting with relevant industry peers and joining professional groups.
546
  """)
547
 
548
+ user_skills = st.text_input("Enter your key skills (comma-separated):")
549
+ industry = st.text_input("Enter your industry (e.g., Technology, Finance):")
 
550
 
551
+ if st.button("Find Networking Opportunities"):
552
+ if not user_skills or not industry:
553
+ st.error("Please enter both key skills and industry.")
554
  return
555
+ with st.spinner("Fetching networking opportunities..."):
556
+ # Suggest LinkedIn groups or connections based on skills and industry
557
+ prompt = f"""
558
+ Based on the following skills: {user_skills}, and industry: {industry}, suggest relevant LinkedIn groups, professional organizations, and industry events for networking.
559
+ """
560
+ suggestions = llm.invoke({"input": prompt}).content.strip()
561
+ st.subheader("Recommended Networking Groups and Events:")
562
+ st.write(suggestions)
563
+
564
+ def salary_estimation_module():
565
+ st.header("Salary Estimation and Negotiation Tips")
566
+
567
+ st.write("""
568
+ Understand the salary expectations for your desired roles and learn effective negotiation strategies.
569
+ """)
570
+
571
+ job_title = st.text_input("Enter the job title:")
572
+ location = st.text_input("Enter the location (e.g., Bangalore, India):")
573
+
574
+ if st.button("Get Salary Estimate"):
575
+ if not job_title or not location:
576
+ st.error("Please enter both job title and location.")
577
  return
578
+ with st.spinner("Fetching salary data..."):
579
+ # Example using a placeholder API or precompiled data
580
+ # Replace with actual API integration if available
581
+ # For demonstration, we'll use a mock response
582
+ prompt = f"""
583
+ Provide an estimated salary range for a {job_title} in {location}. Include the minimum, average, and maximum salaries.
584
+ """
585
+ salary_data = llm.invoke({"input": prompt}).content.strip()
586
+ st.subheader("Salary Estimate:")
587
+ st.write(salary_data)
588
+
589
+ # Generate negotiation tips
590
+ tips_prompt = f"""
591
+ Provide a list of 5 effective tips for negotiating a salary for a {job_title} position in {location}.
592
+ """
593
+ tips = llm.invoke({"input": tips_prompt}).content.strip()
594
+ st.subheader("Negotiation Tips:")
595
+ st.write(tips)
596
+
597
+ def feedback_and_improvement_module():
598
+ st.header("Feedback and Continuous Improvement")
599
 
600
+ st.write("""
601
+ We value your feedback! Let us know how we can improve your experience.
602
+ """)
603
+
604
+ with st.form("feedback_form"):
605
+ name = st.text_input("Your Name")
606
+ email = st.text_input("Your Email")
607
+ feedback_type = st.selectbox("Type of Feedback", ["Bug Report", "Feature Request", "General Feedback"])
608
+ feedback = st.text_area("Your Feedback")
609
+ submitted = st.form_submit_button("Submit")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
610
 
611
+ if submitted:
612
+ if not name or not email or not feedback:
613
+ st.error("Please fill in all the fields.")
614
  else:
615
+ # Here you can implement logic to store feedback, e.g., in a database or send via email
616
+ # For demonstration, we'll print to the console
617
+ print(f"Feedback from {name} ({email}): {feedback_type} - {feedback}")
618
+ st.success("Thank you for your feedback!")
619
+
620
+ # -------------------------------
621
+ # Authentication Setup
622
+ # -------------------------------
623
+
624
+ def setup_authentication():
625
+ """
626
+ Sets up user authentication using streamlit-authenticator.
627
+ """
628
+ # In a real application, retrieve user data from a secure database
629
+ names = ["Adithya S Nair"] # Replace with dynamic user data
630
+ usernames = ["adithya"]
631
+ # Passwords should be hashed in a real application
632
+ passwords = ["$2b$12$KIXvUq2YdZ19FWJGzTqFUeAewH1/gO7xmD2z77Qvxh3A1F1C9KdaW"] # "password" hashed
633
 
634
+ authenticator = stauth.Authenticate(names, usernames, passwords, "job_app_assistant", "abcdef", cookie_expiry_days=30)
635
+ return authenticator
636
 
637
+ # -------------------------------
638
+ # Main App with Sidebar Navigation
639
+ # -------------------------------
640
 
641
  def main():
642
  st.set_page_config(page_title="Job Application Assistant", layout="wide")
643
 
644
+ # Setup authentication
645
+ authenticator = setup_authentication()
646
+ name, authentication_status = authenticator.login("Login", "main")
647
+
648
+ if authentication_status:
649
+ with st.sidebar:
650
+ selected = option_menu(
651
+ "Main Menu",
652
+ ["Email Generator", "Cover Letter Generator", "Resume Analysis", "Application Tracking",
653
+ "Interview Preparation", "Personalized Learning Paths", "Networking Opportunities",
654
+ "Salary Estimation", "Feedback"],
655
+ icons=["envelope", "file-earmark-text", "file-person", "briefcase", "gear",
656
+ "book", "people", "currency-dollar", "chat-left-text"],
657
+ menu_icon="cast",
658
+ default_index=0,
659
+ )
660
+
661
+ if selected == "Email Generator":
662
+ email_generator_page()
663
+ elif selected == "Cover Letter Generator":
664
+ cover_letter_generator_page()
665
+ elif selected == "Resume Analysis":
666
+ resume_analysis_page()
667
+ elif selected == "Application Tracking":
668
+ application_tracking_dashboard()
669
+ elif selected == "Interview Preparation":
670
+ interview_preparation_module()
671
+ elif selected == "Personalized Learning Paths":
672
+ personalized_learning_paths_module()
673
+ elif selected == "Networking Opportunities":
674
+ networking_opportunities_module()
675
+ elif selected == "Salary Estimation":
676
+ salary_estimation_module()
677
+ elif selected == "Feedback":
678
+ feedback_and_improvement_module()
679
+ elif authentication_status == False:
680
+ st.error("Username/password is incorrect")
681
+ elif authentication_status == None:
682
+ st.warning("Please enter your username and password")
683
 
684
  if __name__ == "__main__":
685
  main()