title: DocuAsk
emoji: π
colorFrom: green
colorTo: gray
sdk: static
app_build_command: cd frontend && npm ci && npm run build
app_file: frontend/dist/index.html
pinned: false
license: mit
DocuAsk
DocuAsk is a full-stack document Q&A web app. Upload a PDF (or paste text), ask questions in a chat box, and get answers with the source passage shown underneath β then rate each answer π/π and watch the usage metrics update on a live dashboard. It's a small, end-to-end product loop: a React front end, a FastAPI back end, a lightweight retrieval layer, and a SQLite telemetry layer, all runnable with one command and deployable as a single container.
π Live demo: docuask-production-c732.up.railway.app
β frontend + API from a single Railway container; dashboard at
/#/dashboard.
Screenshots
Features
- Upload & parse β drag-and-drop a PDF or paste text; the backend extracts (pypdf), chunks, and indexes it in memory. Encrypted / broken / non-PDF / empty / oversize inputs all fail with a clear, friendly message.
- Chat with sources β every answer shows the passage it was drawn from, so the retrieval is transparent.
- Hybrid retrieval β BM25 (
rank_bm25) combined with a FAISS cosine search over TF-IDF vectors; deliberately lightweight, no heavyweight model. - Optional LLM answers (free) β set
LLM_PROVIDER(groq|gemini|openrouter) andLLM_API_KEY, and answers become grounded summaries written from the retrieved passages (the source passage is still shown). All three are free OpenAI-compatible providers with email/Google sign-in. Without a key it falls back to an extractive answer, so the app runs with no credentials and no cost. - Feedback & telemetry β each question is logged to SQLite with its measured
latency; π/π feedback and a
/dashboardpage show total questions, median latency, and thumbs-up rate live from the DB.
Run it (one command)
docker compose up --build
Then open http://localhost:5173. The frontend calls the API through nginx, so there's nothing else to configure.
Run without Docker (dev)
Backend
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload # http://localhost:8000
Frontend
cd frontend
npm install
npm run dev # http://localhost:5173
In dev the Vite server proxies /api/* to the backend, so no CORS setup is
needed.
Tests
cd backend
pytest
The suite covers /health, upload success and every failure path, retrieval and
/ask, /feedback, /stats, and the combined deploy entrypoint. CI runs it on
every push.
API
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
Liveness probe. |
| POST | /documents |
Ingest a PDF file or raw text β document_id. |
| GET | /documents/{id} |
Document metadata. |
| POST | /ask |
{document_id, question} β answer + source passage. |
| POST | /feedback |
Attach π/π (up/down) to an interaction. |
| GET | /stats |
Totals, median latency, thumbs-up rate, over-time. |
Deploy
The frontend deploys to a Hugging Face Static Space and the API to any host that runs a Python web process. They're wired together with one Space variable β no rebuild needed to change the API URL.
1. Frontend β Hugging Face Static Space
The README front matter (sdk: static) tells HF to run the
app_build_command (cd frontend && npm ci && npm run build) and serve
frontend/dist.
- Create a new Space β Static SDK, owner
Sri-28, nameDocuask(the workflow default; case-sensitive on HF). - Push this repo to the Space (the
sync-to-hfworkflow does this automatically β see below). - In the Space's Settings β Variables, add
DOCUASK_API_URLset to your deployed API's URL. The frontend reads it at runtime viawindow.huggingface.variables, so you can change it without rebuilding.
The Space serves at https://sri-28-docuask.static.hf.space.
2. Backend β Railway
The API is a standard uvicorn app. On Railway:
- New Project β Deploy from GitHub repo β select
docuask. - Open the service β Settings β Root Directory =
backend. This makesbackend/railway.jsonbuildbackend/Dockerfile(which installs faiss'slibgomp1and honors Railway's injected$PORT). - Settings β Networking β Generate Domain to get a public URL.
- (Optional) In the service Variables, set
LLM_PROVIDER(e.g.gemini) andLLM_API_KEY(a free key β Gemini's is at aistudio.google.com/apikey, Google sign-in) to enable LLM-written answers; otherwise the API serves extractive answers. Add a Volume at/data+DOCUASK_DB=/data/docuask.dbto persist telemetry across restarts. - Copy the public URL β you'll set it as
DOCUASK_API_URLin the HF Space (step 3 above).
The Static Space origin (https://sri-28-docuask.static.hf.space) is already in
the backend's default CORS allow-list; add more via the CORS_ORIGINS env var.
See backend/.env.example.
Other hosts work too: any Docker host can build
backend/Dockerfile, and native-Python hosts (Render, β¦) can usebackend/Procfile.
Keep the demo in sync automatically
The sync-to-hf workflow mirrors main to
your Space on every push. Configure it once under Settings β Secrets and
variables β Actions:
- Secret
HF_TOKENβ a Hugging Face token with write scope. This is the only required step (username defaults toSri-28, Space toDocuask). - Optionally override the
HF_USERNAME/HF_SPACEvariables.
Until HF_TOKEN is set the workflow no-ops, so it never fails the branch.
One-origin alternative: the root
Dockerfile+app/server.pybuild a single image that serves the frontend and API together under one origin (API mounted at/api, no CORS). Use this on any Docker host if you'd rather run one service than two.
Project structure
docuask/
backend/ # FastAPI app + tests
app/
main.py # API: /health, /documents, /ask, /feedback, /stats
parsing.py # PDF/text extraction + chunking
retrieval.py # BM25 + FAISS (TF-IDF) hybrid index
store.py # in-memory document store
db.py # SQLite interaction telemetry
server.py # combined static + API entrypoint (deploy)
tests/ # pytest suite
frontend/ # Vite + React + Tailwind
src/
App.jsx # layout + hash routing (Chat / Dashboard)
DocumentUploader.jsx, Chat.jsx, Dashboard.jsx
Dockerfile # single-image build for Hugging Face Spaces
docker-compose.yml # local: frontend + backend together
.github/workflows/ # CI: pytest + frontend build on every push
Tech stack
- Frontend: React + Vite + Tailwind CSS
- Backend: FastAPI (Python)
- Retrieval: BM25 + FAISS over TF-IDF
- Persistence: SQLite (interaction telemetry)
- Tests: pytest
- CI: GitHub Actions (pytest + build on every push)
- Deploy: Hugging Face Static Space (frontend) + any Python host (API); Docker Compose locally
Roadmap
See PROJECT_SPEC.md for the full plan:
- β Skeleton end to end (health check wired browser β API)
- β Upload & parse flow (PDF/text β chunked, indexed)
- β Retrieval + chat loop (BM25 + FAISS, source passages)
- β
Data-collection & feedback layer (SQLite, π/π,
/stats, dashboard) - β Polish, tests, deploy (single-image Docker Space)

