UNPKG

game-analysis-types

Version:

Common TypeScript types and utilities for game analysis tools.

177 lines 8.78 kB
export class GeminiModelStrategy { config; constructor(config) { this.config = config; } getConfig() { return this.config; } /** * Generate text using Gemini API (fulfills AIModelStrategy interface) * @param request - The AI request with prompt and options * @returns The AI response */ async generate(request) { const apiKey = this.config.apiKey; // Use the specific model endpoint from config if provided, else default const apiEndpoint = this.config.apiEndpoint || `https://generativelanguage.googleapis.com/v1beta/models/${this.config.model}:generateContent?key=${apiKey}`; const headers = { 'Content-Type': 'application/json', // Authorization header might not be needed if key is in URL // 'Authorization': `Bearer ${apiKey}` }; const body = { contents: [{ parts: [{ text: request.prompt }] }], generationConfig: { // Ensure maxOutputTokens is an integer maxOutputTokens: Math.floor(request.options?.maxTokens || this.config.maxTokens || 8192), // Added default temperature: request.options?.temperature || this.config.temperature || 0.7 // Added default } }; try { const response = await fetch(apiEndpoint, { method: 'POST', headers, body: JSON.stringify(body) }); const responseBody = await response.text(); // Read body first for better error reporting if (!response.ok) { console.error('Gemini API Response Error Body:', responseBody); throw new Error(`Gemini API error: ${response.status} ${response.statusText} - ${responseBody}`); } const result = JSON.parse(responseBody); // Gemini returns content in a somewhat different format; extract the text const content = result.candidates?.[0]?.content?.parts?.[0]?.text || ''; // Gemini API (v1beta) may not provide exact token usage in the response // We might need to estimate or use a library if precise token count is needed const inputTokens = 0; // Placeholder const outputTokens = 0; // Placeholder const totalTokens = 0; // Placeholder return { content, model: this.config.model, // Use the configured model name tokenUsage: { input: inputTokens, output: outputTokens, total: totalTokens }, // Calculate cost based on estimated tokens or characters if API doesn't provide cost: this.calculateCost(inputTokens, outputTokens), // Will be 0 with current placeholders metadata: { model_version: result.candidates?.[0]?.model || this.config.model, finishing_reason: result.candidates?.[0]?.finishReason || 'stop', // Add other relevant metadata if available raw_response: result // Include raw response for potential debugging } }; } catch (error) { console.error('Gemini API generate error:', error); throw new Error(`Failed to generate with Gemini: ${error instanceof Error ? error.message : String(error)}`); } } async analyze(request) { const apiKey = this.config.apiKey; // Use the specific model endpoint from config if provided, else default const apiEndpoint = this.config.apiEndpoint || `https://generativelanguage.googleapis.com/v1beta/models/${this.config.model}:generateContent?key=${apiKey}`; const headers = { 'Content-Type': 'application/json', // Authorization header might not be needed if key is in URL // 'Authorization': `Bearer ${apiKey}` }; const body = { contents: [{ parts: [{ text: request.prompt }] }], generationConfig: { // Ensure maxOutputTokens is an integer maxOutputTokens: Math.floor(request.options?.maxTokens || this.config.maxTokens || 8192), // Added default temperature: request.options?.temperature || this.config.temperature || 0.7 // Added default } }; try { const response = await fetch(apiEndpoint, { method: 'POST', headers, body: JSON.stringify(body) }); const responseBody = await response.text(); // Read body first for better error reporting if (!response.ok) { console.error('Gemini API Response Error Body:', responseBody); throw new Error(`Gemini API error: ${response.status} ${response.statusText} - ${responseBody}`); } const result = JSON.parse(responseBody); // Gemini returns content in a somewhat different format; extract the text const content = result.candidates?.[0]?.content?.parts?.[0]?.text || ''; // Gemini API (v1beta) may not provide exact token usage in the response // We might need to estimate or use a library if precise token count is needed const inputTokens = 0; // Placeholder const outputTokens = 0; // Placeholder const totalTokens = 0; // Placeholder return { content, model: this.config.model, // Use the configured model name tokenUsage: { input: inputTokens, output: outputTokens, total: totalTokens }, // Calculate cost based on estimated tokens or characters if API doesn't provide cost: this.calculateCost(inputTokens, outputTokens), // Will be 0 with current placeholders metadata: { model_version: result.candidates?.[0]?.model || this.config.model, finishing_reason: result.candidates?.[0]?.finishReason || 'stop' // Add other relevant metadata if available } }; } catch (error) { console.error('Gemini API error:', error); throw new Error(`Failed to analyze with Gemini: ${error instanceof Error ? error.message : String(error)}`); } } async isAvailable() { // Basic check: is API key configured? if (!this.config.apiKey) { console.warn('Gemini API key not configured.'); return false; } // More robust check: Try listing models (requires API key) // Note: Endpoint might vary based on Gemini API version const listModelsEndpoint = `https://generativelanguage.googleapis.com/v1beta/models?key=${this.config.apiKey}`; try { const response = await fetch(listModelsEndpoint, { method: 'GET' }); if (!response.ok) { const errorBody = await response.text(); console.warn(`Gemini availability check failed: ${response.status} ${response.statusText}`, errorBody); return false; } // Optionally check if the specific configured model is in the list // const data = await response.json(); // const modelExists = data.models?.some(m => m.name.includes(this.config.model)); // return modelExists; return true; // If the list models call succeeds, assume basic availability } catch (error) { console.error('Gemini availability check fetch error:', error); return false; } } /** * Calculate the cost of the API call based on token usage * @param inputTokens - Number of input tokens * @param outputTokens - Number of output tokens * @returns The cost of the API call in USD */ calculateCost(inputTokens, outputTokens) { // Use costs from config, defaulting to 0 if not provided or if tokens are 0 if (inputTokens === 0 && outputTokens === 0) return 0; const inputCostPer1K = this.config.inputCostPer1K || 0; const outputCostPer1K = this.config.outputCostPer1K || 0; // Handle potential estimation if API doesn't provide counts // For now, assumes counts are provided or are 0 const inputCost = (inputTokens / 1000) * inputCostPer1K; const outputCost = (outputTokens / 1000) * outputCostPer1K; return inputCost + outputCost; } } //# sourceMappingURL=gemini.js.map