* feat: 集成豆包 ASR 语音识别后端,支持 /voice doubao 切换 - 新增 src/services/doubaoSTT.ts 适配模块,将 doubaoime-asr 的 AsyncGenerator 协议适配为现有 VoiceStreamConnection 接口 - /voice doubao 启用豆包后端,/voice 使用默认 Anthropic 后端 - 后端选择持久化到 settings.json 的 voiceProvider 字段 - 豆包后端跳过 Anthropic OAuth 认证、语言限制和 Focus Mode - 豆包后端松手即出结果,跳过 processing 状态 - 凭证文件存放在 ~/.claude/tts/doubao/credentials.json - doubaoime-asr 作为 optionalDependencies 安装 - 移除 /voice 命令的 claude-ai 可用性限制,所有用户可用 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: 更新 Voice Mode 文档,添加豆包 ASR 后端说明和致谢 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
29 lines
1.2 KiB
TypeScript
29 lines
1.2 KiB
TypeScript
import { useMemo } from 'react'
|
|
import { useAppState } from '../state/AppState.js'
|
|
import {
|
|
hasVoiceAuth,
|
|
isVoiceGrowthBookEnabled,
|
|
} from '../voice/voiceModeEnabled.js'
|
|
|
|
/**
|
|
* Combines user intent (settings.voiceEnabled) with auth + GB kill-switch.
|
|
* When using Doubao backend, auth check is skipped (Doubao has its own credentials).
|
|
* Only the auth half is memoized on authVersion — it's the expensive one
|
|
* (cold getClaudeAIOAuthTokens memoize → sync `security` spawn, ~60ms/call,
|
|
* ~180ms total in profile v5 when token refresh cleared the cache mid-session).
|
|
* GB is a cheap cached-map lookup and stays outside the memo so a mid-session
|
|
* kill-switch flip still takes effect on the next render.
|
|
*/
|
|
export function useVoiceEnabled(): boolean {
|
|
const userIntent = useAppState(s => s.settings.voiceEnabled === true)
|
|
const provider = useAppState(s => s.settings.voiceProvider)
|
|
// All hooks must be called unconditionally (Rules of Hooks)
|
|
const authVersion = useAppState(s => s.authVersion)
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
const authed = useMemo(hasVoiceAuth, [authVersion])
|
|
if (provider === 'doubao') {
|
|
return userIntent && isVoiceGrowthBookEnabled()
|
|
}
|
|
return userIntent && authed && isVoiceGrowthBookEnabled()
|
|
}
|