File size: 4,311 Bytes
2accaeb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

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<Chat> {
  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
};