├── _conf_schema.json ├── metadata.yaml ├── README.md └── main.py /_conf_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "saucenao_api": { 3 | "description": "SauceNAO API Key", 4 | "type": "string", 5 | "hint": "sauceno搜图api,你可以从https://saucenao.com/user.php注册并获取", 6 | "obvious_hint": true 7 | } 8 | } -------------------------------------------------------------------------------- /metadata.yaml: -------------------------------------------------------------------------------- 1 | name: sauceno_search # 插件的唯一识别名 2 | desc: sauceno搜图 # 插件简短描述 3 | help: sauceno搜图,输入 /搜图 后发送你想要搜索的图片即可 # 插件的帮助信息 4 | version: v1.0.0 # 插件版本号。格式:v1.1.1 或者 v1.1 5 | author: Hazellol # 作者 6 | repo: https://github.com/Hazellol/astrbot_plugin_sauceno # 插件的仓库地址 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sauceno! 搜图插件 2 | 3 | 基于AstrBot 插件模板生产的搜图插件 4 | 5 | ## 指令 6 | 7 | - **/搜图**:发送之后在30s之内发送要搜索的图片 8 | 9 | ## 配置 10 | 11 | 需在面板配置sauceno—api,你可以从 https://saucenao.com/user.php 免费注册并获取 12 | 13 | ## 开发 14 | - 本人也是初次开发,有不足请包含! 15 | - 参考 [AstrBot 插件开发文档](https://astrbot.soulter.top/dev/plugin.html) 了解更多插件开发和打包上传的细节。 16 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from astrbot.api.all import * 2 | from astrbot.api.message_components import * 3 | import aiohttp 4 | import asyncio 5 | import time 6 | from typing import Dict, Optional 7 | 8 | # 用于跟踪每个用户的状态,防止超时或重复请求 9 | USER_STATES: Dict[str, Optional[float]] = {} 10 | 11 | # 注册插件命令,版本号等信息 12 | @register("sauceno_search", "Hazellol", "sauceno搜图", "1.0.0") 13 | class SauceNAOSearch(Star): 14 | 15 | # 初始化,获取配置文件中的 API Key 16 | def __init__(self, context: Context, config: dict): 17 | super().__init__(context) # 调用父类初始化 18 | self.config = config 19 | self.api_key = config.get("saucenao_api", "") # 获取配置中的API Key 20 | 21 | # 处理"搜图"命令 22 | @command("搜图") 23 | async def search_image(self, event: AstrMessageEvent): 24 | '''sauceno搜图''' 25 | user_id = event.get_sender_id() # 获取用户ID 26 | USER_STATES[user_id] = time.time() # 记录用户请求的时间 27 | yield event.plain_result("杂鱼~还得靠我呢!限你30秒内发送你要查找的图片yo~") # 提示用户发送图片 28 | await asyncio.sleep(30) # 等待30秒 29 | # 如果超时,删除用户状态并通知用户 30 | if user_id in USER_STATES: 31 | del USER_STATES[user_id] 32 | yield event.plain_result("搜索超时了哦,杂鱼~") 33 | 34 | # 处理所有消息类型的事件 35 | @event_message_type(EventMessageType.ALL) 36 | async def handle_image(self, event: AstrMessageEvent): 37 | user_id = event.get_sender_id() # 获取发送者的ID 38 | if user_id not in USER_STATES: # 如果用户没有发起请求,跳过 39 | return 40 | 41 | # 检查消息中是否包含图片 42 | images = [c for c in event.message_obj.message if isinstance(c, Image)] 43 | if not images: # 如果没有图片,跳过 44 | return 45 | 46 | # 删除用户状态,表示用户已提交图片 47 | del USER_STATES[user_id] 48 | 49 | # 如果未配置API Key,提醒用户 50 | if not self.api_key: 51 | yield event.plain_result("请先配置SauceNAO API Key") 52 | return 53 | 54 | # 使用第一张图片进行搜索 55 | image_url = images[0].url 56 | 57 | try: 58 | # 使用aiohttp进行异步请求 59 | async with aiohttp.ClientSession() as session: 60 | # 构造API请求的参数 61 | params = { 62 | "url": image_url, 63 | "output_type": 2, 64 | "api_key": self.api_key, 65 | "numres": 5 # 获取前5个结果 66 | } 67 | 68 | # 调用SauceNAO API进行图片搜索 69 | async with session.get("https://saucenao.com/search.php", params=params) as resp: 70 | data = await resp.json() # 解析返回的JSON数据 71 | 72 | results = data.get("results", []) # 获取搜索结果 73 | if not results: # 如果没有结果,返回提示 74 | yield event.plain_result("没有找到匹配的结果哦,杂鱼~") 75 | return 76 | 77 | # 根据相似度对结果进行排序,选择前5个最相似的结果 78 | sorted_results = sorted( 79 | results, 80 | key=lambda x: float(x["header"]["similarity"]), 81 | reverse=True 82 | )[:5] 83 | 84 | # 创建消息列表,用于存储搜索结果 85 | msg_list = [Plain("搜索结果(可能性从高到低):\n")] 86 | 87 | # 遍历前5个排序结果,构建显示信息 88 | for idx, result in enumerate(sorted_results, 1): 89 | header = result["header"] 90 | data = result["data"] 91 | 92 | similarity = header["similarity"] # 获取相似度 93 | thumbnail = header.get("thumbnail", "") # 获取缩略图URL 94 | author = data.get("member_name") or data.get("creator") or "未知作者" # 获取作者 95 | source = data.get("ext_urls", ["无原链接"])[0] if data.get("ext_urls") else "无原链接" # 获取原图链接 96 | 97 | # 添加结果到消息列表 98 | msg_list.append(Plain(f"\n#{idx} 可能性:{similarity}%\n")) 99 | msg_list.append(Plain(f"作者:{author}\n")) 100 | msg_list.append(Plain(f"原图:{source}\n")) 101 | 102 | if thumbnail: # 如果有缩略图,添加图片到消息列表 103 | msg_list.append(Image.fromURL(thumbnail)) # 从缩略图URL生成图片组件 104 | 105 | # 发送最终的结果,直接传递消息列表 106 | yield event.chain_result(msg_list) 107 | 108 | except Exception as e: # 捕获异常并返回错误信息 109 | print(f"SauceNAO搜索失败: {str(e)}") 110 | yield event.plain_result("搜索失败了哦,杂鱼程序员又写bug了!") 111 | --------------------------------------------------------------------------------