Files
go-telegram-bot/handlers.go
HugeFrog24 c8af457af1 MVP
md formatting doesnt work yet

Started implementing owner feature

Add .gitattributes to enforce LF line endings

Temporary commit before merge

Updated owner management

Updated json and gitignore

Proceed with role management

Again, CI

Fix some lint errors

Implemented screening

Per-bot API keys implemented

Use getRoleByName func

Fix unused imports

Upgrade actions

rm unused function

Upgrade action

Fix unaddressed errors
2024-10-23 22:06:55 +02:00

190 lines
5.6 KiB
Go

package main
import (
"context"
"log"
"strings"
"github.com/go-telegram/bot"
"github.com/go-telegram/bot/models"
"github.com/liushuangls/go-anthropic/v2"
)
func (b *Bot) handleUpdate(ctx context.Context, tgBot *bot.Bot, update *models.Update) {
var message *models.Message
if update.Message != nil {
message = update.Message
} else if update.BusinessMessage != nil {
message = update.BusinessMessage
} else {
// No message to process
return
}
// Extract businessConnectionID if available
var businessConnectionID string
if update.BusinessConnection != nil {
businessConnectionID = update.BusinessConnection.ID
} else if message.BusinessConnectionID != "" {
businessConnectionID = message.BusinessConnectionID
}
chatID := message.Chat.ID
userID := message.From.ID
username := message.From.Username
text := message.Text
// Pass the incoming message through the centralized screen for storage
_, err := b.screenIncomingMessage(message)
if err != nil {
log.Printf("Error storing user message: %v", err)
return
}
// Check if the message is a command
if message.Entities != nil {
for _, entity := range message.Entities {
if entity.Type == "bot_command" {
command := strings.TrimSpace(message.Text[entity.Offset : entity.Offset+entity.Length])
switch command {
case "/stats":
b.sendStats(ctx, chatID, userID, username, businessConnectionID)
return
case "/whoami":
b.sendWhoAmI(ctx, chatID, userID, username, businessConnectionID)
return
}
}
}
}
// Check if the message contains a sticker
if message.Sticker != nil {
b.handleStickerMessage(ctx, chatID, userID, message, businessConnectionID)
return
}
// Rate limit check
if !b.checkRateLimits(userID) {
b.sendRateLimitExceededMessage(ctx, chatID, businessConnectionID)
return
}
// Proceed only if the message contains text
if text == "" {
log.Printf("Received a non-text message from user %d in chat %d", userID, chatID)
return
}
// Determine if the user is the owner
var isOwner bool
err = b.db.Where("telegram_id = ? AND bot_id = ? AND is_owner = ?", userID, b.botID, true).First(&User{}).Error
if err == nil {
isOwner = true
}
user, err := b.getOrCreateUser(userID, username, isOwner)
if err != nil {
log.Printf("Error getting or creating user: %v", err)
return
}
// Update the username if it's empty or has changed
if user.Username != username {
user.Username = username
if err := b.db.Save(&user).Error; err != nil {
log.Printf("Error updating user username: %v", err)
}
}
// Determine if the text contains only emojis
isEmojiOnly := isOnlyEmojis(text)
// Prepare context messages for Anthropic
chatMemory := b.getOrCreateChatMemory(chatID)
b.addMessageToChatMemory(chatMemory, b.createMessage(chatID, userID, username, user.Role.Name, text, true))
contextMessages := b.prepareContextMessages(chatMemory)
// Get response from Anthropic
response, err := b.getAnthropicResponse(ctx, contextMessages, b.isNewChat(chatID), isOwner, isEmojiOnly)
if err != nil {
log.Printf("Error getting Anthropic response: %v", err)
response = "I'm sorry, I'm having trouble processing your request right now."
}
// Send the response through the centralized screen
if err := b.sendResponse(ctx, chatID, response, businessConnectionID); err != nil {
log.Printf("Error sending response: %v", err)
return
}
}
func (b *Bot) sendRateLimitExceededMessage(ctx context.Context, chatID int64, businessConnectionID string) {
if err := b.sendResponse(ctx, chatID, "Rate limit exceeded. Please try again later.", businessConnectionID); err != nil {
log.Printf("Error sending rate limit exceeded message: %v", err)
}
}
func (b *Bot) handleStickerMessage(ctx context.Context, chatID, userID int64, message *models.Message, businessConnectionID string) {
username := message.From.Username
// Create the user message (without storing it manually)
userMessage := b.createMessage(chatID, userID, username, "user", "Sent a sticker.", true)
userMessage.StickerFileID = message.Sticker.FileID
// Safely store the Thumbnail's FileID if available
if message.Sticker.Thumbnail != nil {
userMessage.StickerPNGFile = message.Sticker.Thumbnail.FileID
}
// Update chat memory with the user message
chatMemory := b.getOrCreateChatMemory(chatID)
b.addMessageToChatMemory(chatMemory, userMessage)
// Generate AI response about the sticker
response, err := b.generateStickerResponse(ctx, userMessage)
if err != nil {
log.Printf("Error generating sticker response: %v", err)
// Provide a fallback dynamic response based on sticker type
if message.Sticker.IsAnimated {
response = "Wow, that's a cool animated sticker!"
} else if message.Sticker.IsVideo {
response = "Interesting video sticker!"
} else {
response = "That's a cool sticker!"
}
}
// Send the response through the centralized screen
if err := b.sendResponse(ctx, chatID, response, businessConnectionID); err != nil {
log.Printf("Error sending response: %v", err)
return
}
}
func (b *Bot) generateStickerResponse(ctx context.Context, message Message) (string, error) {
// Example: Use the sticker type to generate a response
if message.StickerFileID != "" {
// Prepare context with information about the sticker
contextMessages := []anthropic.Message{
{
Role: anthropic.RoleUser,
Content: []anthropic.MessageContent{
anthropic.NewTextMessageContent("User sent a sticker."),
},
},
}
// Since this is a sticker message, isEmojiOnly is false
response, err := b.getAnthropicResponse(ctx, contextMessages, false, false, false)
if err != nil {
return "", err
}
return response, nil
}
return "Hmm, that's interesting!", nil
}