Skip to content

hk2166/RAG_AgenticVoice

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

49 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Real-Time Voice RAG Agent

A Real-Time Voice RAG Agent that listens to a spoken question, retrieves relevant context from an uploaded PDF, generates a grounded answer with Claude, and responds in voice.

Pipeline: STT (Gemini 2.5 Flash + Groq fallback) β†’ local embeddings + FAISS RAG β†’ Claude LLM β†’ Edge-TTS


Tech Stack

Layer Technology
Backend API FastAPI + Uvicorn
Speech-to-Text Gemini 2.5 Flash + Groq Whisper fallback
LLM Anthropic Claude claude-opus-4-8
Embeddings Sentence-Transformers all-MiniLM-L6-v2 (dim 384)
Vector Store FAISS IndexFlatIP with L2 normalisation
Text-to-Speech Edge-TTS en-IN-NeerjaNeural
Frontend Vanilla HTML / CSS / JS (dark theme)

Features

Status Feature
Gemini 2.5 Flash STT with Groq fallback
Claude reasoning via Anthropic API
Local Sentence-Transformers embeddings
FAISS cosine-similarity vector index
Edge-TTS voice output
Dynamic PDF upload via /ingest
Modular architecture
Low-latency pipeline

Speech-to-Text

The voice pipeline currently uses Gemini 2.5 Flash for transcription. If Gemini STT fails or returns no text, the code falls back to Groq Whisper (whisper-large-v3) when GROQ_API_KEY is available.

This means the README should not describe Whisper-only local STT as the primary path anymore. The current design is:

  • Gemini 2.5 Flash for transcription
  • Groq Whisper as a fallback
  • Claude for query rewriting, reranking, and answer generation

Architecture

flowchart TD
    A([🎀 Browser Microphone]) --> B[MediaRecorder\nCaptures audio as .webm]
    B --> C[POST /voice\nmultipart audio upload]

    subgraph STT ["πŸ—£οΈ Speech-to-Text  |  whisper_provider.py"]
        C --> D[Write to temp .webm file]
        D --> E[Gemini 2.5 Flash STT\nGroq Whisper fallback when needed]
        E --> F[Raw Transcript Text]
    end

    subgraph QR [" Query Rewriting  |  improved_query/query_rewrite.py"]
        F --> G[Claude via Anthropic SDK\nExpand vague voice queries\ninto precise document search queries]
        G --> H[Cleaned Search Query]
    end

    subgraph RAG ["πŸ” Retrieval  |  retrieval/retrieve.py"]
        H --> I[Sentence-Transformers\nall-MiniLM-L6-v2\ndim = 384]
        I --> J[L2-Normalise query vector]
        J --> K[FAISS IndexFlatIP\nCosine similarity search\nTop-12 chunks]
        K --> L[12 Candidate Chunks\n+ similarity scores]
    end

    subgraph RR [" Reranking  |  query_ranker/rerank.py"]
        L --> M[Claude via Anthropic SDK\nRe-order 12 chunks\nby true relevance to query]
        M --> N[Top Reranked Chunks]
    end

    subgraph LLM [" Answer Generation  |  llm/generate.py"]
        N --> O[Build RAG Prompt\nsystem persona + context + question]
        O --> P[Anthropic Claude\nGrounded answer generation]
        P --> Q[Answer Text\nconcise Β· conversational]
    end

    subgraph TTS [" Text-to-Speech  |  tts/edge_tts_provider.py"]
        Q --> R[Edge-TTS\nen-IN-NeerjaNeural\nMicrosoft Neural Voice]
        R --> S[MP3 Audio Bytes]
    end

    subgraph RESP [" HTTP Response"]
        S --> T[Response body: audio/mpeg\nX-Transcription header\nX-Response-Text header]
    end

    T --> U([🌐 Browser\nPlays MP3 · Shows chat bubbles])

    subgraph INGEST [" PDF Ingestion  |  ingestion/ingest.py  β€” runs once per document"]
        V([πŸ“ PDF Upload / File]) --> W[pypdf β€” extract text\nnormalise whitespace]
        W --> X[LangChain RecursiveCharacterTextSplitter\nchunk_size=350 Β· overlap=60]
        X --> Y[Sentence-Transformers\nembed each chunk locally]
        Y --> Z[L2-Normalise Β· build FAISS IndexFlatIP]
        Z --> AA[(faiss.index + chunks.pkl\npersisted to disk)]
    end

    AA -.->|loaded on first query| K
Loading

Project Structure

GPU/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ main.py            # FastAPI app, CORS, router registration
β”‚   β”‚   β”œβ”€β”€ config.py          # API keys, model names, index paths
β”‚   β”‚   β”œβ”€β”€ ingestion/
β”‚   β”‚   β”‚   └── ingest.py      # PDF β†’ chunks β†’ FAISS index pipeline
β”‚   β”‚   β”œβ”€β”€ improved_query/
β”‚   β”‚   β”‚   └── query_rewrite.py  # Claude-powered query rewriter
β”‚   β”‚   β”œβ”€β”€ query_ranker/
β”‚   β”‚   β”‚   └── rerank.py      # Claude-powered semantic reranker
β”‚   β”‚   β”œβ”€β”€ retrieval/
β”‚   β”‚   β”‚   └── retrieve.py    # Query expansion + cosine similarity search
β”‚   β”‚   β”œβ”€β”€ llm/
β”‚   β”‚   β”‚   └── generate.py    # Grounded Claude prompt + generation
β”‚   β”‚   β”œβ”€β”€ stt/
β”‚   β”‚   β”‚   └── whisper_provider.py   # Gemini STT with Groq fallback
β”‚   β”‚   β”œβ”€β”€ tts/
β”‚   β”‚   β”‚   └── edge_tts_provider.py  # Edge-TTS synthesis
β”‚   β”‚   └── routes/
β”‚   β”‚       β”œβ”€β”€ voice.py       # POST /voice, POST /voice/text
β”‚   β”‚       └── ingest.py      # POST /ingest, GET /api/document
β”‚   β”œβ”€β”€ data/                  # gitignored β€” place PDFs here
β”‚   └── .env                   # gitignored β€” create locally
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ index.html
β”‚   β”œβ”€β”€ style.css
β”‚   └── script.js
β”œβ”€β”€ venv/                      # gitignored β€” create locally
└── README.md

Setup Instructions

1. Clone the Repository

git clone <repository-url>
cd GPU

2. Create Virtual Environment

python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

Note: The venv/ folder is gitignored and must be created locally β€” never commit it.

3. Install Dependencies

cd backend
pip install -r requirements.txt

4. Configure Environment Variables

Create a .env file in the backend/ directory:

ANTHROPIC_API_KEY=your_anthropic_api_key_here
GEMINI_API_KEY=your_gemini_api_key_here
# Optional: used only for Groq Whisper fallback in STT
GROQ_API_KEY=your_groq_api_key_here

Warning: .env is gitignored and must never be committed. Keep your API keys private.

5. Ingest Your PDF

Place your PDF in backend/data/ and run the ingestion script once:

cd backend
python -m app.ingestion.ingest

This builds faiss.index and chunks.pkl inside backend/app/.

Alternatively, upload a PDF directly through the web UI after starting the server.

6. Run the Server

cd backend
uvicorn app.main:app --reload

Open http://localhost:8000 in your browser.


API Reference

POST /voice

Upload audio and receive a spoken answer (full end-to-end pipeline).

Form field: audio β€” audio recording (.webm / .wav)

Response headers:

Header Description
X-Transcription Transcript of the query
X-Response-Text LLM answer text

Response body: audio/mpeg β€” synthesised speech

curl -X POST http://localhost:8000/voice \
     -F "audio=@query.webm" \
     --output response.mp3

POST /voice/text

Debug endpoint β€” same as /voice but returns JSON instead of audio.

Form field: audio β€” audio recording (.webm / .wav)

curl -X POST http://localhost:8000/voice/text \
     -F "audio=@query.webm"

Response: { "question": "...", "answer": "..." }


POST /ingest

Upload a PDF to rebuild the FAISS index at runtime (no server restart needed).

curl -X POST http://localhost:8000/ingest \
     -F "file=@resume.pdf"

Response:

{
  "status": "success",
  "filename": "resume.pdf",
  "pages": 2,
  "chunks": 47,
  "dim": 384
}

GET /api/document

Check whether a FAISS index is currently loaded on disk.

curl http://localhost:8000/api/document

Frontend

Served automatically by FastAPI from the frontend/ directory at http://localhost:8000.

Panel Description
Upload zone Drag-and-drop or click to upload a PDF; shows real chunk count after ingestion
Chat area Conversation bubbles β€” your question on the right, agent answer on the left
Mic footer Press the microphone button to record; release to send

Environment Variables

Variable Required Description
ANTHROPIC_API_KEY Yes Anthropic API key used for Claude
GEMINI_API_KEY Yes Google AI Studio API key used for STT
GROQ_API_KEY Optional Used only if Gemini STT falls back to Groq

Create backend/.env:

ANTHROPIC_API_KEY=your_anthropic_api_key_here
GEMINI_API_KEY=your_gemini_api_key_here

.env is gitignored and must never be committed.


Notes

  • The FAISS index is stored at backend/app/faiss.index and backend/app/chunks.pkl.
  • Uploading a new PDF via /ingest or the UI replaces the existing index immediately.
  • Claude is used for query rewriting, reranking, and answer generation.
  • Embeddings are generated locally with Sentence-Transformers, so no embedding API key is required.
  • Gemini is used for STT, with Groq Whisper as a fallback when needed.
  • Edge-TTS requires an outbound internet connection for synthesis.

About

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors