An AI-powered RAG (Retrieval-Augmented Generation) chatbot for the DigiLocker system. It answers questions about DigiLocker document issuers and FAQs using a local LLM, and refuses to answer anything outside its knowledge base.
- Knowledge base build — On first run,
app.pyreads the data sources, converts each record into a text document, embeds them withall-MiniLM-L6-v2(Sentence Transformers), and stores the vectors in a FAISS index. The index (knowledge_base.index) and documents (documents.json) are saved to disk and reused on subsequent runs. - Retrieval — For each user question, the top K nearest documents are retrieved from FAISS. Each result is filtered by an L2 distance threshold to drop irrelevant matches.
- Generation — The retrieved context is injected into a strict system prompt and sent to the local LLM via Ollama (
temperature 0.1). The response is streamed back to the browser chunk by chunk, along with the titles of the sources used. If the context doesn't answer the question, the bot repliesOUT OF SCOPE.
- Semantic search over DigiLocker issuer records and FAQ question/answer pairs
- Local, private LLM inference — Mistral 7B via Ollama (no API keys, no cloud)
- Streaming responses with a stop-generation button and response-time metrics
- Retrieved sources displayed under each answer
- Fast vector search using FAISS with per-result distance filtering to reduce hallucinations
- Knowledge base is cached on disk and only rebuilt when missing
- Lightweight single-page frontend (Tailwind CSS, vanilla JS) served by Flask
/healthendpoint reporting knowledge base and Ollama status
| File | Purpose |
|---|---|
app.py |
Flask backend: builds/loads the knowledge base, serves the UI and the streaming /chat endpoint |
index.html |
Chat UI (served by Flask at /) |
digilockerquestion.txt |
FAQ data source (Question: / Answer: pairs) |
dlDashboardData.json |
Document-issuer records (org name, state, available documents) |
requirements.txt |
Python dependencies |
knowledge_base.index |
FAISS vector index (generated on first run, not committed) |
documents.json |
Text documents backing the index (generated on first run, not committed) |
- Python 3.8+
- Ollama with the
mistral:7bmodel - ~4 GB free RAM/VRAM for the model
pip install -r requirements.txtInstall Ollama from https://ollama.com/download (Windows/macOS installers, or brew install ollama on macOS), then:
ollama serve # start the Ollama server (skip if it runs as a service)
ollama pull mistral:7bpython app.pyThen open http://127.0.0.1:5000 in your browser — Flask serves both the UI and the API.
On first run (or if knowledge_base.index / documents.json are missing) the server builds the knowledge base, which takes a moment while documents are embedded. Later startups load the saved index instantly.
All settings have sensible defaults and can be overridden with environment variables:
| Variable | Default | Purpose |
|---|---|---|
DIGIBOT_MODEL |
mistral:7b |
Ollama model used for generation |
DIGIBOT_PORT |
5000 |
Flask server port |
DIGIBOT_DEBUG |
0 |
Set to 1 to enable Flask debug mode (development only) |
DIGIBOT_TOP_K |
3 |
Number of documents retrieved per query |
DIGIBOT_DISTANCE_THRESHOLD |
1.0 |
Max L2 distance for a retrieved document to count as relevant |
DIGIBOT_MAX_HISTORY |
6 |
Max conversation messages sent to the LLM |
GET /— serves the chat UI.GET /health— returns{"knowledge_base": bool, "ollama": bool}; HTTP 200 when both are healthy, 503 otherwise.POST /chat— accepts a JSON body with the conversation history and streams the reply as plain text. The first line of the stream is__SOURCES__followed by a JSON array of retrieved source titles; the rest is the answer.
{
"messages": [
{ "role": "user", "content": "Is my driving licence available on DigiLocker?" }
]
}Delete the generated files and restart the server:
rm knowledge_base.index documents.json
python app.pyThe knowledge base is rebuilt from dlDashboardData.json and digilockerquestion.txt.
- Ask about DigiLocker document issuers (e.g. "Which documents does the Rajasthan Board issue?") or general DigiLocker FAQs.
- The assistant answers only from the retrieved database context, and shows the sources it used under each answer.
- If the answer is not in the knowledge base, it replies:
OUT OF SCOPE.
- "Could not get a response from the local LLM" — Make sure
ollama serveis running andmistral:7bis pulled. CheckGET /health. - "Sorry, I couldn't connect to the local AI model" (in the browser) — The Flask backend isn't running; start it with
python app.py. - "No data sources found" on startup — Neither
dlDashboardData.jsonnordigilockerquestion.txtcould be read; make sure they're in the project root. - Slow first startup — Embedding all documents takes time; later startups load the saved index instantly.
MIT — see LICENSE.