feat(aiops): 模型配置参考 aiops/opsxshell — 快捷预设 + 供应商下拉
- 快捷预设:deepseek-flash(推荐)/ deepseek-v4-pro / 自定义 一键填入端点与模型 - 供应商目录(9 家 + 自定义):DeepSeek/通义/智谱/Kimi/MiniMax/硅基流动/混元/OpenAI/本地 Ollama·vLLM,选择后自动填 Base URL 与首个推荐模型 - 模型输入支持 datalist 下拉(随供应商联动)且可手输任意模型名;Base URL 保持可编辑
This commit is contained in:
1 parent
63445bd598
commit
1610988c2e
4 files changed
+157
-9
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { LLM_PROVIDERS, matchProvider } from './llmProviders'
|
||||
import { Loader2, Play, Save, Sparkles, PlugZap, History, ShieldCheck } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import { PageContainer } from '@/components/PageContainer'
|
||||
@@ -8,6 +9,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
@@ -479,8 +481,70 @@ export default function AiopsPage() {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-end gap-2">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">{t('config.quickPresets')}</Label>
|
||||
<div className="flex gap-2">
|
||||
{LLM_PROVIDERS.filter(p => p.id === 'deepseek')[0].models.slice(0, 2).reverse().concat([]).map(m => (
|
||||
<Button
|
||||
key={m}
|
||||
type="button"
|
||||
size="sm"
|
||||
variant={config.model === m ? 'default' : 'outline'}
|
||||
onClick={() => setConfig({ ...config, baseUrl: LLM_PROVIDERS.find(p => p.id === 'deepseek')!.endpoint, model: m })}
|
||||
>
|
||||
{m}
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant={matchProvider(config.baseUrl) === 'custom' ? 'default' : 'outline'}
|
||||
onClick={() => setConfig({ ...config, baseUrl: '', model: '' })}
|
||||
>
|
||||
{t('config.presetCustom')}
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground">{t('config.presetHint')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">{t('config.provider')}</Label>
|
||||
<Select
|
||||
value={matchProvider(config.baseUrl)}
|
||||
onValueChange={value => {
|
||||
const p = LLM_PROVIDERS.find(x => x.id === value)
|
||||
if (!p) return
|
||||
setConfig({ ...config, baseUrl: p.endpoint, model: p.models[0] && value !== 'custom' ? p.models[0] : config.model })
|
||||
}}
|
||||
>
|
||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
{LLM_PROVIDERS.map(p => (
|
||||
<SelectItem key={p.id} value={p.id}>{p.name}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-[11px] text-muted-foreground">{t('config.providerSelectHint')}</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">{t('config.model')}</Label>
|
||||
<Input
|
||||
value={config.model}
|
||||
placeholder="deepseek-flash"
|
||||
list="llm-model-options"
|
||||
onChange={e => setConfig({ ...config, model: e.target.value })}
|
||||
/>
|
||||
<datalist id="llm-model-options">
|
||||
{(LLM_PROVIDERS.find(p => p.id === matchProvider(config.baseUrl))?.models ?? []).map(m => (
|
||||
<option key={m} value={m} />
|
||||
))}
|
||||
</datalist>
|
||||
<p className="text-[11px] text-muted-foreground">{t('config.modelHint')}</p>
|
||||
</div>
|
||||
<div className="space-y-1 sm:col-span-2">
|
||||
<Label className="text-xs">{t('config.baseUrl')}</Label>
|
||||
<Input
|
||||
value={config.baseUrl}
|
||||
@@ -489,15 +553,6 @@ export default function AiopsPage() {
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">{t('config.baseUrlHint')}</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">{t('config.model')}</Label>
|
||||
<Input
|
||||
value={config.model}
|
||||
placeholder="deepseek-chat"
|
||||
onChange={e => setConfig({ ...config, model: e.target.value })}
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">{t('config.modelHint')}</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">{t('config.apiKey')}</Label>
|
||||
<Input
|
||||
|
||||
Reference in new issue
Block a user