@sconedev/ai_toolkit
Version:
Simplify AI integration in web apps with local and offline model support
102 lines (101 loc) • 4.68 kB
JavaScript
import { GoogleGenerativeAI } from "@google/generative-ai";
export class GeminiProvider {
constructor(apiKey, model) {
if (!apiKey) {
throw new Error('API key is required for Gemini provider');
}
this.genAI = new GoogleGenerativeAI(apiKey);
this.defaultModel = model || 'gemini-1.5-flash';
}
async chat(messages, options) {
try {
// Ensure we have messages
if (!messages || messages.length === 0) {
throw new Error('No messages provided to Gemini chat');
}
console.log(`Using Gemini model: ${options?.model || this.defaultModel}`);
// Extract system message if present as first message
let systemPrompt;
let chatMessages = [...messages];
if (messages[0]?.role === 'system') {
systemPrompt = messages[0].content;
chatMessages = messages.slice(1);
}
// Ensure we have at least one user message
if (chatMessages.length === 0 || chatMessages[chatMessages.length - 1].role !== 'user') {
throw new Error('The last message must be from the user for Gemini');
}
// Prepare conversation history
const history = chatMessages.slice(0, -1).map(m => ({
role: m.role === 'user' ? 'user' : 'model',
parts: [{ text: m.content }]
}));
// Get the last user message
const lastMessage = chatMessages[chatMessages.length - 1];
// Configure generation parameters
const generationConfig = {
temperature: options?.temperature || 0.7,
topP: options?.topP || 0.95,
topK: options?.topK || 40,
maxOutputTokens: options?.maxTokens || 1024,
...options?.generationConfig
};
// Initialize the model with proper configuration
const model = this.genAI.getGenerativeModel({
model: options?.model || this.defaultModel,
// systemInstruction: systemPrompt, // Removed as it is not a valid property
generationConfig
});
// Start chat session with history
console.log('Starting Gemini chat with history length:', history.length);
const chat = model.startChat({
history,
generationConfig
});
// Send the message and get response
console.log('Sending message to Gemini:', lastMessage.content.substring(0, 100) + '...');
const result = await chat.sendMessage(lastMessage.content);
if (!result || !result.response) {
throw new Error('Empty response from Gemini');
}
const responseText = result.response.text();
console.log('Received response from Gemini:', responseText.substring(0, 100) + '...');
return responseText;
}
catch (error) {
// Enhanced error handling
console.error('Gemini API error:', error);
if (error instanceof Error) {
// Check for specific error types
if (error.message.includes('API key')) {
throw new Error('Invalid Gemini API key or authentication error');
}
else if (error.message.includes('quota')) {
throw new Error('Gemini API quota exceeded');
}
else if (error.message.includes('blocked') || error.message.includes('safety')) {
throw new Error('Content blocked by Gemini safety filters');
}
throw new Error(`Gemini error: ${error.message}`);
}
throw new Error('Unknown error occurred with Gemini provider');
}
}
async generateImage(description, options) {
try {
const model = this.genAI.getGenerativeModel({ model: "gemini-pro-vision" });
// Check if the model supports image generation
const result = await model.generateContent([description]);
const response = await result.response;
const text = response.text();
if (!text) {
throw new Error('Empty response from Gemini image description');
}
return text;
}
catch (error) {
console.error('Gemini image generation error:', error);
throw new Error('Gemini does not support direct image generation. Use text instructions instead.');
}
}
}