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