Multimodel_Rag / context.md
Dhrumil Parikh
deploy GeminiRAG
cdc55f4
|
Raw
History Blame Contribute Delete
14.9 kB

GeminiRAG β€” Project Context

For use by the next chat session to resume work without losing any context.


What This Project Is

GeminiRAG is a production-ready Multimodal RAG (Retrieval-Augmented Generation) pipeline built for MasterCRM Internal Engineering. It allows users to upload any document (PDF, Word, Excel, CSV, image, audio, video), have it processed by Google Gemini, chunked and embedded into a ChromaDB vector store, and then queried in natural language. The system returns answers with citations and RAGAS quality scores.

Delivered by: Dhrumil Parikh
Delivery date: 3 June 2026
GitHub repo: https://github.com/Dhrumilparikh2806/yaya (branch: master)


Tech Stack

Layer Technology
LLM / Embeddings Google Gemini (gemini-2.5-flash, models/gemini-embedding-001) via google-genai SDK
Agent Google ADK (google-adk) with 5 MCP tools
API FastAPI 0.111 + uvicorn, Python 3.11
Task Queue Celery 5.6 + Redis broker, PostgreSQL result backend
Vector Store ChromaDB (HTTP client, cosine similarity)
Database PostgreSQL 18 (native, NOT Docker) β€” SQLModel + Alembic
RAG Evaluation RAGAS (faithfulness, answer_relevancy, context_precision, context_recall, answer_correctness)
Frontend React 18 + TypeScript + Vite + TailwindCSS + Recharts
Observability structlog (JSON), OpenTelemetry (stdout exporter), UsageLog DB table
Auth JWT (HS256, python-jose) + bcrypt passwords
Rate Limiting slowapi (10/min on /auth/login)

Environment (Local, No Docker)

Important: Docker is NOT installed on this machine. All services run natively.

Service Port Status Notes
PostgreSQL 18 5432 Running natively DB: geminirag, user: geminirag, pass: geminirag
Redis 6379 Running natively
ChromaDB 8001 Running natively
FastAPI (uvicorn) 8000 Must be started manually See "How to Start" below
Celery worker β€” Must be started manually Uses --pool=solo on Windows
React (Vite) 5173 Must be started manually

How to Start Everything

Open 3 separate cmd windows (or use PowerShell Start-Process):

Window 1 β€” API Server:

cd "c:\Users\Dhrumil.parikh\OneDrive - Taazaa Tech Pvt Ltd\Desktop\playbook_final\geminirag"
py -m uvicorn app.main:app --reload --port 8000

Window 2 β€” Celery Worker:

cd "c:\Users\Dhrumil.parikh\OneDrive - Taazaa Tech Pvt Ltd\Desktop\playbook_final\geminirag"
py -m celery -A app.workers.celery_app worker --loglevel=info --concurrency=2 --pool=solo

Window 3 β€” Frontend:

cd "c:\Users\Dhrumil.parikh\OneDrive - Taazaa Tech Pvt Ltd\Desktop\playbook_final\geminirag\frontend"
npm run dev

Or via PowerShell (each in its own visible cmd window that stays alive):

Start-Process cmd.exe -ArgumentList "/k", "cd /d `"...\geminirag`" && py -m uvicorn app.main:app --reload --port 8000"
Start-Process cmd.exe -ArgumentList "/k", "cd /d `"...\geminirag\frontend`" && npm run dev"

Verification

# Check health (should return {"status":"ok","database":"ok","chromadb":"ok"})
Invoke-WebRequest http://localhost:8000/health -UseBasicParsing | Select -Expand Content

.env File Location and Contents

Path: c:\Users\Dhrumil.parikh\OneDrive - Taazaa Tech Pvt Ltd\Desktop\playbook_final\geminirag\.env

GEMINI_API_KEY=AIzaSyD-0xYBLCksuwdk0oo1SO3S_gdFXW3DFNs
DATABASE_URL=postgresql://geminirag:geminirag@localhost:5432/geminirag
REDIS_URL=redis://localhost:6379/0
SECRET_KEY=geminirag_secret_key_minimum_32_chars_long_secure
UPLOAD_DIR=C:/tmp/geminirag_uploads
GEMINI_MODEL=gemini-2.5-flash
GEMINI_EMBEDDING_MODEL=models/gemini-embedding-001

.env is gitignored β€” never commit it.


Database

  • Engine: PostgreSQL 18, running on localhost:5432
  • Database: geminirag
  • Tables: users, jobs, usage_logs, query_history
  • Migrations: Alembic (alembic upgrade head)
  • Connection pooling: pool_size=10, max_overflow=20, pool_pre_ping=True (in app/models/db.py)

To view in PgAdmin: connect to localhost:5432, user=geminirag, password=geminirag, DB=geminirag.


Admin Credentials

Email:    admin@test.com
Password: Admin1234!
Role:     admin

To recreate: py scripts/seed_admin.py --email admin@test.com --password Admin1234!


API Overview

Base URL: http://localhost:8000
Docs: http://localhost:8000/docs

Method Path Auth Description
POST /auth/register No Register user
POST /auth/login No Login β†’ JWT token
POST /v1/files/upload JWT Upload file β†’ returns job_id (async)
GET /v1/jobs/{id} JWT Get job status
GET /v1/jobs JWT List all user's jobs (admin sees all)
POST /v1/jobs/{id}/reprocess JWT Re-queue failed job
GET /v1/documents JWT List completed documents
GET /v1/documents/{id}/summary JWT Get document AI summary
POST /v1/query JWT RAG query β†’ answer + citations
POST /v1/query/stream JWT Streaming RAG via SSE
POST /v1/agent/chat JWT ADK agent chat
GET /v1/admin/usage Admin Usage stats
GET /v1/admin/ragas Admin RAGAS metric averages
GET /v1/admin/users Admin User list with stats
PATCH /v1/admin/users/{id} Admin Toggle user is_active
GET /health No DB + ChromaDB health check

Login format (JSON body):

{"email": "admin@test.com", "password": "Admin1234!"}

File Processing Pipeline

User uploads file β†’ POST /v1/files/upload
  β†’ creates Job (PENDING) in PostgreSQL
  β†’ saves file to C:/tmp/geminirag_uploads/{job_id}/
  β†’ enqueues process_file.delay(job_id) in Celery via Redis

Celery worker picks up task β†’ process_file(job_id):
  1. EXTRACTING  β†’ dispatch to processor by file_type
                   (PDFProcessor / DOCXProcessor / XLSXProcessor /
                    ImageProcessor / VideoAudioProcessor)
                   β†’ processor.extract() β†’ raw text
                   β†’ processor.summarise() β†’ Gemini JSON summary
                   β†’ stores summary in job.result

  2. CHUNKING    β†’ chunk_text() or chunk_video_segments()
                   800 words/chunk, 100-word overlap, min 50 words

  3. EMBEDDING   β†’ embed_chunks() β†’ Gemini embedding API (768-dim)
                   batched 100 at a time, retry on 429

  4. INDEXING    β†’ add_chunks() β†’ ChromaDB upsert with 3x retry

  5. COMPLETED   β†’ job.status = COMPLETED, job.chunk_count = N

Supported file types: PDF, DOCX, XLSX, CSV, PNG, JPG, JPEG, WEBP, MP4, MOV, MP3, WAV, M4A
Max file size: 500 MB


RAG Query Flow

POST /v1/query {question, job_ids?}
  1. Embed question β†’ 768-dim vector (Gemini)
  2. Search ChromaDB β†’ top_k=5 chunks (cosine similarity)
  3. Confidence gate: avg_score >= 0.65
     β†’ If fails: return "I don't have enough information..."
  4. Format context from chunks
  5. Call Gemini (gemini-2.5-flash) with RAG system prompt
     β†’ Answer must only use provided context, must cite [1][2]...
  6. Log to UsageLog + QueryHistory
  7. Enqueue compute_ragas.delay() async (adds ~15-60s, runs in background)
  8. Return: {answer, citations, confidence_gate_passed, avg_similarity_score}

RAGAS scores appear later in QueryHistory (populated by background Celery task)

Streaming variant: POST /v1/query/stream uses StreamingResponse with text/event-stream.
Frontend uses Fetch API (not EventSource) because SSE doesn't support POST/auth headers.


Celery Tasks

Task Trigger Purpose
process_file File upload Full extraction β†’ chunk β†’ embed β†’ index pipeline
compute_ragas After each query Async RAGAS score computation
cleanup_old_uploads Daily (beat schedule) Delete upload files for 7-day-old completed jobs

Retry strategy: max_retries=3, exponential backoff (CELERY_RETRY_BACKOFF * 2^retry).
Dead letter queue: FAILED_PERMANENT jobs pushed to Redis list geminirag:dead_letter.
Windows note: Must use --pool=solo flag on Windows.


ADK Agent

The agent has 5 tools and can hold multi-turn conversations:

Tool What it does
ingest_file Upload a file by path β†’ creates job, queues processing
get_job_status Check processing status of a job
query_rag Ask a question against uploaded documents
list_documents List all completed documents
summarize_document Get AI summary of a specific document

Session service: InMemorySessionService β€” conversation history resets on server restart.
Production note: Should be replaced with Redis/PostgreSQL-backed session service.


RAGAS Evaluation

Target scores (from spec):

  • Faithfulness β‰₯ 0.80
  • Context Precision β‰₯ 0.60

Running baseline offline:

  1. Ensure documents are uploaded and COMPLETED
  2. Create test set JSON: C:/tmp/ragas_test_set.json
    [{"question": "...", "ground_truth": "...", "job_id": "uuid-here"}]
    
  3. Run: py scripts/ragas_baseline.py --test-set C:/tmp/ragas_test_set.json
  4. Results saved to: C:/tmp/ragas_baseline.json

Pre-downloaded sample datasets (50 Q&A pairs each, no job_id yet):

  • Data set/ragas_eval/ms_marco_samples.json β€” MS MARCO v1.1 validation
  • Data set/ragas_eval/natural_questions_samples.json β€” Natural Questions dev

To use these, upload relevant documents first, then add the returned job_id to the JSON entries.


Frontend Pages

URL Page What it does
/login LoginPage Email/password login, stores JWT
/register RegisterPage New user registration
/upload UploadPage Drag-drop upload, job polling, summary drawer
/query QueryPage Select docs, ask question, streaming mode, citation links
/agent AgentPage Chat with ADK agent, tool call log sidebar
/jobs JobsPage Full jobs table, re-process button
/admin AdminPage Usage/RAGAS/user management tabs (admin only)

All pages lazy-loaded (React.lazy + Suspense) β€” main bundle ~211KB after code splitting.


Key Design Decisions (for context)

  1. google-genai not google-generativeai β€” The old SDK (google-generativeai) is deprecated. Always use google-genai>=1.0.0 with from google import genai.

  2. SSE streaming uses Fetch not EventSource β€” EventSource API doesn't support POST requests or custom headers. The frontend uses fetch() with ReadableStream reader to stream answers with auth.

  3. ChromaDB 3x retry β€” add_chunks() retries 3 times with 5s backoff because ChromaDB can have transient write failures.

  4. RAGAS is async β€” Computing RAGAS after every query adds 15-60s latency. It runs in a background Celery task (compute_ragas). The query response returns immediately; RAGAS scores appear in QueryHistory later.

  5. ALLOWED_ORIGINS is env-driven β€” Set ALLOWED_ORIGINS=https://your-domain.com in .env for production. In dev it defaults to http://localhost:5173.

  6. No Docker β€” All infrastructure runs natively on this machine. PostgreSQL (v18), Redis, ChromaDB are already running as system services.

  7. Windows Celery β€” Must use --pool=solo flag. Celery's default prefork pool doesn't work on Windows.


Known Limitations

  1. Speaker diarization accuracy β€” depends on audio quality. Mono recordings work best.
  2. Large video files β€” >500 MB rejected. Close-to-limit files may hit Gemini context window.
  3. RAGAS cost β€” ~15-60s and token cost per query. Disable by removing compute_ragas.delay() from app/rag/engine.py.
  4. In-memory agent sessions β€” ADK InMemorySessionService resets on server restart.
  5. ChromaDB not backed up β€” Lives in Docker named volume. If deleted, re-upload all documents.
  6. No email notifications β€” No notification when long jobs complete. Planned future feature.

Adding a New File Type

  1. Create app/processors/newtype.py extending BaseProcessor β€” implement extract() and summarise()
  2. Add extension to EXTENSION_MAP in app/api/files.py
  3. Add extension to EXT_TO_TYPE in frontend/src/pages/UploadPage.tsx
  4. Add dispatch case in process_file() in app/workers/tasks.py
  5. Write a test in tests/test_processors.py

Git History (recent)

5965edb feat: day 8-10 + buffer β€” frontend, security hardening, streaming, delivery docs
636fd39 fix: phase-1 checklist gaps β€” otel spans, from_status logging, user_id in http middleware
48f3cfa day-7: ragas evaluation, observability audit, baseline
39c873f day-6: rag engine, citations, confidence gate, admin api
a8fbf32 day-4: image and video/audio processors, diarization, 14 tests pass
3f24a13 day-3: migrate to google.genai SDK, verify processors end-to-end

Project Directory

playbook_final/
└── geminirag/               ← main project root
    β”œβ”€β”€ app/                 ← FastAPI backend
    β”‚   β”œβ”€β”€ main.py
    β”‚   β”œβ”€β”€ config.py
    β”‚   β”œβ”€β”€ deps.py
    β”‚   β”œβ”€β”€ security.py
    β”‚   β”œβ”€β”€ limiter.py
    β”‚   β”œβ”€β”€ api/             ← route handlers
    β”‚   β”œβ”€β”€ models/          ← SQLModel ORM
    β”‚   β”œβ”€β”€ processors/      ← file type processors
    β”‚   β”œβ”€β”€ rag/             ← chunker, embedder, vectorstore, engine
    β”‚   β”œβ”€β”€ workers/         ← Celery tasks
    β”‚   β”œβ”€β”€ agent/           ← ADK agent + tools
    β”‚   β”œβ”€β”€ evaluation/      ← RAGAS eval
    β”‚   └── observability/   ← logging + tracing
    β”œβ”€β”€ frontend/            ← React + TypeScript
    β”‚   └── src/
    β”‚       β”œβ”€β”€ pages/       ← 7 pages
    β”‚       β”œβ”€β”€ context/     ← Auth + Toast contexts
    β”‚       β”œβ”€β”€ components/  ← NavBar, PrivateRoute
    β”‚       β”œβ”€β”€ hooks/       ← useToast
    β”‚       └── api/         ← Axios client
    β”œβ”€β”€ scripts/             ← seed_admin, ragas_baseline, download_datasets
    β”œβ”€β”€ tests/               ← pytest test suite
    β”œβ”€β”€ migrations/          ← Alembic migration files
    β”œβ”€β”€ Data set/            ← test datasets
    β”‚   └── ragas_eval/      ← ms_marco_samples.json, natural_questions_samples.json
    β”œβ”€β”€ .env                 ← secrets (gitignored)
    β”œβ”€β”€ .env.example         ← template
    β”œβ”€β”€ pyproject.toml       ← Python deps
    β”œβ”€β”€ docker-compose.yml   ← dev (not used locally)
    β”œβ”€β”€ docker-compose.prod.yml
    β”œβ”€β”€ Dockerfile
    β”œβ”€β”€ alembic.ini
    β”œβ”€β”€ README.md
    β”œβ”€β”€ HANDOVER.md
    └── DEMO_SCRIPT.md