mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-12 04:07:42 +08:00
chore: update project files
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { useI18n } from '../../i18n'
|
||||
@@ -6,8 +7,75 @@ import { useChatStreamClient } from './useChatStreamClient'
|
||||
import ConfigPanel from './ConfigPanel'
|
||||
import ChatPanel from './ChatPanel'
|
||||
|
||||
function describeModel(t, modelID) {
|
||||
const noThinking = modelID.endsWith('-nothinking')
|
||||
|
||||
let description = t('apiTester.models.generic')
|
||||
if (modelID.includes('vision-search')) {
|
||||
description = t('apiTester.models.visionSearch')
|
||||
} else if (modelID.includes('vision')) {
|
||||
description = t('apiTester.models.vision')
|
||||
} else if (modelID.includes('pro-search')) {
|
||||
description = t('apiTester.models.proSearch')
|
||||
} else if (modelID.includes('pro')) {
|
||||
description = t('apiTester.models.pro')
|
||||
} else if (modelID.includes('flash-search')) {
|
||||
description = t('apiTester.models.flashSearch')
|
||||
} else if (modelID.includes('flash')) {
|
||||
description = t('apiTester.models.flash')
|
||||
}
|
||||
|
||||
if (noThinking) {
|
||||
return `${description} · ${t('apiTester.models.noThinking')}`
|
||||
}
|
||||
return description
|
||||
}
|
||||
|
||||
function decorateModel(t, modelID) {
|
||||
const isVision = modelID.includes('vision')
|
||||
const isSearch = modelID.includes('search')
|
||||
const isPro = modelID.includes('pro')
|
||||
|
||||
if (isVision && isSearch) {
|
||||
return {
|
||||
id: modelID,
|
||||
name: modelID,
|
||||
icon: 'ImageIcon',
|
||||
desc: describeModel(t, modelID),
|
||||
color: 'text-fuchsia-600',
|
||||
}
|
||||
}
|
||||
if (isVision) {
|
||||
return {
|
||||
id: modelID,
|
||||
name: modelID,
|
||||
icon: 'ImageIcon',
|
||||
desc: describeModel(t, modelID),
|
||||
color: 'text-violet-500',
|
||||
}
|
||||
}
|
||||
if (isSearch) {
|
||||
return {
|
||||
id: modelID,
|
||||
name: modelID,
|
||||
icon: 'SearchIcon',
|
||||
desc: describeModel(t, modelID),
|
||||
color: isPro ? 'text-cyan-600' : 'text-cyan-500',
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: modelID,
|
||||
name: modelID,
|
||||
icon: isPro ? 'Cpu' : 'MessageSquare',
|
||||
desc: describeModel(t, modelID),
|
||||
color: isPro ? 'text-amber-600' : 'text-amber-500',
|
||||
}
|
||||
}
|
||||
|
||||
export default function ApiTesterContainer({ config, onMessage, authFetch }) {
|
||||
const { t } = useI18n()
|
||||
const [availableModelIDs, setAvailableModelIDs] = useState([])
|
||||
const [modelsLoaded, setModelsLoaded] = useState(false)
|
||||
|
||||
const {
|
||||
model,
|
||||
@@ -49,14 +117,58 @@ export default function ApiTesterContainer({ config, onMessage, authFetch }) {
|
||||
const customKeyActive = trimmedApiKey !== ''
|
||||
const customKeyManaged = customKeyActive && configuredKeys.includes(trimmedApiKey)
|
||||
|
||||
const models = [
|
||||
{ id: 'deepseek-v4-flash', name: 'deepseek-v4-flash', icon: 'MessageSquare', desc: t('apiTester.models.flash'), color: 'text-amber-500' },
|
||||
{ id: 'deepseek-v4-pro', name: 'deepseek-v4-pro', icon: 'Cpu', desc: t('apiTester.models.pro'), color: 'text-amber-600' },
|
||||
{ id: 'deepseek-v4-flash-search', name: 'deepseek-v4-flash-search', icon: 'SearchIcon', desc: t('apiTester.models.flashSearch'), color: 'text-cyan-500' },
|
||||
{ id: 'deepseek-v4-pro-search', name: 'deepseek-v4-pro-search', icon: 'SearchIcon', desc: t('apiTester.models.proSearch'), color: 'text-cyan-600' },
|
||||
{ id: 'deepseek-v4-vision', name: 'deepseek-v4-vision', icon: 'ImageIcon', desc: t('apiTester.models.vision'), color: 'text-violet-500' },
|
||||
{ id: 'deepseek-v4-vision-search', name: 'deepseek-v4-vision-search', icon: 'SearchIcon', desc: t('apiTester.models.visionSearch'), color: 'text-fuchsia-600' },
|
||||
]
|
||||
useEffect(() => {
|
||||
let disposed = false
|
||||
|
||||
async function loadModels() {
|
||||
try {
|
||||
const res = await authFetch('/v1/models')
|
||||
if (!res.ok) {
|
||||
throw new Error(`failed to fetch models: ${res.status}`)
|
||||
}
|
||||
const data = await res.json()
|
||||
const modelIDs = Array.isArray(data?.data)
|
||||
? data.data
|
||||
.map((item) => String(item?.id || '').trim())
|
||||
.filter(Boolean)
|
||||
: []
|
||||
if (!disposed) {
|
||||
setAvailableModelIDs(modelIDs)
|
||||
}
|
||||
} catch (_err) {
|
||||
if (!disposed) {
|
||||
setAvailableModelIDs([])
|
||||
}
|
||||
} finally {
|
||||
if (!disposed) {
|
||||
setModelsLoaded(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setModelsLoaded(false)
|
||||
loadModels()
|
||||
return () => {
|
||||
disposed = true
|
||||
}
|
||||
}, [authFetch])
|
||||
|
||||
const models = useMemo(
|
||||
() => availableModelIDs.map((modelID) => decorateModel(t, modelID)),
|
||||
[availableModelIDs, t]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!models.length) {
|
||||
if (model) {
|
||||
setModel('')
|
||||
}
|
||||
return
|
||||
}
|
||||
if (!model || !models.some((item) => item.id === model)) {
|
||||
setModel(models[0].id)
|
||||
}
|
||||
}, [model, models, setModel])
|
||||
|
||||
const { runTest, stopGeneration } = useChatStreamClient({
|
||||
t,
|
||||
@@ -84,6 +196,7 @@ export default function ApiTesterContainer({ config, onMessage, authFetch }) {
|
||||
models={models}
|
||||
model={model}
|
||||
setModel={setModel}
|
||||
modelsLoaded={modelsLoaded}
|
||||
streamingMode={streamingMode}
|
||||
setStreamingMode={setStreamingMode}
|
||||
selectedAccount={selectedAccount}
|
||||
@@ -114,6 +227,7 @@ export default function ApiTesterContainer({ config, onMessage, authFetch }) {
|
||||
streamingContent={streamingContent}
|
||||
onRunTest={runTest}
|
||||
onStopGeneration={stopGeneration}
|
||||
hasAvailableModel={models.length > 0}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user