mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-08 18:35:35 +08:00
feat: Enhance DeepSeek API compatibility by updating SSE parsing, standardizing error responses, and improving API key management in the tester UI.
This commit is contained in:
@@ -42,6 +42,12 @@ export default function ApiTester({ config, onMessage, authFetch }) {
|
||||
|
||||
const apiFetch = authFetch || fetch
|
||||
const accounts = config.accounts || []
|
||||
const configuredKeys = config.keys || []
|
||||
const trimmedApiKey = apiKey.trim()
|
||||
const defaultKey = configuredKeys[0] || ''
|
||||
const effectiveKey = trimmedApiKey || defaultKey
|
||||
const customKeyActive = trimmedApiKey !== ''
|
||||
const customKeyManaged = customKeyActive && configuredKeys.includes(trimmedApiKey)
|
||||
const models = [
|
||||
{ id: "deepseek-chat", name: "deepseek-chat", icon: MessageSquare, desc: t('apiTester.models.chat'), color: "text-amber-500" },
|
||||
{ id: "deepseek-reasoner", name: "deepseek-reasoner", icon: Cpu, desc: t('apiTester.models.reasoner'), color: "text-amber-600" },
|
||||
@@ -58,6 +64,28 @@ export default function ApiTester({ config, onMessage, authFetch }) {
|
||||
setIsStreaming(false)
|
||||
}
|
||||
|
||||
const extractErrorMessage = async (res) => {
|
||||
let raw = ''
|
||||
try {
|
||||
raw = await res.text()
|
||||
} catch {
|
||||
return t('apiTester.requestFailed')
|
||||
}
|
||||
if (!raw) {
|
||||
return t('apiTester.requestFailed')
|
||||
}
|
||||
try {
|
||||
const data = JSON.parse(raw)
|
||||
const fromErrorObject = data?.error?.message
|
||||
const fromErrorString = typeof data?.error === 'string' ? data.error : ''
|
||||
const detail = typeof data?.detail === 'string' ? data.detail : ''
|
||||
const message = typeof data?.message === 'string' ? data.message : ''
|
||||
return fromErrorObject || fromErrorString || detail || message || t('apiTester.requestFailed')
|
||||
} catch {
|
||||
return raw.length > 240 ? `${raw.slice(0, 240)}...` : raw
|
||||
}
|
||||
}
|
||||
|
||||
const runTest = async () => {
|
||||
if (loading) return
|
||||
|
||||
@@ -70,8 +98,7 @@ export default function ApiTester({ config, onMessage, authFetch }) {
|
||||
abortControllerRef.current = new AbortController()
|
||||
|
||||
try {
|
||||
const key = apiKey || (config.keys?.[0] || '')
|
||||
if (!key) {
|
||||
if (!effectiveKey) {
|
||||
onMessage('error', t('apiTester.missingApiKey'))
|
||||
setLoading(false)
|
||||
setIsStreaming(false)
|
||||
@@ -80,7 +107,7 @@ export default function ApiTester({ config, onMessage, authFetch }) {
|
||||
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${key}`,
|
||||
'Authorization': `Bearer ${effectiveKey}`,
|
||||
}
|
||||
if (selectedAccount) {
|
||||
headers['X-Ds2-Target-Account'] = selectedAccount
|
||||
@@ -98,8 +125,7 @@ export default function ApiTester({ config, onMessage, authFetch }) {
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
const data = await res.json().catch(() => ({}))
|
||||
const errorMsg = data.error?.message || t('apiTester.requestFailed')
|
||||
const errorMsg = await extractErrorMessage(res)
|
||||
setResponse({ success: false, error: errorMsg })
|
||||
onMessage('error', errorMsg)
|
||||
setLoading(false)
|
||||
@@ -280,12 +306,22 @@ return (
|
||||
<div className="space-y-2">
|
||||
<label className="text-[11px] font-semibold text-muted-foreground uppercase tracking-wider ml-0.5">{t('apiTester.apiKeyOptional')}</label>
|
||||
<input
|
||||
type="password"
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
spellCheck={false}
|
||||
className="w-full h-10 px-3 bg-muted/30 border border-border rounded-lg text-sm font-mono placeholder:text-muted-foreground/40 focus:outline-none focus:ring-1 focus:ring-ring focus:border-ring transition-all"
|
||||
placeholder={config.keys?.[0] ? t('apiTester.apiKeyDefault', { suffix: config.keys[0].slice(-6) }) : t('apiTester.apiKeyPlaceholder')}
|
||||
value={apiKey}
|
||||
onChange={e => setApiKey(e.target.value)}
|
||||
/>
|
||||
{customKeyActive && (
|
||||
<p className={clsx(
|
||||
"text-[11px] mt-1",
|
||||
customKeyManaged ? "text-emerald-600" : "text-amber-600"
|
||||
)}>
|
||||
{customKeyManaged ? t('apiTester.modeManaged') : t('apiTester.modeDirect')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -145,6 +145,8 @@
|
||||
"apiKeyOptional": "API Key (optional)",
|
||||
"apiKeyDefault": "Default: ...{suffix}",
|
||||
"apiKeyPlaceholder": "Enter a custom key",
|
||||
"modeManaged": "Managed key mode (uses account pool).",
|
||||
"modeDirect": "Direct token mode (requires a valid DeepSeek token).",
|
||||
"statusError": "Error",
|
||||
"reasoningTrace": "Reasoning Trace",
|
||||
"generating": "Generating response...",
|
||||
@@ -234,4 +236,4 @@
|
||||
"four": "Trigger a redeploy to apply the updated environment variables."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +145,8 @@
|
||||
"apiKeyOptional": "API 密钥 (可选)",
|
||||
"apiKeyDefault": "默认: ...{suffix}",
|
||||
"apiKeyPlaceholder": "输入自定义密钥",
|
||||
"modeManaged": "当前使用托管 key 模式(会走账号池)。",
|
||||
"modeDirect": "当前使用直通 token 模式(需填写有效 DeepSeek token)。",
|
||||
"statusError": "错误",
|
||||
"reasoningTrace": "思维链过程",
|
||||
"generating": "正在生成响应...",
|
||||
@@ -234,4 +236,4 @@
|
||||
"four": "触发重新部署以应用新的环境变量。"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user