fix(ai): 修复AI代理请求和图片生成功能
- 添加详细的错误日志记录,包括请求读取、渠道选择、请求构建和响应处理的失败情况 - 统一AI接口请求失败返回消息为"AI 接口请求失败" - 添加对上游响应状态码>=400的检查和错误处理 - 在JWT解析中验证签名方法有效性,防止无效登录状态 - 移除JWT密钥警告日志,改为运行时生成随机密钥 - 调整应用配置模态框中云端和本地选项的显示顺序 - 添加图片生成元数据记录生成类型、模型、尺寸、质量和参考图等信息 - 实现空图片节点直接生成图片而不保留空框的功能 - 完善图片重试逻辑,优先使用保存的元数据进行重试 - 添加参考图片丢失时的错误提示 - 修复图片节点样式圆角显示问题 - 更新AI代理路径为/api/v1/*保持OpenAI风格 - 添加系统设置页面的安全警告提示
This commit is contained in:
@@ -14,6 +14,8 @@ export type ChatCompletionMessage = {
|
||||
type ImageApiResponse = {
|
||||
data?: Array<Record<string, unknown>>;
|
||||
error?: { message?: string };
|
||||
code?: number;
|
||||
msg?: string;
|
||||
};
|
||||
|
||||
function resolveImageDataUrl(item: Record<string, unknown>) {
|
||||
@@ -27,6 +29,9 @@ function resolveImageDataUrl(item: Record<string, unknown>) {
|
||||
}
|
||||
|
||||
function parseImagePayload(payload: ImageApiResponse) {
|
||||
if (typeof payload.code === "number" && payload.code !== 0) {
|
||||
throw new Error(payload.msg || "请求失败");
|
||||
}
|
||||
const images =
|
||||
payload.data
|
||||
?.map(resolveImageDataUrl)
|
||||
@@ -41,8 +46,9 @@ function parseImagePayload(payload: ImageApiResponse) {
|
||||
}
|
||||
|
||||
function readAxiosError(error: unknown, fallback: string) {
|
||||
if (axios.isAxiosError<{ error?: { message?: string } }>(error)) {
|
||||
return error.response?.data?.error?.message || (error.response?.status ? `${fallback}:${error.response.status}` : fallback);
|
||||
if (axios.isAxiosError<{ error?: { message?: string }; msg?: string; code?: number }>(error)) {
|
||||
const responseData = error.response?.data;
|
||||
return responseData?.msg || responseData?.error?.message || (error.response?.status ? `${fallback}:${error.response.status}` : fallback);
|
||||
}
|
||||
return error instanceof Error ? error.message : fallback;
|
||||
}
|
||||
@@ -64,7 +70,7 @@ function withSystemPrompt(config: AiConfig, prompt: string) {
|
||||
}
|
||||
|
||||
function aiApiUrl(config: AiConfig, path: string) {
|
||||
return config.channelMode === "remote" ? `/api/ai${path}` : buildApiUrl(config.baseUrl, path);
|
||||
return config.channelMode === "remote" ? `/api/v1${path}` : buildApiUrl(config.baseUrl, path);
|
||||
}
|
||||
|
||||
function aiHeaders(config: AiConfig, contentType?: string) {
|
||||
@@ -134,7 +140,7 @@ export async function requestImageQuestion(config: AiConfig, messages: ChatCompl
|
||||
let processedLength = 0;
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
const response = await axios.post(
|
||||
aiApiUrl(config, "/chat/completions"),
|
||||
{
|
||||
model: config.model,
|
||||
@@ -162,6 +168,21 @@ export async function requestImageQuestion(config: AiConfig, messages: ChatCompl
|
||||
},
|
||||
},
|
||||
);
|
||||
if (typeof response.data === "object" && response.data && "code" in response.data && (response.data as { code?: number; msg?: string }).code !== 0) {
|
||||
throw new Error((response.data as { msg?: string }).msg || "请求失败");
|
||||
}
|
||||
if (typeof response.data === "string") {
|
||||
let apiError = "";
|
||||
try {
|
||||
const payload = JSON.parse(response.data) as { code?: number; msg?: string };
|
||||
if (typeof payload.code === "number" && payload.code !== 0) {
|
||||
apiError = payload.msg || "请求失败";
|
||||
}
|
||||
} catch {
|
||||
// ignore plain text stream content
|
||||
}
|
||||
if (apiError) throw new Error(apiError);
|
||||
}
|
||||
if (buffer) {
|
||||
parseStreamChunk(buffer, (delta) => {
|
||||
answer += delta;
|
||||
|
||||
Reference in New Issue
Block a user