Retrieval-Augmented Generation system for Polish legal codes (Kodeksy) — criminal, civil, family, administrative, commercial, and other acts published by the Sejm. Upload PDF acts, index them into a vector database, then query with natural language questions grounded in the actual legal text.
┌──────────┐ ┌─────────┐ ┌──────────┐ ┌────────┐
│ Frontend │───▶│ API │───▶│ Worker │───▶│ Qdrant │
│ (Svelte) │ │(FastAPI)│ │(consumer)│ │(vector)│
└──────────┘ └────┬────┘ └────┬─────┘ └────────┘
│ │
┌────┴────┐ ┌────┴─────┐
│ Redis │ │ RabbitMQ │
│ (meta) │ │ (queue) │
└─────────┘ └──────────┘
│
┌─────┴──────┐
│ Embedder │
│(Qwen3-8B) │
└─────────────┘
| Service |
Port |
Description |
| api |
8000 |
FastAPI — query, admin, dataset endpoints |
| worker |
— |
Consumes PDF ingest jobs from RabbitMQ |
| evaluator |
8001 |
Dataset generation and RAGAS evaluation |
| embedder |
8080 |
Qwen3-Embedding-8B via HuggingFace TEI |
| qdrant |
6333 |
Vector storage |
| rabbitmq |
5672 |
Message queue for async PDF processing |
| redis |
6379 |
Document metadata and chunk counts |
- Python 3.11, FastAPI, Uvicorn
- Qdrant — vector database
- Qwen/Qwen3-Embedding-8B — self-hosted embeddings (HuggingFace TEI)
- OpenAI API — chat completions (configurable model)
- RAGAS — evaluation (faithfulness, answer relevancy, context precision)
- RabbitMQ — async job queue (aio-pika)
- Redis — document metadata
- Svelte 5 + Vite — admin frontend
- Docker Compose — deployment
- Docker & Docker Compose
- OpenAI API key
- ~16 GB RAM (embedder model)
- Create
.env in the project root:
OPENAI_API_KEY=sk-...
ADMIN_API_KEY=your-secret-admin-key
-
(Optional) Place PDF files in ./data/pdfs/ to make them available for indexing from the UI.
-
Start all services:
First startup downloads the embedding model (~2 GB) — subsequent starts use the cache in ./data/hf_cache/.
| Variable |
Required |
Default |
Description |
OPENAI_API_KEY |
Yes |
— |
OpenAI API key |
ADMIN_API_KEY |
Yes |
— |
API key for admin endpoints (X-API-Key header) |
OPENAI_CHAT_MODEL |
No |
gpt-4.1 |
Chat model for completions |
CORS_ORIGINS |
No |
["http://localhost:5173"] |
Allowed CORS origins (JSON list) |
RABBITMQ_URL |
No |
amqp://rabbitmq:5672/ |
RabbitMQ connection URL |
| Method |
Path |
Description |
| POST |
/user/query |
Query the RAG system with a question |
Admin (requires X-API-Key header)
| Method |
Path |
Description |
| POST |
/admin/database/add |
Upload and index a PDF |
| GET |
/admin/database/list |
List all documents |
| DELETE |
/admin/database/remove?doc_id= |
Remove a document |
| POST |
/admin/database/reindex?doc_id= |
Re-index a document |
| DELETE |
/admin/database/clear |
Clear all data |
| Method |
Path |
Description |
| GET |
/dataset/list |
List available PDF files |
| POST |
/dataset/index?filename= |
Index an existing PDF |
| Method |
Path |
Description |
| POST |
/datasets/generate?doc_id=&count= |
Generate QA dataset |
| POST |
/datasets/run?dataset_name= |
Run RAGAS evaluation |
| GET |
/datasets/list |
List generated datasets |
| Method |
Path |
Description |
| GET |
/health |
API health check |