修复火山生图失败时跨服务商故障迁移
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-12 13:52:01 +08:00
parent c9c0356fe3
commit 3909bae4c2

View File

@ -2296,6 +2296,7 @@ export async function POST(request: Request) {
const tryGenerateImage = async (modelIdToUse: string, isRetry: boolean) => {
const result = await (languageModel as any).doGenerate({
messages: modelMessages,
imageParams: effectiveImageParams || { aspectRatio: "auto", imageSize: "2K", imageCount: 1 },
overrideModelId: isRetry ? modelIdToUse : undefined,
});
if (result?.finishReason === "error") {
@ -2333,6 +2334,84 @@ export async function POST(request: Request) {
console.error(`[Chat API] ❌ Volcano fallback model ${fallbackModelId} failed:`, fallbackError);
}
}
if (!fallbackSuccess) {
const providerPriority: Record<string, number> = {
gemini: 0,
"huanke-gemini": 1,
"alibaba-image": 2,
"ruxa-image": 3,
"volcano-vision": 4,
};
const crossProviderCandidates = allModels
.filter((m) => {
if (!m.model.supportsImageGen || !m.model.isEnabled || m.model.isSubModel) {
return false;
}
if (m.model.id === finalModelId) return false;
if (m.provider.id === volcanoModelConfig?.providerId) return false;
return true;
})
.sort((a, b) => {
const left = providerPriority[a.provider.type as string] ?? 99;
const right = providerPriority[b.provider.type as string] ?? 99;
if (left !== right) return left - right;
return (a.model.sortOrder ?? 0) - (b.model.sortOrder ?? 0);
});
for (const candidate of crossProviderCandidates) {
try {
console.log(
`[Chat API] 🔁 Volcano cross-provider failover attempt: ${candidate.model.displayName} (${candidate.provider.type})`
);
const candidateLanguageModel = await getLanguageModelById(candidate.model.id);
if (!candidateLanguageModel || typeof (candidateLanguageModel as any).doGenerate !== "function") {
console.log(`[Chat API] Skip candidate without doGenerate: ${candidate.model.id}`);
continue;
}
const convertProvider =
candidate.provider.type === "ruxa-image"
? "ruxa-image"
: candidate.provider.type === "gemini"
? "gemini"
: candidate.provider.type === "huanke-gemini"
? "huanke-gemini"
: candidate.provider.type === "volcano-vision"
? "volcano"
: "alibaba-image";
const candidateMessages = await convertMessagesWithImages(
messagesForVolcano,
convertProvider
);
const candidateResult = await (candidateLanguageModel as any).doGenerate({
messages: candidateMessages,
imageParams: effectiveImageParams || { aspectRatio: "auto", imageSize: "2K", imageCount: 1 },
modelDisplayName: candidate.model.displayName,
overrideModelId: candidate.model.modelId,
});
if (candidateResult?.finishReason === "error") {
throw new Error(candidateResult.text || "图片生成失败");
}
imageMarkdown = candidateResult.text || "图片生成失败";
usedModelId = candidate.model.modelId;
fallbackSuccess = true;
console.log(
`[Chat API] ✅ Volcano cross-provider failover succeeded: ${candidate.model.displayName} (${candidate.provider.type})`
);
break;
} catch (crossError) {
console.error(
`[Chat API] ❌ Volcano cross-provider failover failed: ${candidate.model.displayName} (${candidate.provider.type})`,
crossError
);
}
}
}
if (!fallbackSuccess) {
throw primaryError;
}