mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-07 06:52:28 +00:00
* feat(voice): voice personality, picker catalog, and prompt layer foundation - voicePickerCatalog.ts: per-backend voice lists for Gemini and Qwen with resolve helpers (resolveGeminiLiveVoice, resolveQwenRealtimeVoice) - voicePersonality.ts: VoicePersonalityPreferences schema, presets, composed system prompt with identity/character/response-length layers - voicePromptLayers.ts: buildResolvedVoiceSystemPrompt, preset delivery snippets - voiceSystemPromptParam.ts: hub-side base64url decode for ?systemPrompt= - voicePickerPreferences.ts, voicePersonalitySession.ts: browser-side encode, decode, and storage helpers - useVoicePersonality: React hook for preferences persistence via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(voice): preset delivery included when non-balanced preset selected; restore test typecheck - isDefaultVoicePersonality: add preset check so warm/calm/direct presets trigger the delivery snippet instead of being treated as default - web/tsconfig.json: remove test file exclusion from typecheck (restoring strict coverage of test code); fix resulting type error in mock declaration via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(voice): include use_speaker_boost in ElevenLabs TTS override payload The checkbox persisted the pref but ttsDiffersFromDefault and buildElevenLabsTtsOverride both omitted it, so the setting was never sent to the agent. via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * test(voice): update speaker_boost test to assert it IS included in override The previous test asserted use_speaker_boost was omitted; now it's correctly included in the TTS payload. via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(voice): authorize use_speaker_boost in ElevenLabs override schema Add use_speaker_boost to both the VoiceAgentConfig tts override type and the buildVoiceAgentConfig() platform_settings so the field is accepted by the ElevenLabs agent runtime. via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(voice): propagate full language code through composed prompt, not just zh getDefaultVoiceSystemPrompt and resolveComposedVoiceSystemPrompt were filtering language to zh-only before passing to composeVoiceAgentPrompt. Now append buildVoiceLanguageBlock(language) after composition so French, Spanish, Japanese etc. reach Gemini/Qwen sessions correctly. via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(voice): only append language block when language explicitly set Building language block unconditionally when no language is given caused getDefaultVoiceSystemPrompt() to diverge from VOICE_SYSTEM_PROMPT. Only append the block when a code is explicitly provided. via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> * fix(voice): always include language block for Gemini/Qwen in composed prompt When auto-detect is on (language=undefined), the composed prompt sent via hub proxy was losing the language auto-detect instruction because the block was only added when language was explicitly set. Now: ElevenLabs skips the block (has its own language field); Gemini/Qwen always include it — undefined produces the auto-detect block, an explicit code produces the appropriate language instruction. via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run> --------- Co-authored-by: HAPI <noreply@hapi.run>
This commit is contained in:
@@ -444,9 +444,6 @@ export default {
|
||||
'send.blocked.title': 'Cannot send message',
|
||||
'send.blocked.noConnection': 'Not connected to server',
|
||||
'resume.failed.title': 'Resume failed',
|
||||
'resume.unavailable.noTarget': 'This session cannot be resumed. Start a new session in this directory.',
|
||||
'session.inactive.autoResume': 'Session is inactive. Sending will resume it automatically.',
|
||||
'session.inactive.cannotResume': 'Session is inactive and cannot be resumed from here. Start a new session in this directory.',
|
||||
'toast.ready.title': 'Ready for input',
|
||||
'toast.ready.body': '{agent} is waiting in {session}',
|
||||
'toast.permission.title': 'Permission Request',
|
||||
@@ -496,10 +493,88 @@ export default {
|
||||
'settings.chat.surfaceColor.softYellow': 'Soft yellow',
|
||||
'settings.chat.surfaceColor.custom': 'Custom color',
|
||||
'settings.voice.title': 'Voice Assistant',
|
||||
'settings.voice.sounds.title': 'How It Sounds',
|
||||
'settings.voice.responds.title': 'How It Responds',
|
||||
'settings.voice.connection.title': 'Connection & provider',
|
||||
'settings.voice.behaves.title': 'How it behaves',
|
||||
'settings.voice.persona.title': 'Persona & instructions',
|
||||
'settings.voice.advanced.section.title': 'Advanced',
|
||||
'settings.voice.responseLength.label': 'Response length',
|
||||
'settings.voice.responseLength.brief': 'Brief',
|
||||
'settings.voice.responseLength.balanced': 'Balanced',
|
||||
'settings.voice.responseLength.detailed': 'Detailed',
|
||||
'settings.voice.responseLength.brief.hint': 'Keep answers to 1–2 sentences.',
|
||||
'settings.voice.responseLength.balanced.hint': 'Default — the assistant judges length by context.',
|
||||
'settings.voice.responseLength.detailed.hint': 'Give thorough answers when depth is useful.',
|
||||
'settings.voice.opening.label': 'Opening',
|
||||
'settings.voice.opening.greet': 'Greet me',
|
||||
'settings.voice.opening.brief': 'Brief me',
|
||||
'settings.voice.opening.greet.hint': 'Assistant says hello and waits for you to speak.',
|
||||
'settings.voice.opening.brief.hint': 'Assistant summarises agent activity when you connect.',
|
||||
'settings.voice.group.label': 'Voice settings',
|
||||
'settings.voice.group.hint': 'Language and voice options apply to the selected backend.',
|
||||
'settings.voice.backend': 'Voice backend',
|
||||
'settings.voice.language': 'Voice Language',
|
||||
'settings.voice.autoDetect': 'Auto-detect',
|
||||
'settings.voice.voice': 'Voice',
|
||||
'settings.voice.voiceDefault': 'Default',
|
||||
'settings.voice.advanced.title': 'Advanced voice settings',
|
||||
'settings.voice.advanced.hint': 'Identity, character, fixtures, sliders. Defaults are fine — open only if you want to retune.',
|
||||
'settings.voice.advanced.customizedBadge': 'customized',
|
||||
'settings.voice.fixtures.title': 'Platform rules (read-only)',
|
||||
'settings.voice.fixtures.hint': 'Shipped with the app: tools, routing, TTS rules. Updated when you upgrade HAPI — not editable here.',
|
||||
'settings.voice.identity.title': 'Identity & brand',
|
||||
'settings.voice.identity.hint': 'Who the voice assistant is. HAPI is the app; rename or rebrand the persona here (e.g. overseer). Provider guardrails are always applied separately.',
|
||||
'settings.voice.identity.reset': 'Reset identity',
|
||||
'settings.voice.identity.default': 'Bundled default identity',
|
||||
'settings.voice.identity.customized': 'Custom identity',
|
||||
'settings.voice.character.promptTitle': 'Character & speaking style',
|
||||
'settings.voice.character.promptHint': 'Tone and style. Preset delivery text merges here when character is empty. Composed with platform rules at runtime on all voice backends.',
|
||||
'settings.voice.character.reset': 'Reset character',
|
||||
'settings.voice.character.appendPreset': 'Append preset delivery text',
|
||||
'settings.voice.layers.resetAll': 'Reset identity & character',
|
||||
'settings.voice.layers.composedNote': 'Runtime prompt = platform rules + your identity + character (all backends).',
|
||||
'settings.voice.wireBudget.elevenlabs': 'ElevenLabs sends composed instructions on connect; session history is bootstrapped then streamed.',
|
||||
'settings.voice.wireBudget.gemini': 'Gemini Live uses the same composed instructions via the hub proxy.',
|
||||
'settings.voice.wireBudget.qwen': 'Qwen Realtime uses the same composed instructions in session.update.',
|
||||
'settings.voice.wireBudget.storage': 'Local storage budget (chars):',
|
||||
'settings.voice.wireBudget.elevenlabsLimits': 'Wire caps: ~{msg} B per WebRTC message; composed prompt budget ~{prompt} B.',
|
||||
'settings.voice.wireBudget.promptTruncated': 'Your composed prompt was shortened to fit the ElevenLabs wire budget. Shorten identity/character or we will trim further on connect.',
|
||||
'settings.voice.wireBudget.composedSize': 'Last composed prompt size',
|
||||
'settings.voice.contextNotice': 'Last voice session',
|
||||
'settings.voice.character.title': 'Speaking style preset',
|
||||
'settings.voice.character.presetSlidersHint': 'Presets adjust ElevenLabs TTS sliders and optional delivery wording (character layer).',
|
||||
'settings.voice.character.preset.label': 'Preset',
|
||||
'settings.voice.character.preset.balanced': 'Balanced',
|
||||
'settings.voice.character.preset.balancedHint': 'Warm and focused — good for everyday task work.',
|
||||
'settings.voice.character.preset.warm': 'Warm & expressive',
|
||||
'settings.voice.character.preset.warmHint': 'More animated delivery; ElevenLabs audio tags when available.',
|
||||
'settings.voice.character.preset.calm': 'Calm',
|
||||
'settings.voice.character.preset.calmHint': 'Slow, measured tone for long or late sessions.',
|
||||
'settings.voice.character.preset.direct': 'Direct',
|
||||
'settings.voice.character.preset.directHint': 'Terse and efficient — minimal filler.',
|
||||
'settings.voice.character.preset.custom': 'Custom',
|
||||
'settings.voice.character.preset.customHint': 'You control sliders and the system prompt above.',
|
||||
'settings.voice.tuning.title': 'Acoustic tuning',
|
||||
'settings.voice.tuning.elevenlabs': 'ElevenLabs',
|
||||
'settings.voice.tuning.gemini': 'Gemini Live',
|
||||
'settings.voice.tuning.stability': 'Stability',
|
||||
'settings.voice.tuning.stabilityHint': 'Lower = more dynamic; higher = steadier.',
|
||||
'settings.voice.tuning.expressiveness': 'Expressiveness',
|
||||
'settings.voice.tuning.expressivenessHint': 'Style exaggeration (ElevenLabs style).',
|
||||
'settings.voice.tuning.speakingRate': 'Speaking rate',
|
||||
'settings.voice.tuning.speakingRateHint': '0.7–1.2× (ElevenLabs API).',
|
||||
'settings.voice.tuning.similarity': 'Similarity boost',
|
||||
'settings.voice.tuning.similarityHint': 'Closer match to the trained voice.',
|
||||
'settings.voice.tuning.speakerBoost': 'Speaker boost',
|
||||
'settings.voice.tuning.affectiveDialog': 'Affective dialog',
|
||||
'settings.voice.tuning.affectiveDialogHint': 'Adapt delivery to your tone (Gemini v1alpha).',
|
||||
'settings.voice.tuning.qwenHint': 'Qwen has no TTS sliders here — edit the voice system prompt above; emotion adapts from your speech.',
|
||||
'settings.voice.tuning.selectBackend': 'Per-backend sliders appear when a voice backend is selected.',
|
||||
'settings.voice.preview.elevenlabsOnly': 'Voice preview is only available for ElevenLabs',
|
||||
'settings.voice.preview.unavailable': 'Preview unavailable without an ElevenLabs API key',
|
||||
'settings.voice.staticCatalogHint': 'Open the list to see voice character notes. Audio preview is ElevenLabs only.',
|
||||
'settings.voice.session.label': 'Session behavior',
|
||||
'settings.voice.proactive': 'Start voice session with summary',
|
||||
'settings.voice.proactive.description': 'When on, starting a voice session opens with a spoken summary of current agent activity. When off, the assistant greets you and waits for you to speak.',
|
||||
'settings.about.title': 'About',
|
||||
|
||||
Reference in New Issue
Block a user