Skip to content

Commit 7e7b2cd

Browse files
committed
feat(stage-pages,stage-ui,i18n): supported CometAPI
Close #619
1 parent 6bf15a8 commit 7e7b2cd

File tree

10 files changed

+383
-0
lines changed

10 files changed

+383
-0
lines changed

cspell.config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ words:
4040
- clustr
4141
- collectblock
4242
- colorjs
43+
- cometapi
4344
- Comfortaa
4445
- composables
4546
- cooldown

packages/i18n/src/locales/en/settings.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,9 @@ pages:
568568
302-ai:
569569
description: 302.AI
570570
title: 302.AI
571+
comet-api:
572+
description: CometAPI.com
573+
title: Comet API
571574
transcriptions:
572575
playground:
573576
title: Transcription Playground

packages/i18n/src/locales/es/settings.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ pages:
506506
302-ai:
507507
description: 302.AI
508508
title: 302.AI
509+
comet-api:
510+
description: CometAPI.com
511+
title: Comet API
509512
transcriptions:
510513
playground:
511514
title: Playground de Transcripción

packages/i18n/src/locales/fr/settings.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,9 @@ pages:
509509
302-ai:
510510
description: 302.AI
511511
title: 302.AI
512+
comet-api:
513+
description: CometAPI.com
514+
title: Comet API
512515
transcriptions:
513516
playground:
514517
title: Terrain de test de transcription

packages/i18n/src/locales/ru/settings.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ pages:
490490
302-ai:
491491
description: 302.AI
492492
title: 302.AI
493+
comet-api:
494+
description: CometAPI.com
495+
title: Comet API
493496
transcriptions:
494497
playground:
495498
title: Песочница транскрипции

packages/i18n/src/locales/vi/settings.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,9 @@ pages:
495495
302-ai:
496496
description: 302.AI
497497
title: 302.AI
498+
comet-api:
499+
description: CometAPI.com
500+
title: Comet API
498501
transcriptions:
499502
playground:
500503
title: Transcription Playground

packages/i18n/src/locales/zh-Hans/settings.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,9 @@ pages:
500500
302-ai:
501501
description: 302.AI
502502
title: 302.AI
503+
comet-api:
504+
description: CometAPI.com
505+
title: Comet API
503506
transcriptions:
504507
playground:
505508
title: 实验平台
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
<script setup lang="ts">
2+
import type { RemovableRef } from '@vueuse/core'
3+
import type { SpeechProvider } from '@xsai-ext/shared-providers'
4+
5+
import {
6+
Alert,
7+
ProviderAdvancedSettings,
8+
ProviderApiKeyInput,
9+
ProviderBaseUrlInput,
10+
ProviderBasicSettings,
11+
ProviderSettingsContainer,
12+
ProviderSettingsLayout,
13+
SpeechPlaygroundOpenAICompatible,
14+
} from '@proj-airi/stage-ui/components'
15+
import { useProviderValidation } from '@proj-airi/stage-ui/composables/use-provider-validation'
16+
import { useSpeechStore } from '@proj-airi/stage-ui/stores/modules/speech'
17+
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
18+
import { FieldRange } from '@proj-airi/ui'
19+
import { storeToRefs } from 'pinia'
20+
import { computed, ref } from 'vue'
21+
22+
const speechStore = useSpeechStore()
23+
const providersStore = useProvidersStore()
24+
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
25+
26+
const defaultVoiceSettings = {
27+
speed: 1.0,
28+
}
29+
30+
// Get provider metadata
31+
const providerId = 'comet-api-speech'
32+
33+
// Settings refs
34+
const apiKey = computed({
35+
get: () => providers.value[providerId]?.apiKey || '',
36+
set: (value) => {
37+
if (providers.value[providerId])
38+
providers.value[providerId].apiKey = value
39+
},
40+
})
41+
42+
const baseUrl = computed({
43+
get: () => providers.value[providerId]?.baseUrl || '',
44+
set: (value) => {
45+
if (providers.value[providerId])
46+
providers.value[providerId].baseUrl = value
47+
},
48+
})
49+
50+
const model = computed({
51+
get: () => providers.value[providerId]?.model || 'tts-1',
52+
set: (value) => {
53+
if (providers.value[providerId])
54+
providers.value[providerId].model = value
55+
},
56+
})
57+
58+
const voice = computed({
59+
get: () => providers.value[providerId]?.voice || 'alloy',
60+
set: (value) => {
61+
if (providers.value[providerId])
62+
providers.value[providerId].voice = value
63+
},
64+
})
65+
66+
const speed = ref<number>(1.0)
67+
68+
// Check if API key is configured
69+
const apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey)
70+
71+
// Generate speech with specific parameters
72+
async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean, modelId?: string) {
73+
const provider = await providersStore.getProviderInstance<SpeechProvider<string>>(providerId)
74+
if (!provider)
75+
throw new Error('Failed to initialize speech provider')
76+
77+
const providerConfig = providersStore.getProviderConfig(providerId)
78+
79+
return await speechStore.speech(
80+
provider,
81+
modelId || model.value,
82+
input,
83+
voiceId || voice.value,
84+
{
85+
...providerConfig,
86+
...defaultVoiceSettings,
87+
speed: speed.value,
88+
},
89+
)
90+
}
91+
92+
// Use the composable to get validation logic and state
93+
const {
94+
t,
95+
router,
96+
providerMetadata,
97+
isValidating,
98+
isValid,
99+
validationMessage,
100+
handleResetSettings,
101+
} = useProviderValidation(providerId)
102+
</script>
103+
104+
<template>
105+
<ProviderSettingsLayout
106+
:provider-name="providerMetadata?.localizedName"
107+
:provider-icon-color="providerMetadata?.iconColor"
108+
:on-back="() => router.back()"
109+
>
110+
<ProviderSettingsContainer>
111+
<ProviderBasicSettings
112+
:title="t('settings.pages.providers.common.section.basic.title')"
113+
:description="t('settings.pages.providers.common.section.basic.description')"
114+
:on-reset="handleResetSettings"
115+
>
116+
<ProviderApiKeyInput
117+
v-model="apiKey"
118+
:required="false"
119+
:provider-name="providerMetadata?.localizedName"
120+
placeholder="sk-..."
121+
/>
122+
</ProviderBasicSettings>
123+
124+
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
125+
<ProviderBaseUrlInput
126+
v-model="baseUrl"
127+
:placeholder="providerMetadata?.defaultOptions?.().baseUrl as string || 'https://api.cometapi.com/v1/'"
128+
/>
129+
<FieldRange
130+
v-model="speed"
131+
:label="t('settings.pages.providers.provider.common.fields.field.speed.label')"
132+
:description="t('settings.pages.providers.provider.common.fields.field.speed.description')"
133+
:min="0.5"
134+
:max="2.0" :step="0.01"
135+
/>
136+
</ProviderAdvancedSettings>
137+
138+
<!-- Validation Status -->
139+
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
140+
<template #title>
141+
{{ t('settings.dialogs.onboarding.validationFailed') }}
142+
</template>
143+
<template v-if="validationMessage" #content>
144+
<div class="whitespace-pre-wrap break-all">
145+
{{ validationMessage }}
146+
</div>
147+
</template>
148+
</Alert>
149+
<Alert v-if="isValid && isValidating === 0" type="success">
150+
<template #title>
151+
{{ t('settings.dialogs.onboarding.validationSuccess') }}
152+
</template>
153+
</Alert>
154+
</ProviderSettingsContainer>
155+
156+
<SpeechPlaygroundOpenAICompatible
157+
v-model:model-value="model"
158+
v-model:voice="voice"
159+
:generate-speech="handleGenerateSpeech"
160+
:api-key-configured="apiKeyConfigured"
161+
default-text="Hello! This is a test of the Comet API Speech."
162+
/>
163+
</ProviderSettingsLayout>
164+
</template>
165+
166+
<route lang="yaml">
167+
meta:
168+
layout: settings
169+
stageTransition:
170+
name: slide
171+
</route>
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<script setup lang="ts">
2+
import type { RemovableRef } from '@vueuse/core'
3+
import type { TranscriptionProvider } from '@xsai-ext/shared-providers'
4+
5+
import {
6+
Alert,
7+
ProviderAdvancedSettings,
8+
ProviderApiKeyInput,
9+
ProviderBaseUrlInput,
10+
ProviderBasicSettings,
11+
ProviderSettingsContainer,
12+
ProviderSettingsLayout,
13+
TranscriptionPlayground,
14+
} from '@proj-airi/stage-ui/components'
15+
import { useProviderValidation } from '@proj-airi/stage-ui/composables/use-provider-validation'
16+
import { useHearingStore } from '@proj-airi/stage-ui/stores/modules/hearing'
17+
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
18+
import { FieldInput } from '@proj-airi/ui'
19+
import { storeToRefs } from 'pinia'
20+
import { computed } from 'vue'
21+
22+
const providerId = 'comet-api-transcription'
23+
const hearingStore = useHearingStore()
24+
const providersStore = useProvidersStore()
25+
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
26+
27+
// Define computed properties for credentials
28+
const apiKey = computed({
29+
get: () => providers.value[providerId]?.apiKey || '',
30+
set: (value) => {
31+
if (!providers.value[providerId])
32+
providers.value[providerId] = {}
33+
providers.value[providerId].apiKey = value
34+
},
35+
})
36+
37+
const baseUrl = computed({
38+
get: () => providers.value[providerId]?.baseUrl || '',
39+
set: (value) => {
40+
if (!providers.value[providerId])
41+
providers.value[providerId] = {}
42+
providers.value[providerId].baseUrl = value
43+
},
44+
})
45+
46+
const model = computed({
47+
get: () => providers.value[providerId]?.model || '',
48+
set: (value) => {
49+
if (!providers.value[providerId])
50+
providers.value[providerId] = {}
51+
providers.value[providerId].model = value
52+
},
53+
})
54+
55+
// Check if API key is configured
56+
const apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey)
57+
58+
// Generate transcription
59+
async function handleGenerateTranscription(file: File) {
60+
const provider = await providersStore.getProviderInstance<TranscriptionProvider<string>>(providerId)
61+
if (!provider)
62+
throw new Error('Failed to initialize transcription provider')
63+
64+
return await hearingStore.transcription(
65+
provider,
66+
model.value,
67+
file,
68+
'json',
69+
)
70+
}
71+
72+
// Use the composable to get validation logic and state
73+
const {
74+
t,
75+
router,
76+
providerMetadata,
77+
isValidating,
78+
isValid,
79+
validationMessage,
80+
handleResetSettings,
81+
} = useProviderValidation(providerId)
82+
</script>
83+
84+
<template>
85+
<ProviderSettingsLayout
86+
:provider-name="providerMetadata?.localizedName"
87+
:provider-icon-color="providerMetadata?.iconColor"
88+
:on-back="() => router.back()"
89+
>
90+
<ProviderSettingsContainer>
91+
<ProviderBasicSettings
92+
:title="t('settings.pages.providers.common.section.basic.title')"
93+
:description="t('settings.pages.providers.common.section.basic.description')"
94+
:on-reset="handleResetSettings"
95+
>
96+
<ProviderApiKeyInput
97+
v-model="apiKey"
98+
:provider-name="providerMetadata?.localizedName"
99+
placeholder="sk-..."
100+
/>
101+
<FieldInput
102+
v-model="model"
103+
:label="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.manual_model_name')"
104+
:placeholder="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.manual_model_placeholder')"
105+
/>
106+
</ProviderBasicSettings>
107+
108+
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
109+
<ProviderBaseUrlInput
110+
v-model="baseUrl"
111+
:placeholder="providerMetadata?.defaultOptions?.().baseUrl as string || 'https://api.cometapi.com/v1/'"
112+
/>
113+
</ProviderAdvancedSettings>
114+
115+
<!-- Validation Status -->
116+
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
117+
<template #title>
118+
{{ t('settings.dialogs.onboarding.validationFailed') }}
119+
</template>
120+
<template v-if="validationMessage" #content>
121+
<div class="whitespace-pre-wrap break-all">
122+
{{ validationMessage }}
123+
</div>
124+
</template>
125+
</Alert>
126+
<Alert v-if="isValid && isValidating === 0" type="success">
127+
<template #title>
128+
{{ t('settings.dialogs.onboarding.validationSuccess') }}
129+
</template>
130+
</Alert>
131+
</ProviderSettingsContainer>
132+
133+
<TranscriptionPlayground
134+
:generate-transcription="handleGenerateTranscription"
135+
:api-key-configured="apiKeyConfigured"
136+
/>
137+
</ProviderSettingsLayout>
138+
</template>
139+
140+
<route lang="yaml">
141+
meta:
142+
layout: settings
143+
stageTransition:
144+
name: slide
145+
</route>

0 commit comments

Comments
 (0)