diff --git a/apps/stage-tamagotchi/src/pages/settings/providers/elevenlabs.vue b/apps/stage-tamagotchi/src/pages/settings/providers/elevenlabs.vue
index 374071af0..0f4d99011 100644
--- a/apps/stage-tamagotchi/src/pages/settings/providers/elevenlabs.vue
+++ b/apps/stage-tamagotchi/src/pages/settings/providers/elevenlabs.vue
@@ -203,7 +203,6 @@ watch(providers, async () => {
-
-import type { RemovableRef } from '@vueuse/core'
+import type { SpeechProvider } from '@xsai-ext/shared-providers'
import {
- ProviderAdvancedSettings,
- ProviderApiKeyInput,
- ProviderBaseUrlInput,
- ProviderBasicSettings,
- ProviderSettingsContainer,
- ProviderSettingsLayout,
+ SpeechPlayground,
+ SpeechProviderSettings,
} from '@proj-airi/stage-ui/components'
-import { useProvidersStore } from '@proj-airi/stage-ui/stores'
+import { useProvidersStore, useSpeechStore } from '@proj-airi/stage-ui/stores'
+import { FieldRange } from '@proj-airi/ui'
import { storeToRefs } from 'pinia'
-import { computed, onMounted, watch } from 'vue'
+import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
-import { useRouter } from 'vue-router'
-const { t } = useI18n()
-const router = useRouter()
+const speechStore = useSpeechStore()
const providersStore = useProvidersStore()
-const { providers } = storeToRefs(providersStore) as { providers: RemovableRef> }
+const { providers } = storeToRefs(providersStore)
+const { t } = useI18n()
+
+const defaultVoiceSettings = {
+ speed: 1.0,
+}
// Get provider metadata
-const providerId = 'openai'
-const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
+const providerId = 'openai-audio-speech'
+const defaultModel = 'gpt-4o-mini-tts'
-// Use computed properties for settings
-const apiKey = computed({
- get: () => providers.value[providerId]?.apiKey || '',
- set: (value) => {
- if (!providers.value[providerId])
- providers.value[providerId] = {}
+const speed = ref(1.0)
- providers.value[providerId].apiKey = value
- },
+// Check if API key is configured
+const apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey)
+
+const availableVoices = computed(() => {
+ return speechStore.availableVoices[providerId] || []
})
-const baseUrl = computed({
- get: () => providers.value[providerId]?.baseUrl || 'https://api.openai.com/v1/',
- set: (value) => {
- if (!providers.value[providerId])
- providers.value[providerId] = {}
-
- providers.value[providerId].baseUrl = value
- },
-})
-
-onMounted(() => {
- // Initialize provider if it doesn't exist
- if (!providers.value[providerId]) {
- providers.value[providerId] = {
- baseUrl: 'https://api.openai.com/v1/',
- }
+// Generate speech with ElevenLabs-specific parameters
+async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean) {
+ const provider = providersStore.getProviderInstance(providerId) as SpeechProvider
+ if (!provider) {
+ throw new Error('Failed to initialize speech provider')
}
- // Initialize refs with current values
- apiKey.value = providers.value[providerId]?.apiKey || ''
- baseUrl.value = providers.value[providerId]?.baseUrl || 'https://api.openai.com/v1/'
-})
+ // Get provider configuration
+ const providerConfig = providersStore.getProviderConfig(providerId)
-// Watch settings and update the provider configuration
-watch([apiKey, baseUrl], () => {
- providers.value[providerId] = {
- ...providers.value[providerId],
- apiKey: apiKey.value,
- baseUrl: baseUrl.value || 'https://api.openai.com/v1/',
- }
-})
+ // Get model from configuration or use default
+ const model = providerConfig.model as string | undefined || defaultModel
-function handleResetSettings() {
- providers.value[providerId] = {
- baseUrl: 'https://api.openai.com/v1/',
- }
+ // ElevenLabs doesn't need SSML conversion, but if SSML is provided, use it directly
+ return await speechStore.speech(
+ provider,
+ model,
+ input,
+ voiceId,
+ {
+ ...providerConfig,
+ ...defaultVoiceSettings,
+ },
+ )
}
+
+watch(speed, async () => {
+ const providerConfig = providersStore.getProviderConfig(providerId)
+ providerConfig.speed = speed.value
+})
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
diff --git a/apps/stage-web/src/pages/settings/providers/elevenlabs.vue b/apps/stage-web/src/pages/settings/providers/elevenlabs.vue
index 374071af0..0f4d99011 100644
--- a/apps/stage-web/src/pages/settings/providers/elevenlabs.vue
+++ b/apps/stage-web/src/pages/settings/providers/elevenlabs.vue
@@ -203,7 +203,6 @@ watch(providers, async () => {
-
-import type { RemovableRef } from '@vueuse/core'
+import type { SpeechProvider } from '@xsai-ext/shared-providers'
import {
- ProviderAdvancedSettings,
- ProviderApiKeyInput,
- ProviderBaseUrlInput,
- ProviderBasicSettings,
- ProviderSettingsContainer,
- ProviderSettingsLayout,
+ SpeechPlayground,
+ SpeechProviderSettings,
} from '@proj-airi/stage-ui/components'
-import { useProvidersStore } from '@proj-airi/stage-ui/stores'
+import { useProvidersStore, useSpeechStore } from '@proj-airi/stage-ui/stores'
+import { FieldRange } from '@proj-airi/ui'
import { storeToRefs } from 'pinia'
-import { computed, onMounted, watch } from 'vue'
+import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
-import { useRouter } from 'vue-router'
-const { t } = useI18n()
-const router = useRouter()
+const speechStore = useSpeechStore()
const providersStore = useProvidersStore()
-const { providers } = storeToRefs(providersStore) as { providers: RemovableRef> }
+const { providers } = storeToRefs(providersStore)
+const { t } = useI18n()
+
+const defaultVoiceSettings = {
+ speed: 1.0,
+}
// Get provider metadata
-const providerId = 'openai'
-const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
+const providerId = 'openai-audio-speech'
+const defaultModel = 'gpt-4o-mini-tts'
-// Use computed properties for settings
-const apiKey = computed({
- get: () => providers.value[providerId]?.apiKey || '',
- set: (value) => {
- if (!providers.value[providerId])
- providers.value[providerId] = {}
+const speed = ref(1.0)
- providers.value[providerId].apiKey = value
- },
+// Check if API key is configured
+const apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey)
+
+const availableVoices = computed(() => {
+ return speechStore.availableVoices[providerId] || []
})
-const baseUrl = computed({
- get: () => providers.value[providerId]?.baseUrl || 'https://api.openai.com/v1/',
- set: (value) => {
- if (!providers.value[providerId])
- providers.value[providerId] = {}
-
- providers.value[providerId].baseUrl = value
- },
-})
-
-onMounted(() => {
- // Initialize provider if it doesn't exist
- if (!providers.value[providerId]) {
- providers.value[providerId] = {
- baseUrl: 'https://api.openai.com/v1/',
- }
+// Generate speech with ElevenLabs-specific parameters
+async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean) {
+ const provider = providersStore.getProviderInstance(providerId) as SpeechProvider
+ if (!provider) {
+ throw new Error('Failed to initialize speech provider')
}
- // Initialize refs with current values
- apiKey.value = providers.value[providerId]?.apiKey || ''
- baseUrl.value = providers.value[providerId]?.baseUrl || 'https://api.openai.com/v1/'
-})
+ // Get provider configuration
+ const providerConfig = providersStore.getProviderConfig(providerId)
-// Watch settings and update the provider configuration
-watch([apiKey, baseUrl], () => {
- providers.value[providerId] = {
- ...providers.value[providerId],
- apiKey: apiKey.value,
- baseUrl: baseUrl.value || 'https://api.openai.com/v1/',
- }
-})
+ // Get model from configuration or use default
+ const model = providerConfig.model as string | undefined || defaultModel
-function handleResetSettings() {
- providers.value[providerId] = {
- baseUrl: 'https://api.openai.com/v1/',
- }
+ // ElevenLabs doesn't need SSML conversion, but if SSML is provided, use it directly
+ return await speechStore.speech(
+ provider,
+ model,
+ input,
+ voiceId,
+ {
+ ...providerConfig,
+ ...defaultVoiceSettings,
+ },
+ )
}
+
+watch(speed, async () => {
+ const providerConfig = providersStore.getProviderConfig(providerId)
+ providerConfig.speed = speed.value
+})
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
diff --git a/packages/stage-ui/src/stores/modules/speech.ts b/packages/stage-ui/src/stores/modules/speech.ts
index a092e56e7..56dcc093c 100644
--- a/packages/stage-ui/src/stores/modules/speech.ts
+++ b/packages/stage-ui/src/stores/modules/speech.ts
@@ -74,7 +74,7 @@ export const useSpeechStore = defineStore('speech', () => {
// Helper function to determine if a provider is a speech provider
function isSpeechProvider(providerId: string): boolean {
- return ['elevenlabs', 'microsoft-speech', 'azure-speech', 'google', 'amazon', 'alibaba-cloud-model-studio', 'volcengine', 'player2-speech'].includes(providerId)
+ return ['openai-audio-speech', 'elevenlabs', 'microsoft-speech', 'azure-speech', 'google', 'amazon', 'alibaba-cloud-model-studio', 'volcengine', 'player2-speech'].includes(providerId)
}
async function loadVoicesForProvider(provider: string) {
diff --git a/packages/stage-ui/src/stores/providers.ts b/packages/stage-ui/src/stores/providers.ts
index f93f11aa8..12c997fe1 100644
--- a/packages/stage-ui/src/stores/providers.ts
+++ b/packages/stage-ui/src/stores/providers.ts
@@ -606,6 +606,76 @@ export const useProvidersStore = defineStore('providers', () => {
} satisfies ModelInfo
})
},
+ listVoices: async () => {
+ return [
+ {
+ id: 'alloy',
+ name: 'Alloy',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'ash',
+ name: 'Ash',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'ballad',
+ name: 'Ballad',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'coral',
+ name: 'Coral',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'echo',
+ name: 'Echo',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'fable',
+ name: 'Fable',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'onyx',
+ name: 'Onyx',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'nova',
+ name: 'Nova',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'sage',
+ name: 'Sage',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'shimmer',
+ name: 'Shimmer',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ {
+ id: 'verse',
+ name: 'Verse',
+ provider: 'openai-audio-speech',
+ languages: [],
+ },
+ ] satisfies VoiceInfo[]
+ },
},
validators: {
validateProviderConfig: (config) => {