You've already forked Nano-Banana-AI-Image-Editor
修复(core): 改进图像生成和编辑的中断功能
- 在 geminiService 中添加多个 AbortSignal 检查点,确保及时响应中断请求 - 修复连续生成模式下的中断处理,避免中断后继续重试 - 在 cancelGeneration 和 cancelEdit 中添加连续生成状态重置 - 优化错误处理,区分用户中断和其他错误类型 解决了用户点击中断按钮后操作仍继续执行的问题
This commit is contained in:
@@ -334,6 +334,12 @@ export const PromptComposer: React.FC = () => {
|
||||
// 开始连续生成循环
|
||||
const generateWithRetry = async () => {
|
||||
try {
|
||||
// 在开始前检查是否仍在连续生成模式
|
||||
if (!useAppStore.getState().isContinuousGenerating) {
|
||||
console.log('连续生成已取消');
|
||||
return;
|
||||
}
|
||||
|
||||
// 即使没有参考图像也继续生成,因为提示文本是必需的
|
||||
await new Promise<void>((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();
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user