|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
|
import { Injectable, OnModuleInit, Logger } from '@nestjs/common';
|
|
|
|
|
import { ConfigService } from '@nestjs/config';
|
|
|
|
|
import { GoogleGenAI } from '@google/genai';
|
|
|
|
|
import { Injectable, OnModuleInit, Logger } from "@nestjs/common";
|
|
|
|
|
import { ConfigService } from "@nestjs/config";
|
|
|
|
|
import { GoogleGenAI } from "@google/genai";
|
|
|
|
|
|
|
|
|
|
export interface GeminiGenerateOptions {
|
|
|
|
|
model?: string;
|
|
|
|
@@ -10,7 +10,7 @@ export interface GeminiGenerateOptions {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface GeminiChatMessage {
|
|
|
|
|
role: 'user' | 'model';
|
|
|
|
|
role: "user" | "model";
|
|
|
|
|
content: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -48,34 +48,34 @@ export class GeminiService implements OnModuleInit {
|
|
|
|
|
private defaultModel: string;
|
|
|
|
|
|
|
|
|
|
constructor(private readonly configService: ConfigService) {
|
|
|
|
|
this.isEnabled = this.configService.get<boolean>('gemini.enabled', false);
|
|
|
|
|
this.isEnabled = this.configService.get<boolean>("gemini.enabled", false);
|
|
|
|
|
this.defaultModel = this.configService.get<string>(
|
|
|
|
|
'gemini.defaultModel',
|
|
|
|
|
'gemini-2.5-flash',
|
|
|
|
|
"gemini.defaultModel",
|
|
|
|
|
"gemini-2.5-flash",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onModuleInit() {
|
|
|
|
|
if (!this.isEnabled) {
|
|
|
|
|
this.logger.log(
|
|
|
|
|
'Gemini AI is disabled. Set ENABLE_GEMINI=true to enable.',
|
|
|
|
|
"Gemini AI is disabled. Set ENABLE_GEMINI=true to enable.",
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const apiKey = this.configService.get<string>('gemini.apiKey');
|
|
|
|
|
const apiKey = this.configService.get<string>("gemini.apiKey");
|
|
|
|
|
if (!apiKey) {
|
|
|
|
|
this.logger.warn(
|
|
|
|
|
'GOOGLE_API_KEY is not set. Gemini features will not work.',
|
|
|
|
|
"GOOGLE_API_KEY is not set. Gemini features will not work.",
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
this.client = new GoogleGenAI({ apiKey });
|
|
|
|
|
this.logger.log('✅ Gemini AI initialized successfully');
|
|
|
|
|
this.logger.log("✅ Gemini AI initialized successfully");
|
|
|
|
|
} catch (error) {
|
|
|
|
|
this.logger.error('Failed to initialize Gemini AI', error);
|
|
|
|
|
this.logger.error("Failed to initialize Gemini AI", error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -98,7 +98,7 @@ export class GeminiService implements OnModuleInit {
|
|
|
|
|
options: GeminiGenerateOptions = {},
|
|
|
|
|
): Promise<{ text: string; usage?: any }> {
|
|
|
|
|
if (!this.isAvailable()) {
|
|
|
|
|
throw new Error('Gemini AI is not available. Check your configuration.');
|
|
|
|
|
throw new Error("Gemini AI is not available. Check your configuration.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const model = options.model || this.defaultModel;
|
|
|
|
@@ -109,17 +109,17 @@ export class GeminiService implements OnModuleInit {
|
|
|
|
|
// Add system prompt if provided
|
|
|
|
|
if (options.systemPrompt) {
|
|
|
|
|
contents.push({
|
|
|
|
|
role: 'user',
|
|
|
|
|
role: "user",
|
|
|
|
|
parts: [{ text: options.systemPrompt }],
|
|
|
|
|
});
|
|
|
|
|
contents.push({
|
|
|
|
|
role: 'model',
|
|
|
|
|
parts: [{ text: 'Understood. I will follow these instructions.' }],
|
|
|
|
|
role: "model",
|
|
|
|
|
parts: [{ text: "Understood. I will follow these instructions." }],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
contents.push({
|
|
|
|
|
role: 'user',
|
|
|
|
|
role: "user",
|
|
|
|
|
parts: [{ text: prompt }],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
@@ -133,11 +133,11 @@ export class GeminiService implements OnModuleInit {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
text: (response.text || '').trim(),
|
|
|
|
|
text: (response.text || "").trim(),
|
|
|
|
|
usage: response.usageMetadata,
|
|
|
|
|
};
|
|
|
|
|
} catch (error) {
|
|
|
|
|
this.logger.error('Gemini generation failed', error);
|
|
|
|
|
this.logger.error("Gemini generation failed", error);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -154,7 +154,7 @@ export class GeminiService implements OnModuleInit {
|
|
|
|
|
options: GeminiGenerateOptions = {},
|
|
|
|
|
): Promise<{ text: string; usage?: any }> {
|
|
|
|
|
if (!this.isAvailable()) {
|
|
|
|
|
throw new Error('Gemini AI is not available. Check your configuration.');
|
|
|
|
|
throw new Error("Gemini AI is not available. Check your configuration.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const model = options.model || this.defaultModel;
|
|
|
|
@@ -169,12 +169,12 @@ export class GeminiService implements OnModuleInit {
|
|
|
|
|
if (options.systemPrompt) {
|
|
|
|
|
contents.unshift(
|
|
|
|
|
{
|
|
|
|
|
role: 'user',
|
|
|
|
|
role: "user",
|
|
|
|
|
parts: [{ text: options.systemPrompt }],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
role: 'model',
|
|
|
|
|
parts: [{ text: 'Understood. I will follow these instructions.' }],
|
|
|
|
|
role: "model",
|
|
|
|
|
parts: [{ text: "Understood. I will follow these instructions." }],
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
@@ -189,11 +189,11 @@ export class GeminiService implements OnModuleInit {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
text: (response.text || '').trim(),
|
|
|
|
|
text: (response.text || "").trim(),
|
|
|
|
|
usage: response.usageMetadata,
|
|
|
|
|
};
|
|
|
|
|
} catch (error) {
|
|
|
|
|
this.logger.error('Gemini chat failed', error);
|
|
|
|
|
this.logger.error("Gemini chat failed", error);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -233,8 +233,8 @@ IMPORTANT: Only output valid JSON, no markdown code blocks or other text.`;
|
|
|
|
|
const data = JSON.parse(jsonStr) as T;
|
|
|
|
|
return { data, usage: response.usage };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
this.logger.error('Failed to parse JSON response', error);
|
|
|
|
|
throw new Error('Failed to parse AI response as JSON');
|
|
|
|
|
this.logger.error("Failed to parse JSON response", error);
|
|
|
|
|
throw new Error("Failed to parse AI response as JSON");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|