This commit is contained in:
kikootwo
2026-03-02 17:05:28 -05:00
6 changed files with 125 additions and 11 deletions
+69 -1
View File
@@ -547,7 +547,7 @@ export async function buildAIPrompt(
/**
* Call AI API to get recommendations
* @param provider - 'openai' | 'claude'
* @param provider - 'openai' | 'claude' | 'gemini' | 'custom'
* @param model - Model ID
* @param encryptedApiKey - Encrypted API key
* @param prompt - JSON prompt string
@@ -691,6 +691,74 @@ export async function callAI(
logger.debug('Claude cleaned response:', { cleanedContent });
return JSON.parse(cleanedContent);
} else if (provider === 'gemini') {
const requestBody = {
systemInstruction: {
parts: [{ text: systemMessage }],
},
contents: [
{
parts: [{ text: prompt }],
},
],
generationConfig: {
responseMimeType: "application/json",
responseSchema: {
type: "OBJECT",
properties: {
recommendations: {
type: "ARRAY",
items: {
type: "OBJECT",
properties: {
title: { type: "STRING" },
author: { type: "STRING" },
reason: { type: "STRING" },
},
required: ["title", "author", "reason"],
},
},
},
required: ["recommendations"],
},
},
};
logger.debug('Gemini request body:', { requestBody });
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-goog-api-key': apiKey,
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
const errorText = await response.text();
logger.error('Gemini API error', { status: response.status, error: errorText });
throw new Error(`Gemini API error: ${response.status} ${errorText}`);
}
const data = await response.json();
const content = data.candidates?.[0]?.content?.parts?.[0]?.text;
if (!content) {
throw new Error('Invalid response format from Gemini API');
}
logger.debug('Gemini raw response:', { content });
// Clean potential markdown wrapping
const cleanedContent = content
.replace(/^```(?:json)?\s*/i, '')
.replace(/\s*```$/i, '')
.trim();
logger.debug('Gemini cleaned response:', { cleanedContent });
return JSON.parse(cleanedContent);
} else if (provider === 'custom') {
if (!baseUrl) {
throw new Error('Base URL is required for custom provider');