DeepMed-AI — Project Reference Document
Last updated: 2026-04-14
Author: Pham Ba Thuong
Repo: e:\AI\DeepMed
Production URL: Hugging Face Spaces (Docker)
Version: 3.0.0
1. Tổng Quan
DeepMed-AI là chatbot AI y tế chuyên dụng cho Trung tâm Y tế Khu vực Thanh Ba (TTYT KV Thanh Ba), tỉnh Phú Thọ, Việt Nam. Hỗ trợ y bác sĩ và dược sĩ:
- Tra cứu thông tin thuốc (tên, hoạt chất, giá, hãng SX, liều dùng, chống chỉ định)
- Chẩn đoán, phác đồ điều trị, tư vấn y khoa
- Tra cứu danh mục thuốc nội bộ của TTYT Thanh Ba
2. Kiến Trúc Hệ Thống
2.1. Architecture: HybridRAG
┌──────────────┐ ┌──────────────────────────────────────────────┐
│ React SPA │────▶│ FastAPI Backend (app/main.py) │
│ (Vite) │ │ │
│ Port: 5173 │ │ ┌──────────────────────────────────────┐ │
│ (dev) │ │ │ ChatService (Singleton) │ │
│ │ │ │ │ │ │
│ └───────────┘ │ │ ┌──────────┐ ┌──────────────────┐│ │
│ │ │ │Fast Mode │ │ Deep Mode ││ │
│ │ │ │BM25+Vec │ │ BM25+Vec → Rerank││ │
│ │ │ │ k=15 │ │ k=25 → top 5 ││ │
│ │ │ └──────────┘ └──────────────────┘│ │
│ │ │ │ │
│ │ │ ┌──────────────────────────────────┐│ │
│ │ │ │ ChromaDB (Local Persistent) ││ │
│ │ │ │ Embedding: MiniLM-L12-v2 ││ │
│ │ │ └──────────────────────────────────┘│ │
│ │ │ │ │
│ │ │ LLM: Gemini 2.5 Flash (Google) │ │
│ │ └──────────────────────────────────────┘ │
│ │ │
│ │ SQLite (chat history) via SQLAlchemy │
│ └──────────────────────────────────────────────┘
2.2. Hai Chế Độ Retrieval
| Mode |
Retriever |
k |
Reranker |
Khi nào dùng |
| Fast |
BM25 + Vector (EnsembleRetriever 50/50) |
15 |
❌ |
Tra cứu thuốc nhanh, câu hỏi đơn giản |
| Deep |
BM25 + Vector (EnsembleRetriever 50/50) → CrossEncoder |
25 → 5 |
✅ BGE-reranker-v2-m3 |
Phác đồ, chẩn đoán, điều trị phức tạp |
Auto-detect: Hệ thống tự nhận diện Deep mode khi câu hỏi chứa keyword: phác đồ, điều trị, chẩn đoán, xử trí, hướng dẫn, protocol, guideline, bệnh nhân bị, cách điều trị, dùng thuốc gì, nên dùng, kê đơn, toa thuốc, sơ cứu, cấp cứu.
3. Tech Stack
3.1. Backend
| Component |
Technology |
Version |
| Framework |
FastAPI |
0.115.12 |
| Server |
Uvicorn |
0.34.2 |
| LLM |
Gemini 2.5 Flash |
via langchain-google-genai 2.1.4 |
| Embedding |
paraphrase-multilingual-MiniLM-L12-v2 |
via sentence-transformers 3.4.1 |
| Vector DB |
ChromaDB (local persistent) |
≥0.4.0 |
| Keyword Search |
BM25 (rank-bm25) |
0.2.2 |
| Reranker |
BGE-reranker-v2-m3 (CrossEncoder) |
via langchain-community |
| LangChain |
langchain + langchain-core + langchain-community |
0.3.25 |
| ORM |
SQLAlchemy |
2.0.40 |
| DB |
SQLite (chat history) |
via pysqlite3-binary |
| Data Processing |
pypdf, python-docx, openpyxl, pandas |
various |
| Rate Limiting |
slowapi |
0.1.9 |
| Validation |
Pydantic |
2.11.3 |
| PyTorch |
CPU-only |
2.2.2+cpu |
| Python |
3.10-slim (Docker) |
|
3.2. Frontend
| Component |
Technology |
Version |
| Framework |
React |
19.2.0 |
| Build Tool |
Vite |
7.3.1 |
| Styling |
Tailwind CSS + Vanilla CSS (index.css 30KB) |
4.1.18 |
| Markdown |
react-markdown |
10.1.0 |
| Icons |
Font Awesome (CDN) |
|
| UI Components |
DaisyUI |
5.5.18 |
| Testing |
Vitest + Testing Library |
4.0.18 |
3.3. Deployment
| Platform |
Config |
| Primary: Hugging Face Spaces |
Docker, port 7860 |
| Docker |
Multi-stage build (Node 20 → Python 3.10-slim) |
| Alternative |
docker-compose (backend:8000, frontend:80) |
| CI/CD |
Push via push_hf.bat |
4. Cấu Trúc Thư Mục
e:\AI\DeepMed\
├── Dockerfile # Multi-stage: frontend build → backend
├── docker-compose.yml # Local dev: backend:8000 + frontend:80
├── .env.example # Template env vars
├── push_hf.bat # Deploy to HuggingFace Spaces
├── run.py # Local runner
│
├── backend/
│ ├── requirements.txt # Python dependencies
│ ├── pyproject.toml # Project metadata
│ ├── app/
│ │ ├── main.py # FastAPI entry + lifespan + SPA serving
│ │ ├── core/
│ │ │ ├── config.py # Env vars: GOOGLE_API_KEY, paths
│ │ │ ├── logging_config.py
│ │ │ └── state.py # (minimal)
│ │ ├── api/v1/
│ │ │ ├── api.py # Router aggregator
│ │ │ └── endpoints/
│ │ │ ├── chat.py # POST /chat, /clear, /new-chat
│ │ │ ├── health.py # GET /health
│ │ │ ├── session.py # GET /sessions, /session/{id}, /history
│ │ │ └── voice.py # (placeholder)
│ │ ├── services/
│ │ │ ├── chat_service.py # ★ CORE: DeepMedBot + ChatService (713 lines)
│ │ │ └── database_service.py # CRUD for chat history
│ │ ├── tools/
│ │ │ ├── vector_store.py # Qdrant version (LEGACY, not used in current arch)
│ │ │ ├── document_loader.py # Drug-aware chunking (for Qdrant version)
│ │ │ ├── llm_client.py # Gemini 2.5 Flash singleton
│ │ │ └── pdf_loader.py
│ │ ├── models/
│ │ │ └── message.py # SQLAlchemy Message model
│ │ ├── schemas/
│ │ │ ├── chat.py # ChatRequest, ChatResponse (Pydantic)
│ │ │ └── session.py
│ │ └── db/
│ │ └── session.py # SQLAlchemy session factory
│ │
│ ├── data/ # ★ MEDICAL DATA (Git LFS tracked)
│ │ ├── chroma_db/ # ChromaDB persistent storage
│ │ ├── thông tin thuốc nội bộ/ # 454 drug .md files
│ │ ├── phác đồ bộ y tế/ # 30 MOH guideline PDFs
│ │ ├── phác đồ tại ttytkv thanh ba/ # 8 local protocol PDFs
│ │ ├── các hiệp hội/ # 10 association guideline PDFs
│ │ ├── dược thư quốc gia/ # 1 national formulary PDF (24MB)
│ │ └── medical_book.pdf # 16MB reference book
│ │
│ ├── storage/
│ │ └── chat_db/ # SQLite DB (medigenius.db)
│ └── tests/
│
└── frontend/
├── package.json
├── vite.config.js
├── tailwind.config.js
├── index.html
└── src/
├── App.jsx # ★ Single-file SPA (722 lines)
├── index.css # Full CSS design system (30KB)
├── index.jsx # React entry point
└── App.test.jsx
5. API Endpoints
| Method |
Path |
Description |
Rate Limit |
| POST |
/api/v1/chat |
Send message → HybridRAG response |
15/min/IP |
| POST |
/api/v1/clear |
Clear current session history |
— |
| POST |
/api/v1/new-chat |
Create new session |
— |
| GET |
/api/v1/health |
Health check |
— |
| GET |
/api/v1/sessions |
List all chat sessions |
— |
| GET |
/api/v1/session/{id} |
Get session messages |
— |
| DELETE |
/api/v1/session/{id} |
Delete a session |
— |
| GET |
/api/v1/history |
Get current session history |
— |
Request/Response Schema
class ChatRequest(BaseModel):
message: str
class ChatResponse(BaseModel):
response: str
source: str | None
timestamp: str | None
success: bool
6. Dữ Liệu Y Tế (Data Sources)
6.1. Thông tin thuốc nội bộ (data/thông tin thuốc nội bộ/)
- 454 file .md — mỗi file là 1 thuốc trong danh mục TTYT Thanh Ba
- Format:
# TÊN_THUỐC → Hoạt chất: ... → nội dung chi tiết
- Metadata enrichment:
drug_name, active_ingredient, ingredient_keywords, doc_type
- Ví dụ: MIDANTIN, Ceftriaxone 2000, Amoxicillin 250mg, Metformin...
- Bao gồm: giá thuốc, liều dùng, chống chỉ định, tương tác, bảo quản
6.2. Phác đồ Bộ Y tế (data/phác đồ bộ y tế/)
- 30 file PDF — Quyết định của Bộ Y tế
- Các chuyên khoa: Tim mạch, Hô hấp, Tiêu hóa, Thận-Tiết niệu, Nội tiết, Ung bướu, Da liễu, RHM, Lao, Ngộ độc, BPTNMT, COPD...
6.3. Phác đồ tại TTYT KV Thanh Ba (data/phác đồ tại ttytkv thanh ba/)
- 8 file PDF — phác đồ nội bộ theo chuyên khoa
- CKL, HSCC, NTH, NTM, Ngoại, Nhi, Sản, YHCT
6.4. Các hiệp hội (data/các hiệp hội/)
- 10 file PDF — hướng dẫn từ các hội chuyên khoa (VUNA, etc.)
- Viêm phổi cộng đồng, COPD, Bệnh thận mạn, Nhiễm nấm xâm lấn...
6.5. Dược thư quốc gia (data/dược thư quốc gia/)
- 1 file PDF (24MB) — Dược thư Quốc gia Việt Nam 2023
6.6. Medical book (data/medical_book.pdf)
- 1 file PDF (16MB) — sách tham khảo y khoa
7. Cách Hoạt Động Chi Tiết
7.1. Khởi Động (Lifespan)
db_service.init_db() — tạo bảng SQLite
- LFS pointer detection — cảnh báo nếu file data < 500 bytes
chat_service.initialize() → DeepMedBot():
- Load embedding model (
paraphrase-multilingual-MiniLM-L12-v2)
- Check ChromaDB có sẵn? → nếu có, skip scan PDF
- Nếu chưa: quét toàn bộ
data/ → chunking (1200 chars, overlap 200) → index vào ChromaDB
- Build Fast Retriever (BM25 + Vector, k=15)
- Build Deep Retriever (BM25 + Vector k=25 → BGE-reranker-v2-m3 top 5)
- Init LLM (Gemini 2.5 Flash, temp=0.2)
- Build LangChain retrieval chains (history-aware)
7.2. Chat Flow
- User gửi message →
POST /api/v1/chat
- Session ID: từ header
X-Session-ID hoặc cookie
- Auto-detect mode (Fast/Deep) dựa trên keywords
- ChatService:
- Lưu user message vào SQLite
- Convert history → LangChain messages (max 5 turns)
- Run active chain:
create_retrieval_chain → retrieve docs → LLM answer
- Extract
[USED_SOURCES: ...] từ LLM output
- Build reference block (chỉ nguồn LLM thực sự dùng)
- Lưu assistant response vào SQLite
- Return JSON response
7.3. System Prompt
System prompt rất chi tiết (9 nguyên tắc), bắt buộc:
- Chỉ trả lời từ Context, không bịa
- PHẢI trả lời giá thuốc nếu có trong data
- Trích dẫn đúng nguồn, không bịa tên tài liệu
- Xác định thuốc đúng bằng header
[Trích từ tài liệu: TÊN_FILE]
- Ưu tiên phác đồ Bộ Y tế VN, WHO
- Kết bằng disclaimer
- BẮT BUỘC khai báo
[USED_SOURCES: file1 | file2 | ...]
8. Environment Variables
GOOGLE_API_KEY=xxx
FORCE_REBUILD_DB=False
DATA_DIR=/app/backend/data
CHROMA_DB_PATH=/app/backend/data/chroma_db
CHAT_DB_PATH=/app/backend/storage/chat_db/medigenius.db
LOG_DIR=/app/backend/logs
ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000,http://localhost:7860
SESSION_SECRET=auto_generated
HF_HOME=/tmp/huggingface
HUGGINGFACE_HUB_CACHE=/tmp/huggingface/hub
SENTENCE_TRANSFORMERS_HOME=/tmp/sentence-transformers
TRANSFORMERS_CACHE=/tmp/transformers
XDG_CACHE_HOME=/tmp/.cache
9. Frontend Features
- Single-file SPA:
App.jsx (722 lines) — không dùng React Router
- Components:
ErrorBoundary, Sidebar, ChatArea, MessageBubble, InputArea
- Theme: Dark/Light mode (toggle, persist localStorage)
- Mobile responsive:
useIsMobile hook, sidebar backdrop
- Chat sessions: New, Load, Delete, Download as .txt
- Quick Questions: 6 preset medical queries
- Markdown rendering:
react-markdown cho bot response
- Copy message: clipboard API
- Toast notifications: success/error/info
- Glass morphism design:
.glass-effect class
- Animated background: floating circles + gradient overlay
- Status indicator: "AI Ready" pulse ring
10. Deployment (Hugging Face Spaces)
Dockerfile Flow
- Stage 1: Node 20 Alpine →
npm ci → npm run build → /app/frontend/dist
- Stage 2: Python 3.10-slim → install system deps → install torch CPU → install requirements → copy backend → copy frontend dist → set permissions → run uvicorn on port 7860
Key Docker Issues (Đã Fix)
- SQLite version: Python 3.10-slim ships SQLite 3.34, ChromaDB cần ≥ 3.35 → monkey-patch
pysqlite3-binary
- HF Cache PermissionError: HF Spaces set
HOME=/nonexistent → fix: force all cache to /tmp/
- Git LFS pointers: Data files are LFS-tracked → MUST
git lfs pull before Docker build, or data will be empty stubs
- Non-root user:
appuser:appgroup for security, needs chown for storage dirs
- ChromaDB batch limit: Max 5461 per batch → batch upload in groups of 5000
Deploy Command
git push hf main
11. Lịch Sử Phát Triển & Các Vấn Đề Đã Giải Quyết
Phase 1: Initial Build (03/2026)
- Xây dựng backend FastAPI + frontend React
- Ban đầu dùng Qdrant Cloud cho vector DB
- Deploy lên HuggingFace Spaces
Phase 2: Qdrant Cloud → ChromaDB Migration (04/2026)
- Chuyển từ Qdrant Cloud sang ChromaDB local để giảm latency và dependency
- File
tools/vector_store.py vẫn chứa code Qdrant (LEGACY, không dùng)
- Code ChromaDB hiện tại nằm trong
services/chat_service.py
Phase 3: LangGraph → HybridRAG Simplification (04/07/2026)
- Loại bỏ kiến trúc LangGraph multi-agent phức tạp
- Thay bằng HybridRAG đơn giản: ChromaDB + BM25 + CrossEncoder Reranker
- 2 modes: Fast / Deep
Phase 4: UI Modernization (04/08-09/2026)
- Redesign UI responsive, mobile-friendly
- Thêm sidebar chat history, dark/light theme
- Glass morphism, animated background
Known Issues / TODO
tools/vector_store.py — LEGACY code cho Qdrant, không dùng nữa nhưng chưa xóa
tools/document_loader.py — Version cũ với drug-aware chunking cho Qdrant
core/langgraph_workflow.py — Stub file, nội dung trống
core/state.py — Stub file, nội dung minimal
docker-compose.yml — Lỗi thời, dùng port 8000/80 thay vì 7860
agents/ folder — Có file tavily.py nhưng không được import trong main flow
tools/duckduckgo_search.py, tools/wikipedia_search.py, tools/tavily_search.py — Search tools không dùng trong HybridRAG hiện tại
- Database service vẫn gọi là "MediGenius" trong docstring (tên cũ)
- Frontend: Nút Settings chưa có chức năng
12. Commands
cd e:\AI\DeepMed\frontend && npm run dev
cd e:\AI\DeepMed\backend && uvicorn app.main:app --reload --port 8000
docker build -t deepmed-ai .
docker run -p 7860:7860 -e GOOGLE_API_KEY=xxx deepmed-ai
FORCE_REBUILD_DB=True uvicorn app.main:app
cd frontend && npm test
cd backend && pytest
push_hf.bat
13. File Quan Trọng Nhất (Quick Reference)
| Mục đích |
File |
| Entry point |
backend/app/main.py |
| Core logic |
backend/app/services/chat_service.py (713 lines) |
| Chat API |
backend/app/api/v1/endpoints/chat.py |
| Config |
backend/app/core/config.py |
| LLM |
backend/app/tools/llm_client.py |
| Frontend SPA |
frontend/src/App.jsx (722 lines) |
| CSS |
frontend/src/index.css (30KB) |
| Docker |
Dockerfile (92 lines, multi-stage) |
| Dependencies |
backend/requirements.txt |
| Env template |
.env.example |
14. Lưu Ý Khi Chỉnh Sửa
- System prompt nằm trong
chat_service.py (2 bản: QA_SYSTEM_PROMPT_FAST và QA_SYSTEM_PROMPT_DEEP). Cũng có bản trong llm_client.py (LEGACY).
- ChromaDB logic hoàn toàn trong
chat_service.py, KHÔNG phải vector_store.py (đó là Qdrant legacy).
- Document loading trong
chat_service.py dùng _load_documents_from_folder() riêng, KHÔNG phải document_loader.py (đó cũng là Qdrant legacy).
- Frontend là single-file React (
App.jsx), không có routing. CSS ~30KB custom.
- Deploy phải đảm bảo
git lfs pull trước khi build Docker, nếu không data sẽ trống.
- SQLite monkey-patch PHẢI ở đầu
main.py, trước mọi chromadb import.
- HF cache paths PHẢI set trước khi import sentence-transformers/transformers.