feat(stage-ui/providers): added 302.AI
This commit is contained in:
@@ -183,6 +183,7 @@ npx bumpp --no-commit --no-tag
|
||||
|
||||
## Support of LLM API Providers (powered by [xsai](https://github.com/moeru-ai/xsai))
|
||||
|
||||
- [x] [302.AI (sponsored)](https://share.302.ai/514k2v)
|
||||
- [x] [OpenRouter](https://openrouter.ai/)
|
||||
- [x] [vLLM](https://github.com/vllm-project/vllm)
|
||||
- [x] [SGLang](https://github.com/sgl-project/sglang)
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
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 { storeToRefs } from 'pinia'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const providerId = '302-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// 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
|
||||
},
|
||||
})
|
||||
|
||||
// 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-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="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.302.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>
|
||||
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
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 { storeToRefs } from 'pinia'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const providerId = '302-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// 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
|
||||
},
|
||||
})
|
||||
|
||||
// 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-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="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.302.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>
|
||||
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
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 { storeToRefs } from 'pinia'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const providerId = '302-ai'
|
||||
const providersStore = useProvidersStore()
|
||||
const { providers } = storeToRefs(providersStore) as { providers: RemovableRef<Record<string, any>> }
|
||||
|
||||
// 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
|
||||
},
|
||||
})
|
||||
|
||||
// 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-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="sk-..."
|
||||
/>
|
||||
</ProviderBasicSettings>
|
||||
|
||||
<ProviderAdvancedSettings :title="t('settings.pages.providers.common.section.advanced.title')">
|
||||
<ProviderBaseUrlInput
|
||||
v-model="baseUrl"
|
||||
placeholder="https://api.302.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>
|
||||
@@ -181,6 +181,7 @@ npx bumpp --no-commit --no-tag
|
||||
|
||||
## Support des fournisseurs d'API LLM suivants (propulsé par [xsai](https://github.com/moeru-ai/xsai))
|
||||
|
||||
- [x] [302.AI](https://share.302.ai/514k2v)
|
||||
- [x] [OpenRouter](https://openrouter.ai/)
|
||||
- [x] [vLLM](https://github.com/vllm-project/vllm)
|
||||
- [x] [SGLang](https://github.com/sgl-project/sglang)
|
||||
|
||||
@@ -158,6 +158,7 @@ pnpm dev:docs
|
||||
|
||||
## サポートされているLLM APIプロバイダー([xsai](https://github.com/moeru-ai/xsai)によって提供)
|
||||
|
||||
- [x] [302.AI](https://share.302.ai/514k2v)
|
||||
- [x] [OpenRouter](https://openrouter.ai/)
|
||||
- [x] [vLLM](https://github.com/vllm-project/vllm)
|
||||
- [x] [SGLang](https://github.com/sgl-project/sglang)
|
||||
|
||||
@@ -182,6 +182,7 @@ npx bumpp --no-commit --no-tag
|
||||
|
||||
## Поддержка провайдеров LLM API (на базе [xsai](https://github.com/moeru-ai/xsai))
|
||||
|
||||
- [x] [302.AI](https://share.302.ai/514k2v)
|
||||
- [x] [OpenRouter](https://openrouter.ai/)
|
||||
- [x] [vLLM](https://github.com/vllm-project/vllm)
|
||||
- [x] [SGLang](https://github.com/sgl-project/sglang)
|
||||
|
||||
@@ -180,6 +180,7 @@ npx bumpp --no-commit --no-tag
|
||||
|
||||
## Các LLM API hỗ trợ (cung cấp bởi [xsai](https://github.com/moeru-ai/xsai))
|
||||
|
||||
- [x] [302.AI](https://share.302.ai/514k2v)
|
||||
- [x] [OpenRouter](https://openrouter.ai/)
|
||||
- [x] [vLLM](https://github.com/vllm-project/vllm)
|
||||
- [x] [SGLang](https://github.com/sgl-project/sglang)
|
||||
|
||||
@@ -150,6 +150,7 @@ pnpm -F @proj-airi/docs dev
|
||||
|
||||
## 原生支持的 LLM API 服务来源列表(由 [xsai](https://github.com/moeru-ai/xsai) 驱动)
|
||||
|
||||
- [x] [302.AI](https://share.302.ai/514k2v)
|
||||
- [x] [OpenRouter](https://openrouter.ai/)
|
||||
- [x] [vLLM](https://github.com/vllm-project/vllm)
|
||||
- [x] [SGLang](https://github.com/sgl-project/sglang)
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
import { createOllama, createPlayer2 } from '@xsai-ext/providers-local'
|
||||
import {
|
||||
createChatProvider,
|
||||
createEmbedProvider,
|
||||
createMetadataProvider,
|
||||
createModelProvider,
|
||||
merge,
|
||||
@@ -555,102 +556,6 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
'vllm': {
|
||||
id: 'vllm',
|
||||
category: 'chat',
|
||||
tasks: ['text-generation'],
|
||||
nameKey: 'settings.pages.providers.provider.vllm.title',
|
||||
name: 'vLLM',
|
||||
descriptionKey: 'settings.pages.providers.provider.vllm.description',
|
||||
description: 'vllm.ai',
|
||||
iconColor: 'i-lobe-icons:vllm',
|
||||
createProvider: async config => createOllama((config.baseUrl as string).trim()),
|
||||
capabilities: {
|
||||
listModels: async () => {
|
||||
return [
|
||||
{
|
||||
id: 'llama-2-7b',
|
||||
name: 'Llama 2 (7B)',
|
||||
provider: 'vllm',
|
||||
description: 'Meta\'s Llama 2 7B parameter model',
|
||||
contextLength: 4096,
|
||||
},
|
||||
{
|
||||
id: 'llama-2-13b',
|
||||
name: 'Llama 2 (13B)',
|
||||
provider: 'vllm',
|
||||
description: 'Meta\'s Llama 2 13B parameter model',
|
||||
contextLength: 4096,
|
||||
},
|
||||
{
|
||||
id: 'llama-2-70b',
|
||||
name: 'Llama 2 (70B)',
|
||||
provider: 'vllm',
|
||||
description: 'Meta\'s Llama 2 70B parameter model',
|
||||
contextLength: 4096,
|
||||
},
|
||||
{
|
||||
id: 'mistral-7b',
|
||||
name: 'Mistral (7B)',
|
||||
provider: 'vllm',
|
||||
description: 'Mistral AI\'s 7B parameter model',
|
||||
contextLength: 8192,
|
||||
},
|
||||
{
|
||||
id: 'mixtral-8x7b',
|
||||
name: 'Mixtral (8x7B)',
|
||||
provider: 'vllm',
|
||||
description: 'Mistral AI\'s Mixtral 8x7B MoE model',
|
||||
contextLength: 32768,
|
||||
},
|
||||
{
|
||||
id: 'custom',
|
||||
name: 'Custom Model',
|
||||
provider: 'vllm',
|
||||
description: 'Specify a custom model name',
|
||||
contextLength: 0,
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
validators: {
|
||||
validateProviderConfig: (config) => {
|
||||
if (!config.baseUrl) {
|
||||
return {
|
||||
errors: [new Error('Base URL is required.')],
|
||||
reason: 'Base URL is required. Default to http://localhost:8000/v1/ for vLLM.',
|
||||
valid: false,
|
||||
}
|
||||
}
|
||||
|
||||
const res = baseUrlValidator.value(config.baseUrl)
|
||||
if (res) {
|
||||
return res
|
||||
}
|
||||
|
||||
// Check if the vLLM is reachable
|
||||
return fetch(`${(config.baseUrl as string).trim()}models`, { headers: (config.headers as HeadersInit) || undefined })
|
||||
.then((response) => {
|
||||
const errors = [
|
||||
!response.ok && new Error(`vLLM returned non-ok status code: ${response.statusText}`),
|
||||
].filter(Boolean)
|
||||
|
||||
return {
|
||||
errors,
|
||||
reason: errors.filter(e => e).map(e => String(e)).join(', ') || '',
|
||||
valid: response.ok,
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
return {
|
||||
errors: [err],
|
||||
reason: `Failed to reach vLLM, error: ${String(err)} occurred.`,
|
||||
valid: false,
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
'lm-studio': {
|
||||
id: 'lm-studio',
|
||||
category: 'chat',
|
||||
@@ -942,55 +847,6 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
tasks: ['speech-to-text', 'automatic-speech-recognition', 'asr', 'stt'],
|
||||
creator: createOpenAI,
|
||||
}),
|
||||
'azure-ai-foundry': {
|
||||
id: 'azure-ai-foundry',
|
||||
category: 'chat',
|
||||
tasks: ['text-generation'],
|
||||
nameKey: 'settings.pages.providers.provider.azure-ai-foundry.title',
|
||||
name: 'Azure AI Foundry',
|
||||
descriptionKey: 'settings.pages.providers.provider.azure-ai-foundry.description',
|
||||
description: 'azure.com',
|
||||
icon: 'i-lobe-icons:microsoft',
|
||||
defaultOptions: () => ({}),
|
||||
createProvider: async (config) => {
|
||||
return await createAzure({
|
||||
apiKey: async () => (config.apiKey as string).trim(),
|
||||
resourceName: config.resourceName as string,
|
||||
apiVersion: config.apiVersion as string,
|
||||
})
|
||||
},
|
||||
capabilities: {
|
||||
listModels: async (config) => {
|
||||
return [{ id: config.modelId }].map((model) => {
|
||||
return {
|
||||
id: model.id as string,
|
||||
name: model.id as string,
|
||||
provider: 'azure-ai-foundry',
|
||||
description: '',
|
||||
contextLength: 0,
|
||||
deprecated: false,
|
||||
} satisfies ModelInfo
|
||||
})
|
||||
},
|
||||
},
|
||||
validators: {
|
||||
validateProviderConfig: (config) => {
|
||||
// return !!config.apiKey && !!config.resourceName && !!config.modelId
|
||||
|
||||
const errors = [
|
||||
!config.apiKey && new Error('API key is required'),
|
||||
!config.resourceName && new Error('Resource name is required'),
|
||||
!config.modelId && new Error('Model ID is required'),
|
||||
]
|
||||
|
||||
return {
|
||||
errors,
|
||||
reason: errors.filter(e => e).map(e => String(e)).join(', ') || '',
|
||||
valid: !!config.apiKey && !!config.resourceName && !!config.modelId,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
'anthropic': buildOpenAICompatibleProvider({
|
||||
id: 'anthropic',
|
||||
name: 'Anthropic',
|
||||
@@ -1016,17 +872,6 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
creator: createGoogleGenerativeAI,
|
||||
validation: ['health', 'model_list'],
|
||||
}),
|
||||
'xai': buildOpenAICompatibleProvider({
|
||||
id: 'xai',
|
||||
name: 'xAI',
|
||||
nameKey: 'settings.pages.providers.provider.xai.title',
|
||||
descriptionKey: 'settings.pages.providers.provider.xai.description',
|
||||
icon: 'i-lobe-icons:xai',
|
||||
description: 'x.ai',
|
||||
defaultBaseUrl: 'https://api.x.ai/v1/',
|
||||
creator: createXAI,
|
||||
validation: ['health', 'model_list'],
|
||||
}),
|
||||
'deepseek': buildOpenAICompatibleProvider({
|
||||
id: 'deepseek',
|
||||
name: 'DeepSeek',
|
||||
@@ -1038,6 +883,21 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
creator: createDeepSeek,
|
||||
validation: ['health', 'model_list'],
|
||||
}),
|
||||
'302-ai': buildOpenAICompatibleProvider({
|
||||
id: '302-ai',
|
||||
name: '302.AI',
|
||||
nameKey: 'settings.pages.providers.provider.302-ai.title',
|
||||
descriptionKey: 'settings.pages.providers.provider.302-ai.description',
|
||||
icon: 'i-lobe-icons:ai302',
|
||||
description: '302.ai',
|
||||
defaultBaseUrl: 'https://api.302.ai/v1/',
|
||||
creator: (apiKey, baseURL = 'https://api.302.ai/v1/') => merge(
|
||||
createChatProvider({ apiKey, baseURL }),
|
||||
createEmbedProvider({ apiKey, baseURL }),
|
||||
createModelProvider({ apiKey, baseURL }),
|
||||
),
|
||||
validation: ['model_list'],
|
||||
}),
|
||||
'elevenlabs': {
|
||||
id: 'elevenlabs',
|
||||
category: 'speech',
|
||||
@@ -1402,6 +1262,162 @@ export const useProvidersStore = defineStore('providers', () => {
|
||||
validation: ['health', 'model_list'],
|
||||
iconColor: 'i-lobe-icons:together',
|
||||
}),
|
||||
'azure-ai-foundry': {
|
||||
id: 'azure-ai-foundry',
|
||||
category: 'chat',
|
||||
tasks: ['text-generation'],
|
||||
nameKey: 'settings.pages.providers.provider.azure-ai-foundry.title',
|
||||
name: 'Azure AI Foundry',
|
||||
descriptionKey: 'settings.pages.providers.provider.azure-ai-foundry.description',
|
||||
description: 'azure.com',
|
||||
icon: 'i-lobe-icons:microsoft',
|
||||
defaultOptions: () => ({}),
|
||||
createProvider: async (config) => {
|
||||
return await createAzure({
|
||||
apiKey: async () => (config.apiKey as string).trim(),
|
||||
resourceName: config.resourceName as string,
|
||||
apiVersion: config.apiVersion as string,
|
||||
})
|
||||
},
|
||||
capabilities: {
|
||||
listModels: async (config) => {
|
||||
return [{ id: config.modelId }].map((model) => {
|
||||
return {
|
||||
id: model.id as string,
|
||||
name: model.id as string,
|
||||
provider: 'azure-ai-foundry',
|
||||
description: '',
|
||||
contextLength: 0,
|
||||
deprecated: false,
|
||||
} satisfies ModelInfo
|
||||
})
|
||||
},
|
||||
},
|
||||
validators: {
|
||||
validateProviderConfig: (config) => {
|
||||
// return !!config.apiKey && !!config.resourceName && !!config.modelId
|
||||
|
||||
const errors = [
|
||||
!config.apiKey && new Error('API key is required'),
|
||||
!config.resourceName && new Error('Resource name is required'),
|
||||
!config.modelId && new Error('Model ID is required'),
|
||||
]
|
||||
|
||||
return {
|
||||
errors,
|
||||
reason: errors.filter(e => e).map(e => String(e)).join(', ') || '',
|
||||
valid: !!config.apiKey && !!config.resourceName && !!config.modelId,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
'xai': buildOpenAICompatibleProvider({
|
||||
id: 'xai',
|
||||
name: 'xAI',
|
||||
nameKey: 'settings.pages.providers.provider.xai.title',
|
||||
descriptionKey: 'settings.pages.providers.provider.xai.description',
|
||||
icon: 'i-lobe-icons:xai',
|
||||
description: 'x.ai',
|
||||
defaultBaseUrl: 'https://api.x.ai/v1/',
|
||||
creator: createXAI,
|
||||
validation: ['health', 'model_list'],
|
||||
}),
|
||||
'vllm': {
|
||||
id: 'vllm',
|
||||
category: 'chat',
|
||||
tasks: ['text-generation'],
|
||||
nameKey: 'settings.pages.providers.provider.vllm.title',
|
||||
name: 'vLLM',
|
||||
descriptionKey: 'settings.pages.providers.provider.vllm.description',
|
||||
description: 'vllm.ai',
|
||||
iconColor: 'i-lobe-icons:vllm',
|
||||
createProvider: async config => createOllama((config.baseUrl as string).trim()),
|
||||
capabilities: {
|
||||
listModels: async () => {
|
||||
return [
|
||||
{
|
||||
id: 'llama-2-7b',
|
||||
name: 'Llama 2 (7B)',
|
||||
provider: 'vllm',
|
||||
description: 'Meta\'s Llama 2 7B parameter model',
|
||||
contextLength: 4096,
|
||||
},
|
||||
{
|
||||
id: 'llama-2-13b',
|
||||
name: 'Llama 2 (13B)',
|
||||
provider: 'vllm',
|
||||
description: 'Meta\'s Llama 2 13B parameter model',
|
||||
contextLength: 4096,
|
||||
},
|
||||
{
|
||||
id: 'llama-2-70b',
|
||||
name: 'Llama 2 (70B)',
|
||||
provider: 'vllm',
|
||||
description: 'Meta\'s Llama 2 70B parameter model',
|
||||
contextLength: 4096,
|
||||
},
|
||||
{
|
||||
id: 'mistral-7b',
|
||||
name: 'Mistral (7B)',
|
||||
provider: 'vllm',
|
||||
description: 'Mistral AI\'s 7B parameter model',
|
||||
contextLength: 8192,
|
||||
},
|
||||
{
|
||||
id: 'mixtral-8x7b',
|
||||
name: 'Mixtral (8x7B)',
|
||||
provider: 'vllm',
|
||||
description: 'Mistral AI\'s Mixtral 8x7B MoE model',
|
||||
contextLength: 32768,
|
||||
},
|
||||
{
|
||||
id: 'custom',
|
||||
name: 'Custom Model',
|
||||
provider: 'vllm',
|
||||
description: 'Specify a custom model name',
|
||||
contextLength: 0,
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
validators: {
|
||||
validateProviderConfig: (config) => {
|
||||
if (!config.baseUrl) {
|
||||
return {
|
||||
errors: [new Error('Base URL is required.')],
|
||||
reason: 'Base URL is required. Default to http://localhost:8000/v1/ for vLLM.',
|
||||
valid: false,
|
||||
}
|
||||
}
|
||||
|
||||
const res = baseUrlValidator.value(config.baseUrl)
|
||||
if (res) {
|
||||
return res
|
||||
}
|
||||
|
||||
// Check if the vLLM is reachable
|
||||
return fetch(`${(config.baseUrl as string).trim()}models`, { headers: (config.headers as HeadersInit) || undefined })
|
||||
.then((response) => {
|
||||
const errors = [
|
||||
!response.ok && new Error(`vLLM returned non-ok status code: ${response.statusText}`),
|
||||
].filter(Boolean)
|
||||
|
||||
return {
|
||||
errors,
|
||||
reason: errors.filter(e => e).map(e => String(e)).join(', ') || '',
|
||||
valid: response.ok,
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
return {
|
||||
errors: [err],
|
||||
reason: `Failed to reach vLLM, error: ${String(err)} occurred.`,
|
||||
valid: false,
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
'novita-ai': buildOpenAICompatibleProvider({
|
||||
id: 'novita-ai',
|
||||
name: 'Novita',
|
||||
|
||||
@@ -28,25 +28,27 @@ export function buildOpenAICompatibleProvider(
|
||||
|
||||
const finalCapabilities = capabilities || {
|
||||
listModels: async (config: Record<string, unknown>) => {
|
||||
const provider = creator(
|
||||
const provider = await creator(
|
||||
(config.apiKey as string || '').trim(),
|
||||
(config.baseUrl as string || '').trim(),
|
||||
)
|
||||
if (provider.model) {
|
||||
return (await listModels({
|
||||
...provider.model(),
|
||||
})).map((model: any) => {
|
||||
return {
|
||||
id: model.id,
|
||||
name: model.name || model.display_name || model.id,
|
||||
provider: id,
|
||||
description: model.description || '',
|
||||
contextLength: model.context_length || 0,
|
||||
deprecated: false,
|
||||
} satisfies ModelInfo
|
||||
})
|
||||
|
||||
if (!provider.model) {
|
||||
return []
|
||||
}
|
||||
return []
|
||||
|
||||
return (await listModels({
|
||||
...provider.model(),
|
||||
})).map((model: any) => {
|
||||
return {
|
||||
id: model.id,
|
||||
name: model.name || model.display_name || model.id,
|
||||
provider: id,
|
||||
description: model.description || '',
|
||||
contextLength: model.context_length || 0,
|
||||
deprecated: false,
|
||||
} satisfies ModelInfo
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user