feat: 1. 增加可选插件仓库镜像配置;

2. 仪表盘更新;
This commit is contained in:
Soulter
2024-11-13 17:20:07 +08:00
parent f59de87a31
commit 4976e81ea4
31 changed files with 844 additions and 859 deletions
+1
View File
@@ -0,0 +1 @@
import{k as e,o as a,c as t,w as o,b as s,u as n,R as r,T as c}from"./index-3360c831.js";const f=e({__name:"BlankLayout",setup(u){return(p,_)=>(a(),t(r,null,{default:o(()=>[s(n(c))]),_:1}))}});export{f as default};
-1
View File
@@ -1 +0,0 @@
import{q as e,o as a,c as t,w as o,d as s,x as n,U as r,X as c}from"./index-a2f0b905.js";const f=e({__name:"BlankLayout",setup(p){return(u,_)=>(a(),t(r,null,{default:o(()=>[s(n(c))]),_:1}))}});export{f as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{_ as n}from"./_plugin-vue_export-helper-c27b6911.js";import{o as t,c as a,w as l,B as o,b as s,D as c,n as e}from"./index-3360c831.js";const r={},u=e("div",{style:{display:"flex","flex-direction":"column","justify-content":"center",padding:"24px"}},[e("h3",null,"即将支持。"),e("p",null,"AstrBot 将会支持使用消息记录微调 LLM,并强化人格功能,包括但不限于:"),e("ul",null,[e("li",null,"更像人类的回答"),e("li",null,"长期记忆"),e("li",null,"表情包理解与回复"),e("li",null,"基于兴趣的主动话题展开")])],-1);function i(d,_){return t(),a(o,null,{default:l(()=>[s(c,null,{default:l(()=>[u]),_:1})]),_:1})}const x=n(r,[["render",i]]);export{x as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{q as m,o as e,c as u,w as a,b as s,B as d,C as T,e as _,D as p,a5 as f,n as l,l as r,f as w,g as n,t as o,K as S}from"./index-3360c831.js";import{_ as g}from"./_plugin-vue_export-helper-c27b6911.js";const v={name:"WaitingForRestart",data(){return{visible:!1,startTime:-1,newStartTime:-1,status:"",cnt:0,intervalId:null}},methods:{async check(){this.newStartTime=-1,this.startTime=-1,this.visible=!0,this.status="",console.log("start wfr"),await this.getStartTime(),this.intervalId=setInterval(()=>{if(this.newStartTime===-1&&this.cnt<10&&this.visible)this.checkStartTime(),this.cnt++;else{this.cnt==10&&(this.status="拉取状态达到最大次数,请手动检查。"),this.cnt=0,setTimeout(()=>{this.visible=!1},1e3),clearInterval(this.intervalId);return}},1e3)},async getStartTime(){m.get("/api/stat/start-time").then(i=>{this.startTime=i.data.data.start_time})},async checkStartTime(){let i=await m.get("/api/stat/start-time");this.newStartTime=i.data.data.start_time,console.log("wfr: checkStartTime",this.newStartTime,this.startTime),this.newStartTime!==this.startTime&&(console.log("wfr: restarted"),setTimeout(()=>{this.visible=!1,window.location.reload()},2e3))}}},V={style:{"margin-top":"16px"}},k={key:0,class:"py-12 text-center"},y=l("p",null,"重启成功!",-1),x={key:1},b={key:2},B={key:3};function C(i,c,I,N,t,D){return e(),u(S,{modelValue:t.visible,"onUpdate:modelValue":c[0]||(c[0]=h=>t.visible=h),persistent:"","max-width":"400"},{default:a(()=>[s(d,null,{default:a(()=>[s(T,null,{default:a(()=>[_("正在等待 AstrBot 重启...")]),_:1}),s(p,null,{default:a(()=>[s(f,{indeterminate:"",color:"primary"}),l("div",V,[t.newStartTime!=-1?(e(),r("div",k,[s(w,{class:"mb-6",color:"success",icon:"mdi-check-circle-outline",size:"128"}),y])):n("",!0),t.startTime!=-1?(e(),r("p",x,"当前实例标识:"+o(t.startTime),1)):n("",!0),t.newStartTime!=-1?(e(),r("p",b,"检查到新实例:"+o(t.newStartTime)+",即将自动刷新页面",1)):n("",!0),t.status?(e(),r("p",B,o(t.status),1)):n("",!0),l("p",null,"次数:"+o(t.cnt),1)])]),_:1})]),_:1})]),_:1},8,["modelValue"])}const R=g(v,[["render",C]]);export{R as W};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -11,8 +11,8 @@
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap"
/>
<title>AstrBot - 仪表盘</title>
<script type="module" crossorigin src="/assets/index-a2f0b905.js"></script>
<link rel="stylesheet" href="/assets/index-86dd25ba.css">
<script type="module" crossorigin src="/assets/index-3360c831.js"></script>
<link rel="stylesheet" href="/assets/index-d7da5bd1.css">
</head>
<body>
<div id="app"></div>
+2
View File
@@ -14,6 +14,8 @@ class Broker:
await connection.send(message)
except Exception as e:
logger.warning(f"发送日志失败: {e.__str__()}")
connection.close()
del connection
class LogRoute:
+6
View File
@@ -11,6 +11,7 @@ class StatRoute(Route):
self.routes = {
'/stat/get': ('GET', self.get_stat),
'/stat/version': ('GET', self.get_version),
'/stat/start-time': ('GET', self.get_start_time)
}
self.db_helper = db_helper
self.register_routes()
@@ -24,6 +25,11 @@ class StatRoute(Route):
return Response().ok({
"version": VERSION
}).__dict__
async def get_start_time(self):
return Response().ok({
"start_time": self.context._start_running,
}).__dict__
async def get_stat(self):
offset_sec = request.args.get('offset_sec', 86400)
+3 -1
View File
@@ -21,6 +21,8 @@ def get_default_val_by_type(type_: str):
return False
elif type_ == "string":
return ""
elif type_ == "text":
return ""
elif type_ == "list":
return []
elif type_ == "object":
@@ -57,7 +59,7 @@ def validate_config(data, context: Context):
data[key] = casted
elif meta["type"] == "bool" and not isinstance(value, bool):
errors.append(f"错误的类型 {path}{key}: 期望是 bool, 得到了 {type(value).__name__}")
elif meta["type"] == "string" and not isinstance(value, str):
elif meta["type"] in ["string", "text"] and not isinstance(value, str):
errors.append(f"错误的类型 {path}{key}: 期望是 string, 得到了 {type(value).__name__}")
elif meta["type"] == "list" and not isinstance(value, list):
errors.append(f"错误的类型 {path}{key}: 期望是 list, 得到了 {type(value).__name__}")
+12 -61
View File
@@ -21,7 +21,7 @@ logger: Logger = LogManager.GetLogger(log_name='astrbot')
class PluginManager():
def __init__(self, context: Context):
self.updator = PluginUpdator()
self.updator = PluginUpdator(context.config_helper.plugin_repo_mirror)
self.plugin_store_path = self.updator.get_plugin_store_path()
self.context = context
@@ -80,75 +80,26 @@ class PluginManager():
plugin_path = os.path.join(plugin_dir, p)
if os.path.exists(os.path.join(plugin_path, "requirements.txt")):
pth = os.path.join(plugin_path, "requirements.txt")
logger.info(f"正在检查更新插件 {p} 的依赖: {pth}")
self.update_plugin_dept(os.path.join(plugin_path, "requirements.txt"))
logger.info(f"正在检查插件 {p} 的依赖: {pth}")
try:
self.update_plugin_dept(os.path.join(plugin_path, "requirements.txt"))
except Exception as e:
logger.error(f"更新插件 {p} 的依赖失败。Code: {str(e)}")
def update_plugin_dept(self, path):
pip_main(['install', '-r', path, '--trusted-host', 'mirrors.aliyun.com', '-i', 'https://mirrors.aliyun.com/pypi/simple/'])
# mirror = "https://mirrors.aliyun.com/pypi/simple/"
# py = sys.executable
# cmd = f"{py} -m pip install -r {path} -i {mirror} --trusted-host mirrors.aliyun.com"
# if break_system_package:
# cmd += " --break-system-package"
# process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True)
# while True:
# output = process.stdout.readline()
# err = process.stderr.readline()
# if err:
# err = err.strip()
# logger.error(err)
# if "no such option: --break-system-package" in err:
# self.update_plugin_dept(path, break_system_package=False)
# break
# if output == '' and process.poll() is not None:
# break
# if output:
# output = output.strip()
# if output.startswith("Requirement already satisfied"):
# continue
# if output.startswith("Using cached"):
# continue
# if output.startswith("Looking in indexes"):
# continue
# logger.info(output)
# rc = process.poll()
args = ['install', '-r', path, '--trusted-host', 'mirrors.aliyun.com', '-i', 'https://mirrors.aliyun.com/pypi/simple/', '--break-system-package']
if self.context.config_helper.pip_install_arg:
args.extend(self.context.config_helper.pip_install_arg)
result_code = pip_main(args)
if result_code != 0:
raise Exception(str(result_code))
async def install_plugin(self, repo_url: str):
ppath = self.plugin_store_path
# we no longer use Git anymore :)
# Repo.clone_from(repo_url, to_path=plugin_path, branch='master')
plugin_path = await self.updator.update(repo_url)
with open(os.path.join(plugin_path, "REPO"), "w", encoding='utf-8') as f:
f.write(repo_url)
# self.check_plugin_dept_update()
return plugin_path
# ok, err = self.plugin_reload()
# if not ok:
# raise Exception(err)
async def download_from_repo_url(self, target_path: str, repo_url: str):
repo_namespace = repo_url.split("/")[-2:]
author = repo_namespace[0]
repo = repo_namespace[1]
logger.info(f"正在下载插件 {repo} ...")
release_url = f"https://api.github.com/repos/{author}/{repo}/releases"
releases = await self.updator.fetch_release_info(url=release_url)
if not releases:
# download from the default branch directly.
logger.warn(f"未在插件 {author}/{repo} 中找到任何发布版本,将从默认分支下载。")
release_url = f"https://github.com/{author}/{repo}/archive/refs/heads/master.zip"
else:
release_url = releases[0]['zipball_url']
await download_file(release_url, target_path + ".zip")
def get_registered_plugin(self, plugin_name: str) -> RegisteredPlugin:
for p in self.context.cached_plugins:
+47 -41
View File
@@ -1,4 +1,4 @@
VERSION = '3.3.17'
VERSION = '3.3.19'
DB_PATH = 'data/data_v2.db'
# 新版本配置文件,摈弃旧版本令人困惑的配置项 :D
@@ -99,6 +99,8 @@ DEFAULT_CONFIG_VERSION_2 = {
},
"log_level": "INFO",
"t2i_endpoint": "",
"pip_install_arg": "",
"plugin_repo_mirror": "default",
}
# 这个是用于迁移旧版本配置文件的映射表
@@ -165,55 +167,57 @@ CONFIG_METADATA_2 = {
"description": "平台配置",
"type": "list",
"items": {
"name": {"description": "平台名称", "type": "string"},
"enable": {"description": "启用", "type": "bool"},
"appid": {"description": "appid", "type": "string"},
"secret": {"description": "secret", "type": "string"},
"enable_group_c2c": {"description": "启用消息列表单聊", "type": "bool"},
"enable_guild_direct_message": {"description": "启用频道私", "type": "bool"},
"host": {"description": "主机地址", "type": "string"},
"port": {"description": "端口", "type": "int"},
"websocket_port": {"description": "Websocket 端口", "type": "int"},
"ws_reverse_host": {"description": "反向 Websocket 主机地址", "type": "string"},
"ws_reverse_port": {"description": "反向 Websocket 端口", "type": "int"},
"enable_group": {"description": "接收群组消息", "type": "bool"},
"enable_guild": {"description": "接收频道消息", "type": "bool"},
"enable_direct_message": {"description": "接收频道私聊", "type": "bool"},
"enable_group_increase": {"description": "接收群组成员增加事件", "type": "bool"},
"id": {"description": "ID", "type": "string", "hint": "提供商 ID 名,用于在多实例下方便管理和识别。自定义,ID 不能重复。"},
"name": {"description": "适配器类型", "type": "string", "hint": "当前版本下,支持 `qq_official`QQ 官方机器人), `aiocqhttp`(Onebot 适用), `nakuru` 三种适配器类型。", "options": ["qq_official", "aiocqhttp", "nakuru"]},
"enable": {"description": "启用", "type": "bool", "hint": "是否启用该适配器。未启用的适配器对应的消息平台将不会接收到消息。"},
"appid": {"description": "appid", "type": "string", "hint": "必填项。QQ 官方机器人平台的 appid。如何获取请参考文档。"},
"secret": {"description": "secret", "type": "string", "hint": "必填项。QQ 官方机器人平台的 secret。如何获取请参考文档。"},
"enable_group_c2c": {"description": "启用消息列表单", "type": "bool", "hint": "启用后,机器人可以接收到 QQ 消息列表中的私聊消息。你可能需要在 QQ 机器人平台上通过扫描二维码的方式添加机器人为你的好友。详见文档。"},
"enable_guild_direct_message": {"description": "启用频道私聊", "type": "bool", "hint": "启用后,机器人可以接收到频道的私聊消息。"},
"host": {"description": "主机地址", "type": "string", "hint": "Nakuru 适配器的服务器 IP 地址,不包含端口号。"},
"port": {"description": "端口", "type": "int", "hint": "Nakuru 适配器的 HTTP 端口。"},
"websocket_port": {"description": "Websocket 端口", "type": "int", "hint": "Nakuru 适配器的 Websocket 端口。"},
"ws_reverse_host": {"description": "反向 Websocket 主机地址", "type": "string", "hint": "aiocqhttp 适配器的反向 Websocket 服务器 IP 地址,不包含端口号。"},
"ws_reverse_port": {"description": "反向 Websocket 端口", "type": "int", "hint": "aiocqhttp 适配器的反向 Websocket 端口。"},
"enable_group": {"description": "接收群组消息", "type": "bool", "hint": "启用后,机器人可以接收到群组消息。"},
"enable_guild": {"description": "接收频道消息", "type": "bool", "hint": "启用后,机器人可以接收到频道消息。"},
"enable_direct_message": {"description": "接收频道私聊", "type": "bool", "hint": "启用后,机器人可以接收到频道的私聊消息。"},
}
},
"platform_settings": {
"description": "平台设置",
"type": "object",
"items": {
"unique_session": {"description": "会话隔离到单个人", "type": "bool"},
"unique_session": {"description": "会话隔离", "type": "bool", "hint": "启用后,在群组或者频道中,每个人的消息上下文都是独立的。"},
"rate_limit": {
"description": "速率限制",
"hint": "每个会话在 `time` 秒内最多只能发送 `count` 条消息。",
"type": "object",
"items": {
"time": {"description": "消息速率限制时间", "type": "int"},
"count": {"description": "消息速率限制计数", "type": "int"},
}
},
"reply_prefix": {"description": "回复前缀", "type": "string"},
"forward_threshold": {"description": "转发消息的字数阈值", "type": "int"},
"reply_prefix": {"description": "回复前缀", "type": "string", "hint": "机器人回复消息时带有的前缀。"},
"forward_threshold": {"description": "转发消息的字数阈值", "type": "int", "hint": "超过一定字数后,机器人会将消息折叠成 QQ 群聊的 “转发消息”,以防止刷屏。目前仅 QQ 平台适配器适用。"},
}
},
"llm": {
"description": "大语言模型配置",
"type": "list",
"items": {
"name": {"description": "模型名称", "type": "string"},
"enable": {"description": "启用", "type": "bool"},
"key": {"description": "API Key", "type": "list", "items": {"type": "string"}},
"api_base": {"description": "API Base URL", "type": "string"},
"prompt_prefix": {"description": "Prompt 前缀", "type": "string"},
"default_personality": {"description": "默认人格", "type": "string"},
"id": {"description": "ID", "type": "string", "hint": "提供商 ID 名,用于在多实例下方便管理和识别。自定义,ID 不能重复。"},
"name": {"description": "模型提供商类型", "type": "string", "hint": "当前版本下,支持 `openai` 一个模型提供商。", "options": ["openai"]},
"enable": {"description": "启用", "type": "bool", "hint": "是否启用该模型。未启用的模型将不会被使用。"},
"key": {"description": "API Key", "type": "list", "items": {"type": "string"}, "hint": "API Key 列表。填写好后输入回车即可添加 API Key。支持多个 API Key。"},
"api_base": {"description": "API Base URL", "type": "string", "hint": "API Base URL 请在在模型提供商处获得。支持 Ollama 开放的 API 地址。如果您确认填写正确但是使用时出现了 404 异常,可以尝试在地址末尾加上 `/v1`。"},
"prompt_prefix": {"description": "Prompt 前缀", "type": "text", "hint": "每次与 LLM 对话时在对话前加上的自定义文本。默认为空。"},
"default_personality": {"description": "默认人格", "type": "text", "hint": "在当前版本下,默认人格文本会被添加到 LLM 对话的 `system` 字段中。"},
"model_config": {
"description": "模型配置",
"type": "object",
"items": {
"model": {"description": "模型名称", "type": "string"},
"model": {"description": "模型名称", "type": "string", "hint": "大语言模型的名称,一般是小写的英文。如 gpt-4o-mini, deepseek-chat 等。"},
"max_tokens": {"description": "最大令牌数", "type": "int"},
"temperature": {"description": "温度", "type": "float"},
"top_p": {"description": "Top P值", "type": "float"},
@@ -225,8 +229,8 @@ CONFIG_METADATA_2 = {
"description": "图像生成模型配置",
"type": "object",
"items": {
"enable": {"description": "启用(需要该提供商支持图像生成模型)", "type": "bool"},
"model": {"description": "模型名称", "type": "string"},
"enable": {"description": "启用", "type": "bool", "hint": "启用该功能需要提供商支持图像生成。如 dall-e-3"},
"model": {"description": "模型名称", "type": "string", "hint": "图像生成模型的名称,一般是小写的英文。如 dall-e-3"},
"size": {"description": "图像尺寸", "type": "string"},
"style": {"description": "图像风格", "type": "string"},
"quality": {"description": "图像质量", "type": "string"},
@@ -238,9 +242,9 @@ CONFIG_METADATA_2 = {
"description": "大语言模型设置",
"type": "object",
"items": {
"wake_prefix": {"description": "LLM 聊天额外唤醒前缀", "type": "string"},
"web_search": {"description": "启用网页搜索(能访问 Google 时效果最佳)", "type": "bool"},
"identifier": {"description": "启动识别群员(略微增加token开销)", "type": "bool"},
"wake_prefix": {"description": "LLM 聊天额外唤醒前缀", "type": "string", "hint": "使用 LLM 聊天额外的触发条件。如填写 `chat`,则需要消息前缀加上 `/chat` 才能触发 LLM 聊天,是一个防止滥用的手段。"},
"web_search": {"description": "启用网页搜索", "type": "bool", "hint": "能访问 Google 时效果最佳。如果 Google 访问失败,程序会依次访问 Bing, Sogo 搜索引擎。"},
"identifier": {"description": "启动识别群员", "type": "bool", "hint": "在 Prompt 前加上群成员的名字以让模型更好地了解群聊状态。启用将略微增加 token 开销,"},
}
},
"content_safety": {
@@ -251,7 +255,7 @@ CONFIG_METADATA_2 = {
"description": "百度内容审核配置",
"type": "object",
"items": {
"enable": {"description": "启用百度内容审核(需手动安装 baidu-aip 库)", "type": "bool"},
"enable": {"description": "启用百度内容审核", "type": "bool", "hint": "启用此功能前,您需要手动在设备中安装 baidu-aip 库。一般来说,安装指令如下: `pip3 install baidu-aip`"},
"app_id": {"description": "APP ID", "type": "string"},
"api_key": {"description": "API Key", "type": "string"},
"secret_key": {"description": "Secret Key", "type": "string"},
@@ -262,17 +266,17 @@ CONFIG_METADATA_2 = {
"type": "object",
"items": {
"enable": {"description": "启用内部关键词过滤", "type": "bool"},
"extra_keywords": {"description": "额外关键词(支持正则)", "type": "list", "items": {"type": "string"}},
"extra_keywords": {"description": "额外关键词", "type": "list", "items": {"type": "string"}, "hint": "额外的屏蔽关键词列表,支持正则表达式。"},
}
}
}
},
"wake_prefix": {"description": "唤醒前缀列表", "type": "list", "items": {"type": "string"}},
"t2i": {"description": "文本转图像功能", "type": "bool"},
"dump_history_interval": {"description": "历史记录转储间隔", "type": "int"},
"admins_id": {"description": "管理员ID列表", "type": "list", "items": {"type": "int"}},
"https_proxy": {"description": "HTTPS代理", "type": "string"},
"http_proxy": {"description": "HTTP代理", "type": "string"},
"wake_prefix": {"description": "机器人唤醒前缀", "type": "list", "items": {"type": "string"}, "hint": "在不 @ 机器人的情况下,可以通过外加消息前缀来唤醒机器人。"},
"t2i": {"description": "文本转图像", "type": "bool", "hint": "启用后,超出一定长度的文本将会通过 AstrBot API 渲染成 Markdown 图片发送。可以缓解审核和消息过长刷屏的问题,并提高 Markdown 文本的可读性。"},
"dump_history_interval": {"description": "历史记录保存间隔", "type": "int", "hint": "每隔多少分钟将 LLM 聊天的历史记录转储到数据库。"},
"admins_id": {"description": "管理员 ID", "type": "list", "items": {"type": "int"}, "hint": "管理员 ID 列表,管理员可以使用一些特权命令,如 `update`, `plugin` 等。ID 可以通过 `/myid` 指令获得。回车添加,可添加多个。"},
"https_proxy": {"description": "HTTPS 代理", "type": "string", "hint": "启用后,会以添加环境变量的方式设置代理。格式为 `http://ip:port`"},
"http_proxy": {"description": "HTTP 代理", "type": "string", "hint": "启用后,会以添加环境变量的方式设置代理。格式为 `http://ip:port`"},
"dashboard": {
"description": "仪表盘配置",
"type": "object",
@@ -282,6 +286,8 @@ CONFIG_METADATA_2 = {
"password": {"description": "密码", "type": "string"},
}
},
"log_level": {"description": "控制台日志级别(DEBUG, INFO, WARNING, ERROR)", "type": "string"},
"t2i_endpoint": {"description": "文本转图像服务接口(为空时使用公共服务器)", "type": "string"},
"log_level": {"description": "控制台日志级别", "type": "string", "hint": "控制台输出日志的级别。", "options": ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]},
"t2i_endpoint": {"description": "文本转图像服务接口", "type": "string", "hint": "为空时使用 AstrBot API 服务"},
"pip_install_arg": {"description": "pip 安装参数", "type": "string", "hint": "安装插件依赖时,会使用 Python 的 pip 工具。这里可以填写额外的参数,如 `--break-system-package` 等。"},
"plugin_repo_mirror": {"description": "插件仓库镜像", "type": "string", "hint": "插件仓库的镜像地址,用于加速插件的下载。", "options": ["default", "https://github-mirror.us.kg/"]},
}
-9
View File
@@ -30,12 +30,6 @@ class Context:
self.llms: List[RegisteredLLM] = []
self.default_personality: dict = None
# self.unique_session = False # 独立会话
# self.version: str = None # 机器人版本
# self.nick: tuple = None # gocq 的唤醒词
# self.t2i_mode = False
# self.web_search = False # 是否开启了网页搜索
self.metrics_uploader = None
self.updator: AstrBotUpdator = None
self.plugin_updator: PluginUpdator = None
@@ -53,9 +47,6 @@ class Context:
self._log_queue = CachedQueue()
# useless
# self.reply_prefix = ""
def register_commands(self,
plugin_name: str,
command_name: str,
+5
View File
@@ -136,6 +136,8 @@ class AstrBotConfig():
wake_prefix: List[str] = field(default_factory=list)
log_level: str = "INFO"
t2i_endpoint: str = ""
pip_install_arg: str = ""
plugin_repo_mirror: str = ""
def __init__(self) -> None:
self.init_configs()
@@ -179,6 +181,9 @@ class AstrBotConfig():
self.wake_prefix=data.get("wake_prefix", ["/"])
self.log_level=data.get("log_level", "INFO")
self.t2i_endpoint=data.get("t2i_endpoint", "")
self.pip_install_arg=data.get("pip_install_arg", "")
self.plugin_repo_mirror=data.get("plugin_repo_mirror", "")
def migrate_config_1_2(self, old: dict) -> dict:
'''将配置文件从版本 1 迁移至版本 2'''
+2 -1
View File
@@ -8,7 +8,8 @@ from util.io import on_error, download_file
logger: Logger = LogManager.GetLogger(log_name='astrbot')
class AstrBotUpdator(RepoZipUpdator):
def __init__(self):
def __init__(self, repo_mirror: str = "") -> None:
super().__init__(repo_mirror)
self.MAIN_PATH = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
self.ASTRBOT_RELEASE_API = "https://api.github.com/repos/Soulter/AstrBot/releases"
+2 -1
View File
@@ -12,7 +12,8 @@ logger: Logger = LogManager.GetLogger(log_name='astrbot')
class PluginUpdator(RepoZipUpdator):
def __init__(self) -> None:
def __init__(self, repo_mirror: str = "") -> None:
super().__init__(repo_mirror)
self.plugin_store_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../data/plugins"))
def get_plugin_store_path(self) -> str:
+11 -4
View File
@@ -19,8 +19,8 @@ class ReleaseInfo():
return f"新版本: {self.version}, 发布于: {self.published_at}, 详细内容: {self.body}"
class RepoZipUpdator():
def __init__(self, path):
self.path = path
def __init__(self, repo_mirror: str = "") -> None:
self.repo_mirror = repo_mirror
self.rm_on_error = on_error
async def fetch_release_info(self, url: str, latest: bool = True) -> list:
@@ -38,8 +38,8 @@ class RepoZipUpdator():
else:
ret = self.github_api_release_parser(result)
except BaseException as e:
logger.error(f"解析版本信息失败: {result}")
raise Exception(f"解析版本信息失败: {result}")
logger.error(f"解析版本信息失败")
raise Exception(f"解析版本信息失败")
return ret
def github_api_release_parser(self, releases: list) -> list:
@@ -113,6 +113,13 @@ class RepoZipUpdator():
release_url = f"https://github.com/{author}/{repo}/archive/refs/heads/master.zip"
else:
release_url = releases[0]['zipball_url']
# 镜像站点
if self.repo_mirror:
if self.repo_mirror == 'default':
pass
elif self.repo_mirror == 'https://github-mirror.us.kg/':
release_url = self.repo_mirror + release_url
await download_file(release_url, target_path + ".zip")