ZainabFatimaa commited on
Commit
59b80ef
Β·
verified Β·
1 Parent(s): f816567

Update src/app.py

Browse files
Files changed (1) hide show
  1. src/app.py +333 -199
src/app.py CHANGED
@@ -4,6 +4,9 @@ import numpy as np
4
  import re
5
  import io
6
  import base64
 
 
 
7
  from collections import Counter
8
  import matplotlib.pyplot as plt
9
  import seaborn as sns
@@ -58,6 +61,58 @@ from reportlab.lib.units import inch
58
  from reportlab.graphics.charts.barcharts import VerticalBarChart
59
  from reportlab.graphics.shapes import Drawing
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  # Download NLTK data if not already present
62
  @st.cache_resource
63
  def download_nltk_data():
@@ -146,6 +201,7 @@ def basic_grammar_check(text):
146
  class ResumeAnalyzer:
147
  def __init__(self):
148
  self.nlp, self.grammar_tool = init_tools()
 
149
 
150
  try:
151
  self.stop_words = set(stopwords.words('english'))
@@ -155,32 +211,55 @@ class ResumeAnalyzer:
155
 
156
  self.lemmatizer = WordNetLemmatizer()
157
 
158
- # Job role keywords dictionary
159
  self.job_keywords = {
160
  "Data Scientist": ["python", "machine learning", "statistics", "pandas", "numpy", "scikit-learn",
161
- "tensorflow", "pytorch", "sql", "data analysis", "visualization", "jupyter"],
162
  "Software Engineer": ["programming", "java", "python", "javascript", "react", "node.js", "database",
163
- "git", "agile", "testing", "debugging", "api", "frontend", "backend"],
164
  "Product Manager": ["product", "strategy", "roadmap", "stakeholder", "analytics", "user experience",
165
- "market research", "agile", "scrum", "requirements", "metrics"],
166
  "Marketing Manager": ["marketing", "digital marketing", "seo", "social media", "analytics", "campaigns",
167
- "brand", "content", "advertising", "growth"],
168
  "Data Analyst": ["sql", "excel", "python", "tableau", "power bi", "statistics", "reporting",
169
- "data visualization", "business intelligence", "analytics"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  }
171
 
172
  # Common skills database
173
  self.technical_skills = [
174
- "python", "java", "javascript", "c++", "sql", "html", "css", "react", "angular", "vue",
 
175
  "machine learning", "deep learning", "tensorflow", "pytorch", "pandas", "numpy",
176
- "docker", "kubernetes", "aws", "azure", "git", "jenkins", "ci/cd", "mongodb", "postgresql",
177
- "redis", "elasticsearch", "spark", "hadoop", "tableau", "power bi", "excel"
 
178
  ]
179
 
180
  self.soft_skills = [
181
  "leadership", "communication", "teamwork", "problem solving", "critical thinking",
182
  "project management", "time management", "adaptability", "creativity", "analytical",
183
- "collaboration", "innovation", "strategic thinking", "customer service", "negotiation"
 
184
  ]
185
 
186
  def extract_text_from_pdf(self, file):
@@ -406,6 +485,32 @@ class ResumeAnalyzer:
406
 
407
  return summary
408
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  def create_pdf_report(self, text, sections, ats_score, match_percentage, selected_role, tech_skills, soft_skills, found_keywords):
410
  """Create a PDF report using ReportLab"""
411
  buffer = io.BytesIO()
@@ -462,17 +567,17 @@ class ResumeAnalyzer:
462
 
463
  def main():
464
  st.set_page_config(
465
- page_title="AI Resume Analyzer",
466
  page_icon="πŸ“„",
467
  layout="wide"
468
  )
469
 
470
- st.title("πŸš€ AI-Powered Resume Analyzer")
471
- st.markdown("Upload your resume and get comprehensive analysis with actionable insights!")
472
 
473
- # Show dependency status
474
- with st.expander("πŸ“‹ Dependency Status", expanded=False):
475
- col1, col2, col3 = st.columns(3)
476
  with col1:
477
  if SPACY_AVAILABLE:
478
  st.success("βœ… spaCy Available")
@@ -490,6 +595,12 @@ def main():
490
  st.success("βœ… Grammar Tool Available")
491
  else:
492
  st.warning("⚠️ Grammar Tool Not Available")
 
 
 
 
 
 
493
 
494
  # Initialize analyzer
495
  analyzer = ResumeAnalyzer()
@@ -499,6 +610,12 @@ def main():
499
  job_roles = list(analyzer.job_keywords.keys())
500
  selected_role = st.sidebar.selectbox("Select Target Job Role:", job_roles)
501
 
 
 
 
 
 
 
502
  # File upload section
503
  st.header("πŸ“ Upload Your Resume")
504
  uploaded_file = st.file_uploader(
@@ -523,6 +640,9 @@ def main():
523
  # Process the resume
524
  st.success("βœ… Resume uploaded and processed successfully!")
525
 
 
 
 
526
  # Extract data for analysis
527
  sections = analyzer.extract_sections(text)
528
  tech_skills, soft_skills = analyzer.extract_skills(text)
@@ -530,9 +650,9 @@ def main():
530
  ats_score = analyzer.calculate_ats_score(text, sections)
531
 
532
  # Create tabs for different analyses
533
- tab1, tab2, tab3, tab4, tab5 = st.tabs([
534
  "πŸ“Š Overview", "🎯 Skills Analysis", "πŸ“ Section Breakdown",
535
- "πŸ” ATS Analysis", "πŸ“‹ Report & Suggestions"
536
  ])
537
 
538
  with tab1:
@@ -588,8 +708,29 @@ def main():
588
  skills_text = " β€’ ".join(tech_skills)
589
  st.success(f"Found {len(tech_skills)} technical skills:")
590
  st.write(skills_text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  else:
592
- st.info("No technical skills detected")
 
593
 
594
  with col2:
595
  st.subheader("🀝 Soft Skills")
@@ -597,63 +738,99 @@ def main():
597
  skills_text = " β€’ ".join(soft_skills)
598
  st.success(f"Found {len(soft_skills)} soft skills:")
599
  st.write(skills_text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  else:
601
- st.info("No soft skills detected")
 
602
 
603
- # Job role matching
604
- st.subheader(f"🎯 Match Analysis for {selected_role}")
605
 
606
- # Progress bar for match percentage
607
- st.metric("Match Percentage", f"{match_percentage:.1f}%")
608
- st.progress(match_percentage / 100)
609
 
610
- if found_keywords:
611
- st.write("**Found Keywords:**")
612
- keywords_text = " β€’ ".join(found_keywords)
613
- st.success(keywords_text)
614
 
615
- # Skills gap analysis
616
- missing_keywords = [kw for kw in analyzer.job_keywords[selected_role] if kw not in found_keywords]
617
- if missing_keywords:
618
- st.write("**Missing Keywords (Consider Adding):**")
619
- missing_text = " β€’ ".join(missing_keywords[:10]) # Show top 10
620
- st.warning(missing_text)
621
-
622
- with tab3:
623
- st.header("Section Breakdown")
624
 
625
- for section_name, content in sections.items():
626
- if content:
627
- with st.expander(f"πŸ“‹ {section_name.title()} Section"):
628
- st.text_area(f"{section_name} content", content, height=150, disabled=True)
 
 
 
 
 
629
  else:
630
- st.warning(f"❌ {section_name.title()} section not found or empty")
631
-
632
- with tab4:
633
- st.header("ATS Analysis")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
 
635
  col1, col2 = st.columns(2)
636
 
637
  with col1:
638
- # ATS Score gauge
639
  fig = go.Figure(go.Indicator(
640
- mode="gauge+number+delta",
641
- value=ats_score,
642
- domain={'x': [0, 1], 'y': [0, 1]},
643
- title={'text': "ATS Friendliness Score"},
644
- delta={'reference': 80},
645
- gauge={
646
  'axis': {'range': [None, 100]},
647
- 'bar': {'color': "darkblue"},
648
  'steps': [
649
- {'range': [0, 50], 'color': "lightgray"},
650
- {'range': [50, 80], 'color': "yellow"},
651
- {'range': [80, 100], 'color': "green"}
652
  ],
653
  'threshold': {
654
  'line': {'color': "red", 'width': 4},
655
  'thickness': 0.75,
656
- 'value': 90
657
  }
658
  }
659
  ))
@@ -661,153 +838,110 @@ def main():
661
  st.plotly_chart(fig, use_container_width=True)
662
 
663
  with col2:
664
- # Grammar check
665
- st.subheader("πŸ“ Grammar Check")
666
- grammar_errors = analyzer.grammar_check(text)
667
 
668
- if grammar_errors:
669
- st.warning(f"Found {len(grammar_errors)} potential issues")
670
- for i, error in enumerate(grammar_errors[:5]): # Show first 5
671
- st.text(f"{i+1}. {error.message}")
 
 
 
672
  else:
673
- st.success("βœ… No major grammar issues detected")
674
-
675
- # ATS recommendations
676
- st.subheader("πŸ’‘ ATS Improvement Suggestions")
677
- recommendations = []
678
-
679
- if ats_score < 70:
680
- recommendations.extend([
681
- "Add more bullet points to improve readability",
682
- "Include contact information (email, phone)",
683
- "Ensure all major sections are present",
684
- "Use standard section headings"
685
- ])
686
-
687
- if match_percentage < 60:
688
- recommendations.append(f"Include more {selected_role}-specific keywords")
689
 
690
- if len(text.split()) < 300:
691
- recommendations.append("Consider adding more detailed descriptions")
692
-
693
- for rec in recommendations:
694
- st.write(f"β€’ {rec}")
695
-
696
- with tab5:
697
- st.header("Comprehensive Report & Suggestions")
698
-
699
- # Overall scores
700
- col1, col2, col3 = st.columns(3)
701
-
702
- with col1:
703
- st.metric("ATS Score", f"{ats_score}/100",
704
- delta=f"{ats_score-70} vs Average" if ats_score >= 70 else f"{ats_score-70} vs Average")
705
-
706
- with col2:
707
- st.metric("Role Match", f"{match_percentage:.1f}%",
708
- delta=f"{match_percentage-60:.1f}% vs Good Match" if match_percentage >= 60 else f"{match_percentage-60:.1f}% vs Good Match")
709
 
710
- with col3:
711
- overall_score = (ats_score + match_percentage) / 2
712
- st.metric("Overall Score", f"{overall_score:.1f}/100")
713
-
714
- # Detailed feedback
715
- st.subheader("πŸ“‹ Detailed Feedback")
716
-
717
- # Strengths
718
- strengths = []
719
- if ats_score >= 80:
720
- strengths.append("Resume is ATS-friendly")
721
- if match_percentage >= 70:
722
- strengths.append(f"Strong match for {selected_role} position")
723
- if len(tech_skills) >= 5:
724
- strengths.append("Rich technical skill set")
725
- if len(sections) >= 4:
726
- strengths.append("Well-structured with multiple sections")
727
-
728
- if strengths:
729
- st.success("**Strengths:**")
730
- for strength in strengths:
731
- st.write(f"βœ… {strength}")
732
-
733
- # Areas for improvement
734
- improvements = []
735
- if ats_score < 70:
736
- improvements.append("Improve ATS compatibility")
737
- if match_percentage < 60:
738
- improvements.append("Add more role-specific keywords")
739
- if not sections.get('projects'):
740
- improvements.append("Consider adding a projects section")
741
- if len(soft_skills) < 3:
742
- improvements.append("Highlight more soft skills")
743
 
744
- if improvements:
745
- st.warning("**Areas for Improvement:**")
746
- for improvement in improvements:
747
- st.write(f"⚠️ {improvement}")
748
 
749
- # Generate downloadable report
750
- st.subheader("πŸ“„ Download Report")
 
751
 
752
- col1, col2 = st.columns(2)
 
753
 
754
- with col1:
755
- # Text report
756
- report_content = f"""
757
- RESUME ANALYSIS REPORT
758
- Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
759
-
760
- OVERVIEW:
761
- - ATS Score: {ats_score}/100
762
- - Role Match: {match_percentage:.1f}%
763
- - Overall Score: {overall_score:.1f}/100
764
-
765
- PERSONA SUMMARY:
766
- {analyzer.generate_persona_summary(text, sections)}
767
-
768
- TECHNICAL SKILLS FOUND:
769
- {', '.join(tech_skills) if tech_skills else 'None detected'}
770
-
771
- SOFT SKILLS FOUND:
772
- {', '.join(soft_skills) if soft_skills else 'None detected'}
773
-
774
- ROLE-SPECIFIC KEYWORDS FOUND:
775
- {', '.join(found_keywords) if found_keywords else 'None found'}
776
-
777
- STRENGTHS:
778
- {chr(10).join(f'- {s}' for s in strengths)}
779
-
780
- AREAS FOR IMPROVEMENT:
781
- {chr(10).join(f'- {i}' for i in improvements)}
782
- """
783
 
784
- st.download_button(
785
- label="πŸ“₯ Download Text Report",
786
- data=report_content,
787
- file_name=f"resume_analysis_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
788
- mime="text/plain"
789
- )
790
-
791
- with col2:
792
- # PDF report
793
- if st.button("Generate PDF Report"):
794
- try:
795
- pdf_buffer = analyzer.create_pdf_report(
796
- text, sections, ats_score, match_percentage,
797
- selected_role, tech_skills, soft_skills, found_keywords
798
- )
799
-
800
- st.download_button(
801
- label="πŸ“„ Download PDF Report",
802
- data=pdf_buffer.getvalue(),
803
- file_name=f"resume_analysis_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf",
804
- mime="application/pdf"
805
- )
806
- except Exception as e:
807
- st.error(f"Error generating PDF: {str(e)}")
808
- st.info("PDF generation requires all ReportLab dependencies. Using text report as fallback.")
809
- else:
810
- st.error("❌ Error processing the uploaded file. Please try a different file.")
811
-
812
- if __name__ == "__main__":
813
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import re
5
  import io
6
  import base64
7
+ import os
8
+ import requests
9
+ import json
10
  from collections import Counter
11
  import matplotlib.pyplot as plt
12
  import seaborn as sns
 
61
  from reportlab.graphics.charts.barcharts import VerticalBarChart
62
  from reportlab.graphics.shapes import Drawing
63
 
64
+ # Claude Chatbot Class
65
+ class ClaudeChatbot:
66
+ def __init__(self):
67
+ self.api_key = os.getenv('OPENROUTER_API_KEY')
68
+ self.base_url = "https://openrouter.ai/api/v1/chat/completions"
69
+ self.model = "anthropic/claude-sonnet-4"
70
+
71
+ if not self.api_key:
72
+ st.error("❌ OPENROUTER_API_KEY not found in environment variables!")
73
+ st.info("Please set your OpenRouter API key in the environment variables.")
74
+
75
+ def generate_response(self, prompt, context="", max_tokens=1500):
76
+ """Generate response using Claude via OpenRouter"""
77
+ if not self.api_key:
78
+ return "Error: API key not configured"
79
+
80
+ headers = {
81
+ "Authorization": f"Bearer {self.api_key}",
82
+ "Content-Type": "application/json",
83
+ "HTTP-Referer": "https://your-app-url.com", # Replace with your actual URL
84
+ "X-Title": "AI Resume Analyzer"
85
+ }
86
+
87
+ system_prompt = """You are an expert resume and career consultant with deep knowledge of hiring practices, ATS systems, and industry requirements. You provide actionable, specific advice to help job seekers improve their resumes and career prospects. Always be encouraging but honest in your feedback."""
88
+
89
+ if context:
90
+ system_prompt += f"\n\nContext about the user's resume:\n{context}"
91
+
92
+ data = {
93
+ "model": self.model,
94
+ "messages": [
95
+ {"role": "system", "content": system_prompt},
96
+ {"role": "user", "content": prompt}
97
+ ],
98
+ "max_tokens": max_tokens,
99
+ "temperature": 0.7
100
+ }
101
+
102
+ try:
103
+ response = requests.post(self.base_url, headers=headers, json=data, timeout=30)
104
+ response.raise_for_status()
105
+
106
+ result = response.json()
107
+ return result['choices'][0]['message']['content']
108
+
109
+ except requests.exceptions.RequestException as e:
110
+ return f"Error connecting to API: {str(e)}"
111
+ except KeyError as e:
112
+ return f"Error parsing response: {str(e)}"
113
+ except Exception as e:
114
+ return f"Unexpected error: {str(e)}"
115
+
116
  # Download NLTK data if not already present
117
  @st.cache_resource
118
  def download_nltk_data():
 
201
  class ResumeAnalyzer:
202
  def __init__(self):
203
  self.nlp, self.grammar_tool = init_tools()
204
+ self.chatbot = ClaudeChatbot()
205
 
206
  try:
207
  self.stop_words = set(stopwords.words('english'))
 
211
 
212
  self.lemmatizer = WordNetLemmatizer()
213
 
214
+ # Expanded job role keywords dictionary (15 total roles)
215
  self.job_keywords = {
216
  "Data Scientist": ["python", "machine learning", "statistics", "pandas", "numpy", "scikit-learn",
217
+ "tensorflow", "pytorch", "sql", "data analysis", "visualization", "jupyter", "r", "statistics", "deep learning"],
218
  "Software Engineer": ["programming", "java", "python", "javascript", "react", "node.js", "database",
219
+ "git", "agile", "testing", "debugging", "api", "frontend", "backend", "algorithms", "data structures"],
220
  "Product Manager": ["product", "strategy", "roadmap", "stakeholder", "analytics", "user experience",
221
+ "market research", "agile", "scrum", "requirements", "metrics", "wireframes", "user stories"],
222
  "Marketing Manager": ["marketing", "digital marketing", "seo", "social media", "analytics", "campaigns",
223
+ "brand", "content", "advertising", "growth", "conversion", "roi", "crm"],
224
  "Data Analyst": ["sql", "excel", "python", "tableau", "power bi", "statistics", "reporting",
225
+ "data visualization", "business intelligence", "analytics", "dashboards", "kpi"],
226
+ "DevOps Engineer": ["docker", "kubernetes", "aws", "azure", "gcp", "jenkins", "ci/cd", "terraform",
227
+ "ansible", "monitoring", "linux", "bash", "infrastructure", "deployment"],
228
+ "UI/UX Designer": ["figma", "sketch", "adobe xd", "prototyping", "wireframes", "user research",
229
+ "usability testing", "design systems", "responsive design", "accessibility", "typography"],
230
+ "Cybersecurity Analyst": ["security", "penetration testing", "vulnerability assessment", "siem", "firewall",
231
+ "incident response", "compliance", "risk assessment", "cryptography", "network security"],
232
+ "Business Analyst": ["requirements gathering", "process improvement", "stakeholder management", "documentation",
233
+ "business process", "gap analysis", "user stories", "workflow", "project management"],
234
+ "Full Stack Developer": ["html", "css", "javascript", "react", "angular", "vue", "node.js", "express",
235
+ "mongodb", "postgresql", "rest api", "graphql", "version control", "responsive design"],
236
+ "Machine Learning Engineer": ["tensorflow", "pytorch", "keras", "scikit-learn", "mlops", "model deployment",
237
+ "feature engineering", "model optimization", "docker", "kubernetes", "python", "deep learning"],
238
+ "Cloud Architect": ["aws", "azure", "gcp", "cloud migration", "serverless", "microservices", "containerization",
239
+ "infrastructure as code", "cost optimization", "scalability", "security"],
240
+ "Sales Manager": ["sales", "crm", "lead generation", "client relationship", "negotiation", "revenue growth",
241
+ "pipeline management", "forecasting", "team leadership", "quota attainment"],
242
+ "Project Manager": ["project management", "pmp", "agile", "scrum", "kanban", "risk management",
243
+ "stakeholder communication", "budget management", "timeline", "resource allocation"],
244
+ "Quality Assurance Engineer": ["testing", "automation", "selenium", "junit", "test cases", "bug tracking",
245
+ "regression testing", "performance testing", "api testing", "quality standards"]
246
  }
247
 
248
  # Common skills database
249
  self.technical_skills = [
250
+ "python", "java", "javascript", "c++", "c#", "php", "ruby", "go", "rust", "swift",
251
+ "sql", "html", "css", "react", "angular", "vue", "node.js", "express", "django", "flask",
252
  "machine learning", "deep learning", "tensorflow", "pytorch", "pandas", "numpy",
253
+ "docker", "kubernetes", "aws", "azure", "gcp", "git", "jenkins", "ci/cd", "mongodb", "postgresql",
254
+ "redis", "elasticsearch", "spark", "hadoop", "tableau", "power bi", "excel", "figma", "sketch",
255
+ "linux", "bash", "terraform", "ansible", "selenium", "junit", "jira", "confluence"
256
  ]
257
 
258
  self.soft_skills = [
259
  "leadership", "communication", "teamwork", "problem solving", "critical thinking",
260
  "project management", "time management", "adaptability", "creativity", "analytical",
261
+ "collaboration", "innovation", "strategic thinking", "customer service", "negotiation",
262
+ "presentation", "mentoring", "conflict resolution", "decision making", "emotional intelligence"
263
  ]
264
 
265
  def extract_text_from_pdf(self, file):
 
485
 
486
  return summary
487
 
488
+ def get_claude_analysis(self, text, sections, job_role, ats_score, match_percentage):
489
+ """Get detailed analysis from Claude"""
490
+ context = f"""
491
+ Resume Analysis Data:
492
+ - Target Role: {job_role}
493
+ - ATS Score: {ats_score}/100
494
+ - Role Match: {match_percentage:.1f}%
495
+ - Word Count: {len(text.split())}
496
+ - Sections Found: {list(sections.keys())}
497
+ - Resume Text (first 2000 chars): {text[:2000]}
498
+ """
499
+
500
+ prompt = f"""
501
+ Please provide a comprehensive analysis of this resume for a {job_role} position. Include:
502
+
503
+ 1. **Strengths**: What are the standout elements?
504
+ 2. **Improvement Areas**: Specific areas that need work
505
+ 3. **Missing Elements**: Key components that should be added
506
+ 4. **Industry-Specific Advice**: Tailored recommendations for {job_role}
507
+ 5. **Action Items**: 3-5 concrete steps to improve the resume
508
+
509
+ Keep the analysis professional, constructive, and actionable.
510
+ """
511
+
512
+ return self.chatbot.generate_response(prompt, context)
513
+
514
  def create_pdf_report(self, text, sections, ats_score, match_percentage, selected_role, tech_skills, soft_skills, found_keywords):
515
  """Create a PDF report using ReportLab"""
516
  buffer = io.BytesIO()
 
567
 
568
  def main():
569
  st.set_page_config(
570
+ page_title="AI Resume Analyzer with Claude",
571
  page_icon="πŸ“„",
572
  layout="wide"
573
  )
574
 
575
+ st.title("πŸš€ AI-Powered Resume Analyzer with Claude Assistant")
576
+ st.markdown("Upload your resume and get comprehensive analysis with AI-powered insights!")
577
 
578
+ # Show dependency and API status
579
+ with st.expander("πŸ“‹ System Status", expanded=False):
580
+ col1, col2, col3, col4 = st.columns(4)
581
  with col1:
582
  if SPACY_AVAILABLE:
583
  st.success("βœ… spaCy Available")
 
595
  st.success("βœ… Grammar Tool Available")
596
  else:
597
  st.warning("⚠️ Grammar Tool Not Available")
598
+
599
+ with col4:
600
+ if os.getenv('OPENROUTER_API_KEY'):
601
+ st.success("βœ… Claude API Available")
602
+ else:
603
+ st.error("❌ Claude API Not Available")
604
 
605
  # Initialize analyzer
606
  analyzer = ResumeAnalyzer()
 
610
  job_roles = list(analyzer.job_keywords.keys())
611
  selected_role = st.sidebar.selectbox("Select Target Job Role:", job_roles)
612
 
613
+ # Initialize session state for chat
614
+ if "chat_history" not in st.session_state:
615
+ st.session_state.chat_history = []
616
+ if "resume_context" not in st.session_state:
617
+ st.session_state.resume_context = ""
618
+
619
  # File upload section
620
  st.header("πŸ“ Upload Your Resume")
621
  uploaded_file = st.file_uploader(
 
640
  # Process the resume
641
  st.success("βœ… Resume uploaded and processed successfully!")
642
 
643
+ # Store resume context for chatbot
644
+ st.session_state.resume_context = text
645
+
646
  # Extract data for analysis
647
  sections = analyzer.extract_sections(text)
648
  tech_skills, soft_skills = analyzer.extract_skills(text)
 
650
  ats_score = analyzer.calculate_ats_score(text, sections)
651
 
652
  # Create tabs for different analyses
653
+ tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs([
654
  "πŸ“Š Overview", "🎯 Skills Analysis", "πŸ“ Section Breakdown",
655
+ "πŸ” ATS Analysis", "πŸ“‹ Report & Suggestions", "πŸ€– AI Assistant"
656
  ])
657
 
658
  with tab1:
 
708
  skills_text = " β€’ ".join(tech_skills)
709
  st.success(f"Found {len(tech_skills)} technical skills:")
710
  st.write(skills_text)
711
+
712
+ # Skills distribution chart
713
+ if len(tech_skills) > 5:
714
+ skills_df = pd.DataFrame({
715
+ 'Skill': tech_skills[:10],
716
+ 'Count': [1] * len(tech_skills[:10])
717
+ })
718
+ fig = px.pie(skills_df, values='Count', names='Skill',
719
+ title='Technical Skills Distribution')
720
+ st.plotly_chart(fig, use_container_width=True)
721
+ else:
722
+ # Simple bar chart for fewer skills
723
+ skills_df = pd.DataFrame({
724
+ 'Skill': tech_skills,
725
+ 'Count': [1] * len(tech_skills)
726
+ })
727
+ fig = px.bar(skills_df, x='Skill', y='Count',
728
+ title='Technical Skills Found')
729
+ fig.update_xaxis(tickangle=45)
730
+ st.plotly_chart(fig, use_container_width=True)
731
  else:
732
+ st.warning("No technical skills detected")
733
+ st.info("πŸ’‘ Consider adding technical skills relevant to your field")
734
 
735
  with col2:
736
  st.subheader("🀝 Soft Skills")
 
738
  skills_text = " β€’ ".join(soft_skills)
739
  st.success(f"Found {len(soft_skills)} soft skills:")
740
  st.write(skills_text)
741
+
742
+ # Soft skills chart
743
+ if len(soft_skills) > 3:
744
+ soft_df = pd.DataFrame({
745
+ 'Skill': soft_skills[:8],
746
+ 'Count': [1] * len(soft_skills[:8])
747
+ })
748
+ fig = px.bar(soft_df, x='Skill', y='Count',
749
+ title='Soft Skills Found',
750
+ color='Skill')
751
+ fig.update_xaxis(tickangle=45)
752
+ st.plotly_chart(fig, use_container_width=True)
753
+ else:
754
+ # Display as simple list for fewer skills
755
+ for skill in soft_skills:
756
+ st.write(f"βœ… {skill}")
757
  else:
758
+ st.warning("No soft skills detected")
759
+ st.info("πŸ’‘ Consider highlighting leadership, communication, and teamwork skills")
760
 
761
+ # Skills comparison section
762
+ st.subheader("πŸ“Š Skills Overview")
763
 
764
+ # Create metrics row
765
+ col1, col2, col3, col4 = st.columns(4)
 
766
 
767
+ with col1:
768
+ st.metric("Technical Skills", len(tech_skills))
 
 
769
 
770
+ with col2:
771
+ st.metric("Soft Skills", len(soft_skills))
 
 
 
 
 
 
 
772
 
773
+ with col3:
774
+ total_skills = len(tech_skills) + len(soft_skills)
775
+ st.metric("Total Skills", total_skills)
776
+
777
+ with col4:
778
+ # Calculate skills balance
779
+ if total_skills > 0:
780
+ tech_ratio = len(tech_skills) / total_skills * 100
781
+ st.metric("Tech/Soft Ratio", f"{tech_ratio:.0f}%/{100-tech_ratio:.0f}%")
782
  else:
783
+ st.metric("Tech/Soft Ratio", "0%/0%")
784
+
785
+ # Skills recommendations
786
+ st.subheader("πŸ’‘ Skills Recommendations")
787
+
788
+ recommendations = []
789
+
790
+ # Technical skills recommendations
791
+ if len(tech_skills) < 5:
792
+ recommendations.append("πŸ“ˆ Add more technical skills relevant to your field")
793
+
794
+ # Soft skills recommendations
795
+ if len(soft_skills) < 3:
796
+ recommendations.append("🀝 Highlight more soft skills like leadership and communication")
797
+
798
+ # Balance recommendations
799
+ if len(tech_skills) > 0 and len(soft_skills) == 0:
800
+ recommendations.append("βš–οΈ Balance technical skills with soft skills")
801
+ elif len(soft_skills) > 0 and len(tech_skills) == 0:
802
+ recommendations.append("βš–οΈ Add technical skills to complement your soft skills")
803
+
804
+ if recommendations:
805
+ for rec in recommendations:
806
+ st.info(rec)
807
+ else:
808
+ st.success("βœ… Good balance of technical and soft skills!")
809
+
810
+ # Role-specific keyword analysis
811
+ st.subheader(f"🎯 {selected_role} Keywords Analysis")
812
 
813
  col1, col2 = st.columns(2)
814
 
815
  with col1:
816
+ # Match percentage visualization
817
  fig = go.Figure(go.Indicator(
818
+ mode = "gauge+number",
819
+ value = match_percentage,
820
+ domain = {'x': [0, 1], 'y': [0, 1]},
821
+ title = {'text': f"{selected_role} Match"},
822
+ gauge = {
 
823
  'axis': {'range': [None, 100]},
824
+ 'bar': {'color': "darkgreen"},
825
  'steps': [
826
+ {'range': [0, 40], 'color': "lightcoral"},
827
+ {'range': [40, 70], 'color': "yellow"},
828
+ {'range': [70, 100], 'color': "lightgreen"}
829
  ],
830
  'threshold': {
831
  'line': {'color': "red", 'width': 4},
832
  'thickness': 0.75,
833
+ 'value': 80
834
  }
835
  }
836
  ))
 
838
  st.plotly_chart(fig, use_container_width=True)
839
 
840
  with col2:
841
+ st.metric("Keywords Found", len(found_keywords))
842
+ st.metric("Match Percentage", f"{match_percentage:.1f}%")
 
843
 
844
+ # Match level indicator
845
+ if match_percentage >= 80:
846
+ st.success("πŸŽ‰ Excellent match!")
847
+ elif match_percentage >= 60:
848
+ st.warning("πŸ‘ Good match")
849
+ elif match_percentage >= 40:
850
+ st.warning("⚠️ Fair match")
851
  else:
852
+ st.error("❌ Poor match")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
 
854
+ # Keywords found section
855
+ if found_keywords:
856
+ st.subheader("βœ… Keywords Found")
857
+
858
+ # Display found keywords in a nice format
859
+ keyword_cols = st.columns(3)
860
+ for i, keyword in enumerate(found_keywords):
861
+ with keyword_cols[i % 3]:
862
+ st.success(f"βœ“ {keyword}")
863
+ else:
864
+ st.warning("οΏ½οΏ½οΏ½ No role-specific keywords found")
865
+
866
+ # Missing keywords section
867
+ all_keywords = analyzer.job_keywords[selected_role]
868
+ missing_keywords = [kw for kw in all_keywords if kw not in found_keywords]
 
 
 
 
869
 
870
+ if missing_keywords:
871
+ st.subheader("πŸ” Suggested Keywords to Add")
872
+ st.info(f"Consider adding these {selected_role}-specific keywords to improve your match score:")
873
+
874
+ # Show missing keywords in expandable sections
875
+ with st.expander(f"View all {len(missing_keywords)} missing keywords", expanded=len(missing_keywords) <= 10):
876
+ missing_cols = st.columns(3)
877
+ for i, keyword in enumerate(missing_keywords):
878
+ with missing_cols[i % 3]:
879
+ st.write(f"πŸ“ {keyword}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
880
 
881
+ # Skills gap analysis
882
+ st.subheader("πŸ“‹ Skills Gap Analysis")
 
 
883
 
884
+ # Calculate skills coverage for the role
885
+ role_technical_skills = [skill for skill in analyzer.technical_skills
886
+ if skill in analyzer.job_keywords[selected_role]]
887
 
888
+ found_role_skills = [skill for skill in tech_skills if skill in role_technical_skills]
889
+ missing_role_skills = [skill for skill in role_technical_skills if skill not in tech_skills]
890
 
891
+ if role_technical_skills:
892
+ coverage_percentage = (len(found_role_skills) / len(role_technical_skills)) * 100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
893
 
894
+ col1, col2 = st.columns(2)
895
+
896
+ with col1:
897
+ st.metric("Role Skills Coverage", f"{coverage_percentage:.1f}%")
898
+
899
+ if coverage_percentage >= 80:
900
+ st.success("🎯 Excellent coverage of role-specific skills!")
901
+ elif coverage_percentage >= 60:
902
+ st.warning("πŸ‘ Good coverage, consider adding a few more")
903
+ else:
904
+ st.error("⚠️ Low coverage, focus on adding role-specific skills")
905
+
906
+ with col2:
907
+ if missing_role_skills:
908
+ st.write("**Priority skills to add:**")
909
+ for skill in missing_role_skills[:5]:
910
+ st.write(f"🎯 {skill}")
911
+ else:
912
+ st.success("βœ… All key role skills covered!")
913
+
914
+ # Skills trend analysis (if we had historical data)
915
+ st.subheader("πŸ“ˆ Skills Insights")
916
+
917
+ insights = []
918
+
919
+ # Programming languages analysis
920
+ programming_langs = ['python', 'java', 'javascript', 'c++', 'c#', 'php', 'ruby', 'go']
921
+ found_langs = [lang for lang in programming_langs if lang in [s.lower() for s in tech_skills]]
922
+
923
+ if len(found_langs) >= 3:
924
+ insights.append(f"πŸ’» Strong programming portfolio with {len(found_langs)} languages")
925
+ elif len(found_langs) >= 1:
926
+ insights.append(f"πŸ’» Programming experience in {', '.join(found_langs)}")
927
+
928
+ # Cloud skills analysis
929
+ cloud_skills = ['aws', 'azure', 'gcp', 'docker', 'kubernetes']
930
+ found_cloud = [skill for skill in cloud_skills if skill in [s.lower() for s in tech_skills]]
931
+
932
+ if found_cloud:
933
+ insights.append(f"☁️ Cloud-ready with {', '.join(found_cloud)} experience")
934
+
935
+ # Data skills analysis
936
+ data_skills = ['sql', 'python', 'tableau', 'power bi', 'excel', 'pandas', 'numpy']
937
+ found_data = [skill for skill in data_skills if skill in [s.lower() for s in tech_skills]]
938
+
939
+ if len(found_data) >= 3:
940
+ insights.append(f"πŸ“Š Strong data analysis capabilities")
941
+
942
+ if insights:
943
+ for insight in insights:
944
+ st.info(insight)
945
+ else:
946
+ st.info("πŸ’‘ Add more technical skills to unlock insights about your profile")
947
+