fix: piper 二进制+依赖库+config 修正 (符号链接指向正确二进制,加 LD_LIBRARY_PATH 和 -c 参数)
This commit is contained in:
1
.chat_req.json
Normal file
1
.chat_req.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"text":"hello","session_id":"e2e"}
|
||||||
@@ -1167,6 +1167,8 @@
|
|||||||
},
|
},
|
||||||
"ai": {
|
"ai": {
|
||||||
"backend": "local",
|
"backend": "local",
|
||||||
"whisper_lib_dir": "/home/showen/ai_spike/whisper.cpp/build/bin"
|
"whisper_lib_dir": "/home/showen/ai_spike/whisper.cpp/build/bin",
|
||||||
|
"piper_lib_dir": "/home/showen/ai_spike/piper",
|
||||||
|
"piper_config": "/home/showen/ai_spike/piper/zh_CN-huayan-medium.onnx.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1179,6 +1179,8 @@
|
|||||||
},
|
},
|
||||||
"ai": {
|
"ai": {
|
||||||
"backend": "local",
|
"backend": "local",
|
||||||
"whisper_lib_dir": "/home/showen/ai_spike/whisper.cpp/build/bin"
|
"whisper_lib_dir": "/home/showen/ai_spike/whisper.cpp/build/bin",
|
||||||
|
"piper_lib_dir": "/home/showen/ai_spike/piper",
|
||||||
|
"piper_config": "/home/showen/ai_spike/piper/zh_CN-huayan-medium.onnx.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,6 +384,12 @@ pub struct AiConfig {
|
|||||||
/// whisper-cli 依赖库路径 (libggml*.so 所在,部署时标定)
|
/// whisper-cli 依赖库路径 (libggml*.so 所在,部署时标定)
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub whisper_lib_dir: Option<PathBuf>,
|
pub whisper_lib_dir: Option<PathBuf>,
|
||||||
|
/// piper 依赖库路径 (libespeak-ng.so / libpiper_phonemize.so 所在)
|
||||||
|
#[serde(default)]
|
||||||
|
pub piper_lib_dir: Option<PathBuf>,
|
||||||
|
/// piper 模型 config json 路径 (.onnx.json)
|
||||||
|
#[serde(default)]
|
||||||
|
pub piper_config: Option<PathBuf>,
|
||||||
/// 临时文件目录
|
/// 临时文件目录
|
||||||
#[serde(default = "default_tmp_dir")]
|
#[serde(default = "default_tmp_dir")]
|
||||||
pub tmp_dir: PathBuf,
|
pub tmp_dir: PathBuf,
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ fn main() -> Result<()> {
|
|||||||
let ai_model_store = config.ai.model_store.clone();
|
let ai_model_store = config.ai.model_store.clone();
|
||||||
let ai_tools_dir = config.ai.tools_dir.clone();
|
let ai_tools_dir = config.ai.tools_dir.clone();
|
||||||
let ai_whisper_lib_dir = config.ai.whisper_lib_dir.clone();
|
let ai_whisper_lib_dir = config.ai.whisper_lib_dir.clone();
|
||||||
|
let ai_piper_lib_dir = config.ai.piper_lib_dir.clone();
|
||||||
|
let ai_piper_config = config.ai.piper_config.clone();
|
||||||
let ai_tmp_dir = config.ai.tmp_dir.clone();
|
let ai_tmp_dir = config.ai.tmp_dir.clone();
|
||||||
let ai_context_window = config.ai.context_window;
|
let ai_context_window = config.ai.context_window;
|
||||||
|
|
||||||
@@ -81,6 +83,8 @@ fn main() -> Result<()> {
|
|||||||
ai_model_store,
|
ai_model_store,
|
||||||
ai_tools_dir,
|
ai_tools_dir,
|
||||||
ai_whisper_lib_dir,
|
ai_whisper_lib_dir,
|
||||||
|
ai_piper_lib_dir,
|
||||||
|
ai_piper_config,
|
||||||
ai_tmp_dir,
|
ai_tmp_dir,
|
||||||
ai_context_window,
|
ai_context_window,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ pub struct LocalCliBackend {
|
|||||||
tools_dir: PathBuf,
|
tools_dir: PathBuf,
|
||||||
/// whisper-cli 依赖的库路径(libggml*.so 所在)
|
/// whisper-cli 依赖的库路径(libggml*.so 所在)
|
||||||
whisper_lib_dir: Option<PathBuf>,
|
whisper_lib_dir: Option<PathBuf>,
|
||||||
|
/// piper 依赖的库路径(libespeak-ng.so / libpiper_phonemize.so 所在)
|
||||||
|
piper_lib_dir: Option<PathBuf>,
|
||||||
|
/// piper 模型 config json 路径(.onnx.json)
|
||||||
|
piper_config: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalCliBackend {
|
impl LocalCliBackend {
|
||||||
@@ -55,6 +59,8 @@ impl LocalCliBackend {
|
|||||||
Self {
|
Self {
|
||||||
tools_dir,
|
tools_dir,
|
||||||
whisper_lib_dir: None,
|
whisper_lib_dir: None,
|
||||||
|
piper_lib_dir: None,
|
||||||
|
piper_config: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +70,13 @@ impl LocalCliBackend {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 设置 piper 依赖库路径和 config(部署时由 deploy_ai.sh 标定)
|
||||||
|
pub fn with_piper_deps(mut self, lib_dir: PathBuf, config: PathBuf) -> Self {
|
||||||
|
self.piper_lib_dir = Some(lib_dir);
|
||||||
|
self.piper_config = Some(config);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn whisper_cli(&self) -> PathBuf {
|
fn whisper_cli(&self) -> PathBuf {
|
||||||
self.tools_dir.join("whisper-cli")
|
self.tools_dir.join("whisper-cli")
|
||||||
}
|
}
|
||||||
@@ -76,21 +89,26 @@ impl LocalCliBackend {
|
|||||||
self.tools_dir.join("piper")
|
self.tools_dir.join("piper")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 给命令设置 LD_LIBRARY_PATH(whisper-cli 依赖 libggml*.so)
|
/// 给命令设置 LD_LIBRARY_PATH(合并所有库路径)
|
||||||
fn with_env(&self, cmd: &mut Command) {
|
fn with_lib_path(&self, cmd: &mut Command, lib_dir: &Path) {
|
||||||
if let Some(lib_dir) = &self.whisper_lib_dir {
|
let existing = std::env::var("LD_LIBRARY_PATH").unwrap_or_default();
|
||||||
cmd.env("LD_LIBRARY_PATH", lib_dir);
|
let new_path = if existing.is_empty() {
|
||||||
}
|
lib_dir.to_string_lossy().into_owned()
|
||||||
|
} else {
|
||||||
|
format!("{}:{}", lib_dir.to_string_lossy(), existing)
|
||||||
|
};
|
||||||
|
cmd.env("LD_LIBRARY_PATH", new_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AiBackend for LocalCliBackend {
|
impl AiBackend for LocalCliBackend {
|
||||||
fn asr(&self, audio_path: &Path, model_path: &Path) -> Result<String> {
|
fn asr(&self, audio_path: &Path, model_path: &Path) -> Result<String> {
|
||||||
// whisper-cli -m <model> -f <audio> -l zh --no-timestamps -otxt -of <tmp>
|
// whisper-cli -m <model> -f <audio> -l zh --no-timestamps -otxt -of <tmp>
|
||||||
// 输出到 <tmp>.txt,读取后返回
|
|
||||||
let tmp_out = audio_path.with_extension("asr.txt");
|
let tmp_out = audio_path.with_extension("asr.txt");
|
||||||
let mut cmd = Command::new(self.whisper_cli());
|
let mut cmd = Command::new(self.whisper_cli());
|
||||||
self.with_env(&mut cmd);
|
if let Some(lib_dir) = &self.whisper_lib_dir {
|
||||||
|
self.with_lib_path(&mut cmd, lib_dir);
|
||||||
|
}
|
||||||
let output = cmd
|
let output = cmd
|
||||||
.arg("-m")
|
.arg("-m")
|
||||||
.arg(model_path)
|
.arg(model_path)
|
||||||
@@ -178,15 +196,25 @@ impl AiBackend for LocalCliBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn tts(&self, text: &str, model_path: &Path, output_path: &Path) -> Result<()> {
|
fn tts(&self, text: &str, model_path: &Path, output_path: &Path) -> Result<()> {
|
||||||
// echo <text> | piper -m <model> -f <output> --output_format wav
|
// echo <text> | piper -m <model> [-c <config>] -f <output> --output_format wav
|
||||||
|
// piper 依赖 libespeak-ng.so / libpiper_phonemize.so,需设 LD_LIBRARY_PATH
|
||||||
let mut cmd = Command::new(self.piper());
|
let mut cmd = Command::new(self.piper());
|
||||||
|
if let Some(lib_dir) = &self.piper_lib_dir {
|
||||||
|
self.with_lib_path(&mut cmd, lib_dir);
|
||||||
|
}
|
||||||
cmd.arg("-m")
|
cmd.arg("-m")
|
||||||
.arg(model_path)
|
.arg(model_path)
|
||||||
.arg("-f")
|
.arg("-f")
|
||||||
.arg(output_path)
|
.arg(output_path)
|
||||||
.arg("--output_format")
|
.arg("--output_format")
|
||||||
.arg("wav")
|
.arg("wav");
|
||||||
.stdin(std::process::Stdio::piped())
|
|
||||||
|
// piper 需要 -c 指定 .onnx.json config 文件
|
||||||
|
if let Some(config) = &self.piper_config {
|
||||||
|
cmd.arg("-c").arg(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.stdin(std::process::Stdio::piped())
|
||||||
.stdout(std::process::Stdio::null())
|
.stdout(std::process::Stdio::null())
|
||||||
.stderr(std::process::Stdio::piped());
|
.stderr(std::process::Stdio::piped());
|
||||||
|
|
||||||
@@ -199,7 +227,8 @@ impl AiBackend for LocalCliBackend {
|
|||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
bail!(
|
bail!(
|
||||||
"piper 失败: {}",
|
"piper 失败 (exit={}): {}",
|
||||||
|
output.status,
|
||||||
String::from_utf8_lossy(&output.stderr)
|
String::from_utf8_lossy(&output.stderr)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ impl AiPlugin {
|
|||||||
model_store: PathBuf,
|
model_store: PathBuf,
|
||||||
tools_dir: PathBuf,
|
tools_dir: PathBuf,
|
||||||
whisper_lib_dir: Option<PathBuf>,
|
whisper_lib_dir: Option<PathBuf>,
|
||||||
|
piper_lib_dir: Option<PathBuf>,
|
||||||
|
piper_config: Option<PathBuf>,
|
||||||
tmp_dir: PathBuf,
|
tmp_dir: PathBuf,
|
||||||
context_window: usize,
|
context_window: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -55,6 +57,9 @@ impl AiPlugin {
|
|||||||
if let Some(lib_dir) = whisper_lib_dir {
|
if let Some(lib_dir) = whisper_lib_dir {
|
||||||
backend_builder = backend_builder.with_whisper_lib_dir(lib_dir);
|
backend_builder = backend_builder.with_whisper_lib_dir(lib_dir);
|
||||||
}
|
}
|
||||||
|
if let (Some(lib_dir), Some(config)) = (piper_lib_dir, piper_config) {
|
||||||
|
backend_builder = backend_builder.with_piper_deps(lib_dir, config);
|
||||||
|
}
|
||||||
let backend = Box::new(backend_builder);
|
let backend = Box::new(backend_builder);
|
||||||
let models = model_manager::ModelManager::new(model_store);
|
let models = model_manager::ModelManager::new(model_store);
|
||||||
let pipeline = ChatPipeline::new(backend, models, tmp_dir, context_window);
|
let pipeline = ChatPipeline::new(backend, models, tmp_dir, context_window);
|
||||||
|
|||||||
Reference in New Issue
Block a user