AstrBot 4.0.0b4__py3-none-any.whl → 4.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- astrbot/api/event/filter/__init__.py +2 -0
- astrbot/cli/utils/basic.py +12 -3
- astrbot/core/astrbot_config_mgr.py +16 -9
- astrbot/core/config/default.py +82 -4
- astrbot/core/initial_loader.py +4 -1
- astrbot/core/message/components.py +59 -50
- astrbot/core/pipeline/process_stage/method/llm_request.py +6 -2
- astrbot/core/pipeline/result_decorate/stage.py +5 -1
- astrbot/core/platform/manager.py +25 -3
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +26 -14
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +11 -4
- astrbot/core/platform/sources/satori/satori_adapter.py +482 -0
- astrbot/core/platform/sources/satori/satori_event.py +221 -0
- astrbot/core/platform/sources/telegram/tg_adapter.py +0 -1
- astrbot/core/provider/entities.py +17 -15
- astrbot/core/provider/sources/gemini_source.py +57 -18
- astrbot/core/provider/sources/openai_source.py +12 -5
- astrbot/core/provider/sources/vllm_rerank_source.py +6 -0
- astrbot/core/star/__init__.py +7 -5
- astrbot/core/star/filter/command.py +9 -3
- astrbot/core/star/filter/platform_adapter_type.py +3 -0
- astrbot/core/star/register/__init__.py +2 -0
- astrbot/core/star/register/star_handler.py +18 -4
- astrbot/core/star/star_handler.py +9 -1
- astrbot/core/star/star_tools.py +116 -21
- astrbot/core/updator.py +7 -5
- astrbot/core/utils/io.py +1 -1
- astrbot/core/utils/t2i/network_strategy.py +11 -18
- astrbot/core/utils/t2i/renderer.py +8 -2
- astrbot/core/utils/t2i/template/astrbot_powershell.html +184 -0
- astrbot/core/utils/t2i/template_manager.py +112 -0
- astrbot/core/zip_updator.py +26 -4
- astrbot/dashboard/routes/chat.py +6 -1
- astrbot/dashboard/routes/config.py +24 -49
- astrbot/dashboard/routes/route.py +19 -2
- astrbot/dashboard/routes/t2i.py +230 -0
- astrbot/dashboard/routes/update.py +3 -5
- astrbot/dashboard/server.py +13 -4
- {astrbot-4.0.0b4.dist-info → astrbot-4.1.0.dist-info}/METADATA +40 -53
- {astrbot-4.0.0b4.dist-info → astrbot-4.1.0.dist-info}/RECORD +43 -38
- {astrbot-4.0.0b4.dist-info → astrbot-4.1.0.dist-info}/WHEEL +0 -0
- {astrbot-4.0.0b4.dist-info → astrbot-4.1.0.dist-info}/entry_points.txt +0 -0
- {astrbot-4.0.0b4.dist-info → astrbot-4.1.0.dist-info}/licenses/LICENSE +0 -0
astrbot/core/zip_updator.py
CHANGED
|
@@ -107,16 +107,38 @@ class RepoZipUpdator:
|
|
|
107
107
|
"""Semver 版本比较"""
|
|
108
108
|
return VersionComparator.compare_version(v1, v2)
|
|
109
109
|
|
|
110
|
-
async def check_update(
|
|
110
|
+
async def check_update(
|
|
111
|
+
self, url: str, current_version: str, consider_prerelease: bool = True
|
|
112
|
+
) -> ReleaseInfo | None:
|
|
111
113
|
update_data = await self.fetch_release_info(url)
|
|
112
|
-
|
|
114
|
+
|
|
115
|
+
sel_release_data = None
|
|
116
|
+
if consider_prerelease:
|
|
117
|
+
tag_name = update_data[0]["tag_name"]
|
|
118
|
+
sel_release_data = update_data[0]
|
|
119
|
+
else:
|
|
120
|
+
for data in update_data:
|
|
121
|
+
# 跳过带有 alpha、beta 等预发布标签的版本
|
|
122
|
+
if re.search(
|
|
123
|
+
r"[\-_.]?(alpha|beta|rc|dev)[\-_.]?\d*$",
|
|
124
|
+
data["tag_name"],
|
|
125
|
+
re.IGNORECASE,
|
|
126
|
+
):
|
|
127
|
+
continue
|
|
128
|
+
tag_name = data["tag_name"]
|
|
129
|
+
sel_release_data = data
|
|
130
|
+
break
|
|
131
|
+
|
|
132
|
+
if not sel_release_data or not tag_name:
|
|
133
|
+
logger.error("未找到合适的发布版本")
|
|
134
|
+
return None
|
|
113
135
|
|
|
114
136
|
if self.compare_version(current_version, tag_name) >= 0:
|
|
115
137
|
return None
|
|
116
138
|
return ReleaseInfo(
|
|
117
139
|
version=tag_name,
|
|
118
|
-
published_at=
|
|
119
|
-
body=
|
|
140
|
+
published_at=sel_release_data["published_at"],
|
|
141
|
+
body=f"{tag_name}\n\n{sel_release_data['body']}",
|
|
120
142
|
)
|
|
121
143
|
|
|
122
144
|
async def download_from_repo_url(self, target_path: str, repo_url: str, proxy=""):
|
astrbot/dashboard/routes/chat.py
CHANGED
|
@@ -157,7 +157,11 @@ class ChatRoute(Route):
|
|
|
157
157
|
|
|
158
158
|
if type == "end":
|
|
159
159
|
break
|
|
160
|
-
elif (
|
|
160
|
+
elif (
|
|
161
|
+
(streaming and type == "complete")
|
|
162
|
+
or not streaming
|
|
163
|
+
or type == "break"
|
|
164
|
+
):
|
|
161
165
|
# append bot message
|
|
162
166
|
new_his = {"type": "bot", "message": result_text}
|
|
163
167
|
await self.platform_history_mgr.insert(
|
|
@@ -197,6 +201,7 @@ class ChatRoute(Route):
|
|
|
197
201
|
"Connection": "keep-alive",
|
|
198
202
|
},
|
|
199
203
|
)
|
|
204
|
+
response.timeout = None # fix SSE auto disconnect issue
|
|
200
205
|
return response
|
|
201
206
|
|
|
202
207
|
async def _get_webchat_conv_id_from_conv_id(self, conversation_id: str) -> str:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
import traceback
|
|
3
3
|
import os
|
|
4
|
+
import copy
|
|
4
5
|
from .route import Route, Response, RouteContext
|
|
5
6
|
from astrbot.core.provider.entities import ProviderType
|
|
6
7
|
from quart import request
|
|
@@ -16,10 +17,10 @@ from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
|
|
|
16
17
|
from astrbot.core.platform.register import platform_registry
|
|
17
18
|
from astrbot.core.provider.register import provider_registry
|
|
18
19
|
from astrbot.core.star.star import star_registry
|
|
19
|
-
from astrbot.core import logger
|
|
20
|
+
from astrbot.core import logger
|
|
20
21
|
from astrbot.core.provider import Provider
|
|
22
|
+
from astrbot.core.provider.provider import RerankProvider
|
|
21
23
|
import asyncio
|
|
22
|
-
from astrbot.core.utils.t2i.network_strategy import CUSTOM_T2I_TEMPLATE_PATH
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def try_cast(value: str, type_: str):
|
|
@@ -155,6 +156,7 @@ def save_config(post_config: dict, config: AstrBotConfig, is_core: bool = False)
|
|
|
155
156
|
raise ValueError(f"验证配置时出现异常: {e}")
|
|
156
157
|
if errors:
|
|
157
158
|
raise ValueError(f"格式校验未通过: {errors}")
|
|
159
|
+
|
|
158
160
|
config.save_config(post_config)
|
|
159
161
|
|
|
160
162
|
|
|
@@ -185,56 +187,9 @@ class ConfigRoute(Route):
|
|
|
185
187
|
"/config/provider/check_one": ("GET", self.check_one_provider_status),
|
|
186
188
|
"/config/provider/list": ("GET", self.get_provider_config_list),
|
|
187
189
|
"/config/provider/model_list": ("GET", self.get_provider_model_list),
|
|
188
|
-
"/config/astrbot/t2i-template/get": ("GET", self.get_t2i_template),
|
|
189
|
-
"/config/astrbot/t2i-template/save": ("POST", self.post_t2i_template),
|
|
190
|
-
"/config/astrbot/t2i-template/delete": ("DELETE", self.delete_t2i_template),
|
|
191
190
|
}
|
|
192
191
|
self.register_routes()
|
|
193
192
|
|
|
194
|
-
async def get_t2i_template(self):
|
|
195
|
-
"""获取 T2I 模板"""
|
|
196
|
-
try:
|
|
197
|
-
template = await html_renderer.network_strategy.get_template()
|
|
198
|
-
has_custom_template = os.path.exists(CUSTOM_T2I_TEMPLATE_PATH)
|
|
199
|
-
return (
|
|
200
|
-
Response()
|
|
201
|
-
.ok({"template": template, "has_custom_template": has_custom_template})
|
|
202
|
-
.__dict__
|
|
203
|
-
)
|
|
204
|
-
except Exception as e:
|
|
205
|
-
logger.error(traceback.format_exc())
|
|
206
|
-
return Response().error(f"获取模板失败: {str(e)}").__dict__
|
|
207
|
-
|
|
208
|
-
async def post_t2i_template(self):
|
|
209
|
-
"""保存 T2I 模板"""
|
|
210
|
-
try:
|
|
211
|
-
post_data = await request.json
|
|
212
|
-
if not post_data or "template" not in post_data:
|
|
213
|
-
return Response().error("缺少模板内容").__dict__
|
|
214
|
-
|
|
215
|
-
template_content = post_data["template"]
|
|
216
|
-
|
|
217
|
-
# 保存自定义模板到文件
|
|
218
|
-
with open(CUSTOM_T2I_TEMPLATE_PATH, "w", encoding="utf-8") as f:
|
|
219
|
-
f.write(template_content)
|
|
220
|
-
|
|
221
|
-
return Response().ok(message="模板保存成功").__dict__
|
|
222
|
-
except Exception as e:
|
|
223
|
-
logger.error(traceback.format_exc())
|
|
224
|
-
return Response().error(f"保存模板失败: {str(e)}").__dict__
|
|
225
|
-
|
|
226
|
-
async def delete_t2i_template(self):
|
|
227
|
-
"""删除自定义 T2I 模板,恢复默认模板"""
|
|
228
|
-
try:
|
|
229
|
-
if os.path.exists(CUSTOM_T2I_TEMPLATE_PATH):
|
|
230
|
-
os.remove(CUSTOM_T2I_TEMPLATE_PATH)
|
|
231
|
-
return Response().ok(message="已恢复默认模板").__dict__
|
|
232
|
-
else:
|
|
233
|
-
return Response().ok(message="未找到自定义模板文件").__dict__
|
|
234
|
-
except Exception as e:
|
|
235
|
-
logger.error(traceback.format_exc())
|
|
236
|
-
return Response().error(f"删除模板失败: {str(e)}").__dict__
|
|
237
|
-
|
|
238
193
|
async def get_abconf_list(self):
|
|
239
194
|
"""获取所有 AstrBot 配置文件的列表"""
|
|
240
195
|
abconf_list = self.acm.get_conf_list()
|
|
@@ -481,6 +436,19 @@ class ConfigRoute(Route):
|
|
|
481
436
|
)
|
|
482
437
|
status_info["status"] = "unavailable"
|
|
483
438
|
status_info["error"] = f"STT test failed: {str(e)}"
|
|
439
|
+
elif provider_capability_type == ProviderType.RERANK:
|
|
440
|
+
try:
|
|
441
|
+
assert isinstance(provider, RerankProvider)
|
|
442
|
+
await provider.rerank("Apple", documents=["apple", "banana"])
|
|
443
|
+
status_info["status"] = "available"
|
|
444
|
+
except Exception as e:
|
|
445
|
+
logger.error(
|
|
446
|
+
f"Error testing rerank provider {provider_name}: {e}",
|
|
447
|
+
exc_info=True,
|
|
448
|
+
)
|
|
449
|
+
status_info["status"] = "unavailable"
|
|
450
|
+
status_info["error"] = f"Rerank test failed: {str(e)}"
|
|
451
|
+
|
|
484
452
|
else:
|
|
485
453
|
logger.debug(
|
|
486
454
|
f"Provider {provider_name} is not a Chat Completion or Embedding provider. Marking as available without test. Meta: {meta}"
|
|
@@ -752,6 +720,13 @@ class ConfigRoute(Route):
|
|
|
752
720
|
if conf_id not in self.acm.confs:
|
|
753
721
|
raise ValueError(f"配置文件 {conf_id} 不存在")
|
|
754
722
|
astrbot_config = self.acm.confs[conf_id]
|
|
723
|
+
|
|
724
|
+
# 保留服务端的 t2i_active_template 值
|
|
725
|
+
if "t2i_active_template" in astrbot_config:
|
|
726
|
+
post_configs["t2i_active_template"] = astrbot_config[
|
|
727
|
+
"t2i_active_template"
|
|
728
|
+
]
|
|
729
|
+
|
|
755
730
|
save_config(post_configs, astrbot_config, is_core=True)
|
|
756
731
|
except Exception as e:
|
|
757
732
|
raise e
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from astrbot.core import logger
|
|
1
2
|
from astrbot.core.config.astrbot_config import AstrBotConfig
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from quart import Quart
|
|
@@ -15,8 +16,24 @@ class Route:
|
|
|
15
16
|
self.config = context.config
|
|
16
17
|
|
|
17
18
|
def register_routes(self):
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
def _add_rule(path, method, func):
|
|
20
|
+
# 统一添加 /api 前缀
|
|
21
|
+
full_path = f"/api{path}"
|
|
22
|
+
self.app.add_url_rule(full_path, view_func=func, methods=[method])
|
|
23
|
+
|
|
24
|
+
# 兼容字典和列表两种格式
|
|
25
|
+
routes_to_register = (
|
|
26
|
+
self.routes.items() if isinstance(self.routes, dict) else self.routes
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
for route, definition in routes_to_register:
|
|
30
|
+
# 兼容一个路由多个方法
|
|
31
|
+
if isinstance(definition, list):
|
|
32
|
+
for method, func in definition:
|
|
33
|
+
_add_rule(route, method, func)
|
|
34
|
+
else:
|
|
35
|
+
method, func = definition
|
|
36
|
+
_add_rule(route, method, func)
|
|
20
37
|
|
|
21
38
|
|
|
22
39
|
@dataclass
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# astrbot/dashboard/routes/t2i.py
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict
|
|
4
|
+
from quart import jsonify, request
|
|
5
|
+
|
|
6
|
+
from astrbot.core import logger
|
|
7
|
+
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
|
|
8
|
+
from astrbot.core.utils.t2i.template_manager import TemplateManager
|
|
9
|
+
from .route import Response, Route, RouteContext
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class T2iRoute(Route):
|
|
13
|
+
def __init__(self, context: RouteContext, core_lifecycle: AstrBotCoreLifecycle):
|
|
14
|
+
super().__init__(context)
|
|
15
|
+
self.core_lifecycle = core_lifecycle
|
|
16
|
+
self.config = core_lifecycle.astrbot_config
|
|
17
|
+
self.manager = TemplateManager()
|
|
18
|
+
# 使用列表保证路由注册顺序,避免 /<name> 路由优先匹配 /reset_default
|
|
19
|
+
self.routes = [
|
|
20
|
+
("/t2i/templates", ("GET", self.list_templates)),
|
|
21
|
+
("/t2i/templates/active", ("GET", self.get_active_template)),
|
|
22
|
+
("/t2i/templates/create", ("POST", self.create_template)),
|
|
23
|
+
("/t2i/templates/reset_default", ("POST", self.reset_default_template)),
|
|
24
|
+
("/t2i/templates/set_active", ("POST", self.set_active_template)),
|
|
25
|
+
# 动态路由应该在静态路由之后注册
|
|
26
|
+
(
|
|
27
|
+
"/t2i/templates/<name>",
|
|
28
|
+
[
|
|
29
|
+
("GET", self.get_template),
|
|
30
|
+
("PUT", self.update_template),
|
|
31
|
+
("DELETE", self.delete_template),
|
|
32
|
+
],
|
|
33
|
+
),
|
|
34
|
+
]
|
|
35
|
+
self.register_routes()
|
|
36
|
+
|
|
37
|
+
async def list_templates(self):
|
|
38
|
+
"""获取所有T2I模板列表"""
|
|
39
|
+
try:
|
|
40
|
+
templates = self.manager.list_templates()
|
|
41
|
+
return jsonify(asdict(Response().ok(data=templates)))
|
|
42
|
+
except Exception as e:
|
|
43
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
44
|
+
response.status_code = 500
|
|
45
|
+
return response
|
|
46
|
+
|
|
47
|
+
async def get_active_template(self):
|
|
48
|
+
"""获取当前激活的T2I模板"""
|
|
49
|
+
try:
|
|
50
|
+
active_template = self.config.get("t2i_active_template", "base")
|
|
51
|
+
return jsonify(
|
|
52
|
+
asdict(Response().ok(data={"active_template": active_template}))
|
|
53
|
+
)
|
|
54
|
+
except Exception as e:
|
|
55
|
+
logger.error("Error in get_active_template", exc_info=True)
|
|
56
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
57
|
+
response.status_code = 500
|
|
58
|
+
return response
|
|
59
|
+
|
|
60
|
+
async def get_template(self, name: str):
|
|
61
|
+
"""获取指定名称的T2I模板内容"""
|
|
62
|
+
try:
|
|
63
|
+
content = self.manager.get_template(name)
|
|
64
|
+
return jsonify(
|
|
65
|
+
asdict(Response().ok(data={"name": name, "content": content}))
|
|
66
|
+
)
|
|
67
|
+
except FileNotFoundError:
|
|
68
|
+
response = jsonify(asdict(Response().error("Template not found")))
|
|
69
|
+
response.status_code = 404
|
|
70
|
+
return response
|
|
71
|
+
except Exception as e:
|
|
72
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
73
|
+
response.status_code = 500
|
|
74
|
+
return response
|
|
75
|
+
|
|
76
|
+
async def create_template(self):
|
|
77
|
+
"""创建一个新的T2I模板"""
|
|
78
|
+
try:
|
|
79
|
+
data = await request.json
|
|
80
|
+
name = data.get("name")
|
|
81
|
+
content = data.get("content")
|
|
82
|
+
if not name or not content:
|
|
83
|
+
response = jsonify(
|
|
84
|
+
asdict(Response().error("Name and content are required."))
|
|
85
|
+
)
|
|
86
|
+
response.status_code = 400
|
|
87
|
+
return response
|
|
88
|
+
name = name.strip()
|
|
89
|
+
|
|
90
|
+
self.manager.create_template(name, content)
|
|
91
|
+
response = jsonify(
|
|
92
|
+
asdict(
|
|
93
|
+
Response().ok(
|
|
94
|
+
data={"name": name}, message="Template created successfully."
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
response.status_code = 201
|
|
99
|
+
return response
|
|
100
|
+
except FileExistsError:
|
|
101
|
+
response = jsonify(
|
|
102
|
+
asdict(Response().error("Template with this name already exists."))
|
|
103
|
+
)
|
|
104
|
+
response.status_code = 409
|
|
105
|
+
return response
|
|
106
|
+
except ValueError as e:
|
|
107
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
108
|
+
response.status_code = 400
|
|
109
|
+
return response
|
|
110
|
+
except Exception as e:
|
|
111
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
112
|
+
response.status_code = 500
|
|
113
|
+
return response
|
|
114
|
+
|
|
115
|
+
async def update_template(self, name: str):
|
|
116
|
+
"""更新一个已存在的T2I模板"""
|
|
117
|
+
try:
|
|
118
|
+
name = name.strip()
|
|
119
|
+
data = await request.json
|
|
120
|
+
content = data.get("content")
|
|
121
|
+
if content is None:
|
|
122
|
+
response = jsonify(asdict(Response().error("Content is required.")))
|
|
123
|
+
response.status_code = 400
|
|
124
|
+
return response
|
|
125
|
+
|
|
126
|
+
self.manager.update_template(name, content)
|
|
127
|
+
|
|
128
|
+
# 检查更新的是否为当前激活的模板,如果是,则热重载
|
|
129
|
+
active_template = self.config.get("t2i_active_template", "base")
|
|
130
|
+
if name == active_template:
|
|
131
|
+
await self.core_lifecycle.reload_pipeline_scheduler("default")
|
|
132
|
+
message = f"模板 '{name}' 已更新并重新加载。"
|
|
133
|
+
else:
|
|
134
|
+
message = f"模板 '{name}' 已更新。"
|
|
135
|
+
|
|
136
|
+
return jsonify(asdict(Response().ok(data={"name": name}, message=message)))
|
|
137
|
+
except ValueError as e:
|
|
138
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
139
|
+
response.status_code = 400
|
|
140
|
+
return response
|
|
141
|
+
except Exception as e:
|
|
142
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
143
|
+
response.status_code = 500
|
|
144
|
+
return response
|
|
145
|
+
|
|
146
|
+
async def delete_template(self, name: str):
|
|
147
|
+
"""删除一个T2I模板"""
|
|
148
|
+
try:
|
|
149
|
+
name = name.strip()
|
|
150
|
+
self.manager.delete_template(name)
|
|
151
|
+
return jsonify(
|
|
152
|
+
asdict(Response().ok(message="Template deleted successfully."))
|
|
153
|
+
)
|
|
154
|
+
except FileNotFoundError:
|
|
155
|
+
response = jsonify(asdict(Response().error("Template not found.")))
|
|
156
|
+
response.status_code = 404
|
|
157
|
+
return response
|
|
158
|
+
except ValueError as e:
|
|
159
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
160
|
+
response.status_code = 400
|
|
161
|
+
return response
|
|
162
|
+
except Exception as e:
|
|
163
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
164
|
+
response.status_code = 500
|
|
165
|
+
return response
|
|
166
|
+
|
|
167
|
+
async def set_active_template(self):
|
|
168
|
+
"""设置当前活动的T2I模板"""
|
|
169
|
+
try:
|
|
170
|
+
data = await request.json
|
|
171
|
+
name = data.get("name")
|
|
172
|
+
if not name:
|
|
173
|
+
response = jsonify(asdict(Response().error("模板名称(name)不能为空。")))
|
|
174
|
+
response.status_code = 400
|
|
175
|
+
return response
|
|
176
|
+
|
|
177
|
+
# 验证模板文件是否存在
|
|
178
|
+
self.manager.get_template(name)
|
|
179
|
+
|
|
180
|
+
# 更新配置
|
|
181
|
+
config = self.config
|
|
182
|
+
config["t2i_active_template"] = name
|
|
183
|
+
config.save_config(config)
|
|
184
|
+
|
|
185
|
+
# 热重载以应用更改
|
|
186
|
+
await self.core_lifecycle.reload_pipeline_scheduler("default")
|
|
187
|
+
|
|
188
|
+
return jsonify(asdict(Response().ok(message=f"模板 '{name}' 已成功应用。")))
|
|
189
|
+
|
|
190
|
+
except FileNotFoundError:
|
|
191
|
+
response = jsonify(
|
|
192
|
+
asdict(Response().error(f"模板 '{name}' 不存在,无法应用。"))
|
|
193
|
+
)
|
|
194
|
+
response.status_code = 404
|
|
195
|
+
return response
|
|
196
|
+
except Exception as e:
|
|
197
|
+
logger.error("Error in set_active_template", exc_info=True)
|
|
198
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
199
|
+
response.status_code = 500
|
|
200
|
+
return response
|
|
201
|
+
|
|
202
|
+
async def reset_default_template(self):
|
|
203
|
+
"""重置默认的'base'模板"""
|
|
204
|
+
try:
|
|
205
|
+
self.manager.reset_default_template()
|
|
206
|
+
|
|
207
|
+
# 更新配置,将激活模板也重置为'base'
|
|
208
|
+
config = self.config
|
|
209
|
+
config["t2i_active_template"] = "base"
|
|
210
|
+
config.save_config(config)
|
|
211
|
+
|
|
212
|
+
# 热重载以应用更改
|
|
213
|
+
await self.core_lifecycle.reload_pipeline_scheduler("default")
|
|
214
|
+
|
|
215
|
+
return jsonify(
|
|
216
|
+
asdict(
|
|
217
|
+
Response().ok(
|
|
218
|
+
message="Default template has been reset and activated."
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
except FileNotFoundError as e:
|
|
223
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
224
|
+
response.status_code = 404
|
|
225
|
+
return response
|
|
226
|
+
except Exception as e:
|
|
227
|
+
logger.error("Error in reset_default_template", exc_info=True)
|
|
228
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
229
|
+
response.status_code = 500
|
|
230
|
+
return response
|
|
@@ -57,7 +57,7 @@ class UpdateRoute(Route):
|
|
|
57
57
|
.__dict__
|
|
58
58
|
)
|
|
59
59
|
else:
|
|
60
|
-
ret = await self.astrbot_updator.check_update(None, None)
|
|
60
|
+
ret = await self.astrbot_updator.check_update(None, None, False)
|
|
61
61
|
return Response(
|
|
62
62
|
status="success",
|
|
63
63
|
message=str(ret) if ret is not None else "已经是最新版本了。",
|
|
@@ -100,9 +100,7 @@ class UpdateRoute(Route):
|
|
|
100
100
|
)
|
|
101
101
|
|
|
102
102
|
try:
|
|
103
|
-
await download_dashboard(
|
|
104
|
-
latest=latest, version=version, proxy=proxy
|
|
105
|
-
)
|
|
103
|
+
await download_dashboard(latest=latest, version=version, proxy=proxy)
|
|
106
104
|
except Exception as e:
|
|
107
105
|
logger.error(f"下载管理面板文件失败: {e}。")
|
|
108
106
|
|
|
@@ -133,7 +131,7 @@ class UpdateRoute(Route):
|
|
|
133
131
|
async def update_dashboard(self):
|
|
134
132
|
try:
|
|
135
133
|
try:
|
|
136
|
-
await download_dashboard()
|
|
134
|
+
await download_dashboard(version=f"v{VERSION}", latest=False)
|
|
137
135
|
except Exception as e:
|
|
138
136
|
logger.error(f"下载管理面板文件失败: {e}。")
|
|
139
137
|
return Response().error(f"下载管理面板文件失败: {e}").__dict__
|
astrbot/dashboard/server.py
CHANGED
|
@@ -18,6 +18,7 @@ from astrbot.core.utils.io import get_local_ip_addresses
|
|
|
18
18
|
from .routes import *
|
|
19
19
|
from .routes.route import Response, RouteContext
|
|
20
20
|
from .routes.session_management import SessionManagementRoute
|
|
21
|
+
from .routes.t2i import T2iRoute
|
|
21
22
|
|
|
22
23
|
APP: Quart = None
|
|
23
24
|
|
|
@@ -28,10 +29,19 @@ class AstrBotDashboard:
|
|
|
28
29
|
core_lifecycle: AstrBotCoreLifecycle,
|
|
29
30
|
db: BaseDatabase,
|
|
30
31
|
shutdown_event: asyncio.Event,
|
|
32
|
+
webui_dir: str | None = None,
|
|
31
33
|
) -> None:
|
|
32
34
|
self.core_lifecycle = core_lifecycle
|
|
33
35
|
self.config = core_lifecycle.astrbot_config
|
|
34
|
-
|
|
36
|
+
|
|
37
|
+
# 参数指定webui目录
|
|
38
|
+
if webui_dir and os.path.exists(webui_dir):
|
|
39
|
+
self.data_path = os.path.abspath(webui_dir)
|
|
40
|
+
else:
|
|
41
|
+
self.data_path = os.path.abspath(
|
|
42
|
+
os.path.join(get_astrbot_data_path(), "dist")
|
|
43
|
+
)
|
|
44
|
+
|
|
35
45
|
self.app = Quart("dashboard", static_folder=self.data_path, static_url_path="/")
|
|
36
46
|
APP = self.app # noqa
|
|
37
47
|
self.app.config["MAX_CONTENT_LENGTH"] = (
|
|
@@ -60,9 +70,8 @@ class AstrBotDashboard:
|
|
|
60
70
|
self.session_management_route = SessionManagementRoute(
|
|
61
71
|
self.context, db, core_lifecycle
|
|
62
72
|
)
|
|
63
|
-
self.persona_route = PersonaRoute(
|
|
64
|
-
|
|
65
|
-
)
|
|
73
|
+
self.persona_route = PersonaRoute(self.context, db, core_lifecycle)
|
|
74
|
+
self.t2i_route = T2iRoute(self.context, core_lifecycle)
|
|
66
75
|
|
|
67
76
|
self.app.add_url_rule(
|
|
68
77
|
"/api/plug/<path:subpath>",
|