mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 13:59:39 +08:00
⚡️ 更好的识图触发模式
This commit is contained in:
parent
67622a7668
commit
66ff92e064
@ -2,9 +2,13 @@ package setutime
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
utils "github.com/Yiwen-Chan/ZeroBot-Plugin/setutime/utils"
|
utils "github.com/Yiwen-Chan/ZeroBot-Plugin/setutime/utils"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() { // 插件主体
|
func init() { // 插件主体
|
||||||
@ -28,111 +32,97 @@ func init() { // 插件主体
|
|||||||
ctx.Send(illust.DetailPic)
|
ctx.Send(illust.DetailPic)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
// 通过回复以图搜图
|
// 以图搜图
|
||||||
zero.OnRegex(`\[CQ:reply,id=(.*?)\](.*)搜索图片`).SetBlock(true).SetPriority(32).
|
zero.OnMessage(FullMatchText("以图搜图", "搜索图片", "以图识图"), MustHasPicture()).SetBlock(true).SetPriority(999).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
var pics []string // 图片搜索池子
|
|
||||||
// 获取回复的上文图片链接
|
|
||||||
id := utils.Str2Int(ctx.State["regex_matched"].([]string)[1])
|
|
||||||
for _, elem := range ctx.GetMessage(id).Elements {
|
|
||||||
if elem.Type == "image" {
|
|
||||||
pics = append(pics, elem.Data["url"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 没有收到图片则向用户索取
|
|
||||||
if len(pics) == 0 {
|
|
||||||
ctx.Send("请发送多张图片!")
|
|
||||||
next := ctx.FutureEvent("message", ctx.CheckSession())
|
|
||||||
recv, cancel := next.Repeat()
|
|
||||||
for e := range recv { // 循环获取channel发来的信息
|
|
||||||
if len(e.Message) == 1 && e.Message[0].Type == "text" {
|
|
||||||
cancel() // 如果是纯文本则退出索取
|
|
||||||
break
|
|
||||||
}
|
|
||||||
for _, elem := range e.Message {
|
|
||||||
if elem.Type == "image" { // 将信息中的图片添加到搜索池子
|
|
||||||
pics = append(pics, elem.Data["url"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(pics) >= 5 {
|
|
||||||
cancel() // 如果是图片数量大于等于5则退出索取
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(pics) == 0 {
|
|
||||||
ctx.Send("没有收到图片,搜图结束......")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 开始搜索图片
|
// 开始搜索图片
|
||||||
ctx.Send("少女祈祷中......")
|
ctx.Send("少女祈祷中......")
|
||||||
for _, pic := range pics {
|
for _, pic := range ctx.State["image_url"].([]string) {
|
||||||
if text, err := utils.SauceNaoSearch(pic); err == nil {
|
fmt.Println(pic)
|
||||||
ctx.Send(text) // 返回SauceNAO的结果
|
if m, err := utils.SauceNaoSearch(pic); err == nil {
|
||||||
|
ctx.SendChain(m...) // 返回SauceNAO的结果
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
ctx.Send(fmt.Sprintf("ERROR: %v", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
}
|
}
|
||||||
if text, err := utils.Ascii2dSearch(pic); err == nil {
|
if m, err := utils.Ascii2dSearch(pic); err == nil {
|
||||||
ctx.Send(text) // 返回Ascii2d的结果
|
ctx.SendChain(m...) // 返回Ascii2d的结果
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
ctx.Send(fmt.Sprintf("ERROR: %v", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
})
|
|
||||||
// 通过命令以图搜图
|
|
||||||
zero.OnKeywordGroup([]string{"以图识图", "以图搜图", "搜索图片"}).SetBlock(true).SetPriority(33).
|
|
||||||
Handle(func(ctx *zero.Ctx) {
|
|
||||||
var pics []string // 图片搜索池子
|
|
||||||
// 获取信息中图片链接
|
|
||||||
for _, elem := range ctx.Event.Message {
|
|
||||||
if elem.Type == "image" {
|
|
||||||
pics = append(pics, elem.Data["url"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 没有收到图片则向用户索取
|
|
||||||
if len(pics) == 0 {
|
|
||||||
ctx.Send("请发送多张图片!")
|
|
||||||
next := ctx.FutureEvent("message", zero.CheckUser(ctx.Event.UserID))
|
|
||||||
recv, cancel := next.Repeat()
|
|
||||||
for e := range recv { // 循环获取channel发来的信息
|
|
||||||
if len(e.Message) == 1 && e.Message[0].Type == "text" {
|
|
||||||
cancel() // 如果是纯文本则退出索取
|
|
||||||
break
|
|
||||||
}
|
|
||||||
for _, elem := range e.Message {
|
|
||||||
if elem.Type == "image" { // 将信息中的图片添加到搜索池子
|
|
||||||
pics = append(pics, elem.Data["url"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(pics) >= 5 {
|
|
||||||
cancel() // 如果是图片数量大于等于5则退出索取
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(pics) == 0 {
|
|
||||||
ctx.Send("没有收到图片,搜图结束......")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 开始搜索图片
|
|
||||||
ctx.Send("少女祈祷中......")
|
|
||||||
for _, pic := range pics {
|
|
||||||
if text, err := utils.SauceNaoSearch(pic); err == nil {
|
|
||||||
ctx.Send(text) // 返回SauceNAO的结果
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
ctx.Send(fmt.Sprintf("ERROR: %v", err))
|
|
||||||
}
|
|
||||||
if text, err := utils.Ascii2dSearch(pic); err == nil {
|
|
||||||
ctx.Send(text) // 返回Ascii2d的结果
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
ctx.Send(fmt.Sprintf("ERROR: %v", err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FullMatchText 如果信息中文本完全匹配则返回 true
|
||||||
|
func FullMatchText(src ...string) zero.Rule {
|
||||||
|
return func(ctx *zero.Ctx) bool {
|
||||||
|
msg := ctx.Event.Message
|
||||||
|
for _, elem := range msg {
|
||||||
|
if elem.Type == "text" {
|
||||||
|
text := elem.Data["text"]
|
||||||
|
text = strings.ReplaceAll(text, " ", "")
|
||||||
|
text = strings.ReplaceAll(text, "\r", "")
|
||||||
|
text = strings.ReplaceAll(text, "\n", "")
|
||||||
|
for _, s := range src {
|
||||||
|
if text == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPicture 消息含有图片返回 true
|
||||||
|
func HasPicture() zero.Rule {
|
||||||
|
return func(ctx *zero.Ctx) bool {
|
||||||
|
msg := ctx.Event.Message
|
||||||
|
url := []string{}
|
||||||
|
// 如果是回复信息则将信息替换成被回复的那条
|
||||||
|
if msg[0].Type == "reply" {
|
||||||
|
id, _ := strconv.Atoi(msg[0].Data["id"])
|
||||||
|
msg = ctx.GetMessage(int64(id)).Elements
|
||||||
|
}
|
||||||
|
// 遍历信息中所有图片
|
||||||
|
for _, elem := range msg {
|
||||||
|
if elem.Type == "image" {
|
||||||
|
url = append(url, elem.Data["url"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果有图片就返回true
|
||||||
|
if len(url) > 0 {
|
||||||
|
ctx.State["image_url"] = url
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustHasPicture 消息不存在图片阻塞60秒至有图片,超时返回 false
|
||||||
|
func MustHasPicture() zero.Rule {
|
||||||
|
return func(ctx *zero.Ctx) bool {
|
||||||
|
if HasPicture()(ctx) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 没有图片就索取
|
||||||
|
ctx.Send("请发送一张图片")
|
||||||
|
next := zero.NewFutureEvent("message", 999, false, zero.CheckUser(ctx.Event.UserID), HasPicture())
|
||||||
|
recv, cancel := next.Repeat()
|
||||||
|
select {
|
||||||
|
case e := <-recv:
|
||||||
|
cancel()
|
||||||
|
newCtx := &zero.Ctx{Event: e, State: zero.State{}}
|
||||||
|
if HasPicture()(newCtx) {
|
||||||
|
ctx.State["image_url"] = newCtx.State["image_url"]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case <-time.After(time.Second * 60):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,18 +1,17 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SauceNaoSearch SauceNao 以图搜图 需要链接 返回错误和信息
|
// SauceNaoSearch SauceNao 以图搜图 需要链接 返回错误和信息
|
||||||
func SauceNaoSearch(pic string) (text string, err error) {
|
func SauceNaoSearch(pic string) (message.Message, error) {
|
||||||
var (
|
var (
|
||||||
api = "https://saucenao.com/search.php"
|
api = "https://saucenao.com/search.php"
|
||||||
apiKey = "2cc2772ca550dbacb4c35731a79d341d1a143cb5"
|
apiKey = "2cc2772ca550dbacb4c35731a79d341d1a143cb5"
|
||||||
@ -20,65 +19,59 @@ func SauceNaoSearch(pic string) (text string, err error) {
|
|||||||
minSimilarity = 70.0 // 返回图片结果的最小相似度
|
minSimilarity = 70.0 // 返回图片结果的最小相似度
|
||||||
)
|
)
|
||||||
|
|
||||||
transport := http.Transport{
|
|
||||||
DisableKeepAlives: true,
|
|
||||||
}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: &transport,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 包装请求参数
|
// 包装请求参数
|
||||||
data := url.Values{}
|
link, _ := url.Parse(api)
|
||||||
data.Set("url", pic) // 图片链接
|
link.RawQuery = url.Values{
|
||||||
data.Set("api_key", apiKey) // api_key
|
"url": []string{pic},
|
||||||
data.Set("db", "5") // 只搜索Pixiv
|
"api_key": []string{apiKey},
|
||||||
data.Set("numres", "1") // 返回一个结果
|
"db": []string{"5"},
|
||||||
data.Set("output_type", "2") // 返回JSON格式数据
|
"numres": []string{"1"},
|
||||||
fromData := strings.NewReader(data.Encode())
|
"output_type": []string{"2"},
|
||||||
|
}.Encode()
|
||||||
|
|
||||||
// 网络请求
|
// 网络请求
|
||||||
req, err := http.NewRequest("POST", api, fromData)
|
client := &http.Client{}
|
||||||
|
req, err := http.NewRequest("GET", link.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
req.Header.Set("Accept", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0")
|
req.Header.Set("Accept", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0")
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if code := resp.StatusCode; code != 200 {
|
if resp.StatusCode != http.StatusOK {
|
||||||
// 如果返回不是200则立刻抛出错误
|
// 如果返回不是200则立刻抛出错误
|
||||||
return "", errors.New(fmt.Sprintf("SauceNAO not found, code %d", code))
|
return nil, fmt.Errorf("SauceNAO not found, code %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
content := gjson.ParseBytes(body)
|
content := gjson.ParseBytes(body)
|
||||||
if status := content.Get("header.status").Int(); status != 0 {
|
if status := content.Get("header.status").Int(); status != 0 {
|
||||||
// 如果json信息返回status不为0则立刻抛出错误
|
// 如果json信息返回status不为0则立刻抛出错误
|
||||||
return "", errors.New(fmt.Sprintf("SauceNAO not found, status %d", status))
|
return nil, fmt.Errorf("SauceNAO not found, status %d", status)
|
||||||
}
|
}
|
||||||
if content.Get("results.0.header.similarity").Float() < minSimilarity {
|
if content.Get("results.0.header.similarity").Float() < minSimilarity {
|
||||||
return "", errors.New("SauceNAO not found")
|
return nil, fmt.Errorf("SauceNAO not found")
|
||||||
}
|
}
|
||||||
|
result := content.Get("results.0")
|
||||||
// 正常发送
|
// 正常发送
|
||||||
return fmt.Sprintf(
|
return message.Message{
|
||||||
`[SetuTime] 我有把握是这个![CQ:image,file=%s]相似度:%s%%
|
message.Text("[SetuTime] 我有把握是这个!"),
|
||||||
标题:%s
|
message.Image(result.Get("header.thumbnail").Str),
|
||||||
插画ID:%d
|
message.Text(
|
||||||
画师:%s
|
"\n",
|
||||||
画师ID:%d
|
"相似度:", result.Get("header.similarity").Str, "\n",
|
||||||
直链:https://pixivel.moe/detail?id=%d`,
|
"标题:", result.Get("data.title").Str, "\n",
|
||||||
content.Get("results.0.header.thumbnail").Str,
|
"插画ID:", result.Get("data.pixiv_id").Int(), "\n",
|
||||||
content.Get("results.0.header.similarity").Str,
|
"画师:", result.Get("data.member_name").Str, "\n",
|
||||||
content.Get("results.0.data.title").Str,
|
"画师ID:", result.Get("data.member_id").Int(), "\n",
|
||||||
content.Get("results.0.data.pixiv_id").Int(),
|
"直链:", "https://pixivel.moe/detail?id=", result.Get("data.pixiv_id").Int(),
|
||||||
content.Get("results.0.data.member_name").Str,
|
),
|
||||||
content.Get("results.0.data.member_id").Int(),
|
}, nil
|
||||||
content.Get("results.0.data.pixiv_id").Int(),
|
|
||||||
), nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user