diff --git a/README.md b/README.md index a882658..15f9ecb 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ huggingface_hub | 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 | +| `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. @@ -54,25 +54,23 @@ huggingface_hub ```bash # Gemma 4 E2B (nhỏ hơn, ~nhanh hơn) -huggingface-cli download google/gemma-4-E2B-it \ +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) -huggingface-cli download google/gemma-4-E4B-it \ +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 -### 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 +### Cách 1: Chạy với tùy chọn mặc định ```bash python server.py @@ -92,18 +90,51 @@ Server sẽ hiển thị menu **chọn model** trước khi khởi động: Gemma 4 Edge 4B — thông minh hơn, chậm hơn ✗ chưa tải -Chọn model (1/2): + [3] Sử dụng model từ đường dẫn khác + +Chọn model (1/2/3): ``` -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. +**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 -### Bước 3 — Mở Web UI +**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) -``` -http://<địa-chỉ-ip>:8000 +### 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 ``` -Tên model đang chạy sẽ hiển thị trên header của Web UI. +### Mở Web UI + +``` +http://<địa-chỉ-ip>: +``` + +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 +==================================================== +``` --- @@ -307,6 +338,16 @@ 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 | @@ -315,7 +356,6 @@ Các tham số chỉnh trong đầu `server.py`: | `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`: @@ -323,7 +363,7 @@ Các tham số chỉnh trong đầu `server.py`: AVAILABLE_MODELS = { "gemma-4-E2B-it": { "file": "gemma-4-E2B-it.litertlm", - "repo": "google/gemma-4-E2B-it", + "repo": "litert-community/gemma-4-E2B-it-litert-lm", "desc": "Gemma 4 Edge 2B — nhỏ hơn, nhanh hơn", }, "ten-model-moi": { @@ -340,6 +380,20 @@ AVAILABLE_MODELS = { 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ú diff --git a/SERVICE_README.md b/SERVICE_README.md new file mode 100644 index 0000000..6d730a8 --- /dev/null +++ b/SERVICE_README.md @@ -0,0 +1,415 @@ +# LiteRT-LM Linux Systemd Service + +Hướng dẫn cài đặt và sử dụng LiteRT-LM server như một systemd service trên Linux. + +## 📋 Yêu cầu + +- Linux với systemd (Ubuntu, Debian, Fedora, CentOS, etc.) +- Python 3 đã cài đặt +- Quyền sudo + +## 🚀 Cài đặt Service + +### Bước 1: Cho phép thực thi script + +```bash +chmod +x install_service.sh uninstall_service.sh +``` + +### Bước 2: Chạy script cài đặt + +```bash +sudo bash install_service.sh +``` + +Script sẽ hỏi cấu hình: +- **Port**: Port để chạy server (mặc định 8000) +- **Model path**: Đường dẫn model cụ thể (hoặc Enter để chọn từ menu) + +Sau đó script sẽ: +1. Tạo file config model mặc định (nếu cần) +2. Tạo systemd service file với cấu hình đã chọn +3. Enable service để tự động khởi động khi boot +4. Khởi động service ngay lập tức + +## ⚙️ Cấu hình + +### Cấu hình Model + +**Cách 1: Chọn từ menu (mặc định)** + +Chỉnh sửa file `service_config.txt` để chọn model: + +``` +1 → Gemma 4 Edge 2B (nhanh hơn) +2 → Gemma 4 Edge 4B (thông minh hơn) +3 → Nhập đường dẫn tùy chỉnh +``` + +Sau khi thay đổi, restart service: + +```bash +sudo systemctl restart litert-lm +``` + +**Cách 2: Chỉ định model cụ thể** + +Chỉnh sửa file service: + +```bash +sudo nano /etc/systemd/system/litert-lm.service +``` + +Sửa dòng `ExecStart`: + +```ini +ExecStart=/usr/bin/python3 /path/to/server.py --model /path/to/model.litertlm +``` + +Sau đó: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart litert-lm +``` + +### Cấu hình Port + +Chỉnh sửa file service: + +```bash +sudo nano /etc/systemd/system/litert-lm.service +``` + +Sửa dòng `ExecStart`: + +```ini +# Chỉ port +ExecStart=/usr/bin/python3 /path/to/server.py --port 8080 + +# Hoặc kết hợp với model +ExecStart=/usr/bin/python3 /path/to/server.py --port 8080 --model /path/to/model.litertlm +``` + +Sau đó: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart litert-lm +``` + +## 🎮 Quản lý Service + +### Xem trạng thái +```bash +sudo systemctl status litert-lm +``` + +### Dừng service +```bash +sudo systemctl stop litert-lm +``` + +### Khởi động service +```bash +sudo systemctl start litert-lm +``` + +### Khởi động lại service +```bash +sudo systemctl restart litert-lm +``` + +### Xem logs realtime +```bash +sudo journalctl -u litert-lm -f +``` + +### Xem logs từ đầu +```bash +sudo journalctl -u litert-lm +``` + +### Xem logs 100 dòng cuối +```bash +sudo journalctl -u litert-lm -n 100 +``` + +### Gỡ cài đặt service +```bash +sudo bash uninstall_service.sh +``` + +## 📊 Kiểm tra Service + +### Kiểm tra service đang chạy + +```bash +sudo systemctl is-active litert-lm +``` + +### Kiểm tra server hoạt động + +Mở trình duyệt: http://localhost:8000 (hoặc port đã cấu hình) + +Hoặc test API: +```bash +curl http://localhost:8000/info +``` + +## 🔧 Cấu hình nâng cao + +### Chỉnh sửa service file + +```bash +sudo nano /etc/systemd/system/litert-lm.service +``` + +Sau khi chỉnh sửa: +```bash +sudo systemctl daemon-reload +sudo systemctl restart litert-lm +``` + +### Thay đổi user chạy service + +Trong file service, sửa dòng: +```ini +User=your_username +``` + +### Thêm biến môi trường + +Thêm vào section `[Service]`: +```ini +Environment="VARIABLE_NAME=value" +Environment="ANOTHER_VAR=value" +``` + +### Giới hạn tài nguyên + +Thêm vào section `[Service]`: +```ini +# Giới hạn memory (ví dụ: 2GB) +MemoryLimit=2G + +# Giới hạn CPU (ví dụ: 50%) +CPUQuota=50% +``` + +## 🔍 Troubleshooting + +### Service không khởi động + +1. Kiểm tra logs: +```bash +sudo journalctl -u litert-lm -n 50 +``` + +2. Kiểm tra file service: +```bash +sudo systemctl cat litert-lm +``` + +3. Kiểm tra syntax: +```bash +sudo systemd-analyze verify /etc/systemd/system/litert-lm.service +``` + +### Thay đổi đường dẫn hoặc cấu hình + +Chỉnh sửa file service: + +```bash +sudo nano /etc/systemd/system/litert-lm.service +``` + +Sửa các dòng: +- `WorkingDirectory=` - Đường dẫn thư mục project +- `ExecStart=` - Lệnh khởi động với tham số +- `StandardInput=` - Đường dẫn file config + +Sau đó: +```bash +sudo systemctl daemon-reload +sudo systemctl restart litert-lm +``` + +### Service bị crash + +Service sẽ tự động restart sau 10 giây nhờ cấu hình: +```ini +Restart=always +RestartSec=10 +``` + +### Thay đổi port + +Sử dụng tham số `--port`: + +```bash +sudo nano /etc/systemd/system/litert-lm.service +``` + +Sửa dòng `ExecStart`: +```ini +ExecStart=/usr/bin/python3 /path/to/server.py --port 8080 +``` + +Sau đó: +```bash +sudo systemctl daemon-reload +sudo systemctl restart litert-lm +``` + +### Permission denied + +Đảm bảo user trong service file có quyền đọc/ghi thư mục: +```bash +sudo chown -R your_username:your_username /path/to/litert-lm-orangepi +``` + +## 🔐 Bảo mật + +### Chạy service với user riêng + +Tạo user chuyên dụng: +```bash +sudo useradd -r -s /bin/false litert-lm +sudo chown -R litert-lm:litert-lm /path/to/litert-lm-orangepi +``` + +Sửa trong service file: +```ini +User=litert-lm +Group=litert-lm +``` + +### Giới hạn quyền truy cập + +Thêm vào section `[Service]`: +```ini +# Chỉ đọc /usr, /boot, /etc +ProtectSystem=full + +# Không cho ghi vào /home +ProtectHome=true + +# Không cho truy cập /dev +PrivateDevices=true +``` + +### Firewall + +Chỉ cho phép truy cập local: +```bash +sudo ufw allow from 127.0.0.1 to any port 8000 +``` + +Hoặc cho phép từ mạng nội bộ: +```bash +sudo ufw allow from 192.168.1.0/24 to any port 8000 +``` + +## 📦 Cấu trúc Files + +``` +litert-lm-orangepi/ +├── server.py # Server chính (hỗ trợ --port và --model) +├── install_service.sh # Script cài đặt service +├── uninstall_service.sh # Script gỡ cài đặt service +├── litert-lm.service # Template systemd service +├── service_config.txt # Config model (1/2/3) - dùng khi không chỉ định --model +├── SERVICE_README.md # File này +└── models/ # Thư mục chứa models + ├── gemma-4-E2B-it.litertlm + └── gemma-4-E4B-it.litertlm +``` + +## 🎯 Auto-start khi khởi động + +Service đã được cấu hình để tự động khởi động: + +```bash +# Kiểm tra +sudo systemctl is-enabled litert-lm + +# Tắt auto-start +sudo systemctl disable litert-lm + +# Bật auto-start +sudo systemctl enable litert-lm +``` + +## 📊 Monitoring + +### Xem resource usage + +```bash +systemctl status litert-lm +``` + +### Xem chi tiết hơn + +```bash +sudo systemd-cgtop +``` + +### Xem tất cả services + +```bash +systemctl list-units --type=service +``` + +## ✅ Checklist sau khi cài đặt + +- [ ] Service đã được cài đặt: `systemctl list-units | grep litert-lm` +- [ ] Service đang chạy: `systemctl is-active litert-lm` +- [ ] Có thể truy cập http://localhost:8000 (hoặc port đã cấu hình) +- [ ] API `/info` trả về thông tin model +- [ ] Service tự động khởi động: `systemctl is-enabled litert-lm` +- [ ] Logs hiển thị bình thường: `journalctl -u litert-lm -n 20` + +## 🆘 Các lệnh hữu ích + +```bash +# Xem toàn bộ config của service +sudo systemctl show litert-lm + +# Xem dependencies +systemctl list-dependencies litert-lm + +# Xem thời gian khởi động +systemd-analyze blame + +# Test service file syntax +sudo systemd-analyze verify /etc/systemd/system/litert-lm.service + +# Xem logs từ boot cuối cùng +sudo journalctl -u litert-lm -b + +# Xem logs trong khoảng thời gian +sudo journalctl -u litert-lm --since "1 hour ago" +sudo journalctl -u litert-lm --since "2024-01-01" --until "2024-01-02" + +# Export logs ra file +sudo journalctl -u litert-lm > litert-lm.log +``` + +## 🔄 Update service + +Khi có thay đổi code trong `server.py`: + +```bash +sudo systemctl restart litert-lm +``` + +Không cần cài đặt lại service. + +## 📝 Ghi chú + +- Service sử dụng `StandardInput=file:` để tự động truyền model choice từ `service_config.txt` (nếu không dùng `--model`) +- Logs được quản lý bởi systemd journal (journalctl) +- Service tự động restart nếu bị crash +- Có thể chạy nhiều instance với port khác nhau bằng cách tạo nhiều service file +- Tham số `--port` và `--model` cho phép linh hoạt cấu hình mà không cần chỉnh sửa code diff --git a/install_service.sh b/install_service.sh index 73a8c5c..01437db 100644 --- a/install_service.sh +++ b/install_service.sh @@ -18,14 +18,31 @@ if [ "$EUID" -ne 0 ]; then exit 1 fi -# Tạo file config model mặc định nếu chưa có -if [ ! -f "service_config.txt" ]; then +# Hỏi cấu hình +echo "Cấu hình service:" +echo + +# Port +read -p "Port (mặc định 8000): " SERVICE_PORT +SERVICE_PORT=${SERVICE_PORT:-8000} + +# Model path (tùy chọn) +read -p "Đường dẫn model (Enter để chọn từ menu khi khởi động): " MODEL_PATH +if [ -n "$MODEL_PATH" ]; then + MODEL_ARG="--model $MODEL_PATH" +else + MODEL_ARG="" +fi + +# Tạo file config model mặc định nếu chưa có và không dùng custom model +if [ -z "$MODEL_PATH" ] && [ ! -f "service_config.txt" ]; then echo "1" > service_config.txt chown $SUDO_USER:$SUDO_USER service_config.txt echo "[✓] Đã tạo service_config.txt với model mặc định: 1" fi # Tạo file service từ template +echo echo "[1/4] Tạo file systemd service..." cat > /tmp/litert-lm.service << EOF [Unit] @@ -37,7 +54,7 @@ Type=simple User=$SUDO_USER WorkingDirectory=$CURRENT_DIR Environment="PATH=/usr/bin:/usr/local/bin:$HOME/.local/bin" -ExecStart=$PYTHON_PATH $CURRENT_DIR/server.py +ExecStart=$PYTHON_PATH $CURRENT_DIR/server.py --port $SERVICE_PORT $MODEL_ARG StandardInput=file:$CURRENT_DIR/service_config.txt Restart=always RestartSec=10 @@ -68,6 +85,14 @@ echo echo "Service đã được cài đặt và khởi động." echo "Server sẽ tự động chạy khi khởi động hệ thống." echo +echo "Cấu hình:" +echo " - Port: $SERVICE_PORT" +if [ -n "$MODEL_PATH" ]; then + echo " - Model: $MODEL_PATH" +else + echo " - Model: Chọn từ menu (xem service_config.txt)" +fi +echo echo "Các lệnh quản lý:" echo " - Xem trạng thái: sudo systemctl status litert-lm" echo " - Dừng service: sudo systemctl stop litert-lm" @@ -76,7 +101,7 @@ echo " - Khởi động lại: sudo systemctl restart litert-lm" echo " - Xem logs: sudo journalctl -u litert-lm -f" echo " - Gỡ cài đặt: sudo bash uninstall_service.sh" echo -echo "Server đang chạy tại: http://localhost:8000" +echo "Server đang chạy tại: http://localhost:$SERVICE_PORT" echo # Hiển thị trạng thái diff --git a/litert-lm.service b/litert-lm.service index 8cb465c..28d1489 100644 --- a/litert-lm.service +++ b/litert-lm.service @@ -7,7 +7,14 @@ Type=simple User=your_username WorkingDirectory=/home/your_username/litert-lm-orangepi Environment="PATH=/usr/bin:/usr/local/bin" +# Tùy chọn 1: Chạy với port mặc định, chọn model từ menu ExecStart=/usr/bin/python3 /home/your_username/litert-lm-orangepi/server.py +# Tùy chọn 2: Chỉ định port +# ExecStart=/usr/bin/python3 /home/your_username/litert-lm-orangepi/server.py --port 8080 +# Tùy chọn 3: Chỉ định model cụ thể +# ExecStart=/usr/bin/python3 /home/your_username/litert-lm-orangepi/server.py --model /path/to/model.litertlm +# Tùy chọn 4: Kết hợp cả hai +# ExecStart=/usr/bin/python3 /home/your_username/litert-lm-orangepi/server.py --port 8080 --model /path/to/model.litertlm StandardInput=file:/home/your_username/litert-lm-orangepi/service_config.txt Restart=always RestartSec=10 diff --git a/server.py b/server.py index 9c4ea19..08256f4 100644 --- a/server.py +++ b/server.py @@ -2,6 +2,8 @@ import os import sys import uuid import time +import socket +import argparse from pathlib import Path # Suppress verbose logs @@ -34,6 +36,49 @@ AVAILABLE_MODELS = { # ── CLI: chọn model khi khởi động ──────────────────────────────────────────── +def is_port_available(port: int) -> bool: + """Kiểm tra xem port có khả dụng không.""" + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(("0.0.0.0", port)) + return True + except OSError: + return False + +def select_port(default_port: int = 8000) -> int: + """Chọn port khả dụng.""" + if is_port_available(default_port): + return default_port + + print(f"\n ⚠️ Port {default_port} đã bị chiếm!") + while True: + try: + choice = input(f" Nhập port khác (hoặc Enter để dùng port tự động): ").strip() + if not choice: + # Tìm port tự động + for port in range(8001, 9000): + if is_port_available(port): + print(f" ✓ Sử dụng port tự động: {port}") + return port + print(" ✗ Không tìm thấy port khả dụng trong khoảng 8001-8999") + continue + + port = int(choice) + if port < 1024 or port > 65535: + print(" ✗ Port phải trong khoảng 1024-65535") + continue + + if is_port_available(port): + print(f" ✓ Sử dụng port: {port}") + return port + else: + print(f" ✗ Port {port} đã bị chiếm, vui lòng chọn port khác") + except ValueError: + print(" ✗ Vui lòng nhập số port hợp lệ") + except KeyboardInterrupt: + print("\n Thoát.") + sys.exit(0) + def download_model(repo: str, local_dir: Path) -> bool: """Tải model từ Hugging Face về local.""" try: @@ -61,7 +106,20 @@ def download_model(repo: str, local_dir: Path) -> bool: print(f"\n ✗ Lỗi không xác định: {e}") return False -def select_model() -> Path: +def select_model(custom_path: str = None) -> Path: + """Chọn model để sử dụng.""" + + # Nếu có custom path, kiểm tra và sử dụng luôn + if custom_path: + custom_model = Path(custom_path) + if custom_model.exists() and custom_model.suffix == ".litertlm": + print(f"\n ✓ Sử dụng model từ đường dẫn: {custom_model}") + return custom_model + else: + print(f"\n ✗ Không tìm thấy model tại: {custom_path}") + print(f" Vui lòng kiểm tra lại đường dẫn.\n") + sys.exit(1) + print("\n" + "="*52) print(" LiteRT-LM Server — Chọn model") print("="*52) @@ -73,10 +131,30 @@ def select_model() -> Path: print(f" {info['desc']}") print(f" {status}") print() + + print(f" [3] Sử dụng model từ đường dẫn khác") + print() while True: try: - choice = input("Chọn model (1/2): ").strip() + choice = input("Chọn model (1/2/3): ").strip() + + # Tùy chọn 3: Đường dẫn tùy chỉnh + if choice == "3": + custom_path = input("\n Nhập đường dẫn đầy đủ tới file .litertlm: ").strip() + custom_model = Path(custom_path) + if custom_model.exists() and custom_model.suffix == ".litertlm": + print(f"\n Đã chọn: {custom_model.name}") + print(f" Path: {custom_model}\n") + return custom_model + else: + print(f"\n ✗ Không tìm thấy file model hợp lệ tại: {custom_path}") + retry = input(" Thử lại? (y/n): ").strip().lower() + if retry == "y": + continue + else: + sys.exit(0) + idx = int(choice) - 1 if 0 <= idx < len(AVAILABLE_MODELS): key = list(AVAILABLE_MODELS.keys())[idx] @@ -122,14 +200,43 @@ def select_model() -> Path: print(f" Path: {model_path}\n") return model_path else: - print(" Vui lòng nhập 1 hoặc 2.") + print(" Vui lòng nhập 1, 2 hoặc 3.") except (ValueError, KeyboardInterrupt): print("\n Thoát.") sys.exit(0) -# Chọn model trước khi FastAPI khởi động +# Parse command line arguments +def parse_args(): + parser = argparse.ArgumentParser( + description="LiteRT-LM Server - Local AI inference server", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Ví dụ: + python server.py + python server.py --port 8080 + python server.py --model /path/to/model.litertlm + python server.py --port 8080 --model /path/to/model.litertlm + """ + ) + parser.add_argument( + "--port", "-p", + type=int, + default=8000, + help="Port để chạy server (mặc định: 8000)" + ) + parser.add_argument( + "--model", "-m", + type=str, + default=None, + help="Đường dẫn đầy đủ tới file model .litertlm" + ) + return parser.parse_args() + +# Parse arguments và chọn model trước khi FastAPI khởi động +args = parse_args() MODELS_DIR.mkdir(exist_ok=True) -MODEL_PATH = select_model() +MODEL_PATH = select_model(args.model) +SERVER_PORT = select_port(args.port) # ── Models ─────────────────────────────────────────────────────────────────── @@ -263,4 +370,9 @@ async def web_ui(): if __name__ == "__main__": import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) + print(f"\n{'='*52}") + print(f" 🚀 Server đang khởi động...") + print(f" 📍 URL: http://localhost:{SERVER_PORT}") + print(f" 📦 Model: {MODEL_PATH.name}") + print(f"{'='*52}\n") + uvicorn.run(app, host="0.0.0.0", port=SERVER_PORT)