# otniel113/autocvselector architecture

> Architecture diagram of the GitHub repository otniel113/autocvselector, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-14). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/otniel113/autocvselector
- Repository: https://github.com/otniel113/autocvselector

## Overview

1. **Repository purpose**
   - This is a **batch-oriented CV screening pipeline** for high-volume hiring, not a web app.
   - The system turns a single job description plus a folder of candidate resumes into ranked hiring recommendations.

2. **High-level architecture**
   - The code is split into **three sequential stages**, each with a clear boundary:
     - **JD extraction and structuring**
     - **semantic similarity screening**
     - **LLM-based final evaluation and ranking**
   - Intermediate outputs are persisted to disk so each phase can be rerun independently.

3. **Input layer**
   - The main inputs live under two folders:
     - `JobDesc/` for the vacancy source document
     - `CVs/` for candidate resume files
   - The repo includes both **PDF and Markdown versions** of documents, indicating a conversion/parsing step before scoring.
   - `Vacancy_criteria.json` and `screening_results.json` are intermediate artifacts produced by the pipeline.

4. **Phase 1: Job description extraction**
   - `step1_extract_jd.py` is the first transformation boundary.
   - It converts the raw job description into a **structured criteria JSON** representation.
   - The README indicates this stage uses **Gemini** to extract hard skills, soft skills, and experience requirements into a machine-readable schema.
   - Output is stored in `JobDesc/Vacancy_criteria.json`.

5. **Phase 2: Resume parsing and fast screening**
   - `step2_similarity_screening.py` performs the first candidate reduction pass.
   - Candidate resumes in `CVs/` are parsed into text-friendly form; the README says this uses **LlamaParse** for high-fidelity PDF parsing.
   - The screening logic uses **Hugging Face embeddings** with `BAAI/bge-m3` and cosine similarity to compare each CV against the JD criteria.
   - This phase is the cost-saving filter that removes low-relevance candidates before any expensive LLM reasoning.

6. **Phase 3: Deep evaluation and ranking**
   - `step3_gemini_evaluation.py` consumes the shortlisted candidates and performs a deeper assessment.
   - The README describes this as a **Gemini 3 Flash** “senior recruiter” evaluation step.
   - This stage appears to do more nuanced scoring, including experience calculation, degree synonym recognition, and compensation logic for non-traditional but strong candidates.

7. **Data flow between stages**
   - The pipeline flows from **raw documents → structured criteria → similarity scores → final ranked report**.
   - The key persisted handoff points are:
     - `Vacancy_criteria.json` from phase 1
     - `screening_results.json` from phase 2
     - `final_evaluation_results.json` from phase 3
   - This file-based orchestration makes the system easy to run as standalone scripts without a service layer.

8. **External dependencies and service boundaries**
   - The architecture depends on three external AI services:
     - **LlamaParse** for document parsing
     - **Hugging Face Inference API** for embeddings
     - **Google Gemini API** for extraction and final reasoning
   - API keys are loaded from `.env`, with `.env.example` acting as the configuration template.

9. **Local compute and library layer**
   - The runtime is **Python 3.10+**, with 3.11 recommended.
   - `requirements.txt` points to a lightweight ML/data stack, including `numpy`, `scikit-learn`, `pydantic`, `huggingface-hub`, and `python-dotenv`.
   - This suggests most orchestration and scoring logic is local, while the heavy AI capabilities are delegated to hosted APIs.

10. **Outputs and operational model**
   - The final deliverable is `final_evaluation_results.json`, which contains the ranked candidate list and reasoning.
   - Because the repo stores both intermediate and final artifacts, the system is designed for **auditable screening**, where each stage can be inspected separately.
   - The architecture is optimized for **high-volume offline processing** rather than interactive, real-time candidate review.

Main entry points: [`step1_extract_jd.py`](https://github.com/otniel113/autocvselector/blob/main/step1_extract_jd.py) (Extract JD), [`step2_similarity_screening.py`](https://github.com/otniel113/autocvselector/blob/main/step2_similarity_screening.py) (Screen CVs), [`step3_gemini_evaluation.py`](https://github.com/otniel113/autocvselector/blob/main/step3_gemini_evaluation.py) (Rank candidates), [`.env.example`](https://github.com/otniel113/autocvselector/blob/main/.env.example) (Env template)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_inputs["Inputs"]
  node_job_folder[("JobDesc<br/>input folder")]
  node_cv_folder[("CVs<br/>input folder")]
  node_job_pdf["Vacancy PDF<br/>source doc<br/>[Vacancy.pdf]"]
  node_job_md["Vacancy MD<br/>text doc<br/>[Vacancy.md]"]
  node_cv_pdf["CV PDFs<br/>source docs<br/>[CV Sample 1.pdf]"]
  node_cv_md["CV MDs<br/>text docs<br/>[CV Sample 1.md]"]
end

subgraph group_stage1["Stage 1"]
  node_step1["Extract JD<br/>python script"]
  node_jd_criteria["Criteria JSON<br/>artifact"]
end

subgraph group_stage2["Stage 2"]
  node_step2["Screen CVs<br/>python script"]
  node_screen_results["Screening JSON<br/>artifact"]
end

subgraph group_stage3["Stage 3"]
  node_step3["Rank candidates<br/>python script"]
end

subgraph group_outputs["Outputs"]
  node_final_results["Final JSON<br/>report artifact"]
end

subgraph group_external["External services"]
  node_gemini_extract{{"Gemini extract<br/>llm service"}}
  node_llamaparse{{"LlamaParse<br/>parser service"}}
  node_hf_embeddings{{"BGE-M3<br/>embedding api"}}
  node_gemini_eval{{"Gemini rank<br/>llm service"}}
end

subgraph group_runtime["Runtime"]
  node_env_file["Env template<br/>config<br/>[.env.example]"]
  node_deps["Dependencies<br/>python requirements<br/>[requirements.txt]"]
end

node_job_folder -->|"contains"| node_job_pdf
node_job_folder -->|"contains"| node_job_md
node_cv_folder -->|"contains"| node_cv_pdf
node_cv_folder -->|"contains"| node_cv_md
node_job_pdf -->|"input"| node_step1
node_job_md -->|"input"| node_step1
node_step1 -->|"calls"| node_gemini_extract
node_gemini_extract -->|"writes"| node_jd_criteria
node_jd_criteria -->|"input"| node_step2
node_cv_pdf -->|"parsed by"| node_llamaparse
node_llamaparse -->|"produces"| node_cv_md
node_cv_md -->|"input"| node_step2
node_step2 -->|"calls"| node_hf_embeddings
node_hf_embeddings -->|"writes"| node_screen_results
node_screen_results -->|"input"| node_step3
node_step3 -->|"calls"| node_gemini_eval
node_gemini_eval -->|"writes"| node_final_results
node_env_file -.->|"configures"| node_step1
node_env_file -.->|"configures"| node_step2
node_env_file -.->|"configures"| node_step3
node_deps -.->|"supports"| node_step1
node_deps -.->|"supports"| node_step2
node_deps -.->|"supports"| node_step3

click node_job_folder "https://github.com/otniel113/autocvselector/tree/main/JobDesc"
click node_cv_folder "https://github.com/otniel113/autocvselector/tree/main/CVs"
click node_step1 "https://github.com/otniel113/autocvselector/blob/main/step1_extract_jd.py"
click node_jd_criteria "https://github.com/otniel113/autocvselector/blob/main/JobDesc/Vacancy_criteria.json"
click node_step2 "https://github.com/otniel113/autocvselector/blob/main/step2_similarity_screening.py"
click node_screen_results "https://github.com/otniel113/autocvselector/blob/main/CVs/screening_results.json"
click node_step3 "https://github.com/otniel113/autocvselector/blob/main/step3_gemini_evaluation.py"
click node_final_results "https://github.com/otniel113/autocvselector/blob/main/final_evaluation_results.json"
click node_job_pdf "https://github.com/otniel113/autocvselector/blob/main/JobDesc/Vacancy.pdf"
click node_job_md "https://github.com/otniel113/autocvselector/blob/main/JobDesc/Vacancy.md"
click node_cv_pdf "https://github.com/otniel113/autocvselector/blob/main/CVs/CV Sample 1.pdf"
click node_cv_md "https://github.com/otniel113/autocvselector/blob/main/CVs/CV Sample 1.md"
click node_env_file "https://github.com/otniel113/autocvselector/blob/main/.env.example"
click node_deps "https://github.com/otniel113/autocvselector/blob/main/requirements.txt"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_job_folder,node_cv_folder,node_job_pdf,node_job_md,node_cv_pdf,node_cv_md,node_env_file,node_deps toneBlue
class node_step1,node_jd_criteria toneAmber
class node_step2,node_screen_results toneMint
class node_step3 toneRose
class node_final_results toneIndigo
class node_gemini_extract,node_llamaparse,node_hf_embeddings,node_gemini_eval toneTeal
```

## Components

### Inputs

Source documents and folders

- [JobDesc](https://github.com/otniel113/autocvselector/tree/main/JobDesc): input folder · Vacancy documents and stage-1 artifact store · `JobDesc`
- [CVs](https://github.com/otniel113/autocvselector/tree/main/CVs): input folder · Candidate resumes and stage-2 artifact store · `CVs`
- [Vacancy PDF](https://github.com/otniel113/autocvselector/blob/main/JobDesc/Vacancy.pdf): source doc · Raw vacancy document · `JobDesc/Vacancy.pdf`
- [Vacancy MD](https://github.com/otniel113/autocvselector/blob/main/JobDesc/Vacancy.md): text doc · Converted vacancy text version · `JobDesc/Vacancy.md`
- [CV PDFs](https://github.com/otniel113/autocvselector/blob/HEAD/CVs/CV%20Sample%201.pdf): source docs · Raw candidate resume documents · `CVs/CV Sample 1.pdf`
- [CV MDs](https://github.com/otniel113/autocvselector/blob/HEAD/CVs/CV%20Sample%201.md): text docs · Converted resume text versions · `CVs/CV Sample 1.md`

### Stage 1

Job description extraction

- [Extract JD](https://github.com/otniel113/autocvselector/blob/main/step1_extract_jd.py): python script · Transforms raw vacancy text into structured criteria · `step1_extract_jd.py`
- [Criteria JSON](https://github.com/otniel113/autocvselector/blob/main/JobDesc/Vacancy_criteria.json): artifact · Structured job requirements used by later stages · `JobDesc/Vacancy_criteria.json`

### Stage 2

Similarity screening

- [Screen CVs](https://github.com/otniel113/autocvselector/blob/main/step2_similarity_screening.py): python script · Parses resumes and computes similarity scores · `step2_similarity_screening.py`
- [Screening JSON](https://github.com/otniel113/autocvselector/blob/main/CVs/screening_results.json): artifact · Similarity scores and shortlist from stage 2 · `CVs/screening_results.json`

### Stage 3

Final evaluation

- [Rank candidates](https://github.com/otniel113/autocvselector/blob/main/step3_gemini_evaluation.py): python script · Performs deeper Gemini-based recruiter evaluation · `step3_gemini_evaluation.py`

### Outputs

Persisted artifacts and reports

- [Final JSON](https://github.com/otniel113/autocvselector/blob/main/final_evaluation_results.json): report artifact · Ranked recommendations with reasoning · `final_evaluation_results.json`

### External services

Hosted AI and parsing dependencies

- **Gemini extract**: llm service · Extracts hard skills, soft skills, and experience requirements
- **LlamaParse**: parser service · High-fidelity PDF parsing for resume text extraction
- **BGE-M3**: embedding api · Hugging Face embeddings for semantic matching
- **Gemini rank**: llm service · Final scoring, reasoning, and ranking of shortlisted candidates

### Runtime

Local Python execution and packages

- [Env template](https://github.com/otniel113/autocvselector/blob/main/.env.example): config · API key and runtime configuration template · `.env.example`
- [Dependencies](https://github.com/otniel113/autocvselector/blob/main/requirements.txt): python requirements · Local stack for orchestration and scoring · `requirements.txt`

## Connections

- JobDesc → Vacancy PDF: contains · Vacancy source document
- JobDesc → Vacancy MD: contains · Converted text version
- CVs → CV PDFs: contains · Candidate PDFs
- CVs → CV MDs: contains · Candidate text versions
- Vacancy PDF → Extract JD: input · Raw job description
- Vacancy MD → Extract JD: input · Text-ready vacancy content
- Extract JD → Gemini extract: calls · Uses Gemini for criteria extraction
- Gemini extract → Criteria JSON: writes · Structured vacancy criteria
- Criteria JSON → Screen CVs: input · Criteria schema for screening
- CV PDFs → LlamaParse: parsed by · Resume PDF parsing
- LlamaParse → CV MDs: produces · Text representation of resumes
- CV MDs → Screen CVs: input · Candidate resume text
- Screen CVs → BGE-M3: calls · Semantic embedding generation
- BGE-M3 → Screening JSON: writes · Similarity scores and shortlist
- Screening JSON → Rank candidates: input · Shortlisted candidates
- Rank candidates → Gemini rank: calls · Uses Gemini for final evaluation
- Gemini rank → Final JSON: writes · Ranked final recommendations
- Env template → Extract JD: configures · API credentials and runtime settings
- Env template → Screen CVs: configures · API credentials and runtime settings
- Env template → Rank candidates: configures · API credentials and runtime settings
- Dependencies → Extract JD: supports · Local Python runtime dependencies
- Dependencies → Screen CVs: supports · Local Python runtime dependencies
- Dependencies → Rank candidates: supports · Local Python runtime dependencies
