AI CV Analysis & RAG Pipeline

Automated CV Analysis & Retrieval-Augmented Generation for Candidate Screening

Learn More Try Demo View on GitHub

📋 Project Overview

Hệ thống này là một nền tảng phân tích và truy vấn hồ sơ ứng viên (CV) tự động bằng cách ứng dụng kiến trúc RAG (Retrieval-Augmented Generation). Hệ thống cho phép người dùng tìm kiếm thông tin ứng viên trong kho dữ liệu (HR/IT) hoặc tải lên một CV hoàn toàn mới để AI phân tích và trả lời câu hỏi trực tiếp.

🎯 Key Features:
  • Dual extraction: Text-based + OCR (Tesseract) for maximum coverage
  • LLM-powered structuring using Qwen2.5:7b
  • Semantic chunking with embeddings (nomic-embed-text)
  • ChromaDB vector storage for fast retrieval
  • Tiered evaluation system optimized for limited hardware
  • Hybrid deployment: Local Backend + Cloud Frontend

🏗 System Architecture (Workflow Pipeline)

Hệ thống được thiết kế thành các giai đoạn (Phases) xử lý tuần tự kèm với các tệp dữ liệu đầu ra:

1️⃣
Raw Data Input
Kho dữ liệu CV thô bao gồm 110 CV (HR) + 120 CV (IT) dưới dạng PDF files.
2️⃣
Ingestion (Phase 1)
Trích xuất văn bản sử dụng kép: Text-based extraction + OCR (Tesseract).
3️⃣
LLM Extraction (Phase 2)
Cấu trúc hóa dữ liệu với Qwen2.5:7b theo schema JSON định nghĩa.
4️⃣
Semantic Chunking (Phase 3)
Chia nhỏ data, tạo embeddings, lưu vào ChromaDB.

📝 Chi tiết từng Phase

Phase 1: Ingestion (Trích xuất văn bản)

Đọc và trích xuất nội dung từ các file PDF. Áp dụng cơ chế kép: Text-based (kéo chữ trực tiếp từ file digital) và OCR (Tesseract) (xử lý CV scan).

💡 Chi tiết xây dựng - Phase 1:
Khu vực xử lý chính nằm ở src/ingestion bao gồm 2 engine: ocr_engine (pytesseract) và pdf_parser. Luồng xử lý thực hiện cả 2 phương pháp trên cùng file để tránh kết quả None. Kết quả lưu tại data/temp: ingested_hr.jsoningested_information-technology.json

Phase 2: LLM Extraction (Cấu trúc hóa)

Văn bản hỗn độn từ Phase 1 được đưa qua Qwen2.5:7b chạy cục bộ via Ollama. LLM phân tích và chuẩn hóa theo JSON schema (Profile, Experience, Education, Projects).

💡 Chi tiết xây dựng - Phase 2:
Mục đích: Chuẩn hóa cấu trúc CV do mỗi người viết khác nhau. Đây là phase tốn thời gian nhất (giới hạn phần cứng). Schema tối giản để inference nhanh. Ghi nhận: 2 file HR + 3 file IT bị hallucination (tổng 230 file, sai số ~2%). Xử lý tại chunker.py. Kết quả lưu: backend/processed/hr_extracted.json + it_extracted.json

Phase 3: Semantic Chunking & Indexing

JSON được chia nhỏ theo cụm ngữ nghĩa (Profile, Experience, Education, Project). Chuyển thành Vector dùng nomic-embed-text. Lưu vào ChromaDB.

💡 Chi tiết xây dựng - Phase 3:
Embedding nhanh chóng. Output: data/chunks (chứa chunks để embedding) + data/vector_db (ChromaDB storage). Mỗi file tạo 5-9 chunks. Phát hiện lỗi Phase 2 tại đây nhưng chi phí re-run Phase 2 quá cao, nên xử lý ngay trong chunker.py

🧪 Model Evaluation (Tiered Strategy)

Chiến lược Đánh giá Phân tầng tối ưu cho MacBook 16GB. Chia làm 3 Mode qua run_evaluation.py:

🎯
Mode 1: Retrieval
58%
Hit Rate (50 queries)
⏱️
Mode 1: Latency
0.18s
Avg retrieval time
📝
Mode 2: E2E Latency
22.3s
With LLM inference
☁️
Mode 3: Relevance
3.67/5.0
Cloud Judge score

📊 Evaluation Methods

✅ Mode 1 - Retrieval Evaluation:
Script tự động đặt câu hỏi → ChromaDB trả about source_file/chunk_id. So sánh: if retrieved_id == expected_id: score += 1. Chi phí phần cứng: ~0%. Test 50 queries.
✅ Mode 2 - Generation Evaluation:
Chọn 15 test chính xác từ Mode 1, inference end-to-end với Qwen2.5:7b local. Đo độ trễ và chất lượng response.
✅ Mode 3 - Cloud Judge Evaluation:
Call Google Gemini 2.5 Flash API. Chấm điểm 1-5 dựa trên Answer Relevance. Async + aiohttp optimization.

🚀 Deployment & API Guide

Mô hình Hybrid Deployment tách Backend (Docker/Local) và Frontend (Streamlit Cloud):

1
Backend Setup (Docker)

FastAPI + ChromaDB được đóng gói Docker, chạy local trên máy tính. Cung cấp REST API cho upload, truy vấn. Xử lý rác dữ liệu via cleanup_orphan_collections.

# Xây dựng và chạy backend docker compose up -d --build # Tắt backend docker compose down
2
Frontend (Streamlit Cloud)

Web UI hosted trên Streamlit Community Cloud: https://windycv.streamlit.app

pip install -r frontend/requirements.txt streamlit run frontend/app.py
3
Tunnel Connection (Ngrok)

Ngrok tạo đường hầm an toàn từ Streamlit Cloud → Backend Local. Copy URL HTTPS và cập nhật BACKEND_URL trong frontend/app.py.

ngrok http 8000

⚠️ Limitations & Trade-offs

Ngrok URL Dependency: Link thay đổi mỗi lần khởi động, cần update thủ công mỗi ngày (trừ khi dùng bản trả phí).
Hardware Constraints: Ingestion + Qwen2.5:7b inference tốn nhiều RAM. Multiple cloud sessions có thể gây bottleneck hoặc treo máy local.
Orphan Sessions: Streamlit làm mới session_state khi reload (F5), mất dấu session_id cũ. Nếu user không bấm "Xóa CV", collections tạm lưu ổ cứng. Cần giải pháp TTL/cleanup tốt hơn.

🛠 Technology Stack

🔧 Backend

  • ✓ FastAPI (REST API)
  • ✓ ChromaDB (Vector DB)
  • ✓ Qwen2.5:7b (LLM)
  • ✓ Ollama (Local LLM runtime)
  • ✓ Docker (Container)

🎨 Frontend

  • ✓ Streamlit (Web UI)
  • ✓ Streamlit Cloud (Hosting)
  • ✓ Ngrok (Tunneling)
  • ✓ Session Management

📊 Processing

  • ✓ Tesseract (OCR)
  • ✓ PyPDF (Text extraction)
  • ✓ nomic-embed-text (Embeddings)
  • ✓ Google Gemini 2.5 (Judge)

📁 Project Structure

IMTSolutions/ ├── backend/ │ ├── src/ │ │ ├── ingestion/ # Phase 1: PDF parsing + OCR │ │ ├── extraction/ # Phase 2: LLM structuring │ │ ├── rag/ # Phase 3: Chunking + Indexing │ │ ├── evaluation/ # Metrics & assessment │ │ └── api/ # FastAPI endpoints │ ├── scripts/ # Automation scripts │ └── Dockerfile ├── frontend/ │ └── app.py # Streamlit Web UI ├── notebooks/ # EDA & analysis ├── data/ │ ├── raw/ # Raw PDF files │ ├── processed/ # Extracted JSON │ ├── chunks/ # Semantic chunks │ ├── vector_db/ # ChromaDB storage │ └── evaluation/ # Test results └── README.md

Ready to Get Started?

Explore the project and see the RAG pipeline in action.