Skip to content

Latest commit

Β 

History

56 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ChatVerse - Multi-Mode RAG Chat Platform

Python 3.12+ FastAPI LangGraph ChromaDB React

πŸ“‹ Overview

ChatVerse is a multi-mode Retrieval-Augmented Generation (RAG) platform that lets you chat with four different kinds of sources β€” PDFs, YouTube videos, GitHub repositories, and Gmail inboxes β€” through one unified interface.

Every mode shares the same underlying pattern: ingest a source, chunk and embed it into an isolated vector collection, then retrieve and generate answers through a LangGraph pipeline. Only the ingestion step changes per source β€” everything else is identical, which keeps the system small and easy to reason about instead of four separate apps bolted together.


🎯 Key Features

πŸ“„ Chat with PDF

  • Page-Aware Chunking: Documents are split with RecursiveCharacterTextSplitter, preserving page metadata
  • Grounded Answers: Every reply is generated only from retrieved chunks β€” no answer without a citation

▢️ Chat with YouTube

  • Transcript Retrieval: Pulls captions via youtube-transcript-api, no API key required
  • Timestamp Windows: Transcript segments are grouped into ~60s windows so answers can point to t=6:40

βŒ₯ Chat with GitHub

  • Repo Walking: Uses PyGithub to list and read source files without a local git clone
  • File-Path Citations: Answers reference the exact file a chunk came from

βœ‰οΈ Chat with Gmail

  • OAuth2 Flow: One-time browser consent, cached and auto-refreshed via google-auth-oauthlib
  • Plain-Language Search: Ask about your inbox instead of guessing the right search operators

🧠 Shared RAG Core

  • LangGraph Pipelines: Every mode is a StateGraph with retrieve β†’ generate nodes
  • Isolated Vector Storage: Chroma collections scoped per mode + session_id
  • Uniform API Contract: All four modes expose identical /ingest, /chat, /sessions/{id} shapes

🎨 Frontend

  • Landing Page: Marketing site with a live mode-switching demo
  • Dashboard: Dark, sidebar-driven chat UI β€” pick a source, ingest, and chat
  • React Router: / for the landing page, /app for the dashboard

πŸ—οΈ Architecture

System Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      React Frontend (Vite)                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  LandingPage.jsx  β†’  HomePage.jsx (Sidebar + Chat)        β”‚  β”‚
β”‚  β”‚  β€’ Mode selection (PDF / YouTube / GitHub / Gmail)        β”‚  β”‚
β”‚  β”‚  β€’ Source ingestion UI                                    β”‚  β”‚
β”‚  β”‚  β€’ Chat window + source citations                         β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓ axios (client.js)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       FastAPI Backend                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  POST /api/{mode}/ingest                                  β”‚  β”‚
β”‚  β”‚  POST /api/{mode}/chat                                    β”‚  β”‚
β”‚  β”‚  GET  /api/{mode}/sessions/{id}                            β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    LangGraph Orchestration                      β”‚
β”‚        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚        β”‚  retrieve    β”‚  β†’     β”‚  generate    β”‚                  β”‚
β”‚        β”‚  (Chroma)    β”‚        β”‚  (LLM)       β”‚                  β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β”‚   one graph per mode: pdf_graph / youtube_graph /                β”‚
β”‚   github_graph / gmail_graph β€” identical shape, different        β”‚
β”‚   ingestion feeding the same collection                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        ↓          ↓              ↓                ↓
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ PyPDF   β”‚ β”‚ YouTube  β”‚ β”‚ PyGithub   β”‚   β”‚ Gmail API β”‚
   β”‚ Loader  β”‚ β”‚ Transcriptβ”‚ β”‚ (repo walk)β”‚   β”‚ (OAuth2)  β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Graph Nodes (per mode)

  1. retrieve: Searches the mode's Chroma collection for the top-k relevant chunks
  2. generate: Builds a context-grounded prompt and calls the LLM for an answer

πŸ“¦ Project Structure

chatverse/
β”œβ”€β”€ chatverse-backend/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ main.py                   # FastAPI app, CORS, router mounting
β”‚   β”‚   β”œβ”€β”€ config.py                  # .env-loaded settings
β”‚   β”‚   β”œβ”€β”€ schemas.py                  # IngestResponse / ChatRequest / ChatResponse
β”‚   β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”‚   β”œβ”€β”€ llm.py                   # LLM + embeddings client factory
β”‚   β”‚   β”‚   β”œβ”€β”€ vectorstore.py            # Chroma collection helper
β”‚   β”‚   β”‚   └── gmail_auth.py              # OAuth2 credential flow
β”‚   β”‚   β”œβ”€β”€ graphs/
β”‚   β”‚   β”‚   β”œβ”€β”€ pdf_graph.py
β”‚   β”‚   β”‚   β”œβ”€β”€ youtube_graph.py
β”‚   β”‚   β”‚   β”œβ”€β”€ github_graph.py
β”‚   β”‚   β”‚   └── gmail_graph.py
β”‚   β”‚   └── routers/
β”‚   β”‚       β”œβ”€β”€ pdf.py
β”‚   β”‚       β”œβ”€β”€ youtube.py
β”‚   β”‚       β”œβ”€β”€ github.py
β”‚   β”‚       └── gmail.py
β”‚   β”œβ”€β”€ requirements.txt
β”‚   └── .env
β”‚
β”œβ”€β”€ chatverse-frontend/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ main.jsx                  # mounts <App/> in <BrowserRouter>
β”‚   β”‚   β”œβ”€β”€ App.jsx                    # routes: "/" and "/app"
β”‚   β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”‚   └── client.js               # axios calls matching the API contract
β”‚   β”‚   β”œβ”€β”€ hooks/
β”‚   β”‚   β”‚   β”œβ”€β”€ useDocuments.js          # ingest state
β”‚   β”‚   β”‚   └── useChat.js                # chat state
β”‚   β”‚   β”œβ”€β”€ pages/
β”‚   β”‚   β”‚   β”œβ”€β”€ LandingPage.jsx
β”‚   β”‚   β”‚   └── HomePage.jsx
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   └── Sidebar.jsx
β”‚   β”‚   └── styles/
β”‚   β”‚       β”œβ”€β”€ global.css
β”‚   β”‚       β”œβ”€β”€ landing.css
β”‚   β”‚       └── app.css
β”‚   └── package.json
β”‚
└── README.md

πŸ”Œ API Endpoints

Base URL

http://127.0.0.1:8000

Every mode (pdf, youtube, github, gmail) exposes the same three endpoints.

1. Ingest Endpoint

Load a source and index it for retrieval

POST /api/pdf/ingest
Content-Type: multipart/form-data

file: <PDF file>
POST /api/youtube/ingest
Content-Type: application/json

{ "url": "https://youtube.com/watch?v=..." }
POST /api/github/ingest
Content-Type: application/json

{ "repo_url": "owner/repo" }
POST /api/gmail/ingest
Content-Type: application/json

{ "query": "from:someone@example.com" }

Response:

{
  "session_id": "a1b2c3d4-...",
  "status": "success",
  "chunks_indexed": 42
}

2. Chat Endpoint

Ask a question about an ingested source

POST /api/{mode}/chat
Content-Type: application/json

{
  "session_id": "a1b2c3d4-...",
  "message": "What does chapter 3 conclude?"
}

Response:

{
  "answer": "Chapter 3 reports 91.4% accuracy on the held-out test set...",
  "sources": [
    { "content": "...", "metadata": { "source": "chapter3.pdf", "page": 18 } }
  ],
  "session_id": "a1b2c3d4-..."
}

Status Codes:

  • 200: Success
  • 404: Unknown session_id β€” ingest a source first
  • 500: Server error (usually a missing/invalid API key)

3. History Endpoint

GET /api/{mode}/sessions/{session_id}

Response:

{
  "session_id": "a1b2c3d4-...",
  "history": [
    { "role": "user", "content": "..." },
    { "role": "assistant", "content": "..." }
  ]
}

πŸ“– Usage Guide

1. Prerequisites

# System Requirements
- Python 3.12+
- Node.js 18+
- Gemini API key (or OpenAI API key)
- GitHub token (optional, for higher rate limits on GitHub mode)
- Google Cloud OAuth credentials (for Gmail mode)

2. Backend Installation

cd chatverse-backend
python -m venv venv
source venv/bin/activate      # Windows: venv\Scripts\activate

pip install -r requirements.txt

3. Environment Configuration

Create chatverse-backend/.env:

# LLM Configuration (Gemini)
GOOGLE_API_KEY=your_gemini_api_key_here

# Vector Store
CHROMA_PERSIST_DIR=./chroma_db

# GitHub Mode
GITHUB_TOKEN=your_github_token_here

# Gmail Mode
GMAIL_CREDENTIALS_PATH=./credentials.json

# CORS
CORS_ORIGINS=http://localhost:5173

4. Running the Application

Terminal 1 β€” Backend:

source venv/bin/activate
cd chatverse-backend
uvicorn app.main:app --reload

Terminal 2 β€” Frontend:

cd chatverse-frontend
npm install
npm run dev

Access the Application:

5. Example Usage

Using the Web Interface:

  1. Navigate to http://localhost:5173
  2. Click Start chatting free
  3. Pick a mode (PDF / YouTube / GitHub / Gmail)
  4. Upload a file or paste a link
  5. Ask questions in the chat window

Using cURL:

# Ingest a PDF
curl -X POST http://127.0.0.1:8000/api/pdf/ingest \
  -F "file=@/path/to/document.pdf"

# Chat with it
curl -X POST http://127.0.0.1:8000/api/pdf/chat \
  -H "Content-Type: application/json" \
  -d '{"session_id": "PASTE_SESSION_ID", "message": "Summarize this document"}'

Using Python:

import requests

response = requests.post(
    "http://127.0.0.1:8000/api/pdf/chat",
    json={"session_id": "PASTE_SESSION_ID", "message": "What is this about?"}
)
print(response.json())

πŸ”§ Configuration

Key Configuration Files

app/config.py

# Loaded from .env via pydantic-settings
GOOGLE_API_KEY          # Gemini LLM + embeddings authentication
CHROMA_PERSIST_DIR      # Vector store location on disk
GITHUB_TOKEN            # GitHub API rate-limit headroom
GMAIL_CREDENTIALS_PATH  # OAuth2 client secret file
CORS_ORIGINS            # Allowed frontend origin(s)

app/core/llm.py

Centralizes the LLM and embeddings client β€” swapping providers (OpenAI ↔ Gemini) means editing this one file only.

Build Order Logic

Each mode was built in order of rising ingestion complexity, not feature priority:

Build Order
β”œβ”€β”€ PDF     β†’ no auth, no external API (simplest)
β”œβ”€β”€ YouTube β†’ transcript API, no key required
β”œβ”€β”€ GitHub  β†’ GitHub API, optional token
└── Gmail   β†’ OAuth2 + privacy-sensitive data (most complex)

πŸ§ͺ Testing the API

Using FastAPI Interactive Documentation

  1. Navigate to http://127.0.0.1:8000/docs
  2. Expand POST /api/pdf/ingest
  3. Click Try it out
  4. Upload a PDF via the file picker
  5. Click Execute and copy the returned session_id
  6. Repeat for POST /api/pdf/chat using that session_id

Example Test Cases

Test 1: PDF ingestion

curl -X POST http://127.0.0.1:8000/api/pdf/ingest -F "file=@notes.pdf"

Test 2: Chat on an ingested PDF

{
  "session_id": "<from test 1>",
  "message": "What are the main topics covered?"
}

Test 3: Health check

curl http://127.0.0.1:8000/health

πŸ” Security Considerations

  • Store API keys in .env file (never commit)
  • Never commit chroma_db/ or token.json β€” both contain indexed personal data
  • Use a throwaway Gmail account when demoing Gmail mode publicly
  • Validate uploaded file types before processing
  • Use HTTPS in production
  • Rotate GITHUB_TOKEN and GOOGLE_API_KEY periodically

πŸš€ Deployment

Local Development

uvicorn app.main:app --reload

Production Deployment

uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4

Frontend Build

cd chatverse-frontend
npm run build   # outputs to dist/

πŸ“Š Performance Notes

  • Chunking: PDF/GitHub use ~1000-1200 char chunks with overlap; YouTube uses ~60s transcript windows
  • Isolated Collections: Each mode + session_id gets its own Chroma collection β€” no cross-session leakage
  • In-Memory History: Chat history currently lives in a Python dict per router; swap for Redis/SQLite before scaling past local development

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/YourFeature)
  3. Follow the existing retrieve β†’ generate graph pattern for new modes
  4. Commit with descriptive messages (git commit -m 'feat: Add YourFeature')
  5. Push to your branch and open a Pull Request

Code Quality

  • Follow PEP 8 for Python, keep components small and prop-driven in React
  • Add docstrings to new graph nodes and router functions
  • Keep the API contract (schemas.py) as the source of truth for request/response shapes

πŸ“š Technology Stack

Component Technology
LLM Framework LangChain
Workflow Orchestration LangGraph
Web Framework FastAPI
ASGI Server Uvicorn
Vector Database ChromaDB
LLM Provider Google Gemini
PDF Parsing PyPDF
YouTube Transcripts youtube-transcript-api
GitHub Access PyGithub
Gmail Access google-api-python-client + google-auth-oauthlib
Frontend Framework React 18 + Vite
Routing react-router-dom
HTTP Client axios
Icons lucide-react

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages