Files
2026-05-10 17:00:57 +07:00

415 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🤖 LiteRT-LM Web Server
[English](README-en.md)
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` | [litert-community/gemma-4-E2B-it-litert-lm](https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm) | Edge 2B — nhanh hơn, nhẹ hơn |
| `gemma-4-E4B-it` | [litert-community/gemma-4-E4B-it-litert-lm](https://huggingface.co/litert-community/gemma-4-E4B-it-litert-lm) | 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)
hf download litert-community/gemma-4-E2B-it-litert-lm \
--include '*.litertlm' \
--local-dir models/
# Gemma 4 E4B (lớn hơn, ~thông minh hơn)
hf download litert-community/gemma-4-E4B-it-litert-lm \
--include '*.litertlm' \
--local-dir models/
```
> **Hoặc** để server tự động tải khi chọn model chưa có sẵn.
---
## 🚀 Hướng dẫn sử dụng
### Cách 1: Chạy với tùy chọn mặc định
```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
[3] Sử dụng model từ đường dẫn khác
Chọn model (1/2/3):
```
**Tính năng tự động tải model:**
- Nếu chọn model chưa có, server sẽ hỏi: `Bạn muốn tải model ngay bây giờ? (y/n)`
- Chọn `y` để tự động tải từ Hugging Face
- Hoặc chọn `n` để tải thủ công sau
**Tự động xử lý port:**
- Nếu port 8000 đã bị chiếm, server sẽ hỏi chọn port khác
- Hoặc nhấn Enter để tự động tìm port khả dụng (8001-8999)
### Cách 2: Chạy với tham số command line
```bash
# Chỉ định port
python server.py --port 8080
# Chỉ định model từ đường dẫn
python server.py --model /path/to/model.litertlm
# Kết hợp cả hai
python server.py --port 8080 --model ~/models/gemma-4-E2B-it.litertlm
# Xem hướng dẫn đầy đủ
python server.py --help
```
### Mở Web UI
```
http://<địa-chỉ-ip>:<port>
```
Tên model và port sẽ hiển thị khi server khởi động:
```
====================================================
🚀 Server đang khởi động...
📍 URL: http://localhost:8000
📦 Model: gemma-4-E2B-it.litertlm
====================================================
```
---
## 📄 `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
### Tham số command line
| Tham số | Mô tả | Mặc định |
|---------|-------|---------|
| `--port`, `-p` | Port để chạy server | `8000` |
| `--model`, `-m` | Đường dẫn đầy đủ tới file model .litertlm | None (chọn từ menu) |
| `--help`, `-h` | Hiển thị hướng dẫn | - |
### Cấu hình trong code
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` |
Để 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": "litert-community/gemma-4-E2B-it-litert-lm",
"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)
```
### Chạy như systemd service (Linux)
Xem hướng dẫn chi tiết trong [SERVICE_README.md](SERVICE_README.md)
```bash
# Cài đặt service
sudo bash install_service.sh
# Quản lý service
sudo systemctl status litert-lm
sudo systemctl restart litert-lm
sudo journalctl -u litert-lm -f
```
---
## 📝 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 515 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