Skip to content

dhakksinesh/hireflow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎯 HireFlow β€” AI-Powered Resume Search

HireFlow indexes PDF resumes using hybrid search (BM25 + Pinecone vectors), fuses results with Reciprocal Rank Fusion, applies post-search filters, and optionally re-ranks candidates with a Gemini LLM evaluator.


🌐 Live Demo

HireFlow Live


βœ… Prerequisites


βš™οΈ Setup

1. Clone the Repository

git clone https://github.com/dhakksinesh/hireflow.git
cd Hireflow

2. Create Virtual Environment and Install Dependencies

Mac/Linux:

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Windows:

python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt

3. Configure environment variables

Create a .env file at the project root:

PINECONE_API_KEY=your_pinecone_key
PINECONE_INDEX_NAME=hireflow
PINECONE_DIMENSION=384
PINECONE_METRIC=cosine
GOOGLE_API_KEY=your_google_api_key
GOOGLE_MODEL=gemini-2.5-flash
MAX_TEXT_LENGTH=4000

4. Add resumes

Place your PDF resumes in data/resumes/.


πŸ—ΊοΈ Feature Walkthrough

Follow these steps in order. Each one builds on the previous.

πŸ§ͺ Feature 1 β€” Run the test suite

Verify everything works before touching any external APIs:

pytest tests/ -v

All tests are self-contained (Pinecone and Gemini are mocked). You should see tests passing for: test_filters, test_hybrid_indexer, test_re_ranker, test_ingestion.


⚑ Feature 2 β€” Start the FastAPI backend

python start_backend.py

This starts the API at http://localhost:8000. Open http://localhost:8000/docs to see the Swagger UI.

Check system status:

curl http://localhost:8000/status

Windows users: Use the Swagger UI at http://localhost:8000/docs to test endpoints instead of curl.

Response: {"resumes_ready": false, "vector_store_ready": true, "hybrid_ready": false, "pinecone_vector_count": 0}


πŸ“₯ Feature 3 β€” Index resumes via the API

curl -X POST http://localhost:8000/index

This loads all PDFs from data/resumes/, embeds them, and upserts into Pinecone + builds BM25 index. Response:

{"indexed": 50, "message": "Successfully indexed 50 resumes"}

Verify with /status again β€” pinecone_vector_count should now be > 0.


πŸ” Feature 4 β€” Search candidates via the API

curl -X POST http://localhost:8000/search \
  -H "Content-Type: application/json" \
  -d '{"query": "Senior Accountant with QuickBooks", "top_k": 5}'

Response includes three separate scores for each candidate:

{
  "results": [
    {
      "candidate_id": "c_alice_smith",
      "name": "Alice Smith",
      "bm25_score": 0.8721,
      "vector_score": 0.7534,
      "combined_score": 0.0323,
      "skills": ["QuickBooks", "Excel", "Accounting"],
      "location": "New York, USA",
      "experience": 5
    }
  ],
  "total": 5
}
  • bm25_score β€” normalized keyword match (0-1)
  • vector_score β€” cosine similarity from Pinecone (0-1)
  • combined_score β€” Reciprocal Rank Fusion across both lists

πŸ–₯️ Feature 5 β€” Launch the Streamlit web UI

Open a second terminal:

streamlit run streamlit/app.py

Smart startup: On launch, the app checks if Pinecone already has vectors. If yes, it only rebuilds the in-memory BM25 index (fast). If not, it does a full index. No redundant embedding work on restarts.


πŸ“€ Feature 6 β€” Upload new resumes via the UI

In the Streamlit app:

  1. Use the Add Resumes panel on the left
  2. Upload one or more PDF files
  3. Click Process & Index Resumes

Each resume is parsed with Gemini to extract name, skills, location, and experience, then indexed into both BM25 and Pinecone.


🎯 Feature 7 β€” Search with filters

In the Search Candidates panel:

  1. Enter a Job Title (e.g. "Senior Accountant")
  2. Enter a Job Description (e.g. "Looking for experienced accountant with tax expertise")
  3. Enter Required Skills (one per line)
  4. Optionally set a Location Filter and Min. Experience
  5. Click Find Candidates

Post-search filters (core/filters.py) are applied after the hybrid search to narrow down by skills, location, and experience. Results show:

  • BM25 Score, Vector Score, and Combined (RRF) as separate metrics
  • Skills, experience, and location for each candidate
  • Resume preview

πŸ€– Feature 8 β€” AI evaluation and re-ranking

For the top 5 search results, the ReRanker (core/re_ranker.py) calls Gemini to produce:

  • Fit score (0-100)
  • Strengths β€” what makes this candidate a good match
  • Gaps β€” where they fall short
  • Summary β€” one-line assessment

These appear inside each candidate's expandable card. If Gemini is unavailable, a rule-based fallback scores based on skill overlap.


πŸ“Š Feature 9 β€” Memory and evaluation dashboard

In the Streamlit sidebar, click Memory & Evaluation:

  • Search Memory β€” see total interactions, searches, and candidate views
  • Recent Search History β€” last 5 queries
  • RAG Quality Evaluation β€” enter a query and expected skills, then measure search quality using RAGAS metrics (answer relevancy, context precision, faithfulness, answer correctness)

πŸ”„ Feature 10 β€” Force re-index

If you add new resume PDFs to data/resumes/ and want to refresh the index:

  • Sidebar > click Force Re-index Resumes

This triggers a full BM25 + Pinecone rebuild.


πŸ“ Project Structure

Hireflow/
β”œβ”€β”€ api/
β”‚   └── main.py              # FastAPI backend (POST /index, /search, GET /status)
β”œβ”€β”€ core/
β”‚   β”œβ”€β”€ hybrid_indexer.py    # BM25 + Pinecone vector search with RRF fusion
β”‚   β”œβ”€β”€ vector_store.py      # Pinecone client wrapper
β”‚   β”œβ”€β”€ ingestion.py         # PDF loading -> LangChain Documents
β”‚   β”œβ”€β”€ parsing.py           # Gemini-based resume field extraction
β”‚   β”œβ”€β”€ re_ranker.py         # LLM candidate evaluation (fit score 0-100)
β”‚   β”œβ”€β”€ filters.py           # Post-search filtering (skills/location/experience)
β”‚   β”œβ”€β”€ memory_rag.py        # Search history and interaction tracking
β”‚   β”œβ”€β”€ search_router.py     # Shallow vs deep search routing
β”‚   └── evaluator.py         # RAGAS quality metrics
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ schemas.py           # SearchQuery, Resume, CandidateEvaluation
β”‚   β”œβ”€β”€ config.py            # .env configuration loader
β”‚   β”œβ”€β”€ embeddings.py        # HuggingFace all-MiniLM-L6-v2
β”‚   β”œβ”€β”€ utils.py             # Text processing, PDF loading, logging
β”‚   └── multi_query.py       # LLM query expansion
β”œβ”€β”€ streamlit/
β”‚   └── app.py               # Web interface
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ test_filters.py      # Filter function tests
β”‚   β”œβ”€β”€ test_hybrid_indexer.py # RRF fusion and indexing tests
β”‚   β”œβ”€β”€ test_re_ranker.py    # Evaluation and section parsing tests
β”‚   └── test_ingestion.py    # PDF loading tests
β”œβ”€β”€ data/
β”‚   └── resumes/             # Place PDF resumes here
β”œβ”€β”€ main.py                  # CLI interface
β”œβ”€β”€ start_backend.py         # uvicorn launcher
β”œβ”€β”€ requirements.txt         # All dependencies
└── HireFlow_Architecture.md # Detailed architecture docs

πŸ› οΈ Technology Stack

Component Technology
LLM Google Gemini (gemini-2.5-flash)
Vector DB Pinecone (serverless, cosine, 384 dims)
Embeddings HuggingFace all-MiniLM-L6-v2
Keyword Search rank_bm25 (BM25Okapi)
Score Fusion Reciprocal Rank Fusion (k=60)
Orchestration LangChain
Backend FastAPI + uvicorn
Frontend Streamlit
RAG Evaluation RAGAS
Testing pytest

About

AI-powered hiring workflow tool to streamline recruitment and candidate management

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages