From b7346c28f21ae7a241e6ee965957e2473546b12e Mon Sep 17 00:00:00 2001 From: HCID274 <504283668@qq.com> Date: Sat, 3 Jan 2026 15:34:31 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0AI=20API=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E8=B6=85=E6=97=B6(2=E7=A7=92)=E5=92=8C=E9=87=8D?= =?UTF-8?q?=E8=AF=95(=E6=9C=80=E5=A4=9A3=E6=AC=A1)=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用 AbortController 实现精确的2秒超时控制 - 超时后自动重试,最多3次,每次间隔1秒 - 改善不稳定网络环境下的用户体验 - 更新错误提示信息,明确显示重试次数 --- src/helpers/ipcHandlers.js | 80 ++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/src/helpers/ipcHandlers.js b/src/helpers/ipcHandlers.js index ef657ab..7521a65 100644 --- a/src/helpers/ipcHandlers.js +++ b/src/helpers/ipcHandlers.js @@ -1032,24 +1032,70 @@ ${text} requestData }); - const response = await fetch(`${baseUrl}/chat/completions`, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${apiKey}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify(requestData) - }); + // 重试配置:2秒超时,最多3次重试 + const MAX_RETRIES = 3; + const TIMEOUT_MS = 2000; // 2秒超时 + const RETRY_DELAY_MS = 1000; // 重试间隔1秒 - if (!response.ok) { - const errorText = await response.text(); - let errorData = { error: response.statusText }; + let lastError = null; + let response = null; + + for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) { try { - errorData = JSON.parse(errorText); - } catch { - errorData = { error: errorText || response.statusText }; + this.logger.info(`AI请求第 ${attempt}/${MAX_RETRIES} 次尝试, 超时: ${TIMEOUT_MS}ms`); + + // 使用 AbortController 实现超时 + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS); + + try { + response = await fetch(`${baseUrl}/chat/completions`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${apiKey}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestData), + signal: controller.signal + }); + clearTimeout(timeoutId); + + // 请求成功,跳出重试循环 + if (response.ok) { + this.logger.info(`AI请求第 ${attempt} 次成功`); + break; + } else { + // 非超时错误,也记录下来 + const errorText = await response.text(); + lastError = new Error(`API错误 ${response.status}: ${errorText}`); + this.logger.warn(`AI请求第 ${attempt} 次失败: ${lastError.message}`); + } + } catch (fetchError) { + clearTimeout(timeoutId); + + if (fetchError.name === 'AbortError') { + lastError = new Error(`请求超时 (${TIMEOUT_MS / 1000}秒)`); + this.logger.warn(`AI请求第 ${attempt} 次超时`); + } else { + lastError = fetchError; + this.logger.warn(`AI请求第 ${attempt} 次失败: ${fetchError.message}`); + } + } + + // 如果不是最后一次尝试,等待后重试 + if (attempt < MAX_RETRIES) { + this.logger.info(`等待 ${RETRY_DELAY_MS}ms 后重试...`); + await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS)); + } + } catch (error) { + lastError = error; + this.logger.error(`AI请求第 ${attempt} 次异常: ${error.message}`); } - throw new Error(errorData.error?.message || errorData.error || `API error: ${response.status}`); + } + + // 检查是否所有重试都失败了 + if (!response || !response.ok) { + throw lastError || new Error('所有重试均失败'); } const data = await response.json(); @@ -1097,8 +1143,8 @@ ${text} } else { errorMessage = `API错误: ${error.response.status}`; } - } else if (error.code === 'ECONNABORTED') { - errorMessage = '请求超时,请检查网络连接'; + } else if (error.message.includes('超时')) { + errorMessage = '请求超时,已重试3次仍失败,请检查网络连接'; } else if (error.code === 'ENOTFOUND') { errorMessage = '无法连接到AI服务器,请检查网络'; } else {