From 25af28e5ffe091345dfa0875087ca3662061f6e8 Mon Sep 17 00:00:00 2001 From: Siwoo Jeon Date: Wed, 7 May 2025 19:43:26 +0900 Subject: [PATCH] feat: add export muffin data --- .gitignore | 4 +- databases/Learn.go | 14 ++-- databases/Text.go | 12 ++-- main.go | 18 +++++ scripts/export.go | 169 +++++++++++++++++++++++++++++++++++++++++++++ utils/regexp.go | 1 + 6 files changed, 204 insertions(+), 14 deletions(-) create mode 100644 scripts/export.go diff --git a/.gitignore b/.gitignore index b8b14c5..9c95d85 100644 --- a/.gitignore +++ b/.gitignore @@ -124,4 +124,6 @@ $RECYCLE.BIN/ # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) # Config files *.env -!.env.example \ No newline at end of file +!.env.example + +export/ \ No newline at end of file diff --git a/databases/Learn.go b/databases/Learn.go index f0d25aa..b89efee 100644 --- a/databases/Learn.go +++ b/databases/Learn.go @@ -9,18 +9,18 @@ import ( ) type InsertLearn struct { - Command string - Result string + Command string `bson:"command"` + Result string `bson:"result"` UserId string `bson:"user_id"` CreatedAt time.Time `bson:"created_at"` } type Learn struct { - Id bson.ObjectID `bson:"_id"` - Command string - Result string - UserId string `bson:"user_id"` - CreatedAt time.Time `bson:"created_at"` + Id bson.ObjectID `bson:"_id" json:"id"` + Command string `bson:"command" json:"command"` + Result string `bson:"Result" json:"result"` + UserId string `bson:"user_id" json:"user_id"` + CreatedAt time.Time `bson:"created_at" json:"created_at"` } var Learns *mongo.Collection = Client.Database(configs.Config.DBName).Collection("learn") diff --git a/databases/Text.go b/databases/Text.go index 06dc147..fbff6b2 100644 --- a/databases/Text.go +++ b/databases/Text.go @@ -9,16 +9,16 @@ import ( ) type InsertText struct { - Text string - Persona string + Text string `bson:"text" json:"text"` + Persona string `bson:"persona" json:"persona"` CreatedAt time.Time `bson:"created_at"` } type Text struct { - Id bson.ObjectID `bson:"_id"` - Text string - Persona string - CreatedAt time.Time `bson:"created_at"` + Id bson.ObjectID `bson:"_id" json:"id"` + Text string `bson:"text" json:"text"` + Persona string `bson:"persona" json:"persona"` + CreatedAt time.Time `bson:"created_at" json:"created_at"` } var Texts *mongo.Collection = Client.Database(configs.Config.DBName).Collection("text") diff --git a/main.go b/main.go index 4f36f25..e53f1f5 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,24 @@ func main() { }, ) + command.Root("export", "머핀봇의 데이터를 추출합니다.", scripts.ExportData, + types.OptionData{ + Name: "type", + Desc: "파일형식을 지정합니다. (json, txt(txt는 머핀 데이터만 적용))", + Type: types.STRING, + }, + types.OptionData{ + Name: "export-path", + Desc: "데이터를 저장할 위치를 지정합니다.", + Type: types.STRING, + }, + types.OptionData{ + Name: "refined", + Desc: "머핀 데이터를 있는 그대로 추출할 지, 가려내서 추출할 지를 지정합니다.", + Type: types.BOOLEAN, + }, + ) + err := command.Execute() if err != nil { _, _ = fmt.Fprintln(os.Stderr, err) diff --git a/scripts/export.go b/scripts/export.go new file mode 100644 index 0000000..79f7676 --- /dev/null +++ b/scripts/export.go @@ -0,0 +1,169 @@ +package scripts + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strconv" + "strings" + "time" + + "git.wh64.net/muffin/goMuffin/databases" + "git.wh64.net/muffin/goMuffin/utils" + "github.com/devproje/commando" + "github.com/devproje/commando/option" + "go.mongodb.org/mongo-driver/v2/bson" +) + +var date time.Time = time.Now() + +func getDate() string { + year := strconv.Itoa(date.Year()) + month := strconv.Itoa(int(date.Month())) + day := strconv.Itoa(date.Day()) + hour := strconv.Itoa(date.Hour()) + minute := strconv.Itoa(date.Minute()) + sec := strconv.Itoa(date.Second()) + + if len(month) < 2 { + month = "0" + month + } + + if len(day) < 2 { + day = "0" + day + } + + if len(hour) < 2 { + hour = "0" + hour + } + + if len(minute) < 2 { + minute = "0" + minute + } + + if len(sec) < 2 { + sec = "0" + sec + } + return year + month + day + hour + minute + sec +} + +func checkDir(path string) error { + _, err := os.ReadDir(path) + if err != nil { + err = os.MkdirAll(path, os.ModePerm) + if err != nil { + return err + } + } + return nil +} + +func saveFileToJSON(path, name string, data any) error { + bytes, err := json.MarshalIndent(data, "", " ") + if err != nil { + return err + } + + path += getDate() + err = checkDir(path) + if err != nil { + return err + } + + f, err := os.Create(fmt.Sprintf("%s/%s.json", path, name)) + if err != nil { + return err + } + + defer f.Close() + + _, err = f.Write(bytes) + if err != nil { + return err + } + return nil +} + +func saveFileToTXT(path, name string, data []databases.Text) error { + var content string + + for _, data := range data { + content += data.Text + "\n" + } + + path += getDate() + err := checkDir(path) + if err != nil { + return err + } + + f, err := os.Create(fmt.Sprintf("%s/%s.txt", path, name)) + if err != nil { + return err + } + + defer f.Close() + + _, err = f.WriteString(content) + if err != nil { + return err + } + return nil +} + +func ExportData(n *commando.Node) error { + ch := make(chan error) + defer databases.Client.Disconnect(context.TODO()) + fileType, err := option.ParseString(*n.MustGetOpt("type"), n) + if err != nil { + return err + } + + if fileType != "txt" && fileType != "json" { + return fmt.Errorf("파일 형식은 txt또는 json이여야 해요") + } + + refined, err := option.ParseBool(*n.MustGetOpt("refined"), n) + if err != nil { + return err + } + + path, err := option.ParseString(*n.MustGetOpt("export-path"), n) + if err != nil { + return err + } + + texts := databases.Texts + // learns := databases.Learns + + // 머핀 데이터 추출 + go func() { + var data []databases.Text + + cur, err := texts.Find(context.TODO(), bson.D{{Key: "persona", Value: "muffin"}}) + if err != nil { + ch <- err + } + + cur.All(context.TODO(), &data) + + if refined { + for i, text := range data { + if utils.EmojiRegexp.Match([]byte(text.Text)) { + data = append(data[:i], data[i+1:]...) + } + + text.Text = strings.TrimPrefix(text.Text, "머핀아 ") + } + } + + if fileType == "json" { + ch <- saveFileToJSON(path, "muffin", data) + } else { + fmt.Println("NOTE: 파일 형식이 'txt'인 경우 머핀 데이터만 txt형식으로 저장되고, 나머지는 json으로 저장됩니다.") + ch <- saveFileToTXT(path, "muffin", data) + } + }() + return <-ch +} diff --git a/utils/regexp.go b/utils/regexp.go index d2279e3..f162478 100644 --- a/utils/regexp.go +++ b/utils/regexp.go @@ -5,3 +5,4 @@ import "regexp" var FlexibleStringParser *regexp.Regexp = regexp.MustCompile("[^\\s\"'「」«»]+|\"([^\"]*)\"|'([^']*)'|「([^」]*)」|«([^»]*)»") var Decimals *regexp.Regexp = regexp.MustCompile(`\d+`) var ItemIdRegexp *regexp.Regexp = regexp.MustCompile(`No.\d+`) +var EmojiRegexp *regexp.Regexp = regexp.MustCompile(``)