# 🤖 LiteRT-LM Web Server Chạy mô hình **Gemma 4** trên thiết bị nhúng (Orange Pi 5, Raspberry Pi, v.v.) thông qua [LiteRT-LM](https://github.com/google-ai-edge/litert-lm) với giao diện REST API và Web UI. --- ## 📋 Yêu cầu - Python 3.10+ - [`litert-lm`](https://github.com/google-ai-edge/litert-lm) đã cài và hoạt động - Thư viện Python: ```bash pip install -r requirements.txt ``` `requirements.txt`: ``` fastapi uvicorn pydantic huggingface_hub ``` --- ## 📁 Cấu trúc ``` . ├── app.py # REST API đơn giản, single-turn ├── server.py # REST API đầy đủ + Web UI, multi-turn sessions ├── templates/ │ └── index.html # Giao diện Web UI (tách riêng khỏi server.py) ├── models/ # Thư mục chứa các file model .litertlm │ ├── gemma-4-E2B-it.litertlm │ └── gemma-4-E4B-it.litertlm ├── requirements.txt └── README.md ``` --- ## 🤖 Models hỗ trợ | Model | Repo HuggingFace | Mô tả | |-------|-----------------|-------| | `gemma-4-E2B-it` | [google/gemma-4-E2B-it](https://huggingface.co/google/gemma-4-E2B-it) | Edge 2B — nhanh hơn, nhẹ hơn | | `gemma-4-E4B-it` | [google/gemma-4-E4B-it](https://huggingface.co/google/gemma-4-E4B-it) | Edge 4B — thông minh hơn, nặng hơn | > **Lưu ý:** Nên dùng bản `-it` (instruction-tuned) cho chat/hỏi đáp. Bản không có `-it` là base model, chỉ predict token tiếp theo, không phù hợp để hội thoại. ### Tải model về ```bash # Gemma 4 E2B (nhỏ hơn, ~nhanh hơn) huggingface-cli download google/gemma-4-E2B-it \ --include '*.litertlm' \ --local-dir models/ # Gemma 4 E4B (lớn hơn, ~thông minh hơn) huggingface-cli download google/gemma-4-E4B-it \ --include '*.litertlm' \ --local-dir models/ ``` --- ## 🚀 Hướng dẫn sử dụng ### Bước 1 — Tải ít nhất một model vào thư mục `models/` Xem lệnh tải ở trên. ### Bước 2 — Chạy server ```bash python server.py ``` Server sẽ hiển thị menu **chọn model** trước khi khởi động: ``` ==================================================== LiteRT-LM Server — Chọn model ==================================================== [1] gemma-4-E2B-it Gemma 4 Edge 2B — nhỏ hơn, nhanh hơn ✓ có sẵn [2] gemma-4-E4B-it Gemma 4 Edge 4B — thông minh hơn, chậm hơn ✗ chưa tải Chọn model (1/2): ``` Nếu model chưa được tải, server sẽ hiển thị lệnh `huggingface-cli download` tương ứng và hỏi có muốn chọn model khác không. ### Bước 3 — Mở Web UI ``` http://<địa-chỉ-ip>:8000 ``` Tên model đang chạy sẽ hiển thị trên header của Web UI. --- ## 📄 `app.py` — REST API đơn giản File cơ bản, single-turn, không có menu chọn model. Phù hợp để tích hợp nhanh hoặc test. ### Chạy ```bash python app.py ``` ### Endpoint #### `POST /generate` Gửi một prompt, nhận phản hồi. Mỗi request là độc lập, **không có bộ nhớ** giữa các lần gọi. ```bash curl -X POST http://localhost:8000/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "Bạn là ai?"}' ``` **Response:** ```json { "response": "Tôi là Gemma 4, một Mô hình Ngôn ngữ Lớn...", "tokens": 42, "elapsed_s": 5.31, "tokens_per_sec": 7.91 } ``` --- ## 🖥️ `server.py` — REST API đầy đủ + Web UI Phiên bản đầy đủ với chọn model khi khởi động, multi-turn conversation, quản lý session và giao diện chat trên trình duyệt. --- ### 🌐 Web UI Mở trình duyệt và truy cập `http://<địa-chỉ-ip>:8000` Tính năng: - **Chọn model khi khởi động** qua menu CLI — tên model hiển thị trực tiếp trên header - Giao diện chat trực quan, hỗ trợ tiếng Việt - Tự động tạo session khi mở trang - Nhớ ngữ cảnh hội thoại trong cùng một session - Nút **New** để bắt đầu cuộc trò chuyện mới - Nút **Clear** để xóa lịch sử và tạo session mới - `Enter` để gửi, `Shift + Enter` để xuống dòng - **Render Markdown**: câu trả lời hiển thị đúng định dạng (heading, list, code block, table, bold/italic, v.v.) - **Đo tốc độ**: badge `⚡ X tok/s` bên dưới mỗi câu trả lời, kèm số token và thời gian xử lý --- ### 🔌 REST API #### `GET /info` Trả về thông tin model đang chạy và số session hiện tại. ```bash curl http://localhost:8000/info ``` **Response:** ```json { "model": "gemma-4-E2B-it", "sessions": 2 } ``` --- #### `POST /generate` Single-turn, không nhớ context. Dùng khi chỉ cần hỏi đáp đơn lẻ. ```bash curl -X POST http://localhost:8000/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "Thủ đô của Việt Nam là gì?"}' ``` **Response:** ```json { "response": "Thủ đô của Việt Nam là Hà Nội.", "tokens": 12, "elapsed_s": 1.45, "tokens_per_sec": 8.27 } ``` --- #### `POST /chat/new` Tạo một session mới. Trả về `session_id` dùng cho các request tiếp theo. ```bash curl -X POST http://localhost:8000/chat/new ``` **Response:** ```json { "session_id": "a3f2c1d4-..." } ``` --- #### `POST /chat/{session_id}` Gửi tin nhắn trong một session. Model **nhớ toàn bộ lịch sử hội thoại** trong session đó. ```bash curl -X POST http://localhost:8000/chat/a3f2c1d4-... \ -H "Content-Type: application/json" \ -d '{"prompt": "Kể thêm về điều đó đi"}' ``` **Response:** ```json { "session_id": "a3f2c1d4-...", "response": "...", "tokens": 58, "elapsed_s": 7.12, "tokens_per_sec": 8.15 } ``` --- #### `DELETE /chat/{session_id}` Xóa session và giải phóng bộ nhớ. ```bash curl -X DELETE http://localhost:8000/chat/a3f2c1d4-... ``` **Response:** ```json { "status": "cleared", "session_id": "a3f2c1d4-..." } ``` --- #### `GET /chat/sessions/list` Liệt kê tất cả session đang hoạt động. ```bash curl http://localhost:8000/chat/sessions/list ``` **Response:** ```json { "sessions": ["a3f2c1d4-...", "b7e9f2a1-..."], "count": 2 } ``` --- ## 💡 Ví dụ: Multi-turn conversation qua curl ```bash # 1. Tạo session SESSION=$(curl -s -X POST http://localhost:8000/chat/new | python3 -c "import sys,json; print(json.load(sys.stdin)['session_id'])") # 2. Gửi tin nhắn đầu tiên curl -s -X POST http://localhost:8000/chat/$SESSION \ -H "Content-Type: application/json" \ -d '{"prompt": "Tên tôi là Nam"}' | python3 -m json.tool # 3. Model nhớ context curl -s -X POST http://localhost:8000/chat/$SESSION \ -H "Content-Type: application/json" \ -d '{"prompt": "Tên tôi là gì?"}' | python3 -m json.tool # 4. Xóa session khi xong curl -X DELETE http://localhost:8000/chat/$SESSION ``` --- ## ⚙️ Cấu hình Các tham số chỉnh trong đầu `server.py`: | Biến | Mô tả | Mặc định | |------|-------|---------| | `MODELS_DIR` | Thư mục chứa model | `./models` | | `AVAILABLE_MODELS` | Danh sách model + repo HuggingFace | xem trong file | | `backend` | Backend inference | `litert_lm.Backend.CPU` | | `host` | Địa chỉ lắng nghe | `0.0.0.0` | | `port` | Cổng | `8000` | Để thêm model mới vào menu, bổ sung vào dict `AVAILABLE_MODELS` trong `server.py`: ```python AVAILABLE_MODELS = { "gemma-4-E2B-it": { "file": "gemma-4-E2B-it.litertlm", "repo": "google/gemma-4-E2B-it", "desc": "Gemma 4 Edge 2B — nhỏ hơn, nhanh hơn", }, "ten-model-moi": { "file": "ten-model-moi.litertlm", "repo": "org/repo-name", "desc": "Mô tả model", }, } ``` Để đổi backend sang GPU (nếu thiết bị hỗ trợ): ```python engine = litert_lm.Engine(str(MODEL_PATH), backend=litert_lm.Backend.GPU) ``` --- ## 📝 Ghi chú - Mỗi session giữ toàn bộ lịch sử hội thoại trong RAM. Nên xóa session khi không dùng nữa. - Warning `mel_filterbank` khi khởi động là bình thường — liên quan đến audio encoder của Gemma 4 multimodal, không ảnh hưởng đến text generation. - Tốc độ generate phụ thuộc vào phần cứng. Trên Orange Pi 5 với CPU, khoảng 5–15 token/giây. - Token/s dùng `engine.tokenize()` nếu có, fallback về ước tính `len(text) // 4` nếu không khả dụng. - Markdown được render bằng [marked.js](https://marked.js.org/) trực tiếp trên trình duyệt, không qua server. - Chỉ dùng bản `-it` (instruction-tuned) cho chat — bản base model không phù hợp hội thoại. --- ## 📜 License MIT