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) {
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
// 发送初始消息
|
||||
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];
|
||||
try {
|
||||
// 发送初始消息
|
||||
controller.enqueue(encoder.encode(JSON.stringify({ type: "start", total: processedScenes.length }) + "\n"));
|
||||
|
||||
console.log(`[SceneFusion] ========== Processing scene ${i + 1}/${processedScenes.length} ==========`);
|
||||
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}`);
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
// 如果不是第一张图,等待5秒
|
||||
if (i > 0) {
|
||||
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
|
||||
);
|
||||
for (let i = 0; i < processedScenes.length; i++) {
|
||||
const scene = processedScenes[i];
|
||||
|
||||
// 将分辨率等级用于数据库存储
|
||||
const dbImageSize = imageSize || "2K";
|
||||
console.log(`[SceneFusion] ========== Processing scene ${i + 1}/${processedScenes.length} ==========`);
|
||||
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,因为场景裂变不关联聊天)
|
||||
try {
|
||||
await db.insert(generatedImage).values({
|
||||
userId: session.user.id,
|
||||
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);
|
||||
// 如果不是第一张图,等待5秒
|
||||
if (i > 0) {
|
||||
console.log(`[SceneFusion] Waiting 5 seconds before processing...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
}
|
||||
|
||||
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"));
|
||||
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
|
||||
);
|
||||
|
||||
// 将分辨率等级用于数据库存储
|
||||
const dbImageSize = imageSize || "2K";
|
||||
|
||||
// 保存到数据库(chatId 和 messageId 设为 null,因为场景裂变不关联聊天)
|
||||
try {
|
||||
await db.insert(generatedImage).values({
|
||||
userId: session.user.id,
|
||||
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++;
|
||||
|
||||
// 立即发送完成的结果给前端
|
||||
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 {
|
||||
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) {
|
||||
console.error('[SceneFusion Client] Failed to parse message:', parseError, 'Line:', line);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user