import { GoogleGenAI, Chat, HarmCategory, HarmBlockThreshold, GenerateContentResponse, Part, Content } from "@google/genai"; import { MODEL_NAME } from '../constants'; // Updated import, REEL_BOT_SYSTEM_INSTRUCTION removed as not directly used here import type { GroundingChunk, UploadedFile } from '../types'; const API_KEY = process.env.API_KEY; if (!API_KEY) { console.error("API_KEY for Gemini is not set. Please set the API_KEY environment variable."); } const ai = new GoogleGenAI({ apiKey: API_KEY! }); const generationConfigValues = { temperature: 0.7, topK: 1, topP: 1, maxOutputTokens: 4096, }; const safetySettingsList = [ { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE }, { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE }, { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE }, { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE }, ]; async function createChatSessionWithHistory(systemInstructionText: string, history: Content[]): Promise { const filteredHistory = history.filter(content => content.role !== "system"); return ai.chats.create({ model: MODEL_NAME, history: filteredHistory, config: { systemInstruction: systemInstructionText, temperature: generationConfigValues.temperature, topK: generationConfigValues.topK, topP: generationConfigValues.topP, maxOutputTokens: generationConfigValues.maxOutputTokens, safetySettings: safetySettingsList, tools: [{ googleSearch: {} }], // thinkingConfig: { thinkingBudget: 0 }, // Kept commented: allow default thinking for complex prompt } }); } async function* sendMessageStream( chat: Chat, messageText: string, imageFile?: UploadedFile ): AsyncGenerator<{ text: string; groundingChunks?: GroundingChunk[] }, void, undefined> { try { const parts: Part[] = []; const userProvidedText = messageText.trim(); if (imageFile) { if (imageFile.dataUrl && imageFile.type.startsWith('image/')) { const base64Data = imageFile.dataUrl.split(',')[1]; if (base64Data) { if (!userProvidedText) { parts.push({ text: "Describe this image" }); } else { parts.push({ text: userProvidedText }); } parts.push({ inlineData: { mimeType: imageFile.type, data: base64Data, }, }); } } else { const docInfo = `(User uploaded a document: ${imageFile.name})`; if (userProvidedText) { parts.push({ text: `${userProvidedText}\n${docInfo}` }); } else { parts.push({ text: docInfo }); } } } else { if (userProvidedText) { parts.push({ text: userProvidedText }); } } if (parts.length === 0) { parts.push({ text: " " }); } const result = await chat.sendMessageStream({ message: parts }); for await (const chunk of result) { const text = chunk.text; const groundingMetadata = chunk.candidates?.[0]?.groundingMetadata; let groundingChunks: GroundingChunk[] | undefined = undefined; if (groundingMetadata?.groundingChunks && groundingMetadata.groundingChunks.length > 0) { groundingChunks = groundingMetadata.groundingChunks .filter(gc => gc.web?.uri && gc.web?.title) .map(gc => ({ web: { uri: gc.web!.uri, title: gc.web!.title } })); } yield { text, groundingChunks }; } } catch (error) { console.error("Error in sendMessageStream:", error); if (error instanceof Error) { yield { text: `\n\n[AI Error: ${error.message}]` }; } else { yield { text: `\n\n[An unexpected AI error occurred]` }; } throw error; } } // generateChatName function removed export const geminiService = { createChatSessionWithHistory, sendMessageStream, // generateChatName removed from exports };