mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 05:30:07 +08:00
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
146 lines
4.6 KiB
Go
146 lines
4.6 KiB
Go
// Package animetrace AnimeTrace 动画/Galgame识别
|
|
package animetrace
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"image"
|
|
"image/jpeg"
|
|
"mime/multipart"
|
|
"strings"
|
|
|
|
"github.com/FloatTech/floatbox/web"
|
|
"github.com/FloatTech/imgfactory"
|
|
ctrl "github.com/FloatTech/zbpctrl"
|
|
"github.com/FloatTech/zbputils/control"
|
|
"github.com/FloatTech/zbputils/ctxext"
|
|
"github.com/disintegration/imaging"
|
|
"github.com/tidwall/gjson"
|
|
zero "github.com/wdvxdr1123/ZeroBot"
|
|
"github.com/wdvxdr1123/ZeroBot/message"
|
|
)
|
|
|
|
func init() {
|
|
engine := control.Register("animetrace", &ctrl.Options[*zero.Ctx]{
|
|
DisableOnDefault: false,
|
|
Brief: "AnimeTrace 动画/Galgame识别插件",
|
|
Help: "- Gal识图\n- 动漫识图\n- 动漫识图 2\n- 动漫识图 [模型名]\n- Gal识图 [模型名]",
|
|
})
|
|
|
|
engine.OnPrefix("gal识图", zero.OnlyGroup, zero.MustProvidePicture).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
args := ctx.State["args"].(string)
|
|
var model string
|
|
switch strings.TrimSpace(args) {
|
|
case "":
|
|
model = "full_game_model_kira" // 默认使用的模型
|
|
default:
|
|
model = args // 自定义设置模型
|
|
}
|
|
processImageRecognition(ctx, model)
|
|
})
|
|
|
|
engine.OnPrefix("动漫识图", zero.OnlyGroup, zero.MustProvidePicture).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
args := ctx.State["args"].(string)
|
|
var model string
|
|
switch strings.TrimSpace(args) {
|
|
case "":
|
|
model = "anime_model_lovelive"
|
|
case "2":
|
|
model = "pre_stable"
|
|
default:
|
|
model = args
|
|
}
|
|
processImageRecognition(ctx, model)
|
|
})
|
|
}
|
|
|
|
// 处理图片识别
|
|
func processImageRecognition(ctx *zero.Ctx, model string) {
|
|
urls := ctx.State["image_url"].([]string)
|
|
if len(urls) == 0 {
|
|
return
|
|
}
|
|
imageData, err := imgfactory.Load(urls[0])
|
|
if err != nil {
|
|
ctx.Send(message.Text("下载图片失败: ", err))
|
|
return
|
|
}
|
|
// ctx.Send(message.Text(model))
|
|
respBody, err := createAndSendMultipartRequest("https://api.animetrace.com/v1/search", imageData, map[string]string{
|
|
"is_multi": "0",
|
|
"model": model,
|
|
"ai_detect": "0",
|
|
})
|
|
if err != nil {
|
|
ctx.Send(message.Text("识别请求失败: ", err))
|
|
return
|
|
}
|
|
code := gjson.Get(string(respBody), "code").Int()
|
|
if code != 0 {
|
|
ctx.Send(message.Text("错误: ", gjson.Get(string(respBody), "zh_message").String()))
|
|
return
|
|
}
|
|
dataArray := gjson.Get(string(respBody), "data").Array()
|
|
if len(dataArray) == 0 {
|
|
ctx.Send(message.Text("未识别到任何角色"))
|
|
return
|
|
}
|
|
var sk message.Message
|
|
sk = append(sk, ctxext.FakeSenderForwardNode(ctx, message.Text("共识别到 ", len(dataArray), " 个角色,可能是以下来源")))
|
|
for _, value := range dataArray {
|
|
boxArray := value.Get("box").Array()
|
|
imgWidth, imgHeight := imageData.Bounds().Dx(), imageData.Bounds().Dy() // 你可以从 `imageData.Bounds()` 获取
|
|
box := []int{
|
|
int(boxArray[0].Float() * float64(imgWidth)),
|
|
int(boxArray[1].Float() * float64(imgHeight)),
|
|
int(boxArray[2].Float() * float64(imgWidth)),
|
|
int(boxArray[3].Float() * float64(imgHeight)),
|
|
}
|
|
croppedImg := imaging.Crop(imageData, image.Rect(box[0], box[1], box[2], box[3]))
|
|
var buf bytes.Buffer
|
|
if err := imaging.Encode(&buf, croppedImg, imaging.JPEG, imaging.JPEGQuality(80)); err != nil {
|
|
ctx.Send(message.Text("图片编码失败: ", err))
|
|
continue
|
|
}
|
|
|
|
base64Str := base64.StdEncoding.EncodeToString(buf.Bytes())
|
|
var sb strings.Builder
|
|
value.Get("character").ForEach(func(_, character gjson.Result) bool {
|
|
sb.WriteString(fmt.Sprintf("《%s》的角色 %s\n", character.Get("work").String(), character.Get("character").String()))
|
|
return true
|
|
})
|
|
sk = append(sk, ctxext.FakeSenderForwardNode(ctx, message.Image("base64://"+base64Str), message.Text(sb.String())))
|
|
}
|
|
ctx.SendGroupForwardMessage(ctx.Event.GroupID, sk)
|
|
}
|
|
|
|
// 发送图片识别请求
|
|
func createAndSendMultipartRequest(url string, img image.Image, formFields map[string]string) ([]byte, error) {
|
|
body := &bytes.Buffer{}
|
|
writer := multipart.NewWriter(body)
|
|
|
|
// 直接编码图片
|
|
part, err := writer.CreateFormFile("file", "image.jpg")
|
|
if err != nil {
|
|
return nil, errors.New("创建文件字段失败: " + err.Error())
|
|
}
|
|
if err := jpeg.Encode(part, img, &jpeg.Options{Quality: 80}); err != nil {
|
|
return nil, errors.New("图片编码失败: " + err.Error())
|
|
}
|
|
|
|
// 写入其他字段
|
|
for key, value := range formFields {
|
|
if err := writer.WriteField(key, value); err != nil {
|
|
return nil, errors.New("写入表单字段失败 (" + key + "): " + err.Error())
|
|
}
|
|
}
|
|
|
|
if err := writer.Close(); err != nil {
|
|
return nil, errors.New("关闭 multipart writer 失败: " + err.Error())
|
|
}
|
|
|
|
return web.PostData(url, writer.FormDataContentType(), body)
|
|
}
|