From 16e3aefaa7ddac207dc306273a12fa1c65ce98d5 Mon Sep 17 00:00:00 2001 From: jhqxxx <18280426169@163.com> Date: Sat, 31 Jan 2026 18:37:28 +0800 Subject: [PATCH] fix aha run multiple inputs bug --- docs/CLI_USAGE.md | 39 +++++++++++++-------- src/exec/deepseek_ocr.rs | 24 +++++++++---- src/exec/fun_asr_nano.rs | 27 ++++++++++----- src/exec/glm_asr_nano.rs | 27 ++++++++++----- src/exec/hunyuan_ocr.rs | 24 +++++++++---- src/exec/minicpm4.rs | 17 +++++---- src/exec/mod.rs | 2 +- src/exec/paddleocr_vl.rs | 24 +++++++++---- src/exec/qwen2_5vl.rs | 41 +++++++++++++++++----- src/exec/qwen3.rs | 17 +++++---- src/exec/qwen3vl.rs | 74 +++++++++++++++++++++++++++++++++------- src/exec/rmbg2_0.rs | 20 +++++++---- src/exec/voxcpm.rs | 24 +++++++------ src/exec/voxcpm1_5.rs | 22 +++++++----- src/main.rs | 33 +++++++++++++----- src/utils/mod.rs | 16 ++++++++- 16 files changed, 308 insertions(+), 123 deletions(-) diff --git a/docs/CLI_USAGE.md b/docs/CLI_USAGE.md index 80d0476..7a5a0db 100644 --- a/docs/CLI_USAGE.md +++ b/docs/CLI_USAGE.md @@ -65,7 +65,7 @@ aha -m qwen3vl-2b **语法:** ```bash -aha run [OPTIONS] --model --input --weight-path +aha run [OPTIONS] --model --input [--input ] --weight-path ``` **选项:** @@ -73,30 +73,39 @@ aha run [OPTIONS] --model --input --weight-path | 选项 | 说明 | 默认值 | |------|------|--------| | `-m, --model ` | 模型类型(必选) | - | -| `-in, --input ` | 输入文本或文件路径(模型特定解释) | - | -| `-out, --output ` | 输出文件路径(可选,未指定则自动生成) | - | +| `-i, --input ` | 输入文本或文件路径(模型特定解释,支持1-2个参数, input1: 提示文本, input2: 文件地址) | - | +| `-o, --output ` | 输出文件路径(可选,未指定则自动生成) | - | | `--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 - 启动服务 diff --git a/src/exec/deepseek_ocr.rs b/src/exec/deepseek_ocr.rs index 1449633..ae46595 100644 --- a/src/exec/deepseek_ocr.rs +++ b/src/exec/deepseek_ocr.rs @@ -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": "\nConvert the document to markdown. " }} ] }} ] }}"#, - input_path + input_url ); let mes = serde_json::from_str(&message)?; diff --git a/src/exec/fun_asr_nano.rs b/src/exec/fun_asr_nano.rs index 02fe650..1af00fe 100644 --- a/src/exec/fun_asr_nano.rs +++ b/src/exec/fun_asr_nano.rs @@ -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!( diff --git a/src/exec/glm_asr_nano.rs b/src/exec/glm_asr_nano.rs index d21b0c8..70c1d3a 100644 --- a/src/exec/glm_asr_nano.rs +++ b/src/exec/glm_asr_nano.rs @@ -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!( diff --git a/src/exec/hunyuan_ocr.rs b/src/exec/hunyuan_ocr.rs index f632836..3eb5a7b 100644 --- a/src/exec/hunyuan_ocr.rs +++ b/src/exec/hunyuan_ocr.rs @@ -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)?; diff --git a/src/exec/minicpm4.rs b/src/exec/minicpm4.rs index 880a56c..5e36a4f 100644 --- a/src/exec/minicpm4.rs +++ b/src/exec/minicpm4.rs @@ -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(); diff --git a/src/exec/mod.rs b/src/exec/mod.rs index 76c6e76..67d9735 100644 --- a/src/exec/mod.rs +++ b/src/exec/mod.rs @@ -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<()>; } diff --git a/src/exec/paddleocr_vl.rs b/src/exec/paddleocr_vl.rs index edc0500..803f0eb 100644 --- a/src/exec/paddleocr_vl.rs +++ b/src/exec/paddleocr_vl.rs @@ -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)?; diff --git a/src/exec/qwen2_5vl.rs b/src/exec/qwen2_5vl.rs index 94848f3..ecaaa2e 100644 --- a/src/exec/qwen2_5vl.rs +++ b/src/exec/qwen2_5vl.rs @@ -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)?; diff --git a/src/exec/qwen3.rs b/src/exec/qwen3.rs index 3abe628..7a7d460 100644 --- a/src/exec/qwen3.rs +++ b/src/exec/qwen3.rs @@ -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(); diff --git a/src/exec/qwen3vl.rs b/src/exec/qwen3vl.rs index 5276744..a336d24 100644 --- a/src/exec/qwen3vl.rs +++ b/src/exec/qwen3vl.rs @@ -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(); diff --git a/src/exec/rmbg2_0.rs b/src/exec/rmbg2_0.rs index 86488f3..a93128a 100644 --- a/src/exec/rmbg2_0.rs +++ b/src/exec/rmbg2_0.rs @@ -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)?; diff --git a/src/exec/voxcpm.rs b/src/exec/voxcpm.rs index a509cf1..7a2e2d3 100644 --- a/src/exec/voxcpm.rs +++ b/src/exec/voxcpm.rs @@ -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, diff --git a/src/exec/voxcpm1_5.rs b/src/exec/voxcpm1_5.rs index 6e1e400..b6c7d6b 100644 --- a/src/exec/voxcpm1_5.rs +++ b/src/exec/voxcpm1_5.rs @@ -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, diff --git a/src/main.rs b/src/main.rs index 6be5f4a..add92ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, /// 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(()) -} \ No newline at end of file +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 32995f0..bc85e95 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -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 { path.to_string_lossy().to_string() }) } + +pub fn get_file_path(file: &str) -> Result { + 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) +}