Skip to content

Commit

Permalink
Merge pull request #530 from ai16z/fix/telegram
Browse files Browse the repository at this point in the history
fix: Fix/telegram
  • Loading branch information
ponderingdemocritus authored Nov 23, 2024
2 parents 4cfe830 + 21a8c96 commit 5565830
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 119 deletions.
2 changes: 1 addition & 1 deletion packages/client-telegram/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const TelegramClientInterface: Client = {
return tg;
},
stop: async (_runtime: IAgentRuntime) => {
console.warn("Telegram client does not support stopping yet");
elizaLogger.warn("Telegram client does not support stopping yet");
},
};

Expand Down
71 changes: 37 additions & 34 deletions packages/client-telegram/src/messageManager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Message } from "@telegraf/types";
import { Context, Telegraf } from "telegraf";

import { composeContext } from "@ai16z/eliza";
import { composeContext, elizaLogger, ServiceType } from "@ai16z/eliza";
import { embeddingZeroVector } from "@ai16z/eliza";
import {
Content,
Expand All @@ -17,7 +17,6 @@ import { stringToUuid } from "@ai16z/eliza";

import { generateMessageResponse, generateShouldRespond } from "@ai16z/eliza";
import { messageCompletionFooter, shouldRespondFooter } from "@ai16z/eliza";
import { ImageDescriptionService } from "@ai16z/plugin-node";

const MAX_MESSAGE_LENGTH = 4096; // Telegram's max message length

Expand Down Expand Up @@ -137,57 +136,49 @@ Thread of Tweets You Are Replying To:
export class MessageManager {
public bot: Telegraf<Context>;
private runtime: IAgentRuntime;
private imageService: IImageDescriptionService;

constructor(bot: Telegraf<Context>, runtime: IAgentRuntime) {
this.bot = bot;
this.runtime = runtime;
this.imageService = ImageDescriptionService.getInstance();
}

// Process image messages and generate descriptions
private async processImage(
message: Message
): Promise<{ description: string } | null> {
// console.log(
// "πŸ–ΌοΈ Processing image message:",
// JSON.stringify(message, null, 2)
// );

try {
let imageUrl: string | null = null;

// Handle photo messages
if ("photo" in message && message.photo?.length > 0) {
const photo = message.photo[message.photo.length - 1];
const fileLink = await this.bot.telegram.getFileLink(
photo.file_id
);
imageUrl = fileLink.toString();
}
// Handle image documents
else if (
} else if (
"document" in message &&
message.document?.mime_type?.startsWith("image/")
) {
const doc = message.document;
const fileLink = await this.bot.telegram.getFileLink(
doc.file_id
message.document.file_id
);
imageUrl = fileLink.toString();
}

if (imageUrl) {
const imageDescriptionService =
this.runtime.getService<IImageDescriptionService>(
ServiceType.IMAGE_DESCRIPTION
);
const { title, description } =
await this.imageService.describeImage(imageUrl);
const fullDescription = `[Image: ${title}\n${description}]`;
return { description: fullDescription };
await imageDescriptionService.describeImage(imageUrl);
return { description: `[Image: ${title}\n${description}]` };
}
} catch (error) {
console.error("❌ Error processing image:", error);
}

return null; // No image found
return null;
}

// Decide if the bot should respond to the message
Expand All @@ -196,7 +187,6 @@ export class MessageManager {
state: State
): Promise<boolean> {
// Respond if bot is mentioned

if (
"text" in message &&
message.text?.includes(`@${this.bot.botInfo?.username}`)
Expand All @@ -209,7 +199,7 @@ export class MessageManager {
return true;
}

// Respond to images in group chats
// Don't respond to images in group chats
if (
"photo" in message ||
("document" in message &&
Expand Down Expand Up @@ -238,7 +228,7 @@ export class MessageManager {
return response === "RESPOND";
}

return false; // No criteria met
return false;
}

// Send long messages in chunks
Expand Down Expand Up @@ -291,7 +281,7 @@ export class MessageManager {
// Generate a response using AI
private async _generateResponse(
message: Memory,
state: State,
_state: State,
context: string
): Promise<Content> {
const { userId, roomId } = message;
Expand All @@ -306,9 +296,10 @@ export class MessageManager {
console.error("❌ No response from generateMessageResponse");
return null;
}

await this.runtime.databaseAdapter.log({
body: { message, context, response },
userId: userId,
userId,
roomId,
type: "response",
});
Expand Down Expand Up @@ -342,14 +333,23 @@ export class MessageManager {
try {
// Convert IDs to UUIDs
const userId = stringToUuid(ctx.from.id.toString()) as UUID;

// Get user name
const userName =
ctx.from.username || ctx.from.first_name || "Unknown User";

// Get chat ID
const chatId = stringToUuid(
ctx.chat?.id.toString() + "-" + this.runtime.agentId
) as UUID;

// Get agent ID
const agentId = this.runtime.agentId;

// Get room ID
const roomId = chatId;

// Ensure connection
await this.runtime.ensureConnection(
userId,
roomId,
Expand All @@ -358,6 +358,7 @@ export class MessageManager {
"telegram"
);

// Get message ID
const messageId = stringToUuid(
message.message_id.toString() + "-" + this.runtime.agentId
) as UUID;
Expand All @@ -382,17 +383,18 @@ export class MessageManager {
return; // Skip if no content
}

// Create content
const content: Content = {
text: fullText,
source: "telegram",
// inReplyTo:
// "reply_to_message" in message && message.reply_to_message
// ? stringToUuid(
// message.reply_to_message.message_id.toString() +
// "-" +
// this.runtime.agentId
// )
// : undefined,
inReplyTo:
"reply_to_message" in message && message.reply_to_message
? stringToUuid(
message.reply_to_message.message_id.toString() +
"-" +
this.runtime.agentId
)
: undefined,
};

// Create memory for the message
Expand All @@ -406,6 +408,7 @@ export class MessageManager {
embedding: embeddingZeroVector,
};

// Create memory
await this.runtime.messageManager.createMemory(memory);

// Update state with the new memory
Expand Down Expand Up @@ -498,8 +501,8 @@ export class MessageManager {

await this.runtime.evaluate(memory, state, shouldRespond);
} catch (error) {
console.error("❌ Error handling message:", error);
console.error("Error sending message:", error);
elizaLogger.error("❌ Error handling message:", error);
elizaLogger.error("Error sending message:", error);
}
}
}
138 changes: 65 additions & 73 deletions packages/client-telegram/src/telegramClient.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Context, Telegraf } from "telegraf";

import { IAgentRuntime } from "@ai16z/eliza";
import { IAgentRuntime, elizaLogger } from "@ai16z/eliza";
import { MessageManager } from "./messageManager.ts";
import { elizaLogger } from "@ai16z/eliza";

export class TelegramClient {
private bot: Telegraf<Context>;
Expand All @@ -14,94 +12,88 @@ export class TelegramClient {
this.runtime = runtime;
this.bot = new Telegraf(botToken);
this.messageManager = new MessageManager(this.bot, this.runtime);

elizaLogger.log("βœ… TelegramClient constructor completed");
}

public async start(): Promise<void> {
elizaLogger.log("πŸš€ Starting Telegram bot...");
try {
this.bot.launch({
dropPendingUpdates: true,
});
elizaLogger.log(
"✨ Telegram bot successfully launched and is running!"
);
await this.initializeBot();
this.setupMessageHandlers();
this.setupShutdownHandlers();
} catch (error) {
elizaLogger.error("❌ Failed to launch Telegram bot:", error);
throw error;
}
}

await this.bot.telegram.getMe().then((botInfo) => {
this.bot.botInfo = botInfo;
});
private async initializeBot(): Promise<void> {
this.bot.launch({ dropPendingUpdates: true });
elizaLogger.log(
"✨ Telegram bot successfully launched and is running!"
);

elizaLogger.success(`Bot username: @${this.bot.botInfo?.username}`);
const botInfo = await this.bot.telegram.getMe();
this.bot.botInfo = botInfo;
elizaLogger.success(`Bot username: @${botInfo.username}`);

this.messageManager.bot = this.bot;
this.messageManager.bot = this.bot;
}

// Include if you want to view message maanger bot info
// console.log(`Message Manager bot info: @${this.messageManager.bot}`);
private setupMessageHandlers(): void {
elizaLogger.log("Setting up message handler...");

elizaLogger.log("Setting up message handler...");
this.bot.on("message", async (ctx) => {
try {
await this.messageManager.handleMessage(ctx);
} catch (error) {
elizaLogger.error("❌ Error handling message:", error);
await ctx.reply(
"An error occurred while processing your message."
);
}
});

this.bot.on("message", async (ctx) => {
try {
// console.log("πŸ“₯ Received message:", ctx.message);
await this.messageManager.handleMessage(ctx);
} catch (error) {
elizaLogger.error("❌ Error handling message:", error);
await ctx.reply(
"An error occurred while processing your message."
);
}
});
this.bot.on("photo", (ctx) => {
elizaLogger.log(
"πŸ“Έ Received photo message with caption:",
ctx.message.caption
);
});

// Handle specific message types for better logging
this.bot.on("photo", (ctx) => {
elizaLogger.log(
"πŸ“Έ Received photo message with caption:",
ctx.message.caption
);
});
this.bot.on("document", (ctx) => {
elizaLogger.log(
"πŸ“Ž Received document message:",
ctx.message.document.file_name
);
});

this.bot.on("document", (ctx) => {
elizaLogger.log(
"πŸ“Ž Received document message:",
ctx.message.document.file_name
);
});
this.bot.catch((err, ctx) => {
elizaLogger.error(`❌ Telegram Error for ${ctx.updateType}:`, err);
ctx.reply("An unexpected error occurred. Please try again later.");
});
}

this.bot.catch((err, ctx) => {
private setupShutdownHandlers(): void {
const shutdownHandler = async (signal: string) => {
elizaLogger.log(
`⚠️ Received ${signal}. Shutting down Telegram bot gracefully...`
);
try {
await this.stop();
elizaLogger.log("πŸ›‘ Telegram bot stopped gracefully");
} catch (error) {
elizaLogger.error(
`❌ Telegram Error for ${ctx.updateType}:`,
err
);
ctx.reply(
"An unexpected error occurred. Please try again later."
"❌ Error during Telegram bot shutdown:",
error
);
});
throw error;
}
};

// Graceful shutdown handlers
const shutdownHandler = async (signal: string) => {
elizaLogger.log(
`⚠️ Received ${signal}. Shutting down Telegram bot gracefully...`
);
try {
await this.stop();
elizaLogger.log("πŸ›‘ Telegram bot stopped gracefully");
} catch (error) {
elizaLogger.error(
"❌ Error during Telegram bot shutdown:",
error
);
throw error;
}
};

process.once("SIGINT", () => shutdownHandler("SIGINT"));
process.once("SIGTERM", () => shutdownHandler("SIGTERM"));
process.once("SIGHUP", () => shutdownHandler("SIGHUP"));
} catch (error) {
elizaLogger.error("❌ Failed to launch Telegram bot:", error);
throw error;
}
process.once("SIGINT", () => shutdownHandler("SIGINT"));
process.once("SIGTERM", () => shutdownHandler("SIGTERM"));
process.once("SIGHUP", () => shutdownHandler("SIGHUP"));
}

public async stop(): Promise<void> {
Expand Down
Loading

0 comments on commit 5565830

Please sign in to comment.