From ff9a1ab98c2248d162487455a4cc3f2392cc0680 Mon Sep 17 00:00:00 2001 From: Amaototi Date: Wed, 8 Nov 2023 21:32:59 +0900 Subject: [PATCH] Can use image and Fix bugs --- data.yml | 20 ++- lib/chat/gpt_request.go | 29 +++- lib/chat/gpt_structs.go | 30 ++++ lib/cmds/chat.go | 300 +++++++++++++++++++++++++++++----------- lib/cmds/cost.go | 28 ++-- lib/config/data.go | 101 ++++++++++++-- lib/config/lang.go | 15 ++ 7 files changed, 412 insertions(+), 111 deletions(-) diff --git a/data.yml b/data.yml index 106d0f7..ea280ec 100644 --- a/data.yml +++ b/data.yml @@ -1,6 +1,20 @@ tokens: - gpt_35_turbo: + gpt_35_turbo_1106: prompt: 0 completion: 0 - gpt_4: 0 - gpt_4_32k: 0 + gpt_35_turbo_instruct: + prompt: 0 + completion: 0 + gpt_4: + prompt: 0 + completion: 0 + gpt_4_32k: + prompt: 0 + completion: 0 + gpt_4_1106_preview: + prompt: 0 + completion: 0 + gpt_4_vision_preview: + prompt: 0 + completion: 0 + detail: 0 diff --git a/lib/chat/gpt_request.go b/lib/chat/gpt_request.go index a4f3638..e13c95a 100644 --- a/lib/chat/gpt_request.go +++ b/lib/chat/gpt_request.go @@ -17,20 +17,39 @@ const openai = "https://api.openai.com/v1/chat/completions" var timeout *url.Error -func GptRequest(msg *[]Message, data *config.Tokens, guild *config.Guild, topnum float64, tempnum float64, model string) (string, error) { +func GptRequestImg(img *[]Img, data *config.Tokens, guild *config.Guild, topnum float64, tempnum float64, model string, detcost int) (string, error) { + apikey := config.CurrentConfig.Chat.ChatToken - response, err := getOpenAIResponse(&apikey, msg, data, guild, topnum, tempnum, model) + + requestBody := OpenaiRequestImg{ + Model: model, + Messages: *img, + Top_p: topnum, + Temperature: tempnum, + MaxToken: 3000, + } + + response, err := getOpenAIResponse(&apikey, data, model, requestBody, detcost) return response, err } -func getOpenAIResponse(apikey *string, messages *[]Message, data *config.Tokens, guild *config.Guild, topnum float64, tempnum float64, model string) (string, error) { +func GptRequest(msg *[]Message, data *config.Tokens, guild *config.Guild, topnum float64, tempnum float64, model string, detail int) (string, error) { + + apikey := config.CurrentConfig.Chat.ChatToken + requestBody := OpenaiRequest{ Model: model, - Messages: *messages, + Messages: *msg, Top_p: topnum, Temperature: tempnum, } + response, err := getOpenAIResponse(&apikey, data, model, requestBody, detail) + return response, err +} + +func getOpenAIResponse(apikey *string, data *config.Tokens, model string, requestBody interface{}, detcost int) (string, error) { + requestJSON, err := json.Marshal(requestBody) if err != nil { log.Fatal("Marshaling json error: ", err) @@ -82,7 +101,7 @@ func getOpenAIResponse(apikey *string, messages *[]Message, data *config.Tokens, completionTokens := response.Usages.CompletionTokens totalTokens := response.Usages.TotalTokens - err = config.SaveData(data, &model, &promptTokens, &completionTokens, &totalTokens) + err = config.SaveData(data, &model, &promptTokens, &completionTokens, &totalTokens, &detcost) if err != nil { log.Fatal("Data save failed: ", err) } diff --git a/lib/chat/gpt_structs.go b/lib/chat/gpt_structs.go index f8470c1..97c602d 100644 --- a/lib/chat/gpt_structs.go +++ b/lib/chat/gpt_structs.go @@ -7,6 +7,14 @@ type OpenaiRequest struct { Temperature float64 `json:"temperature"` } +type OpenaiRequestImg struct { + Model string `json:"model"` + Messages []Img `json:"messages"` + Top_p float64 `json:"top_p"` + Temperature float64 `json:"temperature"` + MaxToken int `json:"max_tokens"` +} + type OpenaiResponse struct { ID string `json:"id"` Object string `json:"object"` @@ -26,6 +34,28 @@ type Message struct { Content string `json:"content"` } +type Content interface{} + +type Img struct { + Role string `json:"role"` + Content []Content `json:"content"` +} + +type TextContent struct { + Type string `json:"type"` + Text string `json:"text"` +} + +type ImageContent struct { + Type string `json:"type"` + ImageURL ImageURL `json:"image_url"` +} + +type ImageURL struct { + Url string `json:"url"` + Detail string `json:"detail"` +} + type Usage struct { PromptTokens int `json:"prompt_tokens"` CompletionTokens int `json:"completion_tokens"` diff --git a/lib/cmds/chat.go b/lib/cmds/chat.go index 8d0db6f..b89e37c 100644 --- a/lib/cmds/chat.go +++ b/lib/cmds/chat.go @@ -2,9 +2,15 @@ package cmds import ( "errors" + "image" + _ "image/gif" + _ "image/jpeg" + _ "image/png" "log" + "net/http" "net/url" "reflect" + "regexp" "strconv" "strings" "time" @@ -22,18 +28,26 @@ const ( ) var timeout *url.Error +var detcost int func ChatCmd(session *discordgo.Session, orgMsg *discordgo.MessageCreate, guild *config.Guild, msg *string, data *config.Tokens) { session.MessageReactionAdd(orgMsg.ChannelID, orgMsg.ID, "๐Ÿค”") + if *msg == "" { ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.SubCmd) return } - content, repnum, tmpnum, topnum, systemstr, model, cmodel, filter := splitMsg(msg, guild) + content, repnum, tmpnum, topnum, systemstr, model, cmodel, filter, imgurl, detail := splitMsg(msg, guild) if content == "" { ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.SubCmd) + return + } + + if strings.Contains(strings.ReplaceAll(*msg, content, ""), "-d") && !strings.Contains(strings.ReplaceAll(*msg, content, ""), "-i") { + ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.NoImage) + return } msgChain := []chat.Message{{Role: "user", Content: content}} @@ -60,14 +74,151 @@ func ChatCmd(session *discordgo.Session, orgMsg *discordgo.MessageCreate, guild msgChain = []chat.Message{{Role: "user", Content: content + "\n\nไปฅไธŠใฎๆ–‡็ซ ใ‚’ใƒใ‚ธใƒ†ใ‚ฃใƒ–ใช่จ€่‘‰ใง่จ€ใ„ๆ›ใˆใฆใใ ใ•ใ„ใ€‚"}} topnum, tmpnum, model = 1, 1, "gpt-3.5-turbo" } - } else { - var slog []string + start := time.Now() - if orgMsg.ReferencedMessage != nil { - loopTargetMsg, err := session.State.Message(orgMsg.ChannelID, orgMsg.ReferencedMessage.ID) + response, err := chat.GptRequest(&msgChain, data, guild, topnum, tmpnum, model, detcost) + SendDiscord(session, orgMsg, guild, msg, data, response, err, start, filter, content, model) + return + } + + if imgurl != "" { + + re := regexp.MustCompile(`https?://[\w!?/+\-_~;.,*&@#$%()'[\]]+`) + if !re.MatchString(imgurl) { + ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.NoUrl) + return + } + + if detail == "miss" { + ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.NoDetail) + return + } + + if !strings.Contains(imgurl, ".png") && !strings.Contains(imgurl, ".jpg") && !strings.Contains(imgurl, ".jpeg") && !strings.Contains(imgurl, ".gif") && !strings.Contains(imgurl, ".webp") { + ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.NoSupportimage) + return + } + model = "gpt-4-vision-preview" + + if filter { + filter = false + } + + img := []chat.Img{ + { + Role: "user", + Content: []chat.Content{ + chat.TextContent{ + Type: "text", + Text: content, + }, + chat.ImageContent{ + Type: "image_url", + ImageURL: chat.ImageURL{ + Url: imgurl, + Detail: detail, + }, + }, + }, + }, + } + + if detail == "low" { + detcost = 85 + } else if detail == "high" { + resp, err := http.Get(imgurl) + if err != nil { + log.Panic("Failed to get image: ", err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.BrokenLink) + } + + imageConfig, _, err := image.DecodeConfig(resp.Body) + if err != nil { + log.Panic("Faild to decode: ", err) + } + + width := imageConfig.Width + height := imageConfig.Height + + var newwidth, newheight int + + if width > 2048 || height > 2048 { + if width > height { + newwidth = 2048 + newheight = int(float64(height) * (2048.0 / float64(width))) + } else { + newheight = 2048 + newwidth = int(float64(width) * (2048.0 / float64(height))) + } + } + if newwidth > 768 { + newwidth = 768 + newheight = int(float64(height) * (768.0 / float64(newwidth))) + } else if newheight > 768 { + newheight = 768 + newwidth = int(float64(width) * (768.0 / float64(newheight))) + } else { + newwidth = width + newheight = height + } + detcost = (((((newheight / 512) + 1) + ((newwidth / 512) + 1)) * 170) + 85) + } + + start := time.Now() + + response, err := chat.GptRequestImg(&img, data, guild, topnum, tmpnum, model, detcost) + + SendDiscord(session, orgMsg, guild, msg, data, response, err, start, filter, content, model) + return + } + + detcost := 0 + + var slog []string + + if orgMsg.ReferencedMessage != nil { + loopTargetMsg, err := session.State.Message(orgMsg.ChannelID, orgMsg.ReferencedMessage.ID) + if err != nil { + loopTargetMsg, err = session.ChannelMessage(orgMsg.ChannelID, orgMsg.ReferencedMessage.ID) if err != nil { - loopTargetMsg, err = session.ChannelMessage(orgMsg.ChannelID, orgMsg.ReferencedMessage.ID) + log.Panic("Failed to get channel message: ", err) + } + err = session.State.MessageAdd(loopTargetMsg) + if err != nil { + log.Panic("Failed to add message into state: ", err) + } + } + // Get reply msgs recursively + for i := 0; i < repnum; i++ { + if loopTargetMsg.Author.ID != session.State.User.ID { + break + } else if loopTargetMsg.Embeds[0].Color != embed.ColorGPT3 && loopTargetMsg.Embeds[0].Color != embed.ColorGPT4 { //ToDo: Better handling + break + } + msgChain = append(msgChain, chat.Message{Role: "assistant", Content: loopTargetMsg.Embeds[0].Description}) + + if i == 0 && !cmodel { + if loopTargetMsg.Embeds[0].Color == embed.ColorGPT3 { + model = "gpt-3.5-turbo" + } else if loopTargetMsg.Embeds[0].Color == embed.ColorGPT4 { + model = "gpt-4" + } else { + ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.CantReply) + } + } + + if loopTargetMsg.ReferencedMessage == nil { + break + } + + PrevState := loopTargetMsg + loopTargetMsg, err = session.State.Message(orgMsg.ChannelID, loopTargetMsg.ReferencedMessage.ID) + if err != nil { + loopTargetMsg, err = session.ChannelMessage(orgMsg.ChannelID, PrevState.ReferencedMessage.ID) if err != nil { log.Panic("Failed to get channel message: ", err) } @@ -76,94 +227,63 @@ func ChatCmd(session *discordgo.Session, orgMsg *discordgo.MessageCreate, guild log.Panic("Failed to add message into state: ", err) } } - // Get reply msgs recursively - for i := 0; i < repnum; i++ { - if loopTargetMsg.Author.ID != session.State.User.ID { - break - } else if loopTargetMsg.Embeds[0].Color != embed.ColorGPT3 && loopTargetMsg.Embeds[0].Color != embed.ColorGPT4 { //ToDo: Better handling - break - } - msgChain = append(msgChain, chat.Message{Role: "assistant", Content: loopTargetMsg.Embeds[0].Description}) - - if i == 0 && !cmodel { - if loopTargetMsg.Embeds[0].Color == embed.ColorGPT3 { - model = "gpt-3.5-turbo" - } else if loopTargetMsg.Embeds[0].Color == embed.ColorGPT4 { - model = "gpt-4" - } else { - ErrorReply(session, orgMsg, config.Lang[config.CurrentConfig.Guild.Lang].Error.CantReply) - } - } - if loopTargetMsg.ReferencedMessage == nil { - break - } + if loopTargetMsg.Content == "" { + break + } + _, trimmed := utils.TrimPrefix(loopTargetMsg.Content, config.CurrentConfig.Guild.Prefix+Chat+" ", session.State.User.Mention()) + contentlog, _, _, _, systemstrlog, _, _, _, _, _ := splitMsg(&trimmed, guild) + if systemstrlog != "" { + slog = append(slog, systemstrlog) + } + msgChain = append(msgChain, chat.Message{Role: "user", Content: contentlog}) + if loopTargetMsg.ReferencedMessage == nil { + break + } - PrevState := loopTargetMsg - loopTargetMsg, err = session.State.Message(orgMsg.ChannelID, loopTargetMsg.ReferencedMessage.ID) + PrevState = loopTargetMsg + loopTargetMsg, err = session.State.Message(orgMsg.ChannelID, loopTargetMsg.ReferencedMessage.ID) + if err != nil { + loopTargetMsg, err = session.ChannelMessage(orgMsg.ChannelID, PrevState.ReferencedMessage.ID) if err != nil { - loopTargetMsg, err = session.ChannelMessage(orgMsg.ChannelID, PrevState.ReferencedMessage.ID) - if err != nil { - log.Panic("Failed to get channel message: ", err) - } - err = session.State.MessageAdd(loopTargetMsg) - if err != nil { - log.Panic("Failed to add message into state: ", err) - } - } - - if loopTargetMsg.Content == "" { - break - } - _, trimmed := utils.TrimPrefix(loopTargetMsg.Content, config.CurrentConfig.Guild.Prefix+Chat+" ", session.State.User.Mention()) - contentlog, _, _, _, systemstrlog, _, _, _ := splitMsg(&trimmed, guild) - if systemstrlog != "" { - slog = append(slog, systemstrlog) - } - msgChain = append(msgChain, chat.Message{Role: "user", Content: contentlog}) - if loopTargetMsg.ReferencedMessage == nil { - break + log.Panic("Failed to get channel message: ", err) } - - PrevState = loopTargetMsg - loopTargetMsg, err = session.State.Message(orgMsg.ChannelID, loopTargetMsg.ReferencedMessage.ID) + err = session.State.MessageAdd(loopTargetMsg) if err != nil { - loopTargetMsg, err = session.ChannelMessage(orgMsg.ChannelID, PrevState.ReferencedMessage.ID) - if err != nil { - log.Panic("Failed to get channel message: ", err) - } - err = session.State.MessageAdd(loopTargetMsg) - if err != nil { - log.Panic("Failed to add message into state: ", err) - } + log.Panic("Failed to add message into state: ", err) } } + } - if systemstr == "" { - if len(slog) != 0 { - sysSlice := chat.Message{Role: "system", Content: slog[0]} - msgChain = append([]chat.Message{sysSlice}, msgChain...) - } - } else { - sysSlice := chat.Message{Role: "system", Content: systemstr} + if systemstr == "" { + if len(slog) != 0 { + sysSlice := chat.Message{Role: "system", Content: slog[0]} msgChain = append([]chat.Message{sysSlice}, msgChain...) } - - reverse(msgChain) } else { + sysSlice := chat.Message{Role: "system", Content: systemstr} + msgChain = append([]chat.Message{sysSlice}, msgChain...) + } - if systemstr != "" { - sysSlice := chat.Message{Role: "system", Content: systemstr} - msgChain = append([]chat.Message{sysSlice}, msgChain...) - } + reverse(msgChain) + } else { + if systemstr != "" { + sysSlice := chat.Message{Role: "system", Content: systemstr} + msgChain = append([]chat.Message{sysSlice}, msgChain...) } - } start := time.Now() - response, err := chat.GptRequest(&msgChain, data, guild, topnum, tmpnum, model) + response, err := chat.GptRequest(&msgChain, data, guild, topnum, tmpnum, model, detcost) + + SendDiscord(session, orgMsg, guild, msg, data, response, err, start, filter, content, model) + +} + +func SendDiscord(session *discordgo.Session, orgMsg *discordgo.MessageCreate, guild *config.Guild, msg *string, data *config.Tokens, response string, err error, start time.Time, filter bool, content string, model string) { + if err != nil { if errors.As(err, &timeout) && timeout.Timeout() { ErrorReply(session, orgMsg, config.Lang[guild.Lang].Error.TimeOut) @@ -173,13 +293,16 @@ func ChatCmd(session *discordgo.Session, orgMsg *discordgo.MessageCreate, guild return } } + if utf8.RuneCountInString(response) > 4096 { ErrorReply(session, orgMsg, config.Lang[guild.Lang].Error.LongResponse) return } + exec := time.Since(start).Seconds() dulation := strconv.FormatFloat(exec, 'f', 2, 64) embedMsg := embed.NewEmbed(session, orgMsg) + if filter { embedMsg.Title = "Social Filter" } else if utf8.RuneCountInString(content) > 50 { @@ -187,6 +310,7 @@ func ChatCmd(session *discordgo.Session, orgMsg *discordgo.MessageCreate, guild } else { embedMsg.Title = content } + embedMsg.Description = response exectimetext := config.Lang[guild.Lang].Reply.ExecTime second := config.Lang[guild.Lang].Reply.Second @@ -206,13 +330,13 @@ func reverse(s interface{}) { } } -func splitMsg(msg *string, guild *config.Guild) (string, int, float64, float64, string, string, bool, bool) { - var content, systemstr, modelstr string +func splitMsg(msg *string, guild *config.Guild) (string, int, float64, float64, string, string, bool, bool, string, string) { + var content, systemstr, modelstr, imgurl, detail string var repnum int var tmpnum, topnum float64 var prm, filter, cmodel bool - modelstr = guild.Model + modelstr, detail = guild.Model, "low" repnum, topnum, tmpnum = config.CurrentConfig.Guild.Reply, 1, 1 prm, filter, cmodel = true, false, false @@ -226,20 +350,34 @@ func splitMsg(msg *string, guild *config.Guild) (string, int, float64, float64, } else if str[i] == "-m" { modelstr = str[i+1] cmodel = true + i += 1 } else if str[i] == "-l" { repnum, _ = strconv.Atoi(str[i+1]) + i += 1 } else if str[i] == "-p" { topnum, _ = strconv.ParseFloat(str[i+1], 64) + i += 1 } else if str[i] == "-t" { tmpnum, _ = strconv.ParseFloat(str[i+1], 64) + i += 1 } else if str[i] == "-s" { systemstr = str[i+1] + i += 1 + } else if str[i] == "-i" { + imgurl = str[i+1] + i += 1 + } else if str[i] == "-d" { + if str[i+1] == "high" || str[i+1] == "low" { + detail = str[i+1] + } else { + detail = "miss" + } + i += 1 } - i += 1 } else { prm = false content += str[i] + " " } } - return content, repnum, tmpnum, topnum, systemstr, modelstr, cmodel, filter + return content, repnum, tmpnum, topnum, systemstr, modelstr, cmodel, filter, imgurl, detail } diff --git a/lib/cmds/cost.go b/lib/cmds/cost.go index 53db7dc..601724f 100644 --- a/lib/cmds/cost.go +++ b/lib/cmds/cost.go @@ -25,10 +25,19 @@ func CostCmd(session *discordgo.Session, orgMsg *discordgo.MessageCreate, guild func calculationTokens(guild *config.Guild) string { var rate float64 - Tokens_gpt_35_turbo_prompt := float64(config.CurrentData.Tokens.Gpt_35_turbo.Prompt) - Tokens_gpt_35_turbo_completion := float64(config.CurrentData.Tokens.Gpt_35_turbo.Completion) - Tokens_gpt_4 := float64(config.CurrentData.Tokens.Gpt_4) - Tokens_gpt_4_32k := float64(config.CurrentData.Tokens.Gpt_4_32k) + Tokens_gpt_35_turbo_1106_prompt := float64(config.CurrentData.Tokens.Gpt_35_turbo_1106.Prompt) + Tokens_gpt_35_turbo_1106_completion := float64(config.CurrentData.Tokens.Gpt_35_turbo_1106.Completion) + Tokens_gpt_35_turbo_instruct_prompt := float64(config.CurrentData.Tokens.Gpt_35_turbo_instruct.Prompt) + Tokens_gpt_35_turbo_instruct_completion := float64(config.CurrentData.Tokens.Gpt_35_turbo_instruct.Completion) + Tokens_gpt_4_prompt := float64(config.CurrentData.Tokens.Gpt_4.Prompt) + Tokens_gpt_4_cpmpletion := float64(config.CurrentData.Tokens.Gpt_4.Completion) + Tokens_gpt_4_32k_prompt := float64(config.CurrentData.Tokens.Gpt_4_32k.Prompt) + Tokens_gpt_4_32k_completion := float64(config.CurrentData.Tokens.Gpt_4_32k.Completion) + Tokens_gpt_4_1106_preview_prompt := float64(config.CurrentData.Tokens.Gpt_4_1106_preview.Prompt) + Tokens_gpt_4_1106_preview_completion := float64(config.CurrentData.Tokens.Gpt_4_1106_preview.Completion) + Tokens_gpt_4_vision_preview_prompt := float64(config.CurrentData.Tokens.Gpt_4_vision_preview.Prompt) + Tokens_gpt_4_vision_preview_completion := float64(config.CurrentData.Tokens.Gpt_4_vision_preview.Completion) + Tokens_gpt_4_vision_preview_details := float64(config.CurrentData.Tokens.Gpt_4_vision_preview.Detail) if config.Lang[guild.Lang].Lang == "japanese" { rate = config.CurrentRate @@ -36,10 +45,13 @@ func calculationTokens(guild *config.Guild) string { rate = 1 } - cost_gpt_35 := ((Tokens_gpt_35_turbo_prompt / 1000) * 0.0015 * rate) + ((Tokens_gpt_35_turbo_completion / 1000) * 0.0002 * rate) - cost_gpt_4 := (Tokens_gpt_4 / 1000) * 0.003 * rate - cost_gpt_4_32k := (Tokens_gpt_4_32k / 1000) * 0.006 * rate - cost := (cost_gpt_35 + cost_gpt_4 + cost_gpt_4_32k) * 10 + cost_gpt_35_1106 := ((Tokens_gpt_35_turbo_1106_prompt / 1000) * 0.001 * rate) + ((Tokens_gpt_35_turbo_1106_completion / 1000) * 0.002 * rate) + cost_gpt_35_instruct := ((Tokens_gpt_35_turbo_instruct_prompt / 1000) * 0.0015 * rate) + ((Tokens_gpt_35_turbo_instruct_completion / 1000) * 0.002 * rate) + cost_gpt_4 := ((Tokens_gpt_4_prompt / 1000) * 0.03 * rate) + ((Tokens_gpt_4_cpmpletion / 1000) * 0.06 * rate) + cost_gpt_4_32k := ((Tokens_gpt_4_32k_prompt / 1000) * 0.06 * rate) + ((Tokens_gpt_4_32k_completion / 1000) * 0.12 * rate) + cost_gpt_4_1106_preview := ((Tokens_gpt_4_1106_preview_prompt / 1000) * 0.01 * rate) + ((Tokens_gpt_4_1106_preview_completion / 1000) * 0.03 * rate) + cost_gpt_4_1106_vision_preview := ((Tokens_gpt_4_vision_preview_prompt / 1000) * 0.01 * rate) + ((Tokens_gpt_4_vision_preview_completion / 1000) * 0.03 * rate) + Tokens_gpt_4_vision_preview_details + cost := (cost_gpt_35_1106 + cost_gpt_35_instruct + cost_gpt_4 + cost_gpt_4_32k + cost_gpt_4_1106_preview + cost_gpt_4_1106_vision_preview) coststr := strconv.FormatFloat(cost, 'f', 2, 64) if coststr == "0.00" { coststr = "0" diff --git a/lib/config/data.go b/lib/config/data.go index 00c9d35..99f72be 100644 --- a/lib/config/data.go +++ b/lib/config/data.go @@ -18,16 +18,45 @@ type Data struct { } type Tokens struct { - Gpt_35_turbo Gpt_35_turbo - Gpt_4 int - Gpt_4_32k int + Gpt_35_turbo_1106 Gpt_35_turbo_1106 + Gpt_35_turbo_instruct Gpt_35_turbo_instruct + Gpt_4 Gpt_4 + Gpt_4_32k Gpt_4_32k + Gpt_4_1106_preview Gpt_4_1106_preview + Gpt_4_vision_preview Gpt_4_vision_preview } -type Gpt_35_turbo struct { +type Gpt_35_turbo_1106 struct { Prompt int Completion int } +type Gpt_35_turbo_instruct struct { + Prompt int + Completion int +} + +type Gpt_4 struct { + Prompt int + Completion int +} + +type Gpt_4_32k struct { + Prompt int + Completion int +} + +type Gpt_4_1106_preview struct { + Prompt int + Completion int +} + +type Gpt_4_vision_preview struct { + Prompt int + Completion int + Detail int +} + const dataFile = "./data.yml" var ( @@ -45,15 +74,44 @@ func init() { log.Fatal("Data load failed: ", err) } - initGpt_35_turbo := Gpt_35_turbo{ + initGpt_35_turbo_1106 := Gpt_35_turbo_1106{ + Prompt: 0, + Completion: 0, + } + + initGpt_35_turbo_instruct := Gpt_35_turbo_instruct{ + Prompt: 0, + Completion: 0, + } + + initGpt_4 := Gpt_4{ + Prompt: 0, + Completion: 0, + } + + initGpt_4_32k := Gpt_4_32k{ + Prompt: 0, + Completion: 0, + } + + initGpt_4_1106_preview := Gpt_4_1106_preview{ + Prompt: 0, + Completion: 0, + } + + initGpt_4_vision_preview := Gpt_4_vision_preview{ Prompt: 0, Completion: 0, + Detail: 0, } initTokens := Tokens{ - Gpt_35_turbo: initGpt_35_turbo, - Gpt_4: 0, - Gpt_4_32k: 0, + Gpt_35_turbo_1106: initGpt_35_turbo_1106, + Gpt_35_turbo_instruct: initGpt_35_turbo_instruct, + Gpt_4: initGpt_4, + Gpt_4_32k: initGpt_4_32k, + Gpt_4_1106_preview: initGpt_4_1106_preview, + Gpt_4_vision_preview: initGpt_4_vision_preview, } CurrentData = Data{ @@ -78,7 +136,7 @@ func init() { } } -func SaveData(data *Tokens, model *string, promptTokens *int, completionTokens *int, totalTokens *int) error { +func SaveData(data *Tokens, model *string, promptTokens *int, completionTokens *int, totalTokens *int, detcost *int) error { file, err := os.ReadFile(dataFile) if err != nil { return err @@ -91,12 +149,27 @@ func SaveData(data *Tokens, model *string, promptTokens *int, completionTokens * switch *model { case "gpt-3.5-turbo": - CurrentData.Tokens.Gpt_35_turbo.Prompt += *promptTokens - CurrentData.Tokens.Gpt_35_turbo.Completion += *completionTokens + CurrentData.Tokens.Gpt_35_turbo_instruct.Prompt += *promptTokens + CurrentData.Tokens.Gpt_35_turbo_instruct.Completion += *completionTokens + case "gpt-3.5-turbo-instruct": + CurrentData.Tokens.Gpt_35_turbo_instruct.Prompt += *promptTokens + CurrentData.Tokens.Gpt_35_turbo_instruct.Completion += *completionTokens + case "gpt-3.5-turbo-1106": + CurrentData.Tokens.Gpt_35_turbo_1106.Prompt += *promptTokens + CurrentData.Tokens.Gpt_35_turbo_1106.Completion += *completionTokens case "gpt-4": - CurrentData.Tokens.Gpt_4 += *totalTokens + CurrentData.Tokens.Gpt_4.Prompt += *promptTokens + CurrentData.Tokens.Gpt_4.Completion += *completionTokens case "gpt-4-32k": - CurrentData.Tokens.Gpt_4_32k += *totalTokens + CurrentData.Tokens.Gpt_4_32k.Prompt += *promptTokens + CurrentData.Tokens.Gpt_4_32k.Completion += *completionTokens + case "gpt-4-1106-preview": + CurrentData.Tokens.Gpt_4_1106_preview.Prompt += *promptTokens + CurrentData.Tokens.Gpt_4_1106_preview.Completion += *completionTokens + case "gpt-4-vision-preview": + CurrentData.Tokens.Gpt_4_vision_preview.Prompt += *promptTokens + CurrentData.Tokens.Gpt_4_vision_preview.Completion += *completionTokens + CurrentData.Tokens.Gpt_4_vision_preview.Detail += *detcost } newData := Data{ @@ -125,7 +198,7 @@ func RunCron() { } func ResetTokens() error { - CurrentData.Tokens.Gpt_35_turbo.Prompt, CurrentData.Tokens.Gpt_35_turbo.Completion, CurrentData.Tokens.Gpt_4, CurrentData.Tokens.Gpt_4_32k = 0, 0, 0, 0 + CurrentData.Tokens.Gpt_35_turbo_1106.Prompt, CurrentData.Tokens.Gpt_35_turbo_1106.Completion, CurrentData.Tokens.Gpt_35_turbo_instruct.Prompt, CurrentData.Tokens.Gpt_35_turbo_instruct.Completion, CurrentData.Tokens.Gpt_4.Prompt, CurrentData.Tokens.Gpt_4.Completion, CurrentData.Tokens.Gpt_4_32k.Prompt, CurrentData.Tokens.Gpt_4_32k.Completion, CurrentData.Tokens.Gpt_4_1106_preview.Prompt, CurrentData.Tokens.Gpt_4_1106_preview.Completion, CurrentData.Tokens.Gpt_4_vision_preview.Prompt, CurrentData.Tokens.Gpt_4_vision_preview.Completion, CurrentData.Tokens.Gpt_4_vision_preview.Detail = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 newData := Data{ Tokens: CurrentData.Tokens, diff --git a/lib/config/lang.go b/lib/config/lang.go index 99a1999..3dba580 100644 --- a/lib/config/lang.go +++ b/lib/config/lang.go @@ -25,6 +25,11 @@ type errorstr struct { LongResponse string TimeOut string CantReply string + NoDetail string + NoImage string + NoSupportimage string + NoUrl string + BrokenLink string } type usagestr struct { @@ -142,6 +147,11 @@ func loadLang() { LongResponse: "AIใฎ็”Ÿๆˆใ—ใŸๆ–‡็ซ ใŒ้•ทใ™ใŽใพใ—ใŸใ€‚ๆŒ‡็คบใ‚’ๅค‰ๆ›ดใ—ใฆใ‚‚ใ†ไธ€ๅบฆใŠ่ฉฆใ—ใใ ใ•ใ„ใ€‚", TimeOut: "่ฆๆฑ‚ใŒใ‚ฟใ‚คใƒ ใ‚ขใ‚ฆใƒˆใ—ใพใ—ใŸใ€‚ใ‚‚ใ†ไธ€ๅบฆใŠ่ฉฆใ—ใใ ใ•ใ„ใ€‚", CantReply: "ใ‚จใƒฉใƒผใธใฎ่ฟ”ไฟกใฏใงใใพใ›ใ‚“ใ€‚", + NoDetail: "highใ‹lowใฎใฟ้ธๆŠžใงใใพใ™ใ€‚", + NoImage: "็”ปๅƒใŒๅ…ฅๅŠ›ใ•ใ‚Œใฆใ„ใพใ›ใ‚“ใ€‚", + NoSupportimage: "ใใฎ็”ปๅƒๅฝขๅผใฏๅฏพๅฟœใ—ใฆใ„ใพใ›ใ‚“ใ€‚", + NoUrl: "URLใ‚’ๅ…ฅๅŠ›ใ—ใฆใใ ใ•ใ„ใ€‚", + BrokenLink: "็”ปๅƒใฎใƒชใƒณใ‚ฏใŒๅˆ‡ใ‚Œใฆใ„ใพใ™ใ€‚", }, } Lang["english"] = Strings{ @@ -202,6 +212,11 @@ func loadLang() { LongResponse: "The AI-generated text is too long. Please modify your instructions and try again.", TimeOut: "The request has timed out. Please try again.", CantReply: "Cannot reply for error message.", + NoDetail: "Only high or low.", + NoImage: "No image in command.", + NoSupportimage: "gpt-4-vision-preview is not supported by this type of file.", + NoUrl: "That is no url.", + BrokenLink: "This link has broken.", }, } }