修复已通过桌面连接的机器人仍被要求切换 SDK 控制的问题,网页和后端均兼容 desktop_link 与 python_sdk,保留在线、固件能力和单会话门禁。补齐 macOS 图形进程对 Codex/ChatGPT 自带 CLI 的发现,找不到执行文件时给出准确安装提示。保留 0.2.2 的音色选择、电脑试听与分区布局;本版声明 Windows 与 macOS 支持。详见 0.2.3 发布说明。
新增 Codex 原生音色选择和电脑试听,实时对话与动作编排分区;实体播放可配置 0–12 dB 语音增强,服务检查失败可重试。默认沿用原生音色和 0 dB 增强。包含 SDK 情绪接口兼容性预检,需使用满足 Manifest 要求的客户端运行时。
后端回归 161 项通过、4 项真实服务测试默认跳过;网页专项 53 项、类型检查和生产构建通过。真实机器人声压、与 JoyInside 同条件响度对比及真人打断仍待验收,不将增强参数等同实际声压。商店以审核后的固定快照为准。
原生 Codex 实时语音和本机工具共用同一个 app-server thread,支持任务运行中补充文字、停止任务后继续对话。机器人资源清理未完成时保留重新配对和取消入口,恢复原机器人连接后重试释放;仍禁止断开和在旧资源未释放前开启新硬件会话。
本次重新构建网页快照,使用 Workspace SDK 校验通过,Python 回归 156 项通过、4 项真实服务测试默认跳过。发布目标为 Hugging Face 国际应用商店;源码上传和商店审核提交是两步,审核通过前不视为已上架。
Daemon 管理的 Application 新增「对话设备 → 实体机器人」;独立 run-web.ps1 / run-web.sh 仍仅提供网页预览。实体接入与验收步骤见 ROBOT-INTEGRATION.md。已完成实机收音、转写、回复、播放嘴型、头部动作和会话清理验证;偶发连接断开、回声、自然插话及字幕一致性仍需复核,当前为开发候选。
实时页现在有「机器人连接」区域:显示 Daemon 当前连接状态,输入机器人「SDK 控制」屏幕的六位配对码即可连接;搜索/连接中可以取消,掉线重连中可以停止重连,在线时可以断开。电脑与机器人需在同一局域网。配对请求被接受不代表已连上,实际在线、连接状态为 connected,且处于桌面连接(desktop_link)或 SDK 控制(python_sdk)模式后自动选择实体对话;刷新页面重新读取实际状态。实体离线、重连或模式不支持时禁用开始按钮;已从桌面连接的机器人可直接复用,不必断开再配对。启动仍检查 SDK 与固件能力,不因连接模式兼容而跳过 capability 门禁。
连接管理通过认证同源 /api/robot/status|pair|cancel|disconnect 转交 Daemon 的固定管理 REST,管理地址只来自 SDK 注入的 WATCHER_APP_DEVICE_STATUS_URL,不向网页公开地址或凭据。独立 run-web 明示不支持机器人管理。会话期间禁止变更连接;资源清理未确认时允许重新配对和取消以恢复原设备,仍禁止断开。原设备恢复在线后可开始对话以重试清理。应用锁保护本页操作,不约束外部桌面或 CLI 的设备切换。
实体头部按状态选择重新设计的完整 chat_v1 动作,一次 motion.play_action 在设备本地执行;原有动作只复用 JSON parser/轨迹播放机制。移动、停留和归中按真机速率预算设计,执行中仅保留最新待选状态,等全部分段 DONE、完整动作时长和 120ms 缓冲后才能启动下一段。此功能要求固件 motion.action.once.v1,旧固件在接管音频前明确拒绝。实体模式的数字孪生在命令确认后采样同一资源,表示预计姿态;独立网页预览保留原有表现。未知起点回中仍按 0–180° 最坏行程预算。新设计、资源来源及兼容限制见 对话动作资源;ACK/DONE 不代表 ADC 实际到位。本轮新动作尚未真机部署验收。
实时用户最终语音转写与文字输入进入同一个表情导演。明确的“表演无语/伤心/生气/开心”优先于助手中性回复并保持 4 秒;否定只作用于对应分句。实体固件需 expression.audio_follow.v2,眼形保留与真实 PCM 嘴型共存,情绪执行不被长动作等待阻塞。
应用商店入口启用 Codex 实时对话,补齐独立依赖并更新网页资源。需要本机安装并登录原生 Codex CLI,开始对话时授权浏览器麦克风;Codex 原生实验语音是否可用取决于账号和客户端支持。设备动作仍为 3D 网页预览。JoyInside 配置合成仍使用独立 run-web 入口。
独立的 SDK Application。用真实 GLB 和固件表情算法预览语音、七种情绪、嘴部与两轴头部动作,内含供其他对话系统复用的行为编排核心。
网页模式提供视觉预览;实体模式通过 SDK Application 接入设备。行为核心使用本地规则且未采用强化学习。可选 JoyInside TTS 使用真实平台音色合成文字;可选 Codex 原生语音提供实时对话基准。Manifest 声明 Windows 与 macOS 平台。
同一独立 run-web.ps1 / run-web.sh 入口现在提供「和小沃,实时聊聊」。需要本机已登录的原生 Codex CLI;优先发现桌面应用随附的原生二进制,也可通过 WATCHER_CODEX_BINARY 指定。Windows 查找桌面应用安装目录;macOS 查找系统与当前用户的 Applications 中 Codex/ChatGPT 应用自带的 CLI,再回退 PATH。图形界面启动的 Application 不必继承终端的 PATH;确实未找到二进制时会直接提示安装或配置路径,不误报登录/网络问题。按「开始实时对话」后授权浏览器麦克风;取消勾选麦克风可先用文字输入验证 Codex 回答和原生语音播放。支持静音麦克风、调节声音与动作幅度、查看实际字幕和结束会话。
这是实验 Codex app-server V3 WebRTC 接入,不是稳定公开的桌面语音嵌入接口。语音前台和后台 Codex Agent 使用独立临时 thread:普通聊天由前台直接交流,需要推理的委派和文字输入由后台生成,再返回前台朗读。后台沿用本机模型/供应商配置;显式 WATCHER_CODEX_AGENT_PROVIDER 可覆盖,已配置且存在凭证的本机 opencodex 网关可被识别。前台仍使用本机 Codex 登录与原生音色。初始化字段在创建时传入,不能在 data channel 上重复修改不可变配置。
浏览器直接收发 RTC 音频,本机后端只协商 SDP、管理 Agent 和接收音频强度/字幕;不传原始麦克风 PCM 到本机 WebSocket。网页模式由 HTML audio 输出电脑声音;实体模式保留零音量媒体端点启动 Chromium 解码,再经 WebAudio 增益转交机器人。静音监测图读取同一轨道的原始强度,完全静音时强度归零,与本地播放器保持一致。40 ms 采样进入 behavior_driver/live.py。此增量适配器复用原 BehaviorDriver 的语义、情绪与轨迹,以最近字幕子句更新含义,以实际有声时间启动连续 2400 ms 手势周期;字幕更新不会重置周期,短于 240 ms 的声音间隙保留进度,长停顿平滑回中。嘴部始终采样当前声音,结束时闭合。手势周期是估算节奏,没有逐字/音素对齐,也没有强化学习。
应用商店安装后的 SDK Application 与独立 Web 启动器均提供实时入口;只有用户点击「开始实时对话」才启动 Codex。会话要求同源及首帧临时运行凭据、单实例单会话。结束、断开或启动失败会回收本机子进程、RTC、麦克风和音频上下文;异步取得的迟到麦克风资源立即关闭,不能恢复旧会话。后台 Agent 保留标准 Codex 指令,并继承本机模型、工具、插件与 MCP 配置;按用户授权,该应用的后台 thread 使用完整本机访问 danger-full-access 和执行审批策略 never,电脑命令与文件操作不再逐次审批,不修改全局 Codex 配置。语音前台将电脑查询与操作委派后台,等待实际结果后朗读。补充信息支持选项与自由输入,密码输入不会加入对话记录;仍保留服务端其他交互的具体展示和单次回复,未支持的请求明确拒绝。任务等待上限为 15 分钟;取消/超时中断原任务,不能确认中断时关闭本机进程,防止串到下一任务。具体边界见 VOICE-AGENT.md。实体模式的设备信令与动作使用 Application Device channel;音频媒体使用 SDK 协商的 RTC。
JoyInside TTS 保留独立测试入口,尚未替换原生实时声音。输出字幕与音频分别到达,字幕不能当作音频播放完成信号;原生接话/打断由语音模型处理。浏览器回声消除只是请求启用,实际人声、耳机/扬声器环境和打断体验仍须听感验收。播放诊断只统计连接、声音峰值、收到音频包与 AudioContext 状态,不记录凭证或 SDP。
常规测试不发送 Codex 请求。显式设置 WATCHER_CODEX_LIVE_TEST=1 后运行 python -m pytest tests/test_native_voice_live.py -q:使用已有登录验证同线程真实工具查询、运行中补充、自动非静音 RTC 回复、真实命令中断后保持会话。需要可选 aiortc,不访问物理麦克风或机器人;可用 WATCHER_CODEX_TEST_SPEECH 指向 8 kHz/16-bit/mono 合成录音,改验收语音触发。真人自然打断仍需现场验收。旧 test_live_codex.py 保留此前工具/RTC 基线。
先按下节构建 web/,在 Python 环境安装 app.json 声明的依赖。独立入口不会导入 SDK、拉起 Daemon、选择 Application 或连接机器人。
Windows PowerShell:
$env:WATCHER_PREVIEW_PYTHON = (Resolve-Path .venv/Scripts/python.exe).Path
./examples/speaking_motion_lab/run-web.ps1 --credentials C:/secure/joyinside-credentials.json
macOS / Linux:
WATCHER_PREVIEW_PYTHON=.venv/bin/python sh ./examples/speaking_motion_lab/run-web.sh --credentials /path/to/joyinside-credentials.json
两入口委托 preview.py,参数、默认随机端口和退出码一致;--port 可指定 loopback 端口。不传配置时仍可播放本地示例,云端合成禁用。打开终端输出的地址:页面检查当前音色,输入文字后点击「生成语音并预览」,合成成功自动装入媒体播放器、调用原行为核心并开始播放;可暂停、回到开头或下载 WAV。重建网页资源后刷新页面即可读取新的资源引用。
配置 JSON 字段为 Environment / BotId / AccessKey / SecretKey,当前只接受 Environment=production。配置文件只在本机后端读取,不复制进应用目录,不返回给前端,也不写入日志。请使用专用测试 botId;JoyInside 同 botId 的双连接会互踢。预览继承该 botId 的有效音色,不修改产品、角色或设备配置。
joyinside_tts.py 只负责云端鉴权、配置确认和 TTS;web_server.py 负责同源及运行凭据边界,SpeechPanel / ttsClient 负责输入、取消、声音下载与 UI,原 behavior_driver 保持供应商无关。单轮限制小于 1000 UTF-8 字节、音频最长 60 秒、总超时 90 秒、单实例单并发。取消浏览器请求会释放云端连接与并发锁,迟到结果不安装。
当前使用 CLIENT_INPUT_TEXT_TO_SPEECH。真实平台仍可能发送开场白生命周期、INTERRUPT 确认和本轮 AGENT 文本回显:按 mid/roundId 关联本轮,丢弃已知开场白的迟到字幕/音频/完成事件;完成字幕必须与提交文字一致,否则拒绝播放。不能把旧轮次 TTS_COMPLETE 当作本轮结束。
JoyInside 入口是「真实云端合成完成后播放」版本,尚未替换 Codex 原生实时声音。头部意图和情绪仍使用现有本地规则,字幕时间按文本与音频估算;音色一致不代表完整 JoyInside 情绪语调策略也已复现。
真实云端验收为显式选择,常规测试不发送云端请求。设置 WATCHER_JOYINSIDE_TEST_CREDENTIALS 为本机配置路径,可选 WATCHER_JOYINSIDE_EXPECTED_VOICE 校验音色名称,再执行:
python -m pytest examples/speaking_motion_lab/tests/test_live_tts.py -q
2026-10-09 验收:真实平台返回「上影哪吒-情感丰沛版」;Web API 验证真实非静音 PCM/WAV、提交文字一致、问候/肯定/否定/问句编排和结尾回中闭嘴;浏览器完成自定义文字合成、自动播放和取消测试。独立预览无需设备。浏览器播放状态不能替代用户对声音听感的确认。
当前应用独立发布,不需要将已移除的示例放回 SDK 主线。发布包自带构建好的网页、模型与 WASM,安装用户无需 Node.js。历史前端源码在客户端仓库,Python Application 和行为核心源自 SDK 实验分支。先在 workspace 的 WatcheRobot_client/Watcher Desktop App 安装现有 Node 依赖,然后执行:
npm run build:joyinside-application
生成的 web/ 包含真实模型、示例语音、WASM、许可和 web-build.json 资产哈希,不包含开发机路径。独立 Application 仓库跟踪可分发的 web/ 快照;每次制作可分发 Application 时必须重新构建,并随 Python 源码一起打包。客户端临时构建目录不提交。.watcherignore 保留 web/,排除测试、缓存与构建临时目录。
在 SDK Python 环境中运行以下跨平台命令:
watcherobot app check examples/speaking_motion_lab
watcherobot app run examples/speaking_motion_lab
Daemon 注入 ApplicationContext 的 Desktop 和 Device channel,应用开启本机随机 HTTP 端口并输出网页地址,通常自动打开浏览器。安装后的资源不依赖 Node、Vite 或客户端源码仓库。不要直接执行 app.py。
app run 会选择当前用户 Runtime 的 Application;同一 Daemon 同时只有一个 Application。应用运行时不支持的 Desktop 业务帧会被安全忽略,包括麦克风快捷键,不会绕过 Application 直达设备。需要保留桌面当前会话时,使用 SDK 文档中的自定义 App Store / run-installed 隔离验收流程。
WATCHER_BEHAVIOR_LAB_NO_BROWSER=1 可关闭自动打开浏览器;仍可使用日志地址。watcherobot app stop 停止应用和其 HTTP 服务,Daemon 继续运行。
flowchart LR
A[JoyInside / 其他 AI 对话适配器] --> B[BehaviorRequest v1]
P[网页:解码音频和填写文本] --> B
B --> C[behavior_driver:语义、情绪、节奏、轨迹]
C --> D[BehaviorPlan v1]
D --> E[网页:媒体时钟、GLB、固件表情 WASM]
D -.未来接入.-> F[设备执行适配器]
F -.Application Device channel.-> G[SDK Daemon → Device]
| 模块 | 职责 |
|---|---|
behavior_driver/contracts.py |
版本化输入与输出、边界校验、不可变数据 |
semantics.py |
本地词汇规则;外部意图可覆盖 |
planner.py |
时间对齐、情绪姿态、节奏与平滑曲线 |
driver.py |
唯一编排入口、固定步长帧和按媒体时间采样 |
live.py |
实时手势进度、字幕适配及静音收尾;复用同一规划器 |
web_server.py |
本机 HTTP 输入适配器和静态资源服务 |
application.py / app.py |
SDK 生命周期、启动和退出;不实现 Daemon |
客户端 shared/behavior-driver |
TS 合同、HTTP 客户端和已生成帧采样;不另做语义规划 |
纯核心不依赖 SDK、JoyInside、React、Three.js、HTTP 或设备连接,也不持有播放时钟。不同 AI / TTS 供应商应转换到同一输入合同。显示或设备执行只消费输出,不各自生成一套动作。
BehaviorRequest.from_dict() 接收 watche.behavior.request.v1:
from behavior_driver import BehaviorDriver, BehaviorRequest
request = BehaviorRequest.from_dict({
"schema": "watche.behavior.request.v1",
"audio": {"durationMs": 4000, "stepMs": 20, "levels": [200] * 200},
"transcript": "是的。不可以。",
"emotionMode": "auto", "emotionTarget": 0, "strength": 0.85,
"segments": [
{"text": "是的。", "startMs": 0, "endMs": 1800, "intent": "affirm", "emotion": 2},
{"text": "不可以。", "startMs": 2200, "endMs": 4000, "intent": "deny"},
],
})
driver = BehaviorDriver()
plan = driver.plan(request)
frame = driver.sample(plan, 1000) # 由调用方提供媒体时间,单位 ms
音频包络为每 20 ms 一项、范围 0–1000;最长 60 秒。文本或带时间戳片段总长最多 2000 字,片段最多 128 个,按时间排列且不重叠。意图枚举:greeting / affirm / deny / question / emphasis / neutral。情绪编号:0 平静、1 微笑、2 开心、3 生气、4 专注、5 伤心、6 无语。
有 segments 时保留外部时间戳,alignment=provided;其意图、情绪提示优先于词汇推断。emotionMode=manual 时手动情绪统一覆盖。未提供片段时按文本字数和有声时间估算对齐,标为 estimated;缺少文本时标为 no-text,只跟随声音节奏。估算不是逐字强制对齐,复杂语义可能误判。
输出 watche.behavior.plan.v1 包含片段和每 40 ms 的 BehaviorFrame:
{"timeMs": 1000, "panDeg": 90, "tiltDeg": 113, "mouthLevel": 500, "emotionTarget": 2, "speaking": true}
默认预览中位为 90° / 108°,角度范围 76–104° / 100–122°。嘴部输入放大 5 倍并限制在 1000;片段播放与实时语音共用该增益,普通音量和轻声说话也能呈现更明显的开合,静音输入仍为零。片段两端平滑回位,短片段减小动作;声音停顿时闭嘴但保留说话状态,整段结束后 speaking=false、目标情绪归零、头部回中,并保留 1200 ms 让固件表情收尾。暂停冻结媒体时钟;回到开头、倒拖或替换计划会重放固件状态。预览角度尚未完成实机标定。
网页只把包络、文本和参数发送到本机 /api/behavior/plan,原始音频在浏览器解码。接口使用该次应用运行的随机凭据和同源校验;静态服务仅暴露 web/。
默认 JoyInside 与其他 AI 对话可以提供语音包络、文本、TTS 时间戳、结构化意图/情绪,再调用同一个 BehaviorDriver。本地播放器处理完整短语音,Codex Web 入口通过 LiveBehaviorDriver 处理连续输出;JoyInside 流式队列、统一音色与设备延迟补偿仍需在会话适配层实现并验收,不能把它们隐藏在供应商专属轨迹逻辑里。
设备适配器通过当前 Application 的 Device channel,经 SDK Daemon 到设备;桌面业务进入 Application Desktop channel,不增加 Daemon 按业务 type 分流的例外。默认 JoyInside 聊天接入尚未实现;Codex 实体接入的限制与当前验收状态见 ROBOT-INTEGRATION.md。
先生成 web/,再在 SDK 环境执行:
python -m pytest examples/speaking_motion_lab/tests -q
watcherobot app check examples/speaking_motion_lab
客户端:
npm run test:joyinside-preview
npm run typecheck:joyinside-preview
npm run build:joyinside-application
Python 测试覆盖合同、语义、外部提示、时间对齐、两轴限制与连续性、同一计划确定性、HTTP 适配以及发布文件快照在 SDK Daemon 下的启动和停止。网页测试覆盖模型层级、WASM、媒体时钟、倒拖、合同客户端与构建替换。平台入口 .ps1 / .sh 委托同一 Node 实现。
2026-10-10 实时预览验收:常规 Python 57 项通过、2 项真实服务测试按默认配置跳过;网页专项 22 项、独立 TypeScript 检查及生产网页构建通过。显式真实 Codex 验收验证后台回复、非静音 RTC 输出与输出期间录音输入转写;浏览器文字请求「17 加 8」得到后台 25 及实际语音字幕「答案是二十五」,并检测到输出声音。后台模型依赖本机供应商可用性;本次沿用本机网关,单独指定 openai 的后台文字请求在测试期限内未完成,不能据此宣称所有模型配置已兼容。临时网关不能作为部署依赖,长期运行须提供持续可用的模型配置。真实人声、回声和自然打断尚待用户试听。
同日动作回归修复:原实时版本将多句文本压入短窗口,并固定采样 1200 ms,持续说话时姿态收敛到极小偏角。现保留连续手势进度,以最近子句更新语义;新增长句持续动作、流式字幕不重置进度、开心情绪及静音收尾测试,WebSocket 验收覆盖完整动作和回中。常规 Python 59 项通过、2 项真实服务验收默认跳过;网页专项 23 项、类型检查及生产构建通过。真实浏览器在默认 85% 幅度下观察到讲话时水平约 3.5°、俯仰约 3.2°,讲话结束后回中;音量不再额外缩小嘴部输入。
生成网页保留 LICENSE.KuroBlob-AI.txt 和 firmware-source.json;表情算法来自现有 ESP32 纯 C 核心,模型资产继续使用客户端原资源。可分发 Application 包必须保留这些文件。
网页的“机器人语音增强”在折叠的高级设置中,可在原声 0 dB 到 +12 dB 之间调整,提供原声 / +6 / +12 快捷对比,播放中即时生效,刷新恢复原声。只作用于实体机器人实时播放,不设置硬件音量、不改变麦克风或 Codex 原生交互;网页预览及 JoyInside 合成保持原有链路。
测试时固定设备音量、摆放距离和网页语音音量 100%,使用同一句话对比 0 dB 和 +6 dB,仍偏轻可试 +12 dB。+6 dB 约为信号幅度 2 倍,不能等同听感响度 2 倍。增强启用峰值整形,仍可能改变音色;听到失真就降低。诊断中的原声强度与原声峰值均来自增强前信号,并非分贝计。根据用户反馈,本轮将原先 +24 dB 上限收回至 +12 dB;历史高增益测量保留作调查依据。
网页“Codex 音色”从本机 App Server 读取实际支持的原生 v3 音色,默认使用服务默认值。在开始前选择,结束后重新开始生效;连接期间禁用切换。列表失败仍允许默认对话,可刷新重试。此功能需要同时部署本仓库 Python 与配套网页资源,无需升级固件或改变 Daemon 路由。
选择后可点“试听音色(电脑播放)”,通过真实 Codex 临时会话朗读固定问候,不打开麦克风。试听中可随时停止;结束、超时、服务错误会清理会话。试听期间锁定对话启动、音色切换和机器人连接管理,避免相互抢占。试听会使用当前 Codex 服务,不能用浏览器合成音代替原生音色。
2026-10-15 本机原生 v3 默认 cove,支持 juniper、maple、spruce、ember、vale、breeze、arbor、sol、cove。listVoices 的 v2 音色族不适用于当前 v3:真实 cedar 请求被拒绝后已改用 v1 音色族,Maple 实际 RTC 及非静音输出通过。未来以运行时返回列表为准,不保证其他版本名单一致。
音量诊断:当前 WebAudio 增强的强信号出现饱和;真实 Maple 片段的 +18/+24 dB 输出采样峰值曾达 1.093/1.305。峰值整形不是严格峰值保护,高增益仍可能过冲和失真,不继续以提高上限作为修复。尚未测得 JoyInside 同条件音频或机器人声压级。
实体语音复用 Daemon 已建立的 desktop_link 或 python_sdk 连接,同时要求管理服务可用、online=true 和 state=connected。设备业务继续使用当前 Application 的 Device channel;应用内配对目标仍为 python_sdk。0.2.2 的音色选择、音色列表接口和 SDK emotion 参数兼容性检查保持原有行为。
连接准入专项无需真实服务:python -B -m unittest discover -s tests -v。本轮 9 项通过(含模式与状态子用例),覆盖真实 ASGI WebSocket 准入、音色向后台传递、启动/释放、固件能力拒绝及旧 SDK 的 emotion 错误提示;不代表真实麦克风、设备出声或动作已现场复验。历史文档中提及的完整测试集未随本分发仓库提供,本次专项不替代历史全量回归。