对着机器人说话,它用本地模型理解并开口回答。
对话期间机器人保持彩虹灯效,屏幕表情随状态切换:微笑 → 聆听 → 思考 → 说话。
机器人麦克风 → 本地 ASR(SenseVoice) → 本地 LLM(qwen3/Ollama) → edge-tts → 响度归一化 → 机器人喇叭
识别和大模型全部运行在本机,不需要 API Key;语音合成使用微软在线语音服务。
| 环节 | 方案 | 运行位置 | 需要联网 |
|---|---|---|---|
| 语音识别 ASR | SenseVoice Small(int8,sherpa-onnx 推理) | 本机 CPU | 否 |
| 大模型 LLM | Qwen3 0.6B(Ollama 运行) | 本机 CPU | 否 |
| 语音合成 TTS | edge-tts,音色 zh-CN-XiaoxiaoNeural |
微软在线服务 | 是 |
| 音频处理 | ffmpeg(loudnorm 响度归一化 + alimiter 限幅) |
本机 | 否 |
| 对话记忆 | 最近 4 轮(8 条消息)上下文 | 本机内存 | 否 |
识别单句约 0.05–0.09 秒,大模型生成约 0.07–0.10 秒,语音合成 2–4 秒,单轮总计约 5–8 秒。
# ============ 准备(只需执行一次) ============
conda activate watcherobot-source
python -m pip install sherpa-onnx soundfile soxr edge-tts
brew install ffmpeg
ollama pull qwen3:0.6b
# ============ 启动 ============
cd "/Users/zongzheli/Downloads/self_study/workshop"
watcherobot daemon start
watcherobot robot status # 需要显示 Robot connected
watcherobot app run ./voice_chat
# ============ 停止(任选一种) ============
# 方式 A:在运行窗口按 Ctrl+C
# 方式 B:另开一个终端
watcherobot app stop
# 方式 C:对机器人说「退出」「再见」「拜拜」「停止」「结束」
启动后机器人亮起彩虹灯、露出微笑,说一句开场白,然后进入聆听状态。直接说话即可。
停止后自动恢复:关灯、播放待机表情。
voice_chat/
├─ app.py 主程序(Application 入口)
├─ app.json Application 清单
├─ settings.json 全部可调参数
├─ icon.svg 图标
├─ models/asr/ 识别模型存放位置(发布包中不含,首次使用需下载,见下)
├─ artifacts/ 运行产物,可随时删除
└─ README.md
识别权重以相对路径 models/asr/ 引用。
发布包里不包含识别权重(已在 .watcherignore 中排除)。首次使用前下载到 models/asr/:
cd voice_chat
python - <<'PY'
from huggingface_hub import hf_hub_download
import shutil, pathlib
pathlib.Path("models/asr").mkdir(parents=True, exist_ok=True)
for f in ["model.int8.onnx", "tokens.txt"]:
p = hf_hub_download(
"csukuangfj/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17", f
)
shutil.copy(p, "models/asr/" + pathlib.Path(f).name)
print("已下载", f)
PY
下载约 228 MB。国内网络可先设置 export HF_ENDPOINT=https://hf-mirror.com 走镜像。
大模型权重由 Ollama 管理,位置在 ~/.ollama/models/,用 ollama list 可确认 qwen3:0.6b 已就绪。
全部参数都在 settings.json:
| 参数 | 作用 | 默认值 |
|---|---|---|
asr_model / asr_tokens |
识别模型路径,相对于本目录 | models/asr/... |
asr_input_gain |
送识别前对麦克风音频的放大倍数 | 4.0 |
ollama_model |
使用的大模型 | qwen3:0.6b |
tts_voice |
语音音色 | zh-CN-XiaoxiaoNeural |
loudness_filter |
响度归一化滤镜 | loudnorm + alimiter |
noise_floor_min |
判定「开始说话」的最低能量 | 900 |
speech_ratio |
超过本底噪声多少倍算说话 | 2.5 |
silence_seconds |
停顿多久算说完 | 0.8 |
max_utterance_seconds |
单次录音最长时长 | 12.0 |
light_color / light_zone |
灯光颜色与区域 | #FF1E8A / all |
light_effect |
灯效名称,留空则常亮 | rainbow |
system_prompt |
机器人的说话风格 | 简短口语化 |
knowledge_file |
常见问题参考文件 | knowledge.md |
greeting |
启动开场白 | 「你好,我在听,请说吧。」 |
调音建议:识别不准时先调 asr_input_gain(调到 6.0);环境嘈杂时调高 noise_floor_min(如 1200)。
knowledge.md 存放常见问题的参考回答。启动时它会被注入给模型,同时附带当前时间,所以「现在几点」这类问题也能回答。
文件按 问:… 答:… 的格式编写,想加内容直接追加即可:
问:你几岁了?
答:我是刚出厂的,还很年轻,请多关照。
以下问题有预设答案,回答稳定:
| 类别 | 问题 |
|---|---|
| 身份 | 你是谁 / 你叫什么名字;你是什么做的 / 用什么模型;你几岁了 / 多大了 |
| 能力 | 你会做什么;你能看到我吗;你能听到我说话吗;你会唱歌吗;你能走路吗 / 能动能 |
| 隐私 | 我说的话会被上传到网上吗;你会记录我吗 |
| 时间 | 现在几点 / 今天几号 |
| 闲聊 | 你好 / 嗨;你喜欢什么;讲个笑话;夸夸我;我有点累 / 心情不好;你怎么看这个工作坊 / 今天的活动;再见 / 拜拜 |
以下问题会明确说"答不了",不会编造:
| 类别 | 问题 | 回答方式 |
|---|---|---|
| 实时信息 | 今天天气怎么样 | 说明查不了实时信息,建议用手机 |
| 检索 | 你能帮我查东西吗 | 说明查不了资料,可以陪聊 |
知识库没覆盖的问题走自然闲聊,由 qwen3:0.6b 自由回答。因为是 0.6B 小模型,自由发挥时回答偏短,偶尔会绕。
提问超出知识库时,模型会正常闲聊;不确定的内容会直说不知道,不会编造。不需要知识库就把 knowledge_file 设为空字符串,或删除该文件。
SDK 接受 #RRGGBB,任意颜色可用。几个高饱和推荐:
| 颜色 | 色值 |
|---|---|
| 品红 | #FF1E8A |
| 青蓝 | #00E5FF |
| 紫罗兰 | #B000FF |
| 荧光绿 | #39FF14 |
| 亮橙 | #FF7A00 |
| 宝石红 | #FF0033 |
light_zone 可选 all(全部)、side(两侧)、head(头部)、bottom(底部)。
由 light_effect 与 light_effect_period_ms 控制:
| 灯效 | 说明 |
|---|---|
rainbow |
彩虹流转,当前默认 |
breathing |
呼吸明暗 |
blink |
闪烁 |
status-pulse |
状态脉冲 |
把 light_effect 设为空字符串 "" 即可切回纯色常亮,此时 light_color 生效。
qwen3:0.6b 是 0.6B 小模型,回答较简单;换成 qwen3:4b 会更聪明但更慢。