A portfolio-ready RAG application that turns PDF documents into grounded answers with filename and page-level citations.
Teams often have policies and operational knowledge spread across PDFs. Searching manually is slow, while a general-purpose LLM may invent answers. This service is for internal teams that need a searchable knowledge base whose answers remain traceable to uploaded documents.
The repository includes the synthetic Persian PDF
docs/demo/employee-leave-policy-fa.pdf.
A verified live run answered 26 days and cited page 1. Full evidence is recorded
in docs/demo/DEMO_RESULT.md.
| Persian | English |
|---|---|
![]() |
![]() |
| Persian | English |
|---|---|
![]() |
![]() |
For hands-on local testing, start the application and use its bilingual dashboard.
See docs/USAGE.md for the complete workflow.
- Validated PDF upload with SHA-256 duplicate protection
- Page-aware extraction with PyMuPDF and deterministic overlapping chunks
- PostgreSQL/pgvector storage and cosine-similarity retrieval
- Replaceable fake providers for offline tests and free OpenRouter providers
- Grounded answers with filename/page citations and safe insufficient-evidence behavior
- Citations deduplicated by document/page and limited to the three best pages
- Persistent conversations, user/assistant messages, and citation snapshots
- Paginated conversation history, detail, and cascade-safe deletion
- Transactional document states:
processing,ready, andfailed - Bilingual Persian/English entry, source-management, and question-answering pages
The bilingual dashboard is a portfolio prototype that separates two workflows: knowledge managers maintain PDF sources, while knowledge users ask questions and inspect citations. This separation improves usability but is not an authorization boundary.
A next production-oriented version should add sign-in, user accounts, role-based access control, protected document administration, tenant isolation, rate limiting, and secure session management before private organizational data is used.
flowchart LR
U[Dashboard or API client] --> A[FastAPI routes]
A --> S[Application services]
S --> P[PDF extraction and chunking]
S --> O[OpenRouter providers]
S --> R[Repositories]
R --> D[(PostgreSQL and pgvector)]
D --> S
S --> A
A --> U
The API layer handles HTTP validation, services own business rules and transactions, repositories isolate SQLAlchemy/database access, and provider interfaces keep hosted AI replaceable.
- FastAPI + Pydantic: typed request validation and automatic OpenAPI/Swagger
- PostgreSQL + pgvector: relational metadata and vectors in one database
- SQLAlchemy 2 + Alembic: explicit persistence and reproducible migrations
- PyMuPDF: page-preserving PDF text extraction
- OpenRouter: configurable free embedding and chat models
- pytest + Ruff: automated behavior checks and consistent code quality
Copy .env.example to .env and set OPENROUTER_API_KEY. The current models are:
- Embeddings:
nvidia/nemotron-3-embed-1b:free - Chat:
nvidia/nemotron-3-nano-30b-a3b:free
Use EMBEDDING_PROVIDER=fake and CHAT_PROVIDER=fake for fully offline
development. Never commit .env. Free hosted providers may log prompts and
outputs, so use only synthetic or non-sensitive documents.
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
docker compose up -d db
alembic upgrade head
uvicorn app.main:app --reloadAfter starting the application locally, choose a workspace at
http://127.0.0.1:8000/, manage PDFs at http://127.0.0.1:8000/sources,
or ask questions at http://127.0.0.1:8000/chat. API documentation is available at
http://127.0.0.1:8000/docs. These addresses intentionally refer to the
visitor's own computer; they are setup instructions, not public demo links.
PostgreSQL uses host port 15432 because the standard port is reserved on the
development machine.
docker compose up --build -dThe Compose configuration waits for PostgreSQL health, applies migrations, and
starts FastAPI on port 8000. The configuration is validated; the first image
build still requires network access to Docker Hub.
GET /healthPOST/GET /api/documentsGET/DELETE /api/documents/{document_id}POST /api/searchPOST /api/chatGET /api/conversationsGET/DELETE /api/conversations/{conversation_id}
python -m ruff check .
python -m pytest -qThe suite uses deterministic fake providers and an isolated knowledge_base_test
database, so running tests cannot delete dashboard documents or consume hosted API
quota. Live provider behavior is documented separately in the demo evidence.
- Synchronous ingestion keeps the MVP understandable and transactional, but large PDFs should move to a background queue in production.
- Character-based chunks are deterministic and easy to inspect, but token-aware chunking could improve model-specific context control.
- A low calibrated similarity threshold works for the current free Persian embedding model, but production data needs a larger evaluation set.
- Each chat request currently creates one two-message conversation. Multi-turn continuation requires an explicit conversation contract.
- Separate bilingual source-management and question-answering pages keep admin and end-user responsibilities clear while sharing one FastAPI application.
- No authentication, authorization, tenant isolation, or rate limiting
- No authentication or private-document production deployment
- Uploaded bytes are processed synchronously and are not retained as files
- Free model availability, privacy policy, quality, and rate limits may change
- Do not expose this service publicly or upload sensitive company documents without adding production security controls
- Add real authentication and role-based access to the existing workspaces
- Add per-user document workspaces
- Support multi-turn continuation inside an existing conversation
- Move ingestion to a background worker for larger files
- Add a representative multilingual retrieval evaluation set
MIT License. See LICENSE.
The portfolio MVP is complete. The automated suite, live Persian RAG demo, container build, migration, health endpoint, Swagger UI, usage documentation, and secret-hygiene checks are verified.




