diff --git a/backend/MCP_Execution_Server/src/config.ts b/backend/MCP_Execution_Server/src/config.ts
index 9624a1b..c9c3431 100644
--- a/backend/MCP_Execution_Server/src/config.ts
+++ b/backend/MCP_Execution_Server/src/config.ts
@@ -10,11 +10,11 @@ export const config = {
apiKey: process.env.NEYNAR_API_KEY ?? "0x",
signerUuid: process.env.NEYNAR_SIGNER_UUID ?? "0x",
},
- gemini:{
- apiKey: process.env.GEMINI_API_KEY ?? "0x",
+ gemini: {
+ apiKey: process.env.GEMINI_API_KEY ?? "",
},
openai: {
- apiKey: process.env.OPENAI_API_KEY,
+ apiKey: process.env.OPENAI_API_KEY ?? "",
},
supabase: {
SUPABASE_URL: process.env.SUPABASE_URL ?? "",
diff --git a/backend/MCP_Execution_Server/src/index.ts b/backend/MCP_Execution_Server/src/index.ts
index b8a7d66..2d3d920 100644
--- a/backend/MCP_Execution_Server/src/index.ts
+++ b/backend/MCP_Execution_Server/src/index.ts
@@ -24,8 +24,8 @@ async function main() {
config.reclaim.appId,
config.reclaim.appSecret,
);
- const geminiai = new GeminiAiService(config.gemini.apiKey as string);
- const ai = new AIService(config.openai.apiKey as string);
+ const geminiai = new GeminiAiService(config.gemini.apiKey);
+ const ai = new AIService(config.openai.apiKey);
const avs = new AVSService(
config.network.rpcBaseAddress,
config.network.privateKey,
@@ -41,7 +41,7 @@ async function main() {
avs,
ipfs,
);
- const user = new UserService(neynar, ai, db);
+ const user = new UserService(neynar, ai, db, geminiai);
// Initialize services
const services = {
diff --git a/backend/MCP_Execution_Server/src/services/gemini_ai.service.ts b/backend/MCP_Execution_Server/src/services/gemini_ai.service.ts
index 0b80a88..007f333 100644
--- a/backend/MCP_Execution_Server/src/services/gemini_ai.service.ts
+++ b/backend/MCP_Execution_Server/src/services/gemini_ai.service.ts
@@ -1,4 +1,4 @@
-import { GoogleGenAI } from "@google/genai";
+import { GoogleGenAI, Type } from "@google/genai";
export class GeminiAiService {
private ai: GoogleGenAI;
@@ -9,7 +9,7 @@ export class GeminiAiService {
this.ai = new GoogleGenAI({
apiKey: this.geminiApiKey,
});
- this.geminiModel = "gemini-2.5-flash";
+ this.geminiModel = "gemini-2.5-flash-preview-04-17";
this.embeddingModel = "embedding-001";
}
@@ -42,10 +42,17 @@ Bad output:
`;
try {
+ /**
+ * TODO: Fix this
+ *
+ * Received error:
+ * ClientError: got status: 404 Not Found. {"error":{"code":404,"message":"models/gemini-2.5-flash is not found for API version v1beta, or is not supported for generateContent. Call ListModels to see the list of available models and their supported methods.","status":"NOT_FOUND"}}
+ */
const result = await this.ai.models.generateContent({
model: this.geminiModel,
contents: prompt,
});
+
return result.text;
} catch (err: any) {
console.error("summarizeUserContext error", err);
@@ -151,8 +158,7 @@ ${formattedTrendingFeeds}
7. AVOID talking about airdrops and giveaways.
-
-You MUST respond with ONLY a valid JSON object containing exactly these two fields:
+
- replyText: A string with the message "You should connect with [author_username], who said: '[cast_text]'" - Max 60-70 words, 320 characters.
- link: A string with the URL "https://warpcast.com/[author_username]/[cast_hash]" - this should MATCH the cast you selected and not a fabricated/random one.
@@ -169,30 +175,36 @@ If and only if you find no relevant casts, respond with this exact format:
"replyText": "No relevant trending casts found in the provided data.",
"link": ""
}
-
-
-
-Your response should be a valid JSON object with no additional text or explanation.
-
+
`;
try {
const result = await this.ai.models.generateContent({
model: this.geminiModel,
contents: prompt,
+ config: {
+ responseMimeType: "application/json",
+ responseSchema: {
+ type: Type.OBJECT,
+ properties: {
+ replyText: { type: Type.STRING },
+ link: { type: Type.STRING },
+ },
+ required: ["replyText", "link"],
+ },
+ },
});
- const content = result.text?.trim();
-
+ const content = result.text;
try {
return content
? JSON.parse(content)
: {
- replyText:
- "No relevant trending casts found in the provided data.",
- link: "",
- };
+ replyText:
+ "No relevant trending casts found in the provided data.",
+ link: "",
+ };
} catch (jsonErr) {
- console.warn("Response was not valid JSON:", content);
+ console.warn("Response was not valid JSON Gemini:", content);
return { error: "Invalid JSON format in AI response", raw: content };
}
} catch (err: any) {
diff --git a/backend/MCP_Execution_Server/src/services/user.service.ts b/backend/MCP_Execution_Server/src/services/user.service.ts
index 99224aa..fa5b492 100644
--- a/backend/MCP_Execution_Server/src/services/user.service.ts
+++ b/backend/MCP_Execution_Server/src/services/user.service.ts
@@ -1,7 +1,7 @@
import type { NeynarService } from "./neynar.service.js";
import type { AIService } from "./ai.service.js";
import type { DBService } from "./db.service.js";
-import { GeminiAiService } from "./gemini_ai.service.js";
+import type { GeminiAiService } from "./gemini_ai.service.js";
export enum FID_STATUS {
NOT_EXIST = "NOT_EXIST",
@@ -23,8 +23,10 @@ export class UserService {
try {
if (this.geminiService) {
const summary = await this.geminiService.summarizeUserContext(userData);
+ console.log("Summary generated by Gemini");
if (summary) return summary;
}
+ console.log("Summary generated by AIService");
return await this.aiService.summarizeUserContext(userData);
} catch (e) {
console.warn("Fallback to AIService for summarizeUserContext");
@@ -32,19 +34,6 @@ export class UserService {
}
}
- private async generateEmbeddingsSafe(text: string): Promise {
- try {
- if (this.geminiService) {
- const embeddings = await this.geminiService.generateEmbeddings(text);
- if (embeddings) return embeddings;
- }
- return await this.aiService.generateEmbeddings(text);
- } catch (e) {
- console.warn("Fallback to AIService for generateEmbeddings");
- return await this.aiService.generateEmbeddings(text);
- }
- }
-
private async generateReplyForCastSafe(input: {
userCast: string;
castSummary: string;
@@ -158,7 +147,7 @@ export class UserService {
const userData = await this.neynarService.aggregateUserData(fid);
const summary = await this.summarizeUserContextSafe(userData);
if (!summary) throw new Error("Summary generation failed");
- const embeddings = await this.generateEmbeddingsSafe(summary);
+ const embeddings = await this.aiService.generateEmbeddings(summary);
if (!embeddings) throw new Error("Embedding generation failed");
const { success } = await this.db.registerAndSubscribeFID(
@@ -259,7 +248,8 @@ export class UserService {
// Step 2: Generate embeddings for the received cast
const castSummary = await this.findMeaningFromTextSafe(cast.text);
- const castEmbeddings = await this.generateEmbeddingsSafe(castSummary);
+ const castEmbeddings =
+ await this.aiService.generateEmbeddings(castSummary);
if (!castEmbeddings) {
throw new Error("Embedding generation failed for the cast text");
}