From 6810d1ca13ae55059b2cef925d463d52255b99eb Mon Sep 17 00:00:00 2001 From: pulsareonbot Date: Sat, 4 Jul 2026 15:44:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(M2.1):=20=E8=AE=BE=E5=A4=87=E7=AB=AF?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E8=84=9A=E6=9C=AC=20+=20whisper=20LD=5FLIBRA?= =?UTF-8?q?RY=5FPATH=20+=20dog/cat=20=E8=A7=92=E8=89=B2=E4=BA=BA=E8=AE=BE?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configs/cat_state_machine.json | 9 ++++ configs/dog_state_machine.json | 9 ++++ scripts/deploy_ai.sh | 87 ++++++++++++++++++++++++++++++++++ src/core/config.rs | 3 ++ src/main.rs | 2 + src/plugins/ai/backend.rs | 24 +++++++++- src/plugins/ai/mod.rs | 7 ++- 7 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 scripts/deploy_ai.sh diff --git a/configs/cat_state_machine.json b/configs/cat_state_machine.json index 5c80a9f..7d34b70 100644 --- a/configs/cat_state_machine.json +++ b/configs/cat_state_machine.json @@ -1159,5 +1159,14 @@ "enabled": true, "host": "0.0.0.0", "port": 5000 + }, + "character": { + "name": "小喵", + "character_type": "pet", + "persona_prompt": "你是一只慵懒傲娇的猫咪,名叫小喵。用简短慵懒的口吻回答,偶尔带'喵~',每次回复不超过两句话。" + }, + "ai": { + "backend": "local", + "whisper_lib_dir": "/home/showen/ai_spike/whisper.cpp/build/bin" } } \ No newline at end of file diff --git a/configs/dog_state_machine.json b/configs/dog_state_machine.json index 0a65ecd..27f2acc 100644 --- a/configs/dog_state_machine.json +++ b/configs/dog_state_machine.json @@ -1171,5 +1171,14 @@ "enabled": true, "host": "0.0.0.0", "port": 5000 + }, + "character": { + "name": "小汪", + "character_type": "pet", + "persona_prompt": "你是一只活泼的小狗,名叫小汪。用简短俏皮的口吻回答,以'汪!'开头,每次回复不超过两句话。" + }, + "ai": { + "backend": "local", + "whisper_lib_dir": "/home/showen/ai_spike/whisper.cpp/build/bin" } } \ No newline at end of file diff --git a/scripts/deploy_ai.sh b/scripts/deploy_ai.sh new file mode 100644 index 0000000..fad44c9 --- /dev/null +++ b/scripts/deploy_ai.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# M2.1 设备端部署脚本 — 部署 AI 推理二进制 + 模型文件 +# 用法: bash scripts/deploy_ai.sh +# 前置: ~/ai_spike/ 存在 (spike 2026-07-03 保留) + +set -e +SPIKE_DIR="$HOME/ai_spike" +PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +TOOLS_DIR="$PROJECT_DIR/tools" +MODEL_STORE="$PROJECT_DIR/model_store" + +echo "=== M2.1 AI 部署 ===" +echo "项目: $PROJECT_DIR" +echo "spike: $SPIKE_DIR" + +# 检查 spike 目录 +if [ ! -d "$SPIKE_DIR" ]; then + echo "错误: spike 目录不存在 ($SPIKE_DIR)" + echo "请先完成 spike (参考 TEAM_CHAT.md 2026-07-03 张明远报告)" + exit 1 +fi + +# 1. 部署二进制到 tools/ +echo "--- 部署二进制到 tools/ ---" +mkdir -p "$TOOLS_DIR" + +# whisper-cli (依赖 libggml*.so,需设 LD_LIBRARY_PATH 或 RPATH) +ln -sf "$SPIKE_DIR/whisper.cpp/build/bin/whisper-cli" "$TOOLS_DIR/whisper-cli" +echo " ✓ whisper-cli" + +# llama-cli +ln -sf "$SPIKE_DIR/llama.cpp/build/bin/llama-cli" "$TOOLS_DIR/llama-cli" +echo " ✓ llama-cli" + +# piper +ln -sf "$SPIKE_DIR/piper/piper" "$TOOLS_DIR/piper" +echo " ✓ piper" + +# 2. 部署模型到 model_store/ +echo "--- 部署模型到 model_store/ ---" +mkdir -p "$MODEL_STORE/llm" "$MODEL_STORE/asr" "$MODEL_STORE/tts" + +# LLM: Qwen2.5-0.5B (默认推荐) +ln -sf "$SPIKE_DIR/models/qwen2.5-0.5b-instruct-q4_k_m.gguf" "$MODEL_STORE/llm/qwen2.5-0.5b-q4_k_m.gguf" +echo " ✓ llm/qwen2.5-0.5b-q4_k_m.gguf (469M, 推荐默认)" + +# LLM: Gemma3-1B (可选档) +ln -sf "$SPIKE_DIR/models/gemma-3-1b-it-Q4_K_M.gguf" "$MODEL_STORE/llm/gemma3-1b-q4_k_m.gguf" +echo " ✓ llm/gemma3-1b-q4_k_m.gguf (769M, 可选档)" + +# ASR: whisper tiny +ln -sf "$SPIKE_DIR/models/ggml-tiny.bin" "$MODEL_STORE/asr/ggml-tiny.bin" +echo " ✓ asr/ggml-tiny.bin (75M)" + +# ASR: whisper base (备选) +ln -sf "$SPIKE_DIR/models/ggml-base.bin" "$MODEL_STORE/asr/ggml-base.bin" +echo " ✓ asr/ggml-base.bin (142M, 备选)" + +# TTS: piper zh_CN-huayan-medium +ln -sf "$SPIKE_DIR/piper/zh_CN-huayan-medium.onnx" "$MODEL_STORE/tts/zh_CN-huayan-medium.onnx" +ln -sf "$SPIKE_DIR/piper/zh_CN-huayan-medium.onnx.json" "$MODEL_STORE/tts/zh_CN-huayan-medium.onnx.json" +echo " ✓ tts/zh_CN-huayan-medium.onnx (63M)" + +# 3. 设置 whisper LD_LIBRARY_PATH (whisper-cli 依赖 libggml*.so) +WHISPER_LIB="$SPIKE_DIR/whisper.cpp/build/bin" +echo "--- whisper 依赖库路径: $WHISPER_LIB ---" + +# 4. 验证 +echo "=== 验证 ===" +echo "tools/:" +ls -la "$TOOLS_DIR" +echo "model_store/:" +ls -laR "$MODEL_STORE" + +# 测试 llama-cli 能跑 +echo "--- 测试 llama-cli ---" +"$TOOLS_DIR/llama-cli" --version 2>&1 | head -1 || echo " (llama-cli 版本检查失败, 可能仍可用)" + +# 测试 piper 能跑 +echo "--- 测试 piper ---" +"$TOOLS_DIR/piper" --help 2>&1 | head -1 || echo " (piper 帮助检查失败, 可能仍可用)" + +echo "=== 部署完成 ===" +echo "" +echo "注意: whisper-cli 运行时需要 LD_LIBRARY_PATH 包含:" +echo " $WHISPER_LIB" +echo "建议在 systemd service 或启动脚本中设置此环境变量" diff --git a/src/core/config.rs b/src/core/config.rs index d7bb1dd..aab268d 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -381,6 +381,9 @@ pub struct AiConfig { /// 工具目录 (whisper-cli/llama-cli/piper 二进制所在) #[serde(default = "default_tools_dir")] pub tools_dir: PathBuf, + /// whisper-cli 依赖库路径 (libggml*.so 所在,部署时标定) + #[serde(default)] + pub whisper_lib_dir: Option, /// 临时文件目录 #[serde(default = "default_tmp_dir")] pub tmp_dir: PathBuf, diff --git a/src/main.rs b/src/main.rs index cc96283..5118a82 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,6 +49,7 @@ fn main() -> Result<()> { // 在 config move 进 ServiceManager 之前,提取 AI 相关配置 let ai_model_store = config.ai.model_store.clone(); let ai_tools_dir = config.ai.tools_dir.clone(); + let ai_whisper_lib_dir = config.ai.whisper_lib_dir.clone(); let ai_tmp_dir = config.ai.tmp_dir.clone(); let ai_context_window = config.ai.context_window; @@ -79,6 +80,7 @@ fn main() -> Result<()> { let ai_plugin = AiPlugin::new_default( ai_model_store, ai_tools_dir, + ai_whisper_lib_dir, ai_tmp_dir, ai_context_window, ); diff --git a/src/plugins/ai/backend.rs b/src/plugins/ai/backend.rs index e7cdf5d..3086dc6 100644 --- a/src/plugins/ai/backend.rs +++ b/src/plugins/ai/backend.rs @@ -46,11 +46,22 @@ pub trait AiBackend: Send { pub struct LocalCliBackend { /// 工具目录(含 whisper-cli, llama-cli, piper 二进制) tools_dir: PathBuf, + /// whisper-cli 依赖的库路径(libggml*.so 所在) + whisper_lib_dir: Option, } impl LocalCliBackend { pub fn new(tools_dir: PathBuf) -> Self { - Self { tools_dir } + Self { + tools_dir, + whisper_lib_dir: None, + } + } + + /// 设置 whisper-cli 依赖库路径(部署时由 deploy_ai.sh 标定) + pub fn with_whisper_lib_dir(mut self, lib_dir: PathBuf) -> Self { + self.whisper_lib_dir = Some(lib_dir); + self } fn whisper_cli(&self) -> PathBuf { @@ -64,6 +75,13 @@ impl LocalCliBackend { fn piper(&self) -> PathBuf { self.tools_dir.join("piper") } + + /// 给命令设置 LD_LIBRARY_PATH(whisper-cli 依赖 libggml*.so) + fn with_env(&self, cmd: &mut Command) { + if let Some(lib_dir) = &self.whisper_lib_dir { + cmd.env("LD_LIBRARY_PATH", lib_dir); + } + } } impl AiBackend for LocalCliBackend { @@ -71,7 +89,9 @@ impl AiBackend for LocalCliBackend { // whisper-cli -m -f