From 45212dc447cd756c191013faf788eaaa94c8e487 Mon Sep 17 00:00:00 2001
From: SanaeFox <36219542+Hoshinonyaruko@users.noreply.github.com>
Date: Tue, 18 Jun 2024 12:58:38 +0800
Subject: [PATCH] Beta153 (#152)
* 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
* beta121
* beta122
* beta123
* beta124
* beta125
* beta126
* beta127
* beta128
* beta129
* beta130
* beta131
* beta132
* beta1333
* beta134
* beta135
* beta136
* beta137
* beta138
* beta139
* beta140
* beta141
* beta142
* beta143
* beta144
* beta145
* beta146
* beta148
* beta149
* beta150
* beta151
* beta151
* beta152
---
applogic/gensokyo.go | 3 +-
applogic/memory.go | 3 +-
go.mod | 30 +-
go.sum | 71 +-
.../promptkeyboard.go => promptkb/promptkb.go | 47 +-
utils/promptkeyboard.go | 1911 -----------------
utils/utils.go | 3 +-
7 files changed, 57 insertions(+), 2011 deletions(-)
rename applogic/promptkeyboard.go => promptkb/promptkb.go (78%)
delete mode 100644 utils/promptkeyboard.go
diff --git a/applogic/gensokyo.go b/applogic/gensokyo.go
index 9ef30b1..f6149d0 100644
--- a/applogic/gensokyo.go
+++ b/applogic/gensokyo.go
@@ -17,6 +17,7 @@ import (
"github.com/hoshinonyaruko/gensokyo-llm/config"
"github.com/hoshinonyaruko/gensokyo-llm/fmtf"
"github.com/hoshinonyaruko/gensokyo-llm/prompt"
+ "github.com/hoshinonyaruko/gensokyo-llm/promptkb"
"github.com/hoshinonyaruko/gensokyo-llm/structs"
"github.com/hoshinonyaruko/gensokyo-llm/utils"
)
@@ -981,7 +982,7 @@ func (app *App) GensokyoHandler(w http.ResponseWriter, r *http.Request) {
promptkeyboard = config.GetPromptkeyboard()
} else {
fmtf.Printf("ai生成气泡:%v", "Q"+newmsg+"A"+response)
- promptkeyboard = GetPromptKeyboardAI("Q"+newmsg+"A"+response, promptstr)
+ promptkeyboard = promptkb.GetPromptKeyboardAI("Q"+newmsg+"A"+response, promptstr)
}
// 使用acnode.CheckWordOUT()过滤promptkeyboard中的每个字符串
diff --git a/applogic/memory.go b/applogic/memory.go
index 41893bd..a1488d4 100644
--- a/applogic/memory.go
+++ b/applogic/memory.go
@@ -14,6 +14,7 @@ import (
"github.com/hoshinonyaruko/gensokyo-llm/config"
"github.com/hoshinonyaruko/gensokyo-llm/fmtf"
+ "github.com/hoshinonyaruko/gensokyo-llm/promptkb"
"github.com/hoshinonyaruko/gensokyo-llm/structs"
"github.com/hoshinonyaruko/gensokyo-llm/utils"
)
@@ -60,7 +61,7 @@ func GetMemoryTitle(msg string) string {
}
fmt.Printf("Response: %s\n", string(responseBody))
- var responseData ResponseDataPromptKeyboard
+ var responseData promptkb.ResponseDataPromptKeyboard
if err := json.Unmarshal(responseBody, &responseData); err != nil {
fmt.Printf("Error unmarshalling response data: %v[%v]\n", err, string(responseBody))
return "默认标题"
diff --git a/go.mod b/go.mod
index 5b3170f..d3690b7 100644
--- a/go.mod
+++ b/go.mod
@@ -9,36 +9,16 @@ require (
gopkg.in/yaml.v3 v3.0.1
)
-require github.com/abadojack/whatlanggo v1.0.1
+require (
+ github.com/abadojack/whatlanggo v1.0.1
+ github.com/gorilla/websocket v1.5.1
+ github.com/longbridgeapp/opencc v0.3.11
+)
require (
- github.com/bytedance/sonic v1.9.1 // indirect
- github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
- github.com/gabriel-vasile/mimetype v1.4.2 // indirect
- github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/gin-gonic/gin v1.9.1 // indirect
- github.com/go-playground/locales v0.14.1 // indirect
- github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.14.0 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
- github.com/gorilla/websocket v1.5.1 // indirect
- github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/cpuid/v2 v2.2.4 // indirect
- github.com/leodido/go-urn v1.2.4 // indirect
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d // indirect
- github.com/longbridgeapp/opencc v0.3.11 // indirect
- github.com/mattn/go-isatty v0.0.19 // indirect
- github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
- github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/pelletier/go-toml/v2 v2.0.8 // indirect
- github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
- github.com/ugorji/go/codec v1.2.11 // indirect
- golang.org/x/arch v0.3.0 // indirect
- golang.org/x/crypto v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- google.golang.org/protobuf v1.30.0 // indirect
)
require (
diff --git a/go.sum b/go.sum
index c9475e2..cfc765c 100644
--- a/go.sum
+++ b/go.sum
@@ -1,103 +1,39 @@
github.com/abadojack/whatlanggo v1.0.1 h1:19N6YogDnf71CTHm3Mp2qhYfkRdyvbgwWdd2EPxJRG4=
github.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH9B/K8tQB2uoc=
+github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:ir/IFJU5xbja5UaBEQLjcvn7aAU01nqU/NUyOBEU+ew=
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4=
-github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
-github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
-github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
-github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
-github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
-github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
-github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
-github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
-github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
-github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
-github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
-github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
-github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
-github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
-github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:qSmEGTgjkESUX5kPMSGJ4pcBUtYVDdkNzMrjQyvRvp0=
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:x7SghIWwLVcJObXbjK7S2ENsT1cAcdJcPl7dRaSFog0=
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d h1:hTRDIpJ1FjS9ULJuEzu69n3qTgc18eI+ztw/pJv47hs=
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d/go.mod h1:7xD3p0XnHvJFQ3t/stEJd877CSIMkH/fACVWen5pYnc=
github.com/longbridgeapp/opencc v0.3.11 h1:MfozRXTRmchceDyVsJ/JoOsuXb7AqtjF7RUtWUa0cQo=
github.com/longbridgeapp/opencc v0.3.11/go.mod h1:jRuKtq8eLA+cZUu75XgMvkB/hFSXJbZDmij0v29lNaY=
-github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=
github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
-github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-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/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.839 h1:VGVFNQDaUpDsPkJrh8I9qOxHZ1yj5sJmg9ngsUvTAHM=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.839/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
-github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
-golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
-golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
-golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
-golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -106,4 +42,3 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/applogic/promptkeyboard.go b/promptkb/promptkb.go
similarity index 78%
rename from applogic/promptkeyboard.go
rename to promptkb/promptkb.go
index 3bab3fe..862a602 100644
--- a/applogic/promptkeyboard.go
+++ b/promptkb/promptkb.go
@@ -1,4 +1,4 @@
-package applogic
+package promptkb
import (
"bytes"
@@ -13,7 +13,6 @@ import (
"github.com/hoshinonyaruko/gensokyo-llm/config"
"github.com/hoshinonyaruko/gensokyo-llm/fmtf"
- "github.com/hoshinonyaruko/gensokyo-llm/utils"
)
// ResponseDataPromptKeyboard 用于解析外层响应
@@ -47,7 +46,7 @@ func GetPromptKeyboardAI(msg string, promptstr string) []string {
fmtf.Printf("Generated PromptKeyboard URL:%v\n", fullURL)
// 按提示词区分的细化替换 这里主要不是为了安全和敏感词,而是细化效果,也就没有使用acnode提高效率
- msg = utils.ReplaceTextIn(msg, keyboardprompt)
+ msg = ReplaceTextIn(msg, keyboardprompt)
requestBody, err := json.Marshal(map[string]interface{}{
"message": msg,
@@ -141,7 +140,7 @@ func GetPromptKeyboardAI(msg string, promptstr string) []string {
func ApplyReplaceTextOutToKeyboardPrompts(keyboardPrompts []string, promptstr string) []string {
for i, prompt := range keyboardPrompts {
- keyboardPrompts[i] = utils.ReplaceTextOut(prompt, promptstr)
+ keyboardPrompts[i] = ReplaceTextOut(prompt, promptstr)
}
return keyboardPrompts
}
@@ -164,3 +163,43 @@ func preprocessResponse(response string) string {
return bestMatch
}
+
+// ReplaceTextIn 使用给定的替换对列表对文本进行替换
+func ReplaceTextIn(text string, promptstr string) string {
+ // 调用 GetReplacementPairsIn 函数获取替换对列表
+ replacementPairs := config.GetReplacementPairsIn(promptstr)
+
+ if len(replacementPairs) == 0 {
+ return text
+ }
+
+ // 遍历所有的替换对,并在文本中进行替换
+ for _, pair := range replacementPairs {
+ // 使用 strings.Replace 替换文本中的所有出现
+ // 注意这里我们使用 -1 作为最后的参数,表示替换文本中的所有匹配项
+ text = strings.Replace(text, pair.OriginalWord, pair.TargetWord, -1)
+ }
+
+ // 返回替换后的文本
+ return text
+}
+
+// ReplaceTextOut 使用给定的替换对列表对文本进行替换
+func ReplaceTextOut(text string, promptstr string) string {
+ // 调用 GetReplacementPairsIn 函数获取替换对列表
+ replacementPairs := config.GetReplacementPairsOut(promptstr)
+
+ if len(replacementPairs) == 0 {
+ return text
+ }
+
+ // 遍历所有的替换对,并在文本中进行替换
+ for _, pair := range replacementPairs {
+ // 使用 strings.Replace 替换文本中的所有出现
+ // 注意这里我们使用 -1 作为最后的参数,表示替换文本中的所有匹配项
+ text = strings.Replace(text, pair.OriginalWord, pair.TargetWord, -1)
+ }
+
+ // 返回替换后的文本
+ return text
+}
diff --git a/utils/promptkeyboard.go b/utils/promptkeyboard.go
deleted file mode 100644
index bd86002..0000000
--- a/utils/promptkeyboard.go
+++ /dev/null
@@ -1,1911 +0,0 @@
-package utils
-
-import (
- "bufio"
- "bytes"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io"
- "math/rand"
- "net/http"
- "net/url"
- "os"
- "regexp"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "github.com/abadojack/whatlanggo"
- "github.com/google/uuid"
- "github.com/hoshinonyaruko/gensokyo-llm/acnode"
- "github.com/hoshinonyaruko/gensokyo-llm/config"
- "github.com/hoshinonyaruko/gensokyo-llm/fmtf"
- "github.com/hoshinonyaruko/gensokyo-llm/hunyuan"
- "github.com/hoshinonyaruko/gensokyo-llm/server"
- "github.com/hoshinonyaruko/gensokyo-llm/structs"
-)
-
-// ResponseData 是用于解析HTTP响应的结构体
-type ResponseData struct {
- Data struct {
- MessageID int64 `json:"message_id"`
- } `json:"data"`
-}
-
-// MessageIDInfo 代表消息ID及其到期时间
-type MessageIDInfo struct {
- MessageID int64 // 消息ID
- Expires time.Time // 到期时间
-}
-
-// UserIDMessageIDs 存储每个用户ID对应的消息ID数组及其有效期
-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()
-}
-
-func PrintChatProRequest(request *hunyuan.ChatProRequest) {
-
- // 打印Messages
- for i, msg := range request.Messages {
- fmtf.Printf("Message %d:\n", i)
- fmtf.Printf("Content: %s\n", *msg.Content)
- fmtf.Printf("Role: %s\n", *msg.Role)
- }
-
-}
-
-func PrintChatStdRequest(request *hunyuan.ChatStdRequest) {
-
- // 打印Messages
- for i, msg := range request.Messages {
- fmtf.Printf("Message %d:\n", i)
- fmtf.Printf("Content: %s\n", *msg.Content)
- fmtf.Printf("Role: %s\n", *msg.Role)
- }
-
-}
-
-func PrintChatCompletionsRequest(request *hunyuan.ChatCompletionsRequest) {
-
- // 打印Messages
- for i, msg := range request.Messages {
- fmtf.Printf("Message %d:\n", i)
- fmtf.Printf("Content: %s\n", *msg.Content)
- fmtf.Printf("Role: %s\n", *msg.Role)
- }
-
-}
-
-// contains 检查一个字符串切片是否包含一个特定的字符串
-func Contains(slice []string, item string) bool {
- for _, a := range slice {
- if a == item {
- return true
- }
- }
- return false
-}
-
-// 获取复合键
-func GetKey(groupid int64, userid int64) string {
- return fmt.Sprintf("%d.%d", groupid, userid)
-}
-
-// 随机的分布发送
-func ContainsRune(slice []rune, value rune, groupid int64, promptstr string) bool {
- var probability int
- if groupid == 0 {
- // 获取概率百分比
- probability = config.GetSplitByPuntuations(promptstr)
- } else {
- // 获取概率百分比
- probability = config.GetSplitByPuntuationsGroup(promptstr)
- }
-
- for _, item := range slice {
- if item == value {
- // 将概率转换为0到1之间的浮点数
- probabilityPercentage := float64(probability) / 100.0
- // 生成一个0到1之间的随机浮点数
- randomValue := rand.Float64()
- // 如果随机数小于或等于概率,则返回true
- return randomValue <= probabilityPercentage
- }
- }
- return false
-}
-
-// 取出ai回答
-func ExtractEventDetails(eventData map[string]interface{}) (string, structs.UsageInfo) {
- var responseTextBuilder strings.Builder
- var totalUsage structs.UsageInfo
-
- // 提取使用信息
- if usage, ok := eventData["Usage"].(map[string]interface{}); ok {
- var usageInfo structs.UsageInfo
- if promptTokens, ok := usage["PromptTokens"].(float64); ok {
- usageInfo.PromptTokens = int(promptTokens)
- }
- if completionTokens, ok := usage["CompletionTokens"].(float64); ok {
- usageInfo.CompletionTokens = int(completionTokens)
- }
- totalUsage.PromptTokens += usageInfo.PromptTokens
- totalUsage.CompletionTokens += usageInfo.CompletionTokens
- }
-
- // 提取AI助手的回复
- if choices, ok := eventData["Choices"].([]interface{}); ok {
- for _, choice := range choices {
- if choiceMap, ok := choice.(map[string]interface{}); ok {
- if delta, ok := choiceMap["Delta"].(map[string]interface{}); ok {
- if role, ok := delta["Role"].(string); ok && role == "assistant" {
- if content, ok := delta["Content"].(string); ok {
- responseTextBuilder.WriteString(content)
- }
- }
- }
- }
- }
- }
-
- return responseTextBuilder.String(), totalUsage
-}
-
-func SendGroupMessage(groupID int64, userID int64, message string, selfid string, promptstr string) error {
- //TODO: 用userid作为了echo,在ws收到回调信息的时候,加入到全局撤回数组,AddMessageID,实现撤回
- if server.IsSelfIDExists(selfid) {
- // 创建消息结构体
- msg := map[string]interface{}{
- "action": "send_group_msg",
- "params": map[string]interface{}{
- "group_id": groupID,
- "user_id": userID,
- "message": message,
- },
- "echo": userID,
- }
-
- // 发送消息
- return server.SendMessageBySelfID(selfid, msg)
- }
- 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"
-
- // 获取PathToken并检查其是否为空
- pathToken := config.GetPathToken()
- // 使用net/url包构建URL
- u, err := url.Parse(baseURL)
- if err != nil {
- panic("URL parsing failed: " + err.Error())
- }
-
- // 添加access_token参数
- query := u.Query()
- if pathToken != "" {
- query.Set("access_token", pathToken)
- }
- u.RawQuery = query.Encode()
-
- if config.GetSensitiveModeType() == 1 {
- message = acnode.CheckWordOUT(message)
- }
-
- //精细化替换 每个yml配置文件都可以具有一个非全局的文本替换规则
- message = ReplaceTextOut(message, promptstr)
-
- // 去除末尾的换行符 不去除会导致不好看
- message = removeTrailingCRLFs(message)
-
- // 繁体转换简体 安全策略 防止用户诱导ai发繁体绕过替换规则
- message, err = ConvertTraditionalToSimplified(message)
- if err != nil {
- fmtf.Printf("繁体转换简体失败:%v", err)
- }
-
- // 构造请求体
- requestBody, err := json.Marshal(map[string]interface{}{
- "group_id": groupID,
- "user_id": userID,
- "message": message,
- })
- fmtf.Printf("发群信息请求:%v", string(requestBody))
- fmtf.Printf("实际发送信息:%v", message)
- if err != nil {
- return fmtf.Errorf("failed to marshal request body: %w", err)
- }
-
- // 发送POST请求
- resp, err := http.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
- if err != nil {
- return fmtf.Errorf("failed to send POST request: %w", err)
- }
- defer resp.Body.Close()
-
- // 检查响应状态
- if resp.StatusCode != http.StatusOK {
- return fmtf.Errorf("received non-OK response status: %s", resp.Status)
- }
-
- // 读取响应体
- bodyBytes, err := io.ReadAll(resp.Body)
- if err != nil {
- return fmt.Errorf("failed to read response body: %w", err)
- }
-
- // 解析响应体以获取message_id
- var responseData ResponseData
- if err := json.Unmarshal(bodyBytes, &responseData); err != nil {
- return fmt.Errorf("failed to unmarshal response data: %w", err)
- }
- messageID := responseData.Data.MessageID
-
- // 添加messageID到全局变量
- AddMessageID(userID, messageID)
-
- // 输出响应体,这一步是可选的
- fmt.Println("Response Body:", string(bodyBytes))
-
- return nil
-}
-
-func SendGroupMessageMdPromptKeyboard(groupID int64, userID int64, message string, selfid string, newmsg string, response string, promptstr string) error {
- //TODO: 用userid作为了echo,在ws收到回调信息的时候,加入到全局撤回数组,AddMessageID,实现反向ws连接时候的撤回
- if server.IsSelfIDExists(selfid) {
- // 创建消息结构体
- msg := map[string]interface{}{
- "action": "send_group_msg",
- "params": map[string]interface{}{
- "group_id": groupID,
- "user_id": userID,
- "message": message,
- },
- "echo": userID,
- }
-
- // 发送消息
- return server.SendMessageBySelfID(selfid, msg)
- }
- // 获取基础URL
- baseURL := config.GetHttpPath() // 假设config.getHttpPath()返回基础URL
-
- // 构建完整的URL
- baseURL = baseURL + "/send_group_msg"
-
- // 获取PathToken并检查其是否为空
- pathToken := config.GetPathToken()
- // 使用net/url包构建URL
- u, err := url.Parse(baseURL)
- if err != nil {
- panic("URL parsing failed: " + err.Error())
- }
-
- // 添加access_token参数
- query := u.Query()
- if pathToken != "" {
- query.Set("access_token", pathToken)
- }
- u.RawQuery = query.Encode()
-
- if config.GetSensitiveModeType() == 1 {
- message = acnode.CheckWordOUT(message)
- }
-
- //精细化替换 每个yml配置文件都可以具有一个非全局的文本替换规则
- message = ReplaceTextOut(message, promptstr)
-
- // 去除末尾的换行符 不去除会导致不好看
- message = removeTrailingCRLFs(message)
-
- // 繁体转换简体 安全策略 防止用户诱导ai发繁体绕过替换规则
- message, err = ConvertTraditionalToSimplified(message)
- if err != nil {
- fmtf.Printf("繁体转换简体失败:%v", err)
- }
-
- // 首先获取当前的keyboard
- var promptkeyboard []string
- if !config.GetUseAIPromptkeyboard() {
- promptkeyboard = config.GetPromptkeyboard()
- } else {
- fmtf.Printf("ai生成气泡:%v", "Q"+newmsg+"A"+response)
- promptkeyboard = GetPromptKeyboardAI("Q"+newmsg+"A"+response, promptstr)
- }
-
- // 使用acnode.CheckWordOUT()过滤promptkeyboard中的每个字符串
- for i, item := range promptkeyboard {
- promptkeyboard[i] = acnode.CheckWordOUT(item)
- }
-
- var mdContent string
- // 这里把message构造成一个cq,md码
- if config.GetMemoryListMD() == 2 {
- //构建Markdown内容,对promptkeyboard的内容进行URL编码
- var sb strings.Builder
- // 添加初始消息
- sb.WriteString(message)
- sb.WriteString("\r")
- lastIndex := len(promptkeyboard) - 1 // 获取最后一个索引
- // 遍历promptkeyboard数组,为每个元素生成一个标签
- for i, cmd := range promptkeyboard {
- // 对每个命令进行URL编码
- encodedCmd := url.QueryEscape(cmd)
- // 构建并添加qqbot-cmd-input标签
- if i == lastIndex {
- // 如果是最后一个元素,则不添加 \r
- sb.WriteString(fmt.Sprintf("", encodedCmd, encodedCmd))
- } else {
- sb.WriteString(fmt.Sprintf("\r", encodedCmd, encodedCmd))
- }
- }
- mdContent = sb.String()
- } else {
- mdContent = message
- }
-
- fmt.Println(mdContent)
-
- // 构建Buttons
- buttons := []structs.Button{}
- // 添加promptkeyboard的按钮,每个按钮一行
- for i, label := range promptkeyboard {
- buttons = append(buttons, structs.Button{
- ID: fmt.Sprintf("%d", i+1),
- RenderData: structs.RenderData{
- Label: label,
- VisitedLabel: label,
- Style: 1,
- },
- Action: structs.Action{
- Type: 2,
- Permission: structs.Permission{
- Type: 2,
- SpecifyRoleIDs: []string{"1", "2", "3"},
- },
- Data: label,
- UnsupportTips: "请升级新版手机QQ",
- Enter: true,
- Reply: true,
- },
- })
- }
-
- // 添加"重置", "撤回", "重发"按钮,它们在一个单独的行
- rowWithThreeButtons := []structs.Button{}
- labels := []string{"重置", "忽略", "记忆", "载入"}
-
- for i, label := range labels {
- actionType := 1
- if label == "载入" {
- actionType = 2 // 设置特定的 ActionType
- }
-
- button := structs.Button{
- ID: fmt.Sprintf("%d", i+4), // 确保ID不重复
- RenderData: structs.RenderData{
- Label: label,
- VisitedLabel: label,
- Style: 1,
- },
- Action: structs.Action{
- Type: actionType, // 使用条件变量设置的 actionType
- Permission: structs.Permission{
- Type: 2,
- SpecifyRoleIDs: []string{"1", "2", "3"},
- },
- Data: label,
- UnsupportTips: "请升级新版手机QQ",
- },
- }
-
- rowWithThreeButtons = append(rowWithThreeButtons, button)
- }
-
- // 构建完整的PromptKeyboardMarkdown对象
- var rows []structs.Row // 初始化一个空切片来存放行
-
- // GetMemoryListMD==1 将buttons添加到rows
- if config.GetMemoryListMD() == 1 {
- // 遍历所有按钮,并每个按钮创建一行
- for _, button := range buttons {
- row := structs.Row{
- Buttons: []structs.Button{button}, // 将当前按钮加入到新行中
- }
- rows = append(rows, row) // 将新行添加到行切片中
- }
- }
-
- // 添加特定的 rowWithThreeButtons 至 rows 数组的末尾
- row := structs.Row{
- Buttons: rowWithThreeButtons, // 将当前三个按钮放入
- }
- rows = append(rows, row)
-
- // 构建 PromptKeyboardMarkdown 结构体
- promptKeyboardMd := structs.PromptKeyboardMarkdown{
- Markdown: structs.Markdown{
- Content: mdContent,
- },
- Keyboard: structs.Keyboard{
- Content: structs.KeyboardContent{
- Rows: rows, // 使用动态创建的行数组
- },
- },
- Content: "keyboard",
- MsgID: "123",
- Timestamp: fmt.Sprintf("%d", time.Now().Unix()),
- MsgType: 2,
- }
-
- // 序列化成JSON
- mdContentBytes, err := json.Marshal(promptKeyboardMd)
- if err != nil {
- fmt.Printf("Error marshaling to JSON: %v", err)
- return nil
- }
-
- // 编码成Base64
- encoded := base64.StdEncoding.EncodeToString(mdContentBytes)
- segmentContent := "[CQ:markdown,data=base64://" + encoded + "]"
-
- // 构造请求体
- requestBody, err := json.Marshal(map[string]interface{}{
- "group_id": groupID,
- "user_id": userID,
- "message": segmentContent,
- })
- fmtf.Printf("发群信息请求:%v", string(requestBody))
- fmtf.Printf("实际发送信息:%v", message)
- if err != nil {
- return fmtf.Errorf("failed to marshal request body: %w", err)
- }
-
- // 发送POST请求
- resp, err := http.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
- if err != nil {
- return fmtf.Errorf("failed to send POST request: %w", err)
- }
- defer resp.Body.Close()
-
- // 检查响应状态
- if resp.StatusCode != http.StatusOK {
- return fmtf.Errorf("received non-OK response status: %s", resp.Status)
- }
-
- // 读取响应体
- bodyBytes, err := io.ReadAll(resp.Body)
- if err != nil {
- return fmt.Errorf("failed to read response body: %w", err)
- }
-
- // 解析响应体以获取message_id
- var responseData ResponseData
- if err := json.Unmarshal(bodyBytes, &responseData); err != nil {
- return fmt.Errorf("failed to unmarshal response data: %w", err)
- }
- messageID := responseData.Data.MessageID
-
- // 添加messageID到全局变量
- AddMessageID(userID, messageID)
-
- // 输出响应体,这一步是可选的
- fmt.Println("Response Body:", string(bodyBytes))
-
- return nil
-}
-
-func SendGroupMessageMdPromptKeyboardV2(groupID int64, userID int64, message string, selfid string, promptstr string, promptkeyboard []string) error {
- //TODO: 用userid作为了echo,在ws收到回调信息的时候,加入到全局撤回数组,AddMessageID,实现反向ws连接时候的撤回
- if server.IsSelfIDExists(selfid) {
- // 创建消息结构体
- msg := map[string]interface{}{
- "action": "send_group_msg",
- "params": map[string]interface{}{
- "group_id": groupID,
- "user_id": userID,
- "message": message,
- },
- "echo": userID,
- }
-
- // 发送消息
- return server.SendMessageBySelfID(selfid, msg)
- }
- // 获取基础URL
- baseURL := config.GetHttpPath() // 假设config.getHttpPath()返回基础URL
-
- // 构建完整的URL
- baseURL = baseURL + "/send_group_msg"
-
- // 获取PathToken并检查其是否为空
- pathToken := config.GetPathToken()
- // 使用net/url包构建URL
- u, err := url.Parse(baseURL)
- if err != nil {
- panic("URL parsing failed: " + err.Error())
- }
-
- // 添加access_token参数
- query := u.Query()
- if pathToken != "" {
- query.Set("access_token", pathToken)
- }
- u.RawQuery = query.Encode()
-
- if config.GetSensitiveModeType() == 1 {
- message = acnode.CheckWordOUT(message)
- }
-
- //精细化替换 每个yml配置文件都可以具有一个非全局的文本替换规则
- message = ReplaceTextOut(message, promptstr)
-
- // 去除末尾的换行符 不去除会导致不好看
- message = removeTrailingCRLFs(message)
-
- // 繁体转换简体 安全策略 防止用户诱导ai发繁体绕过替换规则
- message, err = ConvertTraditionalToSimplified(message)
- if err != nil {
- fmtf.Printf("繁体转换简体失败:%v", err)
- }
- var mdContent string
- // 这里把message构造成一个cq,md码
- if config.GetMemoryListMD() == 2 {
- //构建Markdown内容,对promptkeyboard的内容进行URL编码
- var sb strings.Builder
- // 添加初始消息
- sb.WriteString(message)
- sb.WriteString("\r")
- lastIndex := len(promptkeyboard) - 1 // 获取最后一个索引
- // 遍历promptkeyboard数组,为每个元素生成一个标签
- for i, cmd := range promptkeyboard {
- // 对每个命令进行URL编码
- encodedCmd := url.QueryEscape(cmd)
- // 构建并添加qqbot-cmd-input标签
- if i == lastIndex {
- // 如果是最后一个元素,则不添加 \r
- sb.WriteString(fmt.Sprintf("", encodedCmd, encodedCmd))
- } else {
- sb.WriteString(fmt.Sprintf("\r", encodedCmd, encodedCmd))
- }
- }
- mdContent = sb.String()
- } else {
- mdContent = message
- }
-
- fmt.Println(mdContent)
- var promptKeyboardMd structs.PromptKeyboardMarkdown
- if config.GetMemoryListMD() == 1 {
- // 构建Buttons
- buttons := []structs.Button{}
- // 添加promptkeyboard的按钮,每个按钮一行
- for i, label := range promptkeyboard {
- buttons = append(buttons, structs.Button{
- ID: fmt.Sprintf("%d", i+1),
- RenderData: structs.RenderData{
- Label: label,
- VisitedLabel: "已载入",
- Style: 1,
- },
- Action: structs.Action{
- Type: 2,
- Permission: structs.Permission{
- Type: 2,
- SpecifyRoleIDs: []string{"1", "2", "3"},
- },
- Data: label,
- UnsupportTips: "请升级新版手机QQ",
- Enter: true,
- Reply: true,
- },
- })
- }
-
- // 构建完整的PromptKeyboardMarkdown对象
- var rows []structs.Row // 初始化一个空切片来存放行
-
- // 遍历所有按钮,并每个按钮创建一行
- for _, button := range buttons {
- row := structs.Row{
- Buttons: []structs.Button{button}, // 将当前按钮加入到新行中
- }
- rows = append(rows, row) // 将新行添加到行切片中
- }
-
- // 构建 PromptKeyboardMarkdown 结构体
- promptKeyboardMd = structs.PromptKeyboardMarkdown{
- Markdown: structs.Markdown{
- Content: mdContent,
- },
- Keyboard: structs.Keyboard{
- Content: structs.KeyboardContent{
- Rows: rows, // 使用动态创建的行数组
- },
- },
- Content: "keyboard",
- MsgID: "123",
- Timestamp: fmt.Sprintf("%d", time.Now().Unix()),
- MsgType: 2,
- }
- } else {
- // 构建 PromptKeyboardMarkdown 结构体
- promptKeyboardMd = structs.PromptKeyboardMarkdown{
- Markdown: structs.Markdown{
- Content: mdContent,
- },
- Content: "keyboard",
- MsgID: "123",
- Timestamp: fmt.Sprintf("%d", time.Now().Unix()),
- MsgType: 2,
- }
- }
-
- // 序列化成JSON
- mdContentBytes, err := json.Marshal(promptKeyboardMd)
- if err != nil {
- fmt.Printf("Error marshaling to JSON: %v", err)
- return nil
- }
-
- // 编码成Base64
- encoded := base64.StdEncoding.EncodeToString(mdContentBytes)
- segmentContent := "[CQ:markdown,data=base64://" + encoded + "]"
-
- // 构造请求体
- requestBody, err := json.Marshal(map[string]interface{}{
- "group_id": groupID,
- "user_id": userID,
- "message": segmentContent,
- })
- fmtf.Printf("发群信息请求:%v", string(requestBody))
- fmtf.Printf("实际发送信息:%v", message)
- if err != nil {
- return fmtf.Errorf("failed to marshal request body: %w", err)
- }
-
- // 发送POST请求
- resp, err := http.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
- if err != nil {
- return fmtf.Errorf("failed to send POST request: %w", err)
- }
- defer resp.Body.Close()
-
- // 检查响应状态
- if resp.StatusCode != http.StatusOK {
- return fmtf.Errorf("received non-OK response status: %s", resp.Status)
- }
-
- // 读取响应体
- bodyBytes, err := io.ReadAll(resp.Body)
- if err != nil {
- return fmt.Errorf("failed to read response body: %w", err)
- }
-
- // 解析响应体以获取message_id
- var responseData ResponseData
- if err := json.Unmarshal(bodyBytes, &responseData); err != nil {
- return fmt.Errorf("failed to unmarshal response data: %w", err)
- }
- messageID := responseData.Data.MessageID
-
- // 添加messageID到全局变量
- AddMessageID(userID, messageID)
-
- // 输出响应体,这一步是可选的
- fmt.Println("Response Body:", string(bodyBytes))
-
- return nil
-}
-
-func SendPrivateMessage(UserID int64, message string, selfid string, promptstr string) error {
- if server.IsSelfIDExists(selfid) {
- // 创建消息结构体
- msg := map[string]interface{}{
- "action": "send_private_msg",
- "params": map[string]interface{}{
- "user_id": UserID,
- "message": message,
- },
- "echo": UserID,
- }
-
- // 发送消息
- return server.SendMessageBySelfID(selfid, msg)
- }
- 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"
-
- // 获取PathToken并检查其是否为空
- pathToken := config.GetPathToken()
- // 使用net/url包构建URL
- u, err := url.Parse(baseURL)
- if err != nil {
- panic("URL parsing failed: " + err.Error())
- }
-
- // 添加access_token参数
- query := u.Query()
- if pathToken != "" {
- query.Set("access_token", pathToken)
- }
- u.RawQuery = query.Encode()
-
- if config.GetSensitiveModeType() == 1 {
- message = acnode.CheckWordOUT(message)
- }
-
- //精细化替换 每个yml配置文件都可以具有一个非全局的文本替换规则
- message = ReplaceTextOut(message, promptstr)
-
- // 去除末尾的换行符 不去除会导致不好看
- message = removeTrailingCRLFs(message)
-
- // 繁体转换简体 安全策略 防止用户诱导ai发繁体绕过替换规则
- message, err = ConvertTraditionalToSimplified(message)
- if err != nil {
- fmtf.Printf("繁体转换简体失败:%v", err)
- }
-
- // 构造请求体
- requestBody, err := json.Marshal(map[string]interface{}{
- "user_id": UserID,
- "message": message,
- })
-
- if err != nil {
- return fmtf.Errorf("failed to marshal request body: %w", err)
- }
- fmtf.Printf("实际发送信息:%v", message)
-
- // 发送POST请求
- resp, err := http.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
- if err != nil {
- return fmtf.Errorf("failed to send POST request: %w", err)
- }
- defer resp.Body.Close()
-
- // 检查响应状态
- if resp.StatusCode != http.StatusOK {
- return fmtf.Errorf("received non-OK response status: %s", resp.Status)
- }
-
- // 读取响应体
- bodyBytes, err := io.ReadAll(resp.Body)
- if err != nil {
- return fmt.Errorf("failed to read response body: %w", err)
- }
-
- // 解析响应体以获取message_id
- var responseData ResponseData
- if err := json.Unmarshal(bodyBytes, &responseData); err != nil {
- return fmt.Errorf("failed to unmarshal response data: %w", err)
- }
- messageID := responseData.Data.MessageID
-
- // 添加messageID到全局变量
- AddMessageID(UserID, messageID)
-
- // 输出响应体,这一步是可选的
- fmt.Println("Response Body:", string(bodyBytes))
-
- return nil
-}
-
-func SendPrivateMessageRaw(UserID int64, message string, selfid string) error {
- if server.IsSelfIDExists(selfid) {
- // 创建消息结构体
- msg := map[string]interface{}{
- "action": "send_private_msg",
- "params": map[string]interface{}{
- "user_id": UserID,
- "message": message,
- },
- "echo": UserID,
- }
-
- // 发送消息
- return server.SendMessageBySelfID(selfid, msg)
- }
- 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"
-
- // 获取PathToken并检查其是否为空
- pathToken := config.GetPathToken()
- // 使用net/url包构建URL
- u, err := url.Parse(baseURL)
- if err != nil {
- panic("URL parsing failed: " + err.Error())
- }
-
- // 添加access_token参数
- query := u.Query()
- if pathToken != "" {
- query.Set("access_token", pathToken)
- }
- u.RawQuery = query.Encode()
-
- // 构造请求体
- requestBody, err := json.Marshal(map[string]interface{}{
- "user_id": UserID,
- "message": message,
- })
-
- if err != nil {
- return fmtf.Errorf("failed to marshal request body: %w", err)
- }
-
- // 发送POST请求
- resp, err := http.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
- if err != nil {
- return fmtf.Errorf("failed to send POST request: %w", err)
- }
- defer resp.Body.Close()
-
- // 检查响应状态
- if resp.StatusCode != http.StatusOK {
- return fmtf.Errorf("received non-OK response status: %s", resp.Status)
- }
-
- // 读取响应体
- bodyBytes, err := io.ReadAll(resp.Body)
- if err != nil {
- return fmt.Errorf("failed to read response body: %w", err)
- }
-
- // 解析响应体以获取message_id
- var responseData ResponseData
- if err := json.Unmarshal(bodyBytes, &responseData); err != nil {
- return fmt.Errorf("failed to unmarshal response data: %w", err)
- }
- messageID := responseData.Data.MessageID
-
- // 添加messageID到全局变量
- AddMessageID(UserID, messageID)
-
- // 输出响应体,这一步是可选的
- fmt.Println("Response Body:", string(bodyBytes))
-
- return nil
-}
-
-func SendPrivateMessageSSE(UserID int64, message structs.InterfaceBody, promptstr string) error {
- // 获取基础URL
- baseURL := config.GetHttpPath() // 假设config.GetHttpPath()返回基础URL
-
- // 构建完整的URL
- baseURL = baseURL + "/send_private_msg_sse"
-
- // 获取PathToken并检查其是否为空
- pathToken := config.GetPathToken()
- // 使用net/url包构建URL
- u, err := url.Parse(baseURL)
- if err != nil {
- panic("URL parsing failed: " + err.Error())
- }
-
- // 添加access_token参数
- query := u.Query()
- if pathToken != "" {
- query.Set("access_token", pathToken)
- }
- u.RawQuery = query.Encode()
-
- // 调试用的
- if config.GetPrintHanming() {
- fmtf.Printf("流式信息替换前:%v", message.Content)
- }
-
- // 检查是否需要启用敏感词过滤
- if config.GetSensitiveModeType() == 1 && message.Content != "" {
- message.Content = acnode.CheckWordOUT(message.Content)
- }
-
- //精细化替换 每个yml配置文件都可以具有一个非全局的文本替换规则
- message.Content = ReplaceTextOut(message.Content, promptstr)
-
- // 调试用的
- if config.GetPrintHanming() {
- fmtf.Printf("流式信息替换后:%v", message.Content)
- }
-
- // 去除末尾的换行符 不去除会导致sse接口始终等待
- message.Content = removeTrailingCRLFs(message.Content)
-
- // 繁体转换简体 安全策略 防止用户诱导ai发繁体绕过替换规则
- message.Content, err = ConvertTraditionalToSimplified(message.Content)
- if err != nil {
- fmtf.Printf("繁体转换简体失败:%v", err)
- }
-
- if message.Content == "" {
- message.Content = " "
- fmtf.Printf("过滤空SendPrivateMessageSSE,可能是llm api只发了换行符.")
- return nil
- }
-
- fmtf.Printf("实际发送信息:%v", message.Content)
-
- // 构造请求体,包括InterfaceBody
- requestBody, err := json.Marshal(map[string]interface{}{
- "user_id": UserID,
- "message": message,
- })
- if err != nil {
- return fmtf.Errorf("failed to marshal request body: %w", err)
- }
-
- // 发送POST请求
- resp, err := http.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
- if err != nil {
- return fmtf.Errorf("failed to send POST request: %w", err)
- }
- defer resp.Body.Close()
-
- // 检查响应状态
- if resp.StatusCode != http.StatusOK {
- return fmtf.Errorf("received non-OK response status: %s", resp.Status)
- }
-
- // 读取响应体
- bodyBytes, err := io.ReadAll(resp.Body)
- if err != nil {
- return fmt.Errorf("failed to read response body: %w", err)
- }
-
- // 解析响应体以获取message_id
- var responseData ResponseData
- if err := json.Unmarshal(bodyBytes, &responseData); err != nil {
- return fmt.Errorf("failed to unmarshal response data: %w", err)
- }
- messageID := responseData.Data.MessageID
-
- // 添加messageID到全局变量
- AddMessageID(UserID, messageID)
-
- // 输出响应体,这一步是可选的
- fmt.Println("Response Body:", string(bodyBytes))
-
- return nil
-}
-
-// removeTrailingCRLFs 移除字符串末尾的所有CRLF换行符
-func removeTrailingCRLFs(input string) string {
- // 将字符串转换为字节切片
- byteMessage := []byte(input)
-
- // CRLF的字节表示
- crlf := []byte{'\r', '\n'}
-
- // 循环移除末尾的CRLF
- for bytes.HasSuffix(byteMessage, crlf) {
- byteMessage = bytes.TrimSuffix(byteMessage, crlf)
- }
-
- // LFLF的字节表示
- lflf := []byte{'\n', '\n'}
-
- // 循环移除末尾的LFLF
- for bytes.HasSuffix(byteMessage, lflf) {
- byteMessage = bytes.TrimSuffix(byteMessage, lflf)
- }
-
- // 将处理后的字节切片转换回字符串
- return string(byteMessage)
-}
-
-// ReverseString 颠倒给定字符串中的字符顺序
-func ReverseString(s string) string {
- // // 将字符串转换为rune切片,以便处理多字节字符
- // runes := []rune(s)
- // for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
- // // 交换前后对应的字符
- // runes[i], runes[j] = runes[j], runes[i]
- // }
- // // 将颠倒后的rune切片转换回字符串
- // return string(runes)
- return "####" + s + "####"
-}
-
-// RemoveBracketsContent 接收一个字符串,并移除所有[[...]]的内容
-func RemoveBracketsContent(input string) string {
- // 编译一个正则表达式,用于匹配[[任意字符]]的模式
- re := regexp.MustCompile(`\[\[.*?\]\]`)
- // 使用正则表达式的ReplaceAllString方法删除匹配的部分
- return re.ReplaceAllString(input, "")
-}
-
-// RemoveAtTagContentConditional 接收一个字符串和一个 int64 类型的 selfid,
-// 并根据条件移除[@selfowd]格式的内容,然后去除前后的空格。
-// 只有当标签中的ID与传入的selfid相匹配时才进行移除,
-// 如果没有任何[@xxx]出现或者所有出现的[@xxx]中的xxx都不等于selfid时,返回原字符串。
-func RemoveAtTagContentConditionalWithoutAddNick(input string, message structs.OnebotGroupMessage) string {
- // 将 int64 类型的 selfid 转换为字符串
- selfidStr := strconv.FormatInt(message.SelfID, 10)
-
- // 编译一个正则表达式,用于匹配并捕获[@任意字符]的模式
- re := regexp.MustCompile(`\[@(.*?)\]`)
- matches := re.FindAllStringSubmatch(input, -1)
-
- // 如果没有找到任何匹配项,直接返回原输入,代表不带at的信息,会在更上方判断是否处理.同时根据配置项为请求增加名字.
- if len(matches) == 0 { //私聊无法at 只会走这里,只会有nick生效
- return input
- }
-
- foundSelfId := false // 用于跟踪是否找到与selfid相匹配的标签
-
- // 遍历所有匹配项
- for _, match := range matches {
- if match[1] == selfidStr {
- // 如果找到与selfid相匹配的标签,替换该标签
- input = strings.Replace(input, match[0], "", -1)
- foundSelfId = true // 标记已找到至少一个与selfid相匹配的标签
- } else {
- input = strings.Replace(input, match[0], "", -1)
- }
- }
-
- // 只有在包含了at 但是at不包含自己,才忽略信息
- if !foundSelfId {
- // 如果没有找到任何与selfid相匹配的标签,将输入置为空,代表不响应这一条信息
- input = ""
- }
-
- // 去除前后的空格
- cleaned := strings.TrimSpace(input)
- return cleaned
-}
-
-// RemoveAtTagContentConditional 接收一个字符串和一个 int64 类型的 selfid,
-// 并根据条件移除[@selfowd]格式的内容,然后去除前后的空格。
-// 只有当标签中的ID与传入的selfid相匹配时才进行移除,
-// 如果没有任何[@xxx]出现或者所有出现的[@xxx]中的xxx都不等于selfid时,返回原字符串。
-func RemoveAtTagContentConditional(input string, message structs.OnebotGroupMessage, promptstr string) string {
-
- // 获取特殊名称替换对数组
- specialNames := config.GetSpecialNameToQ(promptstr)
-
- // 将 int64 类型的 selfid 转换为字符串
- selfidStr := strconv.FormatInt(message.SelfID, 10)
-
- // 编译一个正则表达式,用于匹配并捕获[@任意字符]的模式
- re := regexp.MustCompile(`\[@(.*?)\]`)
- matches := re.FindAllStringSubmatch(input, -1)
-
- // 如果没有找到任何匹配项,直接返回原输入,代表不带at的信息,会在更上方判断是否处理.同时根据配置项为请求增加名字.
- if len(matches) == 0 { //私聊无法at 只会走这里,只会有nick生效
- var name string
- name = ""
- // 可以都是2 打开 呈现覆盖关系
- if config.GetGroupAddCardToQ(promptstr) == 2 {
- if message.Sender.Card != "" {
- name = "[username:" + message.Sender.Card + "]"
- }
- }
-
- if config.GetGroupAddNicknameToQ(promptstr) == 2 && name == "" {
- if message.Sender.Nickname != "" {
- name = "[username:" + message.Sender.Nickname + "]"
- }
- }
-
- useridstr := strconv.FormatInt(message.UserID, 10)
- // 遍历特殊名称数组,检查是否需要进行进一步替换
- for _, replacement := range specialNames {
- if useridstr == replacement.ID {
- name = "[username:" + replacement.Name + "]"
- break // 找到匹配,跳出循环
- }
- }
-
- if name != "" {
- input = name + input
- }
-
- return input
- }
-
- foundSelfId := false // 用于跟踪是否找到与selfid相匹配的标签
-
- // 遍历所有匹配项
- for _, match := range matches {
- if match[1] == selfidStr {
- // 把at自己的信息替换为当前at自己的人的昵称或者群名片
- var name string
- name = "" // 初始状态
-
- // 可以都是2 打开 呈现覆盖关系
- if config.GetGroupAddCardToQ(promptstr) == 2 {
- if message.Sender.Card != "" {
- name = "[username:" + message.Sender.Card + "]"
- }
- }
-
- if config.GetGroupAddNicknameToQ(promptstr) == 2 && name == "" {
- if message.Sender.Nickname != "" {
- name = "[username:" + message.Sender.Nickname + "]"
- }
- }
-
- useridstr := strconv.FormatInt(message.UserID, 10)
- // 遍历特殊名称数组,检查是否需要进行进一步替换
- for _, replacement := range specialNames {
- if useridstr == replacement.ID {
- name = "[username:" + replacement.Name + "]"
- break // 找到匹配,跳出循环
- }
- }
-
- // 如果找到与selfid相匹配的标签,替换该标签
- input = strings.Replace(input, match[0], name, -1)
- foundSelfId = true // 标记已找到至少一个与selfid相匹配的标签
- } else {
- var name string
- name = ""
-
- // 可以都是2 打开 呈现覆盖关系
- if config.GetGroupAddCardToQ(promptstr) == 2 {
- if message.Sender.Card != "" {
- name = "[username:" + message.Sender.Card + "]"
- }
- }
-
- // 将CQat标签替换为名字
- if config.GetGroupAddNicknameToQ(promptstr) == 2 && name == "" {
- if message.Sender.Nickname != "" {
- name = "[username:" + message.Sender.Nickname + "]"
- }
- }
-
- // 遍历特殊名称数组,检查是否需要进行进一步替换
- for _, replacement := range specialNames {
- if match[1] == replacement.ID {
- name = "[username:" + replacement.Name + "]"
- break // 找到匹配,跳出循环
- }
- }
-
- input = strings.Replace(input, match[0], name, -1)
- }
- }
-
- // 只有在包含了at 但是at不包含自己,才忽略信息
- if !foundSelfId {
- // 如果没有找到任何与selfid相匹配的标签,将输入置为空,代表不响应这一条信息
- input = ""
- }
-
- // 去除前后的空格
- cleaned := strings.TrimSpace(input)
- return cleaned
-}
-
-func PostSensitiveMessages() error {
- port := config.GetPort() // 从config包获取端口号
- var portStr string
- if config.GetLotus() == "" {
- portStr = fmt.Sprintf("http://127.0.0.1:%d/gensokyo", port) // 根据端口号构建URL
- } else {
- portStr = config.GetLotus() + "/gensokyo"
- }
-
- file, err := os.Open("test.txt")
- if err != nil {
- return err
- }
- defer file.Close()
-
- scanner := bufio.NewScanner(file)
- var results []string
- for scanner.Scan() {
- text := scanner.Text()
-
- // 使用读取的文本填充message和raw_message字段
- data := structs.OnebotGroupMessage{
- Font: 0,
- Message: text,
- MessageID: 0,
- MessageSeq: 0,
- MessageType: "private",
- PostType: "message",
- RawMessage: text,
- RealMessageType: "group_private",
- SelfID: 100000000,
- Sender: structs.Sender{
- Nickname: "测试脚本",
- UserID: 100000000,
- },
- SubType: "friend",
- Time: 1700000000,
- UserID: 100000000,
- }
-
- jsonData, err := json.Marshal(data)
- if err != nil {
- return err
- }
-
- response, err := http.Post(portStr, "application/json", bytes.NewBuffer(jsonData))
- if err != nil {
- return err
- }
- defer response.Body.Close()
-
- responseBody, err := io.ReadAll(response.Body)
- if err != nil {
- return err
- }
- fmtf.Printf("测试脚本运行中:%v", results)
- results = append(results, string(responseBody))
- }
-
- // 使用当前时间戳生成文件名
- currentTime := time.Now()
- fileName := "test_result_" + currentTime.Format("20060102_150405") + ".txt"
-
- // 将HTTP响应结果保存到指定的文件中
- return os.WriteFile(fileName, []byte(strings.Join(results, "\n")), 0644)
-}
-
-// SendSSEPrivateMessage 分割并发送消息的核心逻辑,直接遍历字符串
-func SendSSEPrivateMessage(userID int64, content string, promptstr string) {
- punctuations := []rune{'。', '!', '?', ',', ',', '.', '!', '?', '~'}
- splitProbability := config.GetSplitByPuntuations()
-
- var parts []string
- var currentPart strings.Builder
-
- for _, runeValue := range content {
- currentPart.WriteRune(runeValue)
- if strings.ContainsRune(string(punctuations), runeValue) {
- // 根据概率决定是否分割
- if rand.Intn(100) < splitProbability {
- parts = append(parts, currentPart.String())
- currentPart.Reset()
- }
- }
- }
- // 添加最后一部分(如果有的话)
- if currentPart.Len() > 0 {
- parts = append(parts, currentPart.String())
- }
-
- // 根据parts长度处理状态
- for i, part := range parts {
- state := 1
- if i == len(parts)-2 { // 倒数第二部分
- state = 11
- } else if i == len(parts)-1 { // 最后一部分
- state = 20
- }
-
- // 构造消息体并发送
- messageSSE := structs.InterfaceBody{
- Content: part,
- State: state,
- }
-
- if state == 20 { // 对最后一部分特殊处理
- MemoryLoadCommand := config.GetMemoryLoadCommand()
- promptKeyboard := config.GetPromptkeyboard()
-
- if len(MemoryLoadCommand) > 0 {
- selectedRestoreResponse := MemoryLoadCommand[rand.Intn(len(MemoryLoadCommand))]
- if len(promptKeyboard) > 0 {
- promptKeyboard[0] = selectedRestoreResponse
- }
- }
-
- messageSSE.PromptKeyboard = promptKeyboard
- }
-
- // 发送SSE消息函数
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
- }
-}
-
-// SendSSEPrivateMessageWithKeyboard 分割并发送消息的核心逻辑,直接遍历字符串
-func SendSSEPrivateMessageWithKeyboard(userID int64, content string, keyboard []string, promptstr string) {
- punctuations := []rune{'。', '!', '?', ',', ',', '.', '!', '?', '~'}
- splitProbability := config.GetSplitByPuntuations()
-
- var parts []string
- var currentPart strings.Builder
-
- for _, runeValue := range content {
- currentPart.WriteRune(runeValue)
- if strings.ContainsRune(string(punctuations), runeValue) {
- // 根据概率决定是否分割
- if rand.Intn(100) < splitProbability {
- parts = append(parts, currentPart.String())
- currentPart.Reset()
- }
- }
- }
- // 添加最后一部分(如果有的话)
- if currentPart.Len() > 0 {
- parts = append(parts, currentPart.String())
- }
-
- // 根据parts长度处理状态
- for i, part := range parts {
- state := 1
- if i == len(parts)-2 { // 倒数第二部分
- state = 11
- } else if i == len(parts)-1 { // 最后一部分
- state = 20
- }
-
- // 构造消息体并发送
- messageSSE := structs.InterfaceBody{
- Content: part,
- State: state,
- }
-
- if state == 20 { // 对最后一部分特殊处理
- var promptKeyboard []string
- if len(keyboard) == 0 {
- RestoreResponses := config.GetRestoreCommand()
- promptKeyboard = config.GetPromptkeyboard()
-
- if len(RestoreResponses) > 0 {
- selectedRestoreResponse := RestoreResponses[rand.Intn(len(RestoreResponses))]
- if len(promptKeyboard) > 0 {
- promptKeyboard[0] = selectedRestoreResponse
- }
- }
- } else {
- promptKeyboard = keyboard
- }
-
- messageSSE.PromptKeyboard = promptKeyboard
- }
-
- // 发送SSE消息函数
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
- }
-}
-
-// SendSSEPrivateMessageByline 分割并发送消息的核心逻辑,直接遍历字符串
-func SendSSEPrivateMessageByLine(userID int64, content string, keyboard []string, promptstr string) {
- // 直接使用 strings.Split 按行分割字符串
- parts := strings.Split(content, "\n")
-
- // 根据parts长度处理状态
- for i, part := range parts {
- if part == "" {
- continue // 跳过空行
- }
-
- state := 1
- if i == len(parts)-2 { // 倒数第二部分
- state = 11
- } else if i == len(parts)-1 { // 最后一部分
- state = 20
- }
-
- // 构造消息体并发送
- messageSSE := structs.InterfaceBody{
- Content: part + "\n",
- State: state,
- }
-
- if state == 20 { // 对最后一部分特殊处理
- var promptKeyboard []string
- if len(keyboard) == 0 {
- RestoreResponses := config.GetRestoreCommand()
- promptKeyboard = config.GetPromptkeyboard()
-
- if len(RestoreResponses) > 0 {
- selectedRestoreResponse := RestoreResponses[rand.Intn(len(RestoreResponses))]
- if len(promptKeyboard) > 0 {
- promptKeyboard[0] = selectedRestoreResponse
- }
- }
- } else {
- promptKeyboard = keyboard
- }
-
- messageSSE.PromptKeyboard = promptKeyboard
- }
-
- // 发送SSE消息函数
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
- }
-}
-
-// SendSSEPrivateSafeMessage 分割并发送安全消息的核心逻辑,直接遍历字符串
-func SendSSEPrivateSafeMessage(userID int64, saveresponse string, promptstr string) {
- // 将字符串转换为rune切片,以正确处理多字节字符
- runes := []rune(saveresponse)
-
- // 计算每部分应该包含的rune数量
- partLength := len(runes) / 3
-
- // 初始化用于存储分割结果的切片
- parts := make([]string, 3)
-
- // 按字符分割字符串
- for i := 0; i < 3; i++ {
- if i < 2 { // 前两部分
- start := i * partLength
- end := start + partLength
- parts[i] = string(runes[start:end])
- } else { // 最后一部分,包含所有剩余的字符
- start := i * partLength
- parts[i] = string(runes[start:])
- }
- }
- // 开头
- messageSSE := structs.InterfaceBody{
- Content: parts[0],
- State: 1,
- }
-
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
-
- // 中间
- messageSSE = structs.InterfaceBody{
- Content: parts[1],
- State: 11,
- }
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
-
- // 从配置中获取恢复响应数组
- RestoreResponses := config.GetRestoreCommand()
-
- var selectedRestoreResponse string
- // 如果RestoreResponses至少有一个成员,则随机选择一个
- if len(RestoreResponses) > 0 {
- selectedRestoreResponse = RestoreResponses[rand.Intn(len(RestoreResponses))]
- }
-
- // 从配置中获取promptkeyboard
- promptkeyboard := config.GetPromptkeyboard()
-
- // 确保promptkeyboard至少有一个成员
- if len(promptkeyboard) > 0 {
- // 使用随机选中的RestoreResponse替换promptkeyboard的第一个成员
- promptkeyboard[0] = selectedRestoreResponse
- }
-
- // 创建InterfaceBody结构体实例
- messageSSE = structs.InterfaceBody{
- Content: parts[2], // 假设空格字符串是期望的内容
- State: 20, // 假设的状态码
- PromptKeyboard: promptkeyboard, // 使用更新后的promptkeyboard
- }
-
- // 发送SSE私人消息
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
-}
-
-// SendSSEPrivateRestoreMessage 分割并发送重置消息的核心逻辑,直接遍历字符串
-func SendSSEPrivateRestoreMessage(userID int64, RestoreResponse string, promptstr string) {
- // 将字符串转换为rune切片,以正确处理多字节字符
- runes := []rune(RestoreResponse)
-
- // 计算每部分应该包含的rune数量
- partLength := len(runes) / 3
-
- // 初始化用于存储分割结果的切片
- parts := make([]string, 3)
-
- // 按字符分割字符串
- for i := 0; i < 3; i++ {
- if i < 2 { // 前两部分
- start := i * partLength
- end := start + partLength
- parts[i] = string(runes[start:end])
- } else { // 最后一部分,包含所有剩余的字符
- start := i * partLength
- parts[i] = string(runes[start:])
- }
- }
-
- // 开头
- messageSSE := structs.InterfaceBody{
- Content: parts[0],
- State: 1,
- }
-
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
-
- //中间
- messageSSE = structs.InterfaceBody{
- Content: parts[1],
- State: 11,
- }
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
-
- // 从配置中获取promptkeyboard
- promptkeyboard := config.GetPromptkeyboard()
-
- // 创建InterfaceBody结构体实例
- messageSSE = structs.InterfaceBody{
- Content: parts[2], // 假设空格字符串是期望的内容
- State: 20, // 假设的状态码
- PromptKeyboard: promptkeyboard, // 使用更新后的promptkeyboard
- }
-
- // 发送SSE私人消息
- SendPrivateMessageSSE(userID, messageSSE, promptstr)
-}
-
-// LanguageIntercept 检查文本语言,如果不在允许列表中,则返回 true 并发送消息
-func LanguageIntercept(text string, message structs.OnebotGroupMessage, selfid string, promptstr string) bool {
- hintWords := config.GetGroupHintWords()
- // 遍历所有触发词,将其从文本中剔除
- for _, word := range hintWords {
- text = strings.Replace(text, word, "", -1)
- }
- info := whatlanggo.Detect(text)
- lang := whatlanggo.LangToString(info.Lang)
- fmtf.Printf("LanguageIntercept:%v\n", lang)
-
- allowedLanguages := config.GetAllowedLanguages()
- for _, allowed := range allowedLanguages {
- if strings.Contains(allowed, lang) {
- return false // 语言允许,不拦截
- }
- }
-
- // 语言不允许,进行拦截
- responseMessage := config.GetLanguagesResponseMessages()
- friendlyName := FriendlyLanguageNameCN(info.Lang)
- responseMessage = strings.Replace(responseMessage, "**", friendlyName, -1)
-
- // 发送响应消息
- if message.RealMessageType == "group_private" || message.MessageType == "private" {
- if !config.GetUsePrivateSSE() {
- SendPrivateMessage(message.UserID, responseMessage, selfid, promptstr)
- } else {
- SendSSEPrivateMessage(message.UserID, responseMessage, promptstr)
- }
- } else {
- SendGroupMessage(message.GroupID, message.UserID, responseMessage, selfid, promptstr)
- }
-
- return true // 拦截
-}
-
-// FriendlyLanguageNameCN 将语言代码映射为中文名称
-func FriendlyLanguageNameCN(lang whatlanggo.Lang) string {
- langMapCN := map[whatlanggo.Lang]string{
- whatlanggo.Eng: "英文",
- whatlanggo.Cmn: "中文",
- whatlanggo.Spa: "西班牙文",
- whatlanggo.Por: "葡萄牙文",
- whatlanggo.Rus: "俄文",
- whatlanggo.Jpn: "日文",
- whatlanggo.Deu: "德文",
- whatlanggo.Kor: "韩文",
- whatlanggo.Fra: "法文",
- whatlanggo.Ita: "意大利文",
- whatlanggo.Tur: "土耳其文",
- whatlanggo.Pol: "波兰文",
- whatlanggo.Nld: "荷兰文",
- whatlanggo.Hin: "印地文",
- whatlanggo.Ben: "孟加拉文",
- whatlanggo.Vie: "越南文",
- whatlanggo.Ukr: "乌克兰文",
- whatlanggo.Swe: "瑞典文",
- whatlanggo.Fin: "芬兰文",
- whatlanggo.Dan: "丹麦文",
- whatlanggo.Heb: "希伯来文",
- whatlanggo.Tha: "泰文",
- // 根据需要添加更多语言
- }
-
- // 获取中文的语言名称,如果没有找到,则返回"未知语言"
- name, ok := langMapCN[lang]
- if !ok {
- return "未知语言"
- }
- return name
-}
-
-// LengthIntercept 检查文本长度,如果超过最大长度,则返回 true 并发送消息
-func LengthIntercept(text string, message structs.OnebotGroupMessage, selfid string, promptstr string) bool {
- maxLen := config.GetQuestionMaxLenth()
- if len(text) > maxLen {
- // 长度超出限制,获取并发送响应消息
- responseMessage := config.GetQmlResponseMessages()
-
- // 根据消息类型发送响应
- if message.RealMessageType == "group_private" || message.MessageType == "private" {
- if !config.GetUsePrivateSSE() {
- SendPrivateMessage(message.UserID, responseMessage, selfid, promptstr)
- } else {
- SendSSEPrivateMessage(message.UserID, responseMessage, promptstr)
- }
- } else {
- SendGroupMessage(message.GroupID, message.UserID, responseMessage, selfid, promptstr)
- }
-
- return true // 拦截
- }
- return false // 长度符合要求,不拦截
-}
-
-// AddMessageID 为指定user_id添加新的消息ID
-func AddMessageID(userID int64, messageID int64) {
- muUserIDMessageIDs.Lock()
- defer muUserIDMessageIDs.Unlock()
-
- // 消息ID的有效期是120秒
- expiration := time.Now().Add(120 * time.Second)
- messageInfo := MessageIDInfo{MessageID: messageID, Expires: expiration}
-
- // 清理已过期的消息ID
- cleanExpiredMessageIDs(userID)
-
- // 添加新的消息ID
- UserIDMessageIDs[userID] = append(UserIDMessageIDs[userID], messageInfo)
-}
-
-// cleanExpiredMessageIDs 清理指定user_id的已过期消息ID
-func cleanExpiredMessageIDs(userID int64) {
- validMessageIDs := []MessageIDInfo{}
- for _, messageInfo := range UserIDMessageIDs[userID] {
- if messageInfo.Expires.After(time.Now()) {
- validMessageIDs = append(validMessageIDs, messageInfo)
- }
- }
- UserIDMessageIDs[userID] = validMessageIDs
-}
-
-// GetLatestValidMessageID 获取指定user_id当前有效的最新消息ID
-func GetLatestValidMessageID(userID int64) (int64, bool) {
- muUserIDMessageIDs.RLock()
- defer muUserIDMessageIDs.RUnlock()
-
- // 确保已过期的消息ID被清理
- cleanExpiredMessageIDs(userID)
-
- // 获取最新的消息ID
- if len(UserIDMessageIDs[userID]) > 0 {
- latestMessageInfo := UserIDMessageIDs[userID][len(UserIDMessageIDs[userID])-1]
- return latestMessageInfo.MessageID, true
- }
- return 0, false
-}
-
-// sendDeleteRequest 发送删除消息的请求,并输出响应内容
-func sendDeleteRequest(url string, requestBody []byte) error {
- // 发送POST请求
- resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody))
- if err != nil {
- return fmt.Errorf("failed to send POST request: %w", err)
- }
- defer resp.Body.Close()
-
- // 检查响应状态
- if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("received non-OK response status: %s", resp.Status)
- }
-
- // 读取响应体
- bodyBytes, err := io.ReadAll(resp.Body)
- if err != nil {
- return fmt.Errorf("failed to read response body: %w", err)
- }
-
- // 将响应体转换为字符串,并输出
- bodyString := string(bodyBytes)
- fmt.Println("Response Body:", bodyString)
-
- return nil
-}
-
-func DeleteLatestMessage(messageType string, id int64, userid int64) error {
- // 获取基础URL
- baseURL := config.GetHttpPath() // 假设config.GetHttpPath()返回基础URL
-
- // 构建完整的URL
- baseURL = baseURL + "/delete_msg"
-
- // 获取PathToken并检查其是否为空
- pathToken := config.GetPathToken()
- // 使用net/url包构建URL
- u, err := url.Parse(baseURL)
- if err != nil {
- panic("URL parsing failed: " + err.Error())
- }
-
- // 添加access_token参数
- query := u.Query()
- if pathToken != "" {
- query.Set("access_token", pathToken)
- }
- u.RawQuery = query.Encode()
-
- // 获取最新的有效消息ID
- messageID, valid := GetLatestValidMessageID(userid)
- if !valid {
- return fmt.Errorf("no valid message ID found for user/group/guild ID: %d", id)
- }
-
- // 构造请求体
- requestBody := make(map[string]interface{})
- requestBody["message_id"] = strconv.FormatInt(messageID, 10)
-
- // 根据type填充相应的ID字段
- switch messageType {
- case "group_private":
- requestBody["user_id"] = id
- case "group":
- requestBody["group_id"] = id
- case "guild":
- requestBody["channel_id"] = id
- case "guild_private":
- requestBody["guild_id"] = id
- case "interaction":
- requestBody["group_id"] = id
- default:
- return fmt.Errorf("unsupported message type: %s", messageType)
- }
-
- requestBodyBytes, err := json.Marshal(requestBody)
- if err != nil {
- return fmt.Errorf("failed to marshal request body: %w", err)
- }
- fmtf.Printf("发送撤回请求:%v", string(requestBodyBytes))
-
- // 发送删除消息请求
- return sendDeleteRequest(u.String(), requestBodyBytes)
-}
-
-// MakeAlternating ensures that roles alternate between "user" and "assistant".
-func MakeAlternating(messages []structs.MessageContent) []structs.MessageContent {
- if len(messages) < 2 {
- return messages // Not enough messages to need alternation or check
- }
-
- // Initialize placeholders for the last seen user and assistant content
- var lastUserContent, lastAssistantContent []structs.ContentItem
-
- correctedMessages := make([]structs.MessageContent, 0, len(messages))
- expectedRole := "user" // Start expecting "user" initially; this changes as we find roles
-
- for _, message := range messages {
- if message.Role != expectedRole {
- // If the current message does not match the expected role, insert the last seen content of the expected role
- if expectedRole == "user" && lastUserContent != nil {
- correctedMessages = append(correctedMessages, structs.MessageContent{Role: "user", Content: lastUserContent})
- } else if expectedRole == "assistant" && lastAssistantContent != nil {
- correctedMessages = append(correctedMessages, structs.MessageContent{Role: "assistant", Content: lastAssistantContent})
- }
- }
-
- // Append the current message and update last seen contents
- correctedMessages = append(correctedMessages, message)
- if message.Role == "user" {
- lastUserContent = message.Content
- expectedRole = "assistant"
- } else if message.Role == "assistant" {
- lastAssistantContent = message.Content
- expectedRole = "user"
- }
- }
-
- return correctedMessages
-}
-
-// ReplaceTextIn 使用给定的替换对列表对文本进行替换
-func ReplaceTextIn(text string, promptstr string) string {
- // 调用 GetReplacementPairsIn 函数获取替换对列表
- replacementPairs := config.GetReplacementPairsIn(promptstr)
-
- if len(replacementPairs) == 0 {
- return text
- }
-
- // 遍历所有的替换对,并在文本中进行替换
- for _, pair := range replacementPairs {
- // 使用 strings.Replace 替换文本中的所有出现
- // 注意这里我们使用 -1 作为最后的参数,表示替换文本中的所有匹配项
- text = strings.Replace(text, pair.OriginalWord, pair.TargetWord, -1)
- }
-
- // 返回替换后的文本
- return text
-}
-
-// ReplaceTextOut 使用给定的替换对列表对文本进行替换
-func ReplaceTextOut(text string, promptstr string) string {
- // 调用 GetReplacementPairsIn 函数获取替换对列表
- replacementPairs := config.GetReplacementPairsOut(promptstr)
-
- if len(replacementPairs) == 0 {
- return text
- }
-
- // 遍历所有的替换对,并在文本中进行替换
- for _, pair := range replacementPairs {
- // 使用 strings.Replace 替换文本中的所有出现
- // 注意这里我们使用 -1 作为最后的参数,表示替换文本中的所有匹配项
- text = strings.Replace(text, pair.OriginalWord, pair.TargetWord, -1)
- }
-
- // 返回替换后的文本
- return text
-}
diff --git a/utils/utils.go b/utils/utils.go
index bd86002..c678ad0 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -23,6 +23,7 @@ import (
"github.com/hoshinonyaruko/gensokyo-llm/config"
"github.com/hoshinonyaruko/gensokyo-llm/fmtf"
"github.com/hoshinonyaruko/gensokyo-llm/hunyuan"
+ "github.com/hoshinonyaruko/gensokyo-llm/promptkb"
"github.com/hoshinonyaruko/gensokyo-llm/server"
"github.com/hoshinonyaruko/gensokyo-llm/structs"
)
@@ -372,7 +373,7 @@ func SendGroupMessageMdPromptKeyboard(groupID int64, userID int64, message strin
promptkeyboard = config.GetPromptkeyboard()
} else {
fmtf.Printf("ai生成气泡:%v", "Q"+newmsg+"A"+response)
- promptkeyboard = GetPromptKeyboardAI("Q"+newmsg+"A"+response, promptstr)
+ promptkeyboard = promptkb.GetPromptKeyboardAI("Q"+newmsg+"A"+response, promptstr)
}
// 使用acnode.CheckWordOUT()过滤promptkeyboard中的每个字符串