diff --git a/main.go b/main.go index b99c64a..29535da 100644 --- a/main.go +++ b/main.go @@ -1,59 +1,88 @@ package main import ( + "context" "fmt" - "context" "github.com/bwmarrin/discordgo" - "os" - "log" + "github.com/conneroisu/groq-go" + "github.com/joho/godotenv" + "log" + "math/rand" + "os" "os/signal" "syscall" - "math/rand" - "github.com/conneroisu/groq-go" - "github.com/joho/godotenv" ) var ( - Token string - GroqKey string + Token string + GroqKey string + defaultThreshold = 0.1 + defaultMaxTokens = 100 + defaultTemperature float32 = 0.5 + defaultMessagesCount = 100 + + commands = []*discordgo.ApplicationCommand{ + { + Name: "ping", + Description: "Replies with Pong!", + }, + } + + commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){ + "ping": func(s *discordgo.Session, i *discordgo.InteractionCreate) { + log.Println("ping command") + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "Pong!", + }, + }) + }, + } ) func init() { - err := godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") - } + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } - Token = os.Getenv("DISCORD_TOKEN") - GroqKey = os.Getenv("GROQ_API_KEY") + Token = os.Getenv("DISCORD_TOKEN") + GroqKey = os.Getenv("GROQ_API_KEY") - if Token == "" { - log.Fatal("No discord token found in .env file") - } + if Token == "" { + log.Fatal("No discord token found in .env file") + } - if GroqKey == "" { - log.Fatal("No Groq key found in .env file") - } + if GroqKey == "" { + log.Fatal("No Groq key found in .env file") + } } func main() { dg, err := discordgo.New("Bot " + Token) if err != nil { - log.Fatal("Error creating Discord session,", err) + log.Fatal("Error creating Discord session,", err) return } - dg.AddHandler(messageCreate) + dg.AddHandler(messageCreate) + dg.AddHandler(joiningGuild) + dg.AddHandler(leavingGuild) - dg.Identify.Intents = discordgo.IntentsGuildMessages + dg.AddHandler(userCommand) + + dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsGuilds err = dg.Open() if err != nil { - log.Fatal("Error opening connection,", err) + log.Fatal("Error opening connection,", err) return } - log.Println("Bot is now running. Press CTRL-C to exit.") + checkRegisteredCommands(dg) + + log.Println("Bot is now running. Press CTRL-C to exit.") sc := make(chan os.Signal, 1) signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-sc @@ -61,104 +90,146 @@ func main() { dg.Close() } -func getMessages(s *discordgo.Session, channelID string, num int) ([]*discordgo.Message, error) { - if (num <= 100) { - messages, err := s.ChannelMessages(channelID, num, "", "", "") - if err != nil { - log.Println("error getting messages,", err) - return nil, err - } - return messages, nil - } +func checkRegisteredCommands(s *discordgo.Session) { + for _, v := range s.State.Guilds { + registerCommands(s, v.ID) + } +} - messages := []*discordgo.Message{} - for num > 0 { - var toGet int - if num > 100 { - toGet = 100 - } else { - toGet = num - } - lastMessage := "" - if len(messages) > 0 { - lastMessage = messages[len(messages)-1].ID - } - newMessages, err := s.ChannelMessages(channelID, toGet, lastMessage, "", "") - if err != nil { - fmt.Println("error getting messages,", err) - return nil, err - } - messages = append(messages, newMessages...) - num -= toGet - } - return messages, nil +func registerCommands(s *discordgo.Session, guildID string) { + registeredCommands := make([]*discordgo.ApplicationCommand, len(commands)) + for i, v := range commands { + cmd, err := s.ApplicationCommandCreate(s.State.User.ID, guildID, v) + if err != nil { + log.Panicf("Cannot create '%v' command: %v", v.Name, err) + } + registeredCommands[i] = cmd + } +} + +func userCommand(s *discordgo.Session, i *discordgo.InteractionCreate) { + handler, ok := commandHandlers[i.ApplicationCommandData().Name] + if !ok { + return + } + handler(s, i) +} + +func joiningGuild(s *discordgo.Session, m *discordgo.GuildCreate) { + registerCommands(s, m.ID) +} + +func leavingGuild(s *discordgo.Session, m *discordgo.GuildDelete) { + for _, v := range commands { + err := s.ApplicationCommandDelete(s.State.User.ID, m.ID, v.ID) + if err != nil { + log.Panicf("Cannot delete '%v' command: %v", v.Name, err) + } + } +} + +func getMessages(s *discordgo.Session, channelID string, num int) ([]*discordgo.Message, error) { + if num <= 100 { + messages, err := s.ChannelMessages(channelID, num, "", "", "") + if err != nil { + log.Println("error getting messages,", err) + return nil, err + } + return messages, nil + } + + messages := []*discordgo.Message{} + for num > 0 { + var toGet int + if num > 100 { + toGet = 100 + } else { + toGet = num + } + lastMessage := "" + if len(messages) > 0 { + lastMessage = messages[len(messages)-1].ID + } + newMessages, err := s.ChannelMessages(channelID, toGet, lastMessage, "", "") + if err != nil { + fmt.Println("error getting messages,", err) + return nil, err + } + messages = append(messages, newMessages...) + num -= toGet + } + return messages, nil } func botMentioned(s *discordgo.Session, m *discordgo.MessageCreate) bool { - for i := range m.Mentions { - if m.Mentions[i].ID == s.State.User.ID { - return true - } - } - return false + for i := range m.Mentions { + if m.Mentions[i].ID == s.State.User.ID { + return true + } + } + return false } func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { - if m.Author.ID == s.State.User.ID { - return - } + if m.Author.ID == s.State.User.ID { + return + } - rand := rand.Intn(100) + rand := rand.Float32() - if rand > 10 && !botMentioned(s, m){ - return - } + if rand > float32(defaultThreshold) && !botMentioned(s, m) { + return + } - messages, err := getMessages(s, m.ChannelID, 100) - if err != nil { - fmt.Println("error getting messages,", err) - return - } - messagesFormatted := "" - for i := range messages { - if messages[i].Author.ID == s.State.User.ID { - continue - } - messagesFormatted = messagesFormatted + "<" + messages[i].Author.ID + "> " + messages[i].Content + "\n" - } + messages, err := getMessages(s, m.ChannelID, 100) + if err != nil { + fmt.Println("error getting messages,", err) + return + } + messagesFormatted := "" + for i := range messages { + if messages[i].Author.ID == s.State.User.ID { + continue + } + messagesFormatted = messagesFormatted + "<" + messages[i].Author.ID + "> " + messages[i].Content + "\n" + } - question := "Tu fais partie d'une conversation. Tu n'as pas conscience d'etre un bot. Reponds de maniere goofy. Ta reponse doit etre tres courte, une phrase ou deux.\n" - question += "\n" + messagesFormatted + "\n" - response, err := askGroq(context.Background(), question) - if err != nil { - s.ChannelMessageSend(m.ChannelID, "There was an error getting the response.") - return - } - s.ChannelMessageSend(m.ChannelID, response) + question := "Tu fais partie d'une conversation. Tu n'as pas conscience d'etre un bot. Reponds de maniere goofy. Ta reponse doit etre tres courte, une phrase ou deux.\n" + question += "\n" + messagesFormatted + "\n" + response, err := askGroq(context.Background(), question) + if err != nil { + if botMentioned(s, m) { + s.ChannelMessageSendReply(m.ChannelID, "There was an error getting the response.", m.Reference()) + } else { + s.ChannelMessageSend(m.ChannelID, "There was an error getting the response.") + } + return + } + s.ChannelMessageSendReply(m.ChannelID, response, m.Reference()) } -func askGroq(ctx context.Context, message string) (string,error) { - client, err := groq.NewClient(GroqKey) - if err != nil { - fmt.Println("error creating Groq client,", err) - return "", err - } +func askGroq(ctx context.Context, message string) (string, error) { + client, err := groq.NewClient(GroqKey) + if err != nil { + fmt.Println("error creating Groq client,", err) + return "", err + } - resp, err := client.CreateChatCompletion(ctx, groq.ChatCompletionRequest{ - Model: groq.Llama318BInstant, - Messages: []groq.ChatCompletionMessage{ - { - Role: groq.ChatMessageRoleUser, - Content: message, - }, - }, - MaxTokens: 100, - }) - if err != nil { - fmt.Println("error creating Groq completion,", err) - return "", err - } + resp, err := client.CreateChatCompletion(ctx, groq.ChatCompletionRequest{ + Model: groq.Llama318BInstant, + Messages: []groq.ChatCompletionMessage{ + { + Role: groq.ChatMessageRoleUser, + Content: message, + }, + }, + MaxTokens: defaultMaxTokens, + Temperature: defaultTemperature, + }) + if err != nil { + fmt.Println("error creating Groq completion,", err) + return "", err + } - - return string(resp.Choices[0].Message.Content), nil + return string(resp.Choices[0].Message.Content), nil }