chore(stage-web,stage-tamagotchi): sync providers, fix ollama provider issue
This commit is contained in:
@@ -40,7 +40,7 @@ const {
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
|
||||
const headers = ref<{ key: string, value: string }[]>(Object.entries(providers.value[providerId]?.headers).map(([key, value]) => ({ key, value } as { key: string, value: string })) || [{ key: '', value: '' }])
|
||||
const headers = ref<{ key: string, value: string }[]>(Object.entries(providers.value[providerId]?.headers || {}).map(([key, value]) => ({ key, value } as { key: string, value: string })) || [{ key: '', value: '' }])
|
||||
|
||||
function addKeyValue(headers: { key: string, value: string }[], key: string, value: string) {
|
||||
if (!headers)
|
||||
|
||||
@@ -40,7 +40,7 @@ const {
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
|
||||
const headers = ref<{ key: string, value: string }[]>(Object.entries(providers.value[providerId]?.headers).map(([key, value]) => ({ key, value } as { key: string, value: string })) || [{ key: '', value: '' }])
|
||||
const headers = ref<{ key: string, value: string }[]>(Object.entries(providers.value[providerId]?.headers || {}).map(([key, value]) => ({ key, value } as { key: string, value: string })) || [{ key: '', value: '' }])
|
||||
|
||||
function addKeyValue(headers: { key: string, value: string }[], key: string, value: string) {
|
||||
if (!headers)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,92 +10,52 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'anthropic'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'anthropic'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || 'https://api.anthropic.com/v1/',
|
||||
get: () => providers.value[providerId]?.baseUrl || '',
|
||||
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.anthropic.com/v1/',
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || 'https://api.anthropic.com/v1/'
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || 'https://api.anthropic.com/v1/',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
baseUrl: 'https://api.anthropic.com/v1/',
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName || 'Anthropic | Claude'"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<div bg="orange-50 dark:orange-900/20" rounded-xl p-4 flex="~ col gap-3">
|
||||
<h2 text-xl font-semibold text="orange-700 dark:orange-500">
|
||||
{{ t('settings.pages.providers.provider.anthropic.helpinfo.title') }}
|
||||
</h2>
|
||||
<p>
|
||||
{{ t('settings.pages.providers.provider.anthropic.helpinfo.description.part1') }}
|
||||
<a underline href="https://docs.anthropic.com/en/api/openai-sdk">{{ t('settings.pages.providers.provider.anthropic.helpinfo.description.part2') }}</a>,
|
||||
{{ t('settings.pages.providers.provider.anthropic.helpinfo.description.part3') }} <a underline href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS">CORS</a>
|
||||
{{ t('settings.pages.providers.provider.anthropic.helpinfo.description.part4') }}
|
||||
</p>
|
||||
<p>
|
||||
{{ t('settings.pages.providers.provider.anthropic.helpinfo.description.part5') }}
|
||||
<a underline href="https://workers.cloudflare.com/">Cloudflare Workers</a> {{ t('settings.pages.providers.provider.anthropic.helpinfo.description.part6') }}
|
||||
</p>
|
||||
</div>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
@@ -103,8 +64,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName || 'Anthropic'"
|
||||
placeholder="sk-..."
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="sk-ant-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
@@ -114,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.anthropic.com/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAccountIdInput,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
@@ -9,28 +10,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'azure-ai-foundry'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'azure-ai-foundry'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -40,7 +34,6 @@ const resourceName = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].resourceName = value
|
||||
},
|
||||
})
|
||||
@@ -50,7 +43,6 @@ const apiVersion = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiVersion = value
|
||||
},
|
||||
})
|
||||
@@ -60,44 +52,26 @@ const modelId = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].modelId = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
if (!providers.value[providerId]) {
|
||||
providers.value[providerId] = {}
|
||||
}
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
resourceName.value = providers.value[providerId]?.resourceName || ''
|
||||
apiVersion.value = providers.value[providerId]?.apiVersion || ''
|
||||
modelId.value = providers.value[providerId]?.modelId || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, resourceName, apiVersion, modelId], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
resourceName: resourceName.value,
|
||||
apiVersion: apiVersion.value,
|
||||
modelId: modelId.value,
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName || 'Azure OpenAI'"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -108,7 +82,7 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName || 'Azure OpenAI'"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="..."
|
||||
required
|
||||
/>
|
||||
@@ -136,6 +110,23 @@ function handleResetSettings() {
|
||||
description="API version for snapshot of the models"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
@@ -2,34 +2,28 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAccountIdInput,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBasicSettings,
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'cloudflare-workers-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'cloudflare-workers-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -39,34 +33,20 @@ const accountId = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].accountId = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
accountId.value = providers.value[providerId]?.accountId || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, accountId], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
accountId: accountId.value,
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -94,13 +74,30 @@ function handleResetSettings() {
|
||||
:placeholder="t('settings.pages.providers.provider.cloudflare-workers-ai.fields.field.account-id.placeholder')"
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,28 +10,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'deepseek'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'deepseek'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -40,34 +34,20 @@ const baseUrl = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -85,7 +65,7 @@ function handleResetSettings() {
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="sk-..."
|
||||
placeholder="ds-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
@@ -95,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.deepseek.com/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,28 +10,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'featherless-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'featherless-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -40,40 +34,26 @@ const baseUrl = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -85,7 +65,7 @@ function handleResetSettings() {
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="fw-..."
|
||||
placeholder="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
@@ -95,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.featherless.ai/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,28 +10,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'fireworks-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'fireworks-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -40,40 +34,26 @@ const baseUrl = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -95,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.fireworks.ai/inference/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,28 +10,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'google-generative-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'google-generative-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -40,44 +34,26 @@ const baseUrl = computed({
|
||||
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.anthropic.com/v1/',
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || 'https://generativelanguage.googleapis.com/v1beta/openai/'
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || 'https://generativelanguage.googleapis.com/v1beta/openai/',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai/',
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName || 'Google | Gemini'"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -88,8 +64,8 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName || 'Google'"
|
||||
placeholder="GEMINI_API_KEY"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="AIza..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
@@ -99,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://generativelanguage.googleapis.com/v1beta/openai/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -7,29 +7,36 @@ import {
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useSpeechStore } from '@proj-airi/stage-ui/stores/modules/speech'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, watch } from 'vue'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
// import { useI18n } from 'vue-i18n'
|
||||
|
||||
// const { t } = useI18n()
|
||||
|
||||
const providerId = 'index-tts-vllm'
|
||||
const defaultModel = 'IndexTTS-1.5'
|
||||
|
||||
const speechStore = useSpeechStore()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore)
|
||||
// const { t } = useI18n()
|
||||
// const { providers } = storeToRefs(providersStore)
|
||||
|
||||
// Check if API key is configured
|
||||
// const apiKeyConfigured = computed(() => !!providers.value[providerId]?.apiKey)
|
||||
const apiKeyConfigured = true // Assuming API key is always configured as its not required
|
||||
|
||||
// Get available voices for Index TTS
|
||||
// Get available voices for Index TTS provider
|
||||
const availableVoices = computed(() => {
|
||||
return speechStore.availableVoices[providerId] || []
|
||||
})
|
||||
|
||||
// Generate speech with IndexTTS-specific parameters
|
||||
async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean) {
|
||||
onMounted(async () => {
|
||||
await speechStore.loadVoicesForProvider(providerId)
|
||||
})
|
||||
|
||||
watch([apiKeyConfigured], async () => {
|
||||
await speechStore.loadVoicesForProvider(providerId)
|
||||
})
|
||||
|
||||
async function handleGenerateSpeech(input: string, voiceId: string) {
|
||||
const provider = await providersStore.getProviderInstance(providerId) as SpeechProvider
|
||||
if (!provider) {
|
||||
throw new Error('Failed to initialize speech provider')
|
||||
@@ -41,44 +48,28 @@ async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: bo
|
||||
// Get model from configuration or use default
|
||||
const model = providerConfig.model as string | undefined || defaultModel
|
||||
|
||||
// Index TTS doesn't need SSML conversion, but if SSML is provided, use it directly
|
||||
const options = {
|
||||
...providerConfig,
|
||||
}
|
||||
|
||||
return await speechStore.speech(
|
||||
provider,
|
||||
model,
|
||||
input,
|
||||
voiceId,
|
||||
{
|
||||
...providerConfig,
|
||||
},
|
||||
options,
|
||||
)
|
||||
}
|
||||
|
||||
watch([providers], async () => {
|
||||
const providerConfig = providersStore.getProviderConfig(providerId)
|
||||
const providerMetadata = providersStore.getProviderMetadata(providerId)
|
||||
if (await providerMetadata.validators.validateProviderConfig(providerConfig)) {
|
||||
await speechStore.loadVoicesForProvider(providerId)
|
||||
}
|
||||
else {
|
||||
console.error('Failed to validate provider config', providerConfig)
|
||||
}
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SpeechProviderSettings
|
||||
:provider-id="providerId"
|
||||
:default-model="defaultModel"
|
||||
>
|
||||
<SpeechProviderSettings :provider-id="providerId" :default-model="defaultModel">
|
||||
<!-- Replace the default playground with our standalone component -->
|
||||
<template #playground>
|
||||
<SpeechPlayground
|
||||
:available-voices="availableVoices"
|
||||
:generate-speech="handleGenerateSpeech"
|
||||
:api-key-configured="apiKeyConfigured"
|
||||
default-text="Hello! This is a test of the Index TTS voice synthesis."
|
||||
:available-voices="availableVoices" :generate-speech="handleGenerateSpeech"
|
||||
:api-key-configured="apiKeyConfigured" :use-ssml="false"
|
||||
default-text="Hello! This is a test of the Index TTS Speech synthesis?."
|
||||
/>
|
||||
</template>
|
||||
</SpeechProviderSettings>
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
import { IconStatusItem } from '@proj-airi/stage-ui/components'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import IconAnimation from '../../../components/IconAnimation.vue'
|
||||
|
||||
import { useIconAnimation } from '../../../composables/icon-animation'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const providersStore = useProvidersStore()
|
||||
const {
|
||||
allChatProvidersMetadata,
|
||||
@@ -25,29 +22,25 @@ const {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div flex flex-col gap-5 pb-12>
|
||||
<div class="rounded-lg bg-primary-500/10 p-4 dark:bg-primary-800/25">
|
||||
<div class="mb-2 text-xl text-primary-800 font-semibold dark:text-primary-100">
|
||||
{{ $t('settings.pages.providers.helpinfo.title') }}
|
||||
<div mb-6 flex flex-col gap-5>
|
||||
<div bg="primary-500/10 dark:primary-800/25" rounded-lg p-4>
|
||||
<div mb-2 text-xl font-normal text="primary-800 dark:primary-100">
|
||||
First time here?
|
||||
</div>
|
||||
<div class="text-primary-700 dark:text-primary-300">
|
||||
<i18n-t keypath="settings.pages.providers.helpinfo.description">
|
||||
<template #chat>
|
||||
<span class="inline-flex translate-y-[0.25lh] items-center gap-1 rounded-lg bg-primary-500/10 px-2 py-0.5 dark:bg-primary-800/25">
|
||||
<div class="i-solar:chat-square-like-bold-duotone" />
|
||||
<strong class="font-semibold">Chat</strong>
|
||||
</span>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<div text="primary-700 dark:primary-300">
|
||||
AIRI requires at least one <div bg="primary-500/10 dark:primary-800/25" inline-flex items-center gap-1 rounded-lg px-2 py-0.5 translate-y="[0.25lh]">
|
||||
<div i-solar:chat-square-like-bold-duotone /><strong font-normal>Chat</strong>
|
||||
</div> provider to be configured to think, and behave properly. You could think of
|
||||
it as the brain of the characters living in AIRI system.
|
||||
</div>
|
||||
</div>
|
||||
<div flex="~ row items-center gap-2">
|
||||
<div i-solar:chat-square-like-bold-duotone text="neutral-500 dark:neutral-400 4xl" />
|
||||
<div>
|
||||
<div>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.pages.providers.explained.chat') }} </span>
|
||||
<span text="neutral-300 dark:neutral-500 sm sm:base">Text generation model providers. e.g. OpenRouter, OpenAI, Ollama.</span>
|
||||
</div>
|
||||
<div flex text-nowrap text-3xl font-normal>
|
||||
<div flex text-nowrap text="2xl sm:3xl" font-normal>
|
||||
<div>
|
||||
Chat
|
||||
</div>
|
||||
@@ -56,10 +49,19 @@ const {
|
||||
</div>
|
||||
<div grid="~ cols-1 sm:cols-2 xl:cols-3 gap-4">
|
||||
<IconStatusItem
|
||||
v-for="(provider, index) of allChatProvidersMetadata" :key="provider.id" v-motion
|
||||
:initial="{ opacity: 0, y: 10 }" :enter="{ opacity: 1, y: 0 }" :duration="250 + index * 10" :delay="index * 50"
|
||||
:title="provider.localizedName || 'Unknown'" :description="provider.localizedDescription" :icon="provider.icon"
|
||||
:icon-color="provider.iconColor" :icon-image="provider.iconImage" :to="`/settings/providers/${provider.id}`"
|
||||
v-for="(provider, index) of allChatProvidersMetadata"
|
||||
:key="provider.id"
|
||||
v-motion
|
||||
:initial="{ opacity: 0, y: 10 }"
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250 + index * 10"
|
||||
:delay="index * 50"
|
||||
:title="provider.localizedName || 'Unknown'"
|
||||
:description="provider.localizedDescription"
|
||||
:icon="provider.icon"
|
||||
:icon-color="provider.iconColor"
|
||||
:icon-image="provider.iconImage"
|
||||
:to="`/settings/providers/${provider.id}`"
|
||||
:configured="provider.configured"
|
||||
/>
|
||||
</div>
|
||||
@@ -67,9 +69,9 @@ const {
|
||||
<div i-solar:user-speak-rounded-bold-duotone text="neutral-500 dark:neutral-400 4xl" />
|
||||
<div>
|
||||
<div>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.pages.providers.explained.Speech') }}</span>
|
||||
<span text="neutral-300 dark:neutral-500 sm sm:base">Speech (text-to-speech) model providers. e.g. ElevenLabs, Azure Speech.</span>
|
||||
</div>
|
||||
<div flex text-nowrap text-3xl font-normal>
|
||||
<div flex text-nowrap text="2xl sm:3xl" font-normal>
|
||||
<div>
|
||||
Speech
|
||||
</div>
|
||||
@@ -78,20 +80,29 @@ const {
|
||||
</div>
|
||||
<div grid="~ cols-1 sm:cols-2 xl:cols-3 gap-4">
|
||||
<IconStatusItem
|
||||
v-for="(provider, index) of allAudioSpeechProvidersMetadata" :key="provider.id" v-motion
|
||||
:initial="{ opacity: 0, y: 10 }" :enter="{ opacity: 1, y: 0 }" :duration="250 + index * 10"
|
||||
:delay="(allChatProvidersMetadata.length + index) * 50" :title="provider.localizedName || 'Unknown'"
|
||||
:description="provider.localizedDescription" :icon="provider.icon" :icon-color="provider.iconColor"
|
||||
:icon-image="provider.iconImage" :to="`/settings/providers/${provider.id}`" :configured="provider.configured"
|
||||
v-for="(provider, index) of allAudioSpeechProvidersMetadata"
|
||||
:key="provider.id"
|
||||
v-motion
|
||||
:initial="{ opacity: 0, y: 10 }"
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250 + index * 10"
|
||||
:delay="(allChatProvidersMetadata.length + index) * 50"
|
||||
:title="provider.localizedName || 'Unknown'"
|
||||
:description="provider.localizedDescription"
|
||||
:icon="provider.icon"
|
||||
:icon-color="provider.iconColor"
|
||||
:icon-image="provider.iconImage"
|
||||
:to="`/settings/providers/${provider.id}`"
|
||||
:configured="provider.configured"
|
||||
/>
|
||||
</div>
|
||||
<div flex="~ row items-center gap-2" my-5>
|
||||
<div i-solar:microphone-3-bold-duotone text="neutral-500 dark:neutral-400 4xl" />
|
||||
<div>
|
||||
<div>
|
||||
<span text="neutral-300 dark:neutral-500">{{ t('settings.pages.providers.explained.Transcription') }}</span>
|
||||
<span text="neutral-300 dark:neutral-500 sm sm:base">Transcription (speech-to-text) model providers. e.g. Whisper.cpp, OpenAI, Azure Speech</span>
|
||||
</div>
|
||||
<div flex text-nowrap text-3xl font-normal>
|
||||
<div flex text-nowrap text="2xl sm:3xl" font-normal>
|
||||
<div>
|
||||
Transcription
|
||||
</div>
|
||||
@@ -100,24 +111,44 @@ const {
|
||||
</div>
|
||||
<div grid="~ cols-1 sm:cols-2 xl:cols-3 gap-4">
|
||||
<IconStatusItem
|
||||
v-for="(provider, index) of allAudioTranscriptionProvidersMetadata" :key="provider.id" v-motion
|
||||
:initial="{ opacity: 0, y: 10 }" :enter="{ opacity: 1, y: 0 }" :duration="250 + index * 10"
|
||||
v-for="(provider, index) of allAudioTranscriptionProvidersMetadata"
|
||||
:key="provider.id"
|
||||
v-motion
|
||||
:initial="{ opacity: 0, y: 10 }"
|
||||
:enter="{ opacity: 1, y: 0 }"
|
||||
:duration="250 + index * 10"
|
||||
:delay="(allChatProvidersMetadata.length + allAudioSpeechProvidersMetadata.length + index) * 50"
|
||||
:title="provider.localizedName || 'Unknown'" :description="provider.localizedDescription" :icon="provider.icon"
|
||||
:icon-color="provider.iconColor" :icon-image="provider.iconImage" :to="`/settings/providers/${provider.id}`"
|
||||
:title="provider.localizedName || 'Unknown'"
|
||||
:description="provider.localizedDescription"
|
||||
:icon="provider.icon"
|
||||
:icon-color="provider.iconColor"
|
||||
:icon-image="provider.iconImage"
|
||||
:to="`/settings/providers/${provider.id}`"
|
||||
:configured="provider.configured"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<IconAnimation
|
||||
v-if="showIconAnimation" :z-index="-1" :icon="animationIcon" :icon-size="12" :duration="1000"
|
||||
:started="iconAnimationStarted" :is-reverse="true" position="calc(100dvw - 9.5rem), calc(100dvh - 9.5rem)"
|
||||
v-if="showIconAnimation"
|
||||
:z-index="-1"
|
||||
:icon="animationIcon"
|
||||
:icon-size="12"
|
||||
:duration="1000"
|
||||
:started="iconAnimationStarted"
|
||||
:is-reverse="true"
|
||||
position="calc(100dvw - 9.5rem), calc(100dvh - 9.5rem)"
|
||||
text-color="text-neutral-200/50 dark:text-neutral-600/20"
|
||||
/>
|
||||
<div
|
||||
v-else v-motion text="neutral-500/50 dark:neutral-600/20" pointer-events-none fixed top="[calc(100dvh-15rem)]"
|
||||
bottom-0 right--5 z--1 :initial="{ scale: 0.9, opacity: 0, y: 20 }" :enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500" size-60 flex items-center justify-center
|
||||
v-else
|
||||
v-motion
|
||||
text="neutral-500/5 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, y: 20 }"
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-solar:box-minimalistic-bold-duotone />
|
||||
</div>
|
||||
|
||||
@@ -4,137 +4,56 @@ import type { RemovableRef } from '@vueuse/core'
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
ProviderBasicSettings,
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { FieldKeyValues } from '@proj-airi/ui'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'lm-studio'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'lm-studio'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
const validationMessage = ref('')
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || providerMetadata.value?.defaultOptions?.().baseUrl || '',
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
const headers = ref<{ key: string, value: string }[]>(Object.entries(providers.value[providerId]?.headers || {}).map(([key, value]) => ({ key, value } as { key: string, value: string })) || [{ key: '', value: '' }])
|
||||
|
||||
function addKeyValue(headers: { key: string, value: string }[], key: string, value: string) {
|
||||
if (!headers)
|
||||
return
|
||||
|
||||
headers.push({ key, value })
|
||||
}
|
||||
|
||||
function removeKeyValue(index: number, headers: { key: string, value: string }[]) {
|
||||
if (!headers)
|
||||
return
|
||||
|
||||
if (headers.length === 1) {
|
||||
headers[0].key = ''
|
||||
headers[0].value = ''
|
||||
}
|
||||
else {
|
||||
headers.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
watch(headers, (headers) => {
|
||||
if (headers.length > 0 && (headers[headers.length - 1].key !== '' || headers[headers.length - 1].value !== '')) {
|
||||
headers.push({ key: '', value: '' })
|
||||
}
|
||||
|
||||
providers.value[providerId].headers = headers.filter(header => header.key !== '').reduce((acc, header) => {
|
||||
acc[header.key] = header.value
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
async function refetch() {
|
||||
try {
|
||||
const validationResult = await providerMetadata.value.validators.validateProviderConfig({
|
||||
baseUrl: baseUrl.value,
|
||||
headers: headers.value.filter(header => header.key !== '').reduce((acc, header) => {
|
||||
acc[header.key] = header.value
|
||||
return acc
|
||||
}, {} as Record<string, string>),
|
||||
})
|
||||
|
||||
if (!validationResult.valid) {
|
||||
validationMessage.value = t('settings.dialogs.onboarding.validationError', {
|
||||
error: validationResult.reason,
|
||||
})
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
validationMessage.value = t('settings.dialogs.onboarding.validationError', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
watch([baseUrl, headers], refetch, { immediate: true })
|
||||
watch(headers, refetch, { deep: true })
|
||||
|
||||
onMounted(() => {
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || providerMetadata.value?.defaultOptions?.().baseUrl || ''
|
||||
|
||||
// Initialize headers if not already set
|
||||
if (!providers.value[providerId]?.headers) {
|
||||
providers.value[providerId].headers = {}
|
||||
}
|
||||
if (headers.value.length === 0) {
|
||||
headers.value = [{ key: '', value: '' }]
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions?.() || {}),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Alert v-if="validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -143,31 +62,44 @@ function handleResetSettings() {
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultOptions?.().baseUrl as string || ''"
|
||||
required
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="lm-studio"
|
||||
:is-required="false"
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<FieldKeyValues
|
||||
v-model="headers"
|
||||
:label="t('settings.pages.providers.common.section.advanced.fields.field.headers.label')"
|
||||
:description="t('settings.pages.providers.common.section.advanced.fields.field.headers.description')"
|
||||
:key-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.key.placeholder')"
|
||||
:value-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.value.placeholder')"
|
||||
@add="(key: string, value: string) => addKeyValue(headers, key, value)"
|
||||
@remove="(index: number) => removeKeyValue(index, headers)"
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="http://localhost:1234/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -35,7 +35,7 @@ const volume = ref(0)
|
||||
|
||||
// Additional settings specific to Microsoft Speech (region)
|
||||
const region = computed({
|
||||
get: () => providers.value[providerId]?.region as string | undefined,
|
||||
get: () => providers.value[providerId]?.region as string | undefined || 'eastasia',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = { region: 'eastasia' }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,28 +10,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'mistral-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'mistral-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -40,34 +34,20 @@ const baseUrl = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -85,7 +65,7 @@ function handleResetSettings() {
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="mis-..."
|
||||
placeholder="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
@@ -95,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.mistral.ai/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,20 +10,26 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'modelscope'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
|
||||
// Use computed properties for settings
|
||||
const apiKey = computed({
|
||||
@@ -62,12 +69,6 @@ watch([apiKey, baseUrl], () => {
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -95,6 +96,23 @@ function handleResetSettings() {
|
||||
placeholder="https://api-inference.modelscope.cn/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,28 +10,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'moonshot-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'moonshot-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -40,40 +34,26 @@ const baseUrl = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -85,7 +65,7 @@ function handleResetSettings() {
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="ms-..."
|
||||
placeholder="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
@@ -95,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.moonshot.cn/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,28 +10,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'novita-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'novita-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
@@ -40,34 +34,20 @@ const baseUrl = computed({
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -85,7 +65,7 @@ function handleResetSettings() {
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="nvt-..."
|
||||
placeholder="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
@@ -95,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.novita.ai/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -9,36 +9,38 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { FieldKeyValues } from '@proj-airi/ui'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'ollama'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
const loading = ref(0)
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'ollama'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
const validationMessage = ref('')
|
||||
|
||||
// Define computed properties for credentials
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || providerMetadata.value?.defaultOptions?.().baseUrl || '',
|
||||
get: () => providers.value[providerId]?.baseUrl || 'http://localhost:11434/v1/',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
const headers = ref(Object.entries(providers.value[providerId]?.headers ?? {}).map(([key, value]) => ({ key, value } as { key: string, value: string })) || [{ key: '', value: '' }])
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
|
||||
const headers = ref<{ key: string, value: string }[]>(Object.entries(providers.value[providerId]?.headers || {}).map(([key, value]) => ({ key, value } as { key: string, value: string })) || [{ key: '', value: '' }])
|
||||
|
||||
function addKeyValue(headers: { key: string, value: string }[], key: string, value: string) {
|
||||
if (!headers)
|
||||
@@ -75,11 +77,6 @@ watch(headers, (headers) => {
|
||||
})
|
||||
|
||||
async function refetch() {
|
||||
loading.value++
|
||||
// service startup time
|
||||
const startValidationTimestamp = performance.now()
|
||||
let finalValidationMessage = ''
|
||||
|
||||
try {
|
||||
const validationResult = await providerMetadata.value.validators.validateProviderConfig({
|
||||
baseUrl: baseUrl.value,
|
||||
@@ -90,25 +87,16 @@ async function refetch() {
|
||||
})
|
||||
|
||||
if (!validationResult.valid) {
|
||||
finalValidationMessage = t('settings.dialogs.onboarding.validationError', {
|
||||
validationMessage.value = t('settings.dialogs.onboarding.validationError', {
|
||||
error: validationResult.reason,
|
||||
})
|
||||
}
|
||||
else {
|
||||
finalValidationMessage = ''
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
finalValidationMessage = t('settings.dialogs.onboarding.validationError', {
|
||||
validationMessage.value = t('settings.dialogs.onboarding.validationError', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
})
|
||||
}
|
||||
finally {
|
||||
setTimeout(() => {
|
||||
loading.value--
|
||||
validationMessage.value = finalValidationMessage
|
||||
}, 500 - (performance.now() - startValidationTimestamp))
|
||||
}
|
||||
}
|
||||
|
||||
watch([baseUrl, headers], refetch, { immediate: true })
|
||||
@@ -128,73 +116,61 @@ onMounted(() => {
|
||||
headers.value = [{ key: '', value: '' }]
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<Alert v-if="!!loading" type="loading">
|
||||
<template #title>
|
||||
{{ t('settings.pages.providers.provider.common.status.validating') }}
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-else-if="!validationMessage" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.pages.providers.provider.common.status.valid') }}
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-else-if="validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultOptions?.().baseUrl as string || ''"
|
||||
required
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="http://localhost:11434/v1/"
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<FieldKeyValues
|
||||
v-model="headers"
|
||||
:label="t('settings.pages.providers.common.section.advanced.fields.field.headers.label')"
|
||||
:description="t('settings.pages.providers.common.section.advanced.fields.field.headers.description')"
|
||||
:key-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.key.placeholder')"
|
||||
:value-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.value.placeholder')"
|
||||
@add="(key: string, value: string) => addKeyValue(headers, key, value)"
|
||||
@remove="(index: number) => removeKeyValue(index, headers)"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</div>
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<FieldKeyValues
|
||||
v-model="headers"
|
||||
:label="t('settings.pages.providers.common.section.advanced.fields.field.headers.label')"
|
||||
:description="t('settings.pages.providers.common.section.advanced.fields.field.headers.description')"
|
||||
:key-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.key.placeholder')"
|
||||
:value-placeholder="t('settings.pages.providers.common.section.advanced.fields.field.headers.value.placeholder')"
|
||||
@add="(key: string, value: string) => addKeyValue(headers, key, value)"
|
||||
@remove="(index: number) => removeKeyValue(index, headers)"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { RemovableRef } from '@vueuse/core'
|
||||
import type { SpeechProvider } from '@xsai-ext/shared-providers'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -11,19 +12,16 @@ import {
|
||||
ProviderSettingsLayout,
|
||||
SpeechPlaygroundOpenAICompatible,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useSpeechStore } from '@proj-airi/stage-ui/stores/modules/speech'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { FieldRange } from '@proj-airi/ui'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const speechStore = useSpeechStore()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
const defaultVoiceSettings = {
|
||||
speed: 1.0,
|
||||
@@ -31,7 +29,6 @@ const defaultVoiceSettings = {
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'openai-compatible-audio-speech'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Settings refs
|
||||
const apiKey = computed({
|
||||
@@ -92,43 +89,22 @@ async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: bo
|
||||
)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
providersStore.initializeProvider(providerId)
|
||||
const config = providers.value[providerId] || {}
|
||||
apiKey.value = config.apiKey || ''
|
||||
baseUrl.value = config.baseUrl || ''
|
||||
model.value = config.model || 'tts-1'
|
||||
voice.value = config.voice || 'alloy'
|
||||
speed.value = config.speed || 1.0
|
||||
})
|
||||
|
||||
watch(speed, (newSpeed) => {
|
||||
if (providers.value[providerId])
|
||||
providers.value[providerId].speed = newSpeed
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
const defaults = providerMetadata.value?.defaultOptions?.() || {}
|
||||
providers.value[providerId] = {
|
||||
apiKey: '',
|
||||
baseUrl: defaults.baseUrl || '',
|
||||
model: 'tts-1',
|
||||
voice: 'alloy',
|
||||
speed: 1.0,
|
||||
}
|
||||
// Force update refs
|
||||
apiKey.value = ''
|
||||
baseUrl.value = defaults.baseUrl || ''
|
||||
model.value = 'tts-1'
|
||||
voice.value = 'alloy'
|
||||
speed.value = 1.0
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName || 'OpenAI Compatible'"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -148,7 +124,7 @@ function handleResetSettings() {
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.example.com/v1/"
|
||||
placeholder="https://api.openai.com/v1/"
|
||||
/>
|
||||
<FieldRange
|
||||
v-model="speed"
|
||||
@@ -158,6 +134,23 @@ function handleResetSettings() {
|
||||
:max="2.0" :step="0.01"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
|
||||
<SpeechPlaygroundOpenAICompatible
|
||||
@@ -171,8 +164,8 @@ function handleResetSettings() {
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
+60
-49
@@ -3,6 +3,7 @@ import type { RemovableRef } from '@vueuse/core'
|
||||
import type { TranscriptionProvider } from '@xsai-ext/shared-providers'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -11,39 +12,44 @@ import {
|
||||
ProviderSettingsLayout,
|
||||
TranscriptionPlayground,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useHearingStore } from '@proj-airi/stage-ui/stores/modules/hearing'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { FieldInput } from '@proj-airi/ui'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const providerId = 'openai-compatible-audio-transcription'
|
||||
const hearingStore = useHearingStore()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'openai-compatible-audio-transcription'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
const pageTitle = computed(() => providerMetadata.value?.localizedName || t('settings.pages.providers.provider.openai-compatible-audio-transcription.title'))
|
||||
|
||||
// Settings refs
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: value => (providers.value[providerId] = { ...providers.value[providerId], apiKey: value }),
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || '',
|
||||
set: value => (providers.value[providerId] = { ...providers.value[providerId], baseUrl: value }),
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
const model = computed({
|
||||
get: () => providers.value[providerId]?.model || 'whisper-1',
|
||||
set: value => (providers.value[providerId] = { ...providers.value[providerId], model: value }),
|
||||
get: () => providers.value[providerId]?.model || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
providers.value[providerId].model = value
|
||||
},
|
||||
})
|
||||
|
||||
// Check if API key is configured
|
||||
@@ -63,32 +69,22 @@ async function handleGenerateTranscription(file: File) {
|
||||
)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
providersStore.initializeProvider(providerId)
|
||||
const config = providers.value[providerId] || {}
|
||||
apiKey.value = config.apiKey || ''
|
||||
baseUrl.value = config.baseUrl || ''
|
||||
model.value = config.model || 'whisper-1'
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
const defaults = providerMetadata.value?.defaultOptions?.() || {}
|
||||
providers.value[providerId] = {
|
||||
apiKey: '',
|
||||
baseUrl: defaults.baseUrl || '',
|
||||
model: 'whisper-1',
|
||||
}
|
||||
// Force update refs
|
||||
apiKey.value = ''
|
||||
baseUrl.value = defaults.baseUrl || ''
|
||||
model.value = 'whisper-1'
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="pageTitle"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -112,23 +108,38 @@ function handleResetSettings() {
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.example.com/v1/"
|
||||
placeholder="https://api.openai.com/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
|
||||
<template #playground>
|
||||
<TranscriptionPlayground
|
||||
:generate-transcription="handleGenerateTranscription"
|
||||
:api-key-configured="apiKeyConfigured"
|
||||
/>
|
||||
</template>
|
||||
<TranscriptionPlayground
|
||||
:generate-transcription="handleGenerateTranscription"
|
||||
:api-key-configured="apiKeyConfigured"
|
||||
/>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,70 +10,50 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'openai-compatible'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'openai-compatible'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || providerMetadata.value?.defaultOptions?.().baseUrl || '',
|
||||
get: () => providers.value[providerId]?.baseUrl || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || providerMetadata.value?.defaultOptions?.().baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || providerMetadata.value?.defaultOptions?.().baseUrl || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName || 'OpenAI Compatible'"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -83,7 +64,6 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:required="false"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="sk-..."
|
||||
/>
|
||||
@@ -92,16 +72,33 @@ function handleResetSettings() {
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultOptions?.().baseUrl as string || 'https://api.example.com/v1/'"
|
||||
placeholder="https://api.openai.com/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,75 +10,50 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'openai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'openai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || 'https://api.openai.com/v1/',
|
||||
get: () => providers.value[providerId]?.baseUrl || '',
|
||||
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/',
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || 'https://api.openai.com/v1/'
|
||||
})
|
||||
|
||||
// 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/',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
baseUrl: 'https://api.openai.com/v1/',
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName || 'OpenAI'"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -88,7 +64,7 @@ function handleResetSettings() {
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName || 'OpenAI'"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
@@ -99,13 +75,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.openai.com/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,70 +10,50 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providerId = 'openrouter-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'openrouter-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
// Define computed properties for credentials
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || providerMetadata.value?.defaultOptions?.().baseUrl || '',
|
||||
get: () => providers.value[providerId]?.baseUrl || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || providerMetadata.value?.defaultOptions?.().baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || providerMetadata.value?.defaultOptions?.().baseUrl || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
// Use the composable to get validation logic and state
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -91,16 +72,33 @@ function handleResetSettings() {
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
:placeholder="providerMetadata?.defaultOptions?.().baseUrl as string || ''"
|
||||
placeholder="https://openrouter.ai/api/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { SpeechProviderWithExtraOptions } from '@xsai-ext/shared-providers'
|
||||
import type { UnElevenLabsOptions } from 'unspeech'
|
||||
|
||||
import {
|
||||
Callout,
|
||||
Alert,
|
||||
SpeechPlayground,
|
||||
SpeechProviderSettings,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
@@ -18,13 +18,11 @@ const defaultModel = 'v1'
|
||||
const speedRatio = ref<number>(1.0)
|
||||
const speechStore = useSpeechStore()
|
||||
const providersStore = useProvidersStore()
|
||||
|
||||
const { t } = useI18n()
|
||||
// Get available voices for Player2
|
||||
const availableVoices = computed(() => {
|
||||
return speechStore.availableVoices[providerId] || []
|
||||
})
|
||||
|
||||
// Generate speech with Player2-specific parameters
|
||||
async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean) {
|
||||
const provider = await providersStore.getProviderInstance(providerId) as SpeechProviderWithExtraOptions<string, UnElevenLabsOptions>
|
||||
@@ -56,7 +54,6 @@ onMounted(async () => {
|
||||
else {
|
||||
console.error('Failed to validate provider config', providerConfig)
|
||||
}
|
||||
|
||||
try {
|
||||
const baseUrl = (providerConfig.baseUrl as string | undefined) ?? ''
|
||||
const res = await fetch(`${baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl}/health`, {
|
||||
@@ -65,7 +62,6 @@ onMounted(async () => {
|
||||
'player2-game-key': 'airi',
|
||||
},
|
||||
})
|
||||
|
||||
hasPlayer2.value = res.status === 200
|
||||
}
|
||||
catch (e) {
|
||||
@@ -73,7 +69,6 @@ onMounted(async () => {
|
||||
hasPlayer2.value = false
|
||||
}
|
||||
})
|
||||
|
||||
watch(speedRatio, async () => {
|
||||
const providerConfig = providersStore.getProviderConfig(providerId)
|
||||
providerConfig.speed = speedRatio.value
|
||||
@@ -81,26 +76,6 @@ watch(speedRatio, async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!hasPlayer2" style="color: red; margin-bottom: 1rem;">
|
||||
<Callout theme="orange">
|
||||
<template #label>
|
||||
Player 2 is not running
|
||||
</template>
|
||||
<div>
|
||||
Please download and run the Player2 App:
|
||||
<a href="https://player2.game" target="_blank" rel="noopener noreferrer">
|
||||
https://player2.game
|
||||
</a>
|
||||
|
||||
<div>
|
||||
After downloading, if you still are having trouble, please reach out to us on Discord:
|
||||
<a href="https://player2.game/discord" target="_blank" rel="noopener noreferrer">
|
||||
https://player2.game/discord
|
||||
</a>.
|
||||
</div>
|
||||
</div>
|
||||
</Callout>
|
||||
</div>
|
||||
<SpeechProviderSettings
|
||||
:provider-id="providerId"
|
||||
:default-model="defaultModel"
|
||||
@@ -126,6 +101,28 @@ watch(speedRatio, async () => {
|
||||
/>
|
||||
</template>
|
||||
</SpeechProviderSettings>
|
||||
<Alert v-if="!hasPlayer2" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
<div>
|
||||
Please download and run the Player2 App:
|
||||
<a href="https://player2.game" target="_blank" rel="noopener noreferrer">
|
||||
https://player2.game
|
||||
</a>
|
||||
|
||||
<div>
|
||||
After downloading, if you still are having trouble, please reach out to us on Discord:
|
||||
<a href="https://player2.game/discord" target="_blank" rel="noopener noreferrer">
|
||||
https://player2.game/discord
|
||||
</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
import type { RemovableRef } from '@vueuse/shared'
|
||||
|
||||
import {
|
||||
Callout,
|
||||
Alert,
|
||||
ProviderBaseUrlInput,
|
||||
ProviderBasicSettings,
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
@@ -45,7 +44,6 @@ onMounted(async () => {
|
||||
'player2-game-key': 'airi',
|
||||
},
|
||||
})
|
||||
|
||||
hasPlayer2.value = res.status === 200
|
||||
}
|
||||
catch (e) {
|
||||
@@ -70,27 +68,6 @@ function handleResetSettings() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!hasPlayer2" mb-1>
|
||||
<Callout theme="orange">
|
||||
<template #label>
|
||||
Player 2 is not running
|
||||
</template>
|
||||
<div>
|
||||
Please download and run the Player2 App:
|
||||
<a href="https://player2.game" target="_blank" rel="noopener noreferrer">
|
||||
https://player2.game
|
||||
</a>
|
||||
|
||||
<div>
|
||||
After downloading, if you still are having trouble, please reach out to us on Discord:
|
||||
<a href="https://player2.game/discord" target="_blank" rel="noopener noreferrer">
|
||||
https://player2.game/discord
|
||||
</a>.
|
||||
</div>
|
||||
</div>
|
||||
</Callout>
|
||||
</div>
|
||||
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
@@ -106,6 +83,28 @@ function handleResetSettings() {
|
||||
</ProviderBasicSettings>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
<Alert v-if="!hasPlayer2" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
<div>
|
||||
Please download and run the Player2 App:
|
||||
<a href="https://player2.game" target="_blank" rel="noopener noreferrer">
|
||||
https://player2.game
|
||||
</a>
|
||||
|
||||
<div>
|
||||
After downloading, if you still are having trouble, please reach out to us on Discord:
|
||||
<a href="https://player2.game/discord" target="_blank" rel="noopener noreferrer">
|
||||
https://player2.game/discord
|
||||
</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,65 +8,21 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'together-ai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
apiKey,
|
||||
baseUrl,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -85,7 +40,7 @@ function handleResetSettings() {
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="togetherapi-..."
|
||||
placeholder="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
@@ -95,13 +50,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.together.xyz/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
ProviderBasicSettings,
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
|
||||
const providerId = 'vllm'
|
||||
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
apiKey,
|
||||
baseUrl,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
<ProviderBasicSettings
|
||||
:title="t('settings.pages.providers.common.section.basic.title')"
|
||||
:description="t('settings.pages.providers.common.section.basic.description')"
|
||||
:on-reset="handleResetSettings"
|
||||
>
|
||||
<ProviderApiKeyInput
|
||||
v-model="apiKey"
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
placeholder="token-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="http://localhost:8000/v1"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { RemovableRef } from '@vueuse/core'
|
||||
|
||||
import {
|
||||
Alert,
|
||||
ProviderAdvancedSettings,
|
||||
ProviderApiKeyInput,
|
||||
ProviderBaseUrlInput,
|
||||
@@ -9,71 +8,27 @@ import {
|
||||
ProviderSettingsContainer,
|
||||
ProviderSettingsLayout,
|
||||
} from '@proj-airi/stage-ui/components'
|
||||
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useProviderValidation } from '@proj-airi/stage-ui/composables/useProviderValidation'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// Get provider metadata
|
||||
const providerId = 'xai'
|
||||
const providerMetadata = computed(() => providersStore.getProviderMetadata(providerId))
|
||||
|
||||
// Use computed properties for settings
|
||||
const apiKey = computed({
|
||||
get: () => providers.value[providerId]?.apiKey || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].apiKey = value
|
||||
},
|
||||
})
|
||||
|
||||
const baseUrl = computed({
|
||||
get: () => providers.value[providerId]?.baseUrl || '',
|
||||
set: (value) => {
|
||||
if (!providers.value[providerId])
|
||||
providers.value[providerId] = {}
|
||||
|
||||
providers.value[providerId].baseUrl = value
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize provider if it doesn't exist
|
||||
providersStore.initializeProvider(providerId)
|
||||
|
||||
// Initialize refs with current values
|
||||
apiKey.value = providers.value[providerId]?.apiKey || ''
|
||||
baseUrl.value = providers.value[providerId]?.baseUrl || ''
|
||||
})
|
||||
|
||||
// Watch settings and update the provider configuration
|
||||
watch([apiKey, baseUrl], () => {
|
||||
providers.value[providerId] = {
|
||||
...providers.value[providerId],
|
||||
apiKey: apiKey.value,
|
||||
baseUrl: baseUrl.value || '',
|
||||
}
|
||||
})
|
||||
|
||||
function handleResetSettings() {
|
||||
providers.value[providerId] = {
|
||||
...(providerMetadata.value?.defaultOptions as any),
|
||||
}
|
||||
}
|
||||
const {
|
||||
t,
|
||||
router,
|
||||
providerMetadata,
|
||||
apiKey,
|
||||
baseUrl,
|
||||
isValidating,
|
||||
isValid,
|
||||
validationMessage,
|
||||
handleResetSettings,
|
||||
} = useProviderValidation(providerId)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProviderSettingsLayout
|
||||
:provider-name="providerMetadata?.localizedName"
|
||||
:provider-icon="providerMetadata?.icon"
|
||||
:provider-icon-color="providerMetadata?.iconColor"
|
||||
:on-back="() => router.back()"
|
||||
>
|
||||
<ProviderSettingsContainer>
|
||||
@@ -95,13 +50,30 @@ function handleResetSettings() {
|
||||
placeholder="https://api.x.ai/v1/"
|
||||
/>
|
||||
</ProviderAdvancedSettings>
|
||||
|
||||
<!-- Validation Status -->
|
||||
<Alert v-if="!isValid && isValidating === 0 && validationMessage" type="error">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationFailed') }}
|
||||
</template>
|
||||
<template v-if="validationMessage" #content>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{{ validationMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</Alert>
|
||||
<Alert v-if="isValid && isValidating === 0" type="success">
|
||||
<template #title>
|
||||
{{ t('settings.dialogs.onboarding.validationSuccess') }}
|
||||
</template>
|
||||
</Alert>
|
||||
</ProviderSettingsContainer>
|
||||
</ProviderSettingsLayout>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
meta:
|
||||
layout: settings
|
||||
stageTransition:
|
||||
name: slide
|
||||
</route>
|
||||
|
||||
Reference in New Issue
Block a user