DeepReader is a local-first AI document intelligence and RAG workbench for turning technical documents into inspectable retrieval evidence. It demonstrates the pieces a reviewer expects in a serious RAG system: document ingestion, deterministic record IDs, source-preserving retrieval, summaries, processing jobs, citations, and evidence inspection.
It is intentionally not a chatbot wrapper. The dashboard exposes records, scores, retrieval methods, summaries, job steps, citations, and evidence packets so the retrieval pipeline can be inspected end to end.
Document upload and records: ingest local .txt or .epub files, select documents, and inspect stable record IDs.
Generated summaries: deterministic local summaries are displayed beside preserved source text.
Search/retrieval results: compare ranked records with scores, retrieval methods, metadata, summaries, and source text.
Extractive QA with citations/evidence: answers remain tied to cited records and inspectable evidence packets.
Job tracking and steps: summary processing jobs expose status, progress, target stable IDs, attempts, and errors.
- Text and EPUB ingestion through a FastAPI backend.
- SQLite persistence for local, reproducible demos.
- Deterministic document records with stable IDs and source hashes.
- Source-preserving BM25 retrieval over original document text.
- Local vector-style retrieval and simple fusion for comparison.
- Deterministic local summaries with checkpointing.
- Processing jobs and job steps for summary generation.
- Summary-aware search with visible retrieval methods and component scores.
- Deterministic extractive QA with citations, evidence packets, and retrieval settings.
- React/Vite/TypeScript dashboard built for inspection rather than chat.
- Docker Compose setup for a no-secrets local demo.
- Backend tests and frontend build in GitHub Actions CI.
No API keys are required. The local summariser and QA flow are deterministic placeholders for pipeline verification; they do not call OpenAI, Gemini, or any paid external API.
backend/src/deepreader/api: FastAPI routes and response schemas.backend/src/deepreader/ingest: text and EPUB parsing.backend/src/deepreader/storage: SQLAlchemy models and repositories.backend/src/deepreader/summarise: local summariser, checkpointing, and summary job runner.backend/src/deepreader/retrieval: BM25, local vector-style retrieval, and fusion.backend/src/deepreader/answer: extractive QA, evidence packets, and citations.frontend/src: dashboard panels for uploads, documents, records, jobs, search, and QA.
More detail lives in docs/ARCHITECTURE.md.
Install and run the backend:
cd backend
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -e ".[dev]"
cd ..
make backend-devIn a second terminal, install and run the frontend:
cd frontend
pnpm install --frozen-lockfile
pnpm devOpen http://127.0.0.1:5173. The dashboard defaults to the backend at http://127.0.0.1:8000. To override it, copy frontend/.env.example to frontend/.env and set VITE_API_BASE_URL.
From the repository root:
docker compose up --buildThen open http://127.0.0.1:5173.
Docker Compose runs:
- backend on
http://127.0.0.1:8000 - frontend on
http://127.0.0.1:5173 - SQLite in a named local volume, mounted at
/app/datain the backend container
No secrets or external services are required.
Use docs/DEMO_WORKFLOW.md for a step-by-step reviewer script. The short version:
- Start backend and frontend locally, or run Docker Compose.
- Upload
examples/simple_manual.txt. - Select the document and inspect records, stable IDs, and source text.
- Search for
what causes low flow?. - Generate summaries and inspect the processing job.
- Search summaries.
- Ask a QA question.
- Inspect citations and evidence packets.
- Run tests and the frontend build.
Reviewer checklist:
- Uploads accept
.txtand.epuband reject unsafe filenames/extensions. - Source records remain visible and unchanged.
- Stable IDs make records traceable across retrieval, summaries, citations, and jobs.
- Search results show scores, retrieval methods, metadata, summaries, and source text.
- QA answers expose citations and evidence rather than hidden generated claims.
- Tests and frontend build pass locally.
Dashboard uploads use the real API:
POST /documents/ingest/textfor.txtPOST /documents/ingest/epubfor.epub
The backend enforces local filename safety checks, extension allowlists, and upload size limits. Duplicate ingest currently creates another document row, while deterministic record stable IDs are reused for identical content. That behavior is intentional for now and tested.
Generating summaries for a document creates a record_summary job and one summarise_record step per record. The job runner is synchronous today, but it stores background-style progress:
pendingrunningcompletedfailed
Checkpointing is based on record_id, summariser_name, and source_hash. Rerunning summary generation skips unchanged records that already have a matching summary. If a record source hash changes, a new current summary is created and prior source text remains untouched.
The summariser is local_extractive_v1: it normalises whitespace, selects deterministic text, truncates predictably, and stores summary/source hashes. It is not meant to be high-quality AI prose.
Search supports source text, summaries, local vector-style retrieval, and simple fusion. Response fields are inspection-first:
document_idrecord_idstable_idretrieval_methodsource_textsummarymetadatascorecomponent_scores
The QA endpoint is deterministic and extractive. It returns an answer plus citations, all evidence packets, used evidence, unused evidence, and retrieval settings. It is not a chatbot and does not call an LLM.
POST /documents/ingest/textPOST /documents/ingest/epubGET /documentsGET /documents/{document_id}GET /documents/{document_id}/recordsPOST /documents/{document_id}/summaries/runGET /documents/{document_id}/summariesGET /jobsGET /jobs/{job_id}GET /jobs/{job_id}/stepsPOST /jobs/{job_id}/retry-failedPOST /searchPOST /qa/askGET /answersGET /answers/{answer_id}
make test
make backend-dev
make frontend-dev
make frontend-buildmake frontend-dev and make frontend-build use pnpm by default. Override with NPM=npm if needed.
Backend:
make testFrontend:
cd frontend
pnpm install --frozen-lockfile
pnpm buildDocker config:
docker compose configGitHub Actions runs backend install/tests and frontend install/build without secrets.
Backend defaults live in .env.example:
DEEPREADER_DATABASE_URL=sqlite:///./data/deepreader.sqlite3DEEPREADER_MAX_UPLOAD_BYTES=10485760DEEPREADER_CORS_ORIGINS=http://127.0.0.1:5173,http://localhost:5173
The default CORS origins are local-only. Uploaded file content and secrets are not logged by design. A small redaction utility exists for future provider-backed configuration, but no provider keys are needed today.
- SQLite is the only configured persistence layer.
- Text and EPUB are supported; real OCR and PDF OCR are not implemented.
- Summary jobs are synchronous despite job/step bookkeeping.
- The local summariser is deterministic and extractive, not an LLM summary.
- The local vector-style retriever is not embeddings and should not be treated as semantic search.
- Fusion is intentionally simple.
- QA is extractive and deterministic, not answer generation from a model.
- No auth, multi-user permissions, hosted deployment, PostgreSQL, Celery, Redis, or production observability stack.
- Add a short demo video.
- Add optional provider-backed summaries behind disabled-by-default configuration.
- Add real embeddings and hybrid retrieval in a later milestone.
- Add richer job retry/checkpoint inspection.
- Add exportable evidence packets for reviewer handoff.
- Consider production deployment concerns only after the local portfolio workflow is stable.
This project is licensed under the MIT License. See LICENSE.




