alicebotproject / alicebot Goto Github PK
View Code? Open in Web Editor NEW简单的 Python 异步多后端机器人框架
Home Page: https://docs.alicebot.dev/
License: MIT License
简单的 Python 异步多后端机器人框架
Home Page: https://docs.alicebot.dev/
License: MIT License
cqhttp只能将收到的消息转化为字符串且无法分割成为原生消息段数组
在写插件的过程中难免出错,而alicebot的报错机制过于笼统,希望添加更完美的报错
至少在alicebot\__init__.py
的283与287行添加更详细的报错
loguru中有集成一个better_exceptions的库,可以更加详细地输出方法报错的所有信息,只需要将logger.error()改为logger.exception()即可
如题
https://docs.alicebot.dev/guide/plugin-advanced.html
第三行 block 写错了
很喜欢这个框架,简单易用,开发者加油!
尝试让
MiraiMessageSegment.at(self.event.sender.id) + MiraiMessageSegment.plain("ABC")
组合时,出现如下错误:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "~\site-packages\alicebot\message.py", line 379, in __add__
return self._message_class(self) + other
TypeError: _message_class() takes 1 positional argument but 2 were given
环境为
谢谢!
pypi那里是自动更新吗,还是说手动更新
我pip install alicebot[all] --upgrade
的时候,一直是环境满足,怀疑自己没更新上
2022-07-19 09:59:21.824 | ERROR | alicebot:_handle_event:283 - Exception in plugin "<freegame.FreeGame object at 0x00000161236DACE0>": TypeError("MessageSegment.__init__() missing 1 required positional argument: 'type'")
1.经实际使用发现不符
2.缺少富文本特性支持
仅包含群组id和目标id 无群组与私聊区分和发起戳一戳的人的id
缺失群组id
缺失群组id和成员id
我根据「快速上手 | AliceBot」一文中讲述的方法,使用了如下命令安装的 Alicebot 轮子以及其 Mirai Adaptor:
pip install alicebot
pip install alicebot-adapter-mirai
然后当我 from alicebot import Bot
的时候,出现了如下问题:
>>> from alicebot import Bot
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "%appdata%\..\Local\Programs\Python\Python38\lib\site-packages\alicebot\__init__.py", line 14, in <module>
from alicebot.adapter import Adapter
File "%appdata%\..\Local\Programs\Python\Python38\lib\site-packages\alicebot\adapter\__init__.py", line 23, in <module>
from alicebot.utils import is_config_class
File "%appdata%\..\Local\Programs\Python\Python38\lib\site-packages\alicebot\utils.py", line 60, in <module>
StrOrBytesPath: TypeAlias = Union[str, bytes, PathLike[str], PathLike[bytes]]
TypeError: 'ABCMeta' object is not subscriptable
然后当我打开文件 alicebot\utils.py
的时候,发现其内容与仓库中的代码不一致,具体地说,仓库中所编写的内容为:
# At Line 60
StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"]
而 pip 下下来的是:
# At Line 60
StrOrBytesPath: TypeAlias = Union[str, bytes, PathLike[str], PathLike[bytes]]
我不是很清楚这个情况是不是只有在 Python 3.8.X 系列版本中出现的问题,但是它确确实实出现在了使用 Python 3.8.X 的 PC 上。
环境配置如下:
由于我不是专业的,可能有一些地方说的不是很严谨,也请大家多多海涵 ;)
https://docs.alicebot.dev/guide/getting-started.html
pip install alicebot-adapter-dingtalk not pip install alicebot-adapter-digntalk
mirai成功接受到消息,测试Bot没有反应输出
test code
from alicebot import Plugin
from alicebot.exceptions import GetEventTimeout
from alicebot.log import logger
from alicebot.adapter.mirai.event.base import FriendInfo
from alicebot.typing import T_State
from typing import Type, Union, Generic, TypeVar
from .config import BasePluginConfig, RegexPluginConfig, CommandPluginConfig
T_Config = TypeVar("T_Config", bound=BasePluginConfig)
class TestPlugin(Plugin):
priority: int = 0
block: bool = False
async def handle(self) -> None:
pass
async def rule(self) -> bool:
logger.info(self.event.adapter.name)
return True
config.toml
[bot]
plugins = ["chatgpt-qqbot"]
plugin_dirs = ["plugins"]
adapters = ["alicebot.adapter.mirai"]
[bot.log]
verbose_exception = true
[adapter.mirai]
adapter_type = "reverse-ws"
verify_key = "password"
qq = qq
host = "127.0.0.1"
port = 5700
url = "/mirai/ws"
setting.yml
adapters:
- reverse-ws
enableVerify: true
verifyKey: password
singleMode: true
adapterSettings:
reverse-ws:
destinations:
- host: 127.0.0.1
port: 5700
path: /mirai/ws
protocol: ws
method: GET
reservedSyncId: -1
我在文档中似乎没找到发送图片的方法,示例里也没看见,所以想请教一下,我很喜欢这个框架,谢谢
对logger的自定义会被bot.py中的_update_config中的logger.remove()删除˃ ˄ ˂̥̥
为了确认插件被成功加载,我在plugins目录下的xxx.py文件中写了一句代码print('xxx插件已加载成功')
,然后发现启动程序时这个打印出现了两次,单步调试时发现utils.py中的get_classes_from_module_name函数中有这样一段代码:
importlib.invalidate_caches()
module = importlib.import_module(name)
importlib.reload(module)
return [(x, module) for x in get_classes_from_module(module, super_class)]
这里的module = importlib.import_module(name)
和importlib.reload(module)
都会导致xxx.py文件被执行一次,所以xxx.py就被执行了两次
这个问题还导致我之后的另一种应用场景出现问题,简化代码如下:
我在plugins之外创建了一个comm目录,供所有的插件使用,其中提供了一个注册函数接口
fun_arr=[]
def add_fun(fun):
fun_arr.append(fun)
在plugins中的一个文件中调用
class MyPlugin(Plugin):
def f(self):
...
add_fun(MyPlugin.f)
在这种场景下,会导致add_fun
被调用两次,同一个函数会被注册两次
我某个插件用了持久性的数据库连接,想要在退出bot时断开连接,但目前我通过bot_exit_hook的同步钩子函数做不到异步关闭连接
问题已解决
建议新增一个可以遍历插件名和 usage 的类,可以用来写插件帮助图
报错信息如下:
File "D:\Python310\lib\site-packages\alicebot\bot.py", line 173, in run
asyncio.run(self._run())
│ │ │ └ <function Bot._run at 0x0000021A5CC930A0>
│ │ └ <alicebot.bot.Bot object at 0x0000021A5C97D4B0>
│ └ <function run at 0x0000021A5B8BE9E0>
└ <module 'asyncio' from 'D:\\Python310\\lib\\asyncio\\__init__.py'>
File "D:\Python310\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
│ │ └ <coroutine object Bot._run at 0x0000021A5CC5C580>
│ └ <function BaseEventLoop.run_until_complete at 0x0000021A5B99F0A0>
└ <ProactorEventLoop running=True closed=False debug=False>
File "D:\Python310\lib\asyncio\base_events.py", line 633, in run_until_complete
self.run_forever()
│ └ <function ProactorEventLoop.run_forever at 0x0000021A5B9F1240>
└ <ProactorEventLoop running=True closed=False debug=False>
File "D:\Python310\lib\asyncio\windows_events.py", line 321, in run_forever
super().run_forever()
File "D:\Python310\lib\asyncio\base_events.py", line 600, in run_forever
self._run_once()
│ └ <function BaseEventLoop._run_once at 0x0000021A5B9A0B80>
└ <ProactorEventLoop running=True closed=False debug=False>
File "D:\Python310\lib\asyncio\base_events.py", line 1896, in _run_once
handle._run()
│ └ <function Handle._run at 0x0000021A5B9105E0>
└ <Handle Task.task_wakeup(<Future finished result=None>)>
File "D:\Python310\lib\asyncio\events.py", line 80, in _run
self._context.run(self._callback, *self._args)
│ │ │ │ │ └ <member '_args' of 'Handle' objects>
│ │ │ │ └ <Handle Task.task_wakeup(<Future finished result=None>)>
│ │ │ └ <member '_callback' of 'Handle' objects>
│ │ └ <Handle Task.task_wakeup(<Future finished result=None>)>
│ └ <member '_context' of 'Handle' objects>
└ <Handle Task.task_wakeup(<Future finished result=None>)>
> File "D:\Python310\lib\site-packages\alicebot\adapter\__init__.py", line 78, in safe_run
await self.run()
│ └ <function WebSocketAdapter.run at 0x0000021A5E15A440>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x0000021A5E3420E0>
File "D:\Python310\lib\site-packages\alicebot\adapter\utils.py", line 207, in run
await self.websocket_connect()
│ └ <function MiraiAdapter.websocket_connect at 0x0000021A5E18E440>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x0000021A5E3420E0>
File "D:\Python310\lib\site-packages\alicebot\adapter\mirai\__init__.py", line 90, in websocket_connect
await self.handle_websocket()
│ └ <function WebSocketAdapter.handle_websocket at 0x0000021A5E15A710>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x0000021A5E3420E0>
File "D:\Python310\lib\site-packages\alicebot\adapter\utils.py", line 266, in handle_websocket
await self.handle_websocket_msg(msg)
│ │ └ WSMessage(type=<WSMsgType.TEXT: 1>, data='{"syncId":"-1","data":{"type":"FriendRecallEvent","authorId":123456789,"messageId"...
│ └ <function MiraiAdapter.handle_websocket_msg at 0x0000021A5E18E4D0>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x0000021A5E3420E0>
File "D:\Python310\lib\site-packages\alicebot\adapter\mirai\__init__.py", line 119, in handle_websocket_msg
await self.handle_mirai_event(msg_dict.get("data"))
│ │ │ └ <method 'get' of 'dict' objects>
│ │ └ {'syncId': '-1', 'data': {'type': 'FriendRecallEvent', 'authorId': 123456789, 'messageId': 26036, 'time': 1691243648, 'opera...
│ └ <function MiraiAdapter.handle_mirai_event at 0x0000021A5E18E680>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x0000021A5E3420E0>
File "D:\Python310\lib\site-packages\alicebot\adapter\mirai\__init__.py", line 153, in handle_mirai_event
mirai_event = self.get_event_model(msg["type"])(adapter=self, **msg)
│ │ │ │ └ {'type': 'FriendRecallEvent', 'authorId': 123456789, 'messageId': 26036, 'time': 1691243648, 'operator': 123456789}
│ │ │ └ <alicebot.adapter.mirai.MiraiAdapter object at 0x0000021A5E3420E0>
│ │ └ {'type': 'FriendRecallEvent', 'authorId': 123456789, 'messageId': 26036, 'time': 1691243648, 'operator': 123456789}
│ └ <classmethod(<function MiraiAdapter.get_event_model at 0x0000021A5E18E5F0>)>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x0000021A5E3420E0>
File "D:\Python310\lib\site-packages\alicebot\event.py", line 48, in __init__
super().__init__(**data)
└ {'type': 'FriendRecallEvent', 'authorId': 123456789, 'messageId': 26036, 'time': 1691243648, 'operator': 123456789}
File "pydantic\main.py", line 341, in pydantic.main.BaseModel.__init__
raise validation_error
pydantic.error_wrappers.ValidationError: 1 validation error for FriendRecallEvent
friend
field required (type=value_error.missing)
原因为FriendRecallEvent继承自FriendEvent,FriendEvent中有类成员friend: FriendInfo,导致FriendRecallEvent初始化也必须传一个该字段,而mirai传来的事件中没有该字段
#alicebot\adapter\mirai\event\notice.py
class FriendEvent(NoticeEvent):
"""好友事件"""
friend: FriendInfo
class FriendRecallEvent(FriendEvent):
"""好友消息撤回"""
type: Literal["FriendRecallEvent"]
authorId: int
messageId: int
time: int
operator: int
I've gone through the site but couldn't find the footer on the AliceBot page. If you're interested in adding it, please let me know. I'd be happy to work in this task.
Thank you!
复现方法:
1.在Mirai使用ANDROID_PHONE协议登录,并使用Mira适配器连接。
2.在IPad或其他设备登录机器人账号并向群聊发送消息。
3.适配器停止工作。
错误日志:
to load adapter "MiraiAdapter" from "alicebot.adapter.mirai"
2024-02-28 10:58:33.607 | INFO | alicebot.bot:_load_adapters:836 - Succeeded
to load adapter "APSchedulerAdapter" from "alicebot.adapter.apscheduler"
2024-02-28 10:58:33.624 | INFO | alicebot.bot:_run:213 - Running AliceBot...
2024-02-28 10:58:33.798 | INFO | alicebot.bot:_run_hot_reload:291 - Hot relo
ad is working!
2024-02-28 10:58:33.813 | INFO | alicebot.adapter.mirai:websocket_connect:90
- Trying to verify identity and create connection...
2024-02-28 10:58:33.820 | INFO | alicebot.adapter.apscheduler:run:74 - Plugi
n DecreasePlugin has been scheduled to run
2024-02-28 10:58:33.890 | INFO | alicebot.adapter.mirai:handle_websocket_msg
:111 - Verify success! Session key: BBjnUrGX
2024-02-28 10:58:39.804 | INFO | alicebot.bot:handle_event:456 - Adapter mir
ai received: Event<GroupMessage>: "菜单"
2024-02-28 10:58:39.828 | INFO | alicebot.bot:_handle_event:507 - Event will
be handled by <Menu.MenuPlugin object at 0x000000A86E1FEE80>
2024-02-28 10:58:40.953 | INFO | alicebot.bot:_handle_event:527 - Event Fini
shed
2024-02-28 10:58:41.319 | ERROR | alicebot.bot:error_or_exception:910 - Run a
dapter MiraiAdapter failed:
Traceback (most recent call last):
File "C:\Users\Administrator\Desktop\AliceBot\bot.py", line 6, in <module>
bot.run()
│ └ <function Bot.run at 0x000000A86BCC64C0>
└ <alicebot.bot.Bot object at 0x000000A86B035B80>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-p
ackages\alicebot\bot.py", line 174, in run
asyncio.run(self._run())
│ │ │ └ <function Bot._run at 0x000000A86BCC65E0>
│ │ └ <alicebot.bot.Bot object at 0x000000A86B035B80>
│ └ <function run at 0x000000A86BA72820>
└ <module 'asyncio' from 'C:\\Users\\Administrator\\AppData\\Local\\Program
s\\Python\\Python38\\lib\\asyncio\\__init__.py'>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asynci
o\runners.py", line 44, in run
return loop.run_until_complete(main)
│ │ └ <coroutine object Bot._run at 0x000000A8
6BC35DC0>
│ └ <function BaseEventLoop.run_until_complete at 0x000000A86BA6
FAF0>
└ <ProactorEventLoop running=True closed=False debug=False>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asynci
o\base_events.py", line 603, in run_until_complete
self.run_forever()
│ └ <function ProactorEventLoop.run_forever at 0x000000A86BAF7790>
└ <ProactorEventLoop running=True closed=False debug=False>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asynci
o\windows_events.py", line 316, in run_forever
super().run_forever()
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asynci
o\base_events.py", line 570, in run_forever
self._run_once()
│ └ <function BaseEventLoop._run_once at 0x000000A86BA725E0>
└ <ProactorEventLoop running=True closed=False debug=False>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asynci
o\base_events.py", line 1859, in _run_once
handle._run()
│ └ <function Handle._run at 0x000000A86BA06940>
└ <Handle <TaskWakeupMethWrapper object at 0x000000A86E1FE700>(<Future fini
shed result=None>)>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asynci
o\events.py", line 81, in _run
self._context.run(self._callback, *self._args)
│ │ │ │ │ └ <member '_args' of 'Handle'
objects>
│ │ │ │ └ <Handle <TaskWakeupMethWrapper obj
ect at 0x000000A86E1FE700>(<Future finished result=None>)>
│ │ │ └ <member '_callback' of 'Handle' objects>
│ │ └ <Handle <TaskWakeupMethWrapper object at 0x000000A86E
1FE700>(<Future finished result=None>)>
│ └ <member '_context' of 'Handle' objects>
└ <Handle <TaskWakeupMethWrapper object at 0x000000A86E1FE700>(<Future fini
shed result=None>)>
> File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-p
ackages\alicebot\adapter\__init__.py", line 78, in safe_run
await self.run()
│ └ <function WebSocketAdapter.run at 0x000000A86D2B6F70>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x000000A86BECFA00>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-p
ackages\alicebot\adapter\utils.py", line 217, in run
await self.websocket_connect()
│ └ <function MiraiAdapter.websocket_connect at 0x000000A86D34216
0>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x000000A86BECFA00>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-p
ackages\alicebot\adapter\mirai\__init__.py", line 95, in websocket_connect
await self.handle_websocket()
│ └ <function WebSocketAdapter.handle_websocket at 0x000000A86D2B
F280>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x000000A86BECFA00>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-p
ackages\alicebot\adapter\utils.py", line 271, in handle_websocket
await self.handle_websocket_msg(msg)
│ │ └ WSMessage(type=<WSMsgType.TEXT: 1>, dat
a='{"syncId":"-1","data":{"type":"GroupSyncMessage","messageChain":[{"type":"Sou
rce","...
│ └ <function MiraiAdapter.handle_websocket_msg at 0x000000A86D34
21F0>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x000000A86BECFA00>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-p
ackages\alicebot\adapter\mirai\__init__.py", line 122, in handle_websocket_msg
await self.handle_mirai_event(msg_dict.get("data"))
│ │ │ └ <method 'get' of 'dict' objects
>
│ │ └ {'syncId': '-1', 'data': {'type': 'GroupS
yncMessage', 'messageChain': [{'type': 'Source', 'id': 907, 'time': 1709089125},
{'t...
│ └ <function MiraiAdapter.handle_mirai_event at 0x000000A86D3F4F
70>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x000000A86BECFA00>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-p
ackages\alicebot\adapter\mirai\__init__.py", line 158, in handle_mirai_event
mirai_event = self.get_event_model(msg["type"])(adapter=self, **msg)
│ │ │ │ └ {'typ
e': 'GroupSyncMessage', 'messageChain': [{'type': 'Source', 'id': 907, 'time': 1
709089125}, {'type': 'Image', 'imageId':...
│ │ │ └ <alicebot.adap
ter.mirai.MiraiAdapter object at 0x000000A86BECFA00>
│ │ └ {'type': 'GroupSyncMessage', 'messag
eChain': [{'type': 'Source', 'id': 907, 'time': 1709089125}, {'type': 'Image', '
imageId':...
│ └ <classmethod object at 0x000000A86D42C4F0>
└ <alicebot.adapter.mirai.MiraiAdapter object at 0x000000A86B
ECFA00>
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\site-p
ackages\alicebot\adapter\mirai\__init__.py", line 148, in get_event_model
return cls.event_models[event_type]
│ │ └ 'GroupSyncMessage'
│ └ {'BotEvent': <class 'alicebot.adapter.mirai.event.meta.BotEve
nt'>, 'BotGroupPermissionChangeEvent': <class 'alicebot.adapter....
└ <class 'alicebot.adapter.mirai.MiraiAdapter'>
KeyError: 'GroupSyncMessage'
2024-02-28 10:58:43.332 | INFO | alicebot.bot:_handle_exit:432 - Stopping Al
iceBot...```
希望增加对应的类型推断或泛型参数。
系统: windows 11
py版本: 3.10.11
alicebot 版本:0.8.1
(alicebot 0.7.1 版本正常运行无报错)
报错详情:
每次接收到消息就会报错.
2023-10-01 07:44:17.739 | INFO | alicebot.adapter.cqhttp:reverse_ws_connection_hook:88 - WebSocket connected!
2023-10-01 07:44:17.742 | INFO | alicebot.adapter.cqhttp:handle_cqhttp_event:195 - WebSocket connection from CQHTTP Bot xxx accepted!
Error handling request
Traceback (most recent call last):
File "c:\ziyii\bot\bot\venv\lib\site-packages\aiohttp\web_protocol.py", line 433, in _handle_request
resp = await request_handler(request)
File "c:\ziyii\bot\bot\venv\lib\site-packages\aiohttp\web_app.py", line 504, in _handle
resp = await handler(request)
File "c:\ziyii\bot\bot\venv\lib\site-packages\alicebot\adapter\utils.py", line 250, in handle_reverse_ws_response
await self.handle_websocket()
File "c:\ziyii\bot\bot\venv\lib\site-packages\alicebot\adapter\utils.py", line 271, in handle_websocket
await self.handle_websocket_msg(msg)
File "c:\ziyii\bot\bot\venv\lib\site-packages\alicebot\adapter\cqhttp\__init__.py", line 122, in handle_websocket_msg
await self.handle_cqhttp_event(msg_dict)
File "c:\ziyii\bot\bot\venv\lib\site-packages\alicebot\adapter\cqhttp\__init__.py", line 187, in handle_cqhttp_event
cqhttp_event = event_class(adapter=self, **msg)
File "c:\ziyii\bot\bot\venv\lib\site-packages\pydantic\main.py", line 164, in __init__
__pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)
pydantic_core._pydantic_core.ValidationError: 2 validation errors for GroupMessageEvent
message.is-instance[CQHTTPMessage]
Input should be an instance of CQHTTPMessage [type=is_instance_of, input_value='xxx', input_type=str]
For further information visit https://errors.pydantic.dev/2.4/v/is_instance_of
message.function-after[CQHTTPMessage(), list[CQHTTPMessageSegment]]
Input should be a valid list [type=list_type, input_value='xxx', input_type=str]
For further information visit https://errors.pydantic.dev/2.4/v/list_type
2023-10-01 07:44:27.957 | INFO | alicebot.adapter.cqhttp:reverse_ws_connection_hook:88 - WebSocket connected!
2023-10-01 07:44:27.958 | INFO | alicebot.adapter.cqhttp:handle_cqhttp_event:195 - WebSocket connection from CQHTTP Bot xxx accepted!
项目名称:AliceBot 插件商店实现
项目主导师:迷糊小梦神
申请人:Marlene
日期:2023.5.10
邮箱:[email protected]
AliceBot 使用了非常灵活且易于使用的插件编写方式,用户只需要编写两个方法即可实现一个功能强大的插件。随着 AliceBot 用户量的提高,许多用户都编写了自己的插件和适配器,为了方便用户交流,避免“重复造轮子”,急需开发一个商店页面用于用户分享自己编写插件和适配器。
用户想要分享自己的插件或者适配器,可以通过github仓库进行开源分享。为了更方便插件审核以及插件商店的插件提交。急需一个基于GitHub Apps开发的自动化bot,用于插件的提交和审核。
由于用户需要通过issue和pr,提交自己的插件相关内容至插件商店的github仓库。更新后的代码需要及时生成文档站并进行部署。这方面急需一个基于vercel/netlify以及clodeflare(cdn加速)实现自动化部署,方便文档站(插件商店)能够及时更新。
主仓库:https://github.com/AliceBotProject/alicebot
该项目已有一个基于vitepress的项目文档,以及一些基础构建的workflow。
所有内容基本都在master分支。
插件商店的需求是聚合相关插件、适配器、样例的资源站,提供插件等内容的浏览与链接跳转。
资源信息主要包含名称、类型(插件/适配器/样例)、模组名、描述、作者、仓库链接、标签、是否为官方出品等元信息。这些内容课通过pr合并至文档仓库的plugins.json文件内,用于存储相关信息。
界面可以采用vue3.3+vitepress开发,无需引入额外的库。
由于vitepress并无直接的内容聚合型展示功能,需要进行额外开发。主要思路是在vitepress上开发一个插件商店页面,包含多个相关组件。通过vitepress的markdown内置vue功能开发相关组件及页面功能和样式。通过vitepress提供的数据加载器功能实现插件商店数据的实时获取。
以下为实际操作的部分过程:
md文件可以使用内置vue语法编写相关页面样式以及引用相关组件,具体示例如下:
---
hello: world
---
<script setup>
import { ref } from 'vue'
import StoreTab from '../components/StoreTab.vue'
import Adapter from '../components/adapter.vue'
import Example from '../components/example.vue'
import Plugin from '../components/plugin.vue'
</script>
## Markdown Content
<store-tab class="tab">
<plugin></plugin>
<adapter></adapter>
<example></example>
</store-tab>
<style module>
.tab{
...
}
</style>
下图为商店界面的原型设计,UI的设计充分考虑移动设备的布局,做好自适应和暗黑配色。
当插件多起来之后,或许可以增加搜索功能。可以提供发布插件的引导页面,方便新手提交和分享插件。
更有甚至,直接在商店页面增加提交插件功能,一步到位,不过这可能不再是静态网站,需要额外资源进行存储。
用户提交插件的主要流程如下:
当用户新增issue,并提交相关pr,该pr关联issue时。issue相关信息更新,出发bot进行插件审核,pr自动合并,并自动close issue。当用户需要更新插件信息,只需要再次提交pr,关联原先的issue,即可
建立issue必须符合规范,否则bot直接进行close。
当然,bot并不会对所有issue进行如此操作。针对issue标题或者issue的主体中, 如果出现一些常见关键词, 譬如plugin, 那么在标题或者issue的主体内容中出现【plugin】这个词时,通过编写相应的工作流,也可以自动为该issue添加plugin标签。
这里我们也可以建立一个issue模板,具体可以在github repo 的settings里面设置:
这里的github bot(apps)主要参与的时检查代码规范,提交信息规范,在pr中合并,自动检查issue。
我们可以使用webhook来实现issue信息更新的监听,触发相关事件。
需要新建一个bot,然后审核后上架这个bot,再在仓库中使用。
部署主要分为测试环境部署和生产环境部署。自动化部署主要应用于pr提交后,可进行测试环境部署,展示该pr的具体效果。当整个pr merge后进行生产环境部署,用于线上环境。
我们可以使用vercel和netlify提供的静态站点部署功能,将每次commit后都进行自动化部署展示,节约人工成本。当然,使用这些服务需要设置一些自身的信息,比如需要绑定自定义域名,使得最新部署站点能够及时显示在官网中。
由于vercel会被墙,这里推荐使用cloudflare做cdn加速,当然也可以使用其他cdn服务。
非常希望能够参加本次项目开发,由于学校有亚运会项目,可以有暑假三个月假期时间开发,非常充裕,当然项目整体难度不高,开发周期也不是很长。所以完成后,或许可以再开发一些相关插件玩玩。
非常希望参加这样一个全新项目的开发,AliceBot旨在减轻NoneBot这类框架开发的一个负担,我非常认同这个理念。我在之前的bot插件开发使用中也经常为此头疼。希望我能够为这个项目做出贡献,丰富项目生态。
在指南协议适配器部分,Mirai协议适配器一节的发送富文本例子中
https://docs.alicebot.dev/guide/mirai-adapter.html
from alicebot.adapter.mirai.message import CQHTTPMessageSegment
是否应该为
from alicebot.adapter.mirai.message import MiraiMessageSegment
之后的
msg = CQHTTPMessageSegment.plain("Hello, Alice!") + \
CQHTTPMessageSegment.image(url="https://www.example.org/1.jpg")
则应为相应的
msg = MiraiMessageSegment.plain("Hello, Alice!") + \
MiraiMessageSegment.image(url="https://www.example.org/1.jpg")
感谢您制作了alicebot,它对新手真的很友好。但是我遇上了个问题,config.toml中配置自定义字段,例如group_list={"grout1":string1,"group2":string2}
,在使用过程中需要增加键值group3:string3进去,在程序中self.bot.config.group_list['group3']=string3之后关闭程序,发现其内容没有被写入到文件中,但是程序运行状态时却是能正确读出修改后的配置,请问这种情况下是程序bug还是本就没有设计修改配置后的保存功能?我看说明文档中也没有提示相关的内容。期待回复。
2022-08-21 23:03:22.697 | ERROR | alicebot.log:error_or_exception:15 - Config dict parse error: ValidationError(model='MainConfig', errors=[{'loc': ('plugins',), 'msg': 'none is not an allowed value', 'type': 'type_error.none.not_allowed'}])
以上为报错
以下为config.json
{
"plugins": null,
"plugin_dir": [
"plugins",
"plugins/osu"
],
"adapters": ["alicebot.adapter.cqhttp"],
"cqhttp": {
"host": "127.0.0.1",
"port": 9999,
"url": "/cqhttp/ws",
"api_timeout": 10000
},
"superuser": [1483492332],
"osu": {
"api":{
"v2": {
"id": 6322,
"secret": "G5Dpfd1hAgAt8zkt0aFklV8bteaZITv1vC2bxcfO"
}
}
}
}
31行所在的方法中添加类似于
string.replace('&', '&').replace('[', '[').replace(']',']').replace(',', ',')
的字段,虽然难看,但确实有用
为插件添加self.bot.reload()
重载函数,可以热重载,也可以整个重启
有一种设想,可以实施,但是少了这个函数无法便捷地实施,具体如下:
1.开发机的文件系统分两部分,一部分为开发项目,一部分为生产环境用的项目文件
2.生产环境用项目文件与服务器端开发环境项目文件使用rsync进行绑定
3.在本地开发完毕后,将新的插件文件或更改的文件放入开发机的生产环境项目文件中使用rsync进行同步
好处也就只有方便懒人了,而且做一个重载,应该不会非常难,实现退出函数再重新运行bot.run()即可,但我不了解alicebot的代码结构,没办法帮忙,请求加入这个功能
配置定时任务的时候会自动配置多一个重复的
这是插件源代码(部分)
`from alicebot import Plugin, MessageEvent
from .service import get_today_courses, get_tomorrow_courses
from alicebot.adapter.apscheduler import scheduler_decorator
@scheduler_decorator(
trigger="cron", trigger_args={"day_of_week": "sun,mon,wed,thu", "hour": 22, "minute": 0}, override_rule=False
)
class CourseSchedule(Plugin):
async def handle(self) -> None:
data = get_tomorrow_courses()
await self.bot.get_adapter("cqhttp").send(data, "private", self.bot.config.superuser)
async def rule(self) -> bool:
return (
self.event.adapter.name == "apscheduler"
and type(self) == self.event.plugin_class
)
class CourseRemindPlugin(Plugin):
async def handle(self) -> None:
data = ""
if self.event.get_plain_text()[0] == '今':
data = get_today_courses()
elif self.event.get_plain_text()[0] == '明':
data = get_tomorrow_courses()
await self.event.reply(data)
async def rule(self) -> bool:
return (
isinstance(self.event, MessageEvent)
and self.event.user_id == self.bot.config.superuser
and (self.event.get_plain_text() == "今日课表"
or self.event.get_plain_text() == "明日课表")
)
`
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.