修复(core): 改进图像生成和编辑的中断功能

- 在 geminiService 中添加多个 AbortSignal 检查点,确保及时响应中断请求
- 修复连续生成模式下的中断处理,避免中断后继续重试
- 在 cancelGeneration 和 cancelEdit 中添加连续生成状态重置
- 优化错误处理,区分用户中断和其他错误类型

解决了用户点击中断按钮后操作仍继续执行的问题
This commit is contained in:
2025-12-22 21:33:25 +08:00
parent 62946be82f
commit 9359dd13de
3 changed files with 46 additions and 1 deletions

View File

@@ -334,6 +334,12 @@ export const PromptComposer: React.FC = () => {
// 开始连续生成循环 // 开始连续生成循环
const generateWithRetry = async () => { const generateWithRetry = async () => {
try { try {
// 在开始前检查是否仍在连续生成模式
if (!useAppStore.getState().isContinuousGenerating) {
console.log('连续生成已取消');
return;
}
// 即使没有参考图像也继续生成,因为提示文本是必需的 // 即使没有参考图像也继续生成,因为提示文本是必需的
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
// 使用mutateAsync来等待结果 // 使用mutateAsync来等待结果
@@ -347,6 +353,13 @@ export const PromptComposer: React.FC = () => {
setIsContinuousGenerating(false); setIsContinuousGenerating(false);
resolve(); resolve();
}).catch((error) => { }).catch((error) => {
// 检查是否是因为中断导致的错误
if (error.message === '生成已中断' || error.message === '生成已取消') {
console.log('生成被用户中断');
setIsContinuousGenerating(false);
resolve(); // 不再重试
return;
}
// 生成失败,增加重试计数并继续 // 生成失败,增加重试计数并继续
const newCount = useAppStore.getState().retryCount + 1; const newCount = useAppStore.getState().retryCount + 1;
setRetryCount(newCount); setRetryCount(newCount);
@@ -359,7 +372,12 @@ export const PromptComposer: React.FC = () => {
// 如果仍在连续生成模式下,继续重试 // 如果仍在连续生成模式下,继续重试
if (useAppStore.getState().isContinuousGenerating) { if (useAppStore.getState().isContinuousGenerating) {
console.log('生成失败,正在重试...'); 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 = () => { const cancelContinuousGeneration = () => {
setIsContinuousGenerating(false); setIsContinuousGenerating(false);
// 立即调用 cancelGeneration 来中断当前请求
cancelGeneration(); cancelGeneration();
}; };

View File

@@ -253,6 +253,9 @@ export const useImageGeneration = () => {
if (abortControllerRef.current) { if (abortControllerRef.current) {
abortControllerRef.current.abort() abortControllerRef.current.abort()
} }
// 重置连续生成状态
const { setIsContinuousGenerating } = useAppStore.getState()
setIsContinuousGenerating(false)
setIsGenerating(false) setIsGenerating(false)
addToast('生成已中断', 'info', 3000) addToast('生成已中断', 'info', 3000)
} }
@@ -700,6 +703,9 @@ export const useImageEditing = () => {
if (abortControllerRef.current) { if (abortControllerRef.current) {
abortControllerRef.current.abort() abortControllerRef.current.abort()
} }
// 重置连续生成状态(如果正在运行)
const { setIsContinuousGenerating } = useAppStore.getState()
setIsContinuousGenerating(false)
setIsGenerating(false) setIsGenerating(false)
addToast('编辑已中断', 'info', 3000) addToast('编辑已中断', 'info', 3000)
} }

View File

@@ -79,6 +79,11 @@ export class GeminiService {
async generateImage(request: GenerationRequest): Promise<{ images: Blob[]; usageMetadata?: UsageMetadata }> { async generateImage(request: GenerationRequest): Promise<{ images: Blob[]; usageMetadata?: UsageMetadata }> {
try { try {
// 在开始之前检查是否已中断
if (request.abortSignal?.aborted) {
throw new Error('生成已取消')
}
const contents: Array<{ text: string } | { inlineData: { mimeType: string; data: string } }> = [{ text: request.prompt }] const contents: Array<{ text: string } | { inlineData: { mimeType: string; data: string } }> = [{ text: request.prompt }]
// 如果提供了参考图像则添加 // 如果提供了参考图像则添加
@@ -88,6 +93,11 @@ export class GeminiService {
// 为每个参考图像生成或获取base64数据 // 为每个参考图像生成或获取base64数据
for (const blob of request.referenceImages) { for (const blob of request.referenceImages) {
// 在处理每个图像之前检查中断
if (request.abortSignal?.aborted) {
throw new Error('生成已取消')
}
// 生成Blob的唯一标识符 // 生成Blob的唯一标识符
const blobId = await this.generateBlobId(blob) const blobId = await this.generateBlobId(blob)
@@ -116,6 +126,11 @@ export class GeminiService {
base64Images.push(base64) base64Images.push(base64)
} }
// 再次检查中断状态
if (request.abortSignal?.aborted) {
throw new Error('生成已取消')
}
base64Images.forEach(image => { base64Images.forEach(image => {
// 确保图像数据不为空 // 确保图像数据不为空
if (image && image.length > 0) { if (image && image.length > 0) {
@@ -242,6 +257,11 @@ export class GeminiService {
async editImage(request: EditRequest): Promise<{ images: Blob[]; usageMetadata?: UsageMetadata }> { async editImage(request: EditRequest): Promise<{ images: Blob[]; usageMetadata?: UsageMetadata }> {
try { try {
// 在开始之前检查是否已中断
if (request.abortSignal?.aborted) {
throw new Error('编辑已取消')
}
// 将原始图像Blob转换为base64以发送到API // 将原始图像Blob转换为base64以发送到API
let originalImageBase64: string let originalImageBase64: string