From 9359dd13de7c1ee9d11eb743ff4d7159c5d4809b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E6=B6=9B?= Date: Mon, 22 Dec 2025 21:33:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D(core):=20=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E5=9B=BE=E5=83=8F=E7=94=9F=E6=88=90=E5=92=8C=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E7=9A=84=E4=B8=AD=E6=96=AD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 geminiService 中添加多个 AbortSignal 检查点,确保及时响应中断请求 - 修复连续生成模式下的中断处理,避免中断后继续重试 - 在 cancelGeneration 和 cancelEdit 中添加连续生成状态重置 - 优化错误处理,区分用户中断和其他错误类型 解决了用户点击中断按钮后操作仍继续执行的问题 --- src/components/PromptComposer.tsx | 21 ++++++++++++++++++++- src/hooks/useImageGeneration.ts | 6 ++++++ src/services/geminiService.ts | 20 ++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/components/PromptComposer.tsx b/src/components/PromptComposer.tsx index ea92ecc..b5bb76e 100644 --- a/src/components/PromptComposer.tsx +++ b/src/components/PromptComposer.tsx @@ -334,6 +334,12 @@ export const PromptComposer: React.FC = () => { // 开始连续生成循环 const generateWithRetry = async () => { try { + // 在开始前检查是否仍在连续生成模式 + if (!useAppStore.getState().isContinuousGenerating) { + console.log('连续生成已取消'); + return; + } + // 即使没有参考图像也继续生成,因为提示文本是必需的 await new Promise((resolve, reject) => { // 使用mutateAsync来等待结果 @@ -347,6 +353,13 @@ export const PromptComposer: React.FC = () => { setIsContinuousGenerating(false); resolve(); }).catch((error) => { + // 检查是否是因为中断导致的错误 + if (error.message === '生成已中断' || error.message === '生成已取消') { + console.log('生成被用户中断'); + setIsContinuousGenerating(false); + resolve(); // 不再重试 + return; + } // 生成失败,增加重试计数并继续 const newCount = useAppStore.getState().retryCount + 1; setRetryCount(newCount); @@ -359,7 +372,12 @@ export const PromptComposer: React.FC = () => { // 如果仍在连续生成模式下,继续重试 if (useAppStore.getState().isContinuousGenerating) { console.log('生成失败,正在重试...'); - setTimeout(generateWithRetry, 1000); // 1秒后重试 + // 再次检查连续生成状态 + setTimeout(() => { + if (useAppStore.getState().isContinuousGenerating) { + generateWithRetry(); + } + }, 1000); // 1秒后重试 } } }; @@ -371,6 +389,7 @@ export const PromptComposer: React.FC = () => { // 取消连续生成 const cancelContinuousGeneration = () => { setIsContinuousGenerating(false); + // 立即调用 cancelGeneration 来中断当前请求 cancelGeneration(); }; diff --git a/src/hooks/useImageGeneration.ts b/src/hooks/useImageGeneration.ts index 26847d4..f813e60 100644 --- a/src/hooks/useImageGeneration.ts +++ b/src/hooks/useImageGeneration.ts @@ -253,6 +253,9 @@ export const useImageGeneration = () => { if (abortControllerRef.current) { abortControllerRef.current.abort() } + // 重置连续生成状态 + const { setIsContinuousGenerating } = useAppStore.getState() + setIsContinuousGenerating(false) setIsGenerating(false) addToast('生成已中断', 'info', 3000) } @@ -700,6 +703,9 @@ export const useImageEditing = () => { if (abortControllerRef.current) { abortControllerRef.current.abort() } + // 重置连续生成状态(如果正在运行) + const { setIsContinuousGenerating } = useAppStore.getState() + setIsContinuousGenerating(false) setIsGenerating(false) addToast('编辑已中断', 'info', 3000) } diff --git a/src/services/geminiService.ts b/src/services/geminiService.ts index f3c57d8..7ee01d6 100644 --- a/src/services/geminiService.ts +++ b/src/services/geminiService.ts @@ -79,6 +79,11 @@ export class GeminiService { async generateImage(request: GenerationRequest): Promise<{ images: Blob[]; usageMetadata?: UsageMetadata }> { try { + // 在开始之前检查是否已中断 + if (request.abortSignal?.aborted) { + throw new Error('生成已取消') + } + const contents: Array<{ text: string } | { inlineData: { mimeType: string; data: string } }> = [{ text: request.prompt }] // 如果提供了参考图像则添加 @@ -88,6 +93,11 @@ export class GeminiService { // 为每个参考图像生成或获取base64数据 for (const blob of request.referenceImages) { + // 在处理每个图像之前检查中断 + if (request.abortSignal?.aborted) { + throw new Error('生成已取消') + } + // 生成Blob的唯一标识符 const blobId = await this.generateBlobId(blob) @@ -116,6 +126,11 @@ export class GeminiService { base64Images.push(base64) } + // 再次检查中断状态 + if (request.abortSignal?.aborted) { + throw new Error('生成已取消') + } + base64Images.forEach(image => { // 确保图像数据不为空 if (image && image.length > 0) { @@ -242,6 +257,11 @@ export class GeminiService { async editImage(request: EditRequest): Promise<{ images: Blob[]; usageMetadata?: UsageMetadata }> { try { + // 在开始之前检查是否已中断 + if (request.abortSignal?.aborted) { + throw new Error('编辑已取消') + } + // 将原始图像Blob转换为base64以发送到API let originalImageBase64: string