mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 13:59:39 +08:00
Merge branch 'FloatTech:master' into feature-rsshub-20250914
This commit is contained in:
commit
b1d4bdfebf
@ -1644,12 +1644,12 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 设置AI聊天触发概率10
|
- [x] 设置AI聊天触发概率10
|
||||||
- [x] 设置AI聊天温度80
|
- [x] 设置AI聊天温度80
|
||||||
- [x] 设置AI聊天接口类型[OpenAI|OLLaMA|GenAI]
|
- [x] 设置AI聊天(识图)接口类型[OpenAI|OLLaMA|GenAI]
|
||||||
- [x] 设置AI聊天(不)使用Agent模式
|
- [x] 设置AI聊天(不)使用Agent模式
|
||||||
- [x] 设置AI聊天(不)支持系统提示词
|
- [x] 设置AI聊天(不)支持系统提示词
|
||||||
- [x] 设置AI聊天接口地址https://api.siliconflow.cn/v1/chat/completions
|
- [x] 设置AI聊天(识图)接口地址https://api.siliconflow.cn/v1/chat/completions
|
||||||
- [x] 设置AI聊天密钥xxx
|
- [x] 设置AI聊天(识图)密钥xxx
|
||||||
- [x] 设置AI聊天模型名Qwen/Qwen3-8B
|
- [x] 设置AI聊天(识图)模型名Qwen/Qwen3-8B
|
||||||
- [x] 查看AI聊天系统提示词
|
- [x] 查看AI聊天系统提示词
|
||||||
- [x] 重置AI聊天系统提示词
|
- [x] 重置AI聊天系统提示词
|
||||||
- [x] 设置AI聊天系统提示词xxx
|
- [x] 设置AI聊天系统提示词xxx
|
||||||
|
|||||||
8
go.mod
8
go.mod
@ -12,7 +12,7 @@ require (
|
|||||||
github.com/FloatTech/sqlite v1.7.1
|
github.com/FloatTech/sqlite v1.7.1
|
||||||
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562
|
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562
|
||||||
github.com/FloatTech/zbpctrl v1.7.0
|
github.com/FloatTech/zbpctrl v1.7.0
|
||||||
github.com/FloatTech/zbputils v1.7.2-0.20250922144137-bf2b9bb6a8d9
|
github.com/FloatTech/zbputils v1.7.2-0.20250925155009-638ed762e15e
|
||||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
|
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
|
||||||
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5
|
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5
|
||||||
github.com/Tnze/go-mc v1.20.2
|
github.com/Tnze/go-mc v1.20.2
|
||||||
@ -22,9 +22,9 @@ require (
|
|||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/fumiama/ahsai v0.1.0
|
github.com/fumiama/ahsai v0.1.0
|
||||||
github.com/fumiama/cron v1.3.0
|
github.com/fumiama/cron v1.3.0
|
||||||
github.com/fumiama/deepinfra v0.0.0-20250920170049-e3d1b92cc3a1
|
github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa
|
||||||
github.com/fumiama/go-base16384 v1.7.0
|
github.com/fumiama/go-base16384 v1.7.0
|
||||||
github.com/fumiama/go-onebot-agent v0.0.0-20250922152742-c40bb3512d63
|
github.com/fumiama/go-onebot-agent v0.0.0-20250925150209-46ace7c2b17a
|
||||||
github.com/fumiama/go-registry v0.2.7
|
github.com/fumiama/go-registry v0.2.7
|
||||||
github.com/fumiama/gotracemoe v0.0.3
|
github.com/fumiama/gotracemoe v0.0.3
|
||||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565
|
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565
|
||||||
@ -66,7 +66,7 @@ require (
|
|||||||
github.com/faiface/beep v1.1.0 // indirect
|
github.com/faiface/beep v1.1.0 // indirect
|
||||||
github.com/fumiama/go-simple-protobuf v0.2.0 // indirect
|
github.com/fumiama/go-simple-protobuf v0.2.0 // indirect
|
||||||
github.com/fumiama/gofastTEA v0.0.10 // indirect
|
github.com/fumiama/gofastTEA v0.0.10 // indirect
|
||||||
github.com/fumiama/imgsz v0.0.2 // indirect
|
github.com/fumiama/imgsz v0.0.4 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.0.4 // indirect
|
github.com/gabriel-vasile/mimetype v1.0.4 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
|||||||
16
go.sum
16
go.sum
@ -17,8 +17,8 @@ github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562 h1:snfw7FNFym1eNnLrQ
|
|||||||
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||||
github.com/FloatTech/zbpctrl v1.7.0 h1:Hxo6EIhJo+pHjcQP9QgIJgluaT1pHH99zkk3njqTNMo=
|
github.com/FloatTech/zbpctrl v1.7.0 h1:Hxo6EIhJo+pHjcQP9QgIJgluaT1pHH99zkk3njqTNMo=
|
||||||
github.com/FloatTech/zbpctrl v1.7.0/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE=
|
github.com/FloatTech/zbpctrl v1.7.0/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE=
|
||||||
github.com/FloatTech/zbputils v1.7.2-0.20250922144137-bf2b9bb6a8d9 h1:iR36inettls14aMOADNQ7PHNlGvgyDRRYp2dBgZCp8A=
|
github.com/FloatTech/zbputils v1.7.2-0.20250925155009-638ed762e15e h1:M+pIxQFztHqrtUVmfctSs/D5ytn0ag6twP6iJg3gdEk=
|
||||||
github.com/FloatTech/zbputils v1.7.2-0.20250922144137-bf2b9bb6a8d9/go.mod h1:L1Rvdf6JUXGRIdKaXVtBWa0iW481zccCjYdYeDSaMXs=
|
github.com/FloatTech/zbputils v1.7.2-0.20250925155009-638ed762e15e/go.mod h1:AUDxqs7liBF2H7TpSs+OXZj1Akyh0moUN/J/j8iNFxc=
|
||||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||||
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
|
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
|
||||||
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
|
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
|
||||||
@ -63,12 +63,12 @@ github.com/fumiama/ahsai v0.1.0 h1:LXD61Kaj6kJHa3AEGsLIfKNzcgaVxg7JB72OR4yNNZ4=
|
|||||||
github.com/fumiama/ahsai v0.1.0/go.mod h1:fFeNnqgo44i8FIaguK659aQryuZeFy+4klYLQu/rfdk=
|
github.com/fumiama/ahsai v0.1.0/go.mod h1:fFeNnqgo44i8FIaguK659aQryuZeFy+4klYLQu/rfdk=
|
||||||
github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
|
github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
|
||||||
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
|
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
|
||||||
github.com/fumiama/deepinfra v0.0.0-20250920170049-e3d1b92cc3a1 h1:6PglFpNVm3DalGyRldacW2/v4jGWwn3v3q1tr2PhbVQ=
|
github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa h1:UMMNejpPp8dn92GPaVSZ2XKNSgp7+CVneOkZfExUilk=
|
||||||
github.com/fumiama/deepinfra v0.0.0-20250920170049-e3d1b92cc3a1/go.mod h1:wW05PQSn8mo1mZIoa6LBUE+3xIBjkoONvnfPTV5ZOhY=
|
github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa/go.mod h1:uqsWK/GM9OvKV0pXZOQB63rWugBbiXInY8E1JoRKhkg=
|
||||||
github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA=
|
github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA=
|
||||||
github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||||
github.com/fumiama/go-onebot-agent v0.0.0-20250922152742-c40bb3512d63 h1:ZdPMPIgZMH4HV4A/JIBb8G7UpLM4iUHWQ8qGjKnKiVI=
|
github.com/fumiama/go-onebot-agent v0.0.0-20250925150209-46ace7c2b17a h1:PapkA1fkFCzBbcmFaxRQvRAHbRig3NIgstzG7OFcXjQ=
|
||||||
github.com/fumiama/go-onebot-agent v0.0.0-20250922152742-c40bb3512d63/go.mod h1:wVMgFWkR3GpipL05FkokvrV/jWFIgoEWN1jzUGa0bWg=
|
github.com/fumiama/go-onebot-agent v0.0.0-20250925150209-46ace7c2b17a/go.mod h1:FIhZxVeFAs201W06EgXxx/6b/l/ETSmu2sQOj10kjdk=
|
||||||
github.com/fumiama/go-registry v0.2.7 h1:tLEqgEpsiybQMqBv0dLHm5leia/z1DhajMupwnOHeNs=
|
github.com/fumiama/go-registry v0.2.7 h1:tLEqgEpsiybQMqBv0dLHm5leia/z1DhajMupwnOHeNs=
|
||||||
github.com/fumiama/go-registry v0.2.7/go.mod h1:m+wp5fF8dYgVoFkBPZl+vlK90loymaJE0JCtocVQLEs=
|
github.com/fumiama/go-registry v0.2.7/go.mod h1:m+wp5fF8dYgVoFkBPZl+vlK90loymaJE0JCtocVQLEs=
|
||||||
github.com/fumiama/go-simple-protobuf v0.2.0 h1:ACyN1MAlu7pDR3EszWgzUeNP+IRsSHwH6V9JCJA5R5o=
|
github.com/fumiama/go-simple-protobuf v0.2.0 h1:ACyN1MAlu7pDR3EszWgzUeNP+IRsSHwH6V9JCJA5R5o=
|
||||||
@ -77,8 +77,8 @@ github.com/fumiama/gofastTEA v0.0.10 h1:JJJ+brWD4kie+mmK2TkspDXKzqq0IjXm89aGYfoG
|
|||||||
github.com/fumiama/gofastTEA v0.0.10/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
github.com/fumiama/gofastTEA v0.0.10/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
||||||
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
|
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
|
||||||
github.com/fumiama/gotracemoe v0.0.3/go.mod h1:tyqahdUzHf0bQIAVY/GYmDWvYYe5ik1ZbhnGYh+zl40=
|
github.com/fumiama/gotracemoe v0.0.3/go.mod h1:tyqahdUzHf0bQIAVY/GYmDWvYYe5ik1ZbhnGYh+zl40=
|
||||||
github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak=
|
github.com/fumiama/imgsz v0.0.4 h1:Lsasu2hdSSFS+vnD+nvR1UkiRMK7hcpyYCC0FzgSMFI=
|
||||||
github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4=
|
github.com/fumiama/imgsz v0.0.4/go.mod h1:bISOQVTlw9sRytPwe8ir7tAaEmyz9hSNj9n8mXMBG0E=
|
||||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 h1:sQuR2+N5HurnvsZhiKdEg+Ig354TaqgCQRxd/0KgIOQ=
|
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 h1:sQuR2+N5HurnvsZhiKdEg+Ig354TaqgCQRxd/0KgIOQ=
|
||||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565/go.mod h1:UUEvyLTJ7yoOA/viKG4wEis4ERydM7+Ny6gZUWgkS80=
|
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565/go.mod h1:UUEvyLTJ7yoOA/viKG4wEis4ERydM7+Ny6gZUWgkS80=
|
||||||
github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5 h1:jDxsIupsT84A6WHcs6kWbst+KqrRQ8/o0VyoFMnbBOA=
|
github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5 h1:jDxsIupsT84A6WHcs6kWbst+KqrRQ8/o0VyoFMnbBOA=
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package aichat
|
package aichat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -18,19 +19,92 @@ var (
|
|||||||
cfg = newconfig()
|
cfg = newconfig()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
apitypes = map[string]uint8{
|
||||||
|
"OpenAI": 0,
|
||||||
|
"OLLaMA": 1,
|
||||||
|
"GenAI": 2,
|
||||||
|
}
|
||||||
|
apilist = [3]string{"OpenAI", "OLLaMA", "GenAI"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModelType 支持打印 string 并生产 protocal
|
||||||
|
type ModelType int
|
||||||
|
|
||||||
|
func newModelType(typ string) (ModelType, error) {
|
||||||
|
t, ok := apitypes[typ]
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("未知类型 " + typ)
|
||||||
|
}
|
||||||
|
return ModelType(t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mt ModelType) String() string {
|
||||||
|
return apilist[mt]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mt ModelType) protocol(modn string, temp float32, topp float32, maxn uint) (mod model.Protocol, err error) {
|
||||||
|
switch cfg.Type {
|
||||||
|
case 0:
|
||||||
|
mod = model.NewOpenAI(
|
||||||
|
modn, cfg.Separator,
|
||||||
|
temp, topp, maxn,
|
||||||
|
)
|
||||||
|
case 1:
|
||||||
|
mod = model.NewOLLaMA(
|
||||||
|
modn, cfg.Separator,
|
||||||
|
temp, topp, maxn,
|
||||||
|
)
|
||||||
|
case 2:
|
||||||
|
mod = model.NewGenAI(
|
||||||
|
modn,
|
||||||
|
temp, topp, maxn,
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
err = errors.New("unsupported model type " + strconv.Itoa(int(cfg.Type)))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelBool 支持打印成 "是/否"
|
||||||
|
type ModelBool bool
|
||||||
|
|
||||||
|
func (mb ModelBool) String() string {
|
||||||
|
if mb {
|
||||||
|
return "是"
|
||||||
|
}
|
||||||
|
return "否"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelKey 支持隐藏密钥
|
||||||
|
type ModelKey string
|
||||||
|
|
||||||
|
func (mk ModelKey) String() string {
|
||||||
|
if len(mk) == 0 {
|
||||||
|
return "未设置"
|
||||||
|
}
|
||||||
|
if len(mk) <= 4 {
|
||||||
|
return "****"
|
||||||
|
}
|
||||||
|
key := string(mk)
|
||||||
|
return key[:2] + strings.Repeat("*", len(key)-4) + key[len(key)-2:]
|
||||||
|
}
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
ModelName string
|
ModelName string
|
||||||
Type int
|
ImageModelName string
|
||||||
|
Type ModelType
|
||||||
|
ImageType ModelType
|
||||||
MaxN uint
|
MaxN uint
|
||||||
TopP float32
|
TopP float32
|
||||||
SystemP string
|
SystemP string
|
||||||
API string
|
API string
|
||||||
Key string
|
ImageAPI string
|
||||||
|
Key ModelKey
|
||||||
|
ImageKey ModelKey
|
||||||
Separator string
|
Separator string
|
||||||
NoReplyAT bool
|
NoReplyAT ModelBool
|
||||||
NoSystemP bool
|
NoSystemP ModelBool
|
||||||
NoRecord bool
|
|
||||||
NoAgent bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newconfig() config {
|
func newconfig() config {
|
||||||
@ -41,10 +115,47 @@ func newconfig() config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *config) String() string {
|
||||||
|
topp, maxn := c.mparams()
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.WriteString(fmt.Sprintf("• 模型名:%s\n", c.ModelName))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 图像模型名:%s\n", c.ImageModelName))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 接口类型:%v\n", c.Type))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 图像接口类型:%v\n", c.ImageType))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 最大长度:%d\n", maxn))
|
||||||
|
sb.WriteString(fmt.Sprintf("• TopP:%.1f\n", topp))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 系统提示词:%s\n", c.SystemP))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 接口地址:%s\n", c.API))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 图像接口地址:%s\n", c.ImageAPI))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 密钥:%v\n", c.Key))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 图像密钥:%v\n", c.ImageKey))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 分隔符:%s\n", c.Separator))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 响应@:%v\n", !c.NoReplyAT))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 支持系统提示词:%v\n", !c.NoSystemP))
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *config) isvalid() bool {
|
func (c *config) isvalid() bool {
|
||||||
return c.ModelName != "" && c.API != "" && c.Key != ""
|
return c.ModelName != "" && c.API != "" && c.Key != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取全局模型参数:TopP和最大长度
|
||||||
|
func (c *config) mparams() (topp float32, maxn uint) {
|
||||||
|
// 处理TopP参数
|
||||||
|
topp = c.TopP
|
||||||
|
if topp == 0 {
|
||||||
|
topp = 0.9
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理最大长度参数
|
||||||
|
maxn = c.MaxN
|
||||||
|
if maxn == 0 {
|
||||||
|
maxn = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
return topp, maxn
|
||||||
|
}
|
||||||
|
|
||||||
func ensureconfig(ctx *zero.Ctx) bool {
|
func ensureconfig(ctx *zero.Ctx) bool {
|
||||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -62,7 +173,7 @@ func ensureconfig(ctx *zero.Ctx) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func newextrasetstr(ptr *string) func(ctx *zero.Ctx) {
|
func newextrasetstr[T ~string](ptr *T) func(ctx *zero.Ctx) {
|
||||||
return func(ctx *zero.Ctx) {
|
return func(ctx *zero.Ctx) {
|
||||||
args := strings.TrimSpace(ctx.State["args"].(string))
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
if args == "" {
|
if args == "" {
|
||||||
@ -74,7 +185,7 @@ func newextrasetstr(ptr *string) func(ctx *zero.Ctx) {
|
|||||||
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*ptr = args
|
*ptr = T(args)
|
||||||
err := c.SetExtra(&cfg)
|
err := c.SetExtra(&cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
@ -84,7 +195,7 @@ func newextrasetstr(ptr *string) func(ctx *zero.Ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newextrasetbool(ptr *bool) func(ctx *zero.Ctx) {
|
func newextrasetbool[T ~bool](ptr *T) func(ctx *zero.Ctx) {
|
||||||
return func(ctx *zero.Ctx) {
|
return func(ctx *zero.Ctx) {
|
||||||
args := ctx.State["regex_matched"].([]string)
|
args := ctx.State["regex_matched"].([]string)
|
||||||
isno := args[1] == "不"
|
isno := args[1] == "不"
|
||||||
@ -93,7 +204,7 @@ func newextrasetbool(ptr *bool) func(ctx *zero.Ctx) {
|
|||||||
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*ptr = isno
|
*ptr = T(isno)
|
||||||
err := c.SetExtra(&cfg)
|
err := c.SetExtra(&cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
@ -156,44 +267,3 @@ func newextrasetfloat32(ptr *float32) func(ctx *zero.Ctx) {
|
|||||||
ctx.SendChain(message.Text("成功"))
|
ctx.SendChain(message.Text("成功"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printConfig(rate int64, temperature int64, cfg config) string {
|
|
||||||
maxn := cfg.MaxN
|
|
||||||
if maxn == 0 {
|
|
||||||
maxn = 4096
|
|
||||||
}
|
|
||||||
topp := cfg.TopP
|
|
||||||
if topp == 0 {
|
|
||||||
topp = 0.9
|
|
||||||
}
|
|
||||||
var builder strings.Builder
|
|
||||||
builder.WriteString("当前AI聊天配置:\n")
|
|
||||||
builder.WriteString(fmt.Sprintf("• 模型名:%s\n", cfg.ModelName))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 接口类型:%d(%s)\n", cfg.Type, apilist[cfg.Type]))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 触发概率:%d%%\n", rate))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 温度:%.2f\n", float32(temperature)/100))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 最大长度:%d\n", maxn))
|
|
||||||
builder.WriteString(fmt.Sprintf("• TopP:%.1f\n", topp))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 系统提示词:%s\n", cfg.SystemP))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 接口地址:%s\n", cfg.API))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 密钥:%s\n", maskKey(cfg.Key)))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 分隔符:%s\n", cfg.Separator))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 响应@:%s\n", yesNo(!cfg.NoReplyAT)))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 支持系统提示词:%s\n", yesNo(!cfg.NoSystemP)))
|
|
||||||
builder.WriteString(fmt.Sprintf("• 以AI语音输出:%s\n", yesNo(!cfg.NoRecord)))
|
|
||||||
return builder.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func maskKey(key string) string {
|
|
||||||
if len(key) <= 4 {
|
|
||||||
return "****"
|
|
||||||
}
|
|
||||||
return key[:2] + strings.Repeat("*", len(key)-4) + key[len(key)-2:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func yesNo(b bool) string {
|
|
||||||
if b {
|
|
||||||
return "是"
|
|
||||||
}
|
|
||||||
return "否"
|
|
||||||
}
|
|
||||||
|
|||||||
@ -3,9 +3,7 @@ package aichat
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -17,6 +15,7 @@ import (
|
|||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
"github.com/FloatTech/AnimeAPI/airecord"
|
"github.com/FloatTech/AnimeAPI/airecord"
|
||||||
@ -35,12 +34,12 @@ var (
|
|||||||
Brief: "OpenAI聊天",
|
Brief: "OpenAI聊天",
|
||||||
Help: "- 设置AI聊天触发概率10\n" +
|
Help: "- 设置AI聊天触发概率10\n" +
|
||||||
"- 设置AI聊天温度80\n" +
|
"- 设置AI聊天温度80\n" +
|
||||||
"- 设置AI聊天接口类型[OpenAI|OLLaMA|GenAI]\n" +
|
"- 设置AI聊天(识图)接口类型[OpenAI|OLLaMA|GenAI]\n" +
|
||||||
"- 设置AI聊天(不)使用Agent模式\n" +
|
"- 设置AI聊天(不)使用Agent模式\n" +
|
||||||
"- 设置AI聊天(不)支持系统提示词\n" +
|
"- 设置AI聊天(不)支持系统提示词\n" +
|
||||||
"- 设置AI聊天接口地址https://api.siliconflow.cn/v1/chat/completions\n" +
|
"- 设置AI聊天(识图)接口地址https://api.siliconflow.cn/v1/chat/completions\n" +
|
||||||
"- 设置AI聊天密钥xxx\n" +
|
"- 设置AI聊天(识图)密钥xxx\n" +
|
||||||
"- 设置AI聊天模型名Qwen/Qwen3-8B\n" +
|
"- 设置AI聊天(识图)模型名Qwen/Qwen3-8B\n" +
|
||||||
"- 查看AI聊天系统提示词\n" +
|
"- 查看AI聊天系统提示词\n" +
|
||||||
"- 重置AI聊天系统提示词\n" +
|
"- 重置AI聊天系统提示词\n" +
|
||||||
"- 设置AI聊天系统提示词xxx\n" +
|
"- 设置AI聊天系统提示词xxx\n" +
|
||||||
@ -55,61 +54,36 @@ var (
|
|||||||
"- /gpt [内容] (使用大模型聊天)\n",
|
"- /gpt [内容] (使用大模型聊天)\n",
|
||||||
|
|
||||||
PrivateDataFolder: "aichat",
|
PrivateDataFolder: "aichat",
|
||||||
})
|
}).ApplySingle(single.New(
|
||||||
|
single.WithKeyFn(func(ctx *zero.Ctx) int64 {
|
||||||
|
if ctx.Event.GroupID == 0 {
|
||||||
|
return -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
return ctx.Event.GroupID
|
||||||
|
}),
|
||||||
|
// no post option, silently quit
|
||||||
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
apitypes = map[string]uint8{
|
|
||||||
"OpenAI": 0,
|
|
||||||
"OLLaMA": 1,
|
|
||||||
"GenAI": 2,
|
|
||||||
}
|
|
||||||
apilist = [3]string{"OpenAI", "OLLaMA", "GenAI"}
|
|
||||||
limit = ctxext.NewLimiterManager(time.Second*30, 1)
|
limit = ctxext.NewLimiterManager(time.Second*30, 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
// getModelParams 获取模型参数:温度(float32(temp)/100)、TopP和最大长度
|
|
||||||
func getModelParams(temp int64) (temperature float32, topp float32, maxn uint) {
|
|
||||||
// 处理温度参数
|
|
||||||
if temp <= 0 {
|
|
||||||
temp = 70 // default setting
|
|
||||||
}
|
|
||||||
if temp > 100 {
|
|
||||||
temp = 100
|
|
||||||
}
|
|
||||||
temperature = float32(temp) / 100
|
|
||||||
|
|
||||||
// 处理TopP参数
|
|
||||||
topp = cfg.TopP
|
|
||||||
if topp == 0 {
|
|
||||||
topp = 0.9
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理最大长度参数
|
|
||||||
maxn = cfg.MaxN
|
|
||||||
if maxn == 0 {
|
|
||||||
maxn = 4096
|
|
||||||
}
|
|
||||||
|
|
||||||
return temperature, topp, maxn
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
en.OnMessage(ensureconfig, func(ctx *zero.Ctx) bool {
|
en.OnMessage(ensureconfig, func(ctx *zero.Ctx) bool {
|
||||||
return ctx.ExtractPlainText() != "" &&
|
return ctx.ExtractPlainText() != "" &&
|
||||||
(!cfg.NoReplyAT || (cfg.NoReplyAT && !ctx.Event.IsToMe))
|
(bool(!cfg.NoReplyAT) || (bool(cfg.NoReplyAT) && !ctx.Event.IsToMe))
|
||||||
}).SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
}).SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||||
gid := ctx.Event.GroupID
|
gid := ctx.Event.GroupID
|
||||||
if gid == 0 {
|
if gid == 0 {
|
||||||
gid = -ctx.Event.UserID
|
gid = -ctx.Event.UserID
|
||||||
}
|
}
|
||||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
stor, err := newstorage(ctx, gid)
|
||||||
if !ok {
|
if err != nil {
|
||||||
|
logrus.Warnln("ERROR: ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rate := c.GetData(gid)
|
rate := stor.rate()
|
||||||
temp := (rate >> 8) & 0xff
|
|
||||||
rate &= 0xff
|
|
||||||
if !ctx.Event.IsToMe && rand.Intn(100) >= int(rate) {
|
if !ctx.Event.IsToMe && rand.Intn(100) >= int(rate) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -120,33 +94,17 @@ func init() {
|
|||||||
logrus.Warnln("ERROR: get extra err: empty key")
|
logrus.Warnln("ERROR: get extra err: empty key")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
temperature := stor.temp()
|
||||||
|
topp, maxn := cfg.mparams()
|
||||||
|
|
||||||
temperature, topp, maxn := getModelParams(temp)
|
x := deepinfra.NewAPI(cfg.API, string(cfg.Key))
|
||||||
|
mod, err := cfg.Type.protocol(cfg.ModelName, temperature, topp, maxn)
|
||||||
x := deepinfra.NewAPI(cfg.API, cfg.Key)
|
if err != nil {
|
||||||
var mod model.Protocol
|
logrus.Warnln("ERROR: ", err)
|
||||||
switch cfg.Type {
|
|
||||||
case 0:
|
|
||||||
mod = model.NewOpenAI(
|
|
||||||
cfg.ModelName, cfg.Separator,
|
|
||||||
temperature, topp, maxn,
|
|
||||||
)
|
|
||||||
case 1:
|
|
||||||
mod = model.NewOLLaMA(
|
|
||||||
cfg.ModelName, cfg.Separator,
|
|
||||||
temperature, topp, maxn,
|
|
||||||
)
|
|
||||||
case 2:
|
|
||||||
mod = model.NewGenAI(
|
|
||||||
cfg.ModelName,
|
|
||||||
temperature, topp, maxn,
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
logrus.Warnln("[aichat] unsupported AI type", cfg.Type)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cfg.NoAgent {
|
if !stor.noagent() {
|
||||||
role := goba.PermRoleUser
|
role := goba.PermRoleUser
|
||||||
if zero.AdminPermission(ctx) {
|
if zero.AdminPermission(ctx) {
|
||||||
role = goba.PermRoleAdmin
|
role = goba.PermRoleAdmin
|
||||||
@ -154,36 +112,37 @@ func init() {
|
|||||||
role = goba.PermRoleOwner
|
role = goba.PermRoleOwner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reqs, err := chat.AgentOf(ctx.Event.SelfID).GetAction(x, mod, gid, role, false)
|
ag := chat.AgentOf(ctx.Event.SelfID)
|
||||||
|
if cfg.ImageAPI != "" && !ag.CanViewImage() {
|
||||||
|
mod, err := cfg.ImageType.protocol(cfg.ImageModelName, temperature, topp, maxn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnln("[aichat] agent err:", err, reqs)
|
logrus.Warnln("ERROR: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ag.SetViewImageAPI(deepinfra.NewAPI(cfg.ImageAPI, string(cfg.ImageKey)), mod)
|
||||||
|
}
|
||||||
|
ctx.NoTimeout()
|
||||||
|
for i := 0; i < 8; i++ { // 最大运行 8 轮因为问答上下文只有 16
|
||||||
|
reqs := chat.CallAgent(ag, zero.SuperUserPermission(ctx), x, mod, gid, role)
|
||||||
|
if len(reqs) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logrus.Infoln("[aichat] agent do:", reqs)
|
|
||||||
for _, req := range reqs {
|
for _, req := range reqs {
|
||||||
if req.Action == "send_group_msg" {
|
resp := ctx.CallAction(req.Action, req.Params)
|
||||||
v, ok := req.Params["group_id"].(json.Number)
|
logrus.Infoln("[aichat] agent get resp:", reqs)
|
||||||
if !ok {
|
ag.AddResponse(gid, &goba.APIResponse{
|
||||||
logrus.Warnln("[aichat] invalid group_id type", reflect.TypeOf(req.Params["group_id"]))
|
Status: resp.Status,
|
||||||
continue
|
Data: json.RawMessage(resp.Data.Raw),
|
||||||
|
Message: resp.Message,
|
||||||
|
Wording: resp.Wording,
|
||||||
|
RetCode: resp.RetCode,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
gid, err = v.Int64()
|
|
||||||
if !ok {
|
|
||||||
logrus.Warnln("[aichat] agent conv req gid err:", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ctx.Event.GroupID != gid && !zero.SuperUserPermission(ctx) {
|
|
||||||
logrus.Warnln("[aichat] refuse to send out of grp from", ctx.Event.GroupID, "to", gid)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.CallAction(req.Action, req.Params)
|
|
||||||
process.SleepAbout1sTo2s()
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := x.Request(chat.GetChatContext(mod, gid, cfg.SystemP, cfg.NoSystemP))
|
data, err := x.Request(chat.GetChatContext(mod, gid, cfg.SystemP, bool(cfg.NoSystemP)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnln("[aichat] post err:", err)
|
logrus.Warnln("[aichat] post err:", err)
|
||||||
return
|
return
|
||||||
@ -206,7 +165,7 @@ func init() {
|
|||||||
logrus.Infoln("[aichat] 回复内容:", t)
|
logrus.Infoln("[aichat] 回复内容:", t)
|
||||||
recCfg := airecord.GetConfig()
|
recCfg := airecord.GetConfig()
|
||||||
record := ""
|
record := ""
|
||||||
if !cfg.NoRecord {
|
if !stor.norecord() {
|
||||||
record = ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, t)
|
record = ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, t)
|
||||||
}
|
}
|
||||||
if record != "" {
|
if record != "" {
|
||||||
@ -222,72 +181,8 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
en.OnPrefix("设置AI聊天触发概率", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnPrefix("设置AI聊天触发概率", zero.AdminPermission).SetBlock(true).Handle(newstoragebitmap(bitmaprate, 0, 100))
|
||||||
args := strings.TrimSpace(ctx.State["args"].(string))
|
en.OnPrefix("设置AI聊天温度", zero.AdminPermission).SetBlock(true).Handle(newstoragebitmap(bitmaptemp, 0, 100))
|
||||||
if args == "" {
|
|
||||||
ctx.SendChain(message.Text("ERROR: empty args"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
if !ok {
|
|
||||||
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r, err := strconv.Atoi(args)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: parse rate err: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if r > 100 {
|
|
||||||
r = 100
|
|
||||||
} else if r < 0 {
|
|
||||||
r = 0
|
|
||||||
}
|
|
||||||
gid := ctx.Event.GroupID
|
|
||||||
if gid == 0 {
|
|
||||||
gid = -ctx.Event.UserID
|
|
||||||
}
|
|
||||||
val := c.GetData(gid) & (^0xff)
|
|
||||||
err = c.SetData(gid, val|int64(r&0xff))
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: set data err: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Text("成功"))
|
|
||||||
})
|
|
||||||
en.OnPrefix("设置AI聊天温度", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
||||||
args := strings.TrimSpace(ctx.State["args"].(string))
|
|
||||||
if args == "" {
|
|
||||||
ctx.SendChain(message.Text("ERROR: empty args"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
if !ok {
|
|
||||||
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r, err := strconv.Atoi(args)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: parse rate err: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if r > 100 {
|
|
||||||
r = 100
|
|
||||||
} else if r < 0 {
|
|
||||||
r = 0
|
|
||||||
}
|
|
||||||
gid := ctx.Event.GroupID
|
|
||||||
if gid == 0 {
|
|
||||||
gid = -ctx.Event.UserID
|
|
||||||
}
|
|
||||||
val := c.GetData(gid) & (^0xff00)
|
|
||||||
err = c.SetData(gid, val|(int64(r&0xff)<<8))
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: set data err: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Text("成功"))
|
|
||||||
})
|
|
||||||
en.OnPrefix("设置AI聊天接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnPrefix("设置AI聊天接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
args := strings.TrimSpace(ctx.State["args"].(string))
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
if args == "" {
|
if args == "" {
|
||||||
@ -299,13 +194,37 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
typ, ok := apitypes[args]
|
typ, err := newModelType(args)
|
||||||
if !ok {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: 未知类型 ", args))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg.Type = int(typ)
|
cfg.Type = typ
|
||||||
err := c.SetExtra(&cfg)
|
err = c.SetExtra(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
})
|
||||||
|
en.OnPrefix("设置AI聊天识图接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
if args == "" {
|
||||||
|
ctx.SendChain(message.Text("ERROR: empty args"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
typ, err := newModelType(args)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg.ImageType = typ
|
||||||
|
err = c.SetExtra(&cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
return
|
return
|
||||||
@ -314,10 +233,16 @@ func init() {
|
|||||||
})
|
})
|
||||||
en.OnPrefix("设置AI聊天接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnPrefix("设置AI聊天接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(newextrasetstr(&cfg.API))
|
Handle(newextrasetstr(&cfg.API))
|
||||||
|
en.OnPrefix("设置AI聊天识图接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.ImageAPI))
|
||||||
en.OnPrefix("设置AI聊天密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnPrefix("设置AI聊天密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(newextrasetstr(&cfg.Key))
|
Handle(newextrasetstr(&cfg.Key))
|
||||||
|
en.OnPrefix("设置AI聊天识图密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.ImageKey))
|
||||||
en.OnPrefix("设置AI聊天模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnPrefix("设置AI聊天模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(newextrasetstr(&cfg.ModelName))
|
Handle(newextrasetstr(&cfg.ModelName))
|
||||||
|
en.OnPrefix("设置AI聊天识图模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.ImageModelName))
|
||||||
en.OnPrefix("设置AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnPrefix("设置AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(newextrasetstr(&cfg.SystemP))
|
Handle(newextrasetstr(&cfg.SystemP))
|
||||||
en.OnFullMatch("查看AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnFullMatch("查看AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
@ -343,31 +268,32 @@ func init() {
|
|||||||
Handle(newextrasetbool(&cfg.NoReplyAT))
|
Handle(newextrasetbool(&cfg.NoReplyAT))
|
||||||
en.OnRegex("^设置AI聊天(不)?支持系统提示词$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnRegex("^设置AI聊天(不)?支持系统提示词$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(newextrasetbool(&cfg.NoSystemP))
|
Handle(newextrasetbool(&cfg.NoSystemP))
|
||||||
en.OnRegex("^设置AI聊天(不)?使用Agent模式$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnRegex("^设置AI聊天(不)?使用Agent模式$", ensureconfig, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(newextrasetbool(&cfg.NoAgent))
|
Handle(newstoragebool(bitmapnagt))
|
||||||
en.OnPrefix("设置AI聊天最大长度", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnPrefix("设置AI聊天最大长度", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(newextrasetuint(&cfg.MaxN))
|
Handle(newextrasetuint(&cfg.MaxN))
|
||||||
en.OnPrefix("设置AI聊天TopP", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnPrefix("设置AI聊天TopP", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(newextrasetfloat32(&cfg.TopP))
|
Handle(newextrasetfloat32(&cfg.TopP))
|
||||||
en.OnRegex("^设置AI聊天(不)?以AI语音输出$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnRegex("^设置AI聊天(不)?以AI语音输出$", ensureconfig, zero.AdminPermission).SetBlock(true).
|
||||||
Handle(newextrasetbool(&cfg.NoRecord))
|
Handle(newstoragebool(bitmapnrec))
|
||||||
en.OnFullMatch("查看AI聊天配置", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
en.OnFullMatch("查看AI聊天配置", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
gid := ctx.Event.GroupID
|
||||||
if !ok {
|
stor, err := newstorage(ctx, gid)
|
||||||
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gid := ctx.Event.GroupID
|
ctx.SendChain(
|
||||||
rate := c.GetData(gid) & 0xff
|
message.Text(
|
||||||
temp := (c.GetData(gid) >> 8) & 0xff
|
"【当前AI聊天本群配置】\n",
|
||||||
if temp <= 0 {
|
"• 触发概率:", stor.rate(), "\n",
|
||||||
temp = 70 // default setting
|
"• 温度:", stor.temp(), "\n",
|
||||||
}
|
"• 以AI语音输出:", ModelBool(!stor.norecord()), "\n",
|
||||||
if temp > 100 {
|
"• 使用Agent:", ModelBool(!stor.noagent()), "\n",
|
||||||
temp = 100
|
),
|
||||||
}
|
message.Text("【当前AI聊天全局配置】\n", &cfg),
|
||||||
ctx.SendChain(message.Text(printConfig(rate, temp, cfg)))
|
)
|
||||||
})
|
})
|
||||||
en.OnFullMatch("重置AI聊天", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnFullMatch("重置AI聊天", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
chat.ResetChat()
|
chat.ResetChat()
|
||||||
@ -381,12 +307,6 @@ func init() {
|
|||||||
if gid == 0 {
|
if gid == 0 {
|
||||||
gid = -ctx.Event.UserID
|
gid = -ctx.Event.UserID
|
||||||
}
|
}
|
||||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rate := c.GetData(gid)
|
|
||||||
temp := (rate >> 8) & 0xff
|
|
||||||
p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
|
p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
|
||||||
if p > 1000 {
|
if p > 1000 {
|
||||||
p = 1000
|
p = 1000
|
||||||
@ -421,8 +341,13 @@ func init() {
|
|||||||
summaryPrompt := "请总结这个群聊内容,要求按发言顺序梳理,明确标注每个发言者的昵称,并完整呈现其核心观点、提出的问题、发表的看法或做出的回应,确保不遗漏关键信息,且能体现成员间的对话逻辑和互动关系:\n" +
|
summaryPrompt := "请总结这个群聊内容,要求按发言顺序梳理,明确标注每个发言者的昵称,并完整呈现其核心观点、提出的问题、发表的看法或做出的回应,确保不遗漏关键信息,且能体现成员间的对话逻辑和互动关系:\n" +
|
||||||
strings.Join(messages, "\n")
|
strings.Join(messages, "\n")
|
||||||
|
|
||||||
|
stor, err := newstorage(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
// 调用大模型API进行总结
|
// 调用大模型API进行总结
|
||||||
summary, err := llmchat(summaryPrompt, temp)
|
summary, err := llmchat(summaryPrompt, stor.temp())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
@ -469,12 +394,6 @@ func init() {
|
|||||||
if gid == 0 {
|
if gid == 0 {
|
||||||
gid = -ctx.Event.UserID
|
gid = -ctx.Event.UserID
|
||||||
}
|
}
|
||||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rate := c.GetData(gid)
|
|
||||||
temp := (rate >> 8) & 0xff
|
|
||||||
text := ctx.MessageString()
|
text := ctx.MessageString()
|
||||||
|
|
||||||
var query string
|
var query string
|
||||||
@ -517,8 +436,13 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stor, err := newstorage(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
// 调用大模型API进行聊天
|
// 调用大模型API进行聊天
|
||||||
reply, err := llmchat(query, temp)
|
reply, err := llmchat(query, stor.temp())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
@ -549,33 +473,17 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// llmchat 调用大模型API包装
|
// llmchat 调用大模型API包装
|
||||||
func llmchat(prompt string, temp int64) (string, error) {
|
func llmchat(prompt string, temp float32) (string, error) {
|
||||||
temperature, topp, maxn := getModelParams(temp) // 使用默认温度70
|
topp, maxn := cfg.mparams()
|
||||||
|
|
||||||
x := deepinfra.NewAPI(cfg.API, cfg.Key)
|
x := deepinfra.NewAPI(cfg.API, string(cfg.Key))
|
||||||
var mod model.Protocol
|
|
||||||
switch cfg.Type {
|
mod, err := cfg.Type.protocol(cfg.ModelName, temp, topp, maxn)
|
||||||
case 0:
|
if err != nil {
|
||||||
mod = model.NewOpenAI(
|
return "", nil
|
||||||
cfg.ModelName, cfg.Separator,
|
|
||||||
temperature, topp, maxn,
|
|
||||||
)
|
|
||||||
case 1:
|
|
||||||
mod = model.NewOLLaMA(
|
|
||||||
cfg.ModelName, cfg.Separator,
|
|
||||||
temperature, topp, maxn,
|
|
||||||
)
|
|
||||||
case 2:
|
|
||||||
mod = model.NewGenAI(
|
|
||||||
cfg.ModelName,
|
|
||||||
temperature, topp, maxn,
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
logrus.Warnln("[aichat] unsupported AI type", cfg.Type)
|
|
||||||
return "", errors.New("不支持的AI类型")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := x.Request(mod.User(prompt))
|
data, err := x.Request(mod.User(model.NewContentText(prompt)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
141
plugin/aichat/storage.go
Normal file
141
plugin/aichat/storage.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package aichat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/bits"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
bitmaprate = 0x0000ff
|
||||||
|
bitmaptemp = 0x00ff00
|
||||||
|
bitmapnagt = 0x010000
|
||||||
|
bitmapnrec = 0x020000
|
||||||
|
)
|
||||||
|
|
||||||
|
type storage int64
|
||||||
|
|
||||||
|
func newstorage(ctx *zero.Ctx, gid int64) (storage, error) {
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("找不到 manager")
|
||||||
|
}
|
||||||
|
x := c.GetData(gid)
|
||||||
|
return storage(x), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) saveto(ctx *zero.Ctx, gid int64) error {
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
return errors.New("找不到 manager")
|
||||||
|
}
|
||||||
|
return c.SetData(int64(s), gid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) getbybmp(bmp int64) int64 {
|
||||||
|
sft := bits.TrailingZeros64(uint64(bmp))
|
||||||
|
return (int64(s) & bmp) >> int64(sft)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) setbybmp(x int64, bmp int64) {
|
||||||
|
if bmp == 0 {
|
||||||
|
panic("cannot use bmp == 0")
|
||||||
|
}
|
||||||
|
sft := bits.TrailingZeros64(uint64(bmp))
|
||||||
|
*s = storage((int64(*s) & (^bmp)) | ((x & bmp) << int64(sft)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) rate() uint8 {
|
||||||
|
return uint8(s.getbybmp(bitmaprate))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) temp() float32 {
|
||||||
|
temp := s.getbybmp(bitmaptemp)
|
||||||
|
// 处理温度参数
|
||||||
|
if temp <= 0 {
|
||||||
|
temp = 70 // default setting
|
||||||
|
}
|
||||||
|
if temp > 100 {
|
||||||
|
temp = 100
|
||||||
|
}
|
||||||
|
return float32(temp) / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) noagent() bool {
|
||||||
|
return s.getbybmp(bitmapnagt) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) norecord() bool {
|
||||||
|
return s.getbybmp(bitmapnrec) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func newstoragebitmap(bmp int64, minv, maxv int64) func(ctx *zero.Ctx) {
|
||||||
|
return func(ctx *zero.Ctx) {
|
||||||
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
if args == "" {
|
||||||
|
ctx.SendChain(message.Text("ERROR: empty args"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r, err := strconv.ParseInt(args, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: parse int64 err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r > maxv {
|
||||||
|
r = maxv
|
||||||
|
} else if r < minv {
|
||||||
|
r = minv
|
||||||
|
}
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid == 0 {
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
stor, err := newstorage(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stor.setbybmp(r, bmp)
|
||||||
|
err = stor.saveto(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set data err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newstoragebool(bmp int64) func(ctx *zero.Ctx) {
|
||||||
|
if bits.OnesCount64(uint64(bmp)) != 1 {
|
||||||
|
panic("bool bmp must be 1-bit-long")
|
||||||
|
}
|
||||||
|
return func(ctx *zero.Ctx) {
|
||||||
|
args := ctx.State["regex_matched"].([]string)
|
||||||
|
iszero := args[1] == "不"
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid == 0 {
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
stor, err := newstorage(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v := 1
|
||||||
|
if iszero {
|
||||||
|
v = 0
|
||||||
|
}
|
||||||
|
stor.setbybmp(int64(v), bmp)
|
||||||
|
err = stor.saveto(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set data err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,16 +34,7 @@ var (
|
|||||||
Brief: "国际象棋",
|
Brief: "国际象棋",
|
||||||
Help: helpString,
|
Help: helpString,
|
||||||
PrivateDataFolder: "chess",
|
PrivateDataFolder: "chess",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.GroupSingle)
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text("有操作正在执行, 请稍后再试..."),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
// 图片输出
|
// 图片输出
|
||||||
@ -65,17 +64,7 @@ var (
|
|||||||
"- 下载歌单[网易云歌单链接/ID]到[歌单名称]\n" +
|
"- 下载歌单[网易云歌单链接/ID]到[歌单名称]\n" +
|
||||||
"- 解除绑定 [歌单名称]",
|
"- 解除绑定 [歌单名称]",
|
||||||
PrivateDataFolder: "guessmusic",
|
PrivateDataFolder: "guessmusic",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Break()
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text("已经有正在进行的游戏..."),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
// 用于存放歌曲三个片段的缓存文件夹
|
// 用于存放歌曲三个片段的缓存文件夹
|
||||||
cachePath = engine.DataFolder() + "cache/"
|
cachePath = engine.DataFolder() + "cache/"
|
||||||
// 用于存放用户的配置
|
// 用于存放用户的配置
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import (
|
|||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
// 反并发
|
// 反并发
|
||||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
|
||||||
// 数据库
|
// 数据库
|
||||||
sql "github.com/FloatTech/sqlite"
|
sql "github.com/FloatTech/sqlite"
|
||||||
// 画图
|
// 画图
|
||||||
@ -67,16 +67,7 @@ var (
|
|||||||
"\"娶群友\"&\"(娶|嫁)@对方QQ\"指令好感度随机增加1~5。\n\"A牛B的C\"会导致C恨A, 好感度-5;\nB为了报复A, 好感度+5(什么柜子play)\nA为BC做媒,成功B、C对A好感度+1反之-1\n做媒成功BC好感度+1" +
|
"\"娶群友\"&\"(娶|嫁)@对方QQ\"指令好感度随机增加1~5。\n\"A牛B的C\"会导致C恨A, 好感度-5;\nB为了报复A, 好感度+5(什么柜子play)\nA为BC做媒,成功B、C对A好感度+1反之-1\n做媒成功BC好感度+1" +
|
||||||
"\nTips: 群老婆列表过0点刷新",
|
"\nTips: 群老婆列表过0点刷新",
|
||||||
PrivateDataFolder: "qqwife",
|
PrivateDataFolder: "qqwife",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.NewGroupSingle("别着急,民政局门口排长队了!"))
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text("别着急,民政局门口排长队了!"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
民政局.db = sql.New(engine.DataFolder() + "结婚登记表.db")
|
民政局.db = sql.New(engine.DataFolder() + "结婚登记表.db")
|
||||||
err := 民政局.db.Open(time.Hour)
|
err := 民政局.db.Open(time.Hour)
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import (
|
|||||||
sql "github.com/FloatTech/sqlite"
|
sql "github.com/FloatTech/sqlite"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
|
||||||
|
|
||||||
"github.com/FloatTech/AnimeAPI/wallet"
|
"github.com/FloatTech/AnimeAPI/wallet"
|
||||||
"github.com/FloatTech/floatbox/math"
|
"github.com/FloatTech/floatbox/math"
|
||||||
@ -45,16 +44,7 @@ func init() {
|
|||||||
"7. 每日可打劫或被打劫一次\n" +
|
"7. 每日可打劫或被打劫一次\n" +
|
||||||
"8. 打劫失败不计入次数\n",
|
"8. 打劫失败不计入次数\n",
|
||||||
PrivateDataFolder: "robbery",
|
PrivateDataFolder: "robbery",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.NewGroupSingle("别着急,警察局门口排长队了!"))
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text("别着急,警察局门口排长队了!"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
police.db = sql.New(engine.DataFolder() + "robbery.db")
|
police.db = sql.New(engine.DataFolder() + "robbery.db")
|
||||||
err := police.db.Open(time.Hour)
|
err := police.db.Open(time.Hour)
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
// 数据库
|
// 数据库
|
||||||
@ -83,17 +82,7 @@ func init() { // 插件主体
|
|||||||
"指令示例:\n" +
|
"指令示例:\n" +
|
||||||
name + "帮我画几张金凤凰,背景绚烂,高饱和,古风,仙境,高清,4K,古风的油画方图",
|
name + "帮我画几张金凤凰,背景绚烂,高饱和,古风,仙境,高清,4K,古风的油画方图",
|
||||||
PrivateDataFolder: "wenxinAI",
|
PrivateDataFolder: "wenxinAI",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.NewGroupSingle("正在给别人画图,请不要打扰哦"))
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Break()
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text(zero.BotConfig.NickName[0], "正在给别人画图,请不要打扰哦"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
vilginfo.db = sql.New(engine.DataFolder() + "ernieVilg.db")
|
vilginfo.db = sql.New(engine.DataFolder() + "ernieVilg.db")
|
||||||
err := vilginfo.db.Open(time.Hour)
|
err := vilginfo.db.Open(time.Hour)
|
||||||
@ -285,17 +274,7 @@ func init() { // 插件主体
|
|||||||
"文心自定义 请写出下面这道题的解题过程。\\n题目:养殖场养鸭376只,养鸡的只数比鸭多258只,这个养殖场一共养鸭和鸡多少只?\\n解:\n\n" +
|
"文心自定义 请写出下面这道题的解题过程。\\n题目:养殖场养鸭376只,养鸡的只数比鸭多258只,这个养殖场一共养鸭和鸡多少只?\\n解:\n\n" +
|
||||||
"文心自定义 1+1=?\n" +
|
"文心自定义 1+1=?\n" +
|
||||||
"文心自定义 歌曲名:大风车转啊转\\n歌词:",
|
"文心自定义 歌曲名:大风车转啊转\\n歌词:",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.NewGroupSingle("正在给别人编辑,请不要打扰哦"))
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Break()
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text(zero.BotConfig.NickName[0], "正在给别人编辑,请不要打扰哦"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
getmodeldb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getmodeldb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
modelinfo.db = sql.New(engine.DataFolder() + "ernieModel.db")
|
modelinfo.db = sql.New(engine.DataFolder() + "ernieModel.db")
|
||||||
err := modelinfo.db.Open(time.Hour)
|
err := modelinfo.db.Open(time.Hour)
|
||||||
|
|||||||
@ -3,8 +3,9 @@ package wife
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"regexp"
|
||||||
|
|
||||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
@ -15,15 +16,27 @@ import (
|
|||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
var (
|
||||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
cards = []string{}
|
||||||
|
re = regexp.MustCompile(`^\[(.*?)\](.*)\..*$`)
|
||||||
|
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
DisableOnDefault: false,
|
DisableOnDefault: false,
|
||||||
Help: "- 抽老婆",
|
Help: "- 抽老婆",
|
||||||
Brief: "从老婆库抽每日老婆",
|
Brief: "从老婆库抽每日老婆",
|
||||||
PublicDataFolder: "Wife",
|
PublicDataFolder: "Wife",
|
||||||
}).ApplySingle(ctxext.DefaultSingle)
|
}).ApplySingle(ctxext.DefaultSingle)
|
||||||
|
)
|
||||||
|
|
||||||
|
func card2name(card string) (string, string) {
|
||||||
|
match := re.FindStringSubmatch(card)
|
||||||
|
if len(match) >= 3 {
|
||||||
|
return match[1], match[2]
|
||||||
|
}
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
_ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
|
_ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
|
||||||
cards := []string{}
|
|
||||||
engine.OnFullMatch("抽老婆", fcext.DoOnceOnSuccess(
|
engine.OnFullMatch("抽老婆", fcext.DoOnceOnSuccess(
|
||||||
func(ctx *zero.Ctx) bool {
|
func(ctx *zero.Ctx) bool {
|
||||||
data, err := engine.GetLazyData("wife.json", true)
|
data, err := engine.GetLazyData("wife.json", true)
|
||||||
@ -43,22 +56,28 @@ func init() {
|
|||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
card := cards[fcext.RandSenderPerDayN(ctx.Event.UserID, len(cards))]
|
card := cards[fcext.RandSenderPerDayN(ctx.Event.UserID, len(cards))]
|
||||||
data, err := engine.GetLazyData("wives/"+card, true)
|
data, err := engine.GetLazyData("wives/"+card, true)
|
||||||
card, _, _ = strings.Cut(card, ".")
|
var msgText string
|
||||||
|
work, name := card2name(card)
|
||||||
|
if work != "" && name != "" {
|
||||||
|
msgText = fmt.Sprintf("今天的二次元老婆是~来自【%s】的【%s】哒", work, name)
|
||||||
|
} else {
|
||||||
|
msgText = fmt.Sprintf("今天的二次元老婆是~【%s】哒", card)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(
|
ctx.SendChain(
|
||||||
message.At(ctx.Event.UserID),
|
message.At(ctx.Event.UserID),
|
||||||
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片下载失败: ", err, "】"),
|
message.Text(msgText, "\n【图片下载失败: ", err, "】"),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if id := ctx.SendChain(
|
if id := ctx.SendChain(
|
||||||
message.At(ctx.Event.UserID),
|
message.At(ctx.Event.UserID),
|
||||||
message.Text("今天的二次元老婆是~【", card, "】哒"),
|
message.Text(msgText),
|
||||||
message.ImageBytes(data),
|
message.ImageBytes(data),
|
||||||
); id.ID() == 0 {
|
); id.ID() == 0 {
|
||||||
ctx.SendChain(
|
ctx.SendChain(
|
||||||
message.At(ctx.Event.UserID),
|
message.At(ctx.Event.UserID),
|
||||||
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片发送失败, 请联系维护者】"),
|
message.Text(msgText, "\n【图片发送失败, 多半是被夹了,请联系维护者】"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
198
plugin/wife/wifegame.go
Normal file
198
plugin/wife/wifegame.go
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
// Package wife 抽老婆
|
||||||
|
package wife
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"image/color"
|
||||||
|
"io/fs"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/FloatTech/floatbox/file"
|
||||||
|
"github.com/FloatTech/gg"
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
|
zbmath "github.com/FloatTech/floatbox/math"
|
||||||
|
"github.com/FloatTech/imgfactory"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
sizeList = []int{0, 3, 5, 8}
|
||||||
|
enguess = control.Register("wifegame", &ctrl.Options[*zero.Ctx]{
|
||||||
|
DisableOnDefault: false,
|
||||||
|
Help: "- 猜老婆",
|
||||||
|
Brief: "从老婆库猜老婆",
|
||||||
|
}).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// _ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
|
||||||
|
enguess.OnFullMatch("猜老婆").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||||
|
var err error
|
||||||
|
class := 3
|
||||||
|
|
||||||
|
fileName, err := lottery()
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
work, name := card2name(fileName)
|
||||||
|
picFile := file.BOTPATH + "/" + engine.DataFolder() + "wives/" + fileName
|
||||||
|
pic, err := os.ReadFile(picFile)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
img, err := gg.LoadImage(picFile)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst := imgfactory.Size(img, img.Bounds().Dx(), img.Bounds().Dy())
|
||||||
|
q, err := mosaic(dst, class)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(
|
||||||
|
message.Reply(ctx.Event.MessageID),
|
||||||
|
message.Text("[猜老婆]图片生成失败:\n", err),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if id := ctx.SendChain(
|
||||||
|
message.ImageBytes(q),
|
||||||
|
); id.ID() != 0 {
|
||||||
|
ctx.SendChain(message.Text("请回答该二次元角色名字\n以“xxx酱”格式回答"))
|
||||||
|
}
|
||||||
|
var next *zero.FutureEvent
|
||||||
|
if ctx.Event.GroupID == 0 {
|
||||||
|
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`(·)?.+酱$`), ctx.CheckSession())
|
||||||
|
} else {
|
||||||
|
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`(·)?.+酱$`), zero.CheckGroup(ctx.Event.GroupID))
|
||||||
|
}
|
||||||
|
recv, cancel := next.Repeat()
|
||||||
|
defer cancel()
|
||||||
|
tick := time.NewTimer(105 * time.Second)
|
||||||
|
after := time.NewTimer(120 * time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-tick.C:
|
||||||
|
ctx.SendChain(message.Text("[猜老婆]你还有15s作答时间"))
|
||||||
|
case <-after.C:
|
||||||
|
ctx.Send(
|
||||||
|
message.ReplyWithMessage(ctx.Event.MessageID,
|
||||||
|
message.ImageBytes(pic),
|
||||||
|
message.Text("[猜老婆]倒计时结束,游戏结束...\n角色是:\n", name, "\n出自《", work, "》\n"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
case c := <-recv:
|
||||||
|
tick.Reset(105 * time.Second)
|
||||||
|
after.Reset(120 * time.Second)
|
||||||
|
msg := c.Event.Message.String()
|
||||||
|
msg, _, _ = strings.Cut(msg, "酱")
|
||||||
|
class--
|
||||||
|
if strings.Contains(name, msg) {
|
||||||
|
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
|
||||||
|
message.Text("太棒了,你猜对了!\n角色是:\n", name, "\n出自《", work, "》\n"),
|
||||||
|
message.ImageBytes(pic))); msgID.ID() == 0 {
|
||||||
|
ctx.SendChain(message.Text("太棒了,你猜对了!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if class < 1 {
|
||||||
|
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
|
||||||
|
message.Text("很遗憾,次数到了,游戏结束!\n角色是:\n", name, "\n出自《", work, "》\n"),
|
||||||
|
message.ImageBytes(pic))); msgID.ID() == 0 {
|
||||||
|
ctx.SendChain(message.Text("很遗憾,次数到了,游戏结束!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
q, err = mosaic(dst, class)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(
|
||||||
|
message.Text("回答错误,你还有", class, "次机会\n请继续作答\n(提示:", work, ")"),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ctx.SendChain(
|
||||||
|
message.Text("回答错误,你还有", class, "次机会\n请继续作答(难度降低)\n"),
|
||||||
|
message.ImageBytes(q),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从本地图库随机抽取,规避网络问题
|
||||||
|
func lottery() (fileName string, err error) {
|
||||||
|
path := engine.DataFolder() + "wives" + "/"
|
||||||
|
if file.IsNotExist(path) {
|
||||||
|
err = errors.New("图库文件夹不存在,请先发送“抽老婆”扩展图库")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
files, err := os.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 如果本地列表为空
|
||||||
|
if len(files) == 0 {
|
||||||
|
err = errors.New("本地数据为0,请先发送“抽老婆”扩展图库")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileName = randPicture(files, 10)
|
||||||
|
if fileName == "" {
|
||||||
|
err = errors.New("抽取图库轮空了,请重试")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func randPicture(files []fs.DirEntry, indexMax int) (fileName string) {
|
||||||
|
if len(files) > 1 {
|
||||||
|
picture := files[rand.Intn(len(files))]
|
||||||
|
// 如果是文件夹就递归
|
||||||
|
if picture.IsDir() {
|
||||||
|
indexMax--
|
||||||
|
if indexMax <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileName = randPicture(files, indexMax)
|
||||||
|
} else {
|
||||||
|
fileName = picture.Name()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
music := files[0]
|
||||||
|
if !music.IsDir() {
|
||||||
|
fileName = files[0].Name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 马赛克生成
|
||||||
|
func mosaic(dst *imgfactory.Factory, level int) ([]byte, error) {
|
||||||
|
b := dst.Image().Bounds()
|
||||||
|
p := imgfactory.NewFactoryBG(dst.W(), dst.H(), color.NRGBA{255, 255, 255, 255})
|
||||||
|
markSize := zbmath.Max(b.Max.X, b.Max.Y) * sizeList[level] / 200
|
||||||
|
|
||||||
|
for yOfMarknum := 0; yOfMarknum <= zbmath.Ceil(b.Max.Y, markSize); yOfMarknum++ {
|
||||||
|
for xOfMarknum := 0; xOfMarknum <= zbmath.Ceil(b.Max.X, markSize); xOfMarknum++ {
|
||||||
|
a := dst.Image().At(xOfMarknum*markSize+markSize/2, yOfMarknum*markSize+markSize/2)
|
||||||
|
cc := color.NRGBAModel.Convert(a).(color.NRGBA)
|
||||||
|
for y := 0; y < markSize; y++ {
|
||||||
|
for x := 0; x < markSize; x++ {
|
||||||
|
xOfPic := xOfMarknum*markSize + x
|
||||||
|
yOfPic := yOfMarknum*markSize + y
|
||||||
|
p.Image().Set(xOfPic, yOfPic, cc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imgfactory.ToBytes(p.Blur(3).Image())
|
||||||
|
}
|
||||||
@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -69,16 +68,7 @@ func init() {
|
|||||||
"- 团队六阶猜单词\n" +
|
"- 团队六阶猜单词\n" +
|
||||||
"- 团队七阶猜单词",
|
"- 团队七阶猜单词",
|
||||||
PublicDataFolder: "Wordle",
|
PublicDataFolder: "Wordle",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text("已经有正在进行的游戏..."),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
|
|
||||||
en.OnRegex(`^(个人|团队)(五阶|六阶|七阶)?猜单词$`, zero.OnlyGroup, fcext.DoOnceOnSuccess(
|
en.OnRegex(`^(个人|团队)(五阶|六阶|七阶)?猜单词$`, zero.OnlyGroup, fcext.DoOnceOnSuccess(
|
||||||
func(ctx *zero.Ctx) bool {
|
func(ctx *zero.Ctx) bool {
|
||||||
|
|||||||
@ -72,7 +72,7 @@ func init() {
|
|||||||
|
|
||||||
func sendYmgal(y ymgal, ctx *zero.Ctx) {
|
func sendYmgal(y ymgal, ctx *zero.Ctx) {
|
||||||
if y.PictureList == "" {
|
if y.PictureList == "" {
|
||||||
ctx.SendChain(message.Text(zero.BotConfig.NickName[0] + "暂时没有这样的图呢"))
|
ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "暂时没有这样的图呢"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text(y.Title))}
|
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text(y.Title))}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user