fix(stage-ui): should have option to completely disable Speech module
This commit is contained in:
@@ -615,6 +615,9 @@ pages:
|
||||
deepgram-tts:
|
||||
description: deepgram.com
|
||||
title: Deepgram
|
||||
speech-noop:
|
||||
title: None
|
||||
description: No speech output.
|
||||
deepseek:
|
||||
description: deepseek.com
|
||||
title: DeepSeek
|
||||
|
||||
@@ -238,6 +238,21 @@ function updateCustomVoiceName(value: string | undefined) {
|
||||
function updateCustomModelName(value: string | undefined) {
|
||||
activeSpeechModel.value = value || ''
|
||||
}
|
||||
|
||||
function handleDeleteProvider(providerId: string) {
|
||||
if (providerId === 'speech-noop') {
|
||||
return
|
||||
}
|
||||
|
||||
if (activeSpeechProvider.value === providerId) {
|
||||
activeSpeechProvider.value = 'speech-noop'
|
||||
activeSpeechModel.value = ''
|
||||
activeSpeechVoiceId.value = ''
|
||||
activeSpeechVoice.value = undefined
|
||||
}
|
||||
|
||||
providersStore.deleteProvider(providerId)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -268,7 +283,18 @@ function updateCustomModelName(value: string | undefined) {
|
||||
:title="metadata.localizedName || 'Unknown'"
|
||||
:description="metadata.localizedDescription"
|
||||
@click="trackProviderClick(metadata.id, 'speech')"
|
||||
/>
|
||||
>
|
||||
<template #topRight>
|
||||
<button
|
||||
v-if="metadata.id !== 'speech-noop'"
|
||||
type="button"
|
||||
class="rounded bg-neutral-100 p-1 text-neutral-600 transition-colors dark:bg-neutral-800/60 hover:bg-neutral-200 dark:text-neutral-300 dark:hover:bg-neutral-700/60"
|
||||
@click.stop.prevent="handleDeleteProvider(metadata.id)"
|
||||
>
|
||||
<div i-solar:trash-bin-trash-bold-duotone class="text-base" />
|
||||
</button>
|
||||
</template>
|
||||
</RadioCardSimple>
|
||||
<RouterLink
|
||||
to="/settings/providers#speech"
|
||||
border="2px solid"
|
||||
@@ -303,7 +329,7 @@ function updateCustomModelName(value: string | undefined) {
|
||||
</div>
|
||||
<div>
|
||||
<!-- Model selection section -->
|
||||
<div v-if="activeSpeechProvider">
|
||||
<div v-if="activeSpeechProvider && activeSpeechProvider !== 'speech-noop'">
|
||||
<div flex="~ col gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg md:text-2xl">
|
||||
@@ -395,7 +421,7 @@ function updateCustomModelName(value: string | undefined) {
|
||||
</div>
|
||||
|
||||
<!-- Voice Configuration Section -->
|
||||
<div v-if="activeSpeechProvider">
|
||||
<div v-if="activeSpeechProvider && activeSpeechProvider !== 'speech-noop'">
|
||||
<div flex="~ col gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg text-neutral-500 md:text-2xl dark:text-neutral-400">
|
||||
|
||||
@@ -240,6 +240,9 @@ const speechPipeline = createSpeechPipeline<AudioBuffer>({
|
||||
if (signal.aborted)
|
||||
return null
|
||||
|
||||
if (activeSpeechProvider.value === 'speech-noop')
|
||||
return null
|
||||
|
||||
if (!activeSpeechProvider.value)
|
||||
return null
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export const useSpeechStore = defineStore('speech', () => {
|
||||
const { allAudioSpeechProvidersMetadata } = storeToRefs(providersStore)
|
||||
|
||||
// State
|
||||
const activeSpeechProvider = useLocalStorageManualReset<string>('settings/speech/active-provider', '')
|
||||
const activeSpeechProvider = useLocalStorageManualReset<string>('settings/speech/active-provider', 'speech-noop')
|
||||
const activeSpeechModel = useLocalStorageManualReset<string>('settings/speech/active-model', '')
|
||||
const activeSpeechVoiceId = useLocalStorageManualReset<string>('settings/speech/voice', '')
|
||||
const activeSpeechVoice = refManualReset<VoiceInfo | undefined>(undefined)
|
||||
@@ -124,6 +124,29 @@ export const useSpeechStore = defineStore('speech', () => {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
if (!activeSpeechProvider.value) {
|
||||
activeSpeechProvider.value = 'speech-noop'
|
||||
}
|
||||
|
||||
watch(
|
||||
() => providersStore.configuredSpeechProvidersMetadata.map(provider => provider.id),
|
||||
(configuredProviderIds) => {
|
||||
if (!activeSpeechProvider.value)
|
||||
return
|
||||
|
||||
// NOTICE: clear stale selection when the currently selected speech provider
|
||||
// is no longer configured to avoid implicit fallback behavior from persisted state.
|
||||
if (!configuredProviderIds.includes(activeSpeechProvider.value)) {
|
||||
activeSpeechProvider.value = 'speech-noop'
|
||||
activeSpeechModel.value = ''
|
||||
activeSpeechVoiceId.value = ''
|
||||
activeSpeechVoice.value = undefined
|
||||
}
|
||||
},
|
||||
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadVoicesForProvider(activeSpeechProvider.value).then(() => {
|
||||
if (activeSpeechVoiceId.value) {
|
||||
@@ -232,6 +255,9 @@ export const useSpeechStore = defineStore('speech', () => {
|
||||
}
|
||||
|
||||
const configured = computed(() => {
|
||||
if (activeSpeechProvider.value === 'speech-noop')
|
||||
return false
|
||||
|
||||
if (!activeSpeechProvider.value)
|
||||
return false
|
||||
|
||||
|
||||
@@ -237,6 +237,34 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
|
||||
// Centralized provider metadata with provider factory functions
|
||||
const providerMetadata: Record<string, ProviderMetadata> = {
|
||||
'speech-noop': {
|
||||
id: 'speech-noop',
|
||||
category: 'speech',
|
||||
tasks: ['text-to-speech', 'tts'],
|
||||
nameKey: 'settings.pages.providers.provider.speech-noop.title',
|
||||
name: 'None',
|
||||
descriptionKey: 'settings.pages.providers.provider.speech-noop.description',
|
||||
description: 'No speech output.',
|
||||
icon: 'i-solar:volume-cross-bold-duotone',
|
||||
defaultOptions: () => ({}),
|
||||
createProvider: async () => ({
|
||||
speech: () => ({
|
||||
baseURL: 'http://speech-noop.invalid/v1/',
|
||||
model: 'noop',
|
||||
}),
|
||||
}),
|
||||
capabilities: {
|
||||
listModels: async () => [],
|
||||
listVoices: async () => [],
|
||||
},
|
||||
validators: {
|
||||
validateProviderConfig: () => ({
|
||||
errors: [],
|
||||
reason: '',
|
||||
valid: true,
|
||||
}),
|
||||
},
|
||||
},
|
||||
'app-local-audio-speech': buildOpenAICompatibleProvider({
|
||||
id: 'app-local-audio-speech',
|
||||
name: 'App (Local)',
|
||||
|
||||
Reference in New Issue
Block a user