415 lines
10 KiB
Markdown
415 lines
10 KiB
Markdown
# 🤖 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 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
|