feat(stage-web|stage-tamagotchi): speech finished

This commit is contained in:
Neko Ayaka
2025-03-19 18:45:36 +08:00
parent 76483a3740
commit fb859ddfcc
27 changed files with 3012 additions and 525 deletions
@@ -104,7 +104,7 @@ function updateCustomValue(value: string) {
<div class="relative">
<!-- Horizontally scrollable container -->
<div
class="scrollbar-hide grid auto-cols-[350px] grid-flow-col gap-4 overflow-x-auto pb-4"
class="scrollbar-hide grid auto-cols-[350px] grid-flow-col max-h-[calc(100dvh-7lh)] gap-4 overflow-x-auto pb-4"
:class="[
isListExpanded ? 'grid-cols-1 md:grid-cols-2 grid-flow-row auto-cols-auto' : '',
]"
@@ -136,7 +136,7 @@ function updateCustomValue(value: string) {
bg="neutral-100 dark:[rgba(0,0,0,0.3)]"
rounded-xl
:class="[
isListExpanded ? 'fixed bottom-4 left-1/2 translate-x--1/2 z-10 w-full px-9 max-w-screen-lg' : 'mt-0 w-full rounded-lg',
isListExpanded ? 'w-full' : 'mt-4 w-full rounded-lg',
]"
>
<button
@@ -31,7 +31,7 @@ interface Voice {
interface Props {
voice: Voice
selectedVoiceId: string
selectedVoiceId?: string
currentlyPlayingId?: string
customInputPlaceholder?: string
showVisualizer?: boolean
@@ -28,7 +28,7 @@ interface Voice {
interface Props {
voices: Voice[]
selectedVoiceId: string
selectedVoiceId?: string
searchable?: boolean
searchPlaceholder?: string
searchNoResultsTitle?: string
@@ -350,7 +350,7 @@ const customVoiceName = ref('')
<div class="relative">
<!-- Horizontally scrollable container -->
<div
class="scrollbar-hide grid auto-cols-[350px] grid-flow-col gap-4 overflow-x-auto pb-4"
class="scrollbar-hide grid auto-cols-[350px] grid-flow-col max-h-[calc(100dvh-7lh)] gap-4 overflow-x-auto pb-4"
:class="[
isListExpanded ? 'grid-cols-1 md:grid-cols-2 grid-flow-row auto-cols-auto' : '',
]"
@@ -378,7 +378,7 @@ const customVoiceName = ref('')
bg="neutral-100 dark:[rgba(0,0,0,0.3)]"
rounded-xl
:class="[
isListExpanded ? 'fixed bottom-4 left-1/2 translate-x--1/2 z-10 w-full px-9 max-w-screen-lg' : 'mt-0 w-full rounded-lg',
isListExpanded ? 'w-full' : 'mt-4 w-full rounded-lg',
]"
>
<button
@@ -72,7 +72,7 @@ const audioQueue = useQueue<{ audioBuffer: AudioBuffer, text: string }>({
})
const speechStore = useSpeechStore()
const { voiceId, ssmlEnabled, activeSpeechProvider, activeSpeechModel } = storeToRefs(speechStore)
const { ssmlEnabled, activeSpeechProvider, activeSpeechModel, activeSpeechVoice } = storeToRefs(speechStore)
async function handleSpeechGeneration(ctx: { data: string }) {
try {
@@ -81,6 +81,11 @@ async function handleSpeechGeneration(ctx: { data: string }) {
return
}
if (!activeSpeechVoice.value) {
console.warn('No active speech voice configured')
return
}
// TODO: UnElevenLabsOptions
const provider = providersStore.getProviderInstance(activeSpeechProvider.value) as SpeechProviderWithExtraOptions<string, UnElevenLabsOptions>
if (!provider) {
@@ -88,19 +93,16 @@ async function handleSpeechGeneration(ctx: { data: string }) {
return
}
const providerConfig = providersStore.getProviderConfig(activeSpeechProvider.value)
const input = ssmlEnabled.value
? speechStore.generateSSML(ctx.data, activeSpeechVoice.value)
: ctx.data
const res = await generateSpeech({
...provider.speech(activeSpeechModel.value, {
// Optional: Add SSML wrapping if enabled
...(ssmlEnabled.value && {
input: speechStore.generateSSML(ctx.data),
}),
voiceSettings: {
stability: 0.4,
similarityBoost: 0.5,
},
}),
input: ctx.data,
voice: voiceId.value,
...provider.speech(activeSpeechModel.value, providerConfig),
input,
voice: activeSpeechVoice.value.id,
})
// Decode the ArrayBuffer into an AudioBuffer
@@ -44,23 +44,6 @@ export const useConsciousnessStore = defineStore('consciousness', () => {
)
})
// Actions
function setActiveProvider(provider: string) {
activeProvider.value = provider
}
function setActiveModel(model: string) {
activeModel.value = model
}
function setCustomModelName(name: string) {
activeCustomModelName.value = name
}
function setModelSearchQuery(query: string) {
modelSearchQuery.value = query
}
function resetModelSelection() {
activeModel.value = ''
activeCustomModelName.value = ''
@@ -97,10 +80,6 @@ export const useConsciousnessStore = defineStore('consciousness', () => {
filteredModels,
// Actions
setActiveProvider,
setActiveModel,
setCustomModelName,
setModelSearchQuery,
resetModelSelection,
loadModelsForProvider,
}
+65 -41
View File
@@ -2,7 +2,7 @@ import type { VoiceInfo } from '../providers'
import { useLocalStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import { voiceList, voiceMap } from '../../constants/elevenlabs'
import { useProvidersStore } from '../providers'
@@ -13,8 +13,9 @@ export const useSpeechStore = defineStore('speech', () => {
// State
const activeSpeechProvider = useLocalStorage('settings/speech/active-provider', '')
const activeSpeechModel = useLocalStorage('settings/speech/active-model', 'eleven_multilingual_v2')
const voiceName = useLocalStorage('settings/speech/voice-name', '')
const voiceId = useLocalStorage('settings/speech/voice-id', '')
const activeSpeechVoiceId = useLocalStorage<string>('settings/speech/voice', '')
const activeSpeechVoice = ref<VoiceInfo>()
const pitch = useLocalStorage('settings/speech/pitch', 0)
const rate = useLocalStorage('settings/speech/rate', 1)
const ssmlEnabled = useLocalStorage('settings/speech/ssml-enabled', false)
@@ -22,6 +23,7 @@ export const useSpeechStore = defineStore('speech', () => {
const speechProviderError = ref<string | null>(null)
const availableVoices = ref<Record<string, VoiceInfo[]>>({})
const selectedLanguage = useLocalStorage('settings/speech/language', 'en-US')
const modelSearchQuery = ref('')
// Computed properties
const availableSpeechProvidersMetadata = computed(() => {
@@ -31,6 +33,36 @@ export const useSpeechStore = defineStore('speech', () => {
.map(id => providersStore.getProviderMetadata(id))
})
// Computed properties
const supportsModelListing = computed(() => {
return providersStore.getProviderMetadata(activeSpeechProvider.value)?.capabilities.listModels !== undefined
})
const providerModels = computed(() => {
return providersStore.getModelsForProvider(activeSpeechProvider.value)
})
const isLoadingActiveProviderModels = computed(() => {
return providersStore.isLoadingModels[activeSpeechProvider.value] || false
})
const activeProviderModelError = computed(() => {
return providersStore.modelLoadError[activeSpeechProvider.value] || null
})
const filteredModels = computed(() => {
if (!modelSearchQuery.value.trim()) {
return providerModels.value
}
const query = modelSearchQuery.value.toLowerCase().trim()
return providerModels.value.filter(model =>
model.name.toLowerCase().includes(query)
|| model.id.toLowerCase().includes(query)
|| (model.description && model.description.toLowerCase().includes(query)),
)
})
const supportsSSML = computed(() => {
// Currently only ElevenLabs and some other providers support SSML
return ['elevenlabs', 'microsoft-speech', 'azure-speech', 'google'].includes(activeSpeechProvider.value)
@@ -61,13 +93,6 @@ export const useSpeechStore = defineStore('speech', () => {
return ['elevenlabs', 'microsoft-speech', 'azure-speech', 'google', 'amazon'].includes(providerId)
}
function resetVoiceSettings() {
voiceName.value = ''
pitch.value = 0
rate.value = 1
ssmlEnabled.value = false
}
async function loadVoicesForProvider(provider: string) {
if (!provider || !isSpeechProvider(provider)) {
return []
@@ -104,43 +129,36 @@ export const useSpeechStore = defineStore('speech', () => {
}
})
// Generate SSML for the current configuration
function generateSSML(text: string): string {
if (!ssmlEnabled.value) {
return text
}
// Generate SSML from plain text and voice settings
function generateSSML(text: string, voice: VoiceInfo): string {
const pitchValue = pitch.value > 0 ? `+${pitch.value}%` : `${pitch.value}%`
let ssml = '<speak>'
if (voiceName.value) {
ssml += `<voice name="${voiceName.value}">`
}
if (pitch.value !== 0 || rate.value !== 1) {
ssml += `<prosody pitch="+${pitch.value}%" rate="${rate.value}">`
}
ssml += text
if (pitch.value !== 0 || rate.value !== 1) {
ssml += '</prosody>'
}
if (voiceName.value) {
ssml += '</voice>'
}
ssml += '</speak>'
return ssml
return `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="${voice.languages[0].code}">
<voice name="${voice.id}" gender="${voice.gender}">
<prosody pitch="${pitchValue}">
${text}
</prosody>
</voice>
</speak>`
}
onMounted(() => {
if (activeSpeechVoiceId.value) {
activeSpeechVoice.value = availableVoices.value[activeSpeechProvider.value]?.find(voice => voice.id === activeSpeechVoiceId.value)
}
})
watch(activeSpeechVoice, (voice) => {
if (voice) {
activeSpeechVoiceId.value = voice.id
}
})
return {
// State
activeSpeechProvider,
activeSpeechModel,
voiceName,
voiceId,
activeSpeechVoice,
pitch,
rate,
ssmlEnabled,
@@ -148,14 +166,20 @@ export const useSpeechStore = defineStore('speech', () => {
isLoadingSpeechProviderVoices,
speechProviderError,
availableVoices,
modelSearchQuery,
// Computed
availableSpeechProvidersMetadata,
supportsSSML,
availableLanguages,
availableVoicesForLanguage,
supportsModelListing,
providerModels,
isLoadingActiveProviderModels,
activeProviderModelError,
filteredModels,
resetVoiceSettings,
// Actions
loadVoicesForProvider,
getVoicesForProvider,
generateSSML,
+21 -2
View File
@@ -35,6 +35,7 @@ import { useI18n } from 'vue-i18n'
import { createUnElevenLabs } from './fix/elevenlabs'
import { listVoices } from './fix/list-voices'
import { createUnMicrosoft } from './fix/microsoft'
import { models as elevenLabsModels } from './providers/elevenlabs/list-models'
export interface ProviderMetadata {
id: string
@@ -321,7 +322,16 @@ export const useProvidersStore = defineStore('providers', () => {
createProvider: config => createUnElevenLabs((config.apiKey as string).trim(), (config.baseUrl as string).trim()) as SpeechProviderWithExtraOptions<string, UnElevenLabsOptions>,
capabilities: {
listModels: async () => {
return []
return elevenLabsModels.map((model) => {
return {
id: model.model_id,
name: model.name,
provider: 'elevenlabs',
description: model.description,
contextLength: 0,
deprecated: false,
} satisfies ModelInfo
})
},
listVoices: async (config) => {
const provider = createUnElevenLabs((config.apiKey as string).trim(), (config.baseUrl as string).trim()) as VoiceProviderWithExtraOptions<UnElevenLabsOptions>
@@ -497,7 +507,16 @@ export const useProvidersStore = defineStore('providers', () => {
createProvider: config => createUnMicrosoft((config.apiKey as string).trim(), (config.baseUrl as string).trim()) as SpeechProviderWithExtraOptions<string, UnMicrosoftOptions>,
capabilities: {
listModels: async () => {
return []
return [
{
id: 'v1',
name: 'v1',
provider: 'microsoft-speech',
description: '',
contextLength: 0,
deprecated: false,
},
]
},
listVoices: async (config) => {
const provider = createUnMicrosoft((config.apiKey as string).trim(), (config.baseUrl as string).trim()) as VoiceProviderWithExtraOptions<UnMicrosoftOptions>
@@ -0,0 +1,740 @@
export const models = [
{
model_id: 'eleven_multilingual_v2',
name: 'Eleven Multilingual v2',
can_be_finetuned: true,
can_do_text_to_speech: true,
can_do_voice_conversion: false,
can_use_style: true,
can_use_speaker_boost: true,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our most life-like, emotionally rich mode in 29 languages. Best for voice overs, audiobooks, post-production, or any other content creation needs.',
requires_alpha_access: false,
max_characters_request_free_user: 10000,
max_characters_request_subscribed_user: 10000,
maximum_text_length_per_request: 10000,
languages: [
{
language_id: 'en',
name: 'English',
},
{
language_id: 'ja',
name: 'Japanese',
},
{
language_id: 'zh',
name: 'Chinese',
},
{
language_id: 'de',
name: 'German',
},
{
language_id: 'hi',
name: 'Hindi',
},
{
language_id: 'fr',
name: 'French',
},
{
language_id: 'ko',
name: 'Korean',
},
{
language_id: 'pt',
name: 'Portuguese',
},
{
language_id: 'it',
name: 'Italian',
},
{
language_id: 'es',
name: 'Spanish',
},
{
language_id: 'id',
name: 'Indonesian',
},
{
language_id: 'nl',
name: 'Dutch',
},
{
language_id: 'tr',
name: 'Turkish',
},
{
language_id: 'fil',
name: 'Filipino',
},
{
language_id: 'pl',
name: 'Polish',
},
{
language_id: 'sv',
name: 'Swedish',
},
{
language_id: 'bg',
name: 'Bulgarian',
},
{
language_id: 'ro',
name: 'Romanian',
},
{
language_id: 'ar',
name: 'Arabic',
},
{
language_id: 'cs',
name: 'Czech',
},
{
language_id: 'el',
name: 'Greek',
},
{
language_id: 'fi',
name: 'Finnish',
},
{
language_id: 'hr',
name: 'Croatian',
},
{
language_id: 'ms',
name: 'Malay',
},
{
language_id: 'sk',
name: 'Slovak',
},
{
language_id: 'da',
name: 'Danish',
},
{
language_id: 'ta',
name: 'Tamil',
},
{
language_id: 'uk',
name: 'Ukrainian',
},
{
language_id: 'ru',
name: 'Russian',
},
],
model_rates: {
character_cost_multiplier: 1,
},
concurrency_group: 'standard',
},
{
model_id: 'eleven_flash_v2_5',
name: 'Eleven Flash v2.5',
can_be_finetuned: true,
can_do_text_to_speech: true,
can_do_voice_conversion: false,
can_use_style: false,
can_use_speaker_boost: false,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our ultra low latency model in 32 languages. Ideal for conversational use cases.',
requires_alpha_access: false,
max_characters_request_free_user: 40000,
max_characters_request_subscribed_user: 40000,
maximum_text_length_per_request: 40000,
languages: [
{
language_id: 'en',
name: 'English',
},
{
language_id: 'ja',
name: 'Japanese',
},
{
language_id: 'zh',
name: 'Chinese',
},
{
language_id: 'de',
name: 'German',
},
{
language_id: 'hi',
name: 'Hindi',
},
{
language_id: 'fr',
name: 'French',
},
{
language_id: 'ko',
name: 'Korean',
},
{
language_id: 'pt',
name: 'Portuguese',
},
{
language_id: 'it',
name: 'Italian',
},
{
language_id: 'es',
name: 'Spanish',
},
{
language_id: 'ru',
name: 'Russian',
},
{
language_id: 'id',
name: 'Indonesian',
},
{
language_id: 'nl',
name: 'Dutch',
},
{
language_id: 'tr',
name: 'Turkish',
},
{
language_id: 'fil',
name: 'Filipino',
},
{
language_id: 'pl',
name: 'Polish',
},
{
language_id: 'sv',
name: 'Swedish',
},
{
language_id: 'bg',
name: 'Bulgarian',
},
{
language_id: 'ro',
name: 'Romanian',
},
{
language_id: 'ar',
name: 'Arabic',
},
{
language_id: 'cs',
name: 'Czech',
},
{
language_id: 'el',
name: 'Greek',
},
{
language_id: 'fi',
name: 'Finnish',
},
{
language_id: 'hr',
name: 'Croatian',
},
{
language_id: 'ms',
name: 'Malay',
},
{
language_id: 'sk',
name: 'Slovak',
},
{
language_id: 'da',
name: 'Danish',
},
{
language_id: 'ta',
name: 'Tamil',
},
{
language_id: 'uk',
name: 'Ukrainian',
},
{
language_id: 'hu',
name: 'Hungarian',
},
{
language_id: 'no',
name: 'Norwegian',
},
{
language_id: 'vi',
name: 'Vietnamese',
},
],
model_rates: {
character_cost_multiplier: 0.5,
},
concurrency_group: 'turbo',
},
{
model_id: 'eleven_turbo_v2_5',
name: 'Eleven Turbo v2.5',
can_be_finetuned: true,
can_do_text_to_speech: true,
can_do_voice_conversion: false,
can_use_style: false,
can_use_speaker_boost: false,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our high quality, low latency model in 32 languages. Best for developer use cases where speed matters and you need non-English languages.',
requires_alpha_access: false,
max_characters_request_free_user: 40000,
max_characters_request_subscribed_user: 40000,
maximum_text_length_per_request: 40000,
languages: [
{
language_id: 'en',
name: 'English',
},
{
language_id: 'ja',
name: 'Japanese',
},
{
language_id: 'zh',
name: 'Chinese',
},
{
language_id: 'de',
name: 'German',
},
{
language_id: 'hi',
name: 'Hindi',
},
{
language_id: 'fr',
name: 'French',
},
{
language_id: 'ko',
name: 'Korean',
},
{
language_id: 'pt',
name: 'Portuguese',
},
{
language_id: 'it',
name: 'Italian',
},
{
language_id: 'es',
name: 'Spanish',
},
{
language_id: 'ru',
name: 'Russian',
},
{
language_id: 'id',
name: 'Indonesian',
},
{
language_id: 'nl',
name: 'Dutch',
},
{
language_id: 'tr',
name: 'Turkish',
},
{
language_id: 'fil',
name: 'Filipino',
},
{
language_id: 'pl',
name: 'Polish',
},
{
language_id: 'sv',
name: 'Swedish',
},
{
language_id: 'bg',
name: 'Bulgarian',
},
{
language_id: 'ro',
name: 'Romanian',
},
{
language_id: 'ar',
name: 'Arabic',
},
{
language_id: 'cs',
name: 'Czech',
},
{
language_id: 'el',
name: 'Greek',
},
{
language_id: 'fi',
name: 'Finnish',
},
{
language_id: 'hr',
name: 'Croatian',
},
{
language_id: 'ms',
name: 'Malay',
},
{
language_id: 'sk',
name: 'Slovak',
},
{
language_id: 'da',
name: 'Danish',
},
{
language_id: 'ta',
name: 'Tamil',
},
{
language_id: 'uk',
name: 'Ukrainian',
},
{
language_id: 'vi',
name: 'Vietnamese',
},
{
language_id: 'no',
name: 'Norwegian',
},
{
language_id: 'hu',
name: 'Hungarian',
},
],
model_rates: {
character_cost_multiplier: 0.5,
},
concurrency_group: 'turbo',
},
{
model_id: 'eleven_turbo_v2',
name: 'Eleven Turbo v2',
can_be_finetuned: true,
can_do_text_to_speech: true,
can_do_voice_conversion: false,
can_use_style: false,
can_use_speaker_boost: false,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our English-only, low latency model. Best for developer use cases where speed matters and you only need English. Performance is on par with Turbo v2.5.',
requires_alpha_access: false,
max_characters_request_free_user: 30000,
max_characters_request_subscribed_user: 30000,
maximum_text_length_per_request: 30000,
languages: [
{
language_id: 'en',
name: 'English',
},
],
model_rates: {
character_cost_multiplier: 0.5,
},
concurrency_group: 'turbo',
},
{
model_id: 'eleven_flash_v2',
name: 'Eleven Flash v2',
can_be_finetuned: true,
can_do_text_to_speech: true,
can_do_voice_conversion: false,
can_use_style: false,
can_use_speaker_boost: false,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our ultra low latency model in english. Ideal for conversational use cases.',
requires_alpha_access: false,
max_characters_request_free_user: 30000,
max_characters_request_subscribed_user: 30000,
maximum_text_length_per_request: 30000,
languages: [
{
language_id: 'en',
name: 'English',
},
],
model_rates: {
character_cost_multiplier: 0.5,
},
concurrency_group: 'turbo',
},
{
model_id: 'eleven_english_sts_v2',
name: 'Eleven English v2',
can_be_finetuned: false,
can_do_text_to_speech: false,
can_do_voice_conversion: true,
can_use_style: true,
can_use_speaker_boost: true,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our state-of-the-art speech to speech model suitable for scenarios where you need maximum control over the content and prosody of your generations.',
requires_alpha_access: false,
max_characters_request_free_user: 5000,
max_characters_request_subscribed_user: 5000,
maximum_text_length_per_request: 5000,
languages: [
{
language_id: 'en',
name: 'English',
},
],
model_rates: {
character_cost_multiplier: 1,
},
concurrency_group: 'standard',
},
{
model_id: 'eleven_multilingual_v1',
name: 'Eleven Multilingual v1',
can_be_finetuned: false,
can_do_text_to_speech: true,
can_do_voice_conversion: false,
can_use_style: false,
can_use_speaker_boost: false,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our first Multilingual model, capability of generating speech in 10 languages. Now outclassed by Multilingual v2 (for content creation) and Turbo v2.5 (for low latency use cases).',
requires_alpha_access: false,
max_characters_request_free_user: 10000,
max_characters_request_subscribed_user: 10000,
maximum_text_length_per_request: 10000,
languages: [
{
language_id: 'en',
name: 'English',
},
{
language_id: 'de',
name: 'German',
},
{
language_id: 'pl',
name: 'Polish',
},
{
language_id: 'es',
name: 'Spanish',
},
{
language_id: 'it',
name: 'Italian',
},
{
language_id: 'fr',
name: 'French',
},
{
language_id: 'pt',
name: 'Portuguese',
},
{
language_id: 'hi',
name: 'Hindi',
},
{
language_id: 'ar',
name: 'Arabic',
},
],
model_rates: {
character_cost_multiplier: 1,
},
concurrency_group: 'standard',
},
{
model_id: 'eleven_multilingual_sts_v2',
name: 'Eleven Multilingual v2',
can_be_finetuned: true,
can_do_text_to_speech: false,
can_do_voice_conversion: true,
can_use_style: true,
can_use_speaker_boost: true,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our cutting-edge, multilingual speech-to-speech model is designed for situations that demand unparalleled control over both the content and the prosody of the generated speech across various languages.',
requires_alpha_access: false,
max_characters_request_free_user: 10000,
max_characters_request_subscribed_user: 10000,
maximum_text_length_per_request: 10000,
languages: [
{
language_id: 'en',
name: 'English',
},
{
language_id: 'ja',
name: 'Japanese',
},
{
language_id: 'zh',
name: 'Chinese',
},
{
language_id: 'de',
name: 'German',
},
{
language_id: 'hi',
name: 'Hindi',
},
{
language_id: 'fr',
name: 'French',
},
{
language_id: 'ko',
name: 'Korean',
},
{
language_id: 'pt',
name: 'Portuguese',
},
{
language_id: 'it',
name: 'Italian',
},
{
language_id: 'es',
name: 'Spanish',
},
{
language_id: 'ru',
name: 'Russian',
},
{
language_id: 'id',
name: 'Indonesian',
},
{
language_id: 'nl',
name: 'Dutch',
},
{
language_id: 'tr',
name: 'Turkish',
},
{
language_id: 'fil',
name: 'Filipino',
},
{
language_id: 'pl',
name: 'Polish',
},
{
language_id: 'sv',
name: 'Swedish',
},
{
language_id: 'bg',
name: 'Bulgarian',
},
{
language_id: 'ro',
name: 'Romanian',
},
{
language_id: 'ar',
name: 'Arabic',
},
{
language_id: 'cs',
name: 'Czech',
},
{
language_id: 'el',
name: 'Greek',
},
{
language_id: 'fi',
name: 'Finnish',
},
{
language_id: 'hr',
name: 'Croatian',
},
{
language_id: 'ms',
name: 'Malay',
},
{
language_id: 'sk',
name: 'Slovak',
},
{
language_id: 'da',
name: 'Danish',
},
{
language_id: 'ta',
name: 'Tamil',
},
{
language_id: 'uk',
name: 'Ukrainian',
},
],
model_rates: {
character_cost_multiplier: 1,
},
concurrency_group: 'standard',
},
{
model_id: 'eleven_monolingual_v1',
name: 'Eleven English v1',
can_be_finetuned: false,
can_do_text_to_speech: true,
can_do_voice_conversion: false,
can_use_style: false,
can_use_speaker_boost: false,
serves_pro_voices: false,
token_cost_factor: 1,
description: 'Our first ever text to speech model. Now outclassed by Multilingual v2 (for content creation) and Turbo v2.5 (for low latency use cases).',
requires_alpha_access: false,
max_characters_request_free_user: 10000,
max_characters_request_subscribed_user: 10000,
maximum_text_length_per_request: 10000,
languages: [
{
language_id: 'en',
name: 'English',
},
],
model_rates: {
character_cost_multiplier: 1,
},
concurrency_group: 'standard',
},
]