感谢AstrBot和napcat
添加了几个插件,挨个折腾,记录一些遇到的困难,看看人工队和ai队谁的方案能解决问题hhh
先记录一下,ws链接的时候,natcap设置ws://192.168.0.101:6199/ws;Astrbot设置0.0.0.0
一、Pixiv 图片搜索——Refresh Token获取
感谢B站 up Yzenakiki 的教程
Android 端可以使用 Edge/Firefox 浏览器进行操作
- 首先安装 URLRedirector 浏览器插件,下载地址:https://github.com/fengyc/URLRedirector
- 导入 URLRedirector 在线规则配置,规则地址:https://pixiv.pictures/helper/redirect.json
- 安装 Tampermonkey 浏览器插件,下载地址:https://www.tampermonkey.net/index.php
- 安装登录工具用户脚本,脚本地址:https://fastly.jsdelivr.net/gh/asadahimeka/pixiv-viewer@master/public/helper/helper.user.js
- 在此页面选择 App API (OAuth) 进行登录:https://pixiv.pictures/account/login,会打开 Pixiv 官方登录页面
- 登录成功后可在设置(https://pixiv.pictures/setting/others)页面导出 RefreshToken 以供其他软件使用
二、sauceno搜图
sauceno网站登录以后设置api即可 https://saucenao.com/user.php
三、明日方舟抽卡查询
很莫名其妙,装了以后绑定token报错,尝试修改源代码无果,重装了一遍好了hhh
四、赛博试管插件
作者引用了meme_generator的模板,但是名字貌似有更新,从my_friend变成了my_friend_say
所以写了个判断,这两个都检测一下,没有my_friend就用my_friend_say
meme = next((m for m in get_memes() if m.key in [“my_friend”, “my_friend_say”]), None)
随后出现了无法获取meme版本的错误,经过ai分析meme_generator源码后,思路如下:
meme_generator没有from_pil、open、core、utils.load_image这些接口。它唯一接受的images元素是MemeImage(name: str, data: bytes)—— 必须是裸 bytes + 名字。把头像 bytes 直接包成MemeImage,不要任何 PIL 转换。
决定直接固定meme的版本,最终智能队获胜(恭喜kimi打败了ds和gpt)
import asyncio
from astrbot import logger
from astrbot.core.platform.sources.aiocqhttp.aiocqhttp_message_event import (
AiocqhttpMessageEvent,
)
from .utils import (
get_avatar,
get_reply_text,
get_replyer_id,
get_user_name,
)
async def generate_meme(event: AiocqhttpMessageEvent) -> bytes | None:
"""聊天记录转表情包(my_friend 模板)"""
# 1. 收集素材,任何一步失败直接返回 None
reply_text = get_reply_text(event)
if not reply_text:
return None
replyer_id = get_replyer_id(event)
if not replyer_id:
return None
avatar = await get_avatar(replyer_id)
if not avatar:
return None
name = await get_user_name(
client=event.bot,
group_id=int(event.get_group_id()),
user_id=int(replyer_id),
)
# 2. 动态导入 meme_generator,失败直接返回
try:
from meme_generator import get_memes
except ImportError:
logger.error("未安装 meme_generator")
return None
meme = next((m for m in get_memes() if m.key == "my_friend_say"), None)
if not meme:
logger.error("未找到 my_friend 模板")
return None
# 3. 根据版本号决定调用方式
# 3. 不再尝试读版本,默认使用新版 API
__version__ = "0.3.0" # 手动指定
if tuple(map(int, __version__.split("."))) <= (0, 2, 0):
try:
from meme_generator.utils import run_sync
image_io = await run_sync(meme)(
images=[avatar],
texts=[reply_text],
args={"name": name},
)
return image_io.getvalue()
except Exception as e:
logger.exception(f"meme 生成失败: {e}")
return None
else: # 统一走新版入口
try:
from meme_generator import Image as MemeImage
# 直接包成 MemeImage
meme_images = [MemeImage(name, avatar)]
image = await asyncio.to_thread(
meme.generate,
images=meme_images,
texts=[reply_text],
options={},
)
return image if isinstance(image, bytes) else image.getvalue()
except Exception as e:
logger.exception(f"meme 生成失败: {e}")
return None
五、doro表情包插件
需要延长一下获取时间,不然就算是三次申请api的机会可能都获取不到
from httpx import Timeout
timeout = Timeout(10.0, connect=15.0) # 连接超时 15 s,读/写超时 10 s
async with httpx.AsyncClient(timeout=timeout) as client:
response = await client.get(api_url)
六、防撤回插件
气得要死,可能是我太笨,不知道为啥作者只告诉了群组的三段式type,私人聊天的没告诉,一顿乱查,好歹是找到了。以及记得如果napcat和astrbot是部署了两个docker,设置一个共享文件夹连通两个docker的访问文件。
root@astrbot:/AstrBot# cat /AstrBot/astrbot/core/platform/message_type.py
from enum import Enum
class MessageType(Enum):
GROUP_MESSAGE = "GroupMessage" # 群组形式的消息,也可以用官方的group
FRIEND_MESSAGE = "FriendMessage" # 私聊、好友等单聊消息
OTHER_MESSAGE = "OtherMessage" # 其他类型的消息,如系统消息等
root@astrbot:/AstrBot#
### 最终要设置为 aiocqhttp:FriendMessage:qq_id 这种格式才可以
七、JM下载插件
头一次走端口代理,才知道端口是20171,我是个傻berber,v2raya竟然还有个端口分享的按钮,点了这个才能通过特定的端口转发,服了… …
后续又出现了一个问题,jm一些资源需要登录才能看得到(github上也有不少人遇到了这个问题),根据作者的说法传入avs_cookie就可以模拟登陆,尝试后失败,遂决定修改一点代码传入整个cookie,最后还真搞成功了,人工队win了一局。
class JMClientFactory:
"""JM客户端工厂,负责创建和管理JM客户端实例"""
def __init__(self, config: CosmosConfig, resource_manager: ResourceManager):
self.config = config
self.resource_manager = resource_manager
self.option = self._create_option()
def _create_option(self):
"""创建JM客户端选项"""
cookies = {
c.split("=")[0].strip(): c.split("=", 1)[1].strip()
for c in self.config.avs_cookie.split(";")
if "=" in c
}
logger.info(f"[DEBUG] 使用的Cookies: {cookies}")
option_dict = {
"client": {
"impl": "html",
"domain": self.config.domain_list,
"retry_times": 5,
"postman": {
"meta_data": {
"proxies": {"https": self.config.proxy} if self.config.proxy else None,
"cookies": cookies,
# 添加浏览器模拟的请求头
"headers": {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Referer": f"https://{self.config.domain_list[0]}/",
"Connection": "keep-alive",
"Cache-Control": "max-age=0"
}
}
}
},
"download": {
"cache": True,
"image": {
"decode": True,
"suffix": ".jpg"
},
"threading": {
"image": self.config.max_threads,
"photo": self.config.max_threads
}
},
"dir_rule": {
"base_dir": self.resource_manager.downloads_dir
},
"plugins": {
"after_album": [
{
"plugin": "img2pdf",
"kwargs": {
"pdf_dir": self.resource_manager.pdfs_dir,
"filename_rule": "Aid"
}
}
]
}
}
yaml_str = yaml.safe_dump(option_dict, allow_unicode=True)
return jmcomic.create_option_by_str(yaml_str)
八、lolicon插件
源码运行报错
[19:41:23] [Core] [INFO] [core.event_bus:50]: [aiocqhttp] Plumephoenix♥/1106674601: /我要涩涩
Unexpected error saving 69187235_p0.png:
[19:41:43] [Core] [INFO] [respond.stage:212]: AstrBot -> Plumephoenix♥/1106674601: 你怎么这么自私
首先改一下代码输出更多的traceback
import traceback
async def generate_and_save_image(self, url, filename):
async with file_lock:
try:
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=15)) as session:
async with session.get(url) as response:
content = await response.read() # 异步读取响应内容
file_path = os.path.join(self.imgs_folder, filename)
async with aiofiles.open(file_path, 'wb') as f:
await f.write(content) # 异步写入文件
logger.info(f"Successfully saved image: {filename}")
return True
except aiohttp.ClientError as e:
logger.error(f"HTTP Error saving {filename}: {str(e)}")
return False
except Exception as e:
logger.error(f"Unexpected error saving {filename}: {repr(e)}\n{traceback.format_exc()}")
return False
超大工程,根据自己的想法逐步改下,记录一下遇到的问题
- 下载超时,经常性的反复下载超时:原因是默认下载original质量的图片,很多图片都太大了(尤其是.png),lolicon仓库有提供更小质量的图片格式,如regular和small等。
- 图片来源丢失,有些图片只有original大小的,有的图片是全丢失了(经常是404 not found)
- 就算是这样,在线来源也经常抽风,正好我还有点儿存储空间,最终还是想的本地+在线的方式运行
遂采用三步下载的方式,首先是下载regular大小的图片,如果超时下载失败,则执行一次small大小的下载,再失败两种可能,只有original源或者全丢失,最后再尝试一下original源,没有的话就跳过。
以下为五种规格的示例(SFW,请放心打开)
?暂时保持默认的插件
明日方舟抽卡查询
今天吃什么
今日运势图生成插件
戳一戳插件(多功能需要搭配其他插件)
表情包制作插件
?启用失败的插件
Lolicon API的随机涩图插件:盲猜一手网络原因,获取不到图片缓存
网易云点歌:aiocqhttp.exc message=’消息体无法解析,请检查是否发送了不支持的消息类型体无法解析,请检查是否发送了不支持的消息类型{‘seq’:22}>
摸鱼人日历:api集体失效
版本
v1.1.0 实现了黑名单,优化自动缓存和手动缓存
v1.1.1 尝试使用代理直接走官方的链接,发现不好用,废版本,好像还是有用的,只是没有在日志里面输出成功下载,我还以为不下了来着
v1.1.2 使用pid+页数然后通过pixiv api获取正确的url下载地址(因为lolicon的地址有些因为时间变动而失效)
v1.1.4 补全图库使用pixiv api功能,不是走官方链接,可以获取的到了,但是还在摸索中,同时发现补全图库的请求不能太频繁,不然会被风控;尝试获取所有的日语tag和中文tag,已经发现了gtm-new-work-tag-event-click → 日文标签 + gtm-new-work-translate-tag-event-click → 翻译标签 这两组标签。官方默认是英文翻译。最终可能还是通过外部python爬取的方式,然后又有了一个新的想法,信息貌似能获取收藏数,这样就可以根据收藏数来获取更好看的图片了,如下
{ “create_date”: “创建日期”, “series”: “系列名称”, “page_count”: “图片总数”, “height”: “第一张图片的高度”, “total_view”: “总浏览量”, “id”: “作品ID”, “title”: “作品标题”, “width”: “第一张图片的宽度高度”, “type”: “作品类型,例如illust、manga”, “tags”: [ { “name”: “标签名”, “translated_name”: “标签名翻译” } ], “user”: { “account”: “画师用户名”, “id”: “画师用户ID”, “name”: “画师名称” }, “total_bookmarks”: “收藏总数”, “filename”: “原始文件名称,不含扩展名,如12345_p0”, “page”: “单张图片在所有图片中的顺序,从零开始”
经过查询,建议如果要检索的话把所有的数据都放在一个json文件里面然后内存索引


