From ec410b9f81a11f62efeb758b21db9670b88f5c76 Mon Sep 17 00:00:00 2001 From: Siwoo Jeon Date: Mon, 26 May 2025 22:46:37 +0900 Subject: [PATCH] feat: rewrite chatbot --- chatbot/chatbot.go | 92 ++++++++++++++++++++++++++++++++++++++++ chatbot/enum.go | 8 ++++ chatbot/parser.go | 28 ++++++++++++ handler/messageCreate.go | 82 +++-------------------------------- main.go | 12 ++++++ utils/messageBuilder.go | 3 ++ 6 files changed, 148 insertions(+), 77 deletions(-) create mode 100644 chatbot/chatbot.go create mode 100644 chatbot/enum.go create mode 100644 chatbot/parser.go diff --git a/chatbot/chatbot.go b/chatbot/chatbot.go new file mode 100644 index 0000000..6b63f27 --- /dev/null +++ b/chatbot/chatbot.go @@ -0,0 +1,92 @@ +package chatbot + +import ( + "context" + "fmt" + "log" + "math/rand" + + "git.wh64.net/muffin/goMuffin/databases" + "git.wh64.net/muffin/goMuffin/utils" + "github.com/bwmarrin/discordgo" + "go.mongodb.org/mongo-driver/v2/bson" +) + +type Chatbot struct { + Mode ChatbotMode + s *discordgo.Session +} + +var ChatBot *Chatbot + +func New(s *discordgo.Session) { + ChatBot = &Chatbot{ + Mode: ChatbotDefault, + s: s, + } +} + +func (c *Chatbot) SetMode(mode ChatbotMode) *Chatbot { + c.Mode = mode + return c +} + +func getDefaultResponse(s *discordgo.Session, question string) string { + var data []databases.Text + var learnData []databases.Learn + var result string + + ch := make(chan int) + x := rand.Intn(10) + + // 머핀 데이터 + go func() { + cur, err := databases.Database.Texts.Find(context.TODO(), bson.D{{Key: "persona", Value: "muffin"}}) + if err != nil { + log.Fatalln(err) + } + + defer cur.Close(context.TODO()) + + cur.All(context.TODO(), &data) + ch <- 1 + }() + + // 지식 데이터 + go func() { + cur, err := databases.Database.Learns.Find(context.TODO(), bson.D{{Key: "command", Value: question}}) + if err != nil { + log.Fatalln(err) + } + + defer cur.Close(context.TODO()) + + cur.All(context.TODO(), &learnData) + ch <- 1 + }() + + for range 2 { + <-ch + } + close(ch) + + if x > 2 && len(learnData) != 0 { + data := learnData[rand.Intn(len(learnData))] + user, _ := s.User(data.UserId) + + result = + fmt.Sprintf("%s\n%s", data.Result, utils.InlineCode(fmt.Sprintf("%s님이 알려주셨어요.", user.Username))) + } else { + result = data[rand.Intn(len(data))].Text + } + return result +} + +func (c *Chatbot) GetResponse(question string) string { + switch c.Mode { + case ChatbotDefault: + return getDefaultResponse(c.s, question) + default: + return "" + } +} diff --git a/chatbot/enum.go b/chatbot/enum.go new file mode 100644 index 0000000..9eb7319 --- /dev/null +++ b/chatbot/enum.go @@ -0,0 +1,8 @@ +package chatbot + +type ChatbotMode int + +const ( + ChatbotAI ChatbotMode = iota + ChatbotDefault +) diff --git a/chatbot/parser.go b/chatbot/parser.go new file mode 100644 index 0000000..915a9b0 --- /dev/null +++ b/chatbot/parser.go @@ -0,0 +1,28 @@ +package chatbot + +import ( + "strings" + + "git.wh64.net/muffin/goMuffin/configs" + "git.wh64.net/muffin/goMuffin/utils" + "github.com/bwmarrin/discordgo" +) + +func ParseResult(content string, s *discordgo.Session, m *discordgo.MessageCreate) string { + result := content + userCreatedAt, _ := discordgo.SnowflakeTimestamp(m.Author.ID) + + result = strings.ReplaceAll(result, "{user.name}", m.Author.Username) + result = strings.ReplaceAll(result, "{user.mention}", m.Author.Mention()) + result = strings.ReplaceAll(result, "{user.globalName}", m.Author.GlobalName) + result = strings.ReplaceAll(result, "{user.id}", m.Author.ID) + result = strings.ReplaceAll(result, "{user.createdAt}", utils.Time(&userCreatedAt, utils.RelativeTime)) + result = strings.ReplaceAll(result, "{user.joinedAt}", utils.Time(&m.Member.JoinedAt, utils.RelativeTime)) + + result = strings.ReplaceAll(result, "{muffin.version}", configs.MUFFIN_VERSION) + result = strings.ReplaceAll(result, "{muffin.updatedAt}", utils.Time(configs.UpdatedAt, utils.RelativeTime)) + result = strings.ReplaceAll(result, "{muffin.startedAt}", utils.Time(configs.StartedAt, utils.RelativeTime)) + result = strings.ReplaceAll(result, "{muffin.name}", s.State.User.Username) + result = strings.ReplaceAll(result, "{muffin.id}", s.State.User.ID) + return result +} diff --git a/handler/messageCreate.go b/handler/messageCreate.go index fd0f3ee..0ab5d42 100644 --- a/handler/messageCreate.go +++ b/handler/messageCreate.go @@ -4,16 +4,15 @@ import ( "context" "fmt" "log" - "math/rand" "strings" "time" + "git.wh64.net/muffin/goMuffin/chatbot" "git.wh64.net/muffin/goMuffin/commands" "git.wh64.net/muffin/goMuffin/configs" "git.wh64.net/muffin/goMuffin/databases" "git.wh64.net/muffin/goMuffin/utils" "github.com/bwmarrin/discordgo" - "go.mongodb.org/mongo-driver/v2/bson" ) func argParser(content string) (args []string) { @@ -71,83 +70,12 @@ func MessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { if command == "" { s.ChannelTyping(m.ChannelID) - var data []databases.Text - var learnData []databases.Learn - var filter bson.D - - ch := make(chan int) - x := rand.Intn(10) - - channel, _ := s.Channel(m.ChannelID) - if channel.NSFW { - filter = bson.D{{}} - - if _, err := databases.Database.Texts.InsertOne(context.TODO(), databases.InsertText{ - Text: content, - Persona: fmt.Sprintf("user:%s", m.Author.Username), - CreatedAt: time.Now(), - }); err != nil { - log.Fatalln(err) - } - - } else { - filter = bson.D{{Key: "persona", Value: "muffin"}} - } - - go func() { - cur, err := databases.Database.Texts.Find(context.TODO(), filter) - if err != nil { - log.Fatalln(err) - } - - defer cur.Close(context.TODO()) - - cur.All(context.TODO(), &data) - ch <- 1 - }() - go func() { - cur, err := databases.Database.Learns.Find(context.TODO(), bson.D{{Key: "command", Value: content}}) - if err != nil { - log.Fatalln(err) - } - - defer cur.Close(context.TODO()) - - cur.All(context.TODO(), &learnData) - ch <- 1 - }() - - for range 2 { - <-ch - } - close(ch) - - if x > 2 && len(learnData) != 0 { - data := learnData[rand.Intn(len(learnData))] - user, _ := s.User(data.UserId) - result := resultParser(data.Result, s, m) - - utils.NewMessageSender(m). - SetContent(fmt.Sprintf("%s\n%s", result, utils.InlineCode(fmt.Sprintf("%s님이 알려주셨어요.", user.Username)))). - SetAllowedMentions(discordgo.MessageAllowedMentions{ - Roles: []string{}, - Parse: []discordgo.AllowedMentionType{}, - Users: []string{}, - }). - SetReply(true). - Send() - return - } - - utils.NewMessageSender(m). - SetContent(data[rand.Intn(len(data))].Text). - SetAllowedMentions(discordgo.MessageAllowedMentions{ - Roles: []string{}, - Parse: []discordgo.AllowedMentionType{}, - Users: []string{}, - }). + result := chatbot.ParseResult(chatbot.ChatBot.GetResponse(content), s, m) + err := utils.NewMessageSender(m). + SetContent(result). SetReply(true). Send() + fmt.Println(err) return } diff --git a/main.go b/main.go index d70484e..7a73edd 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "flag" "fmt" "log" "os" @@ -9,6 +10,7 @@ import ( "syscall" "time" + "git.wh64.net/muffin/goMuffin/chatbot" "git.wh64.net/muffin/goMuffin/commands" "git.wh64.net/muffin/goMuffin/components" "git.wh64.net/muffin/goMuffin/configs" @@ -79,6 +81,10 @@ func main() { return } + isAI := flag.Bool("ai", false, "시작할 때 AI모드로 설정합니다.") + + flag.Parse() + dg, _ := discordgo.New("Bot " + config.Bot.Token) go dg.AddHandler(handler.MessageCreate) @@ -90,6 +96,12 @@ func main() { log.Fatalln(err) } + chatbot.New(dg) + + if *isAI { + chatbot.ChatBot.SetMode(chatbot.ChatbotAI) + } + defer dg.Close() // 봇의 상태메세지 변경 diff --git a/utils/messageBuilder.go b/utils/messageBuilder.go index 612a1ce..c6be78a 100644 --- a/utils/messageBuilder.go +++ b/utils/messageBuilder.go @@ -1,6 +1,8 @@ package utils import ( + "fmt" + "github.com/bwmarrin/discordgo" ) @@ -82,6 +84,7 @@ func (s *MessageSender) Send() error { Flags: flags, Reference: reference, }) + fmt.Println(err) return err case *InteractionCreate: if s.Ephemeral {