Lumi is a full-stack RAG (Retrieval-Augmented Generation) app that lets you upload a PDF and chat with it using Google Gemini. Ask questions about your document and get accurate, source-cited answers in real time.
| Layer | Technology |
|---|---|
| Frontend | React + Vite + Tailwind CSS |
| Backend | FastAPI (Python) |
| LLM | Google Gemini 2.5 Flash |
| Embeddings | Google Gemini Embedding 001 |
| Vector Store | ChromaDB |
| PDF Parsing | PyMuPDF |
- Upload any PDF and process it instantly
- Ask questions in natural language
- Streaming responses token by token
- Source citations with page numbers
- Multiple chat modes
- Persistent vector storage
pdf-chat-app/
├── backend/
│ ├── models/
│ │ └── schemas.py # Pydantic request/response models
│ ├── routers/
│ │ ├── chat.py # Chat endpoint (SSE streaming)
│ │ └── upload.py # PDF upload endpoint
│ ├── services/
│ │ ├── chat_service.py # LLM streaming logic
│ │ ├── pdf_service.py # PDF parsing and storage
│ │ └── rag_service.py # ChromaDB store and retrieval
│ ├── utils/
│ │ ├── chunker.py # Text splitting
│ │ ├── embedder.py # Gemini embedding calls
│ │ └── prompt_builder.py # System and user prompt construction
│ ├── config.py # Settings via pydantic-settings
│ └── main.py # FastAPI app entry point
├── frontend/
│ ├── src/
│ │ ├── api/client.js # API calls to backend
│ │ ├── components/ # React UI components
│ │ ├── hooks/useChat.js # Chat state and streaming hook
│ │ ├── pages/ # HomePage and WorkspacePage
│ │ └── store/chatStore.js # Global state
│ └── vite.config.js
├── requirements.txt
└── README.md
- Python 3.11+
- Node.js 18+
- Google Gemini API key — get one free at aistudio.google.com
git clone https://github.com/OnlineBunker/lumi.git
cd lumicd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r ../requirements.txtCreate a .env file inside backend/:
GEMINI_API_KEY=your-gemini-api-key-here
LLM_MODEL=gemini-2.5-flash
EMBEDDING_MODEL=gemini-embedding-001
UPLOAD_DIR=./uploads
VECTOR_STORE_DIR=./vector_store
CHUNK_SIZE=500
CHUNK_OVERLAP=100
TOP_K_CHUNKS=5Start the backend:
python -m uvicorn main:app --reloadBackend runs at http://localhost:8000
Swagger docs at http://localhost:8000/docs
Open a new terminal:
cd frontend
npm install
npm run devFrontend runs at http://localhost:5173
- Push code to GitHub
- Go to vercel.com → New Project → Import repo
- Set Root Directory to
frontend - Deploy — you get a live URL instantly
- Go to render.com → New Web Service → Connect repo
- Set Root Directory to
backend - Set Build Command to
pip install -r ../requirements.txt - Set Start Command to
uvicorn main:app --host 0.0.0.0 --port $PORT - Add environment variables in the Environment tab:
GEMINI_API_KEYLLM_MODEL=gemini-2.5-flashEMBEDDING_MODEL=gemini-embedding-001
- Deploy
Note: Render's free tier spins down after 15 minutes of inactivity. First request after inactivity takes ~30 seconds to wake up.
| Variable | Description | Default |
|---|---|---|
GEMINI_API_KEY |
Google Gemini API key | required |
LLM_MODEL |
Gemini model for chat | gemini-2.5-flash |
EMBEDDING_MODEL |
Gemini model for embeddings | gemini-embedding-001 |
UPLOAD_DIR |
Directory to store uploaded PDFs | ./uploads |
VECTOR_STORE_DIR |
Directory for ChromaDB | ./vector_store |
CHUNK_SIZE |
Characters per text chunk | 500 |
CHUNK_OVERLAP |
Overlap between chunks | 100 |
TOP_K_CHUNKS |
Chunks retrieved per query | 5 |
- Upload — PDF is parsed page by page using PyMuPDF
- Chunk — Text is split into overlapping chunks using LangChain text splitter
- Embed — Each chunk is embedded using Gemini Embedding and stored in ChromaDB
- Query — User question is embedded and compared against stored chunks via cosine similarity
- Generate — Top matching chunks are injected into a prompt and streamed through Gemini Flash
- Stream — Tokens arrive in real time via Server-Sent Events (SSE)
MIT