mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-06-22 08:03:52 +08:00
feat(hermes): add tts voice controls
This commit is contained in:
@@ -303,6 +303,28 @@ const STT_DEFAULTS = {
|
||||
sttMistralModel: 'voxtral-mini-latest',
|
||||
}
|
||||
|
||||
const TTS_VOICE_DEFAULTS = {
|
||||
ttsProvider: 'edge',
|
||||
ttsEdgeVoice: 'en-US-AriaNeural',
|
||||
ttsOpenaiModel: 'gpt-4o-mini-tts',
|
||||
ttsOpenaiVoice: 'alloy',
|
||||
ttsElevenlabsVoiceId: 'pNInz6obpgDQGcFmaJgB',
|
||||
ttsElevenlabsModelId: 'eleven_multilingual_v2',
|
||||
ttsXaiVoiceId: 'eve',
|
||||
ttsXaiLanguage: 'en',
|
||||
ttsXaiSampleRate: 24000,
|
||||
ttsXaiBitRate: 128000,
|
||||
ttsMistralModel: 'voxtral-mini-tts-2603',
|
||||
ttsMistralVoiceId: 'c69964a6-ab8b-4f8a-9465-ec0925096ec8',
|
||||
ttsPiperVoice: 'en_US-lessac-medium',
|
||||
voiceRecordKey: 'ctrl+b',
|
||||
voiceMaxRecordingSeconds: 120,
|
||||
voiceAutoTts: false,
|
||||
voiceBeepEnabled: true,
|
||||
voiceSilenceThreshold: 200,
|
||||
voiceSilenceDuration: 3,
|
||||
}
|
||||
|
||||
const TERMINAL_DEFAULTS = {
|
||||
terminalBackend: 'local',
|
||||
terminalCwd: '.',
|
||||
@@ -339,6 +361,8 @@ const STT_PROVIDERS = ['auto', 'local', 'groq', 'openai', 'mistral']
|
||||
const STT_LOCAL_MODELS = ['tiny', 'base', 'small', 'medium', 'large-v3', 'turbo']
|
||||
const STT_OPENAI_MODELS = ['whisper-1', 'gpt-4o-mini-transcribe', 'gpt-4o-transcribe']
|
||||
const STT_MISTRAL_MODELS = ['voxtral-mini-latest', 'voxtral-mini-2602']
|
||||
const TTS_PROVIDERS = ['edge', 'elevenlabs', 'openai', 'xai', 'minimax', 'mistral', 'gemini', 'neutts', 'kittentts', 'piper']
|
||||
const TTS_OPENAI_VOICES = ['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer']
|
||||
const UNAUTHORIZED_DM_BEHAVIORS = ['pair', 'ignore']
|
||||
const IMAGE_INPUT_MODES = ['auto', 'native', 'text']
|
||||
const REASONING_EFFORTS = ['xhigh', 'high', 'medium', 'low', 'minimal', 'none']
|
||||
@@ -399,6 +423,7 @@ export function render() {
|
||||
let privacyValues = { ...PRIVACY_DEFAULTS }
|
||||
let browserValues = { ...BROWSER_DEFAULTS }
|
||||
let sttValues = { ...STT_DEFAULTS }
|
||||
let ttsVoiceValues = { ...TTS_VOICE_DEFAULTS }
|
||||
let terminalValues = { ...TERMINAL_DEFAULTS }
|
||||
let loading = true
|
||||
let runtimeLoading = true
|
||||
@@ -437,6 +462,7 @@ export function render() {
|
||||
let privacyLoading = true
|
||||
let browserLoading = true
|
||||
let sttLoading = true
|
||||
let ttsVoiceLoading = true
|
||||
let terminalLoading = true
|
||||
let saving = false
|
||||
let runtimeSaving = false
|
||||
@@ -475,6 +501,7 @@ export function render() {
|
||||
let privacySaving = false
|
||||
let browserSaving = false
|
||||
let sttSaving = false
|
||||
let ttsVoiceSaving = false
|
||||
let terminalSaving = false
|
||||
let error = null
|
||||
let runtimeError = null
|
||||
@@ -513,6 +540,7 @@ export function render() {
|
||||
let privacyError = null
|
||||
let browserError = null
|
||||
let sttError = null
|
||||
let ttsVoiceError = null
|
||||
let terminalError = null
|
||||
|
||||
function esc(value) {
|
||||
@@ -524,7 +552,7 @@ export function render() {
|
||||
}
|
||||
|
||||
function isBusy() {
|
||||
return loading || runtimeLoading || sessionsMaintenanceLoading || updatesLoading || compressionLoading || promptCachingLoading || openrouterCacheLoading || providerRoutingLoading || auxiliaryLoading || toolGuardrailsLoading || memoryLoading || skillsLoading || curatorLoading || quickCommandsLoading || modelLoading || modelAliasesLoading || hooksLoading || providerOverridesLoading || mcpServersLoading || agentToolsetsLoading || platformToolsetsLoading || agentRuntimeLoading || unauthorizedDmLoading || securityLoading || displayLoading || humanDelayLoading || kanbanLoading || streamingLoading || executionLimitsLoading || ioSafetyLoading || checkpointsLoading || cronLoading || loggingLoading || approvalsLoading || privacyLoading || browserLoading || sttLoading || terminalLoading || saving || runtimeSaving || sessionsMaintenanceSaving || updatesSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || curatorSaving || quickCommandsSaving || modelSaving || modelAliasesSaving || hooksSaving || providerOverridesSaving || mcpServersSaving || agentToolsetsSaving || platformToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || securitySaving || displaySaving || humanDelaySaving || kanbanSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving || cronSaving || loggingSaving || approvalsSaving || privacySaving || browserSaving || sttSaving || terminalSaving
|
||||
return loading || runtimeLoading || sessionsMaintenanceLoading || updatesLoading || compressionLoading || promptCachingLoading || openrouterCacheLoading || providerRoutingLoading || auxiliaryLoading || toolGuardrailsLoading || memoryLoading || skillsLoading || curatorLoading || quickCommandsLoading || modelLoading || modelAliasesLoading || hooksLoading || providerOverridesLoading || mcpServersLoading || agentToolsetsLoading || platformToolsetsLoading || agentRuntimeLoading || unauthorizedDmLoading || securityLoading || displayLoading || humanDelayLoading || kanbanLoading || streamingLoading || executionLimitsLoading || ioSafetyLoading || checkpointsLoading || cronLoading || loggingLoading || approvalsLoading || privacyLoading || browserLoading || sttLoading || ttsVoiceLoading || terminalLoading || saving || runtimeSaving || sessionsMaintenanceSaving || updatesSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || curatorSaving || quickCommandsSaving || modelSaving || modelAliasesSaving || hooksSaving || providerOverridesSaving || mcpServersSaving || agentToolsetsSaving || platformToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || securitySaving || displaySaving || humanDelaySaving || kanbanSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving || cronSaving || loggingSaving || approvalsSaving || privacySaving || browserSaving || sttSaving || ttsVoiceSaving || terminalSaving
|
||||
}
|
||||
|
||||
function option(labelKey, value, selected) {
|
||||
@@ -2271,6 +2299,112 @@ export function render() {
|
||||
`
|
||||
}
|
||||
|
||||
function renderTtsVoicePanel() {
|
||||
const disabled = loading || saving || ttsVoiceLoading || ttsVoiceSaving || sttSaving || approvalsSaving || cronSaving || loggingSaving || privacySaving || browserSaving || terminalSaving || runtimeSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || providerOverridesSaving || agentToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || streamingSaving || executionLimitsSaving || ioSafetySaving || checkpointsSaving
|
||||
return `
|
||||
<div class="hm-panel hm-config-runtime-panel hm-config-tts-voice-panel">
|
||||
<div class="hm-panel-header">
|
||||
<div>
|
||||
<div class="hm-panel-title">${t('engine.hermesTtsVoiceConfigTitle')}</div>
|
||||
<div class="hm-channel-panel-desc">${t('engine.hermesTtsVoiceConfigDesc')}</div>
|
||||
</div>
|
||||
<div class="hm-panel-actions">
|
||||
<span class="hm-muted">${ttsVoiceSaving ? t('engine.hermesConfigStatusSaving') : ttsVoiceLoading ? t('engine.hermesConfigStatusLoading') : t('engine.hermesTtsVoiceConfigStatusReady')}</span>
|
||||
<button class="hm-btn hm-btn--cta hm-btn--sm" id="hm-tts-voice-save" ${disabled ? 'disabled' : ''}>${t('engine.hermesTtsVoiceConfigSave')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hm-panel-body">
|
||||
${renderError(ttsVoiceError)}
|
||||
<div class="hm-config-check-grid">
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-voice-auto-tts" type="checkbox" ${ttsVoiceValues.voiceAutoTts ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesVoiceConfigAutoTts')}</span>
|
||||
</label>
|
||||
<label class="hm-channel-check">
|
||||
<input id="hm-voice-beep-enabled" type="checkbox" ${ttsVoiceValues.voiceBeepEnabled ? 'checked' : ''} ${disabled ? 'disabled' : ''}>
|
||||
<span>${t('engine.hermesVoiceConfigBeepEnabled')}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-config-runtime-grid hm-config-tts-grid">
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigProvider')}</span>
|
||||
<select id="hm-tts-provider" class="hm-input" ${disabled ? 'disabled' : ''}>
|
||||
${TTS_PROVIDERS.map(provider => option(`engine.hermesTtsConfigProvider_${provider}`, provider, ttsVoiceValues.ttsProvider)).join('')}
|
||||
</select>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigEdgeVoice')}</span>
|
||||
<input id="hm-tts-edge-voice" class="hm-input" placeholder="en-US-AriaNeural" value="${esc(ttsVoiceValues.ttsEdgeVoice)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigOpenaiModel')}</span>
|
||||
<input id="hm-tts-openai-model" class="hm-input" placeholder="gpt-4o-mini-tts" value="${esc(ttsVoiceValues.ttsOpenaiModel)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigOpenaiVoice')}</span>
|
||||
<select id="hm-tts-openai-voice" class="hm-input" ${disabled ? 'disabled' : ''}>
|
||||
${TTS_OPENAI_VOICES.map(voice => option(`engine.hermesTtsConfigOpenaiVoice_${voice}`, voice, ttsVoiceValues.ttsOpenaiVoice)).join('')}
|
||||
</select>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigElevenlabsVoiceId')}</span>
|
||||
<input id="hm-tts-elevenlabs-voice-id" class="hm-input" placeholder="pNInz6obpgDQGcFmaJgB" value="${esc(ttsVoiceValues.ttsElevenlabsVoiceId)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigElevenlabsModelId')}</span>
|
||||
<input id="hm-tts-elevenlabs-model-id" class="hm-input" placeholder="eleven_multilingual_v2" value="${esc(ttsVoiceValues.ttsElevenlabsModelId)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigXaiVoiceId')}</span>
|
||||
<input id="hm-tts-xai-voice-id" class="hm-input" placeholder="eve" value="${esc(ttsVoiceValues.ttsXaiVoiceId)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigXaiLanguage')}</span>
|
||||
<input id="hm-tts-xai-language" class="hm-input" placeholder="en" value="${esc(ttsVoiceValues.ttsXaiLanguage)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigXaiSampleRate')}</span>
|
||||
<input id="hm-tts-xai-sample-rate" class="hm-input" type="number" inputmode="numeric" min="8000" max="192000" step="1000" value="${esc(ttsVoiceValues.ttsXaiSampleRate)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigXaiBitRate')}</span>
|
||||
<input id="hm-tts-xai-bit-rate" class="hm-input" type="number" inputmode="numeric" min="16000" max="512000" step="1000" value="${esc(ttsVoiceValues.ttsXaiBitRate)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigMistralModel')}</span>
|
||||
<input id="hm-tts-mistral-model" class="hm-input" placeholder="voxtral-mini-tts-2603" value="${esc(ttsVoiceValues.ttsMistralModel)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigMistralVoiceId')}</span>
|
||||
<input id="hm-tts-mistral-voice-id" class="hm-input" placeholder="c69964a6-ab8b-4f8a-9465-ec0925096ec8" value="${esc(ttsVoiceValues.ttsMistralVoiceId)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTtsConfigPiperVoice')}</span>
|
||||
<input id="hm-tts-piper-voice" class="hm-input" placeholder="en_US-lessac-medium" value="${esc(ttsVoiceValues.ttsPiperVoice)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesVoiceConfigRecordKey')}</span>
|
||||
<input id="hm-voice-record-key" class="hm-input" placeholder="ctrl+b" value="${esc(ttsVoiceValues.voiceRecordKey)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesVoiceConfigMaxRecordingSeconds')}</span>
|
||||
<input id="hm-voice-max-recording-seconds" class="hm-input" type="number" inputmode="numeric" min="1" max="3600" step="1" value="${esc(ttsVoiceValues.voiceMaxRecordingSeconds)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesVoiceConfigSilenceThreshold')}</span>
|
||||
<input id="hm-voice-silence-threshold" class="hm-input" type="number" inputmode="numeric" min="0" max="32767" step="1" value="${esc(ttsVoiceValues.voiceSilenceThreshold)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesVoiceConfigSilenceDuration')}</span>
|
||||
<input id="hm-voice-silence-duration" class="hm-input" type="number" inputmode="decimal" min="0.1" max="60" step="0.1" value="${esc(ttsVoiceValues.voiceSilenceDuration)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-channel-footnote">${t('engine.hermesTtsVoiceConfigFootnote')}</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
function renderTerminalPanel() {
|
||||
const disabled = loading || saving || terminalLoading || terminalSaving || approvalsSaving || cronSaving || loggingSaving || browserSaving || sttSaving || runtimeSaving || compressionSaving || promptCachingSaving || openrouterCacheSaving || providerRoutingSaving || auxiliarySaving || toolGuardrailsSaving || memorySaving || skillsSaving || quickCommandsSaving || providerOverridesSaving || agentToolsetsSaving || agentRuntimeSaving || unauthorizedDmSaving || streamingSaving || executionLimitsSaving || checkpointsSaving
|
||||
return `
|
||||
@@ -2425,6 +2559,7 @@ export function render() {
|
||||
${renderPrivacyPanel()}
|
||||
${renderBrowserPanel()}
|
||||
${renderSttPanel()}
|
||||
${renderTtsVoicePanel()}
|
||||
${renderCompressionPanel()}
|
||||
${renderPromptCachingPanel()}
|
||||
${renderOpenrouterCachePanel()}
|
||||
@@ -2503,6 +2638,7 @@ export function render() {
|
||||
el.querySelector('#hm-privacy-save')?.addEventListener('click', savePrivacyConfig)
|
||||
el.querySelector('#hm-browser-save')?.addEventListener('click', saveBrowserConfig)
|
||||
el.querySelector('#hm-stt-save')?.addEventListener('click', saveSttConfig)
|
||||
el.querySelector('#hm-tts-voice-save')?.addEventListener('click', saveTtsVoiceConfig)
|
||||
el.querySelector('#hm-terminal-save')?.addEventListener('click', saveTerminal)
|
||||
}
|
||||
|
||||
@@ -2691,6 +2827,11 @@ export function render() {
|
||||
sttValues = { ...STT_DEFAULTS, ...(data?.values || {}) }
|
||||
}
|
||||
|
||||
async function loadTtsVoiceConfig() {
|
||||
const data = await api.hermesTtsVoiceConfigRead()
|
||||
ttsVoiceValues = { ...TTS_VOICE_DEFAULTS, ...(data?.values || {}) }
|
||||
}
|
||||
|
||||
async function loadTerminal() {
|
||||
const data = await api.hermesTerminalConfigRead()
|
||||
terminalValues = { ...TERMINAL_DEFAULTS, ...(data?.values || {}) }
|
||||
@@ -2734,6 +2875,7 @@ export function render() {
|
||||
privacyLoading = true
|
||||
browserLoading = true
|
||||
sttLoading = true
|
||||
ttsVoiceLoading = true
|
||||
terminalLoading = true
|
||||
error = null
|
||||
runtimeError = null
|
||||
@@ -2771,6 +2913,7 @@ export function render() {
|
||||
privacyError = null
|
||||
browserError = null
|
||||
sttError = null
|
||||
ttsVoiceError = null
|
||||
terminalError = null
|
||||
draw()
|
||||
try {
|
||||
@@ -2932,6 +3075,14 @@ export function render() {
|
||||
sttLoading = false
|
||||
draw()
|
||||
}
|
||||
try {
|
||||
await loadTtsVoiceConfig()
|
||||
} catch (err) {
|
||||
ttsVoiceError = humanizeError(err, t('engine.hermesTtsVoiceConfigLoadFailed') || 'Load speech output config failed')
|
||||
} finally {
|
||||
ttsVoiceLoading = false
|
||||
draw()
|
||||
}
|
||||
try {
|
||||
await loadTerminal()
|
||||
} catch (err) {
|
||||
@@ -4264,6 +4415,49 @@ export function render() {
|
||||
}
|
||||
}
|
||||
|
||||
async function saveTtsVoiceConfig() {
|
||||
const form = {
|
||||
ttsProvider: el.querySelector('#hm-tts-provider')?.value || 'edge',
|
||||
ttsEdgeVoice: el.querySelector('#hm-tts-edge-voice')?.value || '',
|
||||
ttsOpenaiModel: el.querySelector('#hm-tts-openai-model')?.value || 'gpt-4o-mini-tts',
|
||||
ttsOpenaiVoice: el.querySelector('#hm-tts-openai-voice')?.value || 'alloy',
|
||||
ttsElevenlabsVoiceId: el.querySelector('#hm-tts-elevenlabs-voice-id')?.value || '',
|
||||
ttsElevenlabsModelId: el.querySelector('#hm-tts-elevenlabs-model-id')?.value || '',
|
||||
ttsXaiVoiceId: el.querySelector('#hm-tts-xai-voice-id')?.value || 'eve',
|
||||
ttsXaiLanguage: el.querySelector('#hm-tts-xai-language')?.value || 'en',
|
||||
ttsXaiSampleRate: el.querySelector('#hm-tts-xai-sample-rate')?.value || '24000',
|
||||
ttsXaiBitRate: el.querySelector('#hm-tts-xai-bit-rate')?.value || '128000',
|
||||
ttsMistralModel: el.querySelector('#hm-tts-mistral-model')?.value || 'voxtral-mini-tts-2603',
|
||||
ttsMistralVoiceId: el.querySelector('#hm-tts-mistral-voice-id')?.value || '',
|
||||
ttsPiperVoice: el.querySelector('#hm-tts-piper-voice')?.value || '',
|
||||
voiceRecordKey: el.querySelector('#hm-voice-record-key')?.value || '',
|
||||
voiceMaxRecordingSeconds: el.querySelector('#hm-voice-max-recording-seconds')?.value || '120',
|
||||
voiceAutoTts: !!el.querySelector('#hm-voice-auto-tts')?.checked,
|
||||
voiceBeepEnabled: !!el.querySelector('#hm-voice-beep-enabled')?.checked,
|
||||
voiceSilenceThreshold: el.querySelector('#hm-voice-silence-threshold')?.value || '200',
|
||||
voiceSilenceDuration: el.querySelector('#hm-voice-silence-duration')?.value || '3',
|
||||
}
|
||||
ttsVoiceSaving = true
|
||||
ttsVoiceError = null
|
||||
draw()
|
||||
try {
|
||||
const result = await api.hermesTtsVoiceConfigSave(form)
|
||||
ttsVoiceValues = { ...TTS_VOICE_DEFAULTS, ...(result?.values || form) }
|
||||
await refreshRawAfterStructuredSave()
|
||||
const backup = result?.backup || ''
|
||||
toast({
|
||||
message: t('engine.hermesTtsVoiceConfigSaveSuccess'),
|
||||
hint: backup ? t('engine.hermesConfigBackupHint', { path: backup }) : '',
|
||||
}, 'success')
|
||||
} catch (err) {
|
||||
ttsVoiceError = humanizeError(err, t('engine.hermesTtsVoiceConfigSaveFailed') || 'Save speech output config failed')
|
||||
toast(ttsVoiceError, 'error')
|
||||
} finally {
|
||||
ttsVoiceSaving = false
|
||||
draw()
|
||||
}
|
||||
}
|
||||
|
||||
async function saveTerminal() {
|
||||
const form = {
|
||||
terminalBackend: el.querySelector('#hm-terminal-backend')?.value || 'local',
|
||||
|
||||
@@ -581,6 +581,8 @@ export const api = {
|
||||
hermesBrowserConfigSave: (form) => invoke('hermes_browser_config_save', { form }),
|
||||
hermesSttConfigRead: () => invoke('hermes_stt_config_read'),
|
||||
hermesSttConfigSave: (form) => invoke('hermes_stt_config_save', { form }),
|
||||
hermesTtsVoiceConfigRead: () => invoke('hermes_tts_voice_config_read'),
|
||||
hermesTtsVoiceConfigSave: (form) => invoke('hermes_tts_voice_config_save', { form }),
|
||||
hermesTerminalConfigRead: () => invoke('hermes_terminal_config_read'),
|
||||
hermesTerminalConfigSave: (form) => invoke('hermes_terminal_config_save', { form }),
|
||||
hermesLazyDepsFeatures: () => cachedInvoke('hermes_lazy_deps_features', {}, 600000),
|
||||
|
||||
@@ -739,6 +739,49 @@ export default {
|
||||
'hermesSttConfigMistralModel_voxtral-mini-latest': _('voxtral-mini-latest(推荐)', 'voxtral-mini-latest (recommended)', 'voxtral-mini-latest(建議)'),
|
||||
'hermesSttConfigMistralModel_voxtral-mini-2602': _('voxtral-mini-2602(固定版本)', 'voxtral-mini-2602 (pinned version)', 'voxtral-mini-2602(固定版本)'),
|
||||
hermesSttConfigFootnote: _('这里写入 stt.*。API Key 仍通过 .env 管理;Groq 使用上游默认模型,其他 provider 高级字段会保留在 raw YAML 中。', 'This writes stt.*. API keys are still managed through .env. Groq uses the upstream default model, and other provider advanced fields stay in raw YAML.', '這裡寫入 stt.*。API Key 仍透過 .env 管理;Groq 使用上游預設模型,其他 provider 進階欄位會保留在 raw YAML 中。'),
|
||||
hermesTtsVoiceConfigTitle: _('语音输出与录音', 'Speech output and recording', '語音輸出與錄音'),
|
||||
hermesTtsVoiceConfigDesc: _('控制 Hermes 的 TTS 朗读 provider、主流语音模型,以及 CLI 语音录制热键和静音自动停止。', 'Control Hermes TTS providers and common voice models, plus CLI recording hotkey and silence auto-stop.', '控制 Hermes 的 TTS 朗讀 provider、主流語音模型,以及 CLI 語音錄製熱鍵和靜音自動停止。'),
|
||||
hermesTtsVoiceConfigStatusReady: _('结构化配置', 'structured settings', '結構化設定'),
|
||||
hermesTtsVoiceConfigSave: _('保存语音输出配置', 'Save speech output settings', '儲存語音輸出設定'),
|
||||
hermesTtsVoiceConfigSaveSuccess: _('语音输出配置已保存,建议重启 Hermes Gateway 或 CLI 会话生效', 'Speech output settings saved. Restart Hermes Gateway or CLI sessions to take effect.', '語音輸出設定已儲存,建議重啟 Hermes Gateway 或 CLI 工作階段生效'),
|
||||
hermesTtsVoiceConfigLoadFailed: _('加载语音输出配置失败', 'Load speech output settings failed', '載入語音輸出設定失敗'),
|
||||
hermesTtsVoiceConfigSaveFailed: _('保存语音输出配置失败', 'Save speech output settings failed', '儲存語音輸出設定失敗'),
|
||||
hermesTtsConfigProvider: _('TTS 服务', 'TTS provider', 'TTS 服務'),
|
||||
hermesTtsConfigProvider_edge: _('Edge TTS(免费)', 'Edge TTS (free)', 'Edge TTS(免費)'),
|
||||
hermesTtsConfigProvider_elevenlabs: _('ElevenLabs(高质量)', 'ElevenLabs (high quality)', 'ElevenLabs(高品質)'),
|
||||
hermesTtsConfigProvider_openai: _('OpenAI TTS', 'OpenAI TTS', 'OpenAI TTS'),
|
||||
hermesTtsConfigProvider_xai: _('xAI TTS', 'xAI TTS', 'xAI TTS'),
|
||||
hermesTtsConfigProvider_minimax: _('MiniMax TTS', 'MiniMax TTS', 'MiniMax TTS'),
|
||||
hermesTtsConfigProvider_mistral: _('Mistral Voxtral TTS', 'Mistral Voxtral TTS', 'Mistral Voxtral TTS'),
|
||||
hermesTtsConfigProvider_gemini: _('Gemini TTS', 'Gemini TTS', 'Gemini TTS'),
|
||||
hermesTtsConfigProvider_neutts: _('NeuTTS(本地)', 'NeuTTS (local)', 'NeuTTS(本機)'),
|
||||
hermesTtsConfigProvider_kittentts: _('KittenTTS(本地)', 'KittenTTS (local)', 'KittenTTS(本機)'),
|
||||
hermesTtsConfigProvider_piper: _('Piper(本地)', 'Piper (local)', 'Piper(本機)'),
|
||||
hermesTtsConfigEdgeVoice: _('Edge 声音', 'Edge voice', 'Edge 聲音'),
|
||||
hermesTtsConfigOpenaiModel: _('OpenAI 模型', 'OpenAI model', 'OpenAI 模型'),
|
||||
hermesTtsConfigOpenaiVoice: _('OpenAI 声音', 'OpenAI voice', 'OpenAI 聲音'),
|
||||
hermesTtsConfigOpenaiVoice_alloy: _('alloy', 'alloy', 'alloy'),
|
||||
hermesTtsConfigOpenaiVoice_echo: _('echo', 'echo', 'echo'),
|
||||
hermesTtsConfigOpenaiVoice_fable: _('fable', 'fable', 'fable'),
|
||||
hermesTtsConfigOpenaiVoice_onyx: _('onyx', 'onyx', 'onyx'),
|
||||
hermesTtsConfigOpenaiVoice_nova: _('nova', 'nova', 'nova'),
|
||||
hermesTtsConfigOpenaiVoice_shimmer: _('shimmer', 'shimmer', 'shimmer'),
|
||||
hermesTtsConfigElevenlabsVoiceId: _('ElevenLabs Voice ID', 'ElevenLabs voice ID', 'ElevenLabs Voice ID'),
|
||||
hermesTtsConfigElevenlabsModelId: _('ElevenLabs 模型 ID', 'ElevenLabs model ID', 'ElevenLabs 模型 ID'),
|
||||
hermesTtsConfigXaiVoiceId: _('xAI Voice ID', 'xAI voice ID', 'xAI Voice ID'),
|
||||
hermesTtsConfigXaiLanguage: _('xAI 语言', 'xAI language', 'xAI 語言'),
|
||||
hermesTtsConfigXaiSampleRate: _('xAI 采样率', 'xAI sample rate', 'xAI 取樣率'),
|
||||
hermesTtsConfigXaiBitRate: _('xAI 比特率', 'xAI bit rate', 'xAI 位元率'),
|
||||
hermesTtsConfigMistralModel: _('Mistral 模型', 'Mistral model', 'Mistral 模型'),
|
||||
hermesTtsConfigMistralVoiceId: _('Mistral Voice ID', 'Mistral voice ID', 'Mistral Voice ID'),
|
||||
hermesTtsConfigPiperVoice: _('Piper 声音', 'Piper voice', 'Piper 聲音'),
|
||||
hermesVoiceConfigRecordKey: _('录音热键', 'Recording hotkey', '錄音快捷鍵'),
|
||||
hermesVoiceConfigMaxRecordingSeconds: _('最长录音秒数', 'Max recording seconds', '最長錄音秒數'),
|
||||
hermesVoiceConfigAutoTts: _('CLI 回复后自动朗读', 'Auto-speak CLI replies', 'CLI 回覆後自動朗讀'),
|
||||
hermesVoiceConfigBeepEnabled: _('录音开始/结束提示音', 'Recording start/stop beeps', '錄音開始/結束提示音'),
|
||||
hermesVoiceConfigSilenceThreshold: _('静音阈值 RMS', 'Silence RMS threshold', '靜音閾值 RMS'),
|
||||
hermesVoiceConfigSilenceDuration: _('静音自动停止秒数', 'Silence auto-stop seconds', '靜音自動停止秒數'),
|
||||
hermesTtsVoiceConfigFootnote: _('这里写入 tts.* 与 voice.*。API Key 仍通过 .env 管理;留空的可选声音 ID 会删除覆盖并使用 Hermes/provider 默认值;provider 的高级字段和 max_text_length 会保留在 raw YAML 中。', 'This writes tts.* and voice.*. API keys are still managed through .env. Empty optional voice IDs remove overrides and fall back to Hermes/provider defaults. Advanced provider fields and max_text_length stay in raw YAML.', '這裡寫入 tts.* 與 voice.*。API Key 仍透過 .env 管理;留空的可選聲音 ID 會刪除覆蓋並使用 Hermes/provider 預設值;provider 的進階欄位和 max_text_length 會保留在 raw YAML 中。'),
|
||||
hermesCompressionTitle: _('上下文压缩', 'Context compression', '上下文壓縮'),
|
||||
hermesCompressionDesc: _('控制长对话何时触发压缩、压缩目标和保留范围,降低上下文过长导致的失败与费用浪费。', 'Control when long conversations are compressed, the target size, and protected message ranges to reduce failures and wasted cost from oversized context.', '控制長對話何時觸發壓縮、壓縮目標和保留範圍,降低上下文過長導致的失敗與費用浪費。'),
|
||||
hermesCompressionStatusReady: _('结构化配置', 'structured settings', '結構化設定'),
|
||||
|
||||
Reference in New Issue
Block a user