fix aha run multiple inputs bug
This commit is contained in:
+24
-15
@@ -65,7 +65,7 @@ aha -m qwen3vl-2b
|
|||||||
|
|
||||||
**语法:**
|
**语法:**
|
||||||
```bash
|
```bash
|
||||||
aha run [OPTIONS] --model <MODEL> --input <INPUT> --weight-path <WEIGHT_PATH>
|
aha run [OPTIONS] --model <MODEL> --input <INPUT> [--input <INPUT2>] --weight-path <WEIGHT_PATH>
|
||||||
```
|
```
|
||||||
|
|
||||||
**选项:**
|
**选项:**
|
||||||
@@ -73,30 +73,39 @@ aha run [OPTIONS] --model <MODEL> --input <INPUT> --weight-path <WEIGHT_PATH>
|
|||||||
| 选项 | 说明 | 默认值 |
|
| 选项 | 说明 | 默认值 |
|
||||||
|------|------|--------|
|
|------|------|--------|
|
||||||
| `-m, --model <MODEL>` | 模型类型(必选) | - |
|
| `-m, --model <MODEL>` | 模型类型(必选) | - |
|
||||||
| `-in, --input <INPUT>` | 输入文本或文件路径(模型特定解释) | - |
|
| `-i, --input <INPUT>` | 输入文本或文件路径(模型特定解释,支持1-2个参数, input1: 提示文本, input2: 文件地址) | - |
|
||||||
| `-out, --output <OUTPUT>` | 输出文件路径(可选,未指定则自动生成) | - |
|
| `-o, --output <OUTPUT>` | 输出文件路径(可选,未指定则自动生成) | - |
|
||||||
| `--weight-path <WEIGHT_PATH>` | 本地模型权重路径(必选) | - |
|
| `--weight-path <WEIGHT_PATH>` | 本地模型权重路径(必选) | - |
|
||||||
|
|
||||||
**示例:**
|
**示例:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# VoxCPM1.5 文字转语音
|
# VoxCPM1.5 文字转语音(单个输入)
|
||||||
aha run -m voxcpm1.5 -in "太阳当空照" -out output.wav --weight-path /path/to/model
|
aha run -m voxcpm1.5 -i "太阳当空照" -o output.wav --weight-path /path/to/model
|
||||||
|
|
||||||
# VoxCPM1.5 从文件读取输入
|
# VoxCPM1.5 从文件读取输入(单个输入)
|
||||||
aha run -m voxcpm1.5 -in "file://./input.txt" --weight-path /path/to/model
|
aha run -m voxcpm1.5 -i "file://./input.txt" --weight-path /path/to/model
|
||||||
|
|
||||||
# MiniCPM4 文本生成
|
# MiniCPM4 文本生成(单个输入)
|
||||||
aha run -m minicpm4-0.5b -in "你好" --weight-path /path/to/model
|
aha run -m minicpm4-0.5b -i "你好" --weight-path /path/to/model
|
||||||
|
|
||||||
# DeepSeek OCR 图片识别
|
# DeepSeek OCR 图片识别(单个输入)
|
||||||
aha run -m deepseek-ocr -in "image.jpg" --weight-path /path/to/model
|
aha run -m deepseek-ocr -i "image.jpg" --weight-path /path/to/model
|
||||||
|
|
||||||
# RMBG2.0 背景移除
|
# RMBG2.0 背景移除(单个输入)
|
||||||
aha run -m RMBG2.0 -in "photo.png" -out "no_bg.png" --weight-path /path/to/model
|
aha run -m RMBG2.0 -i "photo.png" -o "no_bg.png" --weight-path /path/to/model
|
||||||
|
|
||||||
# GLM-ASR 语音识别
|
# GLM-ASR 语音识别(两个输入:提示文本 + 音频文件)
|
||||||
aha run -m glm-asr-nano-2512 -in "audio.wav" -in "请转写这段音频" --weight-path /path/to/model
|
aha run -m glm-asr-nano-2512 -i "请转写这段音频" -i "audio.wav" --weight-path /path/to/model
|
||||||
|
|
||||||
|
# Fun-ASR 语音识别(两个输入:提示文本 + 音频文件)
|
||||||
|
aha run -m fun-asr-nano-2512 -i "语音转写:" -i "audio.wav" --weight-path /path/to/model
|
||||||
|
|
||||||
|
# qwen3 文本生成(单个输入)
|
||||||
|
aha run -m qwen3-0.6b -i "你好" --weight-path /path/to/model
|
||||||
|
|
||||||
|
# qwen2.5vl 图像理解(两个输入:提示文本 + 图片文件)
|
||||||
|
aha run -m qwen2.5vl-3b -i "请分析图片并提取所有可见文本内容,按从左到右、从上到下的布局,返回纯文本" -i "image.jpg" --weight-path /path/to/model
|
||||||
```
|
```
|
||||||
|
|
||||||
### serv - 启动服务
|
### serv - 启动服务
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
//! DeepSeek-OCR exec implementation for CLI `run` subcommand
|
//! DeepSeek-OCR exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, deepseek_ocr::generate::DeepseekOCRGenerateModel};
|
use crate::models::{GenerateModel, deepseek_ocr::generate::DeepseekOCRGenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct DeepSeekORExec;
|
pub struct DeepSeekORExec;
|
||||||
|
|
||||||
impl ExecModel for DeepSeekORExec {
|
impl ExecModel for DeepSeekORExec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let input_path = if input.starts_with("file://") {
|
let url = &input[0];
|
||||||
input.to_string()
|
let input_url = if url.starts_with("http://")
|
||||||
|
|| url.starts_with("https://")
|
||||||
|
|| url.starts_with("file://")
|
||||||
|
{
|
||||||
|
url.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("file://{}", input)
|
format!("file://{}", url)
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
@@ -32,12 +38,16 @@ impl ExecModel for DeepSeekORExec {
|
|||||||
"image_url": {{
|
"image_url": {{
|
||||||
"url": "{}"
|
"url": "{}"
|
||||||
}}
|
}}
|
||||||
|
}},
|
||||||
|
{{
|
||||||
|
"type": "text",
|
||||||
|
"text": "<image>\nConvert the document to markdown. "
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}"#,
|
}}"#,
|
||||||
input_path
|
input_url
|
||||||
);
|
);
|
||||||
let mes = serde_json::from_str(&message)?;
|
let mes = serde_json::from_str(&message)?;
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
//! Fun-ASR-Nano-2512 exec implementation for CLI `run` subcommand
|
//! Fun-ASR-Nano-2512 exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, fun_asr_nano::generate::FunAsrNanoGenerateModel};
|
use crate::models::{GenerateModel, fun_asr_nano::generate::FunAsrNanoGenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
use crate::utils::get_file_path;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct FunASRNanoExec;
|
pub struct FunASRNanoExec;
|
||||||
|
|
||||||
impl ExecModel for FunASRNanoExec {
|
impl ExecModel for FunASRNanoExec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let target_text = if input.starts_with("file://") {
|
let input_text = &input[0];
|
||||||
let path = &input[7..];
|
let target_text = if input_text.starts_with("file://") {
|
||||||
|
// let path = &input[7..];
|
||||||
|
let path = get_file_path(input_text)?;
|
||||||
std::fs::read_to_string(path)?
|
std::fs::read_to_string(path)?
|
||||||
} else {
|
} else {
|
||||||
input.to_string()
|
input_text.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
@@ -22,10 +27,14 @@ impl ExecModel for FunASRNanoExec {
|
|||||||
println!("Time elapsed in load model is: {:?}", i_duration);
|
println!("Time elapsed in load model is: {:?}", i_duration);
|
||||||
|
|
||||||
// Create ChatCompletionParameters for ASR
|
// Create ChatCompletionParameters for ASR
|
||||||
let input_url = if input.starts_with("http://") || input.starts_with("https://") || input.starts_with("file://") {
|
let url = &input[1];
|
||||||
input.to_string()
|
let input_url = if url.starts_with("http://")
|
||||||
|
|| url.starts_with("https://")
|
||||||
|
|| url.starts_with("file://")
|
||||||
|
{
|
||||||
|
url.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("file://{}", input)
|
format!("file://{}", url)
|
||||||
};
|
};
|
||||||
|
|
||||||
let message = format!(
|
let message = format!(
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
//! GLM-ASR-Nano-2512 exec implementation for CLI `run` subcommand
|
//! GLM-ASR-Nano-2512 exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, glm_asr_nano::generate::GlmAsrNanoGenerateModel};
|
use crate::models::{GenerateModel, glm_asr_nano::generate::GlmAsrNanoGenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
use crate::utils::get_file_path;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct GlmASRNanoExec;
|
pub struct GlmASRNanoExec;
|
||||||
|
|
||||||
impl ExecModel for GlmASRNanoExec {
|
impl ExecModel for GlmASRNanoExec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let target_text = if input.starts_with("file://") {
|
let input_text = &input[0];
|
||||||
let path = &input[7..];
|
let target_text = if input_text.starts_with("file://") {
|
||||||
|
// let path = &input[7..];
|
||||||
|
let path = get_file_path(input_text)?;
|
||||||
std::fs::read_to_string(path)?
|
std::fs::read_to_string(path)?
|
||||||
} else {
|
} else {
|
||||||
input.to_string()
|
input_text.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
@@ -23,10 +28,14 @@ impl ExecModel for GlmASRNanoExec {
|
|||||||
|
|
||||||
// Create ChatCompletionParameters for ASR
|
// Create ChatCompletionParameters for ASR
|
||||||
// Input should be an audio file path
|
// Input should be an audio file path
|
||||||
let input_url = if input.starts_with("http://") || input.starts_with("https://") || input.starts_with("file://") {
|
let url = &input[1];
|
||||||
input.to_string()
|
let input_url = if url.starts_with("http://")
|
||||||
|
|| url.starts_with("https://")
|
||||||
|
|| url.starts_with("file://")
|
||||||
|
{
|
||||||
|
url.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("file://{}", input)
|
format!("file://{}", url)
|
||||||
};
|
};
|
||||||
|
|
||||||
let message = format!(
|
let message = format!(
|
||||||
|
|||||||
+17
-7
@@ -1,18 +1,24 @@
|
|||||||
//! Hunyuan-OCR exec implementation for CLI `run` subcommand
|
//! Hunyuan-OCR exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, hunyuan_ocr::generate::HunyuanOCRGenerateModel};
|
use crate::models::{GenerateModel, hunyuan_ocr::generate::HunyuanOCRGenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct HunyuanORExec;
|
pub struct HunyuanORExec;
|
||||||
|
|
||||||
impl ExecModel for HunyuanORExec {
|
impl ExecModel for HunyuanORExec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let input_path = if input.starts_with("file://") {
|
let url = &input[0];
|
||||||
input.to_string()
|
let input_url = if url.starts_with("http://")
|
||||||
|
|| url.starts_with("https://")
|
||||||
|
|| url.starts_with("file://")
|
||||||
|
{
|
||||||
|
url.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("file://{}", input)
|
format!("file://{}", url)
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
@@ -32,12 +38,16 @@ impl ExecModel for HunyuanORExec {
|
|||||||
"image_url": {{
|
"image_url": {{
|
||||||
"url": "{}"
|
"url": "{}"
|
||||||
}}
|
}}
|
||||||
|
}},
|
||||||
|
{{
|
||||||
|
"type": "text",
|
||||||
|
"text": "检测并识别图片中的文字,将文本坐标格式化输出。"
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}"#,
|
}}"#,
|
||||||
input_path
|
input_url
|
||||||
);
|
);
|
||||||
let mes = serde_json::from_str(&message)?;
|
let mes = serde_json::from_str(&message)?;
|
||||||
|
|
||||||
|
|||||||
+11
-6
@@ -1,19 +1,24 @@
|
|||||||
//! MiniCPM4-0.5B exec implementation for CLI `run` subcommand
|
//! MiniCPM4-0.5B exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, minicpm4::generate::MiniCPMGenerateModel};
|
use crate::models::{GenerateModel, minicpm4::generate::MiniCPMGenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
use crate::utils::get_file_path;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct MiniCPM4Exec;
|
pub struct MiniCPM4Exec;
|
||||||
|
|
||||||
impl ExecModel for MiniCPM4Exec {
|
impl ExecModel for MiniCPM4Exec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let target_text = if input.starts_with("file://") {
|
let input_text = &input[0];
|
||||||
let path = &input[7..];
|
let target_text = if input_text.starts_with("file://") {
|
||||||
|
// let path = &input[7..];
|
||||||
|
let path = get_file_path(input_text)?;
|
||||||
std::fs::read_to_string(path)?
|
std::fs::read_to_string(path)?
|
||||||
} else {
|
} else {
|
||||||
input.to_string()
|
input_text.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
|
|||||||
+1
-1
@@ -33,5 +33,5 @@ pub trait ExecModel {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// * `Ok(())` on success
|
/// * `Ok(())` on success
|
||||||
/// * `Err(anyhow::Error)` on failure
|
/// * `Err(anyhow::Error)` on failure
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()>;
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
//! PaddleOCR-VL exec implementation for CLI `run` subcommand
|
//! PaddleOCR-VL exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, paddleocr_vl::generate::PaddleOCRVLGenerateModel};
|
use crate::models::{GenerateModel, paddleocr_vl::generate::PaddleOCRVLGenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct PaddleOVLExec;
|
pub struct PaddleOVLExec;
|
||||||
|
|
||||||
impl ExecModel for PaddleOVLExec {
|
impl ExecModel for PaddleOVLExec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let input_path = if input.starts_with("file://") {
|
let url = &input[0];
|
||||||
input.to_string()
|
let input_url = if url.starts_with("http://")
|
||||||
|
|| url.starts_with("https://")
|
||||||
|
|| url.starts_with("file://")
|
||||||
|
{
|
||||||
|
url.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("file://{}", input)
|
format!("file://{}", url)
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
@@ -32,12 +38,16 @@ impl ExecModel for PaddleOVLExec {
|
|||||||
"image_url": {{
|
"image_url": {{
|
||||||
"url": "{}"
|
"url": "{}"
|
||||||
}}
|
}}
|
||||||
|
}},
|
||||||
|
{{
|
||||||
|
"type": "text",
|
||||||
|
"text": "OCR:"
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}"#,
|
}}"#,
|
||||||
input_path
|
input_url
|
||||||
);
|
);
|
||||||
let mes = serde_json::from_str(&message)?;
|
let mes = serde_json::from_str(&message)?;
|
||||||
|
|
||||||
|
|||||||
+32
-9
@@ -1,21 +1,33 @@
|
|||||||
//! Qwen2.5VL-3B exec implementation for CLI `run` subcommand
|
//! Qwen2.5VL-3B exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, qwen2_5vl::generate::Qwen2_5VLGenerateModel};
|
use crate::models::{GenerateModel, qwen2_5vl::generate::Qwen2_5VLGenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
use crate::utils::get_file_path;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct Qwen2_5vlExec;
|
pub struct Qwen2_5vlExec;
|
||||||
|
|
||||||
impl ExecModel for Qwen2_5vlExec {
|
impl ExecModel for Qwen2_5vlExec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let target_text = if input.starts_with("file://") {
|
let input_text = &input[0];
|
||||||
let path = &input[7..];
|
let target_text = if input_text.starts_with("file://") {
|
||||||
|
let path = get_file_path(input_text)?;
|
||||||
std::fs::read_to_string(path)?
|
std::fs::read_to_string(path)?
|
||||||
} else {
|
} else {
|
||||||
input.to_string()
|
input_text.clone()
|
||||||
|
};
|
||||||
|
let url = &input[1];
|
||||||
|
let input_url = if url.starts_with("http://")
|
||||||
|
|| url.starts_with("https://")
|
||||||
|
|| url.starts_with("file://")
|
||||||
|
{
|
||||||
|
url.clone()
|
||||||
|
} else {
|
||||||
|
format!("file://{}", url)
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
let mut model = Qwen2_5VLGenerateModel::init(weight_path, None, None)?;
|
let mut model = Qwen2_5VLGenerateModel::init(weight_path, None, None)?;
|
||||||
let i_duration = i_start.elapsed();
|
let i_duration = i_start.elapsed();
|
||||||
@@ -27,11 +39,22 @@ impl ExecModel for Qwen2_5vlExec {
|
|||||||
"messages": [
|
"messages": [
|
||||||
{{
|
{{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": "{}"
|
"content": [
|
||||||
|
{{
|
||||||
|
"type": "image",
|
||||||
|
"image_url": {{
|
||||||
|
"url": "{}"
|
||||||
|
}}
|
||||||
|
}},
|
||||||
|
{{
|
||||||
|
"type": "text",
|
||||||
|
"text": "{}"
|
||||||
|
}}
|
||||||
|
]
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}"#,
|
}}"#,
|
||||||
target_text.replace('"', "\\\"")
|
input_url, target_text
|
||||||
);
|
);
|
||||||
let mes = serde_json::from_str(&message)?;
|
let mes = serde_json::from_str(&message)?;
|
||||||
|
|
||||||
|
|||||||
+11
-6
@@ -1,19 +1,24 @@
|
|||||||
//! Qwen3-0.6B exec implementation for CLI `run` subcommand
|
//! Qwen3-0.6B exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, qwen3::generate::Qwen3GenerateModel};
|
use crate::models::{GenerateModel, qwen3::generate::Qwen3GenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
use crate::utils::get_file_path;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct Qwen3Exec;
|
pub struct Qwen3Exec;
|
||||||
|
|
||||||
impl ExecModel for Qwen3Exec {
|
impl ExecModel for Qwen3Exec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let target_text = if input.starts_with("file://") {
|
let input_text = &input[0];
|
||||||
let path = &input[7..];
|
let target_text = if input_text.starts_with("file://") {
|
||||||
|
// let path = &input[7..];
|
||||||
|
let path = get_file_path(input_text)?;
|
||||||
std::fs::read_to_string(path)?
|
std::fs::read_to_string(path)?
|
||||||
} else {
|
} else {
|
||||||
input.to_string()
|
input_text.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
|
|||||||
+62
-12
@@ -1,38 +1,88 @@
|
|||||||
//! Qwen3VL-2B exec implementation for CLI `run` subcommand
|
//! Qwen3VL-2B exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::{GenerateModel, qwen3vl::generate::Qwen3VLGenerateModel};
|
use crate::models::{GenerateModel, qwen3vl::generate::Qwen3VLGenerateModel};
|
||||||
use anyhow::{Ok, Result};
|
use crate::utils::get_file_path;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct Qwen3vlExec;
|
pub struct Qwen3vlExec;
|
||||||
|
|
||||||
impl ExecModel for Qwen3vlExec {
|
impl ExecModel for Qwen3vlExec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let target_text = if input.starts_with("file://") {
|
let input_text = &input[0];
|
||||||
let path = &input[7..];
|
let target_text = if input_text.starts_with("file://") {
|
||||||
|
let path = get_file_path(input_text)?;
|
||||||
std::fs::read_to_string(path)?
|
std::fs::read_to_string(path)?
|
||||||
} else {
|
} else {
|
||||||
input.to_string()
|
input_text.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
let mut model = Qwen3VLGenerateModel::init(weight_path, None, None)?;
|
let mut model = Qwen3VLGenerateModel::init(weight_path, None, None)?;
|
||||||
let i_duration = i_start.elapsed();
|
let i_duration = i_start.elapsed();
|
||||||
println!("Time elapsed in load model is: {:?}", i_duration);
|
println!("Time elapsed in load model is: {:?}", i_duration);
|
||||||
|
let url = &input[1];
|
||||||
let message = format!(
|
let input_url = if url.starts_with("http://")
|
||||||
r#"{{
|
|| url.starts_with("https://")
|
||||||
|
|| url.starts_with("file://")
|
||||||
|
{
|
||||||
|
url.clone()
|
||||||
|
} else {
|
||||||
|
format!("file://{}", url)
|
||||||
|
};
|
||||||
|
let message = if input_url.ends_with("mp4") {
|
||||||
|
format!(
|
||||||
|
r#"{{
|
||||||
"model": "qwen3vl",
|
"model": "qwen3vl",
|
||||||
"messages": [
|
"messages": [
|
||||||
{{
|
{{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": "{}"
|
"content": [
|
||||||
|
{{
|
||||||
|
"type": "video",
|
||||||
|
"video_url":
|
||||||
|
{{
|
||||||
|
"url": "{}"
|
||||||
|
}}
|
||||||
|
}},
|
||||||
|
{{
|
||||||
|
"type": "text",
|
||||||
|
"text": "{}"
|
||||||
|
}}
|
||||||
|
]
|
||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}"#,
|
}}"#,
|
||||||
target_text.replace('"', "\\\"")
|
input_url, target_text
|
||||||
);
|
)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
r#"{{
|
||||||
|
"model": "qwen2.5vl",
|
||||||
|
"messages": [
|
||||||
|
{{
|
||||||
|
"role": "user",
|
||||||
|
"content": [
|
||||||
|
{{
|
||||||
|
"type": "image",
|
||||||
|
"image_url": {{
|
||||||
|
"url": "{}"
|
||||||
|
}}
|
||||||
|
}},
|
||||||
|
{{
|
||||||
|
"type": "text",
|
||||||
|
"text": "{}"
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}}"#,
|
||||||
|
input_url, target_text
|
||||||
|
)
|
||||||
|
};
|
||||||
let mes = serde_json::from_str(&message)?;
|
let mes = serde_json::from_str(&message)?;
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
|
|||||||
+13
-7
@@ -1,18 +1,24 @@
|
|||||||
//! RMBG2.0 exec implementation for CLI `run` subcommand
|
//! RMBG2.0 exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
use crate::exec::ExecModel;
|
||||||
use crate::models::rmbg2_0::generate::RMBG2_0Model;
|
use crate::models::rmbg2_0::generate::RMBG2_0Model;
|
||||||
use anyhow::{Ok, Result};
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct RMBG2_0Exec;
|
pub struct RMBG2_0Exec;
|
||||||
|
|
||||||
impl ExecModel for RMBG2_0Exec {
|
impl ExecModel for RMBG2_0Exec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let input_path = if input.starts_with("file://") {
|
let url = &input[0];
|
||||||
input.to_string()
|
let input_url = if url.starts_with("http://")
|
||||||
|
|| url.starts_with("https://")
|
||||||
|
|| url.starts_with("file://")
|
||||||
|
{
|
||||||
|
url.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("file://{}", input)
|
format!("file://{}", url)
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
@@ -38,7 +44,7 @@ impl ExecModel for RMBG2_0Exec {
|
|||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
}}"#,
|
}}"#,
|
||||||
input_path
|
input_url
|
||||||
);
|
);
|
||||||
let mes = serde_json::from_str(&message)?;
|
let mes = serde_json::from_str(&message)?;
|
||||||
|
|
||||||
|
|||||||
+14
-10
@@ -1,19 +1,23 @@
|
|||||||
//! VoxCPM exec implementation for CLI `run` subcommand
|
//! VoxCPM exec implementation for CLI `run` subcommand
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
|
||||||
use crate::models::voxcpm::generate::VoxCPMGenerate;
|
|
||||||
use anyhow::{Ok, Result};
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
|
use crate::models::voxcpm::generate::VoxCPMGenerate;
|
||||||
|
use crate::{exec::ExecModel, utils::get_file_path};
|
||||||
|
|
||||||
pub struct VoxCPMExec;
|
pub struct VoxCPMExec;
|
||||||
|
|
||||||
impl ExecModel for VoxCPMExec {
|
impl ExecModel for VoxCPMExec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let target_text = if input.starts_with("file://") {
|
let input_text = &input[0];
|
||||||
let path = &input[7..];
|
let target_text = if input_text.starts_with("file://") {
|
||||||
|
// let path = &input[7..];
|
||||||
|
let path = get_file_path(input_text)?;
|
||||||
std::fs::read_to_string(path)?
|
std::fs::read_to_string(path)?
|
||||||
} else {
|
} else {
|
||||||
input.to_string()
|
input_text.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
@@ -24,10 +28,10 @@ impl ExecModel for VoxCPMExec {
|
|||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
let audio = voxcpm_generate.inference(
|
let audio = voxcpm_generate.inference(
|
||||||
target_text,
|
target_text,
|
||||||
Some("啥子小师叔,打狗还要看主人,你再要继续,我就是你的对手".to_string()), //todo args
|
Some("啥子小师叔,打狗还要看主人,你再要继续,我就是你的对手".to_string()), // todo args
|
||||||
Some("file://./assets/audio/voice_01.wav".to_string()), //todo args
|
Some("file://./assets/audio/voice_01.wav".to_string()), // todo args
|
||||||
2,
|
2,
|
||||||
100, // max_len (voxcpm uses 100 vs voxcpm1.5's 4096)
|
100, // max_len (voxcpm uses 100 vs voxcpm1.5's 4096)
|
||||||
10,
|
10,
|
||||||
2.0,
|
2.0,
|
||||||
6.0,
|
6.0,
|
||||||
|
|||||||
+13
-9
@@ -5,20 +5,24 @@
|
|||||||
//! - Input can be text content or a file path (with `file://` prefix)
|
//! - Input can be text content or a file path (with `file://` prefix)
|
||||||
//! - Output can be a file path or will be auto-generated if not specified
|
//! - Output can be a file path or will be auto-generated if not specified
|
||||||
|
|
||||||
use crate::exec::ExecModel;
|
|
||||||
use crate::models::voxcpm::generate::VoxCPMGenerate;
|
|
||||||
use anyhow::{Ok, Result};
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
|
use crate::models::voxcpm::generate::VoxCPMGenerate;
|
||||||
|
use crate::{exec::ExecModel, utils::get_file_path};
|
||||||
|
|
||||||
pub struct VoxCPM1_5Exec;
|
pub struct VoxCPM1_5Exec;
|
||||||
|
|
||||||
impl ExecModel for VoxCPM1_5Exec {
|
impl ExecModel for VoxCPM1_5Exec {
|
||||||
fn run(input: &str, output: Option<&str>, weight_path: &str) -> Result<()> {
|
fn run(input: &[String], output: Option<&str>, weight_path: &str) -> Result<()> {
|
||||||
let target_text = if input.starts_with("file://") {
|
let input_text = &input[0];
|
||||||
let path = &input[7..];
|
let target_text = if input_text.starts_with("file://") {
|
||||||
|
// let path = &input[7..];
|
||||||
|
let path = get_file_path(input_text)?;
|
||||||
std::fs::read_to_string(path)?
|
std::fs::read_to_string(path)?
|
||||||
} else {
|
} else {
|
||||||
input.to_string()
|
input_text.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
@@ -29,8 +33,8 @@ impl ExecModel for VoxCPM1_5Exec {
|
|||||||
let i_start = Instant::now();
|
let i_start = Instant::now();
|
||||||
let audio = voxcpm_generate.inference(
|
let audio = voxcpm_generate.inference(
|
||||||
target_text,
|
target_text,
|
||||||
Some("啥子小师叔,打狗还要看主人,你再要继续,我就是你的对手".to_string()), //todo args
|
Some("啥子小师叔,打狗还要看主人,你再要继续,我就是你的对手".to_string()), // todo args
|
||||||
Some("file://./assets/audio/voice_01.wav".to_string()), //todo args
|
Some("file://./assets/audio/voice_01.wav".to_string()), // todo args
|
||||||
2,
|
2,
|
||||||
4096,
|
4096,
|
||||||
10,
|
10,
|
||||||
|
|||||||
+25
-8
@@ -129,8 +129,8 @@ struct RunArgs {
|
|||||||
model: WhichModel,
|
model: WhichModel,
|
||||||
|
|
||||||
/// Input text or file path
|
/// Input text or file path
|
||||||
#[arg(short, long)]
|
#[arg(short, long, num_args = 1..=2, value_delimiter = ' ')]
|
||||||
input: String,
|
input: Vec<String>,
|
||||||
|
|
||||||
/// Output file path (optional)
|
/// Output file path (optional)
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
@@ -219,7 +219,7 @@ fn run_list() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
println!("Available models:");
|
println!("Available models:");
|
||||||
println!();
|
println!();
|
||||||
println!("{:<30} {}", "Model Name", "ModelScope ID");
|
println!("{:<30} ModelScope ID", "Model Name");
|
||||||
println!("{}", "-".repeat(80));
|
println!("{}", "-".repeat(80));
|
||||||
for model in models {
|
for model in models {
|
||||||
let possible_value = model.to_possible_value().unwrap();
|
let possible_value = model.to_possible_value().unwrap();
|
||||||
@@ -233,7 +233,12 @@ fn run_list() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
/// Run the 'cli' subcommand: download model (if needed) and start service
|
/// Run the 'cli' subcommand: download model (if needed) and start service
|
||||||
async fn run_cli(args: CliArgs) -> anyhow::Result<()> {
|
async fn run_cli(args: CliArgs) -> anyhow::Result<()> {
|
||||||
let CliArgs { common, weight_path, save_dir, download_retries } = args;
|
let CliArgs {
|
||||||
|
common,
|
||||||
|
weight_path,
|
||||||
|
save_dir,
|
||||||
|
download_retries,
|
||||||
|
} = args;
|
||||||
let model_id = get_model_id(common.model);
|
let model_id = get_model_id(common.model);
|
||||||
|
|
||||||
let model_path = match weight_path {
|
let model_path = match weight_path {
|
||||||
@@ -257,7 +262,10 @@ 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)
|
||||||
async fn run_serv(args: ServArgs) -> anyhow::Result<()> {
|
async fn run_serv(args: ServArgs) -> anyhow::Result<()> {
|
||||||
let ServArgs { common, weight_path } = args;
|
let ServArgs {
|
||||||
|
common,
|
||||||
|
weight_path,
|
||||||
|
} = args;
|
||||||
|
|
||||||
init(common.model, weight_path)?;
|
init(common.model, weight_path)?;
|
||||||
start_http_server(common.address, common.port).await?;
|
start_http_server(common.address, common.port).await?;
|
||||||
@@ -267,7 +275,11 @@ async fn run_serv(args: ServArgs) -> anyhow::Result<()> {
|
|||||||
|
|
||||||
/// Run the 'download' subcommand: download model only (no server)
|
/// Run the 'download' subcommand: download model only (no server)
|
||||||
async fn run_download(args: DownloadArgs) -> anyhow::Result<()> {
|
async fn run_download(args: DownloadArgs) -> anyhow::Result<()> {
|
||||||
let DownloadArgs { model, save_dir, download_retries } = args;
|
let DownloadArgs {
|
||||||
|
model,
|
||||||
|
save_dir,
|
||||||
|
download_retries,
|
||||||
|
} = args;
|
||||||
let model_id = get_model_id(model);
|
let model_id = get_model_id(model);
|
||||||
|
|
||||||
let save_dir = match save_dir {
|
let save_dir = match save_dir {
|
||||||
@@ -285,7 +297,12 @@ async fn run_download(args: DownloadArgs) -> anyhow::Result<()> {
|
|||||||
fn run_run(args: RunArgs) -> anyhow::Result<()> {
|
fn run_run(args: RunArgs) -> anyhow::Result<()> {
|
||||||
use aha::exec::ExecModel;
|
use aha::exec::ExecModel;
|
||||||
|
|
||||||
let RunArgs { model, input, output, weight_path } = args;
|
let RunArgs {
|
||||||
|
model,
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
weight_path,
|
||||||
|
} = args;
|
||||||
|
|
||||||
match model {
|
match model {
|
||||||
WhichModel::MiniCPM4_0_5B => {
|
WhichModel::MiniCPM4_0_5B => {
|
||||||
@@ -405,4 +422,4 @@ pub(crate) async fn start_http_server(address: String, port: u16) -> anyhow::Res
|
|||||||
|
|
||||||
builder.launch().await?;
|
builder.launch().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-1
@@ -3,7 +3,7 @@ pub mod img_utils;
|
|||||||
pub mod tensor_utils;
|
pub mod tensor_utils;
|
||||||
pub mod video_utils;
|
pub mod video_utils;
|
||||||
|
|
||||||
use std::{fs, process::Command};
|
use std::{fs, path::PathBuf, process::Command};
|
||||||
|
|
||||||
use aha_openai_dive::v1::resources::{
|
use aha_openai_dive::v1::resources::{
|
||||||
chat::{
|
chat::{
|
||||||
@@ -490,3 +490,17 @@ pub fn get_default_save_dir() -> Option<String> {
|
|||||||
path.to_string_lossy().to_string()
|
path.to_string_lossy().to_string()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_file_path(file: &str) -> Result<PathBuf> {
|
||||||
|
let path = url::Url::parse(file)?;
|
||||||
|
let path = path.to_file_path();
|
||||||
|
let path = match path {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(_) => {
|
||||||
|
let mut path = file.to_owned();
|
||||||
|
path = path.split_off(7);
|
||||||
|
PathBuf::from(path)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user