diff --git a/lib/ai/orchestrator.ts b/lib/ai/orchestrator.ts index d1f9dbd..096b33d 100644 --- a/lib/ai/orchestrator.ts +++ b/lib/ai/orchestrator.ts @@ -50,10 +50,44 @@ export async function orchestrateGeneration( }; } - // 1. Try Primary Provider (Google Gemini) + // 1. Try Primary Provider (OpenRouter) + if (isProviderAvailable("openrouter") && hasOpenRouterKey) { + try { + console.log(`[AI Orchestrator] Attempting Primary (OpenRouter: ${config.ai.backup.model})...`); + const result = await generateWithOpenRouter({ + model: config.ai.backup.model, + prompt: style.prompt, + negativePrompt: style.negativePrompt, + imageBase64, + mimeType, + timeoutMs: config.ai.backup.timeoutMs, + }); + + resetProvider("openrouter"); + return { + imageUrl: result.imageUrl, + providerUsed: "openrouter", + modelUsed: result.model, + durationMs: Date.now() - startTime, + fallbackTriggered: false, + }; + } catch (primaryError: any) { + if (isContentSafetyError(primaryError)) { + console.warn(`[AI Orchestrator] Primary provider (OpenRouter) rejected image for safety:`, primaryError.message); + throw new ContentSafetyError(primaryError.message); + } + + console.warn(`[AI Orchestrator] Primary provider (OpenRouter) failed:`, primaryError.message); + warnings.push(`Primary (OpenRouter) failed: ${primaryError.message}`); + } + } else { + warnings.push("Primary provider key (OpenRouter) missing or in cooldown. Skipping to fallback."); + } + + // 2. Try Fallback Provider (Google Gemini) if (isProviderAvailable("gemini") && hasGeminiKey) { try { - console.log(`[AI Orchestrator] Attempting Primary (Gemini: ${config.ai.primary.model})...`); + console.log(`[AI Orchestrator] Attempting Fallback (Gemini: ${config.ai.primary.model})...`); const result = await generateWithGemini({ model: config.ai.primary.model, prompt: style.prompt, @@ -70,51 +104,17 @@ export async function orchestrateGeneration( providerUsed: "gemini", modelUsed: result.model, durationMs: Date.now() - startTime, - fallbackTriggered: false, - }; - } catch (primaryError: any) { - // Content safety rejections are caused by user input, NOT provider downtime - if (isContentSafetyError(primaryError)) { - console.warn(`[AI Orchestrator] Primary provider (Gemini) rejected image for safety:`, primaryError.message); - throw new ContentSafetyError(primaryError.message); - } - - console.warn(`[AI Orchestrator] Primary provider (Gemini) failed:`, primaryError.message); - warnings.push(`Primary failed: ${primaryError.message}`); - } - } else { - warnings.push("Primary provider key missing. Skipping to backup."); - } - - // 2. Try Backup Provider (OpenRouter) - if (isProviderAvailable("openrouter") && hasOpenRouterKey) { - try { - console.log(`[AI Orchestrator] Attempting Backup (OpenRouter: ${config.ai.backup.model})...`); - const result = await generateWithOpenRouter({ - model: config.ai.backup.model, - prompt: style.prompt, - negativePrompt: style.negativePrompt, - imageBase64, - mimeType, - timeoutMs: config.ai.backup.timeoutMs, - }); - - return { - imageUrl: result.imageUrl, - providerUsed: "openrouter", - modelUsed: result.model, - durationMs: Date.now() - startTime, fallbackTriggered: true, warnings, }; - } catch (backupError: any) { - if (isContentSafetyError(backupError)) { - console.warn(`[AI Orchestrator] Backup provider (OpenRouter) rejected image for safety:`, backupError.message); - throw new ContentSafetyError(backupError.message); + } catch (fallbackError: any) { + if (isContentSafetyError(fallbackError)) { + console.warn(`[AI Orchestrator] Fallback provider (Gemini) rejected image for safety:`, fallbackError.message); + throw new ContentSafetyError(fallbackError.message); } - console.error(`[AI Orchestrator] Backup provider (OpenRouter) failed:`, backupError.message); - warnings.push(`Backup failed: ${backupError.message}`); + console.error(`[AI Orchestrator] Fallback provider (Gemini) failed:`, fallbackError.message); + warnings.push(`Fallback (Gemini) failed: ${fallbackError.message}`); } }