Skip to content

About

CareerCompass AI is a local-first AI career platform that analyzes resumes, scans job market signals, ranks job fit with semantic matching, identifies skill gaps, builds personalized learning roadmaps, generates tailored career documents, and runs voice-based mock interviews with scoring.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

CareerCompass AI

Intelligent Resume & Market Gap Analyzer · AI Mock Interviewer · Agentic Career Document Writer


Project Snapshot

CareerCompass AI is a local-first Streamlit platform that turns a resume into a market-aware career plan. It parses a candidate's profile, scans live job listings, ranks job fit through taxonomy-first semantic matching, surfaces skill gaps, builds a learning roadmap, generates tailored application documents, and runs voice-based mock interviews with scoring — all in one workflow.

Project status: Portfolio-ready local AI application. The core workflow is orchestrated through core/pipeline.py; LLM features run on Groq, skill intelligence runs on sentence-transformers, and agentic document generation runs on LangGraph/LangChain.

What It Does

Capability User Outcome
Resume intelligence Extracts contact info, validated skills, proficiency signals, achievements, seniority, and recommendations.
Market scan Validates full schema.org postings, retains blocked pages as labelled partial snippets, and clearly labels fallback demo data.
Semantic job matching Scores roles using skills, title similarity, and experience fit, with transparent score breakdowns.
Gap analysis Clusters missing skills and weights them by market frequency and domain to prioritize what to learn next.
Learning roadmap Converts gaps into dependency-aware learning paths with projects and resource links.
Mock interview Combines Groq, Whisper, and EdgeTTS/gTTS with optional camera analytics for realistic interview practice and scoring.
Career documents Tailors resumes and drafts company-aware cover letters through LLM and LangGraph workflows.

Why This Project Stands Out

  • End-to-end career workflow: Covers analysis, matching, gap diagnosis, upskilling, documents, and interview practice in a single app.
  • Multimodal AI experience: Text, voice, speech analytics, and optional webcam feedback combine into one interactive interview simulator.
  • Provenance-aware recommendations: Verified pages feed market analytics; blocked snippets provide capped, provisional matches; partial and demo data are kept out of trend history.
  • Evidence-based employer identity: Company names are recovered from the strongest available structured page, listing card, search title, snippet, page metadata, or public URL evidence, with source and confidence shown separately.
  • Engineering depth: Shared pipeline orchestration, taxonomy-first matching, lazy model loading, runtime artifact hygiene, and test coverage make this more than a UI demo.
  • Calm, responsive interface: A minimalist visual system, clear data hierarchy, mobile-safe layouts, sticky career-tool navigation, visible focus states, and reduced-motion support keep dense analysis readable.
  • Recruiter-visible polish: Screenshots, dashboards, reports, cover letters, PDFs, and score explanations make the output tangible and easy to evaluate at a glance.

Feature Highlights

Resume & Profile Analysis

  • Validates skills against a curated taxonomy, alias list, regex heuristics, and semantic similarity.
  • Estimates proficiency from surrounding resume context, such as years of experience, seniority language, and project verbs.
  • Extracts achievements, digital presence, and employment timelines; calendar working years remain a factual metric while career level uses a conservative, deterministic evidence model.
  • Scores professional maturity from timeline (45%), role scope (25%), work-evidenced technology depth (20%), and demonstrated impact (10%).
  • Links skills to dated employment evidence, professional duration, recency, and extraction confidence; general skill-list breadth cannot create seniority, while project/certification support is capped at five technical-depth points.
  • Separates total working experience from target-role-relevant experience and reports readiness and hybrid role level for each selected role.
  • Lets users correct contact details, employment records, role-specific skills, responsibilities, achievements, experience, and skills before refreshing matches, gaps, and the roadmap.

Market Intelligence & Job Matching

  • Searches LinkedIn, JobStreet, Indeed, and Glassdoor via public listing discovery and DuckDuckGo dorking.
  • Preserves richer duplicate metadata and recovers employer names without replacing known listing-card evidence with poorer search results.
  • Fetches and validates complete schema.org job descriptions before ranking them.
  • Falls back to blocked search snippets as capped, partial matches when full pages are inaccessible.
  • Uses clearly labelled synthetic demo templates only when neither verified nor usable partial results are available.
  • Scores jobs on a skills (60%) / title (20%) / experience (20%) weighting; experience itself combines relevant years (50%), role scope (25%), and professional technology alignment (25%).
  • Returns matched skills, missing skills, score breakdowns, action items, and market gap severity.

Roadmap, Documents & Interview Practice

  • Builds prerequisite-aware learning paths from data/skill_ontology.py.
  • Generates transfer-learning roadmap advice with deterministic fallback resources.
  • Tailors resumes into ATS-oriented PDFs and writes researched, company-aware cover letters.
  • Runs voice-based mock interviews with LLM scoring, speech metrics, and optional camera posture/eye-contact signals.
  • Loads the optional WebRTC/MediaPipe camera runtime only after camera feedback is enabled, keeping the normal dashboard startup path lightweight.

Product Tour

Dashboard — Professional Profile View

Dashboard A recruiter-style overview of extracted profile signals, target-role readiness, employment history, evidence-backed skills, completeness, and editable verification status.

Resume Analysis — Skills & Strengths

Resume Analysis Taxonomy-first skill extraction groups validated skills by domain and estimates proficiency from resume context.

Job Matching — Ranked Opportunities

Job Matching Each job receives a weighted match score alongside matched skills, missing requirements, and recommended next actions.

Learning Roadmap — Personalized Curriculum

Learning Roadmap The roadmap converts market gaps into a prioritized learning path complete with dependencies, projects, and resource links.

AI Cover Letter Writer

Cover Letter The LangGraph cover-letter flow researches company context before drafting a targeted application letter.

Mock Interviewer — Session Setup

Interviewer Setup Interview sessions can be tuned by target role, focus area, and difficulty level.

Interview Preview The interviewer combines text, voice, scoring, and sample-answer feedback into a single practice workflow.

Mock Interviewer — Live Session

Live Interview Voice answers are transcribed, evaluated, scored, and summarized into an end-of-session report.

🚀 Quick Start

Prerequisites

  • Python 3.10+
  • Groq API key (free at console.groq.com) for LLM features
  • Microphone for the mock interview feature
  • Webcam (optional, for body language scoring)

Without GROQ_API_KEY, some deterministic/fallback paths still run, but roadmap generation, resume tailoring, cover letters, transcription, and interview questions all require Groq access.

Semantic matching is local-first. The app uses a cached all-MiniLM-L6-v2 snapshot when available and otherwise fails fast to deterministic taxonomy/lexical matching. To permit a one-time model download explicitly, set CAREERCOMPASS_ALLOW_MODEL_DOWNLOAD=1 before starting the app.

Installation

# 1. Clone the repository
git clone https://github.com/yixin16/CareerCompass-AI-Intelligent-Resume---Market-Gap-Analyzer.git
cd CareerCompass-AI-Intelligent-Resume---Market-Gap-Analyzer

# 2. Create and activate a virtual environment
python -m venv venv

# Windows
venv\Scripts\activate
# macOS / Linux
source venv/bin/activate

# 3. Install dependencies
pip install -r requirements.txt

# 4. Set your Groq API key
# Option A — .env file (recommended)
echo "GROQ_API_KEY=gsk_your_key_here" > .env

# Option B — environment variable
set GROQ_API_KEY=gsk_your_key_here      # Windows CMD
export GROQ_API_KEY=gsk_your_key_here   # macOS/Linux

Run the Web App

streamlit run app.py

App opens at http://localhost:8501

Run the CLI

# Place your resume in sample_data/resumes/
# Edit config.py to set JOB_SEARCH_KEYWORDS and JOB_SEARCH_LOCATION

python main.py

# All outputs saved to output/

Run Tests

pytest -q

The lightweight test suite uses dummy semantic matchers, so it never downloads or loads the transformer model.


📖 Usage Guide

Step 1 — Upload & Analyze Resume

  1. In the sidebar, enter your Groq API key (auto-loaded from .env if set).
  2. Upload your resume (PDF, DOCX, or TXT).
  3. Set your job keywords (e.g., Data Scientist, ML Engineer) and location.
  4. Click 🚀 Analyze resume & market.
  5. Review the profile summary, skill distribution, strengths, and recommendations.

Step 2 — Verify Your Professional Profile

The profile dashboard distinguishes extracted information from information you have confirmed.

  • Review the Profile Completeness score and its missing-data prompts.
  • Inspect each employment record for title, employer, dates, duration, responsibilities, and evidenced skills.
  • Compare total working years with the target-role readiness card for each keyword you selected.
  • Open Review and correct extracted profile to amend contact details, total working years, employment entries, or skills.
  • Save corrections to mark the profile as user-verified and immediately refresh job matches, skill gaps, the roadmap, and recommendations.

Step 3 — Explore Market Intelligence (Tab: 📊 Market Analysis)

  • Skill radar chart — visual breakdown of your skills by category.
  • Market keyword word cloud — trending skills employers are seeking right now.
  • Salary signals use the currency associated with the selected location; for example, a Malaysia search displays MYR values.

Step 4 — Review Job Matches (Tab: 💼 Job Matches)

  • Browse ranked job opportunities with match scores.
  • See exactly which skills you have and which are missing for each job.
  • Read the Listing quality and Confidence columns before acting on a role:
Label Meaning Included in market intelligence?
● Verified Complete schema.org job posting was retrieved Yes
◐ Partial Direct page was unavailable; matching uses a search snippet and is capped at 60% No
○ Demo Clearly labelled synthetic fallback, not a real vacancy No
  • AI Resume Tailor — select any job, click "✨ Generate Tailored Resume PDF," and download an ATS-optimized resume.

Step 5 — Build Your Learning Path (Tab: 🎓 Learning Roadmap)

Each missing skill has an expandable panel with:

  • A learning strategy that leverages your existing skills.
  • A specific hands-on project idea.
  • A difficulty rating and estimated time.
  • Direct links to documentation, YouTube, and LeetCode/Kaggle.

Step 6 — Generate an AI Cover Letter (Tab: ✍️ AI Cover Letter)

  1. Select your target job.
  2. Click "✨ Draft Cover Letter (Agentic Mode)."
  3. The AI researches the company online first, then writes a personalized letter.
  4. Edit it in the text area and download it as .txt.

Step 7 — Practice a Mock Interview (Tab: 🎤 Mock Interview)

Configuration:

Setting Options
Target Position Any matched job, or a generic "AI Engineer"
Interview Focus ⚖️ Balanced · 💬 Behavioral · 💻 Technical
Difficulty Level 🌱 Entry · 🚀 Mid · ⭐ Senior · 👑 Staff

Interview flow:

① Start Session → AI greets you (voice)
② AI asks a question (voice + text displayed)
③ Click 🎤 Record → speak your answer
④ Whisper transcribes → Llama evaluates → EdgeTTS responds
⑤ See a real-time score + sample answer
⑥ Repeat for 5–10 questions
⑦ End Session → view a full performance report (A–F grade)

🛠️ Tech Stack

Layer Technology Version Why This Choice
LLM Llama 3.3 70B via Groq Latest 300+ tok/s, JSON mode, free tier
Embeddings all-MiniLM-L6-v2 — Local inference, 384-dim, ~20ms/batch
Orchestration LangGraph + LangChain — Stateful multi-agent pipelines
Speech-to-Text Whisper Large V3 Turbo — 8× faster than Whisper base
Text-to-Speech Edge-TTS (+ gTTS fallback) — Neural voice quality at zero cost
Computer Vision MediaPipe + OpenCV ≥ 0.10 Real-time landmark tracking
Vector Similarity sentence-transformers cosine similarity — Local semantic matching with taxonomy-first shortcuts
Web Scraping DuckDuckGo Search + requests — Anti-bot resilient, no API key needed
PDF Processing pdfminer.six + xhtml2pdf — Text extraction and PDF generation
Frontend Streamlit + streamlit-webrtc ≥ 1.40 Session state, file upload, WebRTC
Charts Plotly + Matplotlib + WordCloud — Interactive visuals
Config python-dotenv — Secure API key management

How It Works: Pipeline

The full end-to-end data journey — from raw resume file to personalized output.

┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 1 │ Resume Ingestion                                              │
│  INPUT   │ PDF / DOCX / TXT file                                         │
│  MODULE  │ core/resume_parser.py                                         │
│  OUTPUT  │ Cleaned raw text string                                        │
└────────────────────────────────┬────────────────────────────────────────┘
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 2 │ AI Profile Construction                                       │
│  INPUT   │ Raw resume text                                               │
│  MODULE  │ core/resume_analyzer.py + core/semantic_matcher.py           │
│  OUTPUT  │ Profile, employment evidence, completeness, role readiness   │
└────────────────────────────────┬────────────────────────────────────────┘
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 3 │ Live Job Market Scan                                          │
│  INPUT   │ Job title keywords + location                                 │
│  MODULE  │ core/job_scraper.py                                           │
│  OUTPUT  │ Verified pages, partial snippets, or labelled demo records   │
└────────────────────────────────┬────────────────────────────────────────┘
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 4 │ Semantic Job Matching                                         │
│  INPUT   │ Candidate profile + scraped job list                         │
│  MODULE  │ core/job_matcher.py + core/semantic_matcher.py               │
│  OUTPUT  │ Ranked matches with provenance and confidence-aware scores   │
└────────────────────────────────┬────────────────────────────────────────┘
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 5 │ Skill Gap Analysis                                            │
│  INPUT   │ Aggregated missing skills from ranked match results          │
│  MODULE  │ core/gap_analyzer.py                                          │
│  OUTPUT  │ Prioritised gaps: critical / medium / low-priority          │
└────────────────────────────────┬────────────────────────────────────────┘
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 6 │ Transfer Learning Roadmap Generation                         │
│  INPUT   │ Top gaps + candidate profile                                 │
│  MODULE  │ core/learning_roadmap.py + Llama 3.3 via Groq               │
│  OUTPUT  │ Week-by-week curriculum with projects + curated links        │
└────────────────────────────────┬────────────────────────────────────────┘
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 7 │ AI Mock Interview Simulation                                  │
│  INPUT   │ Voice (microphone) + optional webcam feed                   │
│  MODULES │ core/interviewer.py · speech_analyzer.py · interview_scorer  │
│          │ core/camera_stream.py · camera_analyzer.py                   │
│  OUTPUT  │ Real-time Q&A + performance score (0–100, A–F grade)        │
└────────────────────────────────┬────────────────────────────────────────┘
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 8 │ Resume Tailoring & Cover Letter Generation                   │
│  INPUT   │ Candidate profile + target job description                   │
│  MODULES │ core/resume_tailor.py · core/agent_graph.py (LangGraph)     │
│  OUTPUT  │ ATS-optimised PDF resume + personalised cover letter .txt   │
└────────────────────────────────┬────────────────────────────────────────┘
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  STAGE 9 │ Reporting & Visualisation                                     │
│  INPUT   │ All analysis data                                            │
│  MODULES │ utils/report_generator.py · visualizer.py · pdf_generator   │
│  OUTPUT  │ Charts/reports from verified jobs; user-facing match results │
└─────────────────────────────────────────────────────────────────────────┘

🏗️ System Architecture

graph TB
    subgraph "📥 Ingestion Layer"
        A["Resume (PDF/DOCX/TXT)"] -->|"pdfminer / python-docx"| B["Raw Text"]
        B -->|"Taxonomy + Regex"| C["Structured Profile JSON"]
        C -->|"Taxonomy + SentenceTransformer"| D["Canonical Skills + Embeddings"]
        E["Job Keywords + Location"] -->|"Public Pages + Search Discovery"| F["Live Job Listings"]
        F -->|"Snippet Extraction"| G["Job Requirement Texts"]
        G -->|"Batch Embedding"| H["Market Vectors"]
    end

    subgraph "🧠 Intelligence Engine"
        D --> I["Cosine Similarity"]
        H --> I
        I -->|"Skill × Experience × Title"| J["Weighted Match Scores"]
        J -->|"Aggregate Missing Skills"| K["Gap Frequency Counter"]
        K -->|"× Domain Weight"| L["Severity Scores"]
        L -->|"Threshold split"| M["Critical / Medium / Low Gaps"]
    end

    subgraph "🤖 Agentic Layer"
        M -->|"Llama 3.3 70B + Transfer Learning"| N["Personalised Roadmap"]
        J -->|"Llama 3.3 STAR Rewrite"| O["Tailored Resume PDF"]
        P["Company Name"] -->|"LangGraph: Research Node"| Q["Company Intel"]
        Q -->|"LangGraph: Writing Node"| R["Cover Letter .txt"]
    end

    subgraph "🎤 Interaction Layer"
        S["Microphone Input"] -->|"Whisper Large V3 Turbo"| T["Transcript"]
        U["Webcam (Optional)"] -->|"MediaPipe + OpenCV"| V["Posture / Eye Contact"]
        T --> W["Llama 3.3 Interviewer"]
        V --> W
        W -->|"EdgeTTS / gTTS"| X["AI Voice Response"]
        W --> Y["Answer Score (0–100)"]
    end

    subgraph "📤 Output Layer"
        N --> Z["Streamlit Dashboard"]
        O --> Z
        R --> Z
        Y --> Z
    end

    style I fill:#e1f5ff,stroke:#0288d1
    style W fill:#f3e5f5,stroke:#7b1fa2
    style L fill:#fff3e0,stroke:#f57c00
Loading

📂 Project Structure

CareerCompass-AI/
│
├── 📄 app.py                      │ Streamlit web dashboard (main entry for UI)
├── 📄 main.py                     │ CLI pipeline (headless / batch mode)
├── 📄 config.py                   │ All configs: paths, weights, keywords, thresholds
├── 📄 requirements.txt            │ Python dependencies
├── 📄 .env                        │ API keys (gitignored)
│
├── 📁 core/                       │ Core AI & business logic
│   ├── pipeline.py                │   Shared resume→market analysis orchestrator
│   ├── resume_parser.py           │   PDF/DOCX/TXT text extraction
│   ├── resume_analyzer.py         │   Full profile construction (skills, exp, achievements)
│   ├── semantic_matcher.py        │   Skill taxonomy + lazy embedding matcher
│   ├── job_scraper.py             │   Multi-platform DuckDuckGo dorking scraper
│   ├── job_matcher.py             │   Weighted cosine similarity job ranker
│   ├── gap_analyzer.py            │   Gap clustering, severity scoring, triage
│   ├── learning_roadmap.py        │   Transfer-learning curriculum generator (Llama 3.3)
│   ├── cover_letter_generator.py  │   Standalone cover letter writer (Groq)
│   ├── resume_tailor.py           │   STAR-method ATS resume rewriter (Llama 3.3)
│   ├── agent_graph.py             │   LangGraph 2-node agentic cover letter workflow
│   ├── interviewer.py             │   Mock interviewer: LLM questions + TTS audio
│   ├── speech_analyzer.py         │   Pure-Python speech metrics (WPM, fillers, STAR)
│   ├── interview_scorer.py        │   Unified A–F performance scoring engine
│   ├── camera_analyzer.py         │   MediaPipe frame-level body language analysis
│   ├── camera_stream.py           │   WebRTC video processor bridge for Streamlit
│   ├── market_intelligence.py     │   Skill demand, trend, and salary analytics
│   ├── skill_graph.py             │   Learning dependency graph resolver
│   └── resume_optimizer.py        │   Resume version history and score deltas
│
├── 📁 utils/                      │ Shared helpers
│   ├── logger.py                  │   Structured file + console logger
│   ├── helpers.py                 │   Banner printer, summary display
│   ├── audio.py                   │   Safe audio-byte and duration helpers
│   ├── session_runtime.py         │   Per-browser-session runtime paths
│   ├── visualizer.py              │   Skill radar chart + market word cloud
│   ├── report_generator.py        │   CSV / JSON / Markdown report builder
│   └── pdf_generator.py           │   HTML → PDF converter for tailored resume
│
├── 📁 data/                       │ Static source data + ignored runtime snapshots
│   ├── skill_categories.py        │   Validated skill taxonomy and aliases
│   ├── skill_ontology.py          │   Skill prerequisites and learning estimates
│   └── job_templates.py           │   Fallback synthetic job structures
│
├── 📁 sample_data/resumes/        │ Place your resume here (CLI mode)
├── 📁 runtime/                    │ Ignored local uploads and generated interview audio
├── 📁 output/                     │ Ignored auto-generated reports and charts
├── 📁 logs/                       │ Ignored structured application logs
├── 📁 tests/                      │ Pytest coverage for core behavior
└── 📁 assets/                     │ Screenshots for README

Quality & Engineering Notes

  • Shared orchestration: core/pipeline.py centralizes the resume-to-market workflow so the Streamlit and CLI paths reuse the same analysis logic.
  • Taxonomy-first matching: core/semantic_matcher.py normalizes known skills and aliases before falling back to embedding similarity.
  • Lazy, offline-safe ML loading: sentence-transformers and torch load only when SemanticMatcher() is instantiated. Cached model files are resolved with local_files_only=True; an incomplete cache falls back immediately to deterministic taxonomy/lexical matching instead of retrying the network.
  • Deterministic tests: tests/ covers core matching along with session isolation, audio timing, job provenance, demo-data exclusion, Windows encoding, and camera compatibility — all without downloading the transformer model.
  • Runtime hygiene: Uploads, generated audio, logs, reports, snapshots, and resume-version history live in ignored runtime paths unless intentionally committed.

Privacy & Data Handling

CareerCompass AI is designed as a local-first Streamlit project.

Data Where it goes Notes
Uploaded resumes runtime/sessions/<session-id>/uploads/ Isolated to one browser session; ignored by git.
Generated interview audio runtime/sessions/<session-id>/audio/ Isolated to one browser session; ignored by git.
Reports and charts runtime/sessions/<session-id>/output/ Session-scoped local exports; ignored by git.
Logs logs/ Local diagnostics; ignored by git.
Market snapshots and resume versions runtime/sessions/<session-id>/ Separate history per Streamlit browser session. CLI mode uses the configured global paths.
LLM requests Groq API Required for LLM features; avoid submitting sensitive resumes to hosted APIs unless appropriate for your use case.

The static files under data/ — skill_categories.py, skill_ontology.py, and job_templates.py — are source data and should remain versioned.

Common Issues

Symptom Likely Cause Fix
AI writing/interview is unavailable GROQ_API_KEY is missing Add it to .env, Streamlit secrets, or enter a per-session override. Server keys are never prefilled into the browser.
Semantic model is unavailable The local transformer cache is missing or incomplete The app continues in deterministic lexical mode. Set CAREERCOMPASS_ALLOW_MODEL_DOWNLOAD=1 for one trusted run if downloads are permitted.
Some jobs show "Partial snippet" A job board returned 403/429 or otherwise blocked full-page validation The match stays provisional and capped at 60%; partial jobs are excluded from market trends.
Camera tab is unavailable Dependencies are missing, or MediaPipe lacks the legacy Solutions API Install the pinned requirements; this implementation uses mediapipe==0.10.21. Newer builds such as 0.10.33 no longer expose the required solutions namespace.
PDF export is blank xhtml2pdf failed to render malformed generated content Retry tailoring, or inspect the generated profile structure.

Module-by-Module Breakdown

core/resume_parser.py — File Ingestion

Role: Converts raw document files into clean plain text.

Step Action
1 Detect the file extension (.pdf, .docx, .txt)
2 Extract text with pdfminer.six (PDF) or python-docx (DOCX)
3 Strip null characters and collapse excess whitespace with regex
4 Return a cleaned string ready for NLP

core/semantic_matcher.py — The AI Brain (Singleton)

Role: Provides taxonomy-first skill normalization plus vector-based operations through a lazy singleton.

# Loaded lazily on first SemanticMatcher() instantiation
model = SentenceTransformer('all-MiniLM-L6-v2')  # 384-dim embeddings

# Pre-computes anchor embeddings for 5 categories:
# Programming · Data & AI · Web & UI · Cloud & DevOps · Soft Skills

# Key methods:
batch_filter_skills(candidates)       # Matrix multiply vs. 10 "skill" anchors
batch_classify_categories(skills)     # Assigns each skill to a category
find_best_match(query, options)       # 1-to-N semantic match with threshold
get_similarity(text1, text2)          # Pairwise cosine score (0.0–1.0)

Why a lazy singleton? Importing and loading the transformer model is expensive. The model and its ML dependencies load only when SemanticMatcher() is instantiated, then get reused across modules (resume_analyzer, job_matcher, gap_analyzer).


core/resume_analyzer.py — Profile Constructor

Role: Builds a comprehensive 360° candidate profile from raw resume text.

Processing pipeline:

  1. _extract_contact_info() — Best-effort name extraction plus regex for email, phone, and LinkedIn/GitHub URLs.
  2. extract_skills_dynamically():
    • Extracts known skills first from data/skill_categories.py and data/skill_ontology.py.
    • Normalizes aliases, such as Amazon Web Services → AWS, React.js → React, and sklearn → Scikit-Learn.
    • Uses regex to cast a broader net, then validates unknown candidates with batch_filter_skills() at a semantic threshold ≥ 0.40.
    • Assigns categories with batch_classify_categories() — Programming/Data/Cloud/Web/Soft Skills.
    • _estimate_proficiency_enhanced() checks a ±100-character window around each skill mention for keywords like "advanced" or "5+ years," returning a score of 0.5–1.0 and a label (Beginner/Intermediate/Expert).
  3. _calculate_experience_robust() — Isolates the work-experience section, excludes education/project dates, merges overlapping employment ranges, falls back to explicit work-experience statements, and preserves the years-only result as timeline_seniority_level.
  4. _extract_employment_history() — Builds dated role/company records with responsibilities, achievements, skills used, duration, source excerpts, extraction confidence, employment type, and deterministic scope/impact signals.
  5. _attach_skill_evidence() — Links skills to employment, project, certification, or resume evidence and calculates professional years, recency, and confidence.
  6. calculate_technology_depth() — Scores the strongest eight work-evidenced skills from 55% professional duration (two-year cap per skill), 25% evidence confidence, and 20% recency. Breadth and multi-domain influence are capped; projects/certifications add no more than five points.
  7. calculate_professional_maturity() — Produces an explainable 0–100 score using 45% timeline, 25% role scope, 20% technical depth, and 10% impact. Internship scope/impact use a 0.60 multiplier, and duration guards prevent short careers from being over-promoted.
  8. build_target_role_profiles() — Calculates role-specific readiness from relevant duration (30%), expected-skill coverage (30%), professionally evidenced target-stack depth (25%), and relevant responsibility/impact alignment (15%). Role level uses the same hybrid model restricted to relevant jobs and technologies.
  9. calculate_profile_completeness() — Scores contact details, timeline quality, quantified achievements, skill evidence, and professional links.
  10. _extract_achievements() — Regex for N%, $N, NM users patterns with surrounding context.
  11. _analyze_skill_diversity() — Classifies the profile as Specialist / Generalist / Broad Explorer.
  12. _generate_profile_summary() — Produces a human-readable 3–5 sentence AI-style summary using the hybrid career level.
  13. _generate_recommendations() — Rule-based, actionable tips on career growth, branding, and experience.

Professional-maturity level mapping:

Maturity score Displayed level
<30 Entry-Level
30–54 Junior
55–69 Mid-Level
70–79 Mid-Senior
80–89 Senior
90+ Staff/Principal

Output JSON profile:

{
  "contact_info": { "email": "...", "phone": "...", "links": [...] },
  "skills_by_category": {
    "Data & AI": [{"skill": "PyTorch", "proficiency": 0.92, "proficiency_level": "Expert", "professional_years": 3.5, "last_used_year": 2026, "evidence_confidence": 0.9}]
  },
  "total_skills": 38,
  "experience": {
    "total_years": 4,
    "seniority_level": "Mid-Level",
    "timeline_seniority_level": "Mid-Level",
    "professional_maturity": {
      "overall_score": 66.5,
      "level": "Mid-Level",
      "components": {"timeline": 65, "role_scope": 62, "technical_depth": 76, "impact": 48},
      "calculation_basis": "hybrid_professional_evidence",
      "explanations": ["Timeline contributes 45% from 4 verified working years."]
    },
    "career_level_basis": "hybrid_professional_evidence"
  },
  "employment_history": [{"role": "ML Engineer", "company": "Example", "duration_years": 3.5, "employment_type": "full_time", "role_scope_score": 62, "impact_score": 48, "technology_evidence_score": 76}],
  "target_role_profiles": [{"target_role": "ML Engineer", "relevant_years": 3.5, "readiness_score": 82, "experience_score": 100, "role_scope_score": 62, "technical_depth_score": 76, "impact_score": 48, "role_level_basis": "hybrid_professional_evidence_restricted_to_target"}],
  "profile_completeness": {"score": 85, "missing_items": ["Add a portfolio or professional profile link"]},
  "career_level": "Mid-Level",
  "career_level_basis": "hybrid_professional_evidence",
  "skill_diversity": { "profile_type": "Full-Stack / Generalist", ... },
  "achievements": [{ "metric": "40%", "context": "..." }],
  "strengths": ["Seasoned Professional with 4+ years..."],
  "profile_summary": "A Mid-Level professional...",
  "recommendations": [{ "priority": "High", "suggestion": "..." }]
}

core/job_scraper.py — Live Market Intelligence

Role: Discovers public job listings, handles blocked pages conservatively, and preserves the strongest accessible metadata.

Strategy — "search engine dorking": Direct API access to job boards is blocked, so DuckDuckGo is used to search within specific domain namespaces instead:

# Example dork query:
site:linkedin.com/jobs/view "Data Scientist" Malaysia
site:my.jobstreet.com/job/ "Machine Learning Engineer" Malaysia
site:malaysia.indeed.com "Python Developer" Malaysia
site:glassdoor.com "AI Engineer" Malaysia
  • Uses current my.jobstreet.com/job/<id> vacancy URLs and rejects aggregate JobStreet search pages.
  • Fetches public JobStreet result cards when accessible, with current-domain DuckDuckGo discovery as a fallback.
  • Fetches the top search results per keyword per platform.
  • Fetches each destination and prefers complete schema.org JobPosting descriptions.
  • Retains usable snippets as search_snippet_partial when a page returns 403/429 or stays unavailable after one retry.
  • Opens a per-run domain circuit after the first 403/429 to avoid repeatedly hitting a blocked host.
  • Recovers employer identity from schema.org, explicit listing cards, visible page metadata, search-result titles, selected snippets, and LinkedIn URL slugs in descending confidence order.
  • Merges duplicate discoveries field by field so a richer company name or longer snippet is not overwritten by a poorer result.
  • Records source, retrieval timestamp, description source, data quality, company_source, company_confidence, and whether the employer name was inferred.
  • Uses short randomized discovery delays to reduce rate-limiting.
  • Caps partial match scores at 60% and excludes partial records from market snapshots, salary signals, word clouds, and historical trends.
  • Resolves salary currency from the selected location (e.g., Malaysia → MYR) and extracts only explicitly matching currency amounts.
  • Fallback: Only when both verified and partial collections are empty does generate_synthetic_jobs() create visibly labelled demo roles.

core/job_matcher.py — Semantic Matchmaker

Role: Scores each candidate–job pair across three dimensions.

Matching algorithm:

Step 1: Extract job requirements
  - Taxonomy and aliases identify known skills first
  - Regex finds additional capitalised tokens from the job description
  - batch_filter_skills() validates unknown candidates (threshold ≥ 0.45)

Step 2: Skill Match Score
  For each required skill:
    → Try an exact case-insensitive match first (fastest)
    → Fall back to find_best_match() semantic match (threshold 0.70)
  score = matched_count / required_count

Step 3: Experience Match Score
  - Extract "N+ years" from the job description
  - Identify relevant employment from job-title tokens, required technologies, and the closest target-role profile
  - Experience score = relevant-years fit × 0.50
                     + relevant role-scope alignment × 0.25
                     + professionally evidenced technology alignment × 0.25
  - Unrelated calendar experience cannot satisfy a target role by itself

Step 4: Title Semantic Match
  - Compare the job title with selected target roles and actual employment titles
  - Use the closest real title; do not synthesize a generic "<level> Developer" proxy

Step 5: Final Weighted Score
  overall = (skill_score × 0.60) + (title_sim × 0.20) + (exp_score × 0.20)

Match quality labels:

Score Label Priority
≥ 0.80 Excellent 🔥 URGENT
≥ 0.65 Strong ✅ HIGH
≥ 0.50 Good 📝 MEDIUM
< 0.50 Weak ⚠️ LOW

core/gap_analyzer.py — Skill Gap Engine

Role: Identifies and prioritizes what the candidate is missing at market scale.

4-step algorithm:

Step 1: Aggregation
  - Collect all missing_required skills from every match result
  - Count raw frequency: {"MLflow": 8, "Airflow": 6, "Spark": 4}

Step 2: Semantic Clustering (threshold 0.85 — very strict)
  - Prevents "React" and "ReactJS" from being counted separately
  - Merges synonyms into canonical clusters

Step 3: Severity Scoring
  - Severity = frequency × domain_weight
  - Domain weights:
      Programming    → 1.5× multiplier
      Data & AI      → 1.4×
      Cloud & DevOps → 1.3×
      Web & UI       → 1.2×
      Soft Skills    → 0.8× (important, but not a hard blocker)
  - Market Penetration = (frequency / total_jobs) × 100%

Step 4: Threshold-Based Triage
  - Critical: market_penetration > 40% OR severity_score ≥ 2.5
  - Medium:  frequency > 1
  - Low:     single occurrence ("nice-to-have")

Output:

{
  "critical_gaps": ["MLflow", "Airflow"],
  "medium_priority_gaps": ["FastAPI", "Terraform"],
  "low_priority_gaps": ["Tableau"],
  "detailed_analysis": [
    {"skill": "MLflow", "frequency": 8, "market_penetration": 72.7, "severity_score": 11.2}
  ]
}

core/learning_roadmap.py — AI Career Coach

Role: Generates a personalized learning curriculum using transfer-learning strategies via Llama 3.3.

Workflow:

  1. Extracts the candidate's current skills and experience level from the profile.
  2. Builds a focused prompt (capped at 6 target skills to stay within the context window).
  3. The transfer-learning prompt instructs Llama 3.3 to:
    • Reference overlapping concepts from the candidate's existing stack.
    • Suggest projects that combine old and new skills.
    • Estimate realistic timelines based on skill proximity.
  4. The AI responds in structured JSON; post-processing then adds deterministic resource links (no hallucinated URLs):
    • Programming → LeetCode + GitHub
    • Data & AI → Kaggle + Papers With Code
    • Cloud & DevOps → AWS Workshops + Docker Hub
    • Web & UI → MDN Web Docs
  5. Resources are sorted by difficulty: Low → Medium → High.

Fallback (no API key): Returns a rule-based template roadmap without AI-generated content.


core/interviewer.py — Context-Aware AI Interviewer

Role: Powers the end-to-end mock interview conversation via Groq LLMs and TTS.

Key capabilities:

  • Difficulty system (4 levels): Each level has its own expectation, technical_depth, behavioral_depth, and example questions, hard-coded in difficulty_configs.
  • Focus system (3 modes): behavioral (80/20 split), technical (90/10), and balanced (50/50), each with its own topic list.
  • AI Engineer knowledge base: Built-in domain knowledge covering ML fundamentals, LLMs/RAG, computer vision, MLOps, and system design — injected into every system prompt.
  • Structured JSON output: Llama 3.3 runs in json_object response mode, returning question, sample_answer, and answer_score (5 rubric dimensions, each scored 1–10).
  • Progressive questioning: Rounds 1–2 warm up, 3–5 test core knowledge, 6–8 go deeper, and 9+ probe edge cases.
  • TTS pipeline:
    • Tries EdgeTTS (en-US-AriaNeural) first for neural voice quality.
    • Falls back to gTTS if EdgeTTS fails.
    • Validates audio file size (> 1KB) before returning the path.

Rubric dimensions (each scored 1–10):

Dimension What It Measures
content_relevance Did they actually answer the question?
technical_depth Depth of technical knowledge shown
communication_clarity Clarity and structure of the answer
star_method_usage STAR framework adherence (behavioral) / structured problem solving (technical)
specific_examples Concrete examples with quantified metrics

core/speech_analyzer.py — Speech Analytics Engine

Role: Extracts quantitative metrics from transcribed interview answers. Pure Python — no external ML dependencies.

Metrics computed:

Metric How Ideal Range
Words Per Minute word_count / (duration_sec / 60) 130–170 WPM
Filler Word Count Regex patterns: \bum\b, \buh\b, \byou know\b, etc. < 3% of words
Verbal Confidence assertive_count - hedge_count, normalized per 100 words Net positive
STAR Detection Keyword patterns for Situation / Task / Action / Result ≥ 2/4 components
Vocabulary Diversity Type-token ratio: unique_words / total_words ≥ 0.55
Avg Sentence Length word_count / sentence_count 12–25 words

Component scores (0–100) → composite overall_speech_score:

overall = WPM (20%) + Filler Control (25%) + Confidence (25%) + Structure (15%) + Vocabulary (15%)

core/interview_scorer.py — Performance Scoring Engine

Role: Merges LLM answer quality, speech analytics, and camera data into a single quantitative performance score.

Dimension weights:

Dimension With Camera Without Camera
Content (LLM) 35% 45%
Speech Delivery 25% 30%
Body Language 20% —
Structure / STAR 20% 25%

Content score breakdown:

content_score = (content_relevance × 30%) + (technical_depth × 30%)
              + (communication_clarity × 25%) + (specific_examples × 15%)

Letter grade scale:

Score Grade Score Grade
≥ 93 A 77–79 C+
90–92 A- 73–76 C
87–89 B+ 70–72 C-
83–86 B 67–69 D+
80–82 B- 60–66 D/D-
< 60 F

Session report (get_session_report()): Averages all per-answer scores, identifies top strengths and improvement areas, detects improvement trajectory (comparing 2nd-half scores to 1st-half scores), and summarizes aggregate speech/camera stats.


core/camera_stream.py + core/camera_analyzer.py — Vision Pipeline

Role: Analyzes body language in real time during interviews via webcam.

  • Uses streamlit-webrtc for browser-based WebRTC video streaming.
  • InterviewVideoProcessor processes every 3rd frame (~10 FPS analysis) to maintain performance.
  • CameraAnalyzer (MediaPipe) tracks:
    • Eye contact % — iris landmark projection relative to the screen midpoint.
    • Posture score — shoulder alignment and head tilt angle.
    • Movement stability — frame-to-frame landmark displacement.
    • Attention drift — head rotation away from the screen.
  • A thread-safe _lock ensures the main Streamlit thread can safely read the latest analysis.

core/resume_tailor.py — ATS Optimization Agent

Role: Rewrites the candidate's resume profile to maximize match with a target job description.

Rules enforced in the system prompt:

  1. Truthfulness — Never invent experience; only optimize what already exists.
  2. ATS keyword injection — Extract the top 5 technical keywords from the JD and ensure they appear in the summary/skills.
  3. STAR method rewrite — Transform bullet points into [Action Verb] + [Context] + [Result/Metric].
  4. Skill re-ranking — Move JD-relevant skills to the top of each category list.
  5. Summary hook — A 3-sentence elevator pitch strictly aligned with the target role.

Reliability safeguard: If the LLM omits contact_info or restructures experience incorrectly, the original values are restored from the input profile before returning.


core/agent_graph.py — Agentic Cover Letter (LangGraph)

Role: A two-node agentic workflow that researches a company before writing a personalized cover letter.

State: { company_name, job_title, job_description, resume_text, research_data, cover_letter }

Node 1 — Researcher:
  → DuckDuckGoSearchRun: "recent news mission values work culture of {company}"
  → Stores results in state["research_data"]

Node 2 — Writer:
  → ChatPromptTemplate: uses resume_text + job_title + research_data
  → Instructions: open with a company news hook, connect candidate skills to the JD
  → Writes to state["cover_letter"]

Edge: researcher → writer → END

core/pipeline.py — Shared Analysis Orchestrator

Role: Runs the resume → jobs → matches → gaps → roadmap workflow once for both the Streamlit and CLI entry points.

CareerAnalysisPipeline.run_resume_market_analysis() accepts a resume path, keywords, location, an optional API key, and an optional progress callback. Its constructor also accepts session-scoped output, resume-history, and market-snapshot paths. The result includes parsed data plus explicit job-data provenance.


app.py — Streamlit Frontend

Role: Provides the interactive dashboard and delegates the core workflow to CareerAnalysisPipeline.

Analysis flow triggered by "Analyze resume and market":

  1. Create an isolated runtime/sessions/<session-id>/ workspace and save the upload under a generated filename.
  2. Call CareerAnalysisPipeline.run_resume_market_analysis() with Streamlit status updates.
  3. Store the returned resume_text, resume_profile, matches, roadmap, market snapshot/history, and dependency chain in session state.
  4. Render charts, job matches, the roadmap, the cover letter, resume tailoring, and the mock interview tabs.

The interface uses a responsive two-surface layout: the sidebar contains upload and target controls, while the main canvas uses spacious two-column evidence rows, progressive-disclosure profile sections, task-grouped navigation, and readable job cards. The full comparison table is available on demand. Subtle entrance motion is disabled automatically when the operating system requests reduced motion. Optional camera dependencies are imported only when camera feedback is enabled.

6 task-oriented workspaces:

Tab Content
Profile insights Skill distribution and verified market-demand visuals
Job matches Spacious recommendation cards, employer/listing provenance, filters, and optional comparison table
Growth plan Nested learning-roadmap and skill-graph views
Applications Nested cover-letter and resume-lab views
Interview Voice interview simulator with optional, lazily loaded camera feedback
Market insights Salary, demand, snapshots, and location-aware currency insights from verified jobs

See System Improvement Roadmap for the prioritized reliability, feature, and architecture plan.


main.py — CLI Entry Point

Role: Provides an alternative command-line pipeline for batch or server-side processing (no browser required).

Runs the same shared CareerAnalysisPipeline headlessly, then writes timestamped reports to output/:

  • Strategic job match CSV
  • High-priority hotlist CSV
  • Learning roadmap CSV
  • Full analysis JSON
  • COVER_LETTER_1_<Company>.txt for top viable matches
  • visual_skill_radar.png
  • visual_market_wordcloud.png

⚙️ Configuration

.env — Secrets

GROQ_API_KEY=gsk_...       # Required for all LLM features
CAREERCOMPASS_ALLOW_MODEL_DOWNLOAD=0  # Default: never download embeddings implicitly

config.py — Global Settings

# ── Job Search ────────────────────────────────────────
JOB_SEARCH_KEYWORDS = ["Data Scientist", "ML Engineer", "AI Engineer"]
JOB_SEARCH_LOCATION = "Malaysia"
TOTAL_MAX_JOBS = 30
INCLUDE_SYNTHETIC_JOBS = True       # Fallback if scraping returns 0 results

# ── Matching Weights ──────────────────────────────────
MATCHING_WEIGHTS = {
    'skills': 0.60,
    'title': 0.20,
    'experience': 0.20
}

SKILL_CATEGORY_WEIGHTS = {
    'ml_ai': 1.2,           # High-value AI skills
    'data_engineering': 1.1,
    'cloud': 1.1,
    'languages': 1.0,
    'databases': 1.0,
    'web_frameworks': 0.9,
    'tools': 0.8
}

# ── Runtime Paths ────────────────────────────────────
TEMP_UPLOADS_DIR = RUNTIME_DIR / "temp_uploads"
AUDIO_DIR = RUNTIME_DIR / "audio"

# ── Match Quality Thresholds ──────────────────────────
MATCH_THRESHOLDS = {
    'excellent': 0.85,
    'strong': 0.70,
    'good': 0.55,
    'fair': 0.40
}

# ── Interview Model Settings ──────────────────────────
# Configured directly in core/interviewer.py:
LLM_MODEL    = "llama-3.3-70b-versatile"   # Groq model
STT_MODEL    = "whisper-large-v3-turbo"     # Whisper model
TTS_VOICE    = "en-US-AriaNeural"           # EdgeTTS voice

About

CareerCompass AI is a local-first AI career platform that analyzes resumes, scans job market signals, ranks job fit with semantic matching, identifies skill gaps, builds personalized learning roadmaps, generates tailored career documents, and runs voice-based mock interviews with scoring.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages