UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

229 lines (196 loc) 6.95 kB
import { AgentRuntimeErrorType, ILobeAgentRuntimeErrorType } from '../types/error'; export interface ParsedError { error: any; errorType: ILobeAgentRuntimeErrorType; } export interface GoogleChatError { '@type': string; 'domain': string; 'metadata': { service: string; }; 'reason': string; } export type GoogleChatErrors = GoogleChatError[]; /** * 清理错误消息,移除格式化字符和多余的空格 * @param message - 原始错误消息 * @returns 清理后的错误消息 */ export function cleanErrorMessage(message: string): string { return message .replaceAll(/^\*\s*/g, '') // 移除开头的星号和空格 .replaceAll('\\n', '\n') // 转换转义的换行符 .replaceAll(/\n+/g, ' ') // 将多个换行符替换为单个空格 .trim(); // 去除首尾空格 } /** * 从错误消息中提取状态码信息 * @param message - 错误消息 * @returns 提取的错误详情和前缀 */ export function extractStatusCodeFromError(message: string): { errorDetails: any; prefix: string; } { // 使用正则表达式匹配状态码部分 [数字 描述文本] const regex = /^(.*?)(\[\d+ [^\]]+])(.*)$/; const match = message.match(regex); if (match) { const prefix = match[1].trim(); const statusCodeWithBrackets = match[2].trim(); const messageContent = match[3].trim(); // 提取状态码数字 const statusCodeMatch = statusCodeWithBrackets.match(/\[(\d+)/); const statusCode = statusCodeMatch ? parseInt(statusCodeMatch[1]) : null; // 创建包含状态码和消息的JSON const resultJson = { message: messageContent, statusCode: statusCode, statusCodeText: statusCodeWithBrackets, }; return { errorDetails: resultJson, prefix: prefix, }; } // 如果无法匹配,返回原始消息 return { errorDetails: null, prefix: message, }; } /** * 解析Google AI API返回的错误消息 * @param message - 原始错误消息 * @returns 解析后的错误对象和错误类型 */ export function parseGoogleErrorMessage(message: string): ParsedError { const defaultError = { error: { message }, errorType: AgentRuntimeErrorType.ProviderBizError, }; // 快速识别特殊错误 if (message.includes('location is not supported')) { return { error: { message }, errorType: AgentRuntimeErrorType.LocationNotSupportError }; } // 统一的错误类型判断函数 const getErrorType = (code: number | null, message: string): ILobeAgentRuntimeErrorType => { if (code === 400 && message.includes('API key not valid')) { return AgentRuntimeErrorType.InvalidProviderAPIKey; } else if (code === 429) { return AgentRuntimeErrorType.QuotaLimitReached; } return AgentRuntimeErrorType.ProviderBizError; }; // 递归解析JSON,处理嵌套的JSON字符串 const parseJsonRecursively = (str: string, maxDepth: number = 5): any => { if (maxDepth <= 0) return null; try { const parsed = JSON.parse(str); // 如果解析出的对象包含error字段 if (parsed && typeof parsed === 'object' && parsed.error) { const errorInfo = parsed.error; // 清理错误消息 if (typeof errorInfo.message === 'string') { errorInfo.message = cleanErrorMessage(errorInfo.message); // 如果error.message还是一个JSON字符串,继续递归解析 try { const nestedResult = parseJsonRecursively(errorInfo.message, maxDepth - 1); // 只有当深层结果包含带有 code 的 error 对象时,才优先返回深层结果 if (nestedResult && nestedResult.error && nestedResult.error.code) { return nestedResult; } } catch { // 如果嵌套解析失败,使用当前层的信息 } } return parsed; } return parsed; } catch { return null; } }; // 1. 处理 "got status: UNAVAILABLE. {JSON}" 格式 const statusJsonMatch = message.match(/got status: (\w+)\.\s*({.*})$/); if (statusJsonMatch) { const statusFromMessage = statusJsonMatch[1]; const jsonPart = statusJsonMatch[2]; const parsedError = parseJsonRecursively(jsonPart); if (parsedError && parsedError.error) { const errorInfo = parsedError.error; const finalMessage = errorInfo.message || message; const finalCode = errorInfo.code || null; const finalStatus = errorInfo.status || statusFromMessage; return { error: { code: finalCode, message: finalMessage, status: finalStatus, }, errorType: getErrorType(finalCode, finalMessage), }; } } // 2. 尝试直接解析整个消息作为JSON const directParsed = parseJsonRecursively(message); if (directParsed && directParsed.error) { const errorInfo = directParsed.error; const finalMessage = errorInfo.message || message; const finalCode = errorInfo.code || null; const finalStatus = errorInfo.status || ''; return { error: { code: finalCode, message: finalMessage, status: finalStatus, }, errorType: getErrorType(finalCode, finalMessage), }; } // 3. 处理嵌套JSON格式,特别是message字段包含JSON的情况 try { const firstLevelParsed = JSON.parse(message); if (firstLevelParsed && firstLevelParsed.error && firstLevelParsed.error.message) { const nestedParsed = parseJsonRecursively(firstLevelParsed.error.message); if (nestedParsed && nestedParsed.error) { const errorInfo = nestedParsed.error; const finalMessage = errorInfo.message || message; const finalCode = errorInfo.code || null; const finalStatus = errorInfo.status || ''; return { error: { code: finalCode, message: finalMessage, status: finalStatus, }, errorType: getErrorType(finalCode, finalMessage), }; } } } catch { // 继续其他解析方式 } // 4. 原有的数组格式解析逻辑 const startIndex = message.lastIndexOf('['); if (startIndex !== -1) { try { const jsonString = message.slice(startIndex); const json: GoogleChatErrors = JSON.parse(jsonString); const bizError = json[0]; if (bizError?.reason === 'API_KEY_INVALID') { return { ...defaultError, errorType: AgentRuntimeErrorType.InvalidProviderAPIKey }; } return { error: json, errorType: AgentRuntimeErrorType.ProviderBizError }; } catch { // 忽略解析错误 } } // 5. 使用状态码提取逻辑作为最后的后备方案 const errorObj = extractStatusCodeFromError(message); if (errorObj.errorDetails) { return { error: errorObj.errorDetails, errorType: AgentRuntimeErrorType.ProviderBizError }; } return defaultError; }