Spaces:
Running
Running
| #what is specifically wrong in my resume? | |
| import re | |
| from typing import List, Dict, Any, Optional | |
| from backend.models.schemas import IssueDetail | |
| def analyze_issues( | |
| resume_text: str, | |
| parsed_resume: Dict, | |
| skills: List[str], | |
| projects: List[Dict], | |
| action_verbs: List[str], | |
| skill_validation: Dict, | |
| scores: Dict, | |
| contact_info: Optional[Dict]=None, | |
| ) -> List[IssueDetail]: | |
| detected: List[IssueDetail]=[] | |
| #Unpack frequently-used structured fields once at the top | |
| exp_entries = [e for e in parsed_resume.get('experience', []) if isinstance(e, dict)] | |
| edu_entries = [e for e in parsed_resume.get('education', []) if isinstance(e, dict)] | |
| proj_entries = [p for p in parsed_resume.get('projects', []) if isinstance(p, dict)] | |
| summary = (parsed_resume.get('professional_summary') or '').strip() # Handle None to prevent string concatenation errors | |
| #Build a combined experience text for regex-based checks that still need text | |
| experience_text = '\n'.join(e.get('description', '') for e in exp_entries).strip() | |
| #1. missig project section | |
| resume_lower = resume_text.lower() | |
| has_projects_signal = any(kw in resume_lower for kw in [ | |
| 'project', 'github.com', 'deployed', 'built a', 'developed a', | |
| 'created a', 'implemented a', 'live demo', 'tech stack', | |
| ]) | |
| if not proj_entries and len(projects) == 0 and not has_projects_signal: | |
| detected.append(IssueDetail( | |
| issue_title="Missing Projects Section", | |
| severity_level="High", | |
| ats_impact="High", | |
| explanation=( | |
| "Your resume does not have a dedicated Projects section. " | |
| "ATS systems and recruiters look for concrete projects to validate " | |
| "that your listed skills have been applied in practice." | |
| ), | |
| where_it_appears="Resume structure β no 'Projects' header was detected", | |
| how_to_fix=( | |
| "Add a 'Projects' section with 2β3 significant projects. " | |
| "For each project, include the title, technologies used, " | |
| "what you built, and a measurable outcome." | |
| ), | |
| action_items=[ | |
| "Add a 'PROJECTS' section heading after your Experience section", | |
| "Include 2β3 projects (personal, academic, or open-source)", | |
| "For each project: write the title, tech stack used, what you built, and a measurable result", | |
| "Example: 'E-Commerce Platform β React, Node.js, MongoDB. Handled 500+ transactions/month'", | |
| "Link to GitHub or a live demo if available (e.g., github.com/yourname/project)", | |
| ], | |
| example_improvement=( | |
| "Add:\n" | |
| "PROJECTS\n" | |
| "β’ E-Commerce Platform β Built a full-stack shopping site using " | |
| "React, Node.js, and MongoDB. Implemented payment processing with " | |
| "Stripe, handling 500+ transactions/month.\n" | |
| "β’ ML Sentiment Analyzer β Trained a BERT model on 10K reviews " | |
| "achieving 92% accuracy. Deployed as a REST API with FastAPI." | |
| ), | |
| )) | |
| #2. missing experience section | |
| has_experience_signal = any(kw in resume_lower for kw in [ | |
| 'intern', 'internship', 'employed', 'worked at', 'working at', | |
| 'company', 'organization', 'job', 'role', 'position', 'designation', | |
| 'manager', 'engineer', 'developer', 'analyst', 'consultant', | |
| ]) | |
| if not exp_entries and not has_experience_signal: | |
| detected.append(IssueDetail( | |
| issue_title="Missing Work Experience Section", | |
| severity_level="High", | |
| ats_impact="High", | |
| explanation=( | |
| "No work experience section was detected. Even for freshers, " | |
| "internships, freelance work, or volunteer experience help " | |
| "demonstrate professional capability." | |
| ), | |
| where_it_appears="Resume structure β no 'Experience' or 'Work History' header found", | |
| how_to_fix=( | |
| "Add an 'Experience' section. If you lack formal employment, " | |
| "include internships, freelance projects, open-source contributions, " | |
| "or relevant volunteer work." | |
| ), | |
| action_items=[ | |
| "Add an 'EXPERIENCE' or 'INTERNSHIPS' section to your resume", | |
| "List each role with: Job Title β Company Name (Month Year β Month Year)", | |
| "Add 2β4 bullet points per role describing what you did and its impact", | |
| "If no formal job: include internships, freelance work, open-source, or college clubs", | |
| "Start every bullet with a past-tense action verb (Developed, Built, Led, etc.)", | |
| ], | |
| example_improvement=( | |
| "Add:\n" | |
| "EXPERIENCE\n" | |
| "Software Engineering Intern β XYZ Corp (Jun 2025 β Aug 2025)\n" | |
| "β’ Developed REST APIs with FastAPI serving 10K requests/day\n" | |
| "β’ Reduced page load time by 40% through caching optimization" | |
| ), | |
| )) | |
| #3. Missing Education Section | |
| has_education_signal = any(kw in resume_lower for kw in [ | |
| 'b.tech', 'btech', 'b.e.', 'b.sc', 'bsc', 'm.tech', 'mtech', 'm.sc', | |
| 'bachelor', 'master', 'phd', 'university', 'college', | |
| 'institute of technology', 'cgpa', 'gpa', 'graduated', 'diploma', | |
| 'class of', '20', 'batch of', | |
| ]) | |
| if not edu_entries and not has_education_signal: | |
| detected.append(IssueDetail( | |
| issue_title="Missing Education Section", | |
| severity_level="Moderate", | |
| ats_impact="Medium", | |
| explanation=( | |
| "No education section was found. Most ATS systems expect an " | |
| "Education section with at least your degree and institution." | |
| ), | |
| where_it_appears="Resume structure β no 'Education' header detected", | |
| how_to_fix=( | |
| "Add an 'Education' section listing your degree, university, " | |
| "graduation year, and optionally your GPA or relevant coursework." | |
| ), | |
| action_items=[ | |
| "Add an 'EDUCATION' section (usually at the bottom for experienced candidates, top for freshers)", | |
| "Include: Degree name β Institution name (Start Year β End Year)", | |
| "Add your CGPA or percentage if it is 7.0+ or 70%+", | |
| "Optionally list 3β5 relevant courses (e.g., Data Structures, DBMS, ML)", | |
| ], | |
| example_improvement=( | |
| "Add:\n" | |
| "EDUCATION\n" | |
| "B.Tech in Computer Science β IIT Delhi (2021β2025)\n" | |
| "CGPA: 8.5 | Relevant Coursework: Data Structures, ML, DBMS" | |
| ), | |
| )) | |
| #4. Missing Skills Section | |
| if not parsed_resume.get('skills') and len(skills) < 3: # only flag if extraction also found very few skills | |
| detected.append(IssueDetail( | |
| issue_title="Missing or Weak Skills Section", | |
| severity_level="High", | |
| ats_impact="High", | |
| explanation=( | |
| f"Only {len(skills)} skill(s) were detected. ATS systems " | |
| "rely heavily on keyword matching from a dedicated Skills section. " | |
| "Without clear skills listed, your resume may fail automated filters." | |
| ), | |
| where_it_appears="Skills section β either missing or contains very few items", | |
| how_to_fix=( | |
| "Add a clear 'Skills' section organized by category. " | |
| "Include programming languages, frameworks, tools, and soft skills " | |
| "that match your target role." | |
| ), | |
| action_items=[ | |
| "Add a 'TECHNICAL SKILLS' or 'SKILLS' section", | |
| "Organize by category: Languages, Frameworks, Tools, Databases, Cloud", | |
| "List at least 10β15 skills relevant to your target role", | |
| "Use the exact names that appear in job descriptions (e.g., 'React.js' not just 'React')", | |
| "Include tools you use daily: Git, VS Code, Postman, Docker, etc.", | |
| ], | |
| example_improvement=( | |
| "Add:\n" | |
| "TECHNICAL SKILLS\n" | |
| "Languages: Python, JavaScript, TypeScript, SQL\n" | |
| "Frameworks: React, FastAPI, Django, Express.js\n" | |
| "Tools: Docker, Git, AWS, PostgreSQL, MongoDB" | |
| ), | |
| )) | |
| # 5. Skills Lack Supporting Evidence | |
| unvalidated = skill_validation.get('unvalidated_skills', []) | |
| validated = skill_validation.get('validated_skills', []) | |
| total_skills = len(unvalidated) + len(validated) | |
| if total_skills > 0 and len(unvalidated) > len(validated): | |
| unsupported_list = ', '.join(unvalidated[:8]) | |
| pct_unsupported = round((len(unvalidated) / total_skills) * 100) | |
| action_items_skills = [ | |
| f"Mention '{skill}' in a project or experience bullet point" for skill in unvalidated[:5] | |
| ] | |
| action_items_skills.append("Remove skills you cannot demonstrate with any project or experience") | |
| if len(unvalidated) > 5: | |
| action_items_skills.append(f"({len(unvalidated) - 5} more unvalidated skills β review each one)") | |
| detected.append(IssueDetail( | |
| issue_title="Most Skills Lack Supporting Evidence", | |
| severity_level="Moderate", | |
| ats_impact="High", | |
| explanation=( | |
| f"{pct_unsupported}% of your listed skills ({len(unvalidated)} out of " | |
| f"{total_skills}) are not backed by any mention in your projects or " | |
| "experience sections. Recruiters and ATS systems cross-reference " | |
| "skills against actual work to verify credibility." | |
| ), | |
| where_it_appears=f"These skills have no supporting context: {unsupported_list}", | |
| how_to_fix=( | |
| "For each skill in your Skills section, ensure it appears at least " | |
| "once in a project description or experience bullet point. " | |
| "Describe how and where you used that technology." | |
| ), | |
| action_items=action_items_skills, | |
| example_improvement=( | |
| f"Your skill '{unvalidated[0]}' has no supporting evidence.\n\n" | |
| f"Fix: Add to a project or experience bullet:\n" | |
| f"'Built a data pipeline using {unvalidated[0]} that processed " | |
| "10K records daily, reducing manual effort by 60%.'" | |
| ), | |
| )) | |
| #6. Weak Action Verbs | |
| description_lines = [ | |
| line.strip() | |
| for exp in exp_entries | |
| for line in exp.get('description', '').split('\n') | |
| if line.strip() | |
| ] | |
| if len(description_lines) > 3 and len(action_verbs) < 3: | |
| detected.append(IssueDetail( | |
| issue_title="Bullet Points Lack Strong Action Verbs", | |
| severity_level="Moderate", | |
| ats_impact="Medium", | |
| explanation=( | |
| f"Your experience section has {len(description_lines)} bullet points but " | |
| f"only {len(action_verbs)} start with strong action verbs. " | |
| "ATS systems and recruiters favor bullets that begin with verbs like " | |
| "'Developed', 'Implemented', 'Designed', 'Optimized'." | |
| ), | |
| where_it_appears="Experience section β bullet point openings", | |
| how_to_fix=( | |
| "Start every bullet point with a past-tense action verb. " | |
| "Avoid starting with 'Responsible for', 'Worked on', or 'Helped with'. " | |
| "Use verbs like: Developed, Built, Designed, Implemented, Led, Automated, Optimized." | |
| ), | |
| action_items=[ | |
| "Rewrite every bullet that starts with 'Responsible for', 'Helped', 'Worked on', or 'Assisted'", | |
| "Use: Developed, Built, Designed, Implemented, Led, Automated, Optimized, Deployed, Reduced, Increased", | |
| "Make verbs past-tense for previous roles, present-tense for current role", | |
| f"Review all {len(description_lines)} bullet points β at least {len(description_lines)} should start with action verbs", | |
| "Avoid weak openers like 'Was responsible for...' or 'Involved in...'", | |
| ], | |
| example_improvement=( | |
| "Before:\n" | |
| "β’ Responsible for building the backend\n" | |
| "β’ Worked on the payment feature\n\n" | |
| "After:\n" | |
| "β’ Developed a REST API with FastAPI handling 5K daily requests\n" | |
| "β’ Implemented Stripe payment integration reducing checkout time by 30%" | |
| ), | |
| )) | |
| #7. No Quantifiable Achievements | |
| number_pattern = r'\d+[%+]?|\$\d+' | |
| has_metrics = bool(re.findall(number_pattern, experience_text)) if experience_text else False | |
| if experience_text and not has_metrics: | |
| detected.append(IssueDetail( | |
| issue_title="No Quantifiable Achievements Found", | |
| severity_level="Moderate", | |
| ats_impact="Medium", | |
| explanation=( | |
| "Your experience section does not contain any measurable outcomes " | |
| "(numbers, percentages, or dollar amounts). Quantified achievements " | |
| "make your impact concrete and are strongly preferred by recruiters." | |
| ), | |
| where_it_appears="Experience section β bullet point content", | |
| how_to_fix=( | |
| "Add numbers to at least 50% of your bullet points. " | |
| "Include metrics like: users served, response time improved, " | |
| "revenue generated, lines of code, team size, etc." | |
| ), | |
| action_items=[ | |
| "Go through each bullet point and ask: 'How much?', 'How many?', 'By what %?'", | |
| "Add metrics: users served, requests/day, % improvement, team size, time saved", | |
| "Examples: '500+ daily users', 'reduced load time by 40%', 'handled 10K API calls/day'", | |
| "If exact numbers aren't known, use reasonable estimates (e.g., '~200 users')", | |
| "Aim for numbers in at least 50% of your experience bullets", | |
| ], | |
| example_improvement=( | |
| "Before:\n" | |
| "β’ Improved application performance\n" | |
| "β’ Managed a team of developers\n\n" | |
| "After:\n" | |
| "β’ Improved API response time by 45% through Redis caching\n" | |
| "β’ Led a team of 5 developers delivering 3 features per sprint" | |
| ), | |
| )) | |
| #8. Missing Contact Information | |
| if contact_info: | |
| missing_contacts = [] | |
| if not contact_info.get('email'): | |
| missing_contacts.append('email') | |
| if not contact_info.get('phone'): | |
| missing_contacts.append('phone number') | |
| if not contact_info.get('linkedin'): | |
| missing_contacts.append('LinkedIn URL') | |
| if len(missing_contacts) >= 2: | |
| contact_action_items = [f"Add your {item} to the header section" for item in missing_contacts] | |
| contact_action_items += [ | |
| "Format the contact line as: email | phone | linkedin | github", | |
| "Make sure your LinkedIn URL is a custom short URL (linkedin.com/in/yourname)", | |
| "Add a GitHub link if you have public projects (github.com/yourname)", | |
| ] | |
| detected.append(IssueDetail( | |
| issue_title="Incomplete Contact Information", | |
| severity_level="High", | |
| ats_impact="High", | |
| explanation=( | |
| f"Your resume is missing: {', '.join(missing_contacts)}. " | |
| "Recruiters need reliable ways to reach you. Missing contact " | |
| "details can cause your application to be skipped entirely." | |
| ), | |
| where_it_appears="Header / Contact section at the top of the resume", | |
| how_to_fix=( | |
| "Add your full name, email, phone number, LinkedIn profile, " | |
| "and optionally a GitHub or portfolio link at the top of your resume." | |
| ), | |
| action_items=contact_action_items, | |
| example_improvement=( | |
| "Add at top:\n" | |
| "John Doe\n" | |
| "john.doe@email.com | +91-9876543210\n" | |
| "linkedin.com/in/johndoe | github.com/johndoe" | |
| ), | |
| )) | |
| # 9. Low Formatting Score | |
| formatting_score = scores.get('formatting_score', 20) | |
| if formatting_score < 10: | |
| detected.append(IssueDetail( | |
| issue_title="Poor Resume Formatting", | |
| severity_level="High", | |
| ats_impact="High", | |
| explanation=( | |
| f"Your formatting score is {formatting_score}/20, which indicates " | |
| "problems like missing section headers, inconsistent structure, " | |
| "or non-standard layout that ATS parsers struggle with." | |
| ), | |
| where_it_appears="Overall document structure and formatting", | |
| how_to_fix=( | |
| "Use a clean, single-column layout with standard section headers " | |
| "(Experience, Education, Skills, Projects). Use consistent bullet " | |
| "points, standard fonts, and avoid tables, columns, or graphics." | |
| ), | |
| action_items=[ | |
| "Switch to a single-column layout (avoid two-column templates for ATS)", | |
| "Use standard section headers: EXPERIENCE, EDUCATION, SKILLS, PROJECTS", | |
| "Use bullet points (β’) consistently β don't mix with dashes or asterisks", | |
| "Remove all tables, text boxes, headers/footers, and images β ATS cannot parse them", | |
| "Use a standard font (Calibri, Arial, Times New Roman) at 10β12pt", | |
| "Order sections: Contact β Summary β Experience β Projects β Education β Skills", | |
| ], | |
| example_improvement=( | |
| "Use this structure:\n" | |
| "NAME & CONTACT\n" | |
| "SUMMARY (2-3 lines)\n" | |
| "EXPERIENCE (reverse chronological)\n" | |
| "PROJECTS (2-3 key projects)\n" | |
| "EDUCATION\n" | |
| "SKILLS (categorized)" | |
| ), | |
| )) | |
| #10. Missing Summary/Objective | |
| if not summary: | |
| detected.append(IssueDetail( | |
| issue_title="Missing Professional Summary", | |
| severity_level="Low", | |
| ats_impact="Low", | |
| explanation=( | |
| "Your resume does not include a Professional Summary or Objective " | |
| "section at the top. While not required, a 2-3 line summary helps " | |
| "recruiters quickly understand your profile and target role." | |
| ), | |
| where_it_appears="Top of resume β below contact info", | |
| how_to_fix=( | |
| "Add a 2-3 sentence summary highlighting your experience level, " | |
| "key skills, and career focus. Tailor it to the job you're applying for." | |
| ), | |
| action_items=[ | |
| "Add a 'PROFESSIONAL SUMMARY' or 'OBJECTIVE' section at the top of your resume", | |
| "Write 2β3 sentences: who you are, your key skills, and what role you seek", | |
| "Mention your years of experience or education level upfront", | |
| "Tailor this section for each job application β reference the specific role", | |
| "Keep it under 60 words β recruiters spend only 6 seconds on first scan", | |
| ], | |
| example_improvement=( | |
| "Add:\n" | |
| "PROFESSIONAL SUMMARY\n" | |
| "Full-stack developer with 2+ years of experience building scalable " | |
| "web applications using React, Node.js, and AWS. Passionate about " | |
| "clean architecture and performance optimization." | |
| ), | |
| )) | |
| return detected | |
| def generate_issues_summary(detected_issues: List[IssueDetail]) -> List[str]: | |
| """Extract issue titles to formulate the issues_summary list.""" | |
| return [issue.issue_title for issue in detected_issues] |