diff --git a/backend/src/utils/gemini-fallback.js b/backend/src/utils/gemini-fallback.js index c900443..c8288eb 100644 --- a/backend/src/utils/gemini-fallback.js +++ b/backend/src/utils/gemini-fallback.js @@ -1,10 +1,12 @@ /** - * Gemini API with Multi-Tier Fallback - * Tries: Gemini → OpenRouter → OpenCode + * AI API Fallback System + * Tries: Ollama (local) → Gemini → OpenRouter → OpenCode */ const fetch = require('node-fetch'); +const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434'; +const OLLAMA_MODEL = process.env.OLLAMA_MODEL || 'deepseek-v3.2:cloud'; const GEMINI_API_KEY = process.env.GOOGLE_API_KEY; const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY; const OPENROUTER_BASE_URL = process.env.OPENROUTER_BASE_URL || 'https://openrouter.ai/api/v1'; @@ -14,10 +16,36 @@ const OPENCODE_BASE_URL = process.env.OPENCODE_BASE_URL || 'https://api.opencode async function generateWithFallback(prompt, options = {}) { console.log('🤖 Generating content...'); - // Tier 1: Try Gemini + // Tier 1: Try Ollama (local, free) + try { + console.log(`📍 Tier 1: Attempting Ollama (${OLLAMA_MODEL})...`); + const response = await fetch(`${OLLAMA_URL}/api/generate`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + timeout: 30000, + body: JSON.stringify({ + model: OLLAMA_MODEL, + prompt: prompt, + stream: false, + temperature: options.temperature || 0.7 + }) + }); + + if (response.ok) { + const data = await response.json(); + console.log('✅ Ollama success'); + return { success: true, provider: 'ollama', data }; + } + + console.warn(`⚠️ Ollama error: ${response.status}, trying next...`); + } catch (err) { + console.warn(`Ollama failed: ${err.message}`); + } + + // Tier 2: Try Gemini if (GEMINI_API_KEY) { try { - console.log('📍 Tier 1: Attempting Gemini API...'); + console.log('📍 Tier 2: Attempting Gemini API...'); const response = await fetch( `https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent?key=${GEMINI_API_KEY}`, { @@ -37,7 +65,7 @@ async function generateWithFallback(prompt, options = {}) { } if (response.status === 429 || response.status === 403) { - console.warn('⚠️ Gemini quota exceeded, trying next fallback...'); + console.warn('⚠️ Gemini quota exceeded, trying next...'); } else { throw new Error(`Gemini error: ${response.status}`); } @@ -46,10 +74,10 @@ async function generateWithFallback(prompt, options = {}) { } } - // Tier 2: Fallback to OpenRouter (billigare, mer flexibel) + // Tier 3: Fallback to OpenRouter if (OPENROUTER_API_KEY) { try { - console.log('📍 Tier 2: Attempting OpenRouter API...'); + console.log('📍 Tier 3: Attempting OpenRouter API...'); const response = await fetch(`${OPENROUTER_BASE_URL}/chat/completions`, { method: 'POST', headers: { @@ -71,16 +99,16 @@ async function generateWithFallback(prompt, options = {}) { return { success: true, provider: 'openrouter', data }; } - console.warn(`OpenRouter error: ${response.status}, trying next fallback...`); + console.warn(`OpenRouter error: ${response.status}, trying next...`); } catch (err) { console.warn(`OpenRouter failed: ${err.message}`); } } - // Tier 3: Fallback to OpenCode (sista försöket) + // Tier 4: Final fallback to OpenCode if (OPENCODE_API_KEY) { try { - console.log('📍 Tier 3: Attempting OpenCode API...'); + console.log('📍 Tier 4: Attempting OpenCode API...'); const response = await fetch(`${OPENCODE_BASE_URL}/chat/completions`, { method: 'POST', headers: { @@ -107,12 +135,13 @@ async function generateWithFallback(prompt, options = {}) { } } - throw new Error('All generation APIs failed (Gemini → OpenRouter → OpenCode)'); + throw new Error('All generation APIs failed (Ollama → Gemini → OpenRouter → OpenCode)'); } module.exports = { generateWithFallback, getAvailableProviders: () => ({ + ollama: true, // Always available locally gemini: !!GEMINI_API_KEY, openrouter: !!OPENROUTER_API_KEY, opencode: !!OPENCODE_API_KEY