Blizzard
c66d178efe
fix(voice): 思考看门狗覆盖 PTT 模式(别永远卡在"思考中")
...
此前 armThinkTimer 只在连续对话模式挂,PTT 下后端不回(dispatcher 未就绪/
模型没配/任务失败)就永远卡在"思考中",用户干等且毫无线索。
改:任何模式收到 final 转写都挂看门狗;超时后连续对话回聆听、PTT 回待命,
并明确提示可能原因 + 引导去运行页看任务状态。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-07-25 14:57:18 +08:00
Blizzard
e60679ed7b
fix(voice): PTT 改为主交互——按住说话松开发送(修 PTT 形同虚设的 bug)
...
VAD 自动断句在真实环境不够稳(环境音/停顿都会误触发),改回按住说话。
修掉 PTT 之前根本不生效的三处:
- keydown 里 `if (!c) return`——用户没先点过麦克风按钮时 clientRef 为 null,
按空格什么都不发生。改为懒建客户端(keydown 本身就是用户手势,可启 AudioContext)
- 被 `!inConversation()` 挡着:一旦点过麦进了连续对话,PTT 永久失效。改为 PTT 优先,
必要时先退出对话模式
- 缺 e.repeat 守卫:按住不放会连发 keydown
交互统一为一套 PTT 语义:
- 按住空格 / 按住麦克风按钮(pointer 事件,覆盖鼠标触控) → 说话,松开发送
- 朗读中按按钮 = 打断
- 指针滑出/取消/窗口失焦都算松开,不会卡在录音态
- 录音中按钮变红缩小 + 电平条 + 呼吸环,一眼可见"正在听"
顺带:松开后标签改为"已停止收音"(准确说法——麦克风硬件仍开着以便快速重按,
只是不再上传音频,门控在 shouldSendMic);删掉已无人使用的 micTapAction 及其单测。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-07-25 14:52:26 +08:00
Blizzard
52988af196
feat(voice): 按住空格键语音输入(PTT),松开发送
...
按住空格键开始聆听,松开发送 end 指令提交任务。不销毁麦克风上下文,
下次重按直接复用,避免 getUserMedia/AudioContext 重建延迟。
支持输入框/文本区内不抢空格、窗口失焦自动取消。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-07-24 21:03:27 +08:00
Blizzard
aba88193d8
feat(voice): 提升桌面端语音交互与本地任务执行支持
2026-07-24 16:40:25 +08:00
Blizzard
b8095688ba
fix(voice): TTS 只播前几字就断——tts_end 别打断,等排队音频放完
...
火山合成远快于真实语速:一句话的 PCM 秒级全推到客户端,被 nextStart
预约到未来时刻顺序播。此前 tts_end 直接 resetPlayback() stop 掉所有还
没播的 source,于是只听到前三四个字就断。
改:tts_end 走 drainThenReady()——不打断,按 nextStart 算剩余时长等排队
音频自然放完,末段结束再回 ready;speaking 态维持到真播完(HUD 频谱靠它)。
resetPlayback 只留给 barge-in/close,并清 drainTimer 防迟到定时器改状态。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-23 09:01:02 +08:00
Blizzard
a4b9897eaf
fix(voice): 麦克风打不开时给准确提示——多约束尝试 + 无设备预检
...
- 无麦克风设备(如 Mac Studio/Mini 无内置麦)时,getUserMedia 会以 OverconstrainedError
"Invalid constraint" 误导报错;先 enumerateDevices 预检 audioinput,没有就直说"没检测到麦克风"
- getUserMedia 依次试 {audio:true}/{audio:{}}/带回声消除,全败则暴露真实错误名;
NotAllowedError 单独提示去系统设置授权
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 14:56:08 +08:00
Blizzard
fe5c4215f7
fix(voice): 麦克风约束兜底——WKWebView 不认高级约束("Invalid constraint")退 {audio:true}
...
原生壳(Wails WKWebView)的 getUserMedia 不认 channelCount/echoCancellation 等高级约束,
抛 "Invalid constraint"。先试高级约束(浏览器更好),失败退回最简 {audio:true}(最兼容)。
配合上一提交的 .app 打包+NSMicrophoneUsageDescription,原生壳麦克风打通。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 14:47:19 +08:00
Blizzard
92341be32c
fix(desktop): 麦克风优雅降级 + Info.plist 加 NSMicrophoneUsageDescription
...
- voice.ts: startMic 前探测 navigator.mediaDevices?.getUserMedia——WKWebView(原生壳)非安全
上下文里它可能未暴露,直接调会抛 "undefined is not an object" 崩掉;改为给可读提示
- build/darwin/Info.plist + Info.dev.plist: 加 NSMicrophoneUsageDescription,否则 macOS
不会授权麦克风(package 后的 .app 才能弹权限)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 14:44:27 +08:00
Blizzard
2a743a33f6
feat(desktop): 全屏「JARVIS 模式」HUD——钢铁侠风,接真实语音音频
...
弧反应堆核心 + 同心旋转环 + 随真实声音反应的环形频谱 + 状态编排 + HUD 边框/扫描线/网格。
可视化数据全来自真实语音会话(不是模拟)。
- voice.ts: micCtx/playCtx 各挂 AnalyserNode + level()——说话读下行TTS、其余读麦克风,
实时电平 0..1(HUD 每帧读,复用缓冲)
- JarvisHud.tsx: Canvas 2D HUD,按 VoiceState 编排(待命呼吸/聆听炸开/思考散粒子+雷达/说话频谱),
单一青色强调+思考态琥珀;显示助手名(星期五)+ 我说的 + 打字机回答;尊重 prefers-reduced-motion
- VoiceDock: 加"全屏 JARVIS 模式"按钮(建客户端+拉名字);Esc 退出
真机验证:全屏 HUD 正常渲染,STANDBY 呼吸,品牌位显示自定义名"星期五"。晚上点中心说话即随真声反应。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 14:28:39 +08:00
Blizzard
99ce07c1b0
feat(voice): 每用户 JARVIS——自定义名字/人设 + 自带豆包配置回落 + 语音不串主记忆
...
把 JARVIS 做成每用户独立:名字(你叫JARVIS别人叫星期五)、人设(与主偏好记忆分开)、
可自带豆包配置(齐全则用用户的,否则回落系统)。
- store/user_jarvis.go: sundynix_user_jarvis(user_id唯一;name/persona/火山creds,APIKey密文)
+ Get/Save(upsert) + AutoMigrate 注册
- voice_config.go resolveJarvis(uid): 火山配置用户优先系统兜底 + 取名字/人设
- voice_task.go: voiceSystemPrompt(name,persona)——简短是硬基线,名字/语气由用户定;
buildVoiceGraph 带 name+persona;voice.go 会话升级时按用户解析
- dispatcher compose_compiler: 语音任务(useVoice)不拉主偏好记忆,改用用户 persona(保留短期历史)
- jarvis.go + 路由: GET/PUT /api/v1/me/jarvis(用户级,api_key 脱敏/留空沿用)
真机验证:设 name=星期五+干净人设→语音答"我是星期五…"(自称新名、无糙话、4.4s),
has_own_voice=false 用系统豆包。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 14:06:32 +08:00
Blizzard
b6927247da
feat(voice): 下行打字机文本流 + 首块快出,即时反馈
...
- protocol.go: 新增 ServerReply("reply") 消息——Agent 回答增量文本
- voice_tts.go: token 一到即转发客户端(打字机),同时攒句喂 TTS(音频随后)
- sentence_buffer.go: 本轮首句用低阈值(5 rune)抢首字延迟,之后回常规 12
- 桌面端 voice.ts onReply + VoiceDock 对话气泡(我说的 + JARVIS 打字机回答,思考态光标)
管线已最优:文字在 LLM 首 token 即刻上屏、音频紧随。剩余时延=大模型 TTFT(deepseek-v4-pro
4-7s 且波动大,疑似推理模型),这是模型的账、非管线——真要"马上响应"需换快模型。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 11:25:20 +08:00
Blizzard
9458bf21f3
feat(voice): 桌面端 JARVIS 语音坞——麦克风上行 + TTS 播放队列(Phase 1 收口)
...
右下角悬浮麦克风:点按说话→转写→提交任务→跳运行页→朗读回答,接入既有运行·观测流。
- lib/voice.ts: VoiceClient——一条 WS 承载上行 PCM16k/下行转写/下行 TTS PCM24k;
ScriptProcessorNode 采麦(48k→16k 降采样+Float32→Int16);AudioBufferSourceNode
排队调度做无缝连续朗读;start/end/barge_in/bye 控制;ready/transcript/task/speaking/tts_end
- shell/VoiceDock.tsx: 悬浮麦克风 UI(聆听/思考/朗读态 + 转写气泡 + 打断),懒建客户端(用户手势启 AudioContext)
- App.tsx: onVoiceTask 把语音 task 挂回 attachRun(后端已提交,前端只 attach);挂载 VoiceDock
真识别/合成需部署联调(真连火山+admin录入语音配置);本地过 tsc/build/68 测试。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-22 09:29:47 +08:00