diff --git a/backend/src/utils/gemini-fallback.js b/backend/src/utils/gemini-fallback.js index 8ad75cd..17625fb 100644 --- a/backend/src/utils/gemini-fallback.js +++ b/backend/src/utils/gemini-fallback.js @@ -1,6 +1,6 @@ /** - * Gemini API with OpenCode Fallback - * Tries Gemini first, falls back to OpenCode if quota exceeded + * Gemini API with Multi-Tier Fallback + * Tries: Gemini → OpenCode → OpenRouter */ const fetch = require('node-fetch'); @@ -8,14 +8,16 @@ const fetch = require('node-fetch'); const GEMINI_API_KEY = process.env.GOOGLE_API_KEY; const OPENCODE_API_KEY = process.env.OPENCODE_API_KEY; const OPENCODE_BASE_URL = process.env.OPENCODE_BASE_URL || 'https://api.opencode.com/v1'; +const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY; +const OPENROUTER_BASE_URL = process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1'; async function generateWithFallback(prompt, options = {}) { console.log('🤖 Generating content...'); - // Try Gemini first + // Tier 1: Try Gemini if (GEMINI_API_KEY) { try { - console.log('Attempting Gemini API...'); + console.log('📍 Tier 1: Attempting Gemini API...'); const response = await fetch( `https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent?key=${GEMINI_API_KEY}`, { @@ -35,20 +37,19 @@ async function generateWithFallback(prompt, options = {}) { } if (response.status === 429 || response.status === 403) { - console.warn('⚠️ Gemini quota exceeded, falling back to OpenCode...'); - throw new Error('QUOTA_EXCEEDED'); + console.warn('⚠️ Gemini quota exceeded, trying next fallback...'); + } else { + throw new Error(`Gemini error: ${response.status}`); } - - throw new Error(`Gemini API error: ${response.status}`); } catch (err) { console.warn(`Gemini failed: ${err.message}`); } } - // Fallback to OpenCode + // Tier 2: Fallback to OpenCode if (OPENCODE_API_KEY) { try { - console.log('Attempting OpenCode API...'); + console.log('📍 Tier 2: Attempting OpenCode API...'); const response = await fetch(`${OPENCODE_BASE_URL}/chat/completions`, { method: 'POST', headers: { @@ -69,19 +70,51 @@ async function generateWithFallback(prompt, options = {}) { return { success: true, provider: 'opencode', data }; } - throw new Error(`OpenCode API error: ${response.status}`); + console.warn(`OpenCode error: ${response.status}, trying next fallback...`); } catch (err) { - console.error(`OpenCode failed: ${err.message}`); + console.warn(`OpenCode failed: ${err.message}`); } } - throw new Error('All generation APIs failed'); + // Tier 3: Fallback to OpenRouter + if (OPENROUTER_API_KEY) { + try { + console.log('📍 Tier 3: Attempting OpenRouter API...'); + const response = await fetch(`${OPENROUTER_BASE_URL}/chat/completions`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${OPENROUTER_API_KEY}`, + 'Content-Type': 'application/json', + 'HTTP-Referer': 'https://gravl.app' + }, + body: JSON.stringify({ + model: options.model || 'openai/gpt-4', + messages: [{ role: 'user', content: prompt }], + temperature: options.temperature || 0.7, + max_tokens: options.maxTokens || 2048 + }) + }); + + if (response.ok) { + const data = await response.json(); + console.log('✅ OpenRouter API success'); + return { success: true, provider: 'openrouter', data }; + } + + throw new Error(`OpenRouter error: ${response.status}`); + } catch (err) { + console.error(`OpenRouter failed: ${err.message}`); + } + } + + throw new Error('All generation APIs failed (Gemini → OpenCode → OpenRouter)'); } module.exports = { generateWithFallback, getAvailableProviders: () => ({ gemini: !!GEMINI_API_KEY, - opencode: !!OPENCODE_API_KEY + opencode: !!OPENCODE_API_KEY, + openrouter: !!OPENROUTER_API_KEY }) };