Portfolio under active development.

Resume Analysis and Optimization Engine

An AI-powered platform that analyzes resumes for ATS compliance, skill density, and impact, featuring a custom-trained NER model.

Resume Analysis and Optimization Engine
Published:

Project Overview

This project is an end-to-end platform designed to help job seekers navigate the modern, automated hiring landscape. It uses a custom-trained Natural Language Processing (NLP) model to analyze resumes, providing instant, data-driven feedback on ATS compliance, content quality, and overall effectiveness.

Key Features

  • Custom NER Model: Fine-tuned a spaCy model to accurately identify domain-specific entities like certifications, degrees, and job titles.
  • Multi-Faceted Scoring: Generates a holistic score based on three pillars: ATS-friendly formatting, keyword/skill density, and the use of impactful, metric-driven language.
  • Semantic Analysis: Implemented a Sentence-Transformer model to evaluate the contextual similarity between a resume and a job description (optional feature).
  • API-Driven Architecture: The entire Python analysis engine is deployed as a FastAPI service on Hugging Face Spaces.
  • Interactive Frontend: A responsive Next.js and React application provides a clean user interface for uploading resumes and viewing the detailed analysis.

Technologies Used

  • Backend & AI: Python, FastAPI, spaCy, Sentence-Transformers, pdfminer.six
  • Frontend: Next.js, React, TypeScript, Tailwind CSS, shadcn/ui
  • Deployment: Hugging Face Spaces (for the AI service), Vercel (for the Next.js app)
  • Data Handling: Pandas

Core Outcomes

The final application successfully provides users with an "ATS Compliance Score" and detailed, actionable feedback. The custom NER model, fine-tuned on a curated dataset, significantly outperforms general-purpose models in identifying resume-specific entities, forming the foundation for a suite of powerful career-focused tools.

Problem Context

The Challenge

The vast majority of companies today use Applicant Tracking Systems (ATS) to manage the high volume of job applications. These systems automatically parse and filter resumes, meaning a high percentage are rejected before ever being seen by a human. Job seekers often struggle to understand:

  1. Is my resume formatted in a way that a machine can read it correctly?
  2. Does my resume contain the right skills and keywords for the job I want?
  3. Am I effectively communicating my achievements in a way that demonstrates impact?

Business Impact

A tool that can answer these questions provides immense value by empowering job seekers. It helps level the playing field, increases interview callback rates, and reduces the frustration of applying for jobs. For a platform, this can be monetized as a premium feature for job boards, career coaching services, or university career centers.

Solution Approach

Methodology Selection

The core of this project is a sophisticated NLP pipeline. The chosen approach was to build a custom system rather than relying on generic APIs for several reasons:

  1. Accuracy: General NLP models consistently fail to understand the specific context of resumes, mislabeling certifications and skills. A custom model was essential.
  2. Control: Building the pipeline from scratch provides full control over the logic, from PDF parsing to the final weighted score.
  3. Extensibility: The modular design allows for future enhancements, like comparing a resume to a specific job description or analyzing for tone.

Architecture Overview

The project follows a modern, decoupled architecture:

  1. Next.js Frontend: A performant, user-friendly interface built with React and shadcn/ui, deployed on Vercel.
  2. Python Backend API: A FastAPI service that encapsulates all the complex AI logic. This service handles:
    • PDF Parsing: Using the robust pdfminer.six library.
    • NER Analysis: Using the custom fine-tuned spaCy model.
    • Skill Matching: Using a PhraseMatcher with a database of over 30,000 skills.
    • Scoring: Calculating the weighted ATS compliance score.
  3. Hugging Face Spaces Deployment: The Python API is containerized and hosted on Hugging Face Spaces, separating the heavy ML workload from the web frontend.

Architecture Diagram ### Challenges and Solutions

  1. Challenge: Initial PDF text extraction was unreliable and produced garbled text. Solution: After testing several libraries, pdfminer.six was chosen for its superior ability to handle complex resume layouts, ensuring a clean data input for the NLP models.

  2. Challenge: Standard NLP models misclassified resume entities (e.g., labeling "PMP" as an "Organization"). Solution: Implemented a full fine-tuning workflow. A dataset of over 100 resumes was annotated to create training and evaluation sets. A pre-trained spaCy model was then fine-tuned on this data, teaching it to recognize new labels like CERTIFICATION, DEGREE, and JOB_TITLE. This was validated with an evaluation F-score of over 80%.

  3. Challenge: A single score felt unhelpful to a user. Solution: Developed a multi-faceted scoring system (Formatting, Skill Density, Impact) and a dynamic feedback generator. The final UI presents not just a number, but a detailed rubric with specific, actionable strengths and weaknesses.

Technical Implementation

Custom NER Model Training

The training pipeline was a key part of the project. This snippet shows the evaluation logic within the training loop, which was crucial for validating model performance.

# Part of the training loop to evaluate the model after each iteration
scorer = Scorer()
eval_examples = []
for text, annotations in EVAL_DATA:
    # Make a prediction on the text
    pred_doc = nlp_train(text)
    # Create the Example object with the prediction and the true annotations
    example = Example.from_dict(pred_doc, annotations)
    eval_examples.append(example)

# Pass the ENTIRE LIST of examples to the scorer at once
scores = scorer.score(eval_examples)

# Print the Precision, Recall, and F-Score
print(f"P: {scores.get('ents_p', 0.0):.2f} | R: {scores.get('ents_r', 0.0):.2f} | F: {scores.get('ents_f', 0.0):.2f}")


# Sample function for generating feedback on resume impact
def generate_impact_feedback(analysis_results, score):
    feedback = {"summary": "", "strengths": [], "weaknesses": []}
    num_metrics = len(analysis_results.get('metrics', []))
    num_verbs = len(analysis_results.get('action_verbs', []))

    if score >= 85:
        feedback["summary"] = "Outstanding! Your resume is packed with impactful, results-oriented language."
    elif score >= 60:
        feedback["summary"] = "Your resume effectively demonstrates your accomplishments."
    else:
        feedback["summary"] = "Your resume could be made much stronger by highlighting your achievements."

    if num_metrics > 3:
        feedback["strengths"].append(f"Excellent use of {num_metrics} quantifiable metrics ($, %, #).")
    else:
        feedback["weaknesses"].append("Try to include more measurable results (e.g., 'Increased revenue by 20%').")

    if num_verbs > 5:
        feedback["strengths"].append("Effectively uses strong action verbs to lead your bullet points.")
    else:
        feedback["weaknesses"].append("Start each bullet point with a powerful action verb (e.g., 'Spearheaded', 'Optimized').")

    return feedback