UNPKG

@r-huijts/ethics-vibe-check

Version:

🛡️ Make AI interrupt itself and challenge your thinking. Turns Claude into a philosophical sparring partner who actively contradicts comfortable conversations and challenges confirmation bias.

101 lines (100 loc) 5.56 kB
import { GoogleGenerativeAI } from '@google/generative-ai'; let genAI = null; export function initializeGemini(apiKey) { if (!apiKey) { throw new Error('Gemini API key is required'); } if (apiKey === 'your_actual_gemini_api_key_here' || apiKey === 'test_key') { throw new Error('Please set a valid Gemini API key in your .env file'); } genAI = new GoogleGenerativeAI(apiKey); } export function getGeminiModel() { if (!genAI) { throw new Error('Gemini not initialized. Call initializeGemini first.'); } // Use the latest gemini-2.0-flash model as shown in Google AI Studio return genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }); } /** * Clean Gemini response by removing markdown code block formatting * Gemini 2.0-flash often wraps JSON responses in ```json``` blocks */ export function cleanGeminiJsonResponse(response) { let cleanResponse = response.trim(); // Remove markdown code block formatting if present if (cleanResponse.startsWith('```json')) { cleanResponse = cleanResponse.replace(/^```json\s*/, '').replace(/```\s*$/, ''); } else if (cleanResponse.startsWith('```')) { cleanResponse = cleanResponse.replace(/^```\s*/, '').replace(/```\s*$/, ''); } return cleanResponse.trim(); } export async function generateEthicsResponse(prompt) { const model = getGeminiModel(); // Simple token estimation for monitoring (rough approximation) const estimatedTokens = Math.ceil(prompt.length / 4); // ~4 chars per token average console.error(`📊 Estimated prompt tokens: ${estimatedTokens}`); try { console.error('Making Gemini API call with gemini-2.0-flash...'); const result = await model.generateContent(prompt); const response = await result.response; const text = response.text(); // Log response length for monitoring const responseTokens = Math.ceil(text.length / 4); console.error(`📊 Estimated response tokens: ${responseTokens}, Total: ~${estimatedTokens + responseTokens}`); console.error('Gemini API call successful'); return text; } catch (error) { console.error('Gemini API error details:', error); // Handle specific error types if (error instanceof Error) { const errorMessage = error.message; // Quota exceeded errors (429) if (errorMessage.includes('429') || errorMessage.includes('Too Many Requests') || errorMessage.includes('quota')) { if (errorMessage.includes('free_tier')) { throw new Error('Gemini API free tier quota exceeded. Please wait for quota reset (daily) or upgrade to a paid plan at https://ai.google.dev/pricing'); } throw new Error('Gemini API quota exceeded. Please wait a few minutes and try again, or check your billing at https://console.cloud.google.com/billing'); } // Authentication errors (401/403) if (errorMessage.includes('API_KEY_INVALID') || errorMessage.includes('401') || errorMessage.includes('Unauthorized')) { throw new Error('Invalid Gemini API key. Please check your API key at https://aistudio.google.com/app/apikey'); } if (errorMessage.includes('PERMISSION_DENIED') || errorMessage.includes('403') || errorMessage.includes('Forbidden')) { throw new Error('Permission denied. Please check your Gemini API key permissions and ensure the Generative Language API is enabled.'); } // Rate limiting (different from quota) if (errorMessage.includes('rate limit') || errorMessage.includes('RATE_LIMIT_EXCEEDED')) { throw new Error('Gemini API rate limit exceeded. Please wait a moment and try again.'); } // Service unavailable if (errorMessage.includes('503') || errorMessage.includes('Service Unavailable')) { throw new Error('Gemini API service temporarily unavailable. Please try again in a few minutes.'); } // Network/timeout errors if (errorMessage.includes('timeout') || errorMessage.includes('TIMEOUT')) { throw new Error('Gemini API request timed out. Please try again.'); } if (errorMessage.includes('network') || errorMessage.includes('NETWORK_ERROR')) { throw new Error('Network error connecting to Gemini API. Please check your internet connection.'); } // Model-specific errors if (errorMessage.includes('model not found') || errorMessage.includes('MODEL_NOT_FOUND')) { throw new Error('Gemini model not found. The gemini-2.0-flash model may not be available in your region.'); } // Content filtering if (errorMessage.includes('SAFETY') || errorMessage.includes('content filter')) { throw new Error('Content was blocked by Gemini safety filters. Please rephrase your request.'); } // Generic API errors if (errorMessage.includes('400') || errorMessage.includes('Bad Request')) { throw new Error('Invalid request to Gemini API. Please check the input parameters.'); } } // Fallback for unknown errors throw new Error(`Gemini API call failed: ${error instanceof Error ? error.message : 'Unknown error'}. Please try again or check your API configuration.`); } }