How igoralekseev-dev/rag-vector-chat works
1. This repository is a self-hosted RAG chat application built as a FastAPI backend with server-rendered HTML. The UI is not a SPA: it uses Jinja2 templates plus HTMX-style partial updates to refresh chat, document, and message fragments from the server.
2. The codebase is split into two main application domains: chat and documents. chat owns chat lifecycle, message history, and response generation. documents owns PDF upload, parsing, chunking, embedding, and indexing into the vector store.
3. src/main.py is the application bootstrap point. It likely assembles the FastAPI app, registers routers from both domains, and wires startup configuration and shared dependencies such as database and vector/LLM clients.
4. src/config.py centralizes runtime settings from environment variables, including the SQLite database URL, Qdrant endpoint, and OpenAI-compatible LLM credentials/model name. This makes the app portable across local and Docker Compose deployments.
5. src/database.py is the relational persistence boundary. The README indicates SQLite is used to store chat history, messages, and uploaded file metadata. This relational layer keeps the app lightweight and acts as the source of truth for chat/session state.
6. The vector-search boundary is Qdrant. Documents are split into chunks, embedded with Sentence Transformers, and stored in Qdrant with metadata tied to chat_id. That chat_id filter is the key isolation mechanism that prevents retrieval from mixing content across chats.
7. The documents subsystem likely follows a pipeline: receive PDF upload through documents/router.py, parse and normalize file content in documents/utils.py, then persist document records and upsert vectors via documents/service.py. The relational DB records the file, while Qdrant stores the semantic index.
8. The chat subsystem exposes routes for creating/opening chats and sending messages. chat/models.py and chat/schemas.py define the data shape for persisted chat entities and API/request-response payloads, while chat/service.py handles the business logic for message persistence, retrieval of relevant chunks, prompt assembly, and calling the language model.
9. LLM generation is externalized behind an OpenAI-compatible API. The repository does not appear to hardcode a specific provider; instead, the model endpoint, API key, and model name are configurable, which is an important architectural boundary for swapping providers without changing the UI or domain logic.
10. The rendered UI is composed of reusable partials under src/templates/partials/. These fragments correspond to distinct functional areas such as the sidebar chat list, the active chat workspace, message pairs, document cards, and “new chat” responses. That indicates a page layout driven by incremental server-side updates rather than client-side state management.
11. The end-to-end data flow is: user creates/selects a chat, uploads one or more PDFs, documents are chunked and indexed, then the user asks a question. On message submit, the backend searches Qdrant only within that chat, injects the relevant context into the prompt, sends it to the LLM, stores the answer in SQLite, and returns updated HTML fragments to the browser.
12. Deployment is designed around local or containerized execution. docker-compose.yml runs the app alongside Qdrant, and the README notes that the project can be run entirely self-hosted. The dependency set in pyproject.toml supports async Python web execution, PDF parsing, vector search, and templated HTML rendering.
13. From an architecture-diagram perspective, the important boundaries are: browser/UI, FastAPI server, SQLite relational store, Qdrant vector store, and external LLM API. The chat and documents modules sit inside the FastAPI boundary as separate vertical slices that share config and database infrastructure but have distinct responsibilities.
Main entry points: chat/service.py Chat Service · main.py Bootstrap · documents/service.py Doc Service · router.py Chat Routes
Components 15
Browser UI
Server-rendered HTML interface with partial updates.
- Browser · User-facing browser session interacting with server-rendered pages.
- Index Page · Main server-rendered shell for the chat application.
src/templates/index.html - Partial Views · Reusable fragments for chat, documents, and message updates.
src/templates/partials
FastAPI App
Application bootstrap and domain routes.
Chat Domain
Chat lifecycle, history, and answer generation.
- Chat Routes · Endpoints for chat creation, selection, and message submission.
src/chat/router.py - Chat Service · Coordinates history, retrieval, prompt assembly, and response generation.
src/chat/service.py - Chat Models · Persistent chat and message entities.
src/chat/models.py - Chat Schemas · Request and response payload shapes for the chat domain.
src/chat/schemas.py
Documents Domain
PDF upload, parsing, chunking, and indexing.
- Doc Routes · Endpoints for PDF upload and document management.
src/documents/router.py - Doc Service · Handles parsing, chunking, embedding, and vector indexing.
src/documents/service.py - Doc Utils · File parsing and normalization helpers for document ingestion.
src/documents/utils.py
Data Stores
Relational and vector persistence boundaries.
- Database · Relational persistence layer for chats, messages, and file metadata.
src/database.py
External Services
LLM and vector infrastructure used by the app.
- Qdrant · Semantic index for document chunks filtered by chat.
- LLM API · OpenAI-compatible completion endpoint used for response generation.
Connections 20
- Browser → Index Page: load UI · The browser requests the server-rendered application shell.
- Browser → Chat Routes: chat actions · User interactions submit chat and message requests to the backend.
- Browser → Doc Routes: upload PDFs · Document uploads are sent to the documents endpoints.
- Bootstrap → Config: reads settings · Bootstrap loads runtime configuration from the environment.
- Bootstrap → Chat Routes: registers · Chat routes are mounted on the FastAPI app.
- Bootstrap → Doc Routes: registers · Document routes are mounted on the FastAPI app.
- Bootstrap → Database: connects · Shared relational persistence is initialized at startup.
- Chat Routes → Chat Service: delegates · HTTP handlers pass work into chat business logic.
- Chat Service → Chat Models: persists · Chat and message records are stored through the domain models.
- Chat Service → Database: reads/writes · The chat service uses SQLite-backed state and history.
- Chat Service → Qdrant: retrieves context · Relevant chunks are fetched from the vector store using chat-scoped filters.
- Chat Service → LLM API: generates reply · Prompted context is sent to the external language model endpoint.
- Chat Service → Partial Views: renders fragments · Updated message and workspace fragments are returned to the browser.
- Doc Routes → Doc Service: delegates · Upload handlers pass documents into the ingestion pipeline.
- Doc Service → Doc Utils: parses files · Helper routines normalize PDF content before chunking.
- Doc Service → Database: stores metadata · Uploaded document records are persisted relationally.
- Doc Service → Qdrant: indexes chunks · Embedded chunks are upserted into the vector database.
- Index Page → Partial Views: composes · The main page is assembled from reusable partial fragments.
- Qdrant → Config: endpoint · Vector-store connection details come from shared configuration.
- LLM API → Config: credentials · Model endpoint, API key, and model name are configured centrally.