A production-grade Retrieval-Augmented Generation (RAG) system that learns dynamically.
Ask anything. If the answer isn't in the local knowledge base, Lumina finds it automatically.
Lumina is a full-stack AI research assistant that overcomes the fundamental limitation of static RAG systems β a fixed, outdated knowledge base.
When you ask Lumina a question:
- It searches a local FAISS vector database of research papers.
- A CrossEncoder reranker evaluates if the retrieved context is actually relevant.
- If the context is too weak, Lumina autonomously fetches new papers from ArXiv as a background task β without making you wait.
- Google Gemini 2.0 Flash synthesizes a clear, cited answer.
- Every fetched paper is permanently embedded into the local DB so future queries are answered instantly.
The result is a knowledge base that grows smarter with every query.
| Feature | Description |
|---|---|
| π§ Self-Improving Knowledge Base | Automatically detects weak context and expands the vector DB via ArXiv |
| β‘ Non-Blocking Background Fetching | ArXiv downloads happen after response β user never waits |
| π― CrossEncoder Reranking | MS MARCO model scores and reorders chunks for maximum relevance |
| π Query Expansion | Gemini generates alternative phrasings to improve search recall |
| π Premium Dark Mode UI | Glassmorphic Next.js frontend with Framer Motion animations |
| π Source Citations | Every answer includes the papers it was synthesized from |
| π Feedback Loop | Thumbs up/down feedback is logged for future model improvement |
| π Robust Error Handling | Every pipeline stage has try/except guards β nothing crashes silently |
graph TD
A[π€ User Query] --> B[Lumina UI - Next.js]
B -->|POST /ask| C[FastAPI Backend]
C --> D[Query Expansion<br/>Gemini 2.0 Flash]
D --> E[FAISS Vector Search<br/>all-MiniLM-L6-v2]
E --> F[CrossEncoder Reranker<br/>ms-marco-MiniLM-L-6-v2]
F --> G{Relevance Score<br/>above threshold?}
G -->|β
Yes| H[Generate Answer<br/>Gemini 2.0 Flash]
H --> I[Return Answer + Sources]
I --> B
G -->|β No - Weak Context| H
H --> I
G -->|Schedule Background Task| J[π Background: ArXiv API Fetch]
J --> K[Download PDFs]
K --> L[Extract Text - pdfplumber]
L --> M[Chunk + Embed]
M --> N[Append to FAISS Index]
N --> O[Reload Index in Memory]
O -->|Next query benefits| E
When retrieval scores are below the threshold (-2.0), Lumina schedules a non-blocking background task using FastAPI's BackgroundTasks. The response is sent to the user immediately. The background task then:
- Queries the ArXiv API with the user's search terms
- Downloads up to 3 relevant PDFs (skipping already-cached ones)
- Extracts text (capped at 15 pages per paper for speed)
- Chunks, embeds, and appends to the existing FAISS index
- Reloads the in-memory index β no restart required
| Component | Technology |
|---|---|
| API Framework | FastAPI + uvicorn |
| Vector Database | faiss-cpu (IndexFlatL2) |
| Embedding Model | sentence-transformers/all-MiniLM-L6-v2 |
| Reranking Model | cross-encoder/ms-marco-MiniLM-L-6-v2 |
| LLM | Google GenAI SDK β gemini-2.0-flash |
| PDF Extraction | pdfplumber |
| ArXiv Search | arxiv Python library |
| Environment | python-dotenv |
| Component | Technology |
|---|---|
| Framework | Next.js 16 (App Router + Turbopack) |
| Styling | Tailwind CSS v4 with OKLCH dark mode theming |
| Animations | framer-motion |
| Icons | lucide-react |
| HTTP Client | axios |
| Graph Visualization | react-force-graph (dynamic SSR-safe import) |
self-improving-rag/
βββ backend/
β βββ api/
β β βββ main.py # FastAPI app, /ask (with BackgroundTasks), /feedback
β β βββ schemas.py # Pydantic request/response models
β βββ agent/
β β βββ research_agent.py # Agentic orchestration layer
β βββ feedback/
β β βββ feedback_logger.py # Logs user thumbs up/down to JSON
β βββ generation/
β β βββ gemini_generator.py # Google Gemini 2.0 Flash answer synthesis
β βββ ingestion/
β β βββ arxiv_fetcher.py # ArXiv API PDF downloader (with error handling)
β β βββ build_index.py # Full FAISS index builder (run once to seed DB)
β β βββ chunker.py # Sliding-window text chunking
β β βββ embedder.py # SentenceTransformer embedding wrapper
β β βββ pdf_loader.py # pdfplumber PDF text extraction
β β βββ update_vector_db.py # Incremental FAISS append (no full rebuild)
β βββ learning/
β β βββ feedback_analyzer.py # Analyzes feedback_logs.json for improvements
β β βββ query_expander.py # Gemini-powered query synonym expansion
β β βββ reranker.py # CrossEncoder logit scoring and sorting
β βββ retrieval/
β β βββ search.py # FAISS k-NN search + dynamic index reload
β βββ rag_pipeline.py # Main orchestration: Search β Rerank β Generate
βββ data/
β βββ papers/ # All PDF papers live here (local + arXiv downloads)
βββ vector_store/
β βββ paper_index.faiss # FAISS index file (persisted to disk)
β βββ metadata.pkl # Chunk-to-paper mapping (text + source)
βββ rag-ai-ui/ # Next.js Frontend (Lumina)
β βββ app/
β β βββ globals.css # Tailwind v4, OKLCH dark palette, glass utilities
β β βββ layout.tsx # Root layout β forces dark class globally
β β βββ page.tsx # Main chat page β orchestrates all components
β βββ components/
β β βββ ChatInput.tsx # Glassmorphic floating textarea with glow effect
β β βββ ChatMessage.tsx # User/AI bubbles with Framer Motion entry animation
β β βββ FeedbackButtons.tsx # Thumbs up/down with active-state glass styling
β β βββ PaperPreview.tsx # shadcn Dialog for full paper preview
β β βββ ResearchGraph.tsx # react-force-graph citation network (SSR-safe)
β β SourceList.tsx # Cited paper pill badges
β β βββ ThinkingLoader.tsx # Animated dots skeleton loader
β βββ lib/
β βββ api.ts # Axios wrappers for /ask and /feedback
β βββ utils.ts # Tailwind class merge utility (cn())
βββ feedback_logs.json # Auto-generated feedback storage
βββ README.md
- Python 3.12+
- Node.js 18+
- A Google AI Studio API key (free)
git clone https://github.com/your-username/self-improving-rag.git
cd self-improving-rag# Create and activate virtual environment
python -m venv venv
# Windows
venv\Scripts\activate
# Mac/Linux
source venv/bin/activate
# Install Python dependencies
pip install fastapi uvicorn faiss-cpu sentence-transformers google-genai pdfplumber arxiv python-dotenv pydanticCreate a .env file in the root self-improving-rag/ directory:
GEMINI_API_KEY="your-gemini-api-key-here"Place any PDF research papers you have into data/papers/. Then build the initial index:
# From the self-improving-rag root folder
cd backend/ingestion
python build_index.pyThis only needs to be run once. After that, the arXiv background fetcher keeps the DB updated automatically.
cd rag-ai-ui
npm installYou need two terminals running simultaneously.
Terminal 1 β Backend API:
# From the self-improving-rag root
venv\Scripts\activate # Windows
source venv/bin/activate # Mac/Linux
uvicorn backend.api.main:app --reloadRuns on
http://127.0.0.1:8000
API docs available athttp://127.0.0.1:8000/docs
Terminal 2 β Frontend UI:
# From the rag-ai-ui folder
npm run devRuns on
http://localhost:3000
Accepts a user query, runs the full RAG pipeline, and schedules a background arXiv fetch if context was weak.
Request:
{ "query": "Explain diffusion models" }Response:
{
"query": "Explain diffusion models",
"answer": "Diffusion models are generative models that...",
"sources": ["principles-of-diffusion-model.pdf", "gen-ai.pdf"]
}Logs user feedback for a given query/answer pair.
Request:
{
"query": "Explain diffusion models",
"answer": "Diffusion models are...",
"feedback": "positive"
}| Setting | File | Default | Description |
|---|---|---|---|
WEAK_SCORE_THRESHOLD |
rag_pipeline.py |
-2.0 |
CrossEncoder score below which arXiv fetch is triggered |
max_results |
arxiv_fetcher.py |
3 |
Number of papers to download per background fetch |
pdf.pages[:15] |
build_index.py |
15 pages | Max pages extracted per PDF (prevents hanging on large files) |
pdf.pages[:10] |
update_vector_db.py |
10 pages | Max pages for incrementally-added papers |
k=10 |
rag_pipeline.py |
10 | Number of FAISS nearest-neighbour chunks retrieved |
If uvicorn crashes and leaves a zombie process, clear it manually:
# Windows PowerShell β find and kill the PID on port 8000
netstat -ano | findstr ":8000"
Stop-Process -Id <PID> -ForceThis means the backend is not responding. Check that:
uvicornstarted withApplication startup complete.in its logs.- No other process is blocking port 8000.
- Your
.envfile has a validGEMINI_API_KEY.
Your vector DB is empty or the query is outside the scope of indexed papers. Run build_index.py to seed the database, then the background fetcher will auto-expand it on future queries.
Built to bridge the gap between static knowledge and dynamic discovery.
Lumina β because your AI should never stop learning.