feat: support DeepSeek, OpenRouter & Ollama providers
This commit is contained in:
10
README.md
10
README.md
@ -15,7 +15,7 @@ Features:
|
|||||||
|
|
||||||
Currently available providers:
|
Currently available providers:
|
||||||
|
|
||||||
- AI: OpenAI compatible
|
- AI: OpenAI compatible, DeepSeek, OpenRouter, Ollama
|
||||||
- Web Search: Tavily (similar to Firecrawl, but with more free quota (1000 credits / month))
|
- Web Search: Tavily (similar to Firecrawl, but with more free quota (1000 credits / month))
|
||||||
|
|
||||||
Please give a 🌟 Star if you like this project!
|
Please give a 🌟 Star if you like this project!
|
||||||
@ -24,6 +24,13 @@ Please give a 🌟 Star if you like this project!
|
|||||||
|
|
||||||
## Recent updates
|
## Recent updates
|
||||||
|
|
||||||
|
25/02/15
|
||||||
|
|
||||||
|
- Added provider support for DeepSeek, OpenRouter and Ollama
|
||||||
|
- Supported checking project updates
|
||||||
|
- Supported regenerating reports
|
||||||
|
- General fixes
|
||||||
|
|
||||||
25/02/14
|
25/02/14
|
||||||
|
|
||||||
- Supported reasoning models like DeepSeek R1
|
- Supported reasoning models like DeepSeek R1
|
||||||
@ -37,6 +44,7 @@ Please give a 🌟 Star if you like this project!
|
|||||||
- Fixed "export as PDF" issues
|
- Fixed "export as PDF" issues
|
||||||
|
|
||||||
25/02/12
|
25/02/12
|
||||||
|
|
||||||
- Added Chinese translation. The models will respond in the user's language.
|
- Added Chinese translation. The models will respond in the user's language.
|
||||||
- Various fixes
|
- Various fixes
|
||||||
|
|
||||||
|
15
README_zh.md
15
README_zh.md
@ -3,6 +3,7 @@
|
|||||||
本项目是 https://github.com/dzhng/deep-research 的可视化版本,并做了一些改进。
|
本项目是 https://github.com/dzhng/deep-research 的可视化版本,并做了一些改进。
|
||||||
|
|
||||||
特色:
|
特色:
|
||||||
|
|
||||||
- 🚀 **隐私安全**:所有配置和 API 请求均在浏览器端完成
|
- 🚀 **隐私安全**:所有配置和 API 请求均在浏览器端完成
|
||||||
- 🕙 **实时反馈**:流式传输 AI 响应并在界面实时展示
|
- 🕙 **实时反馈**:流式传输 AI 响应并在界面实时展示
|
||||||
- 🌳 **搜索可视化**:使用树状结构展示研究过程,支持使用英文搜索词
|
- 🌳 **搜索可视化**:使用树状结构展示研究过程,支持使用英文搜索词
|
||||||
@ -11,14 +12,19 @@
|
|||||||
|
|
||||||
当前支持的供应商:
|
当前支持的供应商:
|
||||||
|
|
||||||
- AI 服务:任意兼容 OpenAPI 的供应商
|
- AI 服务:OpenAPI 兼容、DeepSeek、OpenRouter、Ollama
|
||||||
- 网络搜索:Tavily(类似 Firecrawl,提供每月 1000 次免费搜索)
|
- 网络搜索:Tavily(类似 Firecrawl,提供每月 1000 次免费搜索)
|
||||||
|
|
||||||
喜欢本项目请点 ⭐ 收藏!
|
喜欢本项目请点 ⭐ 收藏! <video width="500" src="https://github.com/user-attachments/assets/2f5a6f9c-18d1-4d40-9822-2de260d55dab" controls></video>
|
||||||
|
|
||||||
<video width="500" src="https://github.com/user-attachments/assets/2f5a6f9c-18d1-4d40-9822-2de260d55dab" controls></video>
|
## 近期更新
|
||||||
|
|
||||||
## 最近更新
|
25/02/15
|
||||||
|
|
||||||
|
- AI 提供商支持 DeepSeek,OpenRouter 和 Ollama
|
||||||
|
- 支持检查项目更新
|
||||||
|
- 支持重新生成报告
|
||||||
|
- 一般性优化和改进
|
||||||
|
|
||||||
25/02/14
|
25/02/14
|
||||||
|
|
||||||
@ -33,6 +39,7 @@
|
|||||||
- 修复“导出 PDF”不可用的问题
|
- 修复“导出 PDF”不可用的问题
|
||||||
|
|
||||||
25/02/12
|
25/02/12
|
||||||
|
|
||||||
- 添加中文支持。模型会自动使用用户的语言回答了。
|
- 添加中文支持。模型会自动使用用户的语言回答了。
|
||||||
- 修复一些 bug
|
- 修复一些 bug
|
||||||
|
|
||||||
|
@ -24,11 +24,20 @@
|
|||||||
{
|
{
|
||||||
label: t('settings.ai.providers.openaiCompatible.title'),
|
label: t('settings.ai.providers.openaiCompatible.title'),
|
||||||
help: t('settings.ai.providers.openaiCompatible.description'),
|
help: t('settings.ai.providers.openaiCompatible.description'),
|
||||||
apiBasePlaceholder: t(
|
|
||||||
'settings.ai.providers.openaiCompatible.apiBasePlaceholder',
|
|
||||||
),
|
|
||||||
value: 'openai-compatible',
|
value: 'openai-compatible',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'DeepSeek',
|
||||||
|
value: 'deepseek',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'OpenRouter',
|
||||||
|
value: 'openrouter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Ollama',
|
||||||
|
value: 'ollama',
|
||||||
|
},
|
||||||
])
|
])
|
||||||
const selectedAiProvider = computed(() =>
|
const selectedAiProvider = computed(() =>
|
||||||
aiProviderOptions.value.find((o) => o.value === config.value.ai.provider),
|
aiProviderOptions.value.find((o) => o.value === config.value.ai.provider),
|
||||||
@ -110,15 +119,22 @@
|
|||||||
<h3 class="font-bold">{{ $t('settings.ai.provider') }}</h3>
|
<h3 class="font-bold">{{ $t('settings.ai.provider') }}</h3>
|
||||||
<UFormField>
|
<UFormField>
|
||||||
<template v-if="selectedAiProvider" #help>
|
<template v-if="selectedAiProvider" #help>
|
||||||
{{ selectedAiProvider.help }}
|
<span class="whitespace-pre-wrap">
|
||||||
|
{{ selectedAiProvider.help }}
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<USelect v-model="config.ai.provider" :items="aiProviderOptions" />
|
<USelect
|
||||||
|
v-model="config.ai.provider"
|
||||||
|
class="w-50"
|
||||||
|
:items="aiProviderOptions"
|
||||||
|
/>
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<div
|
|
||||||
v-if="config.ai.provider === 'openai-compatible'"
|
<div class="flex flex-col gap-y-2">
|
||||||
class="flex flex-col gap-y-2"
|
<UFormField
|
||||||
>
|
:label="$t('settings.ai.apiKey')"
|
||||||
<UFormField :label="$t('settings.ai.apiKey')" required>
|
:required="config.ai.provider !== 'ollama'"
|
||||||
|
>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
v-model="config.ai.apiKey"
|
v-model="config.ai.apiKey"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
@ -129,7 +145,7 @@
|
|||||||
<UInput
|
<UInput
|
||||||
v-model="config.ai.apiBase"
|
v-model="config.ai.apiBase"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
:placeholder="selectedAiProvider?.apiBasePlaceholder"
|
:placeholder="aiApiBase"
|
||||||
/>
|
/>
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UFormField :label="$t('settings.ai.model')" required>
|
<UFormField :label="$t('settings.ai.model')" required>
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error('Error getting feedback:', e)
|
console.error('Error getting feedback:', e)
|
||||||
if (e.message.includes('Failed to fetch')) {
|
if (e.message?.includes('Failed to fetch')) {
|
||||||
e.message += `\n${t('error.requestBlockedByCORS')}`
|
e.message += `\n${t('error.requestBlockedByCORS')}`
|
||||||
}
|
}
|
||||||
error.value = t('modelFeedback.error', [e.message])
|
error.value = t('modelFeedback.error', [e.message])
|
||||||
|
@ -1,19 +1,45 @@
|
|||||||
import { createDeepSeek } from '@ai-sdk/deepseek'
|
import { createDeepSeek } from '@ai-sdk/deepseek'
|
||||||
import { extractReasoningMiddleware, wrapLanguageModel } from 'ai'
|
import { createOpenRouter } from '@openrouter/ai-sdk-provider'
|
||||||
|
import { createOpenAI } from '@ai-sdk/openai'
|
||||||
|
import {
|
||||||
|
extractReasoningMiddleware,
|
||||||
|
wrapLanguageModel,
|
||||||
|
type LanguageModelV1,
|
||||||
|
} from 'ai'
|
||||||
|
|
||||||
export const useAiModel = () => {
|
export const useAiModel = () => {
|
||||||
const config = useConfigStore()
|
const config = useConfigStore()
|
||||||
|
let model: LanguageModelV1
|
||||||
|
|
||||||
switch (config.config.ai.provider) {
|
switch (config.config.ai.provider) {
|
||||||
case 'openai-compatible':
|
case 'openrouter': {
|
||||||
const deepseek = createDeepSeek({
|
const openRouter = createOpenRouter({
|
||||||
apiKey: config.config.ai.apiKey,
|
apiKey: config.config.ai.apiKey,
|
||||||
baseURL: config.aiApiBase,
|
baseURL: config.aiApiBase,
|
||||||
})
|
})
|
||||||
return wrapLanguageModel({
|
model = openRouter(config.config.ai.model, {
|
||||||
model: deepseek(config.config.ai.model),
|
includeReasoning: true,
|
||||||
middleware: extractReasoningMiddleware({ tagName: 'think' }),
|
|
||||||
})
|
})
|
||||||
default:
|
}
|
||||||
throw new Error(`Unknown AI provider: ${config.config.ai.provider}`)
|
case 'deepseek': {
|
||||||
|
const deepSeek = createDeepSeek({
|
||||||
|
apiKey: config.config.ai.apiKey,
|
||||||
|
baseURL: config.aiApiBase,
|
||||||
|
})
|
||||||
|
model = deepSeek(config.config.ai.model)
|
||||||
|
}
|
||||||
|
case 'openai-compatible':
|
||||||
|
default: {
|
||||||
|
const openai = createOpenAI({
|
||||||
|
apiKey: config.config.ai.apiKey,
|
||||||
|
baseURL: config.aiApiBase,
|
||||||
|
})
|
||||||
|
model = openai(config.config.ai.model)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return wrapLanguageModel({
|
||||||
|
model,
|
||||||
|
middleware: extractReasoningMiddleware({ tagName: 'think' }),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,7 @@
|
|||||||
"providers": {
|
"providers": {
|
||||||
"openaiCompatible": {
|
"openaiCompatible": {
|
||||||
"title": "OpenAI Compatible",
|
"title": "OpenAI Compatible",
|
||||||
"description": "Currently only supports OpenAI compatible providers, e.g. Gemini, Together AI, DeepSeek, SiliconCloud, ...",
|
"description": "e.g. OpenAI, Gemini, Together AI, SiliconCloud, ...\n(Note: DeepSeek, OpenRouter and Ollama now have their own providers.)"
|
||||||
"apiBasePlaceholder": "https://api.openai.com/v1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -21,9 +21,8 @@
|
|||||||
"contextSizeHelp": "上下文的最大大小(以 token 计)。这是将发送给模型的最大 token 数量。默认值为 128,000 个 token。",
|
"contextSizeHelp": "上下文的最大大小(以 token 计)。这是将发送给模型的最大 token 数量。默认值为 128,000 个 token。",
|
||||||
"providers": {
|
"providers": {
|
||||||
"openaiCompatible": {
|
"openaiCompatible": {
|
||||||
"title": "OpenAI Compatiible",
|
"title": "OpenAI Compatible",
|
||||||
"description": "目前仅支持与 OpenAI 兼容的提供商,如 Gemini、Together AI、DeepSeek、SiliconCloud……",
|
"description": "如 OpenAI、Gemini、Together AI、SiliconCloud……\n注:DeepSeek、OpenRouter 和 Ollama 现在已经有了独立选项,请切换使用。"
|
||||||
"apiBasePlaceholder": "https://api.openai.com/v1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -38,7 +38,7 @@ export function generateFeedback({
|
|||||||
prompt,
|
prompt,
|
||||||
onError({ error }) {
|
onError({ error }) {
|
||||||
console.error(`generateFeedback`, error)
|
console.error(`generateFeedback`, error)
|
||||||
throw error
|
throw error instanceof Error ? error : new Error(String(error))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
"@nuxt/ui": "3.0.0-alpha.12",
|
"@nuxt/ui": "3.0.0-alpha.12",
|
||||||
"@nuxtjs/color-mode": "^3.5.2",
|
"@nuxtjs/color-mode": "^3.5.2",
|
||||||
"@nuxtjs/i18n": "9.2.0",
|
"@nuxtjs/i18n": "9.2.0",
|
||||||
|
"@openrouter/ai-sdk-provider": "^0.2.1",
|
||||||
"@pinia/nuxt": "^0.10.1",
|
"@pinia/nuxt": "^0.10.1",
|
||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@tavily/core": "^0.3.1",
|
"@tavily/core": "^0.3.1",
|
||||||
|
41
pnpm-lock.yaml
generated
41
pnpm-lock.yaml
generated
@ -32,6 +32,9 @@ importers:
|
|||||||
'@nuxtjs/i18n':
|
'@nuxtjs/i18n':
|
||||||
specifier: 9.2.0
|
specifier: 9.2.0
|
||||||
version: 9.2.0(@vue/compiler-dom@3.5.13)(eslint@9.20.1(jiti@2.4.2))(magicast@0.3.5)(rollup@4.34.6)(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
|
version: 9.2.0(@vue/compiler-dom@3.5.13)(eslint@9.20.1(jiti@2.4.2))(magicast@0.3.5)(rollup@4.34.6)(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
|
||||||
|
'@openrouter/ai-sdk-provider':
|
||||||
|
specifier: ^0.2.1
|
||||||
|
version: 0.2.1(zod@3.24.2)
|
||||||
'@pinia/nuxt':
|
'@pinia/nuxt':
|
||||||
specifier: ^0.10.1
|
specifier: ^0.10.1
|
||||||
version: 0.10.1(magicast@0.3.5)(pinia@3.0.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))
|
version: 0.10.1(magicast@0.3.5)(pinia@3.0.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))
|
||||||
@ -108,6 +111,15 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
zod: ^3.0.0
|
zod: ^3.0.0
|
||||||
|
|
||||||
|
'@ai-sdk/provider-utils@2.1.5':
|
||||||
|
resolution: {integrity: sha512-PcNR7E4ovZGV/J47gUqaFlvzorgca6uUfN5WzfXJSFWeOeLunN+oxRVwgUOwj0zbmO0yGQTHQD+FHVw8s3Rz8w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
peerDependencies:
|
||||||
|
zod: ^3.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
zod:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@ai-sdk/provider-utils@2.1.8':
|
'@ai-sdk/provider-utils@2.1.8':
|
||||||
resolution: {integrity: sha512-1j9niMUAFlCBdYRYJr1yoB5kwZcRFBVuBiL1hhrf0ONFNrDiJYA6F+gROOuP16NHhezMfTo60+GeeV1xprHFjg==}
|
resolution: {integrity: sha512-1j9niMUAFlCBdYRYJr1yoB5kwZcRFBVuBiL1hhrf0ONFNrDiJYA6F+gROOuP16NHhezMfTo60+GeeV1xprHFjg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -117,6 +129,10 @@ packages:
|
|||||||
zod:
|
zod:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@ai-sdk/provider@1.0.6':
|
||||||
|
resolution: {integrity: sha512-hwj/gFNxpDgEfTaYzCYoslmw01IY9kWLKl/wf8xuPvHtQIzlfXWmmUwc8PnCwxyt8cKzIuV0dfUghCf68HQ0SA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@ai-sdk/provider@1.0.7':
|
'@ai-sdk/provider@1.0.7':
|
||||||
resolution: {integrity: sha512-q1PJEZ0qD9rVR+8JFEd01/QM++csMT5UVwYXSN2u54BrVw/D8TZLTeg2FEfKK00DgAx0UtWd8XOhhwITP9BT5g==}
|
resolution: {integrity: sha512-q1PJEZ0qD9rVR+8JFEd01/QM++csMT5UVwYXSN2u54BrVw/D8TZLTeg2FEfKK00DgAx0UtWd8XOhhwITP9BT5g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -777,6 +793,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-R7azgNji8jIZdimlylK1CU4plO1OjRPZduTyjS9SHHasMCzxrPM+LBJLRzjt9NUNatquLeCcVfHAYvxIxPHCmg==}
|
resolution: {integrity: sha512-R7azgNji8jIZdimlylK1CU4plO1OjRPZduTyjS9SHHasMCzxrPM+LBJLRzjt9NUNatquLeCcVfHAYvxIxPHCmg==}
|
||||||
engines: {node: ^14.16.0 || >=16.11.0}
|
engines: {node: ^14.16.0 || >=16.11.0}
|
||||||
|
|
||||||
|
'@openrouter/ai-sdk-provider@0.2.1':
|
||||||
|
resolution: {integrity: sha512-Iz+wpGR6001OfbYPp+VmXFZBNpF6a3uN5gzgEBkNCqwZUzuYANO03d4eSgqFrDvfsenG7eE9hpKHB4zIg8YmKA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
peerDependencies:
|
||||||
|
zod: ^3.0.0
|
||||||
|
|
||||||
'@opentelemetry/api@1.9.0':
|
'@opentelemetry/api@1.9.0':
|
||||||
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
|
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
|
||||||
engines: {node: '>=8.0.0'}
|
engines: {node: '>=8.0.0'}
|
||||||
@ -4293,6 +4315,15 @@ snapshots:
|
|||||||
'@ai-sdk/provider-utils': 2.1.8(zod@3.24.2)
|
'@ai-sdk/provider-utils': 2.1.8(zod@3.24.2)
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
||||||
|
'@ai-sdk/provider-utils@2.1.5(zod@3.24.2)':
|
||||||
|
dependencies:
|
||||||
|
'@ai-sdk/provider': 1.0.6
|
||||||
|
eventsource-parser: 3.0.0
|
||||||
|
nanoid: 3.3.8
|
||||||
|
secure-json-parse: 2.7.0
|
||||||
|
optionalDependencies:
|
||||||
|
zod: 3.24.2
|
||||||
|
|
||||||
'@ai-sdk/provider-utils@2.1.8(zod@3.24.2)':
|
'@ai-sdk/provider-utils@2.1.8(zod@3.24.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.0.7
|
'@ai-sdk/provider': 1.0.7
|
||||||
@ -4302,6 +4333,10 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
||||||
|
'@ai-sdk/provider@1.0.6':
|
||||||
|
dependencies:
|
||||||
|
json-schema: 0.4.0
|
||||||
|
|
||||||
'@ai-sdk/provider@1.0.7':
|
'@ai-sdk/provider@1.0.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
json-schema: 0.4.0
|
json-schema: 0.4.0
|
||||||
@ -5329,6 +5364,12 @@ snapshots:
|
|||||||
- typescript
|
- typescript
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
|
'@openrouter/ai-sdk-provider@0.2.1(zod@3.24.2)':
|
||||||
|
dependencies:
|
||||||
|
'@ai-sdk/provider': 1.0.6
|
||||||
|
'@ai-sdk/provider-utils': 2.1.5(zod@3.24.2)
|
||||||
|
zod: 3.24.2
|
||||||
|
|
||||||
'@opentelemetry/api@1.9.0': {}
|
'@opentelemetry/api@1.9.0': {}
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.5.1':
|
'@parcel/watcher-android-arm64@2.5.1':
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0.4"
|
"version": "1.0.5"
|
||||||
}
|
}
|
@ -1,7 +1,12 @@
|
|||||||
import { skipHydrate } from 'pinia'
|
import { skipHydrate } from 'pinia'
|
||||||
import type { Locale } from '~/components/LangSwitcher.vue'
|
import type { Locale } from '~/components/LangSwitcher.vue'
|
||||||
|
|
||||||
export type ConfigAiProvider = 'openai-compatible'
|
export type ConfigAiProvider =
|
||||||
|
| 'openai-compatible'
|
||||||
|
| 'openrouter'
|
||||||
|
| 'deepseek'
|
||||||
|
| 'ollama'
|
||||||
|
|
||||||
export interface ConfigAi {
|
export interface ConfigAi {
|
||||||
provider: ConfigAiProvider
|
provider: ConfigAiProvider
|
||||||
apiKey?: string
|
apiKey?: string
|
||||||
@ -39,6 +44,15 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const aiApiBase = computed(() => {
|
const aiApiBase = computed(() => {
|
||||||
|
if (config.value.ai.provider === 'openrouter') {
|
||||||
|
return config.value.ai.apiBase || 'https://openrouter.ai/api/v1'
|
||||||
|
}
|
||||||
|
if (config.value.ai.provider === 'deepseek') {
|
||||||
|
return config.value.ai.apiBase || 'https://api.deepseek.com/v1'
|
||||||
|
}
|
||||||
|
if (config.value.ai.provider === 'ollama') {
|
||||||
|
return config.value.ai.apiBase || 'http://localhost:11434/v1'
|
||||||
|
}
|
||||||
return config.value.ai.apiBase || 'https://api.openai.com/v1'
|
return config.value.ai.apiBase || 'https://api.openai.com/v1'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user