| # 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 |
|
|
| ```python |
| # ChatRequest |
| class ChatRequest(BaseModel): |
| message: str |
| |
| # ChatResponse |
| 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) |
| |
| 1. `db_service.init_db()` — tạo bảng SQLite |
| 2. LFS pointer detection — cảnh báo nếu file data < 500 bytes |
| 3. `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 |
|
|
| 1. User gửi message → `POST /api/v1/chat` |
| 2. Session ID: từ header `X-Session-ID` hoặc cookie |
| 3. Auto-detect mode (Fast/Deep) dựa trên keywords |
| 4. 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 |
| 5. 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 |
|
|
| ```bash |
| # Required |
| GOOGLE_API_KEY=xxx # Gemini 2.5 Flash API key |
| |
| # Optional |
| FORCE_REBUILD_DB=False # True = rebuild ChromaDB on startup |
| 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 Spaces cache fix (set automatically in Dockerfile) |
| 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 |
| 1. **Stage 1**: Node 20 Alpine → `npm ci` → `npm run build` → `/app/frontend/dist` |
| 2. **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 |
| ```bash |
| # push_hf.bat |
| 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 |
|
|
| ```bash |
| # ── Local Development ── |
| cd e:\AI\DeepMed\frontend && npm run dev # Frontend: localhost:5173 |
| cd e:\AI\DeepMed\backend && uvicorn app.main:app --reload --port 8000 # Backend |
| |
| # ── Docker Build ── |
| docker build -t deepmed-ai . |
| docker run -p 7860:7860 -e GOOGLE_API_KEY=xxx deepmed-ai |
| |
| # ── Force Rebuild ChromaDB ── |
| FORCE_REBUILD_DB=True uvicorn app.main:app |
| |
| # ── Run Tests ── |
| cd frontend && npm test |
| cd backend && pytest |
| |
| # ── Deploy to HF Spaces ── |
| 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 |
|
|
| 1. **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). |
| 2. **ChromaDB** logic hoàn toàn trong `chat_service.py`, KHÔNG phải `vector_store.py` (đó là Qdrant legacy). |
| 3. **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). |
| 4. **Frontend** là single-file React (`App.jsx`), không có routing. CSS ~30KB custom. |
| 5. **Deploy** phải đảm bảo `git lfs pull` trước khi build Docker, nếu không data sẽ trống. |
| 6. **SQLite monkey-patch** PHẢI ở đầu `main.py`, trước mọi chromadb import. |
| 7. **HF cache paths** PHẢI set trước khi import sentence-transformers/transformers. |
|
|