Files
duocthu/README.md
T

5.7 KiB

Dược Thư RAG — Medical Chatbot Platform

Medical chatbot grounded in the Vietnamese National Drug Formulary (Dược thư quốc gia Việt Nam 2018), built as a microservices monorepo.

See docs/architecture.md for the full design (service responsibilities, data stores, RAG ingestion strategy, safety guardrails), docs/adr for architecture decision records, docs/pdf-parsing-outlier-catalog.md for a reusable checklist of confirmed PDF-parsing risks (useful for this book and any similarly-structured PDF), and docs/progress-log.md for a running log of what's been done and what's next.

Dated planning and audit documents (docs/v1-delivery-plan.md, docs/rag-rebuild-plan.md, docs/current-rag-pipeline-audit.md, docs/answer-experience-implementation-plan.md) record what was known on their date and are kept for their reasoning rather than as current status — this README and git log are the better reference for where things stand today.

Status (2026-08-11): live in production at realvuxbaro.me — a real RAG chatbot over the whole formulary, not a scaffold. What exists and what does not:

Part State
ingestion/ Done — 15,100 chunks embedded and loaded into Qdrant duocthu_v1
apps/ai-service/ Done — live grounded RAG (retrieval, generation, grounding, abstention, citations, traces)
apps/web/ Done — chat UI with citation/evidence panel
apps/api-gateway, auth-service, user-service, chat-service Not builtREADME.md + package.json only
apps/mobile/ Not built — reserved
infra/docker/ Done — this is what production actually runs
infra/k8s, helm, terraform, argocd Not built yet — empty scaffold. Still the target (ADR 0002), not abandoned: the plan is the team's self-hosted Gitea + ArgoCD; the current EC2/Compose setup is an interim stopgap

Because the gateway and auth services do not exist, apps/web talks directly to apps/ai-service; there is no authentication layer. See the build roadmap in docs/architecture.md.

Directory map

apps/
  web/            Next.js frontend (also hosts the BFF route the browser calls)
  ai-service/     Python FastAPI — RAG orchestration + AWS Bedrock calls
  api-gateway/    NestJS — public entry point, routes to internal services
  auth-service/   NestJS — signup/login/JWT
  user-service/   NestJS — profile/preferences
  chat-service/   NestJS — chat session + message history
  mobile/         reserved for a future mobile app
packages/
  shared-types/   TS DTOs shared across Node services + web
  api-client/     typed HTTP client for web
  ui/             shared React components
  config/         shared eslint/tsconfig presets
ingestion/        offline batch pipeline: PDF -> monographs -> chunks -> embeddings -> Qdrant
infra/            docker-compose, k8s/Helm, Terraform, CI
docs/             architecture docs and ADRs

Prerequisites

  • Node.js + pnpm (JS workspace: apps/web, packages/*; the NestJS service directories are unbuilt placeholders)
  • Python 3.11+ (apps/ai-service, ingestion)
  • Docker (local Postgres + Qdrant via infra/docker/docker-compose.yml)
  • AWS credentials with Bedrock invoke permission, for anything that generates an answer. Without them ai-service still starts, but every answer abstains rather than falling back to raw source text.

Running it locally

docker compose -f infra\docker\docker-compose.yml up -d postgres qdrant
cd apps\ai-service
python -m migrate
python -m uvicorn main:app --port 8079     # NOT --reload, see below
pnpm install
pnpm --filter web dev                      # http://localhost:3000

ai-service needs a populated Qdrant collection to serve answers: it verifies a duocthu_v1__manifest sidecar at startup and refuses to run against a corpus whose sha/model/dimensions do not match. A fresh machine either restores a Qdrant snapshot or re-runs ingestion/ (the latter costs real Bedrock spend).

Prefer a plain restart over uvicorn --reload on Windows here. The reloader has been observed serving the previous code after an edit on this project, which makes it hard to tell whether a change took effect.

Tests: cd apps/ai-service && python -m pytest -q — 230 pass. test_api.py and test_live_datastores.py need Postgres and Qdrant actually running; skip them with --ignore when the stack is down. apps/web has no test setup at all, so a green suite says nothing about the frontend — drive it in a browser.

Production

Live at realvuxbaro.me: a single EC2 t3.large running infra/docker/docker-compose.prod.yml (postgres, qdrant, ai-service, web, Caddy for automatic Let's Encrypt TLS). Bedrock is reached through an IAM instance role — there are no long-lived AWS keys on the box or in any env file.

Pushing to master deploys: .github/workflows/deploy.yml SSHes in, resets to the pushed commit, rebuilds only ai-service/web, runs migrations and health-checks both. Postgres/Qdrant/Caddy are left untouched, so the vector data survives deploys (it lives in a named volume, not the container).

This is interim infrastructure, not the end state. The intended target is still the team's self-hosted Gitea (company domain) plus their ArgoCD instance, per docs/adr/0002-argocd-gitops.md — that work is not started, not cancelled. Until it is deliberately started, the project stays on private GitHub, and the team's existing git.vinmec.tech/ai-team/gitops repository is reference-only: never push this project into it.