goMuffin/commands/chat.go
2025-07-14 21:36:18 +09:00

293 lines
8.8 KiB
Go

package commands
import (
"context"
"fmt"
"log"
"strings"
"git.wh64.net/muffin/goMuffin/chatbot"
"git.wh64.net/muffin/goMuffin/configs"
"git.wh64.net/muffin/goMuffin/databases"
"git.wh64.net/muffin/goMuffin/utils"
"github.com/bwmarrin/discordgo"
)
type chatCommandType string
var (
chatCommandChatting chatCommandType = "하기"
chatCommandList chatCommandType = "목록"
chatCommandCreate chatCommandType = "생성"
chatCommandDelete chatCommandType = "삭제"
)
var ChatCommand *Command = &Command{
ApplicationCommand: &discordgo.ApplicationCommand{
Name: "대화",
Description: "이 봇이랑 대화해요.",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: string(chatCommandList),
Description: "채팅 목록을 나열해요.",
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: string(chatCommandCreate),
Description: "새로운 채팅을 생성해요.",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "이름",
Description: "채팅의 이름을 정해요. (25자 이내)",
MaxLength: 25,
Required: true,
},
},
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: string(chatCommandChatting),
Description: "이 봇이랑 대화해요.",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "내용",
Description: "대화할 내용",
Required: true,
},
},
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: string(chatCommandDelete),
Description: "채팅을 삭제해요.",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "제목",
Description: "채팅의 제목",
Required: true,
},
},
},
},
},
Aliases: []string{"채팅"},
DetailedDescription: &DetailedDescription{
Usage: fmt.Sprintf("%s대화 (목록/생성) [채팅 이름]", configs.Config.Bot.Prefix),
Examples: []string{
fmt.Sprintf("%s대화 목록", configs.Config.Bot.Prefix),
fmt.Sprintf("%s대화 생성 머핀 냠냠", configs.Config.Bot.Prefix),
},
},
Category: Chatting,
RegisterApplicationCommand: true,
RegisterMessageCommand: true,
Flags: CommandFlagsIsRegistered | CommandFlagsIsBlocked,
ChatInputRun: func(ctx *ChatInputContext) error {
ctx.Inter.DeferReply(nil)
var cType chatCommandType
var str string
if opt, ok := ctx.Inter.Options[string(chatCommandChatting)]; ok {
ctx.Inter.DeferReply(nil)
cType = chatCommandChatting
str = opt.Options[0].StringValue()
} else if opt, ok := ctx.Inter.Options[string(chatCommandCreate)]; ok {
ctx.Inter.DeferReply(&discordgo.InteractionResponseData{
Flags: discordgo.MessageFlagsEphemeral,
})
cType = chatCommandCreate
str = opt.Options[0].StringValue()
} else if _, ok := ctx.Inter.Options[string(chatCommandList)]; ok {
ctx.Inter.DeferReply(nil)
cType = chatCommandList
} else if _, ok := ctx.Inter.Options[string(chatCommandDelete)]; ok {
ctx.Inter.DeferReply(nil)
cType = chatCommandDelete
str = opt.Options[0].StringValue()
}
return chatCommandRun(cType, ctx.Inter, ctx.Inter.User, str)
},
MessageRun: func(ctx *MsgContext) error {
if len((*ctx.Args)) < 1 {
goto RequiredValue
}
switch (*ctx.Args)[0] {
case string(chatCommandCreate):
if len((*ctx.Args)) < 2 {
return utils.NewMessageSender(ctx.Msg).
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "채팅방의 이름을 정해야해요."})).
SetComponentsV2(true).
SetReply(true).
Send()
}
return chatCommandRun(chatCommandCreate, ctx.Msg, ctx.Msg.Author, string([]rune(strings.Join((*ctx.Args)[1:], " "))[:25]))
case string(chatCommandList):
return chatCommandRun(chatCommandList, ctx.Msg, ctx.Msg.Author, "")
case string(chatCommandDelete):
if len((*ctx.Args)) < 2 {
return utils.NewMessageSender(ctx.Msg).
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "채팅방의 이름을 적어야해요."})).
SetComponentsV2(true).
SetReply(true).
Send()
}
return chatCommandRun(chatCommandCreate, ctx.Msg, ctx.Msg.Author, strings.Join((*ctx.Args)[1:], " "))
default:
goto RequiredValue
}
RequiredValue:
return utils.NewMessageSender(ctx.Msg).
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "명령어의 첫번째 인자는 `생성`, `목록`중에 하나여야 해요."})).
SetComponentsV2(true).
SetReply(true).
Send()
},
}
func chatCommandRun(cType chatCommandType, m any, user *discordgo.User, contentOrName string) error {
switch cType {
// 채팅하기는 슬래시 커맨드만 가능
case chatCommandChatting:
i := m.(*utils.InteractionCreate)
str, err := chatbot.ChatBot.GetResponse(user, contentOrName)
if err != nil {
log.Println(err)
i.EditReply(&utils.InteractionEdit{
Content: &str,
})
return nil
}
result := chatbot.ParseResult(str, i.Session, i)
return i.EditReply(&utils.InteractionEdit{
Content: &result,
})
case chatCommandCreate:
_, err := databases.CreateChat(user.ID, contentOrName)
if err != nil {
return err
}
return utils.NewMessageSender(m).
AddComponents(utils.GetSuccessContainer(discordgo.TextDisplay{Content: fmt.Sprintf("%s를 생성했어요. 이제 현재 채팅은 %s에요.", contentOrName, contentOrName)})).
SetComponentsV2(true).
SetReply(true).
Send()
case chatCommandList:
var data []databases.Chat
var sections []discordgo.Section
var containers []*discordgo.Container
cur, err := databases.Database.Chats.Find(context.TODO(), databases.Chat{UserId: user.ID})
if err != nil {
return err
}
err = cur.All(context.TODO(), &data)
if err != nil {
return err
}
if len(data) == 0 {
return utils.NewMessageSender(m).
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "채팅이 단 하나도 없어요. 새로운 채팅을 만들거나, 대화를 시작해 채팅을 만들어주세요."})).
SetComponentsV2(true).
SetReply(true).
SetEphemeral(true).
Send()
}
for i, data := range data {
sections = append(sections, discordgo.Section{
Accessory: discordgo.Button{
Label: "선택",
Style: discordgo.SuccessButton,
CustomID: utils.MakeSelectChat(data.Id.Hex(), i+1, user.ID),
},
Components: []discordgo.MessageComponent{
discordgo.TextDisplay{
Content: fmt.Sprintf("%d. %s\n", i+1, data.Name),
},
},
})
}
textDisplay := discordgo.TextDisplay{Content: fmt.Sprintf("### %s님의 채팅목록", user.GlobalName)}
container := &discordgo.Container{Components: []discordgo.MessageComponent{textDisplay}}
for i, section := range sections {
container.Components = append(container.Components, section, discordgo.Separator{})
if (i+1)%10 == 0 {
containers = append(containers, container)
container = &discordgo.Container{Components: []discordgo.MessageComponent{textDisplay}}
continue
}
}
if len(container.Components) > 1 {
containers = append(containers, container)
}
return utils.PaginationEmbedBuilder(m).
AddContainers(containers...).
Start()
case chatCommandDelete:
var data []databases.Chat
cur, err := databases.Database.Chats.Find(context.TODO(), databases.Chat{Name: contentOrName})
if err != nil {
return err
}
err = cur.All(context.TODO(), &data)
if err != nil {
return err
}
if len(data) == 0 {
return utils.NewMessageSender(m).
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "해당하는 채팅을 찾을 수 없어요."})).
SetComponentsV2(true).
SetReply(true).
Send()
}
if len(data) > 1 {
//TODO: 이름이 같은 채팅이 여러개일때
return nil
}
return utils.NewMessageSender(m).
AddComponents(discordgo.Container{
Components: []discordgo.MessageComponent{
discordgo.TextDisplay{Content: fmt.Sprintf("### 채팅 %s 삭제", contentOrName)},
discordgo.TextDisplay{Content: "이 채팅방을 삭제하면 이 채팅방의 내역을 다시는 못 써요."},
discordgo.ActionsRow{
Components: []discordgo.MessageComponent{
discordgo.Button{
Label: "삭제",
Style: discordgo.DangerButton,
CustomID: utils.MakeDeleteChat(data[0].Id.Hex(), 0, user.ID),
},
discordgo.Button{
Label: "취소",
Style: discordgo.PrimaryButton,
CustomID: utils.MakeDeleteChatCancel(user.ID),
},
},
},
},
}).
SetComponentsV2(true).
SetReply(true).
Send()
}
return nil
}