diff --git a/.gitignore b/.gitignore index 9a674eb..651effe 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,5 @@ test*.json request.json config.toml messages.json -.vscode/settings.json +.vscode .idea \ No newline at end of file diff --git a/README.md b/README.md index b002ae2..9fadb8c 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ ## 使用说明: 1. 默认的配置端口是5580,如果需要修改,请修改配置文件里的`APIURL`字段。默认获取以`!`开头的消息,如果需要修改,请修改配置文件里的`Prefix`字段。 -当前拥有的插件: +2. 现在加入了`Redis`支持,如果需要使用`Redis`,请在配置文件里配置`REDIS`的相关信息,使用`Redis`可以支持`ai`插件的`Context`功能,即支持上下文对话,同时让机器人拥有更高的扩展性。 +3. 当前拥有的插件: - `ping`:判断程序运行,会响应`Pong!` - `ip`:查询一个ip的详细信息,使用方法`ip <域名/ip>` - `lsp`:请求`api.lolicon.app`获取`Pixiv`壁纸,暂时只简单实现获取随机壁纸。 diff --git a/config example.toml b/config example.toml index 7c54801..d077651 100644 --- a/config example.toml +++ b/config example.toml @@ -8,7 +8,14 @@ AllowRole = [] BlockGroup = [] # 群组黑名单 BlockUser = [] Master = [] +[OPENAI] MODEL = "gpt-4o" OPENAI_API_KEY = "sk-xxxx" OPENAI_BaseURL = "https://api.openai.com/v1" PROMPT = "## Role : \nQQ群Linux助手\n\n## Background : \n该角色是一位专门为QQ群提供Linux相关技术支持的助手,熟悉各种Linux发行版的使用和问题解决,旨在帮助群友解决他们在使用Linux过程中遇到的各种问题。\n\n## Preferences : \n该角色偏好简洁明了的回答风格,注重解决方案的精确性和有效性。喜欢友好和尊重的互动方式,致力于营造一个技术交流的和谐环境。\n\n## Profile :\n- language: 中文\n- description: 为QQ群友提供Linux相关问题的简洁、精确解决方案\n\n## Goals :\n1. 回答Linux相关问题\n2. 提供简短、精确的解决方案\n3. 鼓励群友提出问题并尊重他们\n\n## Constrains :\n1. 避免回答政治相关内容\n2. 每个问题只回答一次,确保回复简短、精确\n\n## Skills :\n1. 熟悉各种Linux发行版的使用和问题解决\n2. 能够提供简洁明了的技术支持\n3. 友好回复群友的提问\n\n## Examples :\n1. 问题:如何查看当前Linux系统的内核版本?\n 答案:可以使用命令`uname -r`来查看当前的内核版本。\n \n2. 问题:如何安装一个软件包?\n 答案:可以使用`sudo pacman -S <软件包名>`来安装软件包(适用于Archlinux系)。\n\n## OutputFormat :\n1. 接收用户输入的问题。\n2. 提供简洁、精确的解决方案。\n\n## Initialization : \n作为 QQ群Linux助手, 拥有 熟悉各种Linux发行版的使用和问题解决, 能够提供简洁明了的技术支持, 友好回复群友的提问, 避免回答政治相关内容, 每个问题只回答一次,确保回复简短、精确, 使用默认 中文 与用户对话,友好的欢迎用户。然后介绍自己,并提示用户输入。\n" +Context = 5 + +[REDIS] +REDIS_URL = "localhost:6379" +REDIS_PASSWORD = "" +REDIS_DB = 0 \ No newline at end of file diff --git a/go.mod b/go.mod index 3cf9250..477357b 100644 --- a/go.mod +++ b/go.mod @@ -13,9 +13,11 @@ require ( github.com/andybalholm/cascadia v1.3.2 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -56,7 +58,9 @@ require ( github.com/PuerkitoBio/goquery v1.9.2 github.com/andybalholm/brotli v1.1.0 github.com/gin-gonic/gin v1.10.0 + github.com/go-redis/redis/v8 v8.11.5 github.com/imroc/req/v3 v3.44.0 + github.com/redis/go-redis/v9 v9.6.1 github.com/sashabaranov/go-openai v1.29.0 github.com/sirupsen/logrus v1.9.3 golang.org/x/net v0.26.0 // indirect diff --git a/go.sum b/go.sum index 20f48d4..6852eda 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,10 @@ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= @@ -20,6 +24,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -36,6 +42,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= @@ -90,6 +98,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k= github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/refraction-networking/utls v1.6.3 h1:MFOfRN35sSx6K5AZNIoESsBuBxS2LCgRilRIdHb6fDc= github.com/refraction-networking/utls v1.6.3/go.mod h1:yil9+7qSl+gBwJqztoQseO6Pr3h62pQoY1lXiNR/FPs= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= diff --git a/tools/get_history_message.go b/test/get_history_message.go similarity index 100% rename from tools/get_history_message.go rename to test/get_history_message.go diff --git a/test/openai.go b/test/openai.go new file mode 100644 index 0000000..1c5ed03 --- /dev/null +++ b/test/openai.go @@ -0,0 +1,139 @@ +package main + +import ( + "bufio" + "context" + "fmt" + "go-bot/tools" + + "os" + "strings" + "time" + + "github.com/redis/go-redis/v9" + "github.com/sashabaranov/go-openai" +) + +var ctx = context.Background() + +// 初始化 Redis 客户端 +func initRedis() *redis.Client { + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", // Redis 地址 + Password: "", // no password set + DB: 0, // use default DB + }) + return rdb +} + +// 检查请求频率,10秒内只能请求一次 +func checkRequestFrequency(rdb *redis.Client, groupID string, qqID string) bool { + key := fmt.Sprintf("last_request:%s:%s", groupID, qqID) + lastRequest, err := rdb.Get(ctx, key).Int64() + println("key:", key) + now := time.Now().Unix() + println("now:", now) + println("lastRequest:", lastRequest) + + if err == redis.Nil { + // 键不存在,这是第一次请求 + rdb.Set(ctx, key, now, 10*time.Second) + + return true + } else if err != nil { + fmt.Println("获取上次请求时间时出错:", err) + return false + } + currentRequest := getContext(rdb, key) + fmt.Println("currentRequest:", currentRequest) + if now-lastRequest < 10 { + fmt.Printf("请求过于频繁。距离上次请求还有 %d 秒。\n", 10-(now-lastRequest)) + return false // 频率超限,拒绝请求 + } + + // 更新最后请求时间,并设置 10 秒的过期时间 + rdb.Set(ctx, key, now, 10*time.Second) + return true +} + +// 添加对话到上下文,超过5条则删除所有上下文 +func addToContext(rdb *redis.Client, groupID string, qqID string, message string) { + key := fmt.Sprintf("context:%s:%s", groupID, qqID) + + // 如果上下文超过5条,删除所有上下文 + listLength := rdb.LLen(ctx, key).Val() + if listLength > 5 { + rdb.Del(ctx, key) // 删除该用户的所有上下文 + } + rdb.RPush(ctx, key, message) // 添加新消息到列表 +} + +// 获取当前上下文 +func getContext(rdb *redis.Client, key string) []string { + // key := + context, err := rdb.LRange(ctx, key, 0, -1).Result() + if err != nil { + fmt.Println("Error fetching context:", err) + return nil + } + return context +} + +func main() { + // ctx := context.Background() + groupID := "12345" + qqID := "67890" + rdb := initRedis() + + OPENAI_API_KEY, OPENAI_BaseURL, MODEL := tools.GetOAIConfig() + oaiconfig := openai.DefaultConfig(OPENAI_API_KEY) + oaiconfig.BaseURL = OPENAI_BaseURL + client := openai.NewClientWithConfig(oaiconfig) + + messages := make([]openai.ChatCompletionMessage, 0) + reader := bufio.NewReader(os.Stdin) + fmt.Println("Conversation") + fmt.Println("---------------------") + + for { + fmt.Print("-> ") + // 检查请求频率 + if !checkRequestFrequency(rdb, groupID, qqID) { + // fmt.Println("请求太频繁,请稍后再试。") + return + } + text, _ := reader.ReadString('\n') + // convert CRLF to LF + text = strings.Replace(text, "\n", "", -1) + + messages = append(messages, openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: text, + }) + + resp, err := client.CreateChatCompletion( + ctx, + openai.ChatCompletionRequest{ + Model: MODEL, + Messages: messages, + }, + ) + + if err != nil { + fmt.Printf("ChatCompletion error: %v\n", err) + continue + } + + content := resp.Choices[0].Message.Content + messages = append(messages, openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleAssistant, + Content: content, + }) + // 添加新消息到上下文 + addToContext(rdb, groupID, qqID, text) + + fmt.Println(content) + fmt.Println("---------------------") + fmt.Println(getContext(rdb, "context:"+groupID+":"+qqID)) + } +} diff --git a/tools/update_message_seq.go b/test/update_message_seq.go similarity index 100% rename from tools/update_message_seq.go rename to test/update_message_seq.go diff --git a/tools/getOAIConfig.go b/tools/getOAIConfig.go new file mode 100644 index 0000000..4f64134 --- /dev/null +++ b/tools/getOAIConfig.go @@ -0,0 +1,51 @@ +package tools + +import ( + "go-bot/config" + "log" +) + +func GetOAIConfig() (string, string, string, string, int64) { + cfg := config.GetConfig() + // config.PrintConfig(cfg, "") + var OPENAI_API_KEY, OPENAI_BaseURL, MODEL, PROMPT string + var context int64 + openai_cfg := cfg["OPENAI"].(map[string]interface{}) + if openai_cfg["OPENAI_API_KEY"] != nil { + OPENAI_API_KEY = openai_cfg["OPENAI_API_KEY"].(string) + } else { + log.Println("OPENAI_API_KEY 未配置") + } + + if openai_cfg["OPENAI_BaseURL"] != nil { + OPENAI_BaseURL = openai_cfg["OPENAI_BaseURL"].(string) + } else { + log.Println("OPENAI_BaseURL 未配置,使用openai默认配置") + OPENAI_BaseURL = "https://api.openai.com/v1" + } + + if openai_cfg["MODEL"] != nil { + MODEL = openai_cfg["MODEL"].(string) + } else { + log.Println("模型 未配置,使用默认 gpt-4o 模型") + MODEL = "gpt-4o" + } + if openai_cfg["PROMPT"] != nil { + PROMPT = openai_cfg["PROMPT"].(string) + } else { + log.Println("PROMPT 未配置,使用默认 PROMPT") + PROMPT = "" + } + if openai_cfg["Context"] != nil { + // var err error + context = openai_cfg["Context"].(int64) + // if err != nil { + // log.Println("Context 解析错误,使用默认 Context") + // context = 5 + // } + } else { + log.Println("Context 未配置,使用默认 Context") + context = 5 + } + return OPENAI_API_KEY, OPENAI_BaseURL, MODEL, PROMPT, int64(context) +} diff --git a/tools/redisClient.go b/tools/redisClient.go new file mode 100644 index 0000000..22f5e26 --- /dev/null +++ b/tools/redisClient.go @@ -0,0 +1,103 @@ +package tools + +import ( + "context" + "fmt" + "go-bot/config" + "log" + "sync" + + "github.com/go-redis/redis/v8" +) + +var ( + rdb *redis.Client + once sync.Once + ctx = context.Background() +) + +// InitRedis 初始化 Redis 客户端(懒加载模式,确保只初始化一次) +func InitRedis() *redis.Client { + // 使用 sync.Once 确保客户端只初始化一次 + once.Do(func() { + redisConfig := config.GetConfig()["REDIS"].(map[string]interface{}) + rdb = redis.NewClient(&redis.Options{ + Addr: redisConfig["REDIS_URL"].(string), // Redis 地址 + Password: redisConfig["REDIS_PASSWORD"].(string), // Redis 密码,如果有设置 + DB: int(redisConfig["REDIS_DB"].(int64)), // 使用的 Redis 数据库 + PoolSize: 20, // 连接池大小 + MinIdleConns: 10, // 最小空闲连接数 + }) + + // 测试连接是否成功 + _, err := rdb.Ping(ctx).Result() + if err != nil { + log.Println("Redis 连接失败:", err) + } else { + log.Println("Redis 连接成功") + } + }) + return rdb +} + +// GetRedisClient 获取 Redis 客户端实例 +func GetRedisClient() *redis.Client { + if rdb == nil { + return InitRedis() + } + return rdb +} + +// 添加对话到上下文,超过5条则删除所有上下文 +func AddToContext(key string, message string, contextlenth int64) { + // key := fmt.Sprintf("context:%s:%s:%s", worker, groupID, qqID) + + // 如果上下文超过5条,删除所有上下文 + listLength := GetListLength(key) + log.Println("listLength:", listLength) + if listLength >= contextlenth { + rdb.Del(ctx, key) // 删除该用户的所有上下文 + } + rdb.RPush(ctx, key, message) // 添加新消息到列表 +} + +// getListLength 获取列表长度 +func GetListLength(key string) int64 { + return rdb.LLen(ctx, key).Val() +} + +func GetListValue(key string, index int64) (string, error) { + return rdb.LIndex(ctx, key, index).Result() +} + +// 删除列表最后一个元素 +func RemoveLastValueFromList(key string) (string, error) { + // RPOP 命令会移除并返回列表的最后一个元素 + value, err := rdb.RPop(ctx, key).Result() + if err != nil { + if err == redis.Nil { + return "", fmt.Errorf("列表为空或不存在") + } + return "", fmt.Errorf("删除最后一个值时出错: %v", err) + } + return value, nil +} + +// SetValue 设置键值对 +func SetValue(key string, value string) error { + return rdb.Set(ctx, key, value, 0).Err() +} + +// GetValue 获取键对应的值 +func GetValue(key string) (string, error) { + return rdb.Get(ctx, key).Result() +} + +// CheckKeyExists 检查键是否存在 +func CheckKeyExists(key string) (bool, error) { + val, err := rdb.Exists(ctx, key).Result() + if err != nil { + return false, err + } + return val > 0, nil +} diff --git a/utils/openai.go b/utils/openai.go deleted file mode 100644 index d4b585b..0000000 --- a/utils/openai.go +++ /dev/null @@ -1 +0,0 @@ -package utils diff --git a/workers/ai.go b/workers/ai.go index 57a54c2..43c17b2 100644 --- a/workers/ai.go +++ b/workers/ai.go @@ -4,11 +4,12 @@ import ( "context" "encoding/base64" "fmt" + "go-bot/tools" + "io" + "log" "net/http" "os" - - "log" "regexp" "strconv" "strings" @@ -38,7 +39,7 @@ func (a *AI) GetMsg() string { return "不问问题你说个屁!" } - OPENAI_API_KEY, OPENAI_BaseURL, MODEL := getConfig() + OPENAI_API_KEY, OPENAI_BaseURL, MODEL, PROMPT, CONTEXT := tools.GetOAIConfig() if OPENAI_API_KEY == "" { return "OPENAI_API_KEY 未配置" } @@ -48,34 +49,62 @@ func (a *AI) GetMsg() string { client := openai.NewClientWithConfig(oaiconfig) msg := fmt.Sprintf("[CQ:at,qq=%s] ", a.UID) if strings.ToLower(a.Parms[1]) != "models" { - // OPENAI_BaseURL = OPENAI_BaseURL + "/chat/completions" - PROMPT, ok := cfg["PROMPT"].(string) - if !ok { - log.Println("PROMPT 未配置") - PROMPT = "" - } - // var requestBody map[string]interface{} + // 如果非回复消息 if !strings.HasPrefix(a.Parms[len(a.Parms)-1], "[CQ:reply,id=") { + messages := make([]openai.ChatCompletionMessage, 0) + messages = append(messages, openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleSystem, + Content: PROMPT, + }) + // println("messages0:", messages) + var key string + redisClient := tools.GetRedisClient() + // 如果redisClient不为空,则获取上下文 + if redisClient != nil { + + key = fmt.Sprintf("context:%s:%s:%s", "ai", a.GID, a.UID) + // 获取上下文 + + tools.AddToContext(key, a.RawMsg[strings.Index(a.RawMsg, " ")+1:], CONTEXT) + // } + // println("RawMsg:", a.RawMsg[strings.Index(a.RawMsg, " ")+1:]) + length := tools.GetListLength(key) + for i := 1; i < int(length); i++ { + message, err := tools.GetListValue(key, int64(i)) + if err != nil { + log.Println("获取上下文失败:", err) + return "获取上下文失败" + } + messages = append(messages, openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: message, + }) + } + } else { + messages = append(messages, openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: a.RawMsg[strings.Index(a.RawMsg, " ")+1:], + }) + } + // println("messages:", messages) + // for i, msg := range messages { + // fmt.Printf("消息 %d:\n", i+1) + // fmt.Printf(" 角色: %s\n", msg.Role) + // fmt.Printf(" 内容: %s\n", msg.Content) + // fmt.Println() + // } resp, err := client.CreateChatCompletion( context.Background(), openai.ChatCompletionRequest{ - Model: MODEL, - Stream: false, - Messages: []openai.ChatCompletionMessage{ - { - Role: "system", - Content: PROMPT, - }, - { - Role: "user", - Content: a.RawMsg[strings.Index(a.RawMsg, " ")+1:], - }, - }, + Model: MODEL, + Stream: false, + Messages: messages, }, ) if err != nil { log.Println("ChatCompletion error: ", err) + tools.RemoveLastValueFromList(key) return "请求失败" } // println(resp.Choices[0].Message.Content) @@ -170,7 +199,7 @@ func (a *AI) GetMsg() string { var modelList string for _, model := range models.Models { if MODEL == model.ID { - model.ID = model.ID + "(当前使用)" + model.ID = model.ID + "\t(当前使用)" } modelList += model.ID + "\n" } @@ -234,32 +263,6 @@ func stripMarkdown(text string) string { return strings.TrimSpace(text) } -func getConfig() (string, string, string) { - var OPENAI_API_KEY, OPENAI_BaseURL, MODEL string - - if cfg["OPENAI_API_KEY"] != nil { - OPENAI_API_KEY = cfg["OPENAI_API_KEY"].(string) - } else { - log.Println("OPENAI_API_KEY 未配置") - } - - if cfg["OPENAI_BaseURL"] != nil { - OPENAI_BaseURL = cfg["OPENAI_BaseURL"].(string) - } else { - log.Println("OPENAI_BaseURL 未配置,使用openai默认配置") - OPENAI_BaseURL = "https://api.openai.com/v1" - } - - if cfg["MODEL"] != nil { - MODEL = cfg["MODEL"].(string) - } else { - log.Println("模型 未配置,使用默认 gpt-4o 模型") - MODEL = "gpt-4o" - } - - return OPENAI_API_KEY, OPENAI_BaseURL, MODEL -} - func Image2Base64(path string, picUrl string) string { // 尝试从文件路径读取图片 file, err := os.Open(path)