-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #174 from Soulter/refactor-v3.3.0
重写工程,提高稳定性
- Loading branch information
Showing
112 changed files
with
3,412 additions
and
3,242 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
FROM python:3.10.13-bullseye | ||
FROM python:3.10-slim | ||
WORKDIR /AstrBot | ||
|
||
COPY . /AstrBot/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,32 @@ | ||
import os | ||
import shutil | ||
from nakuru.entities.components import * | ||
flag_not_support = False | ||
try: | ||
from util.plugin_dev.api.v1.bot import Context, AstrMessageEvent, CommandResult | ||
from util.plugin_dev.api.v1.config import * | ||
from util.plugin_dev.api.v1.bot import ( | ||
AstrMessageEvent, | ||
CommandResult, | ||
) | ||
except ImportError: | ||
flag_not_support = True | ||
print("导入接口失败。请升级到 AstrBot 最新版本。") | ||
|
||
|
||
''' | ||
注意改插件名噢!格式:XXXPlugin 或 Main | ||
小提示:把此模板仓库 fork 之后 clone 到机器人文件夹下的 addons/plugins/ 目录下,然后用 Pycharm/VSC 等工具打开可获更棒的编程体验(自动补全等) | ||
注意以格式 XXXPlugin 或 Main 来修改插件名。 | ||
提示:把此模板仓库 fork 之后 clone 到机器人文件夹下的 addons/plugins/ 目录下,然后用 Pycharm/VSC 等工具打开可获更棒的编程体验(自动补全等) | ||
''' | ||
class HelloWorldPlugin: | ||
""" | ||
初始化函数, 可以选择直接pass | ||
AstrBot 会传递 context 给插件。 | ||
- context.register_commands: 注册指令 | ||
- context.register_task: 注册任务 | ||
- context.message_handler: 消息处理器(平台类插件用) | ||
""" | ||
def __init__(self) -> None: | ||
pass | ||
def __init__(self, context: Context) -> None: | ||
self.context = context | ||
self.context.register_commands("helloworld", "helloworld", "内置测试指令。", 1, self.helloworld) | ||
|
||
""" | ||
机器人程序会调用此函数。 | ||
""" | ||
def run(self, ame: AstrMessageEvent): | ||
if ame.message_str.startswith("helloworld"): # 如果消息文本以"helloworld"开头 | ||
return CommandResult( | ||
hit=True, # 代表插件会响应此消息 | ||
success=True, # 插件响应类型为成功响应 | ||
message_chain=[Plain("Hello World!!")], # 消息链 | ||
command_name="helloworld" # 指令名 | ||
) | ||
return CommandResult( | ||
hit=False, # 插件不会响应此消息 | ||
success=False, | ||
message_chain=None | ||
) | ||
""" | ||
插件元信息。 | ||
当用户输入 plugin v 插件名称 时,会调用此函数,返回帮助信息。 | ||
返回参数要求(必填):dict{ | ||
"name": str, # 插件名称 | ||
"desc": str, # 插件简短描述 | ||
"help": str, # 插件帮助信息 | ||
"version": str, # 插件版本 | ||
"author": str, # 插件作者 | ||
"repo": str, # 插件仓库地址 [ 可选 ] | ||
"homepage": str, # 插件主页 [ 可选 ] | ||
} | ||
指令处理函数。 | ||
- 需要接收两个参数:message: AstrMessageEvent, context: Context | ||
- 返回 CommandResult 对象 | ||
""" | ||
def info(self): | ||
return { | ||
"name": "helloworld", | ||
"desc": "这是 AstrBot 的默认插件,支持关键词回复。", | ||
"help": "输入 /keyword 查看关键词回复帮助。", | ||
"version": "v1.3", | ||
"author": "Soulter", | ||
"repo": "https://github.com/Soulter/helloworld" | ||
} | ||
def helloworld(self, message: AstrMessageEvent, context: Context): | ||
return CommandResult().message("Hello, World!") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
name: helloworld # 这是你的插件的唯一识别名。 | ||
desc: 这是 AstrBot 的默认插件,支持关键词回复。 # 插件简短描述 | ||
help: 输入 /keyword 查看关键词回复帮助。 # 插件的帮助信息 | ||
desc: 这是 AstrBot 的默认插件。 | ||
help: | ||
version: v1.3 # 插件版本号。格式:v1.1.1 或者 v1.1 | ||
author: Soulter # 作者 | ||
repo: https://github.com/Soulter/helloworld # 插件的仓库地址 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import asyncio | ||
import traceback | ||
from astrbot.message.handler import MessageHandler | ||
from astrbot.persist.helper import dbConn | ||
from dashboard.server import AstrBotDashBoard | ||
from model.provider.provider import Provider | ||
from model.command.manager import CommandManager | ||
from model.command.internal_handler import InternalCommandHandler | ||
from model.plugin.manager import PluginManager | ||
from model.platform.manager import PlatformManager | ||
from typing import Dict, List, Union | ||
from type.types import Context | ||
from SparkleLogging.utils.core import LogManager | ||
from logging import Logger | ||
from util.cmd_config import CmdConfig | ||
from util.metrics import MetricUploader | ||
from util.config_utils import * | ||
from util.updator.astrbot_updator import AstrBotUpdator | ||
|
||
logger: Logger = LogManager.GetLogger(log_name='astrbot') | ||
|
||
|
||
class AstrBotBootstrap(): | ||
def __init__(self) -> None: | ||
self.context = Context() | ||
self.config_helper: CmdConfig = CmdConfig() | ||
|
||
# load configs and ensure the backward compatibility | ||
init_configs() | ||
try_migrate_config() | ||
self.configs = inject_to_context(self.context) | ||
logger.info("AstrBot v" + self.context.version) | ||
self.context.config_helper = self.config_helper | ||
|
||
# apply proxy settings | ||
http_proxy = self.context.base_config.get("http_proxy") | ||
https_proxy = self.context.base_config.get("https_proxy") | ||
if http_proxy: | ||
os.environ['HTTP_PROXY'] = http_proxy | ||
if https_proxy: | ||
os.environ['HTTPS_PROXY'] = https_proxy | ||
os.environ['NO_PROXY'] = 'https://api.sgroup.qq.com' | ||
|
||
if http_proxy and https_proxy: | ||
logger.info(f"使用代理: {http_proxy}, {https_proxy}") | ||
else: | ||
logger.info("未使用代理。") | ||
|
||
async def run(self): | ||
self.command_manager = CommandManager() | ||
self.plugin_manager = PluginManager(self.context) | ||
self.updator = AstrBotUpdator() | ||
self.cmd_handler = InternalCommandHandler(self.command_manager, self.plugin_manager) | ||
self.db_conn_helper = dbConn() | ||
|
||
# load llm provider | ||
self.llm_instance: Provider = None | ||
self.load_llm() | ||
|
||
self.message_handler = MessageHandler(self.context, self.command_manager, self.db_conn_helper, self.llm_instance) | ||
self.platfrom_manager = PlatformManager(self.context, self.message_handler) | ||
self.dashboard = AstrBotDashBoard(self.context, plugin_manager=self.plugin_manager, astrbot_updator=self.updator) | ||
self.metrics_uploader = MetricUploader(self.context) | ||
|
||
self.context.metrics_uploader = self.metrics_uploader | ||
self.context.updator = self.updator | ||
self.context.plugin_updator = self.plugin_manager.updator | ||
self.context.message_handler = self.message_handler | ||
|
||
# load plugins, plugins' commands. | ||
self.load_plugins() | ||
self.command_manager.register_from_pcb(self.context.plugin_command_bridge) | ||
|
||
# load platforms | ||
platform_tasks = self.load_platform() | ||
# load metrics uploader | ||
metrics_upload_task = asyncio.create_task(self.metrics_uploader.upload_metrics(), name="metrics-uploader") | ||
# load dashboard | ||
self.dashboard.run_http_server() | ||
dashboard_task = asyncio.create_task(self.dashboard.ws_server(), name="dashboard") | ||
tasks = [metrics_upload_task, dashboard_task, *platform_tasks, *self.context.ext_tasks] | ||
tasks = [self.handle_task(task) for task in tasks] | ||
await asyncio.gather(*tasks) | ||
|
||
async def handle_task(self, task: Union[asyncio.Task, asyncio.Future]): | ||
while True: | ||
try: | ||
result = await task | ||
return result | ||
except Exception as e: | ||
logger.error(traceback.format_exc()) | ||
logger.error(f"{task.get_name()} 任务发生错误,将在 5 秒后重试。") | ||
await asyncio.sleep(5) | ||
|
||
def load_llm(self): | ||
if 'openai' in self.configs and \ | ||
len(self.configs['openai']['key']) and \ | ||
self.configs['openai']['key'][0] is not None: | ||
from model.provider.openai_official import ProviderOpenAIOfficial | ||
from model.command.openai_official_handler import OpenAIOfficialCommandHandler | ||
self.openai_command_handler = OpenAIOfficialCommandHandler(self.command_manager) | ||
self.llm_instance = ProviderOpenAIOfficial(self.context) | ||
self.openai_command_handler.set_provider(self.llm_instance) | ||
logger.info("已启用 OpenAI API 支持。") | ||
|
||
def load_plugins(self): | ||
self.plugin_manager.plugin_reload() | ||
|
||
def load_platform(self): | ||
return self.platfrom_manager.load_platforms() |
Oops, something went wrong.