Flask + Gunicorn backend for a notes-first RAG (Retrieval-Augmented Generation) assistant.
- Pass 1 (notes-first): retrieve relevant chunks from your course notes (FAISS) and answer primarily from those notes.
- Pass 2 (optional extra): add general context without contradicting the notes answer.
-
User input (browser)
- The user enters a question.
- The user selects
extra_mode(never,auto, oralways).
-
Frontend sends request
- JavaScript sends
POST /askwith JSON:question(string)extra_mode(string)chat_model(optional string, must be allowed by the backend)- (optionally)
include_extra(boolean, depending on UI)
- JavaScript sends
-
Nginx reverse proxy
- Nginx receives the HTTPS request on
/ask. - It proxies the request to Gunicorn via the Unix socket
unix:/run/rag/rag.sock.
- Nginx receives the HTTPS request on
-
Gunicorn → Flask
- Gunicorn forwards the request to the Flask app.
- Flask routes it to the
/askhandler and parses the JSON payload (with defaults).
-
Retrieve relevant note chunks (RAG retrieval)
- The backend calls the embeddings endpoint to embed the user question.
- FAISS searches the vector index for the top-k most relevant chunks.
- The backend prepares:
sources[](metadata used for citations)source_blocks(text snippets injected into the model prompt)
-
Pass 1: Notes-first answer
- The backend calls the chat model with a prompt that prioritizes answering from the retrieved notes.
- The raw model output is sanitized (e.g. remove
thinktraces). - Coverage is computed:
- Prefer
COVERAGE: full|partial|noneif the model provided it - Otherwise fall back to a retrieval-based heuristic
- Prefer
-
Pass 2: Extra context (optional)
- If enabled by
extra_mode:never: skip pass 2always: always run pass 2auto: run pass 2 only if notes coverage is notfull
- Pass 2 adds general context without contradicting the notes answer.
- If enabled by
-
Backend returns JSON
- Flask returns JSON with:
answer_notesanswer_extra(ornull)coveragesources
- Flask returns JSON with:
-
Frontend renders response
- The UI displays the notes-based answer first (with citations).
- If present, the UI shows the extra context section.
- If MathJax is enabled, the page typesets LaTeX math in the rendered output.
flowchart TD
A["User in browser<br/>types question + chooses extra_mode"] --> B["Frontend JS<br/>POST /ask (JSON)"]
B --> C["Nginx (HTTPS)<br/>proxy /ask"]
C --> D["Gunicorn<br/>unix:/run/rag/rag.sock"]
D --> E["Flask: /ask handler<br/>parse JSON + defaults"]
E --> F["Embed query<br/>POST /v1/embeddings"]
F --> G["FAISS vector search<br/>top-k chunks"]
G --> H["Build source_blocks + sources[]"]
H --> I["Pass 1: Notes-first prompt<br/>question + retrieved chunks"]
I --> J["LLM chat completions<br/>POST /v1/chat/completions"]
J --> K["Sanitize + extract COVERAGE<br/>remove think-tags etc."]
K --> L["coverage = model_coverage<br/>or retrieval_coverage"]
L --> M{"Do pass 2?<br/>include_extra & extra_mode"}
M -->|never| R["Skip extra"]
M -->|always| N["Pass 2: Extra prompt<br/>question + notes answer"]
M -->|"auto & coverage!=full"| N
N --> O["LLM chat completions<br/>POST /v1/chat/completions"]
O --> P["Sanitize extra<br/>ensure header"]
R --> Q["Build JSON response<br/>answer_notes, coverage, sources"]
P --> Q
Q --> S["Frontend renders<br/>notes + sources + extra (optional)"]
S --> T["MathJax typeset<br/>(if enabled)"]
Request JSON:
{
"question": "What is a partial derivative?",
"extra_mode": "auto",
"chat_model": "your-provider/model-a"
}
extra_mode:"never"|"auto"|"always"chat_model: optional; if omitted, the backend usesCHAT_MODELas the default/fallback
Response JSON (shape):
{
"answer_notes": "…",
"answer_extra": "… or null",
"coverage": "full|partial|none",
"chat_model": "…",
"sources": [
{
"tag": "[S1]",
"source": "_includes/module2/m2_2.md",
"chunk_id": 74,
"score": 0.744
}
]
}
Returns:
{"status":"ok"}
Returns the backend-owned allowlist of selectable chat models, plus the default model that will be used when the client does not send chat_model.
- The FAISS index + metadata live under
vector_store/(generated by the ingest pipeline). - Typical deployment: Nginx → Gunicorn (Unix socket) → Flask.