From d1053df9e9b60c88f20847e1873af8530ef5105e Mon Sep 17 00:00:00 2001 From: SanaeFox <36219542+Hoshinonyaruko@users.noreply.github.com> Date: Sun, 19 May 2024 14:43:14 +0800 Subject: [PATCH] Beta120 (#118) * beta1 * beta2 * beta3 * beta4 * beta5 * beta6 * beta7 * beta8 * beta9 * beta10 * beta11 * beta12 * beta13 * beta14 * beta15 * beta16 * beta16 * beta19 * beta20 * beta21 * beta22 * beta23 * beta24 * beta25 * beta27 * beta28 * beta29 * beta30 * beta31 * beta33 * beta34 * beta35 * beta36 * beta37 * beta38 * beta39 * beta40 * beta41 * beta42 * beta43 * beta44 * beta45 * beta45 * beta46 * beat48 * beta49 * beta50 * beta51 * beta52 * beta53 * beta54 * beta55 * beta57 * beta58 * beta59 * beta61 * beta62 * beta63 * beta63 * beta64 * beta65 * beta66 * beta67 * beta70 * beta71 * beta72 * beta72 * beta74 * beta75 * beta76 * beta77 * beta78 * beta79 * beta80 * beta81 * beta82 * beta83 * beta85 * beta86 * beta87 * beta88 * beta89 * beta90 * beta91 * beta92 * beta93 * beta94 * beta94 * beta96 * beta97 * beta98 * beta99 * beta100 * beta101 * beta102 * beta104 * beta105 * beta106 * beta107 * beta108 * beta109 * beta110 * beta111 * beta112 * beta113 * beta115 * beta116 * beta117 * beta118 * beta119 * beta120 --- applogic/gensokyo.go | 12 ++---- config/config.go | 10 +++++ main.go | 5 +++ readme.md | 28 +++++++----- server/server.go | 45 +++++++++++++++++-- structs/struct.go | 1 + template/config_template.go | 1 + utils/utils.go | 86 ++++++++++++++++++++++++++++++++----- 8 files changed, 156 insertions(+), 32 deletions(-) diff --git a/applogic/gensokyo.go b/applogic/gensokyo.go index 60d5a94..eb5c435 100644 --- a/applogic/gensokyo.go +++ b/applogic/gensokyo.go @@ -206,18 +206,14 @@ func (app *App) GensokyoHandler(w http.ResponseWriter, r *http.Request) { } } - // 读取URL参数 "selfid" - selfid := r.URL.Query().Get("selfid") - if selfid != "" { - // 使用 prompt 变量进行后续处理 - fmt.Printf("收到selfid参数: %s\n", selfid) - } + // 直接从ob11事件获取selfid + selfid := strconv.FormatInt(message.SelfID, 10) // 读取URL参数 "api" api := r.URL.Query().Get("api") - if selfid != "" { + if api != "" { // 使用 prompt 变量进行后续处理 - fmt.Printf("收到api参数: %s\n", selfid) + fmt.Printf("收到api参数: %s\n", api) } // 打印日志信息,包括prompt参数 diff --git a/config/config.go b/config/config.go index c87ae21..5fda48c 100644 --- a/config/config.go +++ b/config/config.go @@ -231,6 +231,16 @@ func IPWhiteList() []string { return nil } +// 获取HttpPaths +func GetHttpPaths() []string { + mu.Lock() + defer mu.Unlock() + if instance != nil { + return instance.Settings.HttpPaths + } + return nil +} + // 获取最大上下文 func GetMaxTokensHunyuan(options ...string) int { mu.Lock() diff --git a/main.go b/main.go index c950854..7de4084 100644 --- a/main.go +++ b/main.go @@ -195,6 +195,11 @@ func main() { log.Fatalf("Failed to load blacklist: %v", err) } + // 判断是否设置多个http地址,获取对应关系 + if len(config.GetHttpPaths()) > 0 { + utils.FetchAndStoreUserIDs() + } + // 启动黑名单文件变动监听 go utils.WatchBlacklist(blacklistPath) diff --git a/readme.md b/readme.md index 6df07f8..f6750d1 100644 --- a/readme.md +++ b/readme.md @@ -32,16 +32,6 @@ _✨ 适用于Gensokyo以及Onebotv11的大模型一键端 ✨_ 并发环境下的sse内存安全,支持维持多用户同时双向sse传输 ---- - -## 效果 - -![效果图](/pic/3.png) - -![效果图](/pic/4.png) - ---- - ## 支持llm平台 腾讯混元 @@ -117,6 +107,14 @@ AhoCorasick算法实现的超高效文本IN-Out替换规则,可大量替换n 支持中间件开发,在gensokyo框架层到gensokyo-llm的http请求之间,可开发中间件实现向量拓展,数据库拓展,动态修改用户问题. +支持反向ws连接,支持同时连接多个onebotv11的http-api + +--- + +## 使用教程 + +施工中...(部署非常简单,有一定onebotv11机器人部署经验者可参考config.yml注释直接部署出来.) + --- # API接口调用说明 @@ -285,6 +283,16 @@ exitOnQ需要enhancedPromptChoices=true,其实enhancedPromptChoices最好就是t promptMarks和switchOnQ、switchOnA在功能上是相同的,都是根据关键字跳转分支,promptMarks先执行,不分轮次不分QA,switchOnQ和switchOnA更具体,区分Q和A,区分轮次,实现细节跳转。 +--- + +## 故事模式效果(QQ开放平台) + +![效果图](/pic/3.png) + +![效果图](/pic/4.png) + +--- + ## 已知问题 如果有固定且不需要切换的分支,请设置该yml的promptMarksLength为99999 diff --git a/server/server.go b/server/server.go index eaa1706..bfcc210 100644 --- a/server/server.go +++ b/server/server.go @@ -30,12 +30,49 @@ var upgrader = websocket.Upgrader{ }, } +// 全局变量和互斥锁 +var ( + selfIDs []string + selfIDsMu sync.Mutex +) + +// AddSelfID 添加一个 ID 到全局切片中 +func AddSelfID(id string) { + selfIDsMu.Lock() + defer selfIDsMu.Unlock() + selfIDs = append(selfIDs, id) +} + +// GetSelfIDs 返回当前保存的所有 ID +func GetSelfIDs() []string { + selfIDsMu.Lock() + defer selfIDsMu.Unlock() + // 返回切片的副本以防止外部修改 + copiedIDs := make([]string, len(selfIDs)) + copy(copiedIDs, selfIDs) + return copiedIDs +} + +// IsSelfIDExists 检查一个 ID 是否存在于全局切片中 +func IsSelfIDExists(id string) bool { + selfIDsMu.Lock() + defer selfIDsMu.Unlock() + for _, sid := range selfIDs { + if sid == id { + return true + } + } + return false +} + // 用于处理WebSocket连接 func WsHandler(w http.ResponseWriter, r *http.Request, config *config.Config) { // 从请求头或URL查询参数中提取token tokenFromHeader := r.Header.Get("Authorization") selfID := r.Header.Get("X-Self-ID") fmtf.Printf("接入机器人X-Self-ID[%v]", selfID) + // 加入到数组里 + AddSelfID(selfID) var token string if strings.HasPrefix(tokenFromHeader, "Token ") { token = strings.TrimPrefix(tokenFromHeader, "Token ") @@ -86,13 +123,13 @@ func WsHandler(w http.ResponseWriter, r *http.Request, config *config.Config) { } if messageType == websocket.TextMessage { - processWSMessage(p, selfID) + processWSMessage(p) } } } // 处理收到的信息 -func processWSMessage(msg []byte, selfid string) { +func processWSMessage(msg []byte) { var genericMap map[string]interface{} if err := json.Unmarshal(msg, &genericMap); err != nil { log.Printf("Error unmarshalling message to map: %v, Original message: %s\n", err, string(msg)) @@ -131,9 +168,9 @@ func processWSMessage(msg []byte, selfid string) { // 构造请求URL var url string if config.GetLotus() == "" { - url = "http://127.0.0.1:" + fmt.Sprint(port) + "/gensokyo?selfid=" + selfid + url = "http://127.0.0.1:" + fmt.Sprint(port) + "/gensokyo" } else { - url = config.GetLotus() + "/gensokyo?selfid=" + selfid + url = config.GetLotus() + "/gensokyo" } // 创建POST请求 diff --git a/structs/struct.go b/structs/struct.go index a04e96e..3c9cebd 100644 --- a/structs/struct.go +++ b/structs/struct.go @@ -254,6 +254,7 @@ type Settings struct { Port int `yaml:"port"` SelfPath string `yaml:"selfPath"` HttpPath string `yaml:"path"` + HttpPaths []string `yaml:"paths"` Lotus string `yaml:"lotus"` PathToken string `yaml:"pathToken"` SystemPrompt []string `yaml:"systemPrompt"` diff --git a/template/config_template.go b/template/config_template.go index 215e99a..d258476 100644 --- a/template/config_template.go +++ b/template/config_template.go @@ -10,6 +10,7 @@ settings: port : 46233 #本程序监听端口,支持gensokyo http上报, 请在gensokyo的反向http配置加入 post_url: ["http://127.0.0.1:port/gensokyo"] selfPath : "" #本程序监听地址,不包含http头,请放通port到公网,仅发图场景需要填写,可以是域名,暂不支持https. path : "http://123.123.123.123:11111" #调用gensokyo api的地址,填入 gensokyo 的 正向http地址 http_address: "0.0.0.0:46231" 对应填入 "http://127.0.0.1:46231" + paths : [] #当要连接多个onebotv11的http正向地址时,多个地址填入这里. lotus : "" #当填写另一个gensokyo-llm的http地址时,将请求另一个的conversation端点,实现多个llm不需要多次配置,简化配置,单独使用请忽略留空.例:http://192.168.0.1:12345(包含http头和端口) pathToken : "" #gensokyo正向http-api的access_token(是onebotv11标准的) apiType : 0 #0=混元 1=文心(文心平台包含了N种模型...) 2=gpt 3=rwkv 4=通义千问 5=智谱AI diff --git a/utils/utils.go b/utils/utils.go index 0c57b76..f543ef5 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -44,6 +44,57 @@ type MessageIDInfo struct { var UserIDMessageIDs = make(map[int64][]MessageIDInfo) var muUserIDMessageIDs sync.RWMutex // 用于UserIDMessageIDs的读写锁 +var ( + baseURLMap = make(map[string]string) + baseURLMapMu sync.Mutex +) + +// 结构体用于解析 JSON 响应 +type loginInfoResponse struct { + Status string `json:"status"` + Retcode int `json:"retcode"` + Data struct { + UserID int64 `json:"user_id"` + Nickname string `json:"nickname"` + } `json:"data"` +} + +// 构造 URL 并请求数据 +func FetchAndStoreUserIDs() { + httpPaths := config.GetHttpPaths() + for _, baseURL := range httpPaths { + url := baseURL + "/get_login_info" + resp, err := http.Get(url) + if err != nil { + fmtf.Printf("Error fetching login info from %s: %v", url, err) + continue + } + defer resp.Body.Close() + + var result loginInfoResponse + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + fmtf.Printf("Error decoding response from %s: %v", url, err) + continue + } + + if result.Retcode == 0 && result.Status == "ok" { + fmtf.Printf("成功绑定机器人selfid[%v]onebot api baseURL[%v]", result.Data.UserID, baseURL) + baseURLMapMu.Lock() + useridstr := strconv.FormatInt(result.Data.UserID, 10) + baseURLMap[useridstr] = baseURL + baseURLMapMu.Unlock() + } + } +} + +// GetBaseURLByUserID 通过 user_id 获取 baseURL +func GetBaseURLByUserID(userID string) (string, bool) { + baseURLMapMu.Lock() + defer baseURLMapMu.Unlock() + url, exists := baseURLMap[userID] + return url, exists +} + func GenerateUUID() string { return uuid.New().String() } @@ -158,7 +209,7 @@ func ExtractEventDetails(eventData map[string]interface{}) (string, structs.Usag func SendGroupMessage(groupID int64, userID int64, message string, selfid string) error { //TODO: 用userid作为了echo,在ws收到回调信息的时候,加入到全局撤回数组,AddMessageID,实现撤回 - if selfid != "" { + if server.IsSelfIDExists(selfid) { // 创建消息结构体 msg := map[string]interface{}{ "action": "send_group_msg", @@ -173,8 +224,13 @@ func SendGroupMessage(groupID int64, userID int64, message string, selfid string // 发送消息 return server.SendMessageBySelfID(selfid, msg) } - // 获取基础URL - baseURL := config.GetHttpPath() // 假设config.getHttpPath()返回基础URL + var baseURL string + if len(config.GetHttpPaths()) > 0 { + baseURL, _ = GetBaseURLByUserID(selfid) + } else { + // 获取基础URL + baseURL = config.GetHttpPath() // 假设config.getHttpPath()返回基础URL + } // 构建完整的URL baseURL = baseURL + "/send_group_msg" @@ -255,7 +311,7 @@ func SendGroupMessage(groupID int64, userID int64, message string, selfid string func SendGroupMessageMdPromptKeyboard(groupID int64, userID int64, message string, selfid string, newmsg string, response string, promptstr string) error { //TODO: 用userid作为了echo,在ws收到回调信息的时候,加入到全局撤回数组,AddMessageID,实现反向ws连接时候的撤回 - if selfid != "" { + if server.IsSelfIDExists(selfid) { // 创建消息结构体 msg := map[string]interface{}{ "action": "send_group_msg", @@ -493,7 +549,7 @@ func SendGroupMessageMdPromptKeyboard(groupID int64, userID int64, message strin } func SendPrivateMessage(UserID int64, message string, selfid string) error { - if selfid != "" { + if server.IsSelfIDExists(selfid) { // 创建消息结构体 msg := map[string]interface{}{ "action": "send_private_msg", @@ -507,8 +563,13 @@ func SendPrivateMessage(UserID int64, message string, selfid string) error { // 发送消息 return server.SendMessageBySelfID(selfid, msg) } - // 获取基础URL - baseURL := config.GetHttpPath() // 假设config.getHttpPath()返回基础URL + var baseURL string + if len(config.GetHttpPaths()) > 0 { + baseURL, _ = GetBaseURLByUserID(selfid) + } else { + // 获取基础URL + baseURL = config.GetHttpPath() // 假设config.getHttpPath()返回基础URL + } // 构建完整的URL baseURL = baseURL + "/send_private_msg" @@ -587,7 +648,7 @@ func SendPrivateMessage(UserID int64, message string, selfid string) error { } func SendPrivateMessageRaw(UserID int64, message string, selfid string) error { - if selfid != "" { + if server.IsSelfIDExists(selfid) { // 创建消息结构体 msg := map[string]interface{}{ "action": "send_private_msg", @@ -601,8 +662,13 @@ func SendPrivateMessageRaw(UserID int64, message string, selfid string) error { // 发送消息 return server.SendMessageBySelfID(selfid, msg) } - // 获取基础URL - baseURL := config.GetHttpPath() // 假设config.getHttpPath()返回基础URL + var baseURL string + if len(config.GetHttpPaths()) > 0 { + baseURL, _ = GetBaseURLByUserID(selfid) + } else { + // 获取基础URL + baseURL = config.GetHttpPath() // 假设config.getHttpPath()返回基础URL + } // 构建完整的URL baseURL = baseURL + "/send_private_msg"