feat: AI验证支持错误提示

This commit is contained in:
digua
2025-12-09 22:16:32 +08:00
parent 2c682faf02
commit 95c0eb1c7e
7 changed files with 81 additions and 31 deletions
+19 -4
View File
@@ -298,7 +298,7 @@ export class DeepSeekService implements ILLMService {
}
}
async validateApiKey(): Promise<boolean> {
async validateApiKey(): Promise<{ success: boolean; error?: string }> {
try {
// 发送一个简单请求验证 API Key
const response = await fetch(`${this.baseUrl}/v1/models`, {
@@ -307,9 +307,24 @@ export class DeepSeekService implements ILLMService {
Authorization: `Bearer ${this.apiKey}`,
},
})
return response.ok
} catch {
return false
if (response.ok) {
return { success: true }
}
// 尝试获取错误详情
const errorText = await response.text()
let errorMessage = `HTTP ${response.status}`
try {
const errorJson = JSON.parse(errorText)
errorMessage = errorJson.error?.message || errorJson.message || errorMessage
} catch {
if (errorText) {
errorMessage = errorText.slice(0, 200)
}
}
return { success: false, error: errorMessage }
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
return { success: false, error: errorMessage }
}
}
}
+20 -7
View File
@@ -248,7 +248,7 @@ export class OpenAICompatibleService implements ILLMService {
// 调试:如果有 delta 但没有 content,记录其他可能的内容字段
if (delta && !delta.content && !delta.tool_calls && !finishReason) {
const deltaKeys = Object.keys(delta)
if (deltaKeys.length > 0 && !deltaKeys.every(k => ['role', 'name', 'audio_content'].includes(k))) {
if (deltaKeys.length > 0 && !deltaKeys.every((k) => ['role', 'name', 'audio_content'].includes(k))) {
aiLogger.warn('OpenAI-Compatible', '检测到未处理的 delta 字段', { deltaKeys, delta })
}
}
@@ -348,7 +348,7 @@ export class OpenAICompatibleService implements ILLMService {
}
}
async validateApiKey(): Promise<boolean> {
async validateApiKey(): Promise<{ success: boolean; error?: string }> {
try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
@@ -370,19 +370,32 @@ export class OpenAICompatibleService implements ILLMService {
// 200 表示成功,401/403 表示认证失败,其他状态可能是参数问题但服务可达
if (response.ok) {
return true
return { success: true }
}
// 尝试获取错误详情
const errorText = await response.text()
let errorMessage = `HTTP ${response.status}`
try {
const errorJson = JSON.parse(errorText)
errorMessage = errorJson.error?.message || errorJson.message || errorMessage
} catch {
if (errorText) {
errorMessage = errorText.slice(0, 200)
}
}
// 认证失败
if (response.status === 401 || response.status === 403) {
return false
return { success: false, error: errorMessage }
}
// 其他错误(如 400 参数错误)但服务可达,认为验证通过
// 因为这说明认证成功了,只是请求参数有问题
return true
} catch {
return false
return { success: true }
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
return { success: false, error: errorMessage }
}
}
}
+19 -4
View File
@@ -276,7 +276,7 @@ export class QwenService implements ILLMService {
}
}
async validateApiKey(): Promise<boolean> {
async validateApiKey(): Promise<{ success: boolean; error?: string }> {
try {
// 发送一个简单请求验证 API Key
const response = await fetch(`${this.baseUrl}/models`, {
@@ -285,9 +285,24 @@ export class QwenService implements ILLMService {
Authorization: `Bearer ${this.apiKey}`,
},
})
return response.ok
} catch {
return false
if (response.ok) {
return { success: true }
}
// 尝试获取错误详情
const errorText = await response.text()
let errorMessage = `HTTP ${response.status}`
try {
const errorJson = JSON.parse(errorText)
errorMessage = errorJson.error?.message || errorJson.message || errorMessage
} catch {
if (errorText) {
errorMessage = errorText.slice(0, 200)
}
}
return { success: false, error: errorMessage }
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
return { success: false, error: errorMessage }
}
}
}
+2 -1
View File
@@ -150,8 +150,9 @@ export interface ILLMService {
/**
* 验证 API Key 是否有效
* @returns 验证结果和可能的错误信息
*/
validateApiKey(): Promise<boolean>
validateApiKey(): Promise<{ success: boolean; error?: string }>
}
/**
+5 -2
View File
@@ -265,6 +265,7 @@ export function registerAIHandlers({ win }: IpcContext): void {
/**
* 验证 API Key(支持自定义 baseUrl 和 model
* 返回对象格式:{ success: boolean, error?: string }
*/
ipcMain.handle(
'llm:validateApiKey',
@@ -274,10 +275,12 @@ export function registerAIHandlers({ win }: IpcContext): void {
const service = llm.createLLMService({ provider, apiKey, baseUrl, model })
const result = await service.validateApiKey()
console.log('[LLM:validateApiKey] 验证结果:', result)
return result
return { success: result.success, error: result.error }
} catch (error) {
console.error('[LLM:validateApiKey] 验证失败:', error)
return false
// 提取有意义的错误信息
const errorMessage = error instanceof Error ? error.message : String(error)
return { success: false, error: errorMessage }
}
}
)
+6 -1
View File
@@ -225,7 +225,12 @@ interface LlmApi {
setActiveConfig: (id: string) => Promise<{ success: boolean; error?: string }>
// 验证和检查
validateApiKey: (provider: string, apiKey: string, baseUrl?: string, model?: string) => Promise<boolean>
validateApiKey: (
provider: string,
apiKey: string,
baseUrl?: string,
model?: string
) => Promise<{ success: boolean; error?: string }>
hasConfig: () => Promise<boolean>
// 聊天功能