Compare commits
2 commits
feature/mu
...
main
Author | SHA1 | Date | |
---|---|---|---|
ea0dd64df8 | |||
a76d0344c9 |
36 changed files with 1212 additions and 1569 deletions
|
@ -20,8 +20,5 @@ BOT_TOKEN=
|
|||
BOT_PREFIX=
|
||||
BOT_OWNER_ID=
|
||||
|
||||
# 챗봇
|
||||
CHATBOT_GEMINI_TOKEN=
|
||||
CHATBOT_GEMINI_PROMPT_PATH=
|
||||
CHATBOT_GEMINI_MODEL= # 기본 값은 gemini-2.5-flash
|
||||
CHATBOT_TRAIN_USER_ID= # 필수 아님
|
||||
# 학습 (필수 아님)
|
||||
TRAIN_USER_ID=
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -128,5 +128,3 @@ $RECYCLE.BIN/
|
|||
|
||||
export/
|
||||
data/
|
||||
|
||||
*prompt.txt
|
|
@ -1,189 +0,0 @@
|
|||
package chatbot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"sync"
|
||||
|
||||
"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"
|
||||
"google.golang.org/genai"
|
||||
)
|
||||
|
||||
type Chatbot struct {
|
||||
Mode ChatbotMode
|
||||
Gemini *genai.Client
|
||||
systemPrompt string
|
||||
s *discordgo.Session
|
||||
}
|
||||
|
||||
var ChatBot *Chatbot
|
||||
|
||||
func New(s *discordgo.Session) error {
|
||||
gemini, err := genai.NewClient(context.TODO(), &genai.ClientConfig{
|
||||
APIKey: configs.Config.Chatbot.Gemini.Token,
|
||||
Backend: genai.BackendGeminiAPI,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ChatBot = &Chatbot{
|
||||
Mode: ChatbotAI,
|
||||
Gemini: gemini,
|
||||
s: s,
|
||||
}
|
||||
|
||||
prompt, err := loadPrompt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ChatBot.systemPrompt = prompt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Chatbot) SetMode(mode ChatbotMode) *Chatbot {
|
||||
c.Mode = mode
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Chatbot) SwitchMode() *Chatbot {
|
||||
switch c.Mode {
|
||||
case ChatbotAI:
|
||||
c.SetMode(ChatbotMuffin)
|
||||
case ChatbotMuffin:
|
||||
c.SetMode(ChatbotAI)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Chatbot) ModeString() string {
|
||||
switch c.Mode {
|
||||
case ChatbotAI:
|
||||
return "AI모드"
|
||||
case ChatbotMuffin:
|
||||
return "머핀 모드"
|
||||
default:
|
||||
return "알 수 없음"
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Chatbot) ReloadPrompt() error {
|
||||
prompt, err := loadPrompt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.systemPrompt = prompt
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMuffinResponse(s *discordgo.Session, question string) (string, error) {
|
||||
var data []databases.Text
|
||||
var learnData []databases.Learn
|
||||
var result string
|
||||
var wg sync.WaitGroup
|
||||
|
||||
ch1 := make(chan error)
|
||||
ch2 := make(chan error)
|
||||
x := rand.Intn(10)
|
||||
|
||||
wg.Add(2)
|
||||
|
||||
// 머핀 데이터
|
||||
go func() {
|
||||
cur, err := databases.Database.Texts.Find(context.TODO(), bson.D{{Key: "persona", Value: "muffin"}})
|
||||
if err != nil {
|
||||
ch1 <- err
|
||||
}
|
||||
|
||||
defer cur.Close(context.TODO())
|
||||
|
||||
cur.All(context.TODO(), &data)
|
||||
ch1 <- nil
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
// 지식 데이터
|
||||
go func() {
|
||||
cur, err := databases.Database.Learns.Find(context.TODO(), bson.D{{Key: "command", Value: question}})
|
||||
if err != nil {
|
||||
ch2 <- err
|
||||
}
|
||||
|
||||
defer cur.Close(context.TODO())
|
||||
|
||||
cur.All(context.TODO(), &learnData)
|
||||
ch2 <- nil
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
select {
|
||||
case err := <-ch1:
|
||||
if err != nil {
|
||||
return "에러 발생", fmt.Errorf("muffin data error\n%s", err.Error())
|
||||
}
|
||||
case err := <-ch2:
|
||||
if err != nil {
|
||||
return "에러 발생", fmt.Errorf("learn data error\n%s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
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, nil
|
||||
}
|
||||
|
||||
func getAIResponse(c *Chatbot, user *discordgo.User, question string) (string, error) {
|
||||
contents, err := GetMemory(user.ID)
|
||||
if err != nil {
|
||||
ChatBot.Mode = ChatbotMuffin
|
||||
return "AI에 문제가 생겼ㅇ어요.", err
|
||||
}
|
||||
|
||||
contents = append(contents, genai.NewContentFromText(question, genai.RoleUser))
|
||||
result, err := ChatBot.Gemini.Models.GenerateContent(context.TODO(), configs.Config.Chatbot.Gemini.Model, contents, &genai.GenerateContentConfig{
|
||||
SystemInstruction: genai.NewContentFromText(makePrompt(c.systemPrompt, user), genai.RoleUser),
|
||||
})
|
||||
if err != nil {
|
||||
ChatBot.Mode = ChatbotMuffin
|
||||
return "AI에 문제가 생겼ㅇ어요.", err
|
||||
}
|
||||
|
||||
resultText := result.Text()
|
||||
err = SaveMemory(&databases.InsertMemory{
|
||||
UserId: user.ID,
|
||||
Content: question,
|
||||
Answer: resultText,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Printf("%s TOKEN: %d", user.ID, result.UsageMetadata.PromptTokenCount)
|
||||
|
||||
return resultText, nil
|
||||
}
|
||||
|
||||
func (c *Chatbot) GetResponse(user *discordgo.User, question string) (string, error) {
|
||||
switch c.Mode {
|
||||
case ChatbotMuffin:
|
||||
return getMuffinResponse(c.s, question)
|
||||
default:
|
||||
return getAIResponse(c, user, question)
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package chatbot
|
||||
|
||||
type ChatbotMode int
|
||||
|
||||
const (
|
||||
ChatbotAI ChatbotMode = iota
|
||||
ChatbotMuffin
|
||||
)
|
|
@ -1,36 +0,0 @@
|
|||
package chatbot
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/databases"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"google.golang.org/genai"
|
||||
)
|
||||
|
||||
func SaveMemory(data *databases.InsertMemory) error {
|
||||
_, err := databases.Database.Memory.InsertOne(context.TODO(), *data)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetMemory(userId string) ([]*genai.Content, error) {
|
||||
var data []databases.Memory
|
||||
|
||||
memory := []*genai.Content{}
|
||||
|
||||
cur, err := databases.Database.Memory.Find(context.TODO(), bson.D{{Key: "user_id", Value: userId}})
|
||||
if err != nil {
|
||||
return memory, err
|
||||
}
|
||||
|
||||
cur.All(context.TODO(), &data)
|
||||
|
||||
for _, data := range data {
|
||||
memory = append(memory,
|
||||
genai.NewContentFromText(data.Content, genai.RoleUser),
|
||||
genai.NewContentFromText(data.Answer, genai.RoleModel),
|
||||
)
|
||||
}
|
||||
|
||||
return memory, nil
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package chatbot
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/configs"
|
||||
"git.wh64.net/muffin/goMuffin/utils"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
func ParseResult(content string, s *discordgo.Session, m any) string {
|
||||
result := content
|
||||
|
||||
var user *discordgo.User
|
||||
var joinedAt *time.Time
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
user = m.Author
|
||||
joinedAt = &m.Member.JoinedAt
|
||||
case *utils.InteractionCreate:
|
||||
user = m.Member.User
|
||||
joinedAt = &m.Member.JoinedAt
|
||||
}
|
||||
|
||||
userCreatedAt, _ := discordgo.SnowflakeTimestamp(user.ID)
|
||||
|
||||
result = strings.ReplaceAll(result, "{user.name}", user.Username)
|
||||
result = strings.ReplaceAll(result, "{user.mention}", user.Mention())
|
||||
result = strings.ReplaceAll(result, "{user.globalName}", user.GlobalName)
|
||||
result = strings.ReplaceAll(result, "{user.id}", user.ID)
|
||||
result = strings.ReplaceAll(result, "{user.createdAt}", utils.Time(&userCreatedAt, utils.RelativeTime))
|
||||
result = strings.ReplaceAll(result, "{user.joinedAt}", utils.Time(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
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package chatbot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/configs"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
func loadPrompt() (string, error) {
|
||||
bin, err := os.ReadFile(configs.Config.Chatbot.Gemini.PromptPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(bin), nil
|
||||
}
|
||||
|
||||
func makePrompt(systemPrompt string, user *discordgo.User) string {
|
||||
if user.ID == configs.Config.Bot.OwnerId {
|
||||
return fmt.Sprintf(systemPrompt, fmt.Sprintf(
|
||||
"## User Information\n* **ID:** %s\n* **Name:** %s\n* **Other:** This user is your developer.",
|
||||
user.ID,
|
||||
user.GlobalName,
|
||||
))
|
||||
}
|
||||
|
||||
return fmt.Sprintf(systemPrompt, fmt.Sprintf(
|
||||
"## User Information\n* **ID:** %s\n* **Name:** %s\n* **Other:** This user is **not** your developer.",
|
||||
user.ID,
|
||||
user.GlobalName,
|
||||
))
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/chatbot"
|
||||
"git.wh64.net/muffin/goMuffin/utils"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
var ChatCommand *Command = &Command{
|
||||
ApplicationCommand: &discordgo.ApplicationCommand{
|
||||
Name: "대화",
|
||||
Description: "이 봇이랑 대화해요. (슬래시 커맨드 전용)",
|
||||
Options: []*discordgo.ApplicationCommandOption{
|
||||
{
|
||||
Type: discordgo.ApplicationCommandOptionString,
|
||||
Name: "내용",
|
||||
Description: "대화할 내용",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
DetailedDescription: &DetailedDescription{
|
||||
Usage: "/대화 (내용:대화할 내용)",
|
||||
Examples: []string{"/대화 내용:안녕", "/대화 내용:냠냠"},
|
||||
},
|
||||
Category: Chatting,
|
||||
RegisterApplicationCommand: true,
|
||||
RegisterMessageCommand: false,
|
||||
ChatInputRun: func(ctx *ChatInputContext) {
|
||||
i := ctx.Inter
|
||||
i.DeferReply(&discordgo.InteractionResponseData{})
|
||||
|
||||
str, err := chatbot.ChatBot.GetResponse(i.Member.User, i.Options["내용"].StringValue())
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
i.EditReply(&utils.InteractionEdit{
|
||||
Content: &str,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result := chatbot.ParseResult(str, ctx.Inter.Session, i)
|
||||
i.EditReply(&utils.InteractionEdit{
|
||||
Content: &result,
|
||||
})
|
||||
},
|
||||
}
|
|
@ -29,6 +29,7 @@ const (
|
|||
userLearn
|
||||
)
|
||||
|
||||
var dataLengthCh chan chStruct = make(chan chStruct)
|
||||
var dataLengthWg sync.WaitGroup
|
||||
|
||||
var DataLengthCommand *Command = &Command{
|
||||
|
@ -41,22 +42,16 @@ var DataLengthCommand *Command = &Command{
|
|||
DetailedDescription: &DetailedDescription{
|
||||
Usage: fmt.Sprintf("%s학습데이터량", configs.Config.Bot.Prefix),
|
||||
},
|
||||
Category: General,
|
||||
RegisterApplicationCommand: true,
|
||||
RegisterMessageCommand: true,
|
||||
Category: General,
|
||||
MessageRun: func(ctx *MsgContext) {
|
||||
dataLengthRun(ctx.Msg.Session, ctx.Msg, ctx.Msg.Author.Username, ctx.Msg.Author.ID)
|
||||
dataLengthRun(ctx.Session, ctx.Msg)
|
||||
},
|
||||
ChatInputRun: func(ctx *ChatInputContext) {
|
||||
ctx.Inter.DeferReply(&discordgo.InteractionResponseData{
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
})
|
||||
|
||||
dataLengthRun(ctx.Inter.Session, ctx.Inter, ctx.Inter.Member.User.Username, ctx.Inter.Member.User.ID)
|
||||
dataLengthRun(ctx.Session, ctx.Inter)
|
||||
},
|
||||
}
|
||||
|
||||
func getLength(ch chan chStruct, dType dataType, coll *mongo.Collection, filter bson.D) {
|
||||
func getLength(dType dataType, coll *mongo.Collection, filter bson.D) {
|
||||
defer dataLengthWg.Done()
|
||||
var err error
|
||||
var cur *mongo.Cursor
|
||||
|
@ -70,21 +65,33 @@ func getLength(ch chan chStruct, dType dataType, coll *mongo.Collection, filter
|
|||
defer cur.Close(context.TODO())
|
||||
|
||||
cur.All(context.TODO(), &data)
|
||||
ch <- chStruct{name: dType, length: len(data)}
|
||||
dataLengthCh <- chStruct{name: dType, length: len(data)}
|
||||
}
|
||||
|
||||
func dataLengthRun(s *discordgo.Session, m any, username, userId string) {
|
||||
ch := make(chan chStruct)
|
||||
func dataLengthRun(s *discordgo.Session, m any) {
|
||||
var username, userId, channelId string
|
||||
var textLength,
|
||||
muffinLength,
|
||||
nsfwLength,
|
||||
learnLength,
|
||||
userLearnLength int
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
username = m.Author.Username
|
||||
userId = m.Author.ID
|
||||
channelId = m.ChannelID
|
||||
case *utils.InteractionCreate:
|
||||
m.DeferReply(true)
|
||||
username = m.Member.User.Username
|
||||
userId = m.Member.User.ID
|
||||
channelId = m.ChannelID
|
||||
}
|
||||
|
||||
dataLengthWg.Add(5)
|
||||
go getLength(ch, text, databases.Database.Texts, bson.D{{}})
|
||||
go getLength(ch, muffin, databases.Database.Texts, bson.D{{Key: "persona", Value: "muffin"}})
|
||||
go getLength(ch, nsfw, databases.Database.Texts, bson.D{
|
||||
go getLength(text, databases.Database.Texts, bson.D{{}})
|
||||
go getLength(muffin, databases.Database.Texts, bson.D{{Key: "persona", Value: "muffin"}})
|
||||
go getLength(nsfw, databases.Database.Texts, bson.D{
|
||||
{
|
||||
Key: "persona",
|
||||
Value: bson.M{
|
||||
|
@ -92,15 +99,15 @@ func dataLengthRun(s *discordgo.Session, m any, username, userId string) {
|
|||
},
|
||||
},
|
||||
})
|
||||
go getLength(ch, learn, databases.Database.Learns, bson.D{{}})
|
||||
go getLength(ch, userLearn, databases.Database.Learns, bson.D{{Key: "user_id", Value: userId}})
|
||||
go getLength(learn, databases.Database.Learns, bson.D{{}})
|
||||
go getLength(userLearn, databases.Database.Learns, bson.D{{Key: "user_id", Value: userId}})
|
||||
|
||||
go func() {
|
||||
dataLengthWg.Wait()
|
||||
close(ch)
|
||||
close(dataLengthCh)
|
||||
}()
|
||||
|
||||
for resp := range ch {
|
||||
for resp := range dataLengthCh {
|
||||
switch dataType(resp.name) {
|
||||
case text:
|
||||
textLength = resp.length
|
||||
|
@ -117,39 +124,46 @@ func dataLengthRun(s *discordgo.Session, m any, username, userId string) {
|
|||
|
||||
sum := textLength + learnLength
|
||||
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.Section{
|
||||
Accessory: discordgo.Thumbnail{
|
||||
Media: discordgo.UnfurledMediaItem{
|
||||
URL: s.State.User.AvatarURL("512"),
|
||||
},
|
||||
},
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("### 저장된 데이터량\n총합: %s", utils.InlineCode(strconv.Itoa(sum)+"개")),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **총 채팅 데이터량**\n> %s", utils.InlineCode(strconv.Itoa(textLength))+"개"),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **머핀 데이터량**\n> %s", utils.InlineCode(strconv.Itoa(muffinLength))+"개"),
|
||||
},
|
||||
},
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **nsfw 데이터량**\n> %s", utils.InlineCode(strconv.Itoa(nsfwLength))+"개"),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **총 지식 데이터량**\n> %s", utils.InlineCode(strconv.Itoa(learnLength))+"개"),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **%s님이 가르쳐준 데이터량**\n> %s", username, utils.InlineCode(strconv.Itoa(userLearnLength))+"개"),
|
||||
},
|
||||
// 나중에 djs처럼 Embed 만들어 주는 함수 만들어야겠다
|
||||
// 지금은 임시방편
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "저장된 데이터량",
|
||||
Description: fmt.Sprintf("총합: %s개", utils.InlineCode(strconv.Itoa(sum))),
|
||||
Color: utils.EmbedDefault,
|
||||
Fields: []*discordgo.MessageEmbedField{
|
||||
{
|
||||
Name: "총 채팅 데이터량",
|
||||
Value: utils.InlineCode(strconv.Itoa(textLength)) + "개",
|
||||
Inline: true,
|
||||
},
|
||||
}).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
{
|
||||
Name: "총 지식 데이터량",
|
||||
Value: utils.InlineCode(strconv.Itoa(learnLength)) + "개",
|
||||
Inline: true,
|
||||
},
|
||||
{
|
||||
Name: "머핀 데이터량",
|
||||
Value: utils.InlineCode(strconv.Itoa(muffinLength)) + "개",
|
||||
},
|
||||
{
|
||||
Name: "nsfw 데이터량",
|
||||
Value: utils.InlineCode(strconv.Itoa(nsfwLength)) + "개",
|
||||
Inline: true,
|
||||
},
|
||||
{
|
||||
Name: fmt.Sprintf("%s님이 가르쳐준 데이터량", username),
|
||||
Value: utils.InlineCode(strconv.Itoa(userLearnLength)) + "개",
|
||||
Inline: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(channelId, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,104 +29,141 @@ var DeleteLearnedDataCommand *Command = &Command{
|
|||
Usage: fmt.Sprintf("%s삭제 (삭제할 단어)", configs.Config.Bot.Prefix),
|
||||
Examples: []string{fmt.Sprintf("%s삭제 머핀", configs.Config.Bot.Prefix)},
|
||||
},
|
||||
Category: Chatting,
|
||||
RegisterApplicationCommand: true,
|
||||
RegisterMessageCommand: true,
|
||||
Category: Chatting,
|
||||
MessageRun: func(ctx *MsgContext) {
|
||||
command := strings.Join(*ctx.Args, " ")
|
||||
if command == "" {
|
||||
utils.NewMessageSender(ctx.Msg).
|
||||
AddComponents(utils.GetErrorContainer(
|
||||
discordgo.TextDisplay{
|
||||
Content: "올바르지 않ㅇ은 용법이에요.",
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **사용법**\n> %s", ctx.Command.DetailedDescription.Usage),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **예시**\n%s", strings.Join(utils.AddPrefix("> ", ctx.Command.DetailedDescription.Examples), "\n")),
|
||||
},
|
||||
)).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
}
|
||||
deleteLearnedDataRun(ctx.Msg, strings.Join(*ctx.Args, " "), ctx.Msg.Author.ID)
|
||||
deleteLearnedDataRun(ctx.Command, ctx.Session, ctx.Msg, ctx.Args)
|
||||
},
|
||||
ChatInputRun: func(ctx *ChatInputContext) {
|
||||
ctx.Inter.DeferReply(&discordgo.InteractionResponseData{
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
})
|
||||
|
||||
var command string
|
||||
|
||||
if opt, ok := ctx.Inter.Options["단어"]; ok {
|
||||
command = opt.StringValue()
|
||||
}
|
||||
|
||||
deleteLearnedDataRun(ctx.Inter, command, ctx.Inter.Member.User.ID)
|
||||
deleteLearnedDataRun(ctx.Command, ctx.Session, ctx.Inter, nil)
|
||||
},
|
||||
}
|
||||
|
||||
func deleteLearnedDataRun(m any, command, userId string) {
|
||||
func deleteLearnedDataRun(c *Command, s *discordgo.Session, m any, args *[]string) {
|
||||
var command, userId, description string
|
||||
var data []databases.Learn
|
||||
var sections []discordgo.Section
|
||||
var containers []*discordgo.Container
|
||||
var options []discordgo.SelectMenuOption
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
command = strings.Join(*args, " ")
|
||||
userId = m.Author.ID
|
||||
|
||||
if command == "" {
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "올바르지 않ㅇ은 용법이에요.",
|
||||
Fields: []*discordgo.MessageEmbedField{
|
||||
{
|
||||
Name: "사용법",
|
||||
Value: utils.InlineCode(c.DetailedDescription.Usage),
|
||||
},
|
||||
{
|
||||
Name: "예시",
|
||||
Value: utils.CodeBlock("md", strings.Join(addPrefix(c.DetailedDescription.Examples), "\n")),
|
||||
},
|
||||
},
|
||||
Color: utils.EmbedFail,
|
||||
}, m.Reference())
|
||||
}
|
||||
case *utils.InteractionCreate:
|
||||
m.DeferReply(true)
|
||||
|
||||
if opt, ok := m.Options["단어"]; ok {
|
||||
command = opt.StringValue()
|
||||
}
|
||||
userId = m.Member.User.ID
|
||||
}
|
||||
|
||||
cur, err := databases.Database.Learns.Find(context.TODO(), bson.M{"user_id": userId, "command": command})
|
||||
if err != nil {
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "데이터를 가져오는데 실패했어요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "데이터를 가져오는데 실패했어요.",
|
||||
Color: utils.EmbedFail,
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
cur.All(context.TODO(), &data)
|
||||
|
||||
if len(data) < 1 {
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "해당 하는 지식ㅇ을 찾을 수 없어요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "해당 하는 지식ㅇ을 찾을 수 없어요.",
|
||||
Color: utils.EmbedFail,
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i, data := range data {
|
||||
sections = append(sections, discordgo.Section{
|
||||
Accessory: discordgo.Button{
|
||||
Label: "삭제",
|
||||
Style: discordgo.DangerButton,
|
||||
CustomID: utils.MakeDeleteLearnedData(data.Id.Hex(), i+1, userId),
|
||||
},
|
||||
for i := range len(data) {
|
||||
data := data[i]
|
||||
|
||||
options = append(options, discordgo.SelectMenuOption{
|
||||
Label: fmt.Sprintf("%d번 지식", i+1),
|
||||
Description: data.Result,
|
||||
Value: utils.MakeDeleteLearnedData(data.Id.Hex(), i+1),
|
||||
})
|
||||
description += fmt.Sprintf("%d. %s\n", i+1, data.Result)
|
||||
}
|
||||
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: fmt.Sprintf("%s 삭제", command),
|
||||
Description: utils.CodeBlock("md", fmt.Sprintf("# %s에 대한 대답 중 하나를 선ㅌ택하여 삭제해주세요.\n%s", command, description)),
|
||||
Color: utils.EmbedDefault,
|
||||
}
|
||||
|
||||
components := []discordgo.MessageComponent{
|
||||
discordgo.ActionsRow{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("%d. %s\n", i+1, data.Result),
|
||||
discordgo.SelectMenu{
|
||||
MenuType: discordgo.StringSelectMenu,
|
||||
CustomID: utils.MakeDeleteLearnedDataUserId(userId),
|
||||
Options: options,
|
||||
Placeholder: "ㅈ지울 응답을 선택해주세요.",
|
||||
},
|
||||
},
|
||||
},
|
||||
discordgo.ActionsRow{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.Button{
|
||||
CustomID: utils.MakeDeleteLearnedDataCancel(userId),
|
||||
Label: "취소하기",
|
||||
Style: discordgo.DangerButton,
|
||||
Disabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{
|
||||
Embeds: []*discordgo.MessageEmbed{embed},
|
||||
Components: components,
|
||||
Reference: m.Reference(),
|
||||
})
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
Components: &components,
|
||||
})
|
||||
}
|
||||
|
||||
textDisplay := discordgo.TextDisplay{Content: fmt.Sprintf("### %s 삭제", command)}
|
||||
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)
|
||||
}
|
||||
|
||||
utils.PaginationEmbedBuilder(m).
|
||||
AddContainers(containers...).
|
||||
Start()
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package commands
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/configs"
|
||||
"git.wh64.net/muffin/goMuffin/utils"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
@ -25,13 +24,11 @@ type DetailedDescription struct {
|
|||
|
||||
type Command struct {
|
||||
*discordgo.ApplicationCommand
|
||||
Aliases []string
|
||||
DetailedDescription *DetailedDescription
|
||||
Category Category
|
||||
RegisterApplicationCommand bool
|
||||
RegisterMessageCommand bool
|
||||
MessageRun messageRun
|
||||
ChatInputRun chatInputRun
|
||||
Aliases []string
|
||||
DetailedDescription *DetailedDescription
|
||||
Category Category
|
||||
MessageRun messageRun
|
||||
ChatInputRun chatInputRun
|
||||
}
|
||||
|
||||
type DiscommandStruct struct {
|
||||
|
@ -42,17 +39,20 @@ type DiscommandStruct struct {
|
|||
}
|
||||
|
||||
type MsgContext struct {
|
||||
Msg *utils.MessageCreate
|
||||
Session *discordgo.Session
|
||||
Msg *discordgo.MessageCreate
|
||||
Args *[]string
|
||||
Command *Command
|
||||
}
|
||||
|
||||
type ChatInputContext struct {
|
||||
Session *discordgo.Session
|
||||
Inter *utils.InteractionCreate
|
||||
Command *Command
|
||||
}
|
||||
|
||||
type ComponentContext struct {
|
||||
Session *discordgo.Session
|
||||
Inter *utils.InteractionCreate
|
||||
Component *Component
|
||||
}
|
||||
|
@ -73,9 +73,8 @@ type Modal struct {
|
|||
}
|
||||
|
||||
const (
|
||||
Chatting Category = "채팅"
|
||||
General Category = "일반"
|
||||
DeveloperOnly Category = "개발자 전용"
|
||||
Chatting Category = "채팅"
|
||||
General Category = "일반"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -84,15 +83,14 @@ var (
|
|||
modalMutex sync.Mutex
|
||||
)
|
||||
|
||||
var Discommand *DiscommandStruct
|
||||
|
||||
func init() {
|
||||
Discommand = &DiscommandStruct{
|
||||
func new() *DiscommandStruct {
|
||||
discommand := DiscommandStruct{
|
||||
Commands: map[string]*Command{},
|
||||
Aliases: map[string]string{},
|
||||
Components: []*Component{},
|
||||
Modals: []*Modal{},
|
||||
}
|
||||
return &discommand
|
||||
}
|
||||
|
||||
func (d *DiscommandStruct) LoadCommand(c *Command) {
|
||||
|
@ -120,29 +118,13 @@ func (d *DiscommandStruct) LoadModal(m *Modal) {
|
|||
|
||||
func (d *DiscommandStruct) MessageRun(name string, s *discordgo.Session, m *discordgo.MessageCreate, args []string) {
|
||||
if command, ok := d.Commands[name]; ok {
|
||||
if command.Category == DeveloperOnly && m.Author.ID != configs.Config.Bot.OwnerId {
|
||||
utils.NewMessageSender(&utils.MessageCreate{MessageCreate: m, Session: s}).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "해당 명령어는 개발자만 사용 가능해요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
return
|
||||
}
|
||||
|
||||
if !command.RegisterMessageCommand {
|
||||
return
|
||||
}
|
||||
|
||||
command.MessageRun(&MsgContext{&utils.MessageCreate{
|
||||
MessageCreate: m,
|
||||
Session: s,
|
||||
}, &args, command})
|
||||
command.MessageRun(&MsgContext{s, m, &args, command})
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DiscommandStruct) ChatInputRun(name string, s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||
if command, ok := d.Commands[name]; ok && command.RegisterApplicationCommand {
|
||||
command.ChatInputRun(&ChatInputContext{&utils.InteractionCreate{
|
||||
if command, ok := d.Commands[name]; ok {
|
||||
command.ChatInputRun(&ChatInputContext{s, &utils.InteractionCreate{
|
||||
InteractionCreate: i,
|
||||
Session: s,
|
||||
Options: utils.GetInteractionOptions(i),
|
||||
|
@ -152,6 +134,7 @@ func (d *DiscommandStruct) ChatInputRun(name string, s *discordgo.Session, i *di
|
|||
|
||||
func (d *DiscommandStruct) ComponentRun(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||
data := &ComponentContext{
|
||||
Session: s,
|
||||
Inter: &utils.InteractionCreate{
|
||||
InteractionCreate: i,
|
||||
Session: s,
|
||||
|
@ -189,3 +172,5 @@ func (d *DiscommandStruct) ModalRun(s *discordgo.Session, i *discordgo.Interacti
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
var Discommand *DiscommandStruct = new()
|
||||
|
|
174
commands/help.go
174
commands/help.go
|
@ -28,20 +28,12 @@ var HelpCommand *Command = &Command{
|
|||
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: General,
|
||||
RegisterApplicationCommand: true,
|
||||
RegisterMessageCommand: true,
|
||||
Category: General,
|
||||
MessageRun: func(ctx *MsgContext) {
|
||||
helpRun(ctx.Msg.Session, ctx.Msg, strings.Join(*ctx.Args, " "))
|
||||
helpRun(ctx.Session, ctx.Msg, ctx.Args)
|
||||
},
|
||||
ChatInputRun: func(ctx *ChatInputContext) {
|
||||
var command string
|
||||
|
||||
if opt, ok := ctx.Inter.Options["명령어"]; ok {
|
||||
command = opt.StringValue()
|
||||
}
|
||||
|
||||
helpRun(ctx.Inter.Session, ctx.Inter, command)
|
||||
helpRun(ctx.Session, ctx.Inter, nil)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -49,100 +41,108 @@ func getCommandsByCategory(d *DiscommandStruct, category Category) []string {
|
|||
commands := []string{}
|
||||
for _, command := range d.Commands {
|
||||
if command.Category == category {
|
||||
commands = append(commands, fmt.Sprintf("> **%s**: %s", command.Name, command.Description))
|
||||
commands = append(commands, fmt.Sprintf("- %s: %s", command.Name, command.Description))
|
||||
}
|
||||
}
|
||||
return commands
|
||||
}
|
||||
|
||||
func helpRun(s *discordgo.Session, m any, commandName string) {
|
||||
section := &discordgo.Section{
|
||||
Accessory: discordgo.Thumbnail{
|
||||
Media: discordgo.UnfurledMediaItem{
|
||||
URL: s.State.User.AvatarURL("512"),
|
||||
},
|
||||
func helpRun(s *discordgo.Session, m any, args *[]string) {
|
||||
var commandName string
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Color: utils.EmbedDefault,
|
||||
Footer: &discordgo.MessageEmbedFooter{
|
||||
Text: fmt.Sprintf("버전: %s", configs.MUFFIN_VERSION),
|
||||
},
|
||||
Thumbnail: &discordgo.MessageEmbedThumbnail{
|
||||
URL: s.State.User.AvatarURL("512"),
|
||||
},
|
||||
}
|
||||
|
||||
commandName = Discommand.Aliases[commandName]
|
||||
|
||||
if commandName == "" || Discommand.Commands[commandName] == nil {
|
||||
section.Components = append(section.Components,
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("### %s의 도움말", s.State.User.Username),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **일반**\n%s", strings.Join(getCommandsByCategory(Discommand, General), "\n")),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **채팅**\n%s", strings.Join(getCommandsByCategory(Discommand, Chatting), "\n")),
|
||||
},
|
||||
)
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(&discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{section},
|
||||
}).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
return
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
commandName = Discommand.Aliases[strings.Join(*args, " ")]
|
||||
case *utils.InteractionCreate:
|
||||
if opt, ok := m.Options["명령어"]; ok {
|
||||
commandName = opt.StringValue()
|
||||
} else {
|
||||
commandName = ""
|
||||
}
|
||||
}
|
||||
|
||||
var aliases, examples discordgo.TextDisplay
|
||||
if commandName == "" || Discommand.Commands[commandName] == nil {
|
||||
embed.Title = fmt.Sprintf("%s의 도움말", s.State.User.Username)
|
||||
embed.Description = utils.CodeBlock(
|
||||
"md",
|
||||
fmt.Sprintf("# 일반\n%s\n\n# 채팅\n%s",
|
||||
strings.Join(getCommandsByCategory(Discommand, General), "\n"),
|
||||
strings.Join(getCommandsByCategory(Discommand, Chatting), "\n")),
|
||||
)
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.Reply(&discordgo.InteractionResponseData{
|
||||
Embeds: []*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
command := Discommand.Commands[commandName]
|
||||
|
||||
section.Components = append(section.Components,
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("### %s의 %s 명령어의 도움말", s.State.User.Username, command.Name),
|
||||
embed.Title = fmt.Sprintf("%s의 %s 명령어의 도움말", s.State.User.Username, command.Name)
|
||||
embed.Fields = []*discordgo.MessageEmbedField{
|
||||
{
|
||||
Name: "설명",
|
||||
Value: utils.InlineCode(command.Description),
|
||||
Inline: true,
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **설명**\n> %s", command.Description),
|
||||
{
|
||||
Name: "사용법",
|
||||
Value: utils.InlineCode(command.DetailedDescription.Usage),
|
||||
Inline: true,
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **사용법**\n> %s", command.DetailedDescription.Usage),
|
||||
},
|
||||
)
|
||||
|
||||
if command.Aliases != nil {
|
||||
aliases = discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **별칭**\n%s", strings.Join(utils.AddPrefix("> ", command.Aliases), "\n")),
|
||||
}
|
||||
} else {
|
||||
aliases = discordgo.TextDisplay{
|
||||
Content: "- **별칭**\n> 없음",
|
||||
}
|
||||
}
|
||||
|
||||
if command.DetailedDescription.Examples != nil {
|
||||
examples = discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **예시**\n%s", strings.Join(utils.AddPrefix("> ", command.DetailedDescription.Examples), "\n")),
|
||||
}
|
||||
} else {
|
||||
aliases = discordgo.TextDisplay{
|
||||
Content: "- **예시**\n> 없음",
|
||||
}
|
||||
}
|
||||
|
||||
if command.Name == LearnCommand.Name {
|
||||
learnArgs := discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **대답에 쓸 수 있는 인자**\n%s", learnArguments),
|
||||
}
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{section, aliases, examples, learnArgs},
|
||||
}).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
return
|
||||
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
|
||||
Name: "대답에 쓸 수 있는 인자",
|
||||
Value: learnArguments,
|
||||
})
|
||||
}
|
||||
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{section, aliases, examples},
|
||||
}).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
if command.Aliases != nil {
|
||||
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
|
||||
Name: "별칭",
|
||||
Value: utils.CodeBlock("md", strings.Join(addPrefix(command.Aliases), "\n")),
|
||||
})
|
||||
} else {
|
||||
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
|
||||
Name: "별칭",
|
||||
Value: "없음",
|
||||
})
|
||||
}
|
||||
|
||||
if command.DetailedDescription.Examples != nil {
|
||||
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
|
||||
Name: "예시",
|
||||
Value: utils.CodeBlock("md", strings.Join(addPrefix(command.DetailedDescription.Examples), "\n")),
|
||||
})
|
||||
} else {
|
||||
embed.Fields = append(embed.Fields, &discordgo.MessageEmbedField{
|
||||
Name: "예시",
|
||||
Value: "없음",
|
||||
})
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.Reply(&discordgo.InteractionResponseData{
|
||||
Embeds: []*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package commands
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/configs"
|
||||
"git.wh64.net/muffin/goMuffin/utils"
|
||||
|
@ -16,49 +17,55 @@ var InformationCommand *Command = &Command{
|
|||
DetailedDescription: &DetailedDescription{
|
||||
Usage: fmt.Sprintf("%s정보", configs.Config.Bot.Prefix),
|
||||
},
|
||||
Category: General,
|
||||
RegisterApplicationCommand: true,
|
||||
RegisterMessageCommand: true,
|
||||
Category: General,
|
||||
MessageRun: func(ctx *MsgContext) {
|
||||
informationRun(ctx.Msg.Session, ctx.Msg)
|
||||
informationRun(ctx.Session, ctx.Msg)
|
||||
},
|
||||
ChatInputRun: func(ctx *ChatInputContext) {
|
||||
informationRun(ctx.Inter.Session, ctx.Inter)
|
||||
informationRun(ctx.Session, ctx.Inter)
|
||||
},
|
||||
}
|
||||
|
||||
func informationRun(s *discordgo.Session, m any) {
|
||||
owner, _ := s.User(configs.Config.Bot.OwnerId)
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.Section{
|
||||
Accessory: discordgo.Thumbnail{
|
||||
Media: discordgo.UnfurledMediaItem{
|
||||
URL: s.State.User.AvatarURL("512"),
|
||||
},
|
||||
},
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("### %s의 정보", s.State.User.Username),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **제작자**\n> %s", owner.Username),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **버전**\n> %s", configs.MUFFIN_VERSION),
|
||||
},
|
||||
},
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **최근에 업데이트된 날짜**\n> %s", utils.Time(configs.UpdatedAt, utils.RelativeTime)),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **봇이 시작한 시각**\n> %s", utils.Time(configs.StartedAt, utils.RelativeTime)),
|
||||
},
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: fmt.Sprintf("%s의 정보", s.State.User.Username),
|
||||
Fields: []*discordgo.MessageEmbedField{
|
||||
{
|
||||
Name: "운영 체제",
|
||||
Value: utils.InlineCode(fmt.Sprintf("%s %s", runtime.GOARCH, runtime.GOOS)),
|
||||
},
|
||||
}).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
{
|
||||
Name: "제작자",
|
||||
Value: utils.InlineCode(owner.Username),
|
||||
},
|
||||
{
|
||||
Name: "버전",
|
||||
Value: utils.InlineCode(configs.MUFFIN_VERSION),
|
||||
},
|
||||
{
|
||||
Name: "최근에 업데이트된 날짜",
|
||||
Value: utils.Time(configs.UpdatedAt, utils.RelativeTime),
|
||||
Inline: true,
|
||||
},
|
||||
{
|
||||
Name: "시작한 시각",
|
||||
Value: utils.Time(configs.StartedAt, utils.RelativeTime),
|
||||
Inline: true,
|
||||
},
|
||||
},
|
||||
Color: utils.EmbedDefault,
|
||||
Thumbnail: &discordgo.MessageEmbedThumbnail{
|
||||
URL: s.State.User.AvatarURL("512"),
|
||||
},
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.Reply(&discordgo.InteractionResponseData{
|
||||
Embeds: []*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package commands
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -14,17 +13,17 @@ import (
|
|||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
var learnArguments = "> " + utils.InlineCode("{user.name}") + "\n" +
|
||||
"> " + utils.InlineCode("{user.mention}") + "\n" +
|
||||
"> " + utils.InlineCode("{user.globalName}") + "\n" +
|
||||
"> " + utils.InlineCode("{user.id}") + "\n" +
|
||||
"> " + utils.InlineCode("{user.createdAt}") + "\n" +
|
||||
"> " + utils.InlineCode("{user.joinedAt}") + "\n" +
|
||||
"> " + utils.InlineCode("{muffin.version}") + "\n" +
|
||||
"> " + utils.InlineCode("{muffin.updatedAt}") + "\n" +
|
||||
"> " + utils.InlineCode("{muffin.statedAt}") + "\n" +
|
||||
"> " + utils.InlineCode("{muffin.name}") + "\n" +
|
||||
"> " + utils.InlineCode("{muffin.id}")
|
||||
var learnArguments = utils.InlineCode("{user.name}") + "\n" +
|
||||
utils.InlineCode("{user.mention}") + "\n" +
|
||||
utils.InlineCode("{user.globalName}") + "\n" +
|
||||
utils.InlineCode("{user.id}") + "\n" +
|
||||
utils.InlineCode("{user.createdAt}") + "\n" +
|
||||
utils.InlineCode("{user.joinedAt}") + "\n" +
|
||||
utils.InlineCode("{muffin.version}") + "\n" +
|
||||
utils.InlineCode("{muffin.updatedAt}") + "\n" +
|
||||
utils.InlineCode("{muffin.statedAt}") + "\n" +
|
||||
utils.InlineCode("{muffin.name}") + "\n" +
|
||||
utils.InlineCode("{muffin.id}")
|
||||
|
||||
var LearnCommand *Command = &Command{
|
||||
ApplicationCommand: &discordgo.ApplicationCommand{
|
||||
|
@ -56,55 +55,70 @@ var LearnCommand *Command = &Command{
|
|||
fmt.Sprintf("%s배워 \"나의 아이디를 알려줘\" \"너의 아이디는 {user.id}야.\"", configs.Config.Bot.Prefix),
|
||||
},
|
||||
},
|
||||
Category: Chatting,
|
||||
RegisterApplicationCommand: true,
|
||||
RegisterMessageCommand: true,
|
||||
Category: Chatting,
|
||||
MessageRun: func(ctx *MsgContext) {
|
||||
if len(*ctx.Args) < 2 {
|
||||
utils.NewMessageSender(ctx.Msg).
|
||||
AddComponents(utils.GetErrorContainer(
|
||||
discordgo.TextDisplay{
|
||||
Content: "올바르지 않ㅇ은 용법이에요.",
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **사용법**\n> %s", ctx.Command.DetailedDescription.Usage),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **예시**\n%s", strings.Join(utils.AddPrefix("> ", ctx.Command.DetailedDescription.Examples), "\n")),
|
||||
},
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("- **사용 가능한 인자**\n%s", learnArguments),
|
||||
},
|
||||
)).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
return
|
||||
}
|
||||
|
||||
learnRun(ctx.Msg, ctx.Msg.Author.ID, strings.ReplaceAll((*ctx.Args)[0], "_", " "), strings.ReplaceAll((*ctx.Args)[1], "_", " "))
|
||||
learnRun(ctx.Command, ctx.Session, ctx.Msg, ctx.Args)
|
||||
},
|
||||
ChatInputRun: func(ctx *ChatInputContext) {
|
||||
ctx.Inter.DeferReply(&discordgo.InteractionResponseData{
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
})
|
||||
|
||||
var command, result string
|
||||
|
||||
if opt, ok := ctx.Inter.Options["단어"]; ok {
|
||||
command = opt.StringValue()
|
||||
}
|
||||
|
||||
if opt, ok := ctx.Inter.Options["대답"]; ok {
|
||||
result = opt.StringValue()
|
||||
}
|
||||
|
||||
learnRun(ctx.Inter, ctx.Inter.Member.User.ID, command, result)
|
||||
learnRun(ctx.Command, ctx.Session, ctx.Inter, nil)
|
||||
},
|
||||
}
|
||||
|
||||
func learnRun(m any, userId, command, result string) {
|
||||
func addPrefix(arr []string) (newArr []string) {
|
||||
for _, item := range arr {
|
||||
newArr = append(newArr, fmt.Sprintf("- %s", item))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func learnRun(c *Command, s *discordgo.Session, m any, args *[]string) {
|
||||
var userId, command, result string
|
||||
|
||||
igCommands := []string{}
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
userId = m.Author.ID
|
||||
|
||||
if len(*args) < 2 {
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "올바르지 않ㅇ은 용법이에요.",
|
||||
Fields: []*discordgo.MessageEmbedField{
|
||||
{
|
||||
Name: "사용법",
|
||||
Value: utils.InlineCode(c.DetailedDescription.Usage),
|
||||
Inline: true,
|
||||
},
|
||||
{
|
||||
Name: "사용 가능한 인자",
|
||||
Value: learnArguments,
|
||||
Inline: true,
|
||||
},
|
||||
{
|
||||
Name: "예시",
|
||||
Value: utils.CodeBlock("md", strings.Join(addPrefix(c.DetailedDescription.Examples), "\n")),
|
||||
},
|
||||
},
|
||||
Color: utils.EmbedFail,
|
||||
}, m.Reference())
|
||||
return
|
||||
}
|
||||
|
||||
command = strings.ReplaceAll((*args)[0], "_", " ")
|
||||
result = strings.ReplaceAll((*args)[1], "_", " ")
|
||||
case *utils.InteractionCreate:
|
||||
m.DeferReply(true)
|
||||
|
||||
userId = m.Member.User.ID
|
||||
|
||||
if opt, ok := m.Options["단어"]; ok {
|
||||
command = opt.StringValue()
|
||||
}
|
||||
|
||||
if opt, ok := m.Options["대답"]; ok {
|
||||
result = opt.StringValue()
|
||||
}
|
||||
}
|
||||
|
||||
for _, command := range Discommand.Commands {
|
||||
igCommands = append(igCommands, command.Name)
|
||||
|
@ -122,32 +136,58 @@ func learnRun(m any, userId, command, result string) {
|
|||
|
||||
for _, ig := range ignores {
|
||||
if strings.Contains(command, ig) {
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "해ㄷ당 단어는 배우기 껄끄ㄹ럽네요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "해ㄷ당 단어는 배우기 껄끄ㄹ럽네요.",
|
||||
Color: utils.EmbedFail,
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, di := range disallows {
|
||||
if strings.Contains(result, di) {
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "해당 단ㅇ어의 대답으로 하기 좀 그렇ㄴ네요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
return
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "해당 단ㅇ어의 대답으로 하기 좀 그렇ㄴ네요.",
|
||||
Color: utils.EmbedFail,
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len([]rune(command)) > 100 {
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "단어는 100글자를 못 넘ㅇ어가요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "단어는 100글자를 못 넘ㅇ어가요.",
|
||||
Color: utils.EmbedFail,
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_, err := databases.Database.Learns.InsertOne(context.TODO(), databases.InsertLearn{
|
||||
|
@ -157,23 +197,36 @@ func learnRun(m any, userId, command, result string) {
|
|||
CreatedAt: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
fmt.Println(err)
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "단어를 배우는데 오류가 생겼어요.",
|
||||
Color: utils.EmbedFail,
|
||||
}
|
||||
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "단어를 배우는데 오류가 생겼어요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetSuccessContainer(
|
||||
discordgo.TextDisplay{
|
||||
Content: fmt.Sprintf("%s 배웠어요.", hangul.GetJosa(command, hangul.EUL_REUL)),
|
||||
},
|
||||
)).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "✅ 성공",
|
||||
Description: fmt.Sprintf("%s 배웠어요.", hangul.GetJosa(command, hangul.EUL_REUL)),
|
||||
Color: utils.EmbedSuccess,
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,87 +56,12 @@ var LearnedDataListCommand *Command = &Command{
|
|||
fmt.Sprintf("%s리스트 대답:머핀", configs.Config.Bot.Prefix),
|
||||
},
|
||||
},
|
||||
Category: Chatting,
|
||||
RegisterApplicationCommand: true,
|
||||
RegisterMessageCommand: true,
|
||||
Category: Chatting,
|
||||
MessageRun: func(ctx *MsgContext) {
|
||||
var length int
|
||||
|
||||
filter := bson.D{{Key: "user_id", Value: ctx.Msg.Author.ID}}
|
||||
query := strings.Join(*ctx.Args, " ")
|
||||
|
||||
if match := utils.RegexpLearnQueryCommand.FindStringSubmatch(query); match != nil {
|
||||
filter = append(filter, bson.E{
|
||||
Key: "command",
|
||||
Value: bson.M{
|
||||
"$regex": match[1],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if match := utils.RegexpLearnQueryResult.FindStringSubmatch(query); match != nil {
|
||||
filter = append(filter, bson.E{
|
||||
Key: "result",
|
||||
Value: bson.M{
|
||||
"$regex": match[1],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if match := utils.RegexpLearnQueryLength.FindStringSubmatch(query); match != nil {
|
||||
length, _ = strconv.Atoi(match[1])
|
||||
|
||||
if float64(length) < LIST_MIN_VALUE {
|
||||
utils.NewMessageSender(ctx.Msg).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: fmt.Sprintf("개수의 값은 %d보다 커야해요.", int(LIST_MIN_VALUE))})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
return
|
||||
}
|
||||
|
||||
if float64(length) > LIST_MAX_VALUE {
|
||||
utils.NewMessageSender(ctx.Msg).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: fmt.Sprintf("개수의 값은 %d보다 작아야해요.", int(LIST_MAX_VALUE))})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
return
|
||||
}
|
||||
}
|
||||
learnedDataListRun(ctx.Msg, ctx.Msg.Author.GlobalName, ctx.Msg.Author.AvatarURL("512"), filter, length)
|
||||
learnedDataListRun(ctx.Session, ctx.Msg, ctx.Args)
|
||||
},
|
||||
ChatInputRun: func(ctx *ChatInputContext) {
|
||||
ctx.Inter.DeferReply(&discordgo.InteractionResponseData{
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
})
|
||||
|
||||
var length int
|
||||
|
||||
filter := bson.D{{Key: "user_id", Value: ctx.Inter.Member.User.ID}}
|
||||
|
||||
if opt, ok := ctx.Inter.Options["단어"]; ok {
|
||||
filter = append(filter, bson.E{
|
||||
Key: "command",
|
||||
Value: bson.M{
|
||||
"$regex": opt.StringValue(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if opt, ok := ctx.Inter.Options["대답"]; ok {
|
||||
filter = append(filter, bson.E{
|
||||
Key: "result",
|
||||
Value: bson.M{
|
||||
"$regex": opt.StringValue(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if opt, ok := ctx.Inter.Options["개수"]; ok {
|
||||
length = int(opt.IntValue())
|
||||
}
|
||||
learnedDataListRun(ctx.Inter, ctx.Inter.Member.User.GlobalName, ctx.Inter.Member.User.AvatarURL("512"), filter, length)
|
||||
learnedDataListRun(ctx.Session, ctx.Inter, nil)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -180,64 +105,134 @@ func getDescriptions(data *[]databases.Learn, length int) (descriptions []string
|
|||
return
|
||||
}
|
||||
|
||||
func getContainers(accessory *discordgo.Thumbnail, defaultDesc string, data *[]databases.Learn, length int) []*discordgo.Container {
|
||||
var containers []*discordgo.Container
|
||||
|
||||
descriptions := getDescriptions(data, length)
|
||||
|
||||
if len(descriptions) <= 0 {
|
||||
containers = append(containers, &discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.Section{
|
||||
Accessory: accessory,
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.TextDisplay{
|
||||
Content: utils.MakeDesc(defaultDesc, "없음"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for _, desc := range descriptions {
|
||||
containers = append(containers, &discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.Section{
|
||||
Accessory: accessory,
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.TextDisplay{
|
||||
Content: utils.MakeDesc(defaultDesc, desc),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return containers
|
||||
}
|
||||
|
||||
func learnedDataListRun(m any, globalName, avatarUrl string, filter bson.D, length int) {
|
||||
func learnedDataListRun(s *discordgo.Session, m any, args *[]string) {
|
||||
var globalName, avatarUrl string
|
||||
var data []databases.Learn
|
||||
var filter bson.D
|
||||
var length int
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
filter = bson.D{{Key: "user_id", Value: m.Author.ID}}
|
||||
globalName = m.Author.GlobalName
|
||||
avatarUrl = m.Author.AvatarURL("512")
|
||||
|
||||
query := strings.Join(*args, " ")
|
||||
|
||||
if match := utils.RegexpLearnQueryCommand.FindStringSubmatch(query); match != nil {
|
||||
filter = append(filter, bson.E{
|
||||
Key: "command",
|
||||
Value: bson.M{
|
||||
"$regex": match[1],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if match := utils.RegexpLearnQueryResult.FindStringSubmatch(query); match != nil {
|
||||
filter = append(filter, bson.E{
|
||||
Key: "result",
|
||||
Value: bson.M{
|
||||
"$regex": match[1],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if match := utils.RegexpLearnQueryLength.FindStringSubmatch(query); match != nil {
|
||||
var err error
|
||||
length, err = strconv.Atoi(match[1])
|
||||
|
||||
if err != nil {
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "개수의 값은 숫자여야해요.",
|
||||
Color: utils.EmbedFail,
|
||||
}, m.Reference())
|
||||
return
|
||||
}
|
||||
|
||||
if float64(length) < LIST_MIN_VALUE {
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: fmt.Sprintf("개수의 값은 %d보다 커야해요.", int(LIST_MIN_VALUE)),
|
||||
Color: utils.EmbedFail,
|
||||
}, m.Reference())
|
||||
return
|
||||
}
|
||||
|
||||
if float64(length) > LIST_MAX_VALUE {
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: fmt.Sprintf("개수의 값은 %d보다 작아야해요.", int(LIST_MAX_VALUE)),
|
||||
Color: utils.EmbedFail,
|
||||
}, m.Reference())
|
||||
return
|
||||
}
|
||||
}
|
||||
case *utils.InteractionCreate:
|
||||
m.DeferReply(true)
|
||||
|
||||
filter = bson.D{{Key: "user_id", Value: m.Member.User.ID}}
|
||||
globalName = m.Member.User.GlobalName
|
||||
avatarUrl = m.Member.User.AvatarURL("512")
|
||||
|
||||
if opt, ok := m.Options["단어"]; ok {
|
||||
filter = append(filter, bson.E{
|
||||
Key: "command",
|
||||
Value: bson.M{
|
||||
"$regex": opt.StringValue(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if opt, ok := m.Options["대답"]; ok {
|
||||
filter = append(filter, bson.E{
|
||||
Key: "result",
|
||||
Value: bson.M{
|
||||
"$regex": opt.StringValue(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if opt, ok := m.Options["개수"]; ok {
|
||||
length = int(opt.IntValue())
|
||||
}
|
||||
}
|
||||
|
||||
cur, err := databases.Database.Learns.Find(context.TODO(), filter)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "당신은 지식ㅇ을 가르쳐준 적이 없어요!"})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "당신은 지식ㅇ을 가르쳐준 적이 없어요!",
|
||||
Color: utils.EmbedFail,
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(err)
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: "❌ 오류",
|
||||
Description: "데이터를 가져오는데 실패했어요.",
|
||||
Color: utils.EmbedFail,
|
||||
}
|
||||
|
||||
utils.NewMessageSender(m).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "데이터를 가져오는데 실패했어요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendEmbedReply(m.ChannelID, embed, m.Reference())
|
||||
case *utils.InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{embed},
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -245,13 +240,13 @@ func learnedDataListRun(m any, globalName, avatarUrl string, filter bson.D, leng
|
|||
|
||||
cur.All(context.TODO(), &data)
|
||||
|
||||
containers := getContainers(&discordgo.Thumbnail{
|
||||
Media: discordgo.UnfurledMediaItem{
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Title: fmt.Sprintf("%s님이 알려주신 지식", globalName),
|
||||
Color: utils.EmbedDefault,
|
||||
Thumbnail: &discordgo.MessageEmbedThumbnail{
|
||||
URL: avatarUrl,
|
||||
},
|
||||
}, fmt.Sprintf("### %s님이 알려주신 지식\n%s", globalName, utils.CodeBlock("md", fmt.Sprintf("# 총 %d개에요.\n", len(data))+"%s")), &data, length)
|
||||
}
|
||||
|
||||
utils.PaginationEmbedBuilder(m).
|
||||
AddContainers(containers...).
|
||||
Start()
|
||||
utils.StartPaginationEmbed(s, m, embed, getDescriptions(&data, length), utils.CodeBlock("md", fmt.Sprintf("# 총 %d개에요.\n", len(data))+"%s"))
|
||||
}
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/chatbot"
|
||||
"git.wh64.net/muffin/goMuffin/configs"
|
||||
"git.wh64.net/muffin/goMuffin/utils"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
var ReloadPromptCommand *Command = &Command{
|
||||
ApplicationCommand: &discordgo.ApplicationCommand{
|
||||
Name: "프롬프트재설정",
|
||||
Description: "프롬프트를 다시 불러와요.",
|
||||
},
|
||||
DetailedDescription: &DetailedDescription{
|
||||
Usage: fmt.Sprintf("%s프롬프트재설정", configs.Config.Bot.Prefix),
|
||||
},
|
||||
Category: DeveloperOnly,
|
||||
RegisterApplicationCommand: false,
|
||||
RegisterMessageCommand: true,
|
||||
MessageRun: func(ctx *MsgContext) {
|
||||
err := chatbot.ChatBot.ReloadPrompt()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
utils.NewMessageSender(ctx.Msg).
|
||||
AddComponents(utils.GetErrorContainer(discordgo.TextDisplay{Content: "프롬프트를 다시 불러오는 데 문제가 생겼어요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
return
|
||||
}
|
||||
|
||||
utils.NewMessageSender(ctx.Msg).
|
||||
AddComponents(utils.GetSuccessContainer(discordgo.TextDisplay{Content: "프롬프트를 다시 불러왔어요."})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
},
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/chatbot"
|
||||
"git.wh64.net/muffin/goMuffin/configs"
|
||||
"git.wh64.net/muffin/goMuffin/utils"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
var SwitchModeCommand *Command = &Command{
|
||||
ApplicationCommand: &discordgo.ApplicationCommand{
|
||||
Name: "모드전환",
|
||||
Description: "머핀봇의 대답을 변경합니다.",
|
||||
},
|
||||
DetailedDescription: &DetailedDescription{
|
||||
Usage: fmt.Sprintf("%s모드전환", configs.Config.Bot.Prefix),
|
||||
},
|
||||
Category: DeveloperOnly,
|
||||
RegisterApplicationCommand: false,
|
||||
RegisterMessageCommand: true,
|
||||
MessageRun: func(ctx *MsgContext) {
|
||||
chatbot.ChatBot.SwitchMode()
|
||||
|
||||
utils.NewMessageSender(ctx.Msg).
|
||||
AddComponents(utils.GetSuccessContainer(discordgo.TextDisplay{Content: fmt.Sprintf("모드를 %s로 바꾸었어요.", chatbot.ChatBot.ModeString())})).
|
||||
SetComponentsV2(true).
|
||||
SetReply(true).
|
||||
Send()
|
||||
},
|
||||
}
|
|
@ -14,20 +14,47 @@ import (
|
|||
|
||||
var DeleteLearnedDataComponent *commands.Component = &commands.Component{
|
||||
Parse: func(ctx *commands.ComponentContext) bool {
|
||||
var userId string
|
||||
i := ctx.Inter
|
||||
customId := i.MessageComponentData().CustomID
|
||||
|
||||
if !strings.HasPrefix(customId, utils.DeleteLearnedData) {
|
||||
return false
|
||||
if i.MessageComponentData().ComponentType == discordgo.ButtonComponent {
|
||||
if !strings.HasPrefix(customId, utils.DeleteLearnedDataCancel) {
|
||||
return false
|
||||
}
|
||||
|
||||
userId = utils.GetDeleteLearnedDataUserId(customId)
|
||||
if i.Member.User.ID == userId {
|
||||
i.Update(&discordgo.InteractionResponseData{
|
||||
Embeds: []*discordgo.MessageEmbed{
|
||||
{
|
||||
Title: "❌ 취소",
|
||||
Description: "지식 삭제 작업ㅇ을 취소했어요.",
|
||||
Color: utils.EmbedFail,
|
||||
},
|
||||
},
|
||||
})
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if !strings.HasPrefix(customId, utils.DeleteLearnedDataUserId) {
|
||||
return false
|
||||
}
|
||||
|
||||
userId = utils.GetDeleteLearnedDataUserId(customId)
|
||||
}
|
||||
|
||||
userId := utils.GetDeleteLearnedDataUserId(customId)
|
||||
if i.Member.User.ID != userId {
|
||||
i.Reply(&discordgo.InteractionResponseData{
|
||||
Flags: discordgo.MessageFlagsEphemeral | discordgo.MessageFlagsIsComponentsV2,
|
||||
Components: []discordgo.MessageComponent{
|
||||
utils.GetErrorContainer(discordgo.TextDisplay{Content: "당신은 해당 권한이 없ㅇ어요."}),
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
Embeds: []*discordgo.MessageEmbed{
|
||||
{
|
||||
Title: "❌ 오류",
|
||||
Description: "당신은 해당 권한이 없ㅇ어요.",
|
||||
Color: utils.EmbedFail,
|
||||
},
|
||||
},
|
||||
Components: []discordgo.MessageComponent{},
|
||||
},
|
||||
)
|
||||
return false
|
||||
|
@ -39,17 +66,19 @@ var DeleteLearnedDataComponent *commands.Component = &commands.Component{
|
|||
|
||||
i.DeferUpdate()
|
||||
|
||||
id, itemId := utils.GetDeleteLearnedDataId(i.MessageComponentData().CustomID)
|
||||
fmt.Println(id, itemId)
|
||||
id, itemId := utils.GetDeleteLearnedDataId(i.MessageComponentData().Values[0])
|
||||
|
||||
databases.Database.Learns.DeleteOne(context.TODO(), bson.D{{Key: "_id", Value: id}})
|
||||
|
||||
flags := discordgo.MessageFlagsIsComponentsV2
|
||||
i.EditReply(&utils.InteractionEdit{
|
||||
Flags: &flags,
|
||||
Components: &[]discordgo.MessageComponent{
|
||||
utils.GetSuccessContainer(discordgo.TextDisplay{Content: fmt.Sprintf("%d번을 삭ㅈ제했어요.", itemId)}),
|
||||
i.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{
|
||||
{
|
||||
Title: "✅ 삭제 완료",
|
||||
Description: fmt.Sprintf("%d번을 삭ㅈ제했어요.", itemId),
|
||||
Color: utils.EmbedSuccess,
|
||||
},
|
||||
},
|
||||
Components: &[]discordgo.MessageComponent{},
|
||||
})
|
||||
},
|
||||
}
|
||||
|
|
|
@ -16,18 +16,7 @@ type botConfig struct {
|
|||
}
|
||||
|
||||
type trainConfig struct {
|
||||
UserId string
|
||||
}
|
||||
|
||||
type geminiConfig struct {
|
||||
Token string
|
||||
PromptPath string
|
||||
Model string
|
||||
}
|
||||
|
||||
type chatbotConfig struct {
|
||||
Train trainConfig
|
||||
Gemini geminiConfig
|
||||
UserID string
|
||||
}
|
||||
|
||||
type databaseConfig struct {
|
||||
|
@ -43,18 +32,21 @@ type databaseConfig struct {
|
|||
// MuffinConfig for Muffin bot
|
||||
type MuffinConfig struct {
|
||||
Bot botConfig
|
||||
Train trainConfig
|
||||
Database databaseConfig
|
||||
Chatbot chatbotConfig
|
||||
|
||||
// Deprecated: Use Chatbot.Train
|
||||
Train trainConfig
|
||||
// Deprecated: Use Database.URL
|
||||
DatabaseURL string
|
||||
|
||||
// Deprecated: Use Database.Name
|
||||
DatabaseName string
|
||||
}
|
||||
|
||||
var Config *MuffinConfig
|
||||
|
||||
func init() {
|
||||
godotenv.Load()
|
||||
Config = &MuffinConfig{}
|
||||
Config = &MuffinConfig{Bot: botConfig{}, Train: trainConfig{}, Database: databaseConfig{}}
|
||||
setConfig(Config)
|
||||
}
|
||||
|
||||
|
@ -71,22 +63,20 @@ func getValue(key string) string {
|
|||
}
|
||||
|
||||
func setConfig(config *MuffinConfig) {
|
||||
config.Bot = botConfig{
|
||||
Prefix: getRequiredValue("BOT_PREFIX"),
|
||||
Token: getRequiredValue("BOT_TOKEN"),
|
||||
OwnerId: getRequiredValue("BOT_OWNER_ID"),
|
||||
}
|
||||
config.Bot.Prefix = getRequiredValue("BOT_PREFIX")
|
||||
config.Bot.Token = getRequiredValue("BOT_TOKEN")
|
||||
config.Bot.OwnerId = getRequiredValue("BOT_OWNER_ID")
|
||||
|
||||
config.Database = databaseConfig{
|
||||
URL: getValue("DATABASE_URL"),
|
||||
HostName: getValue("DATABASE_HOSTNAME"),
|
||||
Password: getValue("DATABASE_PASSWORD"),
|
||||
Username: getValue("DATABASE_USERNAME"),
|
||||
AuthSource: getValue("DATABASE_AUTH_SOURCE"),
|
||||
Name: getRequiredValue("DATABASE_NAME"),
|
||||
}
|
||||
config.Train.UserID = getValue("TRAIN_USER_ID")
|
||||
|
||||
config.Database.URL = getValue("DATABASE_URL")
|
||||
config.Database.HostName = getValue("DATABASE_HOSTNAME")
|
||||
config.Database.Password = getValue("DATABASE_PASSWORD")
|
||||
config.Database.Username = getValue("DATABASE_USERNAME")
|
||||
config.Database.AuthSource = getValue("DATABASE_AUTH_SOURCE")
|
||||
config.Database.Name = getRequiredValue("DATABASE_NAME")
|
||||
port, err := strconv.Atoi(getValue("DATABASE_PORT"))
|
||||
if getValue("DATABASE_PORT") != "" && err != nil {
|
||||
if err != nil {
|
||||
log.Println("[goMuffin] 'DATABASE_PORT'값을 int로 파싱할 수 없어요.")
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
@ -101,14 +91,7 @@ func setConfig(config *MuffinConfig) {
|
|||
config.Database.URL = fmt.Sprintf("mongodb://%s:%s@%s:%d/?authSource=%s", config.Database.Username, config.Database.Password, config.Database.HostName, config.Database.Port, config.Database.AuthSource)
|
||||
}
|
||||
|
||||
config.Chatbot = chatbotConfig{
|
||||
Gemini: geminiConfig{Token: getValue("CHATBOT_GEMINI_TOKEN"), PromptPath: getValue("CHATBOT_GEMINI_PROMPT_PATH"), Model: getValue("CHATBOT_GEMINI_MODEL")},
|
||||
Train: trainConfig{UserId: getValue("CHATBOT_TRAIN_USER_ID")},
|
||||
}
|
||||
|
||||
if config.Chatbot.Gemini.Model == "" {
|
||||
config.Chatbot.Gemini.Model = "gemini-2.0-flash"
|
||||
}
|
||||
|
||||
config.Train = config.Chatbot.Train
|
||||
// Deprecated된 Value
|
||||
config.DatabaseURL = config.Database.URL
|
||||
config.DatabaseName = config.Database.Name
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"git.wh64.net/muffin/goMuffin/utils"
|
||||
)
|
||||
|
||||
const MUFFIN_VERSION = "0.0.0-madeleine_canary.250604b-muffin-ai"
|
||||
const MUFFIN_VERSION = "5.1.1-gopher_release.250526a"
|
||||
|
||||
var updatedString string = utils.RegexpDecimals.FindAllStringSubmatch(MUFFIN_VERSION, -1)[3][0]
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package databases
|
||||
|
||||
import "go.mongodb.org/mongo-driver/v2/bson"
|
||||
|
||||
type InsertMemory struct {
|
||||
UserId string `bson:"user_id"`
|
||||
Content string `bson:"content"`
|
||||
Answer string `bson:"answer"`
|
||||
}
|
||||
|
||||
type Memory struct {
|
||||
Id bson.ObjectID `bson:"_id"`
|
||||
UserId string `bson:"user_id"`
|
||||
Content string `bson:"content"`
|
||||
Answer string `bson:"answer"`
|
||||
}
|
|
@ -12,7 +12,6 @@ type MuffinDatabase struct {
|
|||
Client *mongo.Client
|
||||
Learns *mongo.Collection
|
||||
Texts *mongo.Collection
|
||||
Memory *mongo.Collection
|
||||
}
|
||||
|
||||
var Database *MuffinDatabase
|
||||
|
@ -27,14 +26,13 @@ func init() {
|
|||
}
|
||||
|
||||
func Connect() (*MuffinDatabase, error) {
|
||||
client, err := mongo.Connect(options.Client().ApplyURI(configs.Config.Database.URL))
|
||||
client, err := mongo.Connect(options.Client().ApplyURI(configs.Config.DatabaseURL))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &MuffinDatabase{
|
||||
Client: client,
|
||||
Learns: client.Database(configs.Config.Database.Name).Collection("learn"),
|
||||
Texts: client.Database(configs.Config.Database.Name).Collection("text"),
|
||||
Memory: client.Database(configs.Config.Database.Name).Collection("memory"),
|
||||
Learns: client.Database(configs.Config.DatabaseName).Collection("learn"),
|
||||
Texts: client.Database(configs.Config.DatabaseName).Collection("text"),
|
||||
}, nil
|
||||
}
|
||||
|
|
17
go.mod
17
go.mod
|
@ -4,35 +4,24 @@ go 1.24.1
|
|||
|
||||
require (
|
||||
github.com/LoperLee/golang-hangul-toolkit v1.1.0
|
||||
github.com/bwmarrin/discordgo v0.28.2-0.20250520184322-b9883c495955
|
||||
github.com/bwmarrin/discordgo v0.28.1
|
||||
github.com/devproje/commando v0.1.0-alpha.1
|
||||
github.com/go-sql-driver/mysql v1.9.2
|
||||
github.com/joho/godotenv v1.5.1
|
||||
go.mongodb.org/mongo-driver/v2 v2.1.0
|
||||
google.golang.org/genai v1.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.116.0 // indirect
|
||||
cloud.google.com/go/auth v0.9.3 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.5.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/s2a-go v0.1.8 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/net v0.29.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/grpc v1.66.2 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
)
|
||||
|
|
115
go.sum
115
go.sum
|
@ -1,56 +1,19 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
|
||||
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
|
||||
cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U=
|
||||
cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk=
|
||||
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
|
||||
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/LoperLee/golang-hangul-toolkit v1.1.0 h1:JEyLpLyA2hDQwWY9oCprHClnKIdkYVOSJzAat2uFX/A=
|
||||
github.com/LoperLee/golang-hangul-toolkit v1.1.0/go.mod h1:CDbZ23/IL4v2ovWIOb7xDEiFcSc0pIIbbYTpg+gP+Sk=
|
||||
github.com/bwmarrin/discordgo v0.28.2-0.20250520184322-b9883c495955 h1:ReUA/wL53HdO2jlzwwl5kVa2UJInBtHzqrvf3eVTEvk=
|
||||
github.com/bwmarrin/discordgo v0.28.2-0.20250520184322-b9883c495955/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4=
|
||||
github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/devproje/commando v0.1.0-alpha.1 h1:JU6CKIdt1otjUKh+asCJC0yTzwVj+4Yh8KoTdzaKAkU=
|
||||
github.com/devproje/commando v0.1.0-alpha.1/go.mod h1:OhrPX3mZUGSyEX/E7d1o0vaQIYkjG/N5rk6Nqwgyc7k=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
|
||||
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
|
@ -58,14 +21,6 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
|||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
|
@ -77,41 +32,20 @@ github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfS
|
|||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver/v2 v2.1.0 h1:/ELnVNjmfUKDsoBisXxuJL0noR9CfeUIrP7Yt3R+egg=
|
||||
go.mongodb.org/mongo-driver/v2 v2.1.0/go.mod h1:AWiLRShSrk5RHQS3AEn3RL19rqOzVq49MCpWQ3x/huI=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -127,43 +61,6 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
|||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genai v1.6.0 h1:aG0J3QF/Ad2GsjHvY8LjRp9hiDl4hvLJN98YwkLDqFE=
|
||||
google.golang.org/genai v1.6.0/go.mod h1:TyfOKRz/QyCaj6f/ZDt505x+YreXnY40l2I6k8TvgqY=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
|
||||
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
@ -2,16 +2,19 @@ package handler
|
|||
|
||||
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"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo"
|
||||
)
|
||||
|
||||
func argParser(content string) (args []string) {
|
||||
|
@ -25,6 +28,25 @@ func argParser(content string) (args []string) {
|
|||
return
|
||||
}
|
||||
|
||||
func resultParser(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
|
||||
}
|
||||
|
||||
// MessageCreate is handlers of messageCreate event
|
||||
func MessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
config := configs.Config
|
||||
|
@ -37,37 +59,96 @@ func MessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|||
args := argParser(content)
|
||||
command := commands.Discommand.Aliases[args[0]]
|
||||
|
||||
if command == "" || command == "대화" {
|
||||
if command == "" {
|
||||
s.ChannelTyping(m.ChannelID)
|
||||
|
||||
str, err := chatbot.ChatBot.GetResponse(m.Author, strings.TrimPrefix(content, "대화 "))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
utils.NewMessageSender(&utils.MessageCreate{
|
||||
MessageCreate: m,
|
||||
Session: s,
|
||||
}).
|
||||
SetContent(str).
|
||||
SetReply(true).
|
||||
Send()
|
||||
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 {
|
||||
if err == mongo.ErrNilDocument {
|
||||
learnData = []databases.Learn{}
|
||||
}
|
||||
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)
|
||||
|
||||
s.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{
|
||||
Reference: m.Reference(),
|
||||
Content: fmt.Sprintf("%s\n%s", result, utils.InlineCode(fmt.Sprintf("%s님이 알려주셨어요.", user.Username))),
|
||||
AllowedMentions: &discordgo.MessageAllowedMentions{
|
||||
Roles: []string{},
|
||||
Parse: []discordgo.AllowedMentionType{},
|
||||
Users: []string{},
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result := chatbot.ParseResult(str, s, m)
|
||||
utils.NewMessageSender(&utils.MessageCreate{
|
||||
MessageCreate: m,
|
||||
Session: s,
|
||||
}).
|
||||
SetContent(result).
|
||||
SetReply(true).
|
||||
Send()
|
||||
s.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{
|
||||
Reference: m.Reference(),
|
||||
Content: data[rand.Intn(len(data))].Text,
|
||||
AllowedMentions: &discordgo.MessageAllowedMentions{
|
||||
Roles: []string{},
|
||||
Parse: []discordgo.AllowedMentionType{},
|
||||
Users: []string{},
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
commands.Discommand.MessageRun(command, s, m, args[1:])
|
||||
return
|
||||
} else {
|
||||
if m.Author.ID == config.Chatbot.Train.UserId {
|
||||
if m.Author.ID == config.Train.UserID {
|
||||
if _, err := databases.Database.Texts.InsertOne(context.TODO(), databases.InsertText{
|
||||
Text: m.Content,
|
||||
Persona: "muffin",
|
||||
|
|
39
main.go
39
main.go
|
@ -9,7 +9,6 @@ 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"
|
||||
|
@ -22,28 +21,12 @@ import (
|
|||
"github.com/devproje/commando/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
go commands.Discommand.LoadCommand(commands.HelpCommand)
|
||||
go commands.Discommand.LoadCommand(commands.DataLengthCommand)
|
||||
go commands.Discommand.LoadCommand(commands.LearnCommand)
|
||||
go commands.Discommand.LoadCommand(commands.LearnedDataListCommand)
|
||||
go commands.Discommand.LoadCommand(commands.InformationCommand)
|
||||
go commands.Discommand.LoadCommand(commands.DeleteLearnedDataCommand)
|
||||
go commands.Discommand.LoadCommand(commands.ReloadPromptCommand)
|
||||
go commands.Discommand.LoadCommand(commands.SwitchModeCommand)
|
||||
go commands.Discommand.LoadCommand(commands.ChatCommand)
|
||||
|
||||
go commands.Discommand.LoadComponent(components.DeleteLearnedDataComponent)
|
||||
go commands.Discommand.LoadComponent(components.PaginationEmbedComponent)
|
||||
|
||||
go commands.Discommand.LoadModal(modals.PaginationEmbedModal)
|
||||
}
|
||||
|
||||
func main() {
|
||||
command := commando.NewCommando(os.Args[1:])
|
||||
config := configs.Config
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
command.Root("db-migrate", "봇의 데이터를 MariaDB에서 MongoDB로 옮깁니다.", scripts.DBMigrate)
|
||||
command.Root("delete-all-commands", "봇의 모든 슬래시 커맨드를 삭제합니다.", scripts.DeleteAllCommands,
|
||||
types.OptionData{
|
||||
Name: "id",
|
||||
|
@ -60,7 +43,7 @@ func main() {
|
|||
command.Root("export", "머핀봇의 데이터를 추출합니다.", scripts.ExportData,
|
||||
types.OptionData{
|
||||
Name: "type",
|
||||
Desc: "파일형식을 지정합니다. (json, jsonl, finetune)",
|
||||
Desc: "파일형식을 지정합니다. (json, txt(txt는 머핀 데이터만 적용))",
|
||||
Type: types.STRING,
|
||||
},
|
||||
types.OptionData{
|
||||
|
@ -85,6 +68,18 @@ func main() {
|
|||
|
||||
dg, _ := discordgo.New("Bot " + config.Bot.Token)
|
||||
|
||||
go commands.Discommand.LoadCommand(commands.HelpCommand)
|
||||
go commands.Discommand.LoadCommand(commands.DataLengthCommand)
|
||||
go commands.Discommand.LoadCommand(commands.LearnCommand)
|
||||
go commands.Discommand.LoadCommand(commands.LearnedDataListCommand)
|
||||
go commands.Discommand.LoadCommand(commands.InformationCommand)
|
||||
go commands.Discommand.LoadCommand(commands.DeleteLearnedDataCommand)
|
||||
|
||||
go commands.Discommand.LoadComponent(components.DeleteLearnedDataComponent)
|
||||
go commands.Discommand.LoadComponent(components.PaginationEmbedComponent)
|
||||
|
||||
go commands.Discommand.LoadModal(modals.PaginationEmbedModal)
|
||||
|
||||
go dg.AddHandler(handler.MessageCreate)
|
||||
go dg.AddHandler(handler.InteractionCreate)
|
||||
|
||||
|
@ -94,8 +89,6 @@ func main() {
|
|||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
chatbot.New(dg)
|
||||
|
||||
defer dg.Close()
|
||||
|
||||
// 봇의 상태메세지 변경
|
||||
|
@ -118,10 +111,6 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
if !cmd.RegisterApplicationCommand {
|
||||
continue
|
||||
}
|
||||
|
||||
go dg.ApplicationCommandCreate(dg.State.User.ID, "", cmd.ApplicationCommand)
|
||||
}
|
||||
|
||||
|
|
196
scripts/dbMigrate.go
Normal file
196
scripts/dbMigrate.go
Normal file
|
@ -0,0 +1,196 @@
|
|||
package scripts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.wh64.net/muffin/goMuffin/configs"
|
||||
|
||||
"github.com/devproje/commando"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
||||
)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 이 스크립트는 MariaDB -> MongoDB로의 전환을 위해 만들었음.
|
||||
func DBMigrate(n *commando.Node) error {
|
||||
mariaURL := os.Getenv("PREVIOUS_DATABASE_URL")
|
||||
mongoURL := configs.Config.DatabaseURL
|
||||
dbName := configs.Config.DatabaseName
|
||||
|
||||
dbConnectionQuery := "?parseTime=true"
|
||||
|
||||
wg.Add(3)
|
||||
|
||||
fmt.Println("[경고] 해당 명령어는 다음 버전에서 사라져요.")
|
||||
|
||||
// statement -> text
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
newDataList := []any{}
|
||||
mariaDB, err := sql.Open("mysql", mariaURL+dbConnectionQuery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mongoDB, err := mongo.Connect(options.Client().ApplyURI(mongoURL))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer mongoDB.Disconnect(context.TODO())
|
||||
defer mariaDB.Close()
|
||||
rows, err := mariaDB.Query("select text, persona, created_at from statement;")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
i := 1
|
||||
|
||||
for rows.Next() {
|
||||
var text, persona string
|
||||
var createdAt time.Time
|
||||
|
||||
fmt.Printf("statement %d\n", i)
|
||||
err = rows.Scan(&text, &persona, &createdAt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if text == "" {
|
||||
text = "살ㄹ려주세요"
|
||||
}
|
||||
|
||||
newDataList = append(newDataList, bson.M{
|
||||
"text": text,
|
||||
"persona": persona,
|
||||
"created_at": createdAt,
|
||||
})
|
||||
i++
|
||||
}
|
||||
_, err = mongoDB.Database(dbName).Collection("text").InsertMany(context.TODO(), newDataList)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// nsfw_content -> text
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
newDataList := []any{}
|
||||
mariaDB, err := sql.Open("mysql", mariaURL+dbConnectionQuery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mongoDB, err := mongo.Connect(options.Client().ApplyURI(mongoURL))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer mongoDB.Disconnect(context.TODO())
|
||||
defer mariaDB.Close()
|
||||
rows, err := mariaDB.Query("select text, persona, created_at from nsfw_content;")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
i := 1
|
||||
|
||||
for rows.Next() {
|
||||
var text, persona string
|
||||
var createdAt time.Time
|
||||
|
||||
fmt.Printf("nsfw_content %d\n", i)
|
||||
err = rows.Scan(&text, &persona, &createdAt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if text == "" {
|
||||
text = "살ㄹ려주세요"
|
||||
}
|
||||
|
||||
newDataList = append(newDataList, bson.M{
|
||||
"text": text,
|
||||
"persona": persona,
|
||||
"created_at": createdAt,
|
||||
})
|
||||
i++
|
||||
}
|
||||
|
||||
_, err = mongoDB.Database(dbName).Collection("text").InsertMany(context.TODO(), newDataList)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// learn -> learn
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
newDataList := []any{}
|
||||
mariaDB, err := sql.Open("mysql", mariaURL+dbConnectionQuery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mongoDB, err := mongo.Connect(options.Client().ApplyURI(mongoURL))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer mongoDB.Disconnect(context.TODO())
|
||||
defer mariaDB.Close()
|
||||
rows, err := mariaDB.Query("select command, result, user_id, created_at from learn;")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
i := 1
|
||||
|
||||
for rows.Next() {
|
||||
var command, result, userId string
|
||||
var createdAt time.Time
|
||||
|
||||
fmt.Printf("learn %d\n", i)
|
||||
err = rows.Scan(&command, &result, &userId, &createdAt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
newDataList = append(newDataList, bson.M{
|
||||
"command": command,
|
||||
"result": result,
|
||||
"user_id": userId,
|
||||
"created_at": createdAt,
|
||||
})
|
||||
i++
|
||||
}
|
||||
|
||||
_, err = mongoDB.Database(dbName).Collection("learn").InsertMany(context.TODO(), newDataList)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 모든 고루틴이 끝날 떄 까지 대기
|
||||
wg.Wait()
|
||||
fmt.Println("데이터 마이그레이션이 끝났어요.")
|
||||
return nil
|
||||
}
|
|
@ -17,7 +17,7 @@ import (
|
|||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
type role string
|
||||
var date time.Time = time.Now()
|
||||
|
||||
type textJSONLData struct {
|
||||
Text string `json:"text"`
|
||||
|
@ -29,26 +29,6 @@ type learnJSONLData struct {
|
|||
Result string `json:"result"`
|
||||
}
|
||||
|
||||
type fineTuneMessageData struct {
|
||||
Role role `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type fineTuneJSONLData struct {
|
||||
Messages []fineTuneMessageData `json:"messages"`
|
||||
}
|
||||
|
||||
var date time.Time = time.Now()
|
||||
|
||||
var (
|
||||
system role = "system"
|
||||
user role = "user"
|
||||
assistant role = "assistant"
|
||||
)
|
||||
|
||||
const SYSTEM_PROMPT = "당신은 머핀AI입니다. 질문을 최대한 분석하지 말고, 간단히하며, 고급 개념은 대답할 수 없습니다. " +
|
||||
"모르면 모른다고 말해도 괜찮습니다. 말투는 친근하되 존댓말을 사용하여야 합니다. 그리고 대답을 길게 하지 말아야 합니다. 그리고 약간 엉뚱한 면이 있어야 합니다."
|
||||
|
||||
func getDate() string {
|
||||
year := strconv.Itoa(date.Year())
|
||||
month := strconv.Itoa(int(date.Month()))
|
||||
|
@ -110,15 +90,26 @@ func saveFileToJSON(path, name string, data any) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func saveFileToJSONL[T any](path, name string, data []T) error {
|
||||
func saveFileToJSONL(path, name string, data any) error {
|
||||
var content string
|
||||
|
||||
for _, data := range data {
|
||||
bytes, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
switch data := data.(type) {
|
||||
case []textJSONLData:
|
||||
for _, data := range data {
|
||||
bytes, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content += string(bytes) + "\n"
|
||||
}
|
||||
case []learnJSONLData:
|
||||
for _, data := range data {
|
||||
bytes, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content += string(bytes) + "\n"
|
||||
}
|
||||
content += string(bytes) + "\n"
|
||||
}
|
||||
|
||||
f, err := os.Create(fmt.Sprintf("%s/%s.jsonl", path, name))
|
||||
|
@ -146,8 +137,8 @@ func ExportData(n *commando.Node) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if fileType != "json" && fileType != "jsonl" && fileType != "finetune" {
|
||||
return fmt.Errorf("파일 형식은 txt또는 json또는 jsonl, finetune이여야 해요")
|
||||
if fileType != "json" && fileType != "jsonl" {
|
||||
return fmt.Errorf("파일 형식은 txt또는 json또는 jsonl이여야 해요")
|
||||
}
|
||||
|
||||
refined, err := option.ParseBool(*n.MustGetOpt("refined"), n)
|
||||
|
@ -222,33 +213,6 @@ func ExportData(n *commando.Node) error {
|
|||
ch <- err
|
||||
return
|
||||
}
|
||||
} else if fileType == "finetune" {
|
||||
var newData []fineTuneJSONLData
|
||||
|
||||
for _, data := range data {
|
||||
newData = append(newData, fineTuneJSONLData{
|
||||
[]fineTuneMessageData{
|
||||
{
|
||||
Role: system,
|
||||
Content: SYSTEM_PROMPT,
|
||||
},
|
||||
{
|
||||
Role: user,
|
||||
Content: "",
|
||||
},
|
||||
{
|
||||
Role: assistant,
|
||||
Content: data.Text,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
err = saveFileToJSONL(path, "muffin-fine-tune", newData)
|
||||
if err != nil {
|
||||
ch <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("머핀 데이터 추출 완료")
|
||||
|
@ -258,10 +222,6 @@ func ExportData(n *commando.Node) error {
|
|||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
if fileType == "finetune" {
|
||||
return
|
||||
}
|
||||
|
||||
var data []databases.Text
|
||||
|
||||
cur, err := databases.Database.Texts.Find(context.TODO(), bson.D{
|
||||
|
@ -312,10 +272,6 @@ func ExportData(n *commando.Node) error {
|
|||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
if fileType == "finetune" {
|
||||
return
|
||||
}
|
||||
|
||||
var data []databases.Learn
|
||||
|
||||
cur, err := databases.Database.Learns.Find(context.TODO(), bson.D{{}})
|
||||
|
|
|
@ -9,7 +9,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
DeleteLearnedData = "#muffin/deleteLearnedData@"
|
||||
DeleteLearnedData = "#muffin/deleteLearnedData@"
|
||||
DeleteLearnedDataUserId = "#muffin/deleteLearnedData@"
|
||||
DeleteLearnedDataCancel = "#muffin/deleteLearnedData/cancel@"
|
||||
|
||||
PaginationEmbedPrev = "#muffin-pages/prev$"
|
||||
PaginationEmbedPages = "#muffin-pages/pages$"
|
||||
|
@ -18,19 +20,31 @@ const (
|
|||
PaginationEmbedSetPage = "#muffin-pages/modal/set$"
|
||||
)
|
||||
|
||||
func MakeDeleteLearnedData(id string, number int, userId string) string {
|
||||
return fmt.Sprintf("%sid=%s&no=%d&user_id=%s", DeleteLearnedData, id, number, userId)
|
||||
func MakeDeleteLearnedData(id string, number int) string {
|
||||
return fmt.Sprintf("%s%s&No.%d", DeleteLearnedData, id, number)
|
||||
}
|
||||
|
||||
func MakeDeleteLearnedDataUserId(userId string) string {
|
||||
return fmt.Sprintf("%s%s", DeleteLearnedDataUserId, userId)
|
||||
}
|
||||
|
||||
func MakeDeleteLearnedDataCancel(id string) string {
|
||||
return fmt.Sprintf("%s%s", DeleteLearnedDataCancel, id)
|
||||
}
|
||||
|
||||
func GetDeleteLearnedDataId(customId string) (id bson.ObjectID, itemId int) {
|
||||
id, _ = bson.ObjectIDFromHex(strings.ReplaceAll(RegexpDLDId.FindAllString(customId, 1)[0], "id=", ""))
|
||||
stringItemId := strings.ReplaceAll(RegexpDLDItemId.FindAllString(customId, 1)[0], "no=", "")
|
||||
id, _ = bson.ObjectIDFromHex(strings.ReplaceAll(RegexpItemId.ReplaceAllString(customId[len(DeleteLearnedData):], ""), "&", ""))
|
||||
stringItemId := strings.ReplaceAll(RegexpItemId.FindAllString(customId, 1)[0], "No.", "")
|
||||
itemId, _ = strconv.Atoi(stringItemId)
|
||||
return
|
||||
}
|
||||
|
||||
func GetDeleteLearnedDataUserId(customId string) string {
|
||||
return strings.ReplaceAll(RegexpDLDUserId.FindAllString(customId, 1)[0], "user_id=", "")
|
||||
if strings.HasPrefix(customId, DeleteLearnedDataCancel) {
|
||||
return customId[len(DeleteLearnedDataCancel):]
|
||||
} else {
|
||||
return customId[len(DeleteLearnedDataUserId):]
|
||||
}
|
||||
}
|
||||
|
||||
func MakePaginationEmbedPrev(id string) string {
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
package utils
|
||||
|
||||
import "github.com/bwmarrin/discordgo"
|
||||
|
||||
const (
|
||||
EmbedDefault int = 0xaddb87
|
||||
EmbedFail int = 0xff0000
|
||||
EmbedSuccess int = 0x00ff00
|
||||
)
|
||||
|
||||
func GetErrorContainer(components ...discordgo.MessageComponent) *discordgo.Container {
|
||||
c := &discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.TextDisplay{
|
||||
Content: "### ❌ 오류",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c.Components = append(c.Components, components...)
|
||||
return c
|
||||
}
|
||||
|
||||
func GetSuccessContainer(components ...discordgo.MessageComponent) *discordgo.Container {
|
||||
c := &discordgo.Container{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.TextDisplay{
|
||||
Content: "### ✅ 성공",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
c.Components = append(c.Components, components...)
|
||||
return c
|
||||
}
|
7
utils/embedColor.go
Normal file
7
utils/embedColor.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package utils
|
||||
|
||||
const (
|
||||
EmbedDefault int = 0xaddb87
|
||||
EmbedFail int = 0xff0000
|
||||
EmbedSuccess int = 0x00ff00
|
||||
)
|
|
@ -1,6 +1,12 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
|
@ -10,37 +16,20 @@ type ModalData struct {
|
|||
Components []discordgo.MessageComponent `json:"components"`
|
||||
}
|
||||
|
||||
type InteractionEdit struct {
|
||||
Content *string `json:"content,omitempty"`
|
||||
Components *[]discordgo.MessageComponent `json:"components,omitempty"`
|
||||
Embeds *[]*discordgo.MessageEmbed `json:"embeds,omitempty"`
|
||||
Flags *discordgo.MessageFlags `json:"flags,omitempty"`
|
||||
Attachments *[]*discordgo.MessageAttachment `json:"attachments,omitempty"`
|
||||
AllowedMentions *discordgo.MessageAllowedMentions `json:"allowed_mentions,omitempty"`
|
||||
}
|
||||
|
||||
// InteractionCreate custom data of discordgo.InteractionCreate
|
||||
type InteractionCreate struct {
|
||||
*discordgo.InteractionCreate
|
||||
Session *discordgo.Session
|
||||
// NOTE: It's only can ApplicationCommand
|
||||
Options map[string]*discordgo.ApplicationCommandInteractionDataOption
|
||||
Deferred bool
|
||||
Replied bool
|
||||
Options map[string]*discordgo.ApplicationCommandInteractionDataOption
|
||||
}
|
||||
|
||||
// Reply to this interaction.
|
||||
func (i *InteractionCreate) Reply(data *discordgo.InteractionResponseData) error {
|
||||
err := i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
func (i *InteractionCreate) Reply(data *discordgo.InteractionResponseData) {
|
||||
i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: data,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.Replied = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetInteractionOptions to this interaction.
|
||||
|
@ -54,54 +43,38 @@ func GetInteractionOptions(i *discordgo.InteractionCreate) map[string]*discordgo
|
|||
}
|
||||
|
||||
// DeferReply to this interaction.
|
||||
func (i *InteractionCreate) DeferReply(data *discordgo.InteractionResponseData) error {
|
||||
err := i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseDeferredChannelMessageWithSource,
|
||||
Data: data,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
func (i *InteractionCreate) DeferReply(ephemeral bool) {
|
||||
var flags discordgo.MessageFlags
|
||||
if ephemeral {
|
||||
flags = discordgo.MessageFlagsEphemeral
|
||||
}
|
||||
|
||||
i.Deferred = true
|
||||
return err
|
||||
i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseDeferredChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{
|
||||
Flags: flags,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// DeferUpdate to this interaction.
|
||||
func (i *InteractionCreate) DeferUpdate() error {
|
||||
err := i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
func (i *InteractionCreate) DeferUpdate() {
|
||||
i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseDeferredMessageUpdate,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.Deferred = true
|
||||
return err
|
||||
}
|
||||
|
||||
// EditReply to this interaction.
|
||||
func (i *InteractionCreate) EditReply(data *InteractionEdit) error {
|
||||
endpoint := discordgo.EndpointWebhookMessage(i.AppID, i.Token, "@original")
|
||||
|
||||
_, err := i.Session.RequestWithBucketID("PATCH", endpoint, *data, discordgo.EndpointWebhookToken("", ""))
|
||||
|
||||
i.Replied = true
|
||||
return err
|
||||
func (i *InteractionCreate) EditReply(data *discordgo.WebhookEdit) {
|
||||
i.Session.InteractionResponseEdit(i.Interaction, data)
|
||||
}
|
||||
|
||||
// Update to this interaction.
|
||||
func (i *InteractionCreate) Update(data *discordgo.InteractionResponseData) error {
|
||||
err := i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
func (i *InteractionCreate) Update(data *discordgo.InteractionResponseData) {
|
||||
i.Session.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseUpdateMessage,
|
||||
Data: data,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.Replied = true
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *InteractionCreate) ShowModal(data *ModalData) error {
|
||||
|
@ -112,8 +85,35 @@ func (i *InteractionCreate) ShowModal(data *ModalData) error {
|
|||
|
||||
reqData.Type = discordgo.InteractionResponseModal
|
||||
reqData.Data = *data
|
||||
bin, err := json.Marshal(reqData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint := discordgo.EndpointInteractionResponse(i.ID, i.Token)
|
||||
_, err := i.Session.RequestWithBucketID("POST", endpoint, reqData, endpoint)
|
||||
return err
|
||||
buf := bytes.NewBuffer(bin)
|
||||
|
||||
req, err := http.NewRequest("POST", discordgo.EndpointInteractionResponse(i.ID, i.Token), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", i.Session.Identify.Token)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp, err := i.Session.Client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
respBin, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("%s", string(respBin))
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
type MessageCreate struct {
|
||||
*discordgo.MessageCreate
|
||||
Session *discordgo.Session
|
||||
}
|
||||
|
||||
type MessageSender struct {
|
||||
Embeds []*discordgo.MessageEmbed
|
||||
Content string
|
||||
Components []discordgo.MessageComponent
|
||||
Ephemeral bool
|
||||
Reply bool
|
||||
ComponentsV2 bool
|
||||
AllowedMentions *discordgo.MessageAllowedMentions
|
||||
m any
|
||||
}
|
||||
|
||||
func NewMessageSender(m any) *MessageSender {
|
||||
return &MessageSender{m: m}
|
||||
}
|
||||
|
||||
func (s *MessageSender) AddEmbeds(embeds ...*discordgo.MessageEmbed) *MessageSender {
|
||||
s.Embeds = append(s.Embeds, embeds...)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *MessageSender) AddComponents(components ...discordgo.MessageComponent) *MessageSender {
|
||||
s.Components = append(s.Components, components...)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *MessageSender) SetContent(content string) *MessageSender {
|
||||
s.Content = content
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *MessageSender) SetEphemeral(ephemeral bool) *MessageSender {
|
||||
s.Ephemeral = ephemeral
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *MessageSender) SetReply(reply bool) *MessageSender {
|
||||
s.Reply = reply
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *MessageSender) SetAllowedMentions(allowedMentions discordgo.MessageAllowedMentions) *MessageSender {
|
||||
s.AllowedMentions = &allowedMentions
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *MessageSender) SetComponentsV2(componentsV2 bool) *MessageSender {
|
||||
s.ComponentsV2 = componentsV2
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *MessageSender) Send() error {
|
||||
var flags discordgo.MessageFlags
|
||||
|
||||
if s.ComponentsV2 {
|
||||
flags = flags | discordgo.MessageFlagsIsComponentsV2
|
||||
}
|
||||
|
||||
switch m := s.m.(type) {
|
||||
case *MessageCreate:
|
||||
var reference *discordgo.MessageReference = nil
|
||||
|
||||
if s.Reply {
|
||||
reference = m.Reference()
|
||||
}
|
||||
|
||||
_, err := m.Session.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{
|
||||
Content: s.Content,
|
||||
Embeds: s.Embeds,
|
||||
Components: s.Components,
|
||||
AllowedMentions: s.AllowedMentions,
|
||||
Flags: flags,
|
||||
Reference: reference,
|
||||
})
|
||||
return err
|
||||
case *InteractionCreate:
|
||||
if s.Ephemeral {
|
||||
flags = flags | discordgo.MessageFlagsEphemeral
|
||||
}
|
||||
|
||||
if m.Replied || m.Deferred {
|
||||
err := m.EditReply(&InteractionEdit{
|
||||
Content: &s.Content,
|
||||
Embeds: &s.Embeds,
|
||||
Components: &s.Components,
|
||||
Flags: &flags,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
err := m.Reply(&discordgo.InteractionResponseData{
|
||||
Content: s.Content,
|
||||
Embeds: s.Embeds,
|
||||
Components: s.Components,
|
||||
Flags: flags,
|
||||
})
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -9,81 +9,50 @@ import (
|
|||
|
||||
// PaginationEmbed is embed with page
|
||||
type PaginationEmbed struct {
|
||||
Container *discordgo.Container
|
||||
Containers []*discordgo.Container
|
||||
Current int
|
||||
Total int
|
||||
Id string
|
||||
m any
|
||||
Embed *discordgo.MessageEmbed
|
||||
Data []string
|
||||
Current int
|
||||
Total int
|
||||
id string
|
||||
desc string
|
||||
}
|
||||
|
||||
var PaginationEmbeds = make(map[string]*PaginationEmbed)
|
||||
|
||||
func PaginationEmbedBuilder(m any) *PaginationEmbed {
|
||||
var userId string
|
||||
|
||||
switch m := m.(type) {
|
||||
case *MessageCreate:
|
||||
userId = m.Author.ID
|
||||
case *InteractionCreate:
|
||||
userId = m.Member.User.ID
|
||||
}
|
||||
|
||||
id := fmt.Sprintf("%s/%d", userId, rand.Intn(100))
|
||||
return &PaginationEmbed{
|
||||
Current: 1,
|
||||
Id: id,
|
||||
m: m,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PaginationEmbed) SetContainer(container discordgo.Container) *PaginationEmbed {
|
||||
p.Container = &container
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PaginationEmbed) AddContainers(container ...*discordgo.Container) *PaginationEmbed {
|
||||
p.Total += len(container)
|
||||
p.Containers = append(p.Containers, container...)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PaginationEmbed) Start() error {
|
||||
return startPaginationEmbed(p)
|
||||
}
|
||||
|
||||
func makeComponents(id string, current, total int) *discordgo.ActionsRow {
|
||||
func makeComponents(id string, current, total int) *[]discordgo.MessageComponent {
|
||||
disabled := false
|
||||
|
||||
if total == 1 {
|
||||
disabled = true
|
||||
}
|
||||
|
||||
return &discordgo.ActionsRow{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.Button{
|
||||
Style: discordgo.PrimaryButton,
|
||||
Label: "이전",
|
||||
CustomID: MakePaginationEmbedPrev(id),
|
||||
Disabled: disabled,
|
||||
},
|
||||
discordgo.Button{
|
||||
Style: discordgo.SecondaryButton,
|
||||
Label: fmt.Sprintf("(%d/%d)", current, total),
|
||||
CustomID: MakePaginationEmbedPages(id),
|
||||
Disabled: disabled,
|
||||
},
|
||||
discordgo.Button{
|
||||
Style: discordgo.PrimaryButton,
|
||||
Label: "다음",
|
||||
CustomID: MakePaginationEmbedNext(id),
|
||||
Disabled: disabled,
|
||||
return &[]discordgo.MessageComponent{
|
||||
discordgo.ActionsRow{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.Button{
|
||||
Style: discordgo.PrimaryButton,
|
||||
Label: "이전",
|
||||
CustomID: MakePaginationEmbedPrev(id),
|
||||
Disabled: disabled,
|
||||
},
|
||||
discordgo.Button{
|
||||
Style: discordgo.SecondaryButton,
|
||||
Label: fmt.Sprintf("(%d/%d)", current, total),
|
||||
CustomID: MakePaginationEmbedPages(id),
|
||||
Disabled: disabled,
|
||||
},
|
||||
discordgo.Button{
|
||||
Style: discordgo.PrimaryButton,
|
||||
Label: "다음",
|
||||
CustomID: MakePaginationEmbedNext(id),
|
||||
Disabled: disabled,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func MakeDesc(desc, item string) string {
|
||||
func makeDesc(desc, item string) string {
|
||||
var newDesc string
|
||||
|
||||
if desc == "" {
|
||||
|
@ -94,19 +63,49 @@ func MakeDesc(desc, item string) string {
|
|||
return newDesc
|
||||
}
|
||||
|
||||
func startPaginationEmbed(p *PaginationEmbed) error {
|
||||
container := *p.Containers[0]
|
||||
container.Components = append(container.Components, makeComponents(p.Id, p.Current, p.Total))
|
||||
// StartPaginationEmbed starts new PaginationEmbed struct
|
||||
func StartPaginationEmbed(s *discordgo.Session, m any, e *discordgo.MessageEmbed, data []string, defaultDesc string) {
|
||||
var userId string
|
||||
|
||||
PaginationEmbeds[p.Id] = p
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
userId = m.Author.ID
|
||||
case *InteractionCreate:
|
||||
userId = m.Member.User.ID
|
||||
}
|
||||
|
||||
err := NewMessageSender(p.m).
|
||||
AddComponents(container).
|
||||
SetReply(true).
|
||||
SetEphemeral(true).
|
||||
SetComponentsV2(true).
|
||||
Send()
|
||||
return err
|
||||
id := fmt.Sprintf("%s/%d", userId, rand.Intn(12))
|
||||
p := &PaginationEmbed{
|
||||
Embed: e,
|
||||
Data: data,
|
||||
Current: 1,
|
||||
Total: len(data),
|
||||
id: id,
|
||||
desc: defaultDesc,
|
||||
}
|
||||
|
||||
if len(data) <= 0 {
|
||||
p.Embed.Description = makeDesc(p.desc, "없음")
|
||||
p.Total = 1
|
||||
} else {
|
||||
p.Embed.Description = makeDesc(p.desc, data[0])
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
s.ChannelMessageSendComplex(m.ChannelID, &discordgo.MessageSend{
|
||||
Reference: m.Reference(),
|
||||
Embeds: []*discordgo.MessageEmbed{p.Embed},
|
||||
Components: *makeComponents(id, p.Current, p.Total),
|
||||
})
|
||||
case *InteractionCreate:
|
||||
m.EditReply(&discordgo.WebhookEdit{
|
||||
Embeds: &[]*discordgo.MessageEmbed{p.Embed},
|
||||
Components: makeComponents(id, p.Current, p.Total),
|
||||
})
|
||||
}
|
||||
|
||||
PaginationEmbeds[id] = p
|
||||
}
|
||||
|
||||
func GetPaginationEmbed(id string) *PaginationEmbed {
|
||||
|
@ -119,77 +118,101 @@ func GetPaginationEmbed(id string) *PaginationEmbed {
|
|||
func (p *PaginationEmbed) Prev(i *InteractionCreate) {
|
||||
if p.Current == 1 {
|
||||
i.Reply(&discordgo.InteractionResponseData{
|
||||
Components: []discordgo.MessageComponent{
|
||||
GetErrorContainer(discordgo.TextDisplay{Content: "해당 페이지가 처음ㅇ이에요."}),
|
||||
Embeds: []*discordgo.MessageEmbed{
|
||||
{
|
||||
Title: "❌ 오류",
|
||||
Description: "해당 페이지가 처음ㅇ이에요.",
|
||||
Color: EmbedFail,
|
||||
},
|
||||
},
|
||||
Flags: discordgo.MessageFlagsEphemeral | discordgo.MessageFlagsIsComponentsV2,
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
p.Current -= 1
|
||||
|
||||
p.Set(i, p.Current)
|
||||
p.Embed.Description = makeDesc(p.desc, p.Data[p.Current-1])
|
||||
|
||||
i.Update(&discordgo.InteractionResponseData{
|
||||
Embeds: []*discordgo.MessageEmbed{p.Embed},
|
||||
Components: *makeComponents(p.id, p.Current, p.Total),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *PaginationEmbed) Next(i *InteractionCreate) {
|
||||
if p.Current >= p.Total {
|
||||
i.Reply(&discordgo.InteractionResponseData{
|
||||
Components: []discordgo.MessageComponent{
|
||||
GetErrorContainer(discordgo.TextDisplay{Content: "해당 페이지가 마지막ㅇ이에요."}),
|
||||
Embeds: []*discordgo.MessageEmbed{
|
||||
{
|
||||
Title: "❌ 오류",
|
||||
Description: "해당 페이지가 마지막ㅇ이에요.",
|
||||
Color: EmbedFail,
|
||||
},
|
||||
},
|
||||
Flags: discordgo.MessageFlagsEphemeral | discordgo.MessageFlagsIsComponentsV2,
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
p.Current += 1
|
||||
|
||||
p.Set(i, p.Current)
|
||||
p.Embed.Description = makeDesc(p.desc, p.Data[p.Current-1])
|
||||
|
||||
i.Update(&discordgo.InteractionResponseData{
|
||||
Embeds: []*discordgo.MessageEmbed{p.Embed},
|
||||
Components: *makeComponents(p.id, p.Current, p.Total),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *PaginationEmbed) Set(i *InteractionCreate, page int) error {
|
||||
func (p *PaginationEmbed) Set(i *InteractionCreate, page int) {
|
||||
if page <= 0 {
|
||||
i.Reply(&discordgo.InteractionResponseData{
|
||||
Components: []discordgo.MessageComponent{
|
||||
GetErrorContainer(discordgo.TextDisplay{Content: "해당 값은 0보다 커야해요."}),
|
||||
Embeds: []*discordgo.MessageEmbed{
|
||||
{
|
||||
Title: "❌ 오류",
|
||||
Description: "해당 값은 0보다 커야해요.",
|
||||
Color: EmbedFail,
|
||||
},
|
||||
},
|
||||
Flags: discordgo.MessageFlagsEphemeral | discordgo.MessageFlagsIsComponentsV2,
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
})
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
if page > p.Total {
|
||||
if page >= p.Total {
|
||||
i.Reply(&discordgo.InteractionResponseData{
|
||||
Components: []discordgo.MessageComponent{
|
||||
GetErrorContainer(discordgo.TextDisplay{Content: "해당 값은 총 페이지의 수보다 작아야해요."}),
|
||||
Embeds: []*discordgo.MessageEmbed{
|
||||
{
|
||||
Title: "❌ 오류",
|
||||
Description: "해당 값은 총 페이지의 수보다 작아야해요.",
|
||||
Color: EmbedFail,
|
||||
},
|
||||
},
|
||||
Flags: discordgo.MessageFlagsEphemeral | discordgo.MessageFlagsIsComponentsV2,
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
})
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
p.Current = page
|
||||
|
||||
container := *p.Containers[p.Current-1]
|
||||
container.Components = append(container.Components, makeComponents(p.Id, p.Current, p.Total))
|
||||
p.Embed.Description = makeDesc(p.desc, p.Data[p.Current-1])
|
||||
|
||||
err := i.Update(&discordgo.InteractionResponseData{
|
||||
Flags: discordgo.MessageFlagsIsComponentsV2,
|
||||
Components: []discordgo.MessageComponent{container},
|
||||
i.Update(&discordgo.InteractionResponseData{
|
||||
Embeds: []*discordgo.MessageEmbed{p.Embed},
|
||||
Components: *makeComponents(p.id, p.Current, p.Total),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PaginationEmbed) ShowModal(i *InteractionCreate) {
|
||||
i.ShowModal(&ModalData{
|
||||
CustomId: MakePaginationEmbedModal(p.Id),
|
||||
CustomId: MakePaginationEmbedModal(p.id),
|
||||
Title: fmt.Sprintf("%s의 리스트", i.Session.State.User.Username),
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.ActionsRow{
|
||||
Components: []discordgo.MessageComponent{
|
||||
discordgo.TextInput{
|
||||
CustomID: MakePaginationEmbedSetPage(p.Id),
|
||||
CustomID: MakePaginationEmbedSetPage(p.id),
|
||||
Label: "페이지",
|
||||
Style: discordgo.TextInputShort,
|
||||
Placeholder: "이동할 페이지를 여기에 적어주세요.",
|
||||
|
|
|
@ -5,9 +5,7 @@ import "regexp"
|
|||
var (
|
||||
RegexpFlexibleString = regexp.MustCompile(`[^\s"'「」«»]+|"([^"]*)"|'([^']*)'|「([^」]*)」|«([^»]*)»`)
|
||||
RegexpDecimals = regexp.MustCompile(`\d+`)
|
||||
RegexpDLDItemId = regexp.MustCompile(`no=\d+`)
|
||||
RegexpDLDUserId = regexp.MustCompile(`user_id=\d+`)
|
||||
RegexpDLDId = regexp.MustCompile(`id=[^&]*`)
|
||||
RegexpItemId = regexp.MustCompile(`No.\d+`)
|
||||
RegexpEmoji = regexp.MustCompile(`<a?:\w+:\d+>`)
|
||||
RegexpLearnQueryCommand = regexp.MustCompile(`단어:([^\n대답개수:]*)`)
|
||||
RegexpLearnQueryResult = regexp.MustCompile(`대답:([^\n단어개수:]*)`)
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package utils
|
||||
|
||||
import "fmt"
|
||||
|
||||
func AddPrefix(prefix string, arr []string) (newArr []string) {
|
||||
for _, item := range arr {
|
||||
newArr = append(newArr, fmt.Sprintf("%s%s", prefix, item))
|
||||
}
|
||||
return
|
||||
}
|
Loading…
Reference in a new issue