CLI update: subcommand must be specified

This commit is contained in:
jhqxxx
2026-04-03 20:43:51 +08:00
parent 279480e3d7
commit 44d91da650
17 changed files with 240 additions and 212 deletions
+3 -2
View File
@@ -47,8 +47,9 @@ aha is a high-performance, cross-platform AI inference engine built with Rust an
## Changelog ## Changelog
### 2026-04-03 ### 2026-04-03
- CLI update: subcommand must be specified
- ChatCompletionParameters add repeat_penalty and repeat_last_n - ChatCompletionParameters add repeat_penalty and repeat_last_n
- generate add penalty repeat code - generate add penalty repeat
### 2026-04-02 ### 2026-04-02
- refactor generate code - refactor generate code
@@ -113,7 +114,7 @@ aha list
aha download -m Qwen/Qwen3-ASR-0.6B aha download -m Qwen/Qwen3-ASR-0.6B
# Download model and start service # Download model and start service
aha -m Qwen/Qwen3-ASR-0.6B aha cli -m Qwen/Qwen3-ASR-0.6B
# Run inference directly (without starting service) # Run inference directly (without starting service)
aha run -m Qwen/Qwen3-ASR-0.6B -i "audio.wav" aha run -m Qwen/Qwen3-ASR-0.6B -i "audio.wav"
+2 -4
View File
@@ -47,6 +47,7 @@ aha 是一款基于 Rust 和 Candle 框架构建的高性能跨平台 AI 推理
## 更新日志 ## 更新日志
## Changelog ## Changelog
### 2026-04-03 ### 2026-04-03
- CLI 更新: 必须指定子命令
- ChatCompletionParameters 新增 repeat_penalty 和 repeat_last_n 参数 - ChatCompletionParameters 新增 repeat_penalty 和 repeat_last_n 参数
- 生成添加重复惩罚代码 - 生成添加重复惩罚代码
@@ -73,9 +74,6 @@ aha 是一款基于 Rust 和 Candle 框架构建的高性能跨平台 AI 推理
- 新增 LFM2.5-1.2B-Instruct - 新增 LFM2.5-1.2B-Instruct
- 新增 LFM2-1.2B - 新增 LFM2-1.2B
### v0.2.3 (2026-03-18)
- 新增 DeepSeek-OCR-2
**[查看完整更新日志](docs/changelog.zh-CN.md)** → **[查看完整更新日志](docs/changelog.zh-CN.md)** →
@@ -116,7 +114,7 @@ aha list
aha download -m Qwen/Qwen3-ASR-0.6B aha download -m Qwen/Qwen3-ASR-0.6B
# 下载模型并启动服务 # 下载模型并启动服务
aha -m Qwen/Qwen3-ASR-0.6B aha cli -m Qwen/Qwen3-ASR-0.6B
# 直接运行推理(无需启动服务) # 直接运行推理(无需启动服务)
aha run -m Qwen/Qwen3-ASR-0.6B -i "audio.wav" aha run -m Qwen/Qwen3-ASR-0.6B -i "audio.wav"
+2 -1
View File
@@ -6,8 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### 2026-04-03 ### 2026-04-03
- CLI update: subcommand must be specified
- ChatCompletionParameters add repeat_penalty and repeat_last_n - ChatCompletionParameters add repeat_penalty and repeat_last_n
- generate add penalty repeat code - generate add penalty repeat
### 2026-04-02 ### 2026-04-02
- refactor generate code - refactor generate code
+1
View File
@@ -6,6 +6,7 @@
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/spec/v2.0.0.html)。 本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/spec/v2.0.0.html)。
### 2026-04-03 ### 2026-04-03
- CLI 更新: 必须指定子命令
- ChatCompletionParameters 新增 repeat_penalty 和 repeat_last_n 参数 - ChatCompletionParameters 新增 repeat_penalty 和 repeat_last_n 参数
- 生成添加重复惩罚代码 - 生成添加重复惩罚代码
+20 -25
View File
@@ -18,16 +18,19 @@ aha [COMMAND] [OPTIONS]
| `--weight-path <WEIGHT_PATH>` | Local model weight path | - | | `--weight-path <WEIGHT_PATH>` | Local model weight path | - |
| `--save-dir <SAVE_DIR>` | Model download save directory | ~/.aha/ | | `--save-dir <SAVE_DIR>` | Model download save directory | ~/.aha/ |
| `--download-retries <DOWNLOAD_RETRIES>` | Download retry count | 3 | | `--download-retries <DOWNLOAD_RETRIES>` | Download retry count | 3 |
| `--gguf-path <GGUF_PATH>` | Local GGUF weight | - | | `--gguf-path <GGUF_PATH>` | Local GGUF weightrequired when using GGUF models | - |
| `--mmproj-path <MMPROJ_PATH>` | Local mmproj GGUF weight | - | | `--mmproj-path <MMPROJ_PATH>` | Local mmproj GGUF weight | - |
| `--onnx-path <ONNX_PATH>` | Local ONNX weightrequired when using ONNX models | - |
| `--config-path <ONNX_PATH>` | extra config path for gguf/onnx | - |
| `-h, --help` | Display help information | - | | `-h, --help` | Display help information | - |
| `-V, --version` | Display version number | - | | `-V, --version` | Display version number | - |
## Commands ## Commands
### cli - Download model and start service (default) ### cli - Download model and start service
Download the specified model and start an HTTP service. This command is used by default when no subcommand is specified. Download the specified model and start an HTTP service.
Download only supports models in safetensors format; for GGUF/ONNX models, you must specify a local file path.
**Syntax:** **Syntax:**
```bash ```bash
@@ -44,8 +47,10 @@ aha cli [OPTIONS] --model <MODEL>
| `--weight-path <WEIGHT_PATH>` | Local model weight path (skip download if specified) | - | | `--weight-path <WEIGHT_PATH>` | Local model weight path (skip download if specified) | - |
| `--save-dir <SAVE_DIR>` | Model download save directory | ~/.aha/ | | `--save-dir <SAVE_DIR>` | Model download save directory | ~/.aha/ |
| `--download-retries <DOWNLOAD_RETRIES>` | Download retry count | 3 | | `--download-retries <DOWNLOAD_RETRIES>` | Download retry count | 3 |
| `--gguf-path <GGUF_PATH>` | Local GGUF weight | - | | `--gguf-path <GGUF_PATH>` | Local GGUF weightrequired when using GGUF models | - |
| `--mmproj-path <MMPROJ_PATH>` | Local mmproj GGUF weight | - | | `--mmproj-path <MMPROJ_PATH>` | Local mmproj GGUF weight | - |
| `--onnx-path <ONNX_PATH>` | Local ONNX weightrequired when using ONNX models | - |
| `--config-path <ONNX_PATH>` | extra config path for gguf/onnx | - |
**Examples:** **Examples:**
@@ -59,9 +64,6 @@ aha cli -m Qwen/Qwen3-VL-2B-Instruct -p 8080 --save-dir /data/models
# Use local model (skip download) # Use local model (skip download)
aha cli -m Qwen/Qwen3-VL-2B-Instruct --weight-path /path/to/model aha cli -m Qwen/Qwen3-VL-2B-Instruct --weight-path /path/to/model
# Backward compatible way (equivalent to cli subcommand)
aha -m Qwen/Qwen3-VL-2B-Instruct
# use gguf-path and mmproj-path # use gguf-path and mmproj-path
aha cli -m qwen3.5-gguf --gguf-path /path/to/xxx.gguf --mmproj-path /path/to/mmproj-xxx.gguf aha cli -m qwen3.5-gguf --gguf-path /path/to/xxx.gguf --mmproj-path /path/to/mmproj-xxx.gguf
``` ```
@@ -72,7 +74,7 @@ Run model inference directly without starting an HTTP service. Suitable for one-
**Syntax:** **Syntax:**
```bash ```bash
aha run [OPTIONS] --model <MODEL> --input <INPUT> [--input <INPUT2>] [--weight-path <WEIGHT_PATH>] [--gguf-path <GGUF_PATH>] [--mmproj-path <MMPROJ_PATH>] aha run [OPTIONS] --model <MODEL> --input <INPUT> [--input <INPUT2>] [--weight-path <WEIGHT_PATH>] [--gguf-path <GGUF_PATH>] [--mmproj-path <MMPROJ_PATH>] [--onnx-path <ONNX_PATH>] [--config-path <CONFIG_PATH>]
``` ```
**Options:** **Options:**
@@ -82,9 +84,12 @@ aha run [OPTIONS] --model <MODEL> --input <INPUT> [--input <INPUT2>] [--weight-p
| `-m, --model <MODEL>` | Model type (required) | - | | `-m, --model <MODEL>` | Model type (required) | - |
| `-i, --input <INPUT>` | Input text or file path (model-specific interpretation, supports 1-2 parameters: input1: prompt text, input2: file path) | - | | `-i, --input <INPUT>` | Input text or file path (model-specific interpretation, supports 1-2 parameters: input1: prompt text, input2: file path) | - |
| `-o, --output <OUTPUT>` | Output file path (optional, auto-generated if not specified) | - | | `-o, --output <OUTPUT>` | Output file path (optional, auto-generated if not specified) | - |
| `--weight-path <WEIGHT_PATH>` | Local model weight path (required when using non-GGUF models) | - | | `--weight-path <WEIGHT_PATH>` | Local model weight path (required when using safetensors models) | - |
| `--gguf-path <GGUF_PATH>` | Local GGUF model weight pathrequired when using GGUF models | - | | `--gguf-path <GGUF_PATH>` | Local GGUF model weight pathrequired when using GGUF models | - |
| `--mmproj-path <MMPROJ_PATH>` | Local mmproj GGUF weight pathoptionalIf not specified, the module will not be loaded | - | | `--mmproj-path <MMPROJ_PATH>` | Local mmproj GGUF weight pathoptionalIf not specified, the module will not be loaded | - |
| `--onnx-path <ONNX_PATH>` | Local ONNX weightrequired when using ONNX models | - |
| `--config-path <ONNX_PATH>` | extra config path for gguf/onnx | - |
**Examples:** **Examples:**
```bash ```bash
@@ -129,11 +134,13 @@ aha run -m qwen3.5-gguf -i 提取图片中的文本 -i https://ai.bdstatic.com/f
### serv - Start service ### serv - Start service
Start HTTP service with a model. The `--weight-path` is optional - if not specified, it defaults to `~/.aha/{model_id}`. Start HTTP service with a model.
Safetensors model: The `--weight-path` is optional - if not specified, it defaults to `~/.aha/{model_id}`.
GGUF/ONNX model: The `--gguf-path`/ `--onnx-path` must be specified
**Syntax:** **Syntax:**
```bash ```bash
aha serv [OPTIONS] --model <MODEL> [--weight-path <WEIGHT_PATH>] [--gguf-path <GGUF_PATH>] [--mmproj-path <MMPROJ_PATH>] aha serv [OPTIONS] --model <MODEL> [--weight-path <WEIGHT_PATH>] [--gguf-path <GGUF_PATH>] [--mmproj-path <MMPROJ_PATH>] [--onnx-path <ONNX_PATH>] [--config-path <CONFIG_PATH>]
``` ```
**Options:** **Options:**
@@ -336,7 +343,7 @@ Example:
```bash ```bash
# One command to download and start service # One command to download and start service
aha -m Qwen/Qwen3-VL-2B-Instruct aha cli -m Qwen/Qwen3-VL-2B-Instruct
``` ```
### Scenario 2: Start service with existing model ### Scenario 2: Start service with existing model
@@ -360,7 +367,7 @@ aha serv -m Qwen/Qwen3-VL-2B-Instruct --weight-path /data/models/Qwen/Qwen3-VL-2
```bash ```bash
# Start service on 0.0.0.0:8080, allow external access # Start service on 0.0.0.0:8080, allow external access
aha -m Qwen/Qwen3-VL-2B-Instruct -a 0.0.0.0 -p 8080 aha cli -m Qwen/Qwen3-VL-2B-Instruct -a 0.0.0.0 -p 8080
``` ```
## API Endpoints ## API Endpoints
@@ -395,18 +402,6 @@ After the service starts, the following API endpoints are available:
- **Format**: JSON response - **Format**: JSON response
## Backward Compatibility
To maintain compatibility with older versions, the following two usage methods are equivalent:
```bash
# New way (recommended)
aha cli -m Qwen/Qwen3-VL-2B-Instruct
# Old way (backward compatible)
aha -m Qwen/Qwen3-VL-2B-Instruct
```
## Notes ## Notes
1. **serv subcommand requires `--weight-path`**: Since the `serv` subcommand does not download models, you must specify the path to an already downloaded model via `--weight-path`. 1. **serv subcommand requires `--weight-path`**: Since the `serv` subcommand does not download models, you must specify the path to an already downloaded model via `--weight-path`.
+24 -27
View File
@@ -15,19 +15,22 @@ aha [COMMAND] [OPTIONS]
| `-a, --address <ADDRESS>` | 服务监听地址 | 127.0.0.1 | | `-a, --address <ADDRESS>` | 服务监听地址 | 127.0.0.1 |
| `-p, --port <PORT>` | 服务监听端口 | 10100 | | `-p, --port <PORT>` | 服务监听端口 | 10100 |
| `-m, --model <MODEL>` | 模型类型(必选) | - | | `-m, --model <MODEL>` | 模型类型(必选) | - |
| `--weight-path <WEIGHT_PATH>` | 本地模型权重路径 | - | | `--weight-path <WEIGHT_PATH>` | 本地safetensors模型权重路径 | - |
| `--save-dir <SAVE_DIR>` | 模型下载保存目录 | ~/.aha/ | | `--save-dir <SAVE_DIR>` | 模型下载保存目录 | ~/.aha/ |
| `--download-retries <DOWNLOAD_RETRIES>` | 下载重试次数 | 3 | | `--download-retries <DOWNLOAD_RETRIES>` | 下载重试次数 | 3 |
| `--gguf-path <GGUF_PATH>` | 本地 GGUF 模型权重 | - | | `--gguf-path <GGUF_PATH>` | 本地 GGUF 模型权重(使用GGUF模型时必选) | - |
| `--mmproj-path <MMPROJ_PATH>` | 本地 mmproj GGUF 模型权重 | - | | `--mmproj-path <MMPROJ_PATH>` | 本地 mmproj GGUF 模型权重(可选,未指定则不加载该模块) | - |
| `--onnx-path <ONNX_PATH>` | 本地 ONNX 模型权重 (使用ONNX模型时必选) | - |
| `--config-path <ONNX_PATH>` | GGUF/ONNX 需要的额外配置路径(可选) | - |
| `-h, --help` | 显示帮助信息 | - | | `-h, --help` | 显示帮助信息 | - |
| `-V, --version` | 显示版本号 | - | | `-V, --version` | 显示版本号 | - |
## 子命令 ## 子命令
### cli - 下载模型并启动服务(默认) ### cli - 下载模型并启动服务
下载指定的模型并启动 HTTP 服务。当不指定子命令时,默认使用此命令。 下载指定的模型并启动 HTTP 服务。
下载仅支持safetensors格式模型, GGUF/ONNX模型必须指定本地文件路径
**语法:** **语法:**
```bash ```bash
@@ -41,11 +44,13 @@ aha cli [OPTIONS] --model <MODEL>
| `-a, --address <ADDRESS>` | 服务监听地址 | 127.0.0.1 | | `-a, --address <ADDRESS>` | 服务监听地址 | 127.0.0.1 |
| `-p, --port <PORT>` | 服务监听端口 | 10100 | | `-p, --port <PORT>` | 服务监听端口 | 10100 |
| `-m, --model <MODEL>` | 模型类型(必选) | - | | `-m, --model <MODEL>` | 模型类型(必选) | - |
| `--weight-path <WEIGHT_PATH>` | 本地模型权重路径(如指定则跳过下载) | - | | `--weight-path <WEIGHT_PATH>` | 本地safetensors模型权重路径(如指定则跳过下载) | - |
| `--save-dir <SAVE_DIR>` | 模型下载保存目录 | ~/.aha/ | | `--save-dir <SAVE_DIR>` | 模型下载保存目录 | ~/.aha/ |
| `--download-retries <DOWNLOAD_RETRIES>` | 下载重试次数 | 3 | | `--download-retries <DOWNLOAD_RETRIES>` | 下载重试次数 | 3 |
| `--gguf-path <GGUF_PATH>` | 本地 GGUF 模型权重 | - | | `--gguf-path <GGUF_PATH>` | 本地 GGUF 模型权重(使用GGUF模型时必选) | - |
| `--mmproj-path <MMPROJ_PATH>` | 本地 mmproj GGUF 模型权重 | - | | `--mmproj-path <MMPROJ_PATH>` | 本地 mmproj GGUF 模型权重(可选,未指定则不加载该模块) | - |
| `--onnx-path <ONNX_PATH>` | 本地 ONNX 模型权重 (使用ONNX模型时必选) | - |
| `--config-path <ONNX_PATH>` | GGUF/ONNX 需要的额外配置路径(可选) | - |
**示例:** **示例:**
@@ -59,9 +64,6 @@ aha cli -m Qwen/Qwen3-VL-2B-Instruct -p 8080 --save-dir /data/models
# 使用本地模型(不下载) # 使用本地模型(不下载)
aha cli -m Qwen/Qwen3-VL-2B-Instruct --weight-path /path/to/model aha cli -m Qwen/Qwen3-VL-2B-Instruct --weight-path /path/to/model
# 向后兼容方式(等同于 cli 子命令)
aha -m Qwen/Qwen3-VL-2B-Instruct
# 指定gguf-path和mmproj-path # 指定gguf-path和mmproj-path
aha cli -m qwen3.5-gguf --gguf-path /path/to/xxx.gguf --mmproj-path /path/to/mmproj-xxx.gguf aha cli -m qwen3.5-gguf --gguf-path /path/to/xxx.gguf --mmproj-path /path/to/mmproj-xxx.gguf
``` ```
@@ -72,7 +74,7 @@ aha cli -m qwen3.5-gguf --gguf-path /path/to/xxx.gguf --mmproj-path /path/to/mmp
**语法:** **语法:**
```bash ```bash
aha run [OPTIONS] --model <MODEL> --input <INPUT> [--input <INPUT2>] [--weight-path <WEIGHT_PATH>] [--gguf-path <GGUF_PATH>] [--mmproj-path <MMPROJ_PATH>] aha run [OPTIONS] --model <MODEL> --input <INPUT> [--input <INPUT2>] [--weight-path <WEIGHT_PATH>] [--gguf-path <GGUF_PATH>] [--mmproj-path <MMPROJ_PATH>] [--onnx-path <ONNX_PATH>] [--config-path <CONFIG_PATH>]
``` ```
**选项:** **选项:**
@@ -82,9 +84,11 @@ aha run [OPTIONS] --model <MODEL> --input <INPUT> [--input <INPUT2>] [--weight-p
| `-m, --model <MODEL>` | 模型类型(必选) | - | | `-m, --model <MODEL>` | 模型类型(必选) | - |
| `-i, --input <INPUT>` | 输入文本或文件路径(模型特定解释,支持1-2个参数, input1: 提示文本, input2: 文件地址) | - | | `-i, --input <INPUT>` | 输入文本或文件路径(模型特定解释,支持1-2个参数, input1: 提示文本, input2: 文件地址) | - |
| `-o, --output <OUTPUT>` | 输出文件路径(可选,未指定则自动生成) | - | | `-o, --output <OUTPUT>` | 输出文件路径(可选,未指定则自动生成) | - |
| `--weight-path <WEIGHT_PATH>` | 本地模型权重路径(使用非GGUF模型时必选) | - | | `--weight-path <WEIGHT_PATH>` | 本地模型权重路径(使用Safetensors模型时必选) | - |
| `--gguf-path <GGUF_PATH>` | 本地GGUF模型权重路径(使用GGUF模型时必选) | - | | `--gguf-path <GGUF_PATH>` | 本地GGUF模型权重路径(使用GGUF模型时必选) | - |
| `--mmproj-path <MMPROJ_PATH>` | 本地mmproj GGUF模型权重路径(可选,未指定则不加载该模块) | - | | `--mmproj-path <MMPROJ_PATH>` | 本地mmproj GGUF模型权重路径(可选,未指定则不加载该模块) | - |
| `--onnx-path <ONNX_PATH>` | 本地 ONNX 模型权重 (使用ONNX模型时必选) | - |
| `--config-path <ONNX_PATH>` | GGUF/ONNX 需要的额外配置路径(可选) | - |
**示例:** **示例:**
@@ -129,7 +133,9 @@ aha run -m qwen3.5-gguf -i 提取图片中的文本 -i https://ai.bdstatic.com/f
### serv - 启动服务 ### serv - 启动服务
使用指定模型启动 HTTP 服务。`--weight-path` 是可选的 - 如果不指定,默认使用 `~/.aha/{model_id}` 使用指定模型启动 HTTP 服务。
safetensors模型`--weight-path` 是可选的 - 如果不指定,默认使用 `~/.aha/{model_id}`
GGUF/ONNX模型必须指定本地文件路径
**语法:** **语法:**
```bash ```bash
@@ -147,6 +153,8 @@ aha serv [OPTIONS] --model <MODEL> [--weight-path <WEIGHT_PATH>] [--gguf-path <G
| `--allow-remote-shutdown` | 允许远程关机请求(不推荐) | false | | `--allow-remote-shutdown` | 允许远程关机请求(不推荐) | false |
| `--gguf-path <GGUF_PATH>` | 本地GGUF模型权重路径(使用GGUF模型时必选) | - | | `--gguf-path <GGUF_PATH>` | 本地GGUF模型权重路径(使用GGUF模型时必选) | - |
| `--mmproj-path <MMPROJ_PATH>` | 本地mmproj GGUF模型权重路径(可选,未指定则不加载该模块) | - | | `--mmproj-path <MMPROJ_PATH>` | 本地mmproj GGUF模型权重路径(可选,未指定则不加载该模块) | - |
| `--onnx-path <ONNX_PATH>` | 本地 ONNX 模型权重 (使用ONNX模型时必选) | - |
| `--config-path <ONNX_PATH>` | GGUF/ONNX 需要的额外配置路径(可选) | - |
**示例:** **示例:**
@@ -336,7 +344,7 @@ aha list -j
```bash ```bash
# 一条命令下载并启动服务 # 一条命令下载并启动服务
aha -m Qwen/Qwen3-VL-2B-Instruct aha cli -m Qwen/Qwen3-VL-2B-Instruct
``` ```
### 场景 2:使用已有模型启动服务 ### 场景 2:使用已有模型启动服务
@@ -360,7 +368,7 @@ aha serv -m Qwen/Qwen3-VL-2B-Instruct --weight-path /data/models/Qwen/Qwen3-VL-2
```bash ```bash
# 在 0.0.0.0:8080 启动服务,允许外部访问 # 在 0.0.0.0:8080 启动服务,允许外部访问
aha -m Qwen/Qwen3-VL-2B-Instruct -a 0.0.0.0 -p 8080 aha cli -m Qwen/Qwen3-VL-2B-Instruct -a 0.0.0.0 -p 8080
``` ```
## API 接口 ## API 接口
@@ -394,17 +402,6 @@ aha -m Qwen/Qwen3-VL-2B-Instruct -a 0.0.0.0 -p 8080
- **安全性**: 默认仅允许本地访问,使用 `--allow-remote-shutdown` 标志启用远程访问(不推荐) - **安全性**: 默认仅允许本地访问,使用 `--allow-remote-shutdown` 标志启用远程访问(不推荐)
- **格式**: JSON 响应 - **格式**: JSON 响应
## 向后兼容性
为了保持与旧版本的兼容性,以下两种使用方式是等效的:
```bash
# 新方式(推荐)
aha cli -m Qwen/Qwen3-VL-2B-Instruct
# 旧方式(向后兼容)
aha -m Qwen/Qwen3-VL-2B-Instruct
```
## 注意事项 ## 注意事项
+2 -1
View File
@@ -291,7 +291,8 @@ OpenBMB/MiniCPM4-0.5B OpenBMB llm ✔
Qwen/Qwen2.5-VL-3B-Instruct Qwen vlm ✔ Qwen/Qwen2.5-VL-3B-Instruct Qwen vlm ✔
Qwen/Qwen2.5-VL-7B-Instruct Qwen vlm Qwen/Qwen2.5-VL-7B-Instruct Qwen vlm
Qwen/Qwen3-0.6B Qwen llm ✔ Qwen/Qwen3-0.6B Qwen llm ✔
Qwen/Qwen3-1.7B Qwen llm Qwen/Qwen3-1.7B Qwen llm
Qwen/Qwen3-4B Qwen llm
Qwen/Qwen3.5-0.8B Qwen vlm ✔ Qwen/Qwen3.5-0.8B Qwen vlm ✔
Qwen/Qwen3.5-2B Qwen vlm Qwen/Qwen3.5-2B Qwen vlm
Qwen/Qwen3.5-4B Qwen vlm Qwen/Qwen3.5-4B Qwen vlm
+2 -1
View File
@@ -291,7 +291,8 @@ OpenBMB/MiniCPM4-0.5B OpenBMB llm ✔
Qwen/Qwen2.5-VL-3B-Instruct Qwen vlm ✔ Qwen/Qwen2.5-VL-3B-Instruct Qwen vlm ✔
Qwen/Qwen2.5-VL-7B-Instruct Qwen vlm Qwen/Qwen2.5-VL-7B-Instruct Qwen vlm
Qwen/Qwen3-0.6B Qwen llm ✔ Qwen/Qwen3-0.6B Qwen llm ✔
Qwen/Qwen3-1.7B Qwen llm Qwen/Qwen3-1.7B Qwen llm
Qwen/Qwen3-4B Qwen llm
Qwen/Qwen3.5-0.8B Qwen vlm ✔ Qwen/Qwen3.5-0.8B Qwen vlm ✔
Qwen/Qwen3.5-2B Qwen vlm Qwen/Qwen3.5-2B Qwen vlm
Qwen/Qwen3.5-4B Qwen vlm Qwen/Qwen3.5-4B Qwen vlm
+3 -2
View File
@@ -15,7 +15,8 @@ OpenBMB/MiniCPM4-0.5B OpenBMB llm ✔
Qwen/Qwen2.5-VL-3B-Instruct Qwen vlm ✔ Qwen/Qwen2.5-VL-3B-Instruct Qwen vlm ✔
Qwen/Qwen2.5-VL-7B-Instruct Qwen vlm Qwen/Qwen2.5-VL-7B-Instruct Qwen vlm
Qwen/Qwen3-0.6B Qwen llm ✔ Qwen/Qwen3-0.6B Qwen llm ✔
Qwen/Qwen3-1.7B Qwen llm Qwen/Qwen3-1.7B Qwen llm
Qwen/Qwen3-4B Qwen llm
Qwen/Qwen3.5-0.8B Qwen vlm ✔ Qwen/Qwen3.5-0.8B Qwen vlm ✔
Qwen/Qwen3.5-2B Qwen vlm Qwen/Qwen3.5-2B Qwen vlm
Qwen/Qwen3.5-4B Qwen vlm Qwen/Qwen3.5-4B Qwen vlm
@@ -44,7 +45,7 @@ ZhipuAI/GLM-OCR ZhipuAI ocr ✔
| Model | Parameters | Model Id | License | | Model | Parameters | Model Id | License |
|-------|-----------|--------|---------| |-------|-----------|--------|---------|
| **Qwen3-0.6B** | 0.6B | Qwen/Qwen3-0.6B <br> Qwen/Qwen3-1.7B | [Apache 2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) | | **Qwen3-0.6B** | 0.6B | Qwen/Qwen3-0.6B <br> Qwen/Qwen3-1.7B <br> Qwen/Qwen3-4B | [Apache 2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) |
| **MiniCPM4-0.5B** | 0.5B | OpenBMB/MiniCPM4-0.5B | [Apache 2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) | | **MiniCPM4-0.5B** | 0.5B | OpenBMB/MiniCPM4-0.5B | [Apache 2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) |
| **LFM2-1.2B** | 1.2B | LiquidAI/LFM2-1.2B | [lfm1.0](https://huggingface.co/LiquidAI/LFM2-1.2B/blob/main/LICENSE) | | **LFM2-1.2B** | 1.2B | LiquidAI/LFM2-1.2B | [lfm1.0](https://huggingface.co/LiquidAI/LFM2-1.2B/blob/main/LICENSE) |
| **LFM2.5-1.2B-Instruct** | 1.2B | LiquidAI/LFM2.5-1.2B-Instruct | [lfm1.0](https://huggingface.co/LiquidAI/LFM2.5-1.2B-Instruct/blob/main/LICENSE) | | **LFM2.5-1.2B-Instruct** | 1.2B | LiquidAI/LFM2.5-1.2B-Instruct | [lfm1.0](https://huggingface.co/LiquidAI/LFM2.5-1.2B-Instruct/blob/main/LICENSE) |
+3 -2
View File
@@ -15,7 +15,8 @@ OpenBMB/MiniCPM4-0.5B OpenBMB llm ✔
Qwen/Qwen2.5-VL-3B-Instruct Qwen vlm ✔ Qwen/Qwen2.5-VL-3B-Instruct Qwen vlm ✔
Qwen/Qwen2.5-VL-7B-Instruct Qwen vlm Qwen/Qwen2.5-VL-7B-Instruct Qwen vlm
Qwen/Qwen3-0.6B Qwen llm ✔ Qwen/Qwen3-0.6B Qwen llm ✔
Qwen/Qwen3-1.7B Qwen llm Qwen/Qwen3-1.7B Qwen llm
Qwen/Qwen3-4B Qwen llm
Qwen/Qwen3.5-0.8B Qwen vlm ✔ Qwen/Qwen3.5-0.8B Qwen vlm ✔
Qwen/Qwen3.5-2B Qwen vlm Qwen/Qwen3.5-2B Qwen vlm
Qwen/Qwen3.5-4B Qwen vlm Qwen/Qwen3.5-4B Qwen vlm
@@ -44,7 +45,7 @@ ZhipuAI/GLM-OCR ZhipuAI ocr ✔
| 模型 | 参数量 | 模型id | 开源协议 | | 模型 | 参数量 | 模型id | 开源协议 |
|------|--------|------|---------| |------|--------|------|---------|
| **Qwen3-0.6B** | 0.6B | Qwen/Qwen3-0.6B <br> Qwen/Qwen3-1.7B | [Apache 2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) | | **Qwen3-0.6B** | 0.6B | Qwen/Qwen3-0.6B <br> Qwen/Qwen3-1.7B <br> Qwen/Qwen3-4B | [Apache 2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) |
| **MiniCPM4-0.5B** | 0.5B | OpenBMB/MiniCPM4-0.5B | [Apache 2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) | | **MiniCPM4-0.5B** | 0.5B | OpenBMB/MiniCPM4-0.5B | [Apache 2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) |
| **LFM2-1.2B** | 1.2B | LiquidAI/LFM2-1.2B | [lfm1.0](https://huggingface.co/LiquidAI/LFM2-1.2B/blob/main/LICENSE) | | **LFM2-1.2B** | 1.2B | LiquidAI/LFM2-1.2B | [lfm1.0](https://huggingface.co/LiquidAI/LFM2-1.2B/blob/main/LICENSE) |
| **LFM2.5-1.2B-Instruct** | 1.2B | LiquidAI/LFM2.5-1.2B-Instruct | [lfm1.0](https://huggingface.co/LiquidAI/LFM2.5-1.2B-Instruct/blob/main/LICENSE) | | **LFM2.5-1.2B-Instruct** | 1.2B | LiquidAI/LFM2.5-1.2B-Instruct | [lfm1.0](https://huggingface.co/LiquidAI/LFM2.5-1.2B-Instruct/blob/main/LICENSE) |
+40 -73
View File
@@ -5,40 +5,8 @@ use clap::{Args, Parser, Subcommand};
#[command(name = "aha")] #[command(name = "aha")]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
pub(crate) struct Cli { pub(crate) struct Cli {
/// Service listen address
#[arg(short, long, default_value = "127.0.0.1")]
pub address: Option<String>,
/// Service listen port
#[arg(short, long)]
pub port: Option<u16>,
/// Model type (required for backward compatibility)
#[arg(short, long)]
pub model: Option<WhichModel>,
/// Local model weight path
#[arg(long)]
pub weight_path: Option<String>,
/// Model download save directory
#[arg(long)]
pub save_dir: Option<String>,
/// Download retry count
#[arg(long)]
pub download_retries: Option<u32>,
/// Local GGUF model weight path (required for loading models with GGUF).
#[arg(long)]
pub gguf_path: Option<String>,
/// Local path for mmproj GGUF model weights (required for loading with multimodel GGUF)
#[arg(long)]
pub mmproj_path: Option<String>,
#[command(subcommand)] #[command(subcommand)]
pub command: Option<Commands>, pub command: Commands,
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
@@ -61,7 +29,7 @@ pub(crate) enum Commands {
/// Common/shared arguments for server operations /// Common/shared arguments for server operations
#[derive(Args, Debug)] #[derive(Args, Debug)]
pub(crate) struct CommonArgs { pub(crate) struct ServerCommonArgs {
/// Service listen address /// Service listen address
#[arg(short, long, default_value = "127.0.0.1")] #[arg(short, long, default_value = "127.0.0.1")]
pub address: String, pub address: String,
@@ -70,24 +38,42 @@ pub(crate) struct CommonArgs {
#[arg(short, long, default_value_t = 10100)] #[arg(short, long, default_value_t = 10100)]
pub port: u16, pub port: u16,
/// Model type (required)
#[arg(short, long)]
pub model: WhichModel,
/// Allow remote shutdown requests (default: local only, use with caution) /// Allow remote shutdown requests (default: local only, use with caution)
#[arg(long)] #[arg(long)]
pub allow_remote_shutdown: bool, pub allow_remote_shutdown: bool,
} }
/// Arguments for the 'cli' subcommand (download + serve)
#[derive(Args, Debug)] #[derive(Args, Debug)]
pub(crate) struct CliArgs { pub(crate) struct PathCommonArgs {
#[command(flatten)]
pub common: CommonArgs,
/// Local model weight path (skip download if provided) /// Local model weight path (skip download if provided)
#[arg(long)] #[arg(long)]
pub weight_path: Option<String>, pub weight_path: Option<String>,
/// Local GGUF model weight path (required for loading models with GGUF).
#[arg(long)]
pub gguf_path: Option<String>,
/// Local path for mmproj GGUF model weights (required for loading with multimodel GGUF)
#[arg(long)]
pub mmproj_path: Option<String>,
/// Local path for onnx model weights (required for loading with onnx)
#[arg(long)]
pub onnx_path: Option<String>,
/// config path for onnx/gguf model need extra config file
#[arg(long)]
pub config_path: Option<String>,
}
/// Arguments for the 'cli' subcommand (download + serve)
#[derive(Args, Debug)]
pub(crate) struct CliArgs {
/// Model type (required)
#[arg(short, long)]
pub model: WhichModel,
#[command(flatten)]
pub server_common: ServerCommonArgs,
/// Model download save directory /// Model download save directory
#[arg(long)] #[arg(long)]
@@ -97,32 +83,22 @@ pub(crate) struct CliArgs {
#[arg(long)] #[arg(long)]
pub download_retries: Option<u32>, pub download_retries: Option<u32>,
/// Local GGUF model weight path (required for loading models with GGUF). #[command(flatten)]
#[arg(long)] pub path_common: PathCommonArgs,
pub gguf_path: Option<String>,
/// Local path for mmproj GGUF model weights (required for loading with multimodel GGUF)
#[arg(long)]
pub mmproj_path: Option<String>,
} }
/// Arguments for the 'serv start' subcommand /// Arguments for the 'serv start' subcommand
#[derive(Args, Debug)] #[derive(Args, Debug)]
pub(crate) struct ServArgs { pub(crate) struct ServArgs {
/// Model type (required)
#[arg(short, long)]
pub model: WhichModel,
#[command(flatten)] #[command(flatten)]
pub common: CommonArgs, pub server_common: ServerCommonArgs,
/// Local model weight path (defaults to ~/.aha/{model_id} if not specified) #[command(flatten)]
#[arg(long)] pub path_common: PathCommonArgs,
pub weight_path: Option<String>,
/// Local GGUF model weight path (required for loading models with GGUF).
#[arg(long)]
pub gguf_path: Option<String>,
/// Local path for mmproj GGUF model weights (required for loading with multimodel GGUF)
#[arg(long)]
pub mmproj_path: Option<String>,
} }
/// Arguments for the 'serv list' subcommand /// Arguments for the 'serv list' subcommand
@@ -164,17 +140,8 @@ pub(crate) struct RunArgs {
#[arg(short, long)] #[arg(short, long)]
pub output: Option<String>, pub output: Option<String>,
/// Local model weight path (defaults to ~/.aha/{model_id} if not specified) #[command(flatten)]
#[arg(long)] pub path_common: PathCommonArgs,
pub weight_path: Option<String>,
/// Local GGUF model weight path (required for loading models with GGUF).
#[arg(long)]
pub gguf_path: Option<String>,
/// Local path for mmproj GGUF model weights (required for loading with multimodel GGUF)
#[arg(long)]
pub mmproj_path: Option<String>,
} }
/// Arguments for the 'delete' subcommand (delete model from default location) /// Arguments for the 'delete' subcommand (delete model from default location)
+58 -28
View File
@@ -76,22 +76,27 @@ pub(crate) fn run_list(args: ListArgs) -> anyhow::Result<()> {
/// Run the 'cli' subcommand: download model (if needed) and start service /// Run the 'cli' subcommand: download model (if needed) and start service
pub(crate) async fn run_cli(args: CliArgs) -> anyhow::Result<()> { pub(crate) async fn run_cli(args: CliArgs) -> anyhow::Result<()> {
let CliArgs { let CliArgs {
common, model,
weight_path, server_common,
save_dir, save_dir,
download_retries, download_retries,
gguf_path, path_common,
mmproj_path,
} = args; } = args;
let model_id = common.model.as_string(); let model_id = model.as_string();
let (model_path, gguf, mmproj) = if model_id.contains("gguf") { let (model_path, gguf, mmproj) = if model.is_gguf() {
if gguf_path.is_none() { if path_common.gguf_path.is_none() {
return Err(anyhow!("gguf model path is required")); return Err(anyhow!("gguf model path is required"));
} }
("GGUF".to_string(), gguf_path, mmproj_path) (
"GGUF".to_string(),
path_common.gguf_path,
path_common.mmproj_path,
)
} else if model.is_onnx() {
return Err(anyhow!("onnx model not support now"));
} else { } else {
let model_path = match weight_path { let model_path = match path_common.weight_path {
Some(path) => path, Some(path) => path,
None => { None => {
let save_dir = match save_dir { let save_dir = match save_dir {
@@ -106,8 +111,13 @@ pub(crate) async fn run_cli(args: CliArgs) -> anyhow::Result<()> {
(model_path, None, None) (model_path, None, None)
}; };
init(common.model, model_path, gguf, mmproj)?; init(model, model_path, gguf, mmproj)?;
start_http_server(common.address, common.port, common.allow_remote_shutdown).await?; start_http_server(
server_common.address,
server_common.port,
server_common.allow_remote_shutdown,
)
.await?;
Ok(()) Ok(())
} }
@@ -115,27 +125,41 @@ pub(crate) async fn run_cli(args: CliArgs) -> anyhow::Result<()> {
/// Run the 'serv' subcommand: start service only (no download) /// Run the 'serv' subcommand: start service only (no download)
pub(crate) async fn run_serv(args: ServArgs) -> anyhow::Result<()> { pub(crate) async fn run_serv(args: ServArgs) -> anyhow::Result<()> {
let ServArgs { let ServArgs {
common, model,
weight_path, server_common,
gguf_path, path_common,
mmproj_path,
} = args; } = args;
let model_id = common.model.as_string(); let (model_path, gguf, mmproj) = if model.is_gguf() {
let (model_path, gguf, mmproj) = if model_id.contains("gguf") { if path_common.gguf_path.is_none() {
if gguf_path.is_none() {
return Err(anyhow!("gguf model path is required")); return Err(anyhow!("gguf model path is required"));
} }
("GGUF".to_string(), gguf_path, mmproj_path) (
"GGUF".to_string(),
path_common.gguf_path,
path_common.mmproj_path,
)
} else if model.is_onnx() {
return Err(anyhow!("onnx model not support now"));
} else { } else {
let model_path = match weight_path { let model_path = match path_common.weight_path {
Some(path) => path, Some(path) => path,
None => get_default_weight_path(common.model), None => get_default_weight_path(model),
}; };
if !std::path::Path::new(&model_path).exists() {
return Err(anyhow!(
"serv subcommand will not download model, use `weight-path` to pass the model path"
));
}
(model_path, None, None) (model_path, None, None)
}; };
init(common.model, model_path, gguf, mmproj)?; init(model, model_path, gguf, mmproj)?;
start_http_server(common.address, common.port, common.allow_remote_shutdown).await?; start_http_server(
server_common.address,
server_common.port,
server_common.allow_remote_shutdown,
)
.await?;
Ok(()) Ok(())
} }
@@ -205,13 +229,11 @@ pub(crate) fn run_run(args: RunArgs) -> anyhow::Result<()> {
model, model,
input, input,
output, output,
weight_path, path_common,
gguf_path,
mmproj_path,
} = args; } = args;
// Use default weight path if not specified // Use default weight path if not specified
let weight_path = match weight_path { let weight_path = match path_common.weight_path {
Some(path) => path, Some(path) => path,
None => get_default_weight_path(model), None => get_default_weight_path(model),
}; };
@@ -243,6 +265,9 @@ pub(crate) fn run_run(args: RunArgs) -> anyhow::Result<()> {
WhichModel::Qwen3_1_7B => { WhichModel::Qwen3_1_7B => {
qwen3::Qwen3Exec::run(&input, output.as_deref(), &weight_path)?; qwen3::Qwen3Exec::run(&input, output.as_deref(), &weight_path)?;
} }
WhichModel::Qwen3_4B => {
qwen3::Qwen3Exec::run(&input, output.as_deref(), &weight_path)?;
}
WhichModel::Qwen3_5_0_8B => { WhichModel::Qwen3_5_0_8B => {
qwen3_5::Qwen3_5Exec::run(&input, output.as_deref(), &weight_path)?; qwen3_5::Qwen3_5Exec::run(&input, output.as_deref(), &weight_path)?;
} }
@@ -256,7 +281,12 @@ pub(crate) fn run_run(args: RunArgs) -> anyhow::Result<()> {
qwen3_5::Qwen3_5Exec::run(&input, output.as_deref(), &weight_path)?; qwen3_5::Qwen3_5Exec::run(&input, output.as_deref(), &weight_path)?;
} }
WhichModel::Qwen3_5Gguf => { WhichModel::Qwen3_5Gguf => {
qwen3_5::Qwen3_5Exec::run_gguf(&input, output.as_deref(), gguf_path, mmproj_path)?; qwen3_5::Qwen3_5Exec::run_gguf(
&input,
output.as_deref(),
path_common.gguf_path,
path_common.mmproj_path,
)?;
} }
WhichModel::Qwen3ASR0_6B => { WhichModel::Qwen3ASR0_6B => {
qwen3_asr::Qwen3ASRExec::run(&input, output.as_deref(), &weight_path)?; qwen3_asr::Qwen3ASRExec::run(&input, output.as_deref(), &weight_path)?;
+8 -27
View File
@@ -1,7 +1,7 @@
use clap::Parser; use clap::Parser;
use crate::cli::{ use crate::cli::{
args::{Cli, CliArgs, Commands, CommonArgs}, args::{Cli, Commands},
run_cli, run_delete, run_download, run_list, run_ps, run_run, run_serv, run_cli, run_delete, run_download, run_list, run_ps, run_run, run_serv,
}; };
@@ -11,32 +11,13 @@ mod server;
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
let cli = Cli::parse(); let cli = Cli::parse();
match cli.command { match cli.command {
Some(Commands::Cli(args)) => run_cli(args).await, Commands::Cli(args) => run_cli(args).await,
Some(Commands::Serv(args)) => run_serv(args).await, Commands::Serv(args) => run_serv(args).await,
Some(Commands::Ps(args)) => run_ps(args), Commands::Ps(args) => run_ps(args),
Some(Commands::Delete(args)) => run_delete(args), Commands::Delete(args) => run_delete(args),
Some(Commands::Download(args)) => run_download(args).await, Commands::Download(args) => run_download(args).await,
Some(Commands::Run(args)) => run_run(args), Commands::Run(args) => run_run(args),
Some(Commands::List(args)) => run_list(args), Commands::List(args) => run_list(args),
None => {
// Backward compatibility: when no subcommand is provided, use 'cli' behavior
let model = cli.model.expect("Model is required (use -m or --model)");
let args = CliArgs {
common: CommonArgs {
address: cli.address.unwrap_or_else(|| "127.0.0.1".to_string()),
port: cli.port.unwrap_or(10100),
model,
allow_remote_shutdown: false,
},
weight_path: cli.weight_path,
save_dir: cli.save_dir,
download_retries: cli.download_retries,
gguf_path: cli.gguf_path,
mmproj_path: cli.mmproj_path,
};
run_cli(args).await
}
} }
} }
+26 -1
View File
@@ -20,6 +20,8 @@ pub enum WhichModel {
Qwen3_0_6B, Qwen3_0_6B,
#[value(name = "Qwen/Qwen3-1.7B")] #[value(name = "Qwen/Qwen3-1.7B")]
Qwen3_1_7B, Qwen3_1_7B,
#[value(name = "Qwen/Qwen3-4B")]
Qwen3_4B,
#[value(name = "Qwen/Qwen3.5-0.8B")] #[value(name = "Qwen/Qwen3.5-0.8B")]
Qwen3_5_0_8B, Qwen3_5_0_8B,
#[value(name = "Qwen/Qwen3.5-2B")] #[value(name = "Qwen/Qwen3.5-2B")]
@@ -67,18 +69,40 @@ pub enum WhichModel {
} }
impl WhichModel { impl WhichModel {
/// Get the ModelScope model ID for this model variant /// Get the model ID for this model variant
pub fn as_string(&self) -> String { pub fn as_string(&self) -> String {
self.to_possible_value() self.to_possible_value()
.expect("not exists") .expect("not exists")
.get_name() .get_name()
.to_string() .to_string()
} }
/// Checks if the model is in GGUF format
///
/// Returns true if the model ID contains "gguf", false otherwise
pub fn is_gguf(&self) -> bool {
let model_id = self.as_string();
model_id.to_lowercase().contains("gguf")
}
/// Checks if the model is in ONNX format
///
/// Returns true if the model ID contains "onnx", false otherwise
pub fn is_onnx(&self) -> bool {
let model_id = self.as_string();
model_id.to_lowercase().contains("onnx")
}
/// Get the WhichModel enum list /// Get the WhichModel enum list
pub fn model_list() -> Vec<Self> { pub fn model_list() -> Vec<Self> {
WhichModel::value_variants().to_vec() WhichModel::value_variants().to_vec()
} }
/// Extracts the model owner/organization from the model ID
///
/// Splits the model ID string on '/' and returns the first part which typically represents
/// the organization or user who owns the model in Hugging Face format (e.g., "Qwen" from "Qwen/Qwen3-0.6B")
/// Returns "none" if the model ID doesn't contain a '/' separator
pub fn model_owner(&self) -> String { pub fn model_owner(&self) -> String {
let name = self.as_string(); let name = self.as_string();
let names: Vec<&str> = name.split("/").collect(); let names: Vec<&str> = name.split("/").collect();
@@ -96,6 +120,7 @@ impl WhichModel {
WhichModel::MiniCPM4_0_5B WhichModel::MiniCPM4_0_5B
| WhichModel::Qwen3_0_6B | WhichModel::Qwen3_0_6B
| WhichModel::Qwen3_1_7B | WhichModel::Qwen3_1_7B
| WhichModel::Qwen3_4B
| WhichModel::LFM2_1_2B | WhichModel::LFM2_1_2B
| WhichModel::LFM2_5_1_2BInstruct => "llm", | WhichModel::LFM2_5_1_2BInstruct => "llm",
// VLM models // VLM models
+27 -12
View File
@@ -129,12 +129,27 @@ impl<'a> GenerateModel for ModelInstance<'a> {
} }
} }
pub fn load_model<'a>( #[allow(unused)]
pub fn load_gguf_model<'a>(
model_type: WhichModel, model_type: WhichModel,
path: &str, config_path: Option<&str>, // 有些gguf未包含模型其他配置,需额外指定
gguf: Option<&str>, gguf_path: &str,
mmproj: Option<&str>, mmproj_path: Option<&str>,
) -> Result<ModelInstance<'a>> { ) -> Result<ModelInstance<'a>> {
let model = match model_type {
WhichModel::Qwen3_5Gguf => {
let model = Qwen3_5GenerateModel::init_from_gguf(gguf_path, mmproj_path, None)?;
ModelInstance::Qwen3_5(model)
}
_ => {
let model_id = model_type.as_string();
return Err(anyhow!("model id {model_id} is not gguf model"));
}
};
Ok(model)
}
pub fn load_model<'a>(model_type: WhichModel, path: &str) -> Result<ModelInstance<'a>> {
let model = match model_type { let model = match model_type {
WhichModel::MiniCPM4_0_5B => { WhichModel::MiniCPM4_0_5B => {
let model = MiniCPMGenerateModel::init(path, None, None)?; let model = MiniCPMGenerateModel::init(path, None, None)?;
@@ -172,6 +187,10 @@ pub fn load_model<'a>(
let model = Qwen3GenerateModel::init(path, None, None)?; let model = Qwen3GenerateModel::init(path, None, None)?;
ModelInstance::Qwen3(model) ModelInstance::Qwen3(model)
} }
WhichModel::Qwen3_4B => {
let model = Qwen3GenerateModel::init(path, None, None)?;
ModelInstance::Qwen3(model)
}
WhichModel::Qwen3_5_0_8B => { WhichModel::Qwen3_5_0_8B => {
let model = Qwen3_5GenerateModel::init(path, None, None)?; let model = Qwen3_5GenerateModel::init(path, None, None)?;
ModelInstance::Qwen3_5(model) ModelInstance::Qwen3_5(model)
@@ -188,14 +207,6 @@ pub fn load_model<'a>(
let model = Qwen3_5GenerateModel::init(path, None, None)?; let model = Qwen3_5GenerateModel::init(path, None, None)?;
ModelInstance::Qwen3_5(model) ModelInstance::Qwen3_5(model)
} }
WhichModel::Qwen3_5Gguf => {
if gguf.is_none() {
return Err(anyhow!("Qwen3_5Gguf gguf model path is required"));
}
let gguf = gguf.unwrap();
let model = Qwen3_5GenerateModel::init_from_gguf(gguf, mmproj, None)?;
ModelInstance::Qwen3_5(model)
}
WhichModel::Qwen3ASR0_6B => { WhichModel::Qwen3ASR0_6B => {
let model = Qwen3AsrGenerateModel::init(path, None, None)?; let model = Qwen3AsrGenerateModel::init(path, None, None)?;
ModelInstance::Qwen3ASR(model) ModelInstance::Qwen3ASR(model)
@@ -264,6 +275,10 @@ pub fn load_model<'a>(
let model = GlmOcrGenerateModel::init(path, None, None)?; let model = GlmOcrGenerateModel::init(path, None, None)?;
ModelInstance::GlmOCR(model) ModelInstance::GlmOCR(model)
} }
_ => {
let model_id = model_type.as_string();
return Err(anyhow!("model id {model_id} is not safetensor model"));
}
}; };
Ok(model) Ok(model)
} }
+2 -2
View File
@@ -59,7 +59,7 @@ impl<'a> Qwen3_5GenerateModel<'a> {
qwen3_5, qwen3_5,
device, device,
model_name: model_name.to_string(), model_name: model_name.to_string(),
repeat_penalty: 1.01, repeat_penalty: 1.0,
repeat_last_n: 64, repeat_last_n: 64,
}) })
} }
@@ -116,7 +116,7 @@ impl<'a> Qwen3_5GenerateModel<'a> {
qwen3_5, qwen3_5,
device, device,
model_name: stem.to_string(), model_name: stem.to_string(),
repeat_penalty: 1.1, repeat_penalty: 1.2,
repeat_last_n: 64, repeat_last_n: 64,
}) })
} }
+17 -4
View File
@@ -2,9 +2,11 @@ use std::pin::pin;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, OnceLock}; use std::sync::{Arc, OnceLock};
use aha::models::load_gguf_model;
use aha::models::{GenerateModel, ModelInstance, common::model_mapping::WhichModel, load_model}; use aha::models::{GenerateModel, ModelInstance, common::model_mapping::WhichModel, load_model};
use aha::params::chat::ChatCompletionParameters; use aha::params::chat::ChatCompletionParameters;
use aha::utils::string_to_static_str; use aha::utils::string_to_static_str;
use anyhow::anyhow;
use rocket::futures::StreamExt; use rocket::futures::StreamExt;
use rocket::serde::{Serialize, json::Json}; use rocket::serde::{Serialize, json::Json};
use rocket::{ use rocket::{
@@ -37,10 +39,21 @@ pub fn init(
gguf: Option<String>, gguf: Option<String>,
mmproj: Option<String>, mmproj: Option<String>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let model_path = string_to_static_str(path); let model = if model_type.is_gguf() {
let gguf = gguf.map(string_to_static_str); if let Some(gguf_path) = gguf {
let mmproj = mmproj.map(string_to_static_str); let gguf_path = string_to_static_str(gguf_path);
let model = load_model(model_type, model_path, gguf, mmproj)?; let mmproj_path = mmproj.map(string_to_static_str);
load_gguf_model(model_type, None, gguf_path, mmproj_path)?
} else {
return Err(anyhow!("gguf model need gguf model path"));
}
} else if model_type.is_onnx() {
return Err(anyhow!("onnx comming soon but now not support"));
} else {
let model_path = string_to_static_str(path);
load_model(model_type, model_path)?
};
MODEL.get_or_init(|| { MODEL.get_or_init(|| {
Arc::new(RwLock::new(StoredModel { Arc::new(RwLock::new(StoredModel {
which_model: model_type, which_model: model_type,