DocTalk lets you talk to your documents. Upload a PDF, click Start Talking, and have a real-time voice conversation powered by Gemini Live, Google Speech/OCR, LlamaIndex, and Supabase.
Ask anything like:
- “What certificates does this person have?”
- “When does this document expire?”
- “Summarize the key points.”
DocTalk listens, understands, pulls the right context from your PDFs, and speaks the answer back.
- 🎙️ Voice-first experience – no typing required
- 🔍 RAG-powered answers using Gemini 2.0 + LlamaIndex vector search
- 📄 PDF understanding with OCR fallback for scanned docs
- 🔐 Google login via Supabase Auth
- 🧠 Document memory via Supabase storage + embeddings
- 🚀 Real-time WebSocket bridge between browser mic and Gemini Live
┌─────────────┐ mic/audio ┌─────────────┐ function calls ┌──────────────┐
│ Browser │◄────────────────► │ Python WS │◄────────────────────►│ Gemini Live │
│ (Next.js) │ chat UI │ (main.py) │ Embeddings + OCR │ (models/g2) │
└────┬────────┘ └────┬────────┘ └────┬─────────┘
│ Supabase Auth + Storage │ Supabase vector DB │
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ Supabase │◄───────────────►│ LlamaIndex │◄──────────────────►│ Google Cloud │
│ Auth/Storage│ doc blobs │ embeddings │ OCR / STT │ Vision + STT │
└─────────────┘ └──────────────┘ └──────────────┘
Create .env.local (for Next.js) and .env (for Python). Example values below:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
NEXT_PUBLIC_WS_URL=ws://localhost:9084GOOGLE_API_KEY=your_google_gemini_api_key
GOOGLE_APPLICATION_CREDENTIALS=etc/secrets/gcp-service-key.json
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key # NEVER expose publicly
PORT=9084Place your Google service account JSON at
etc/secrets/gcp-service-key.json(gitignored).
| Layer | Component | Notes |
|---|---|---|
| AI / ML | Gemini 2.0 Live API (models/gemini-2.0-flash-exp) |
Real-time multimodal reasoning + speech synthesis via WebSocket. |
Gemini Text Embeddings (models/text-embedding-004) |
Generates 1,536‑dim vectors used by pgvector in Supabase. | |
| Google Cloud Vision | OCR fallback for scanned PDFs; invoked per-page inside extract_text_with_ocr. |
|
| Google Speech-to-Text | Optional transcription service when not relying solely on Gemini queries. | |
| Backend | ws://<host>:9084 |
Main WebSocket endpoint (defined in main.py) for streaming PCM audio + receiving AI responses. |
process_pdf |
Handles Supabase storage download, chunking, embedding, and persistence. | |
query_docs Supabase RPC |
Cosine-similarity search over pgvector embeddings (per user). | |
| Frontend | useAudioWebSocket hook |
Sends audio media_chunks, receives Gemini tool calls/responses, and renders chat. |
| Supabase Auth + Storage APIs | Google OAuth login, PDF uploads (pdfs bucket), and metadata reads. |
Gemini Live function-calling is restricted to query_docs and delete_document, ensuring every answer references document context. Delete requests propagate via Supabase storage and Postgres tables.
Two core tables (with pgvector extension enabled):
-
user_documentsColumn Type Description iduuid(PK)Document row id user_idtextSupabase auth user id filenametextOriginal filename original_pathtextpdfs/<user>/<file>path in storageuploaded_attimestampDefaults to now() -
document_chunksColumn Type Description iduuid(PK)Chunk id user_idtextOwner filenametextDocument identifier chunktext500-token slice generated by LlamaIndex embeddingvector(1536)Gemini embedding created_attimestampDefaults to now()
The stored procedure match_document_chunks(query_embedding float8[], match_user_id text, match_count int) returns top‑K chunks for a given user, enforcing multi-tenant isolation at the query layer.
| Tool | Version | Notes |
|---|---|---|
| Node.js | 18+ | For Next.js frontend |
| Python | 3.11+ | For backend WS bridge |
| Supabase | account | Auth + storage + Postgres |
| Google Cloud | apis enabled | Gemini, Speech-to-Text, Vision |
Enable these Google APIs:
- Vertex AI / Gemini
- Cloud Speech-to-Text
- Cloud Vision
Create a service account with aiplatform.user, vision.user, speech.client roles and download the JSON key.
git https://github.com/malikdotexe/doc-Talk/
cd doc-talknpm install
cp .env.local.example .env.local # create from template
npm run dev
# http://localhost:3000python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
python main.py # starts on ws://0.0.0.0:9084- Create project
- Enable Google login (Auth > Providers)
- Add redirect URLs:
- Site URL:
http://localhost:3000 - Redirect URL:
http://localhost:3000/auth/callback
- Site URL:
- Create storage bucket
pdfs - Run
supabase_migration.sqlto set up tables + RPC
Doc-Talk/
├── app/ # Next.js (App Router)
│ ├── page.tsx # Entry page
│ ├── layout.tsx
│ └── globals.css
├── components/ # UI components
│ ├── MainContent.tsx # Voice controls + chat
│ ├── UploadedDocuments.tsx
│ └── LoginButton.tsx
├── hooks/
│ └── useAudioWebSocket.ts # Mic capture + WS streaming
├── lib/
│ └── supabaseClient.ts
├── main.py # Python WS server
├── requirements.txt
├── package.json
├── supabase_migration.sql
└── etc/secrets/
└── gcp-service-key.json (gitignored)
| File | Description |
|---|---|
main.py |
WebSocket bridge between browser audio and Gemini Live. Handles speech transcription, OCR, Supabase storage, and function-calling. |
components/MainContent.tsx |
UI for voice controls, chat history, PDF viewer, upload progress. |
hooks/useAudioWebSocket.ts |
Handles microphone capture, PCM conversion, WebSocket streaming, audio playback. |
supabase_migration.sql |
Tables (user_documents, document_chunks) + stored procedure match_document_chunks. |
- Login via Google OAuth (Supabase)
- Upload PDF – stored in Supabase bucket + chunked via LlamaIndex
- Click Start Talking – send microphone PCM stream to backend
- Gemini Live transcribes + issues
query_docstool calls - Supabase RPC returns relevant chunks
- Gemini answers with contextual voice + text
- Frontend displays conversation + plays audio reply
- 🗂️ Document Scale: Tested with PDFs up to ~50 MB. OCR pass (Vision API) handles image-only docs; text-native PDFs index in <5 s, scanned docs in 10–25 s.
- 🧠 Embedding Footprint: Each 1536-dim chunk ≈ 6 KB. 1,000 chunks (≈500k tokens) require ~6 MB in
document_chunks. - ⚡ Query Latency:
query_docsRPC (top 5 chunks) returns in 100–150 ms on Supabase free tier; Gemini streaming response arrives ~2–3 s after speech input. - 🎙️ Voice Loop Reliability: WebSocket bridge sustains 20 concurrent sessions on a single
python:3.11instance before audio lag appears (observed during manual testing). - ✅ Test Coverage: Manual end-to-end tests include new uploads, repeated queries, deletion flows, and OCR fallback. Error rates primarily tied to misconfigured Google credentials (handed via troubleshooting section).
- Deploy Next.js to Vercel/Netlify/Render
- Set
NEXT_PUBLIC_WS_URLto your backend WebSocket URL
- Deploy
main.pyservice to Render/Railway/Fly.io - Ensure long-lived WebSocket connections are supported
- Set environment variables (Google/Supabase keys)
- Mount
etc/secrets/gcp-service-key.jsonor use secret manager
- Use hosted Supabase or self-host
- Make sure
pdfsbucket allows authenticated uploads
- Voice conversation loop (mic → Gemini → audio reply)
- OCR fallback for image-only PDFs
- Multi Document Context Window
- Supabase vector search + RPC
- Conversation UI with live transcription
- Doc upload, listing, and deletion
- 📌 Citation highlights in PDF viewer
- 📝 Export answers as notes/summaries
# Frontend lint
npm run lint
# Backend manual test
python main.py # with DEBUG logsManual test script:
- Run backend & frontend
- Login via Google
- Upload sample PDF (text + scanned)
- Ask: “What’s the certificate date?”
- Confirm chat shows both question + DocTalk response
- Verify Supabase tables updated
| Issue | Fix |
|---|---|
401 Request had invalid authentication credentials |
Ensure GOOGLE_APPLICATION_CREDENTIALS points to valid service account with Vision/Speech/Gemini access. |
Gemini returns executableCode parts |
Live API sometimes sends tool suggestions; we ignore executable code and rely on declared tools. |
| No text extracted from PDFs | Set useOCR=true when uploading, ensure Vision API enabled. |
| WebSocket fails in production | Use wss:// and enable CORS/websocket upgrades on hosting provider. |
| Audio playback silent | Check browser mic permissions, use HTTPS, ensure AudioWorklet registered (/pcm-processor.js). |
- Fork the repo
- Create a feature branch
- Submit PR with description + screenshots/tests