fix: improve error handling for streaming response in scene fusion
This commit is contained in:
parent
bec71cf195
commit
da99fbdc93
@ -683,105 +683,115 @@ export async function POST(request: Request) {
|
|||||||
async start(controller) {
|
async start(controller) {
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
// 发送初始消息
|
try {
|
||||||
controller.enqueue(encoder.encode(JSON.stringify({ type: "start", total: processedScenes.length }) + "\n"));
|
// 发送初始消息
|
||||||
|
controller.enqueue(encoder.encode(JSON.stringify({ type: "start", total: processedScenes.length }) + "\n"));
|
||||||
let successCount = 0;
|
|
||||||
let failCount = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < processedScenes.length; i++) {
|
|
||||||
const scene = processedScenes[i];
|
|
||||||
|
|
||||||
console.log(`[SceneFusion] ========== Processing scene ${i + 1}/${processedScenes.length} ==========`);
|
let successCount = 0;
|
||||||
console.log(`[SceneFusion] Scene ID: ${scene.id}`);
|
let failCount = 0;
|
||||||
console.log(`[SceneFusion] Product Image URL: ${productImageUrl.substring(0, 80)}...`);
|
|
||||||
console.log(`[SceneFusion] Scene Image URL: ${scene.imageUrl.substring(0, 80)}...`);
|
|
||||||
console.log(`[SceneFusion] Target Name: ${scene.targetName || '(not specified)'}`);
|
|
||||||
console.log(`[SceneFusion] Custom Prompt: ${scene.customPrompt || '(none)'}`);
|
|
||||||
console.log(`[SceneFusion] Provider Type: ${provider.type}`);
|
|
||||||
|
|
||||||
// 如果不是第一张图,等待5秒
|
for (let i = 0; i < processedScenes.length; i++) {
|
||||||
if (i > 0) {
|
const scene = processedScenes[i];
|
||||||
console.log(`[SceneFusion] Waiting 5 seconds before processing...`);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 使用新的通用处理函数,支持多种模型类型
|
|
||||||
const result = await processSceneWithProvider(
|
|
||||||
productImageUrl,
|
|
||||||
scene.imageUrl,
|
|
||||||
productName,
|
|
||||||
scene.targetName,
|
|
||||||
scene.customPrompt,
|
|
||||||
config.defaultPrompt,
|
|
||||||
{ type: provider.type, baseUrl: provider.baseUrl, apiKey: provider.apiKey },
|
|
||||||
model.modelId,
|
|
||||||
aspectRatio,
|
|
||||||
imageSize
|
|
||||||
);
|
|
||||||
|
|
||||||
// 将分辨率等级用于数据库存储
|
console.log(`[SceneFusion] ========== Processing scene ${i + 1}/${processedScenes.length} ==========`);
|
||||||
const dbImageSize = imageSize || "2K";
|
console.log(`[SceneFusion] Scene ID: ${scene.id}`);
|
||||||
|
console.log(`[SceneFusion] Product Image URL: ${productImageUrl.substring(0, 80)}...`);
|
||||||
|
console.log(`[SceneFusion] Scene Image URL: ${scene.imageUrl.substring(0, 80)}...`);
|
||||||
|
console.log(`[SceneFusion] Target Name: ${scene.targetName || '(not specified)'}`);
|
||||||
|
console.log(`[SceneFusion] Custom Prompt: ${scene.customPrompt || '(none)'}`);
|
||||||
|
console.log(`[SceneFusion] Provider Type: ${provider.type}`);
|
||||||
|
|
||||||
// 保存到数据库(chatId 和 messageId 设为 null,因为场景裂变不关联聊天)
|
// 如果不是第一张图,等待5秒
|
||||||
try {
|
if (i > 0) {
|
||||||
await db.insert(generatedImage).values({
|
console.log(`[SceneFusion] Waiting 5 seconds before processing...`);
|
||||||
userId: session.user.id,
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||||
chatId: null, // 场景裂变不关联聊天
|
|
||||||
messageId: null, // 场景裂变不关联消息
|
|
||||||
thumbnailUrl: result.thumbnail,
|
|
||||||
originalUrl: result.original,
|
|
||||||
imageSize: dbImageSize,
|
|
||||||
prompt: `[场景裂变] ${result.prompt}`,
|
|
||||||
modelId: model.modelId,
|
|
||||||
});
|
|
||||||
console.log(`[SceneFusion] ✅ Saved image to gallery: ${result.original.substring(0, 80)}...`);
|
|
||||||
} catch (dbError) {
|
|
||||||
console.error("[SceneFusion] ❌ Failed to save to gallery:", dbError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
successCount++;
|
try {
|
||||||
|
// 使用新的通用处理函数,支持多种模型类型
|
||||||
// 立即发送完成的结果给前端
|
const result = await processSceneWithProvider(
|
||||||
controller.enqueue(encoder.encode(JSON.stringify({
|
productImageUrl,
|
||||||
type: "result",
|
scene.imageUrl,
|
||||||
data: {
|
productName,
|
||||||
id: scene.id,
|
scene.targetName,
|
||||||
status: "completed" as const,
|
scene.customPrompt,
|
||||||
result: result.thumbnail, // 返回缩略图用于预览
|
config.defaultPrompt,
|
||||||
originalUrl: result.original, // 原图用于下载
|
{ type: provider.type, baseUrl: provider.baseUrl, apiKey: provider.apiKey },
|
||||||
},
|
model.modelId,
|
||||||
}) + "\n"));
|
aspectRatio,
|
||||||
|
imageSize
|
||||||
} catch (error) {
|
);
|
||||||
console.error(`[SceneFusion] Failed to process scene ${scene.id}:`, error);
|
|
||||||
failCount++;
|
// 将分辨率等级用于数据库存储
|
||||||
|
const dbImageSize = imageSize || "2K";
|
||||||
// 立即发送失败的结果给前端
|
|
||||||
controller.enqueue(encoder.encode(JSON.stringify({
|
// 保存到数据库(chatId 和 messageId 设为 null,因为场景裂变不关联聊天)
|
||||||
type: "result",
|
try {
|
||||||
data: {
|
await db.insert(generatedImage).values({
|
||||||
id: scene.id,
|
userId: session.user.id,
|
||||||
status: "failed" as const,
|
chatId: null, // 场景裂变不关联聊天
|
||||||
error: error instanceof Error ? error.message : "处理失败",
|
messageId: null, // 场景裂变不关联消息
|
||||||
},
|
thumbnailUrl: result.thumbnail,
|
||||||
}) + "\n"));
|
originalUrl: result.original,
|
||||||
|
imageSize: dbImageSize,
|
||||||
|
prompt: `[场景裂变] ${result.prompt}`,
|
||||||
|
modelId: model.modelId,
|
||||||
|
});
|
||||||
|
console.log(`[SceneFusion] ✅ Saved image to gallery: ${result.original.substring(0, 80)}...`);
|
||||||
|
} catch (dbError) {
|
||||||
|
console.error("[SceneFusion] ❌ Failed to save to gallery:", dbError);
|
||||||
|
}
|
||||||
|
|
||||||
|
successCount++;
|
||||||
|
|
||||||
|
// 立即发送完成的结果给前端
|
||||||
|
controller.enqueue(encoder.encode(JSON.stringify({
|
||||||
|
type: "result",
|
||||||
|
data: {
|
||||||
|
id: scene.id,
|
||||||
|
status: "completed" as const,
|
||||||
|
result: result.thumbnail, // 返回缩略图用于预览
|
||||||
|
originalUrl: result.original, // 原图用于下载
|
||||||
|
},
|
||||||
|
}) + "\n"));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[SceneFusion] Failed to process scene ${scene.id}:`, error);
|
||||||
|
failCount++;
|
||||||
|
|
||||||
|
// 立即发送失败的结果给前端
|
||||||
|
controller.enqueue(encoder.encode(JSON.stringify({
|
||||||
|
type: "result",
|
||||||
|
data: {
|
||||||
|
id: scene.id,
|
||||||
|
status: "failed" as const,
|
||||||
|
error: error instanceof Error ? error.message : "处理失败",
|
||||||
|
},
|
||||||
|
}) + "\n"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发送完成消息
|
||||||
|
console.log(`[SceneFusion] Completed: ${successCount} success, ${failCount} failed`);
|
||||||
|
controller.enqueue(encoder.encode(JSON.stringify({
|
||||||
|
type: "done",
|
||||||
|
summary: {
|
||||||
|
total: processedScenes.length,
|
||||||
|
success: successCount,
|
||||||
|
failed: failCount,
|
||||||
|
},
|
||||||
|
}) + "\n"));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[SceneFusion] Stream error:", error);
|
||||||
|
// 发送错误消息
|
||||||
|
controller.enqueue(encoder.encode(JSON.stringify({
|
||||||
|
type: "error",
|
||||||
|
error: error instanceof Error ? error.message : "处理失败",
|
||||||
|
}) + "\n"));
|
||||||
|
} finally {
|
||||||
|
controller.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送完成消息
|
|
||||||
console.log(`[SceneFusion] Completed: ${successCount} success, ${failCount} failed`);
|
|
||||||
controller.enqueue(encoder.encode(JSON.stringify({
|
|
||||||
type: "done",
|
|
||||||
summary: {
|
|
||||||
total: processedScenes.length,
|
|
||||||
success: successCount,
|
|
||||||
failed: failCount,
|
|
||||||
},
|
|
||||||
}) + "\n"));
|
|
||||||
|
|
||||||
controller.close();
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -291,6 +291,13 @@ export function SceneFusionView({ onBack }: SceneFusionViewProps) {
|
|||||||
} else {
|
} else {
|
||||||
toast.success(`批量处理完成:${summary.success} 张图片已生成`);
|
toast.success(`批量处理完成:${summary.success} 张图片已生成`);
|
||||||
}
|
}
|
||||||
|
} else if (message.type === 'error') {
|
||||||
|
console.error('[SceneFusion Client] Stream error:', message.error);
|
||||||
|
toast.error(`处理失败:${message.error || '未知错误'}`);
|
||||||
|
// 将所有处理中的场景标记为失败
|
||||||
|
setScenes(prev => prev.map(s =>
|
||||||
|
s.status === 'processing' ? { ...s, status: 'failed', error: message.error || '处理失败' } : s
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.error('[SceneFusion Client] Failed to parse message:', parseError, 'Line:', line);
|
console.error('[SceneFusion Client] Failed to parse message:', parseError, 'Line:', line);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user