AstrBot 3.4.39__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/__init__.py +3 -0
- astrbot/api/__init__.py +7 -0
- astrbot/api/all.py +53 -0
- astrbot/api/event/__init__.py +18 -0
- astrbot/api/event/filter/__init__.py +49 -0
- astrbot/api/message_components.py +1 -0
- astrbot/api/platform/__init__.py +23 -0
- astrbot/api/provider/__init__.py +17 -0
- astrbot/api/star/__init__.py +8 -0
- astrbot/api/util/__init__.py +7 -0
- astrbot/cli/__main__.py +238 -0
- astrbot/core/__init__.py +33 -0
- astrbot/core/config/__init__.py +9 -0
- astrbot/core/config/astrbot_config.py +132 -0
- astrbot/core/config/default.py +1343 -0
- astrbot/core/conversation_mgr.py +199 -0
- astrbot/core/core_lifecycle.py +231 -0
- astrbot/core/db/__init__.py +161 -0
- astrbot/core/db/plugin/sqlite_impl.py +112 -0
- astrbot/core/db/po.py +89 -0
- astrbot/core/db/sqlite.py +565 -0
- astrbot/core/db/sqlite_init.sql +50 -0
- astrbot/core/event_bus.py +57 -0
- astrbot/core/initial_loader.py +48 -0
- astrbot/core/log.py +248 -0
- astrbot/core/message/components.py +607 -0
- astrbot/core/message/message_event_result.py +222 -0
- astrbot/core/pipeline/__init__.py +41 -0
- astrbot/core/pipeline/content_safety_check/stage.py +37 -0
- astrbot/core/pipeline/content_safety_check/strategies/__init__.py +8 -0
- astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py +30 -0
- astrbot/core/pipeline/content_safety_check/strategies/keywords.py +23 -0
- astrbot/core/pipeline/content_safety_check/strategies/strategy.py +34 -0
- astrbot/core/pipeline/context.py +11 -0
- astrbot/core/pipeline/platform_compatibility/stage.py +56 -0
- astrbot/core/pipeline/preprocess_stage/stage.py +73 -0
- astrbot/core/pipeline/process_stage/method/llm_request.py +539 -0
- astrbot/core/pipeline/process_stage/method/star_request.py +67 -0
- astrbot/core/pipeline/process_stage/stage.py +68 -0
- astrbot/core/pipeline/rate_limit_check/stage.py +101 -0
- astrbot/core/pipeline/respond/stage.py +230 -0
- astrbot/core/pipeline/result_decorate/stage.py +258 -0
- astrbot/core/pipeline/scheduler.py +79 -0
- astrbot/core/pipeline/stage.py +110 -0
- astrbot/core/pipeline/waking_check/stage.py +165 -0
- astrbot/core/pipeline/whitelist_check/stage.py +65 -0
- astrbot/core/platform/__init__.py +14 -0
- astrbot/core/platform/astr_message_event.py +407 -0
- astrbot/core/platform/astrbot_message.py +69 -0
- astrbot/core/platform/manager.py +154 -0
- astrbot/core/platform/message_type.py +7 -0
- astrbot/core/platform/platform.py +59 -0
- astrbot/core/platform/platform_metadata.py +16 -0
- astrbot/core/platform/register.py +48 -0
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +139 -0
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +330 -0
- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +228 -0
- astrbot/core/platform/sources/dingtalk/dingtalk_event.py +75 -0
- astrbot/core/platform/sources/gewechat/client.py +754 -0
- astrbot/core/platform/sources/gewechat/downloader.py +55 -0
- astrbot/core/platform/sources/gewechat/gewechat_event.py +231 -0
- astrbot/core/platform/sources/gewechat/gewechat_platform_adapter.py +103 -0
- astrbot/core/platform/sources/gewechat/xml_data_parser.py +78 -0
- astrbot/core/platform/sources/lark/lark_adapter.py +232 -0
- astrbot/core/platform/sources/lark/lark_event.py +118 -0
- astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +213 -0
- astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +212 -0
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +124 -0
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py +15 -0
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +110 -0
- astrbot/core/platform/sources/telegram/tg_adapter.py +353 -0
- astrbot/core/platform/sources/telegram/tg_event.py +198 -0
- astrbot/core/platform/sources/webchat/webchat_adapter.py +124 -0
- astrbot/core/platform/sources/webchat/webchat_event.py +124 -0
- astrbot/core/platform/sources/wecom/wecom_adapter.py +244 -0
- astrbot/core/platform/sources/wecom/wecom_event.py +99 -0
- astrbot/core/provider/__init__.py +5 -0
- astrbot/core/provider/entites.py +19 -0
- astrbot/core/provider/entities.py +281 -0
- astrbot/core/provider/func_tool_manager.py +523 -0
- astrbot/core/provider/manager.py +386 -0
- astrbot/core/provider/provider.py +181 -0
- astrbot/core/provider/register.py +51 -0
- astrbot/core/provider/sources/anthropic_source.py +232 -0
- astrbot/core/provider/sources/dashscope_source.py +203 -0
- astrbot/core/provider/sources/dashscope_tts.py +39 -0
- astrbot/core/provider/sources/dify_source.py +281 -0
- astrbot/core/provider/sources/edge_tts_source.py +121 -0
- astrbot/core/provider/sources/fishaudio_tts_api_source.py +105 -0
- astrbot/core/provider/sources/gemini_source.py +581 -0
- astrbot/core/provider/sources/gsvi_tts_source.py +52 -0
- astrbot/core/provider/sources/llmtuner_source.py +132 -0
- astrbot/core/provider/sources/openai_source.py +537 -0
- astrbot/core/provider/sources/openai_tts_api_source.py +41 -0
- astrbot/core/provider/sources/sensevoice_selfhosted_source.py +104 -0
- astrbot/core/provider/sources/whisper_api_source.py +72 -0
- astrbot/core/provider/sources/whisper_selfhosted_source.py +72 -0
- astrbot/core/provider/sources/zhipu_source.py +83 -0
- astrbot/core/rag/embedding/openai_source.py +20 -0
- astrbot/core/rag/knowledge_db_mgr.py +94 -0
- astrbot/core/rag/store/__init__.py +9 -0
- astrbot/core/rag/store/chroma_db.py +42 -0
- astrbot/core/star/README.md +5 -0
- astrbot/core/star/__init__.py +32 -0
- astrbot/core/star/config.py +85 -0
- astrbot/core/star/context.py +303 -0
- astrbot/core/star/filter/__init__.py +14 -0
- astrbot/core/star/filter/command.py +143 -0
- astrbot/core/star/filter/command_group.py +122 -0
- astrbot/core/star/filter/custom_filter.py +61 -0
- astrbot/core/star/filter/event_message_type.py +31 -0
- astrbot/core/star/filter/permission.py +27 -0
- astrbot/core/star/filter/platform_adapter_type.py +38 -0
- astrbot/core/star/filter/regex.py +16 -0
- astrbot/core/star/register/__init__.py +33 -0
- astrbot/core/star/register/star.py +38 -0
- astrbot/core/star/register/star_handler.py +390 -0
- astrbot/core/star/star.py +75 -0
- astrbot/core/star/star_handler.py +185 -0
- astrbot/core/star/star_manager.py +789 -0
- astrbot/core/star/star_tools.py +192 -0
- astrbot/core/star/updator.py +84 -0
- astrbot/core/updator.py +100 -0
- astrbot/core/utils/command_parser.py +23 -0
- astrbot/core/utils/dify_api_client.py +152 -0
- astrbot/core/utils/io.py +228 -0
- astrbot/core/utils/log_pipe.py +36 -0
- astrbot/core/utils/metrics.py +74 -0
- astrbot/core/utils/path_util.py +70 -0
- astrbot/core/utils/pip_installer.py +40 -0
- astrbot/core/utils/session_waiter.py +198 -0
- astrbot/core/utils/shared_preferences.py +38 -0
- astrbot/core/utils/t2i/__init__.py +13 -0
- astrbot/core/utils/t2i/local_strategy.py +784 -0
- astrbot/core/utils/t2i/network_strategy.py +77 -0
- astrbot/core/utils/t2i/renderer.py +46 -0
- astrbot/core/utils/t2i/template/base.html +247 -0
- astrbot/core/utils/tencent_record_helper.py +52 -0
- astrbot/core/zip_updator.py +209 -0
- astrbot/dashboard/routes/__init__.py +24 -0
- astrbot/dashboard/routes/auth.py +78 -0
- astrbot/dashboard/routes/chat.py +258 -0
- astrbot/dashboard/routes/config.py +368 -0
- astrbot/dashboard/routes/conversation.py +215 -0
- astrbot/dashboard/routes/log.py +44 -0
- astrbot/dashboard/routes/plugin.py +455 -0
- astrbot/dashboard/routes/route.py +37 -0
- astrbot/dashboard/routes/stat.py +118 -0
- astrbot/dashboard/routes/static_file.py +34 -0
- astrbot/dashboard/routes/tools.py +290 -0
- astrbot/dashboard/routes/update.py +147 -0
- astrbot/dashboard/server.py +178 -0
- astrbot-3.4.39.dist-info/METADATA +244 -0
- astrbot-3.4.39.dist-info/RECORD +157 -0
- astrbot-3.4.39.dist-info/WHEEL +4 -0
- astrbot-3.4.39.dist-info/entry_points.txt +2 -0
- astrbot-3.4.39.dist-info/licenses/LICENSE +661 -0
astrbot/__init__.py
ADDED
astrbot/api/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from astrbot.core.config.astrbot_config import AstrBotConfig
|
|
2
|
+
from astrbot import logger
|
|
3
|
+
from astrbot.core import html_renderer
|
|
4
|
+
from astrbot.core import sp
|
|
5
|
+
from astrbot.core.star.register import register_llm_tool as llm_tool
|
|
6
|
+
|
|
7
|
+
__all__ = ["AstrBotConfig", "logger", "html_renderer", "llm_tool", "sp"]
|
astrbot/api/all.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from astrbot.core.config.astrbot_config import AstrBotConfig
|
|
2
|
+
from astrbot import logger
|
|
3
|
+
from astrbot.core import html_renderer
|
|
4
|
+
from astrbot.core.star.register import register_llm_tool as llm_tool
|
|
5
|
+
|
|
6
|
+
# event
|
|
7
|
+
from astrbot.core.message.message_event_result import (
|
|
8
|
+
MessageEventResult,
|
|
9
|
+
MessageChain,
|
|
10
|
+
CommandResult,
|
|
11
|
+
EventResultType,
|
|
12
|
+
)
|
|
13
|
+
from astrbot.core.platform import AstrMessageEvent
|
|
14
|
+
|
|
15
|
+
# star register
|
|
16
|
+
from astrbot.core.star.register import (
|
|
17
|
+
register_command as command,
|
|
18
|
+
register_command_group as command_group,
|
|
19
|
+
register_event_message_type as event_message_type,
|
|
20
|
+
register_regex as regex,
|
|
21
|
+
register_platform_adapter_type as platform_adapter_type,
|
|
22
|
+
)
|
|
23
|
+
from astrbot.core.star.filter.event_message_type import (
|
|
24
|
+
EventMessageTypeFilter,
|
|
25
|
+
EventMessageType,
|
|
26
|
+
)
|
|
27
|
+
from astrbot.core.star.filter.platform_adapter_type import (
|
|
28
|
+
PlatformAdapterTypeFilter,
|
|
29
|
+
PlatformAdapterType,
|
|
30
|
+
)
|
|
31
|
+
from astrbot.core.star.register import (
|
|
32
|
+
register_star as register, # 注册插件(Star)
|
|
33
|
+
)
|
|
34
|
+
from astrbot.core.star import Context, Star
|
|
35
|
+
from astrbot.core.star.config import *
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# provider
|
|
39
|
+
from astrbot.core.provider import Provider, Personality, ProviderMetaData
|
|
40
|
+
|
|
41
|
+
# platform
|
|
42
|
+
from astrbot.core.platform import (
|
|
43
|
+
AstrMessageEvent,
|
|
44
|
+
Platform,
|
|
45
|
+
AstrBotMessage,
|
|
46
|
+
MessageMember,
|
|
47
|
+
MessageType,
|
|
48
|
+
PlatformMetadata,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
from astrbot.core.platform.register import register_platform_adapter
|
|
52
|
+
|
|
53
|
+
from .message_components import *
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from astrbot.core.message.message_event_result import (
|
|
2
|
+
MessageEventResult,
|
|
3
|
+
MessageChain,
|
|
4
|
+
CommandResult,
|
|
5
|
+
EventResultType,
|
|
6
|
+
ResultContentType,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from astrbot.core.platform import AstrMessageEvent
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"MessageEventResult",
|
|
13
|
+
"MessageChain",
|
|
14
|
+
"CommandResult",
|
|
15
|
+
"EventResultType",
|
|
16
|
+
"AstrMessageEvent",
|
|
17
|
+
"ResultContentType",
|
|
18
|
+
]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from astrbot.core.star.register import (
|
|
2
|
+
register_command as command,
|
|
3
|
+
register_command_group as command_group,
|
|
4
|
+
register_event_message_type as event_message_type,
|
|
5
|
+
register_regex as regex,
|
|
6
|
+
register_platform_adapter_type as platform_adapter_type,
|
|
7
|
+
register_permission_type as permission_type,
|
|
8
|
+
register_custom_filter as custom_filter,
|
|
9
|
+
register_on_astrbot_loaded as on_astrbot_loaded,
|
|
10
|
+
register_on_llm_request as on_llm_request,
|
|
11
|
+
register_on_llm_response as on_llm_response,
|
|
12
|
+
register_llm_tool as llm_tool,
|
|
13
|
+
register_on_decorating_result as on_decorating_result,
|
|
14
|
+
register_after_message_sent as after_message_sent,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from astrbot.core.star.filter.event_message_type import (
|
|
18
|
+
EventMessageTypeFilter,
|
|
19
|
+
EventMessageType,
|
|
20
|
+
)
|
|
21
|
+
from astrbot.core.star.filter.platform_adapter_type import (
|
|
22
|
+
PlatformAdapterTypeFilter,
|
|
23
|
+
PlatformAdapterType,
|
|
24
|
+
)
|
|
25
|
+
from astrbot.core.star.filter.permission import PermissionTypeFilter, PermissionType
|
|
26
|
+
from astrbot.core.star.filter.custom_filter import CustomFilter
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"command",
|
|
30
|
+
"command_group",
|
|
31
|
+
"event_message_type",
|
|
32
|
+
"regex",
|
|
33
|
+
"platform_adapter_type",
|
|
34
|
+
"permission_type",
|
|
35
|
+
"EventMessageTypeFilter",
|
|
36
|
+
"EventMessageType",
|
|
37
|
+
"PlatformAdapterTypeFilter",
|
|
38
|
+
"PlatformAdapterType",
|
|
39
|
+
"PermissionTypeFilter",
|
|
40
|
+
"CustomFilter",
|
|
41
|
+
"custom_filter",
|
|
42
|
+
"PermissionType",
|
|
43
|
+
"on_astrbot_loaded",
|
|
44
|
+
"on_llm_request",
|
|
45
|
+
"llm_tool",
|
|
46
|
+
"on_decorating_result",
|
|
47
|
+
"after_message_sent",
|
|
48
|
+
"on_llm_response",
|
|
49
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from astrbot.core.message.components import *
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from astrbot.core.platform import (
|
|
2
|
+
AstrMessageEvent,
|
|
3
|
+
Platform,
|
|
4
|
+
AstrBotMessage,
|
|
5
|
+
MessageMember,
|
|
6
|
+
MessageType,
|
|
7
|
+
PlatformMetadata,
|
|
8
|
+
Group,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from astrbot.core.platform.register import register_platform_adapter
|
|
12
|
+
from astrbot.core.message.components import *
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"AstrMessageEvent",
|
|
16
|
+
"Platform",
|
|
17
|
+
"AstrBotMessage",
|
|
18
|
+
"MessageMember",
|
|
19
|
+
"MessageType",
|
|
20
|
+
"PlatformMetadata",
|
|
21
|
+
"register_platform_adapter",
|
|
22
|
+
"Group",
|
|
23
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from astrbot.core.provider import Provider, STTProvider, Personality
|
|
2
|
+
from astrbot.core.provider.entities import (
|
|
3
|
+
ProviderRequest,
|
|
4
|
+
ProviderType,
|
|
5
|
+
ProviderMetaData,
|
|
6
|
+
LLMResponse,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"Provider",
|
|
11
|
+
"STTProvider",
|
|
12
|
+
"Personality",
|
|
13
|
+
"ProviderRequest",
|
|
14
|
+
"ProviderType",
|
|
15
|
+
"ProviderMetaData",
|
|
16
|
+
"LLMResponse",
|
|
17
|
+
]
|
astrbot/cli/__main__.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import sys
|
|
5
|
+
import click
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from astrbot.core.config.default import VERSION
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
logo_tmpl = r"""
|
|
11
|
+
___ _______.___________..______ .______ ______ .___________.
|
|
12
|
+
/ \ / | || _ \ | _ \ / __ \ | |
|
|
13
|
+
/ ^ \ | (----`---| |----`| |_) | | |_) | | | | | `---| |----`
|
|
14
|
+
/ /_\ \ \ \ | | | / | _ < | | | | | |
|
|
15
|
+
/ _____ \ .----) | | | | |\ \----.| |_) | | `--' | | |
|
|
16
|
+
/__/ \__\ |_______/ |__| | _| `._____||______/ \______/ |__|
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# utils
|
|
22
|
+
def _get_astrbot_root(path: str | None) -> Path:
|
|
23
|
+
"""获取astrbot根目录"""
|
|
24
|
+
match path:
|
|
25
|
+
case None:
|
|
26
|
+
match ASTRBOT_ROOT := os.getenv("ASTRBOT_ROOT"):
|
|
27
|
+
case None:
|
|
28
|
+
astrbot_root = Path.cwd() / "data"
|
|
29
|
+
case _:
|
|
30
|
+
astrbot_root = Path(ASTRBOT_ROOT).resolve()
|
|
31
|
+
case str():
|
|
32
|
+
astrbot_root = Path(path).resolve()
|
|
33
|
+
|
|
34
|
+
dot_astrbot = astrbot_root / ".astrbot"
|
|
35
|
+
if not dot_astrbot.exists():
|
|
36
|
+
if click.confirm(
|
|
37
|
+
f"运行前必须先执行初始化!请检查当前目录是否正确,回车以继续: {astrbot_root}",
|
|
38
|
+
default=True,
|
|
39
|
+
abort=True,
|
|
40
|
+
):
|
|
41
|
+
dot_astrbot.touch()
|
|
42
|
+
astrbot_root.mkdir(parents=True, exist_ok=True)
|
|
43
|
+
click.echo(f"Created {dot_astrbot}")
|
|
44
|
+
|
|
45
|
+
return astrbot_root
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# 通过类型来验证先后,必须先获取 Path 对象才能对该目录进行检查
|
|
49
|
+
def _check_astrbot_root(astrbot_root: Path) -> None:
|
|
50
|
+
"""验证"""
|
|
51
|
+
dot_astrbot = astrbot_root / ".astrbot"
|
|
52
|
+
if not astrbot_root.exists():
|
|
53
|
+
click.echo(f"AstrBot root directory does not exist: {astrbot_root}")
|
|
54
|
+
click.echo("Please run 'astrbot init' to create the directory.")
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
else:
|
|
57
|
+
click.echo(f"AstrBot root directory exists: {astrbot_root}")
|
|
58
|
+
if not dot_astrbot.exists():
|
|
59
|
+
click.echo(
|
|
60
|
+
"如果你确认这是 Astrbot root directory, 你需要在当前目录下创建一个 .astrbot 文件标记该目录为 AstrBot 的数据目录。"
|
|
61
|
+
)
|
|
62
|
+
if click.confirm(
|
|
63
|
+
f"请检查当前目录是否正确,确认正确请回车: {astrbot_root}",
|
|
64
|
+
default=True,
|
|
65
|
+
abort=True,
|
|
66
|
+
):
|
|
67
|
+
dot_astrbot.touch()
|
|
68
|
+
click.echo(f"Created {dot_astrbot}")
|
|
69
|
+
else:
|
|
70
|
+
click.echo(f"Welcome back! AstrBot root directory: {astrbot_root}")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
async def _check_dashboard(astrbot_root: Path) -> None:
|
|
74
|
+
"""检查是否安装了dashboard"""
|
|
75
|
+
try:
|
|
76
|
+
from ..core.utils.io import get_dashboard_version, download_dashboard
|
|
77
|
+
except ImportError:
|
|
78
|
+
from astrbot.core.utils.io import get_dashboard_version, download_dashboard
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
# 添加 create=True 参数以确保在初始化时不会抛出异常
|
|
82
|
+
dashboard_version = await get_dashboard_version()
|
|
83
|
+
match dashboard_version:
|
|
84
|
+
case None:
|
|
85
|
+
click.echo("未安装管理面板")
|
|
86
|
+
if click.confirm(
|
|
87
|
+
"是否安装管理面板?",
|
|
88
|
+
default=True,
|
|
89
|
+
abort=True,
|
|
90
|
+
):
|
|
91
|
+
click.echo("正在安装管理面板...")
|
|
92
|
+
# 确保使用 create=True 参数
|
|
93
|
+
await download_dashboard(
|
|
94
|
+
path="data/dashboard.zip", extract_path=str(astrbot_root)
|
|
95
|
+
)
|
|
96
|
+
click.echo("管理面板安装完成")
|
|
97
|
+
|
|
98
|
+
case str():
|
|
99
|
+
if dashboard_version == f"v{VERSION}":
|
|
100
|
+
click.echo("无需更新")
|
|
101
|
+
else:
|
|
102
|
+
try:
|
|
103
|
+
version = dashboard_version.split("v")[1]
|
|
104
|
+
click.echo(f"管理面板版本: {version}")
|
|
105
|
+
# 确保使用 create=True 参数
|
|
106
|
+
await download_dashboard(
|
|
107
|
+
path="data/dashboard.zip", extract_path=str(astrbot_root)
|
|
108
|
+
)
|
|
109
|
+
except Exception as e:
|
|
110
|
+
click.echo(f"下载管理面板失败: {e}")
|
|
111
|
+
return
|
|
112
|
+
except FileNotFoundError:
|
|
113
|
+
click.echo("初始化管理面板目录...")
|
|
114
|
+
# 初始化模式下,下载到指定位置
|
|
115
|
+
try:
|
|
116
|
+
await download_dashboard(
|
|
117
|
+
path=str(astrbot_root / "dashboard.zip"), extract_path=str(astrbot_root)
|
|
118
|
+
)
|
|
119
|
+
click.echo("管理面板初始化完成")
|
|
120
|
+
except Exception as e:
|
|
121
|
+
click.echo(f"下载管理面板失败: {e}")
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@click.group(name="astrbot")
|
|
126
|
+
def cli() -> None:
|
|
127
|
+
"""The AstrBot CLI"""
|
|
128
|
+
click.echo(logo_tmpl)
|
|
129
|
+
click.echo("Welcome to AstrBot CLI!")
|
|
130
|
+
click.echo(f"AstrBot version: {VERSION}")
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# region init
|
|
134
|
+
@cli.command()
|
|
135
|
+
@click.option("--path", "-p", help="AstrBot 数据目录")
|
|
136
|
+
@click.option("--force", "-f", is_flag=True, help="强制初始化")
|
|
137
|
+
def init(path: str | None, force: bool) -> None:
|
|
138
|
+
"""Initialize AstrBot"""
|
|
139
|
+
click.echo("Initializing AstrBot...")
|
|
140
|
+
astrbot_root = _get_astrbot_root(path)
|
|
141
|
+
if force:
|
|
142
|
+
if click.confirm(
|
|
143
|
+
"强制初始化会删除当前目录下的所有文件,是否继续?",
|
|
144
|
+
default=False,
|
|
145
|
+
abort=True,
|
|
146
|
+
):
|
|
147
|
+
click.echo("正在删除当前目录下的所有文件...")
|
|
148
|
+
shutil.rmtree(astrbot_root, ignore_errors=True)
|
|
149
|
+
|
|
150
|
+
_check_astrbot_root(astrbot_root)
|
|
151
|
+
|
|
152
|
+
click.echo(f"AstrBot root directory: {astrbot_root}")
|
|
153
|
+
|
|
154
|
+
if not astrbot_root.exists():
|
|
155
|
+
# 创建目录
|
|
156
|
+
astrbot_root.mkdir(parents=True, exist_ok=True)
|
|
157
|
+
click.echo(f"Created directory: {astrbot_root}")
|
|
158
|
+
else:
|
|
159
|
+
click.echo(f"Directory already exists: {astrbot_root}")
|
|
160
|
+
|
|
161
|
+
config_path: Path = astrbot_root / "config"
|
|
162
|
+
plugins_path: Path = astrbot_root / "plugins"
|
|
163
|
+
temp_path: Path = astrbot_root / "temp"
|
|
164
|
+
config_path.mkdir(parents=True, exist_ok=True)
|
|
165
|
+
plugins_path.mkdir(parents=True, exist_ok=True)
|
|
166
|
+
temp_path.mkdir(parents=True, exist_ok=True)
|
|
167
|
+
|
|
168
|
+
click.echo(f"Created directories: {config_path}, {plugins_path}, {temp_path}")
|
|
169
|
+
|
|
170
|
+
# 检查是否安装了dashboard
|
|
171
|
+
asyncio.run(_check_dashboard(astrbot_root))
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# region run
|
|
175
|
+
@cli.command()
|
|
176
|
+
@click.option("--path", "-p", help="AstrBot 数据目录")
|
|
177
|
+
def run(path: str | None = None) -> None:
|
|
178
|
+
"""Run AstrBot"""
|
|
179
|
+
# 解析为绝对路径
|
|
180
|
+
try:
|
|
181
|
+
from ..core.log import LogBroker
|
|
182
|
+
from ..core import db_helper
|
|
183
|
+
from ..core.initial_loader import InitialLoader
|
|
184
|
+
except ImportError:
|
|
185
|
+
from astrbot.core.log import LogBroker
|
|
186
|
+
from astrbot.core import db_helper
|
|
187
|
+
from astrbot.core.initial_loader import InitialLoader
|
|
188
|
+
|
|
189
|
+
astrbot_root = _get_astrbot_root(path)
|
|
190
|
+
|
|
191
|
+
_check_astrbot_root(astrbot_root)
|
|
192
|
+
|
|
193
|
+
asyncio.run(_check_dashboard(astrbot_root))
|
|
194
|
+
|
|
195
|
+
log_broker = LogBroker()
|
|
196
|
+
db = db_helper
|
|
197
|
+
|
|
198
|
+
core_lifecycle = InitialLoader(db, log_broker)
|
|
199
|
+
try:
|
|
200
|
+
asyncio.run(core_lifecycle.start())
|
|
201
|
+
except KeyboardInterrupt:
|
|
202
|
+
click.echo("接收到退出信号,正在关闭 AstrBot...")
|
|
203
|
+
except Exception as e:
|
|
204
|
+
click.echo(f"运行时出现错误: {e}")
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# region Basic
|
|
208
|
+
@cli.command(name="version")
|
|
209
|
+
def version() -> None:
|
|
210
|
+
"""Show the version of AstrBot"""
|
|
211
|
+
click.echo(f"AstrBot version: {VERSION}")
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@cli.command()
|
|
215
|
+
@click.argument("command_name", required=False, type=str)
|
|
216
|
+
def help(command_name: str | None) -> None:
|
|
217
|
+
"""Show help information for commands
|
|
218
|
+
|
|
219
|
+
If COMMAND_NAME is provided, show detailed help for that command.
|
|
220
|
+
Otherwise, show general help information.
|
|
221
|
+
"""
|
|
222
|
+
ctx = click.get_current_context()
|
|
223
|
+
if command_name:
|
|
224
|
+
# 查找指定命令
|
|
225
|
+
command = cli.get_command(ctx, command_name)
|
|
226
|
+
if command:
|
|
227
|
+
# 显示特定命令的帮助信息
|
|
228
|
+
click.echo(command.get_help(ctx))
|
|
229
|
+
else:
|
|
230
|
+
click.echo(f"Unknown command: {command_name}")
|
|
231
|
+
sys.exit(1)
|
|
232
|
+
else:
|
|
233
|
+
# 显示通用帮助信息
|
|
234
|
+
click.echo(cli.get_help(ctx))
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
if __name__ == "__main__":
|
|
238
|
+
cli()
|
astrbot/core/__init__.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import asyncio
|
|
3
|
+
from .log import LogManager, LogBroker # noqa
|
|
4
|
+
from astrbot.core.utils.t2i.renderer import HtmlRenderer
|
|
5
|
+
from astrbot.core.utils.shared_preferences import SharedPreferences
|
|
6
|
+
from astrbot.core.utils.pip_installer import PipInstaller
|
|
7
|
+
from astrbot.core.db.sqlite import SQLiteDatabase
|
|
8
|
+
from astrbot.core.config.default import DB_PATH
|
|
9
|
+
from astrbot.core.config import AstrBotConfig
|
|
10
|
+
|
|
11
|
+
# 初始化数据存储文件夹
|
|
12
|
+
os.makedirs("data", exist_ok=True)
|
|
13
|
+
|
|
14
|
+
astrbot_config = AstrBotConfig()
|
|
15
|
+
t2i_base_url = astrbot_config.get("t2i_endpoint", "https://t2i.soulter.top/text2img")
|
|
16
|
+
html_renderer = HtmlRenderer(t2i_base_url)
|
|
17
|
+
logger = LogManager.GetLogger(log_name="astrbot")
|
|
18
|
+
|
|
19
|
+
if os.environ.get("TESTING", ""):
|
|
20
|
+
logger.setLevel("DEBUG")
|
|
21
|
+
|
|
22
|
+
db_helper = SQLiteDatabase(DB_PATH)
|
|
23
|
+
sp = (
|
|
24
|
+
SharedPreferences()
|
|
25
|
+
) # 简单的偏好设置存储, 这里后续应该存储到数据库中, 一些部分可以存储到配置中
|
|
26
|
+
pip_installer = PipInstaller(
|
|
27
|
+
astrbot_config.get("pip_install_arg", ""),
|
|
28
|
+
astrbot_config.get("pypi_index_url", None),
|
|
29
|
+
)
|
|
30
|
+
web_chat_queue = asyncio.Queue(maxsize=32)
|
|
31
|
+
web_chat_back_queue = asyncio.Queue(maxsize=32)
|
|
32
|
+
WEBUI_SK = "Advanced_System_for_Text_Response_and_Bot_Operations_Tool"
|
|
33
|
+
DEMO_MODE = os.getenv("DEMO_MODE", False)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import enum
|
|
5
|
+
from .default import DEFAULT_CONFIG, DEFAULT_VALUE_MAP
|
|
6
|
+
from typing import Dict
|
|
7
|
+
|
|
8
|
+
ASTRBOT_CONFIG_PATH = "data/cmd_config.json"
|
|
9
|
+
logger = logging.getLogger("astrbot")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RateLimitStrategy(enum.Enum):
|
|
13
|
+
STALL = "stall"
|
|
14
|
+
DISCARD = "discard"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AstrBotConfig(dict):
|
|
18
|
+
"""从配置文件中加载的配置,支持直接通过点号操作符访问根配置项。
|
|
19
|
+
|
|
20
|
+
- 初始化时会将传入的 default_config 与配置文件进行比对,如果配置文件中缺少配置项则会自动插入默认值并进行一次写入操作。会递归检查配置项。
|
|
21
|
+
- 如果配置文件路径对应的文件不存在,则会自动创建并写入默认配置。
|
|
22
|
+
- 如果传入了 schema,将会通过 schema 解析出 default_config,此时传入的 default_config 会被忽略。
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
config_path: str = ASTRBOT_CONFIG_PATH,
|
|
28
|
+
default_config: dict = DEFAULT_CONFIG,
|
|
29
|
+
schema: dict = None,
|
|
30
|
+
):
|
|
31
|
+
super().__init__()
|
|
32
|
+
|
|
33
|
+
# 调用父类的 __setattr__ 方法,防止保存配置时将此属性写入配置文件
|
|
34
|
+
object.__setattr__(self, "config_path", config_path)
|
|
35
|
+
object.__setattr__(self, "default_config", default_config)
|
|
36
|
+
object.__setattr__(self, "schema", schema)
|
|
37
|
+
|
|
38
|
+
if schema:
|
|
39
|
+
default_config = self._config_schema_to_default_config(schema)
|
|
40
|
+
|
|
41
|
+
if not self.check_exist():
|
|
42
|
+
"""不存在时载入默认配置"""
|
|
43
|
+
with open(config_path, "w", encoding="utf-8-sig") as f:
|
|
44
|
+
json.dump(default_config, f, indent=4, ensure_ascii=False)
|
|
45
|
+
|
|
46
|
+
with open(config_path, "r", encoding="utf-8-sig") as f:
|
|
47
|
+
conf_str = f.read()
|
|
48
|
+
if conf_str.startswith("/ufeff"): # remove BOM
|
|
49
|
+
conf_str = conf_str.encode("utf8")[3:].decode("utf8")
|
|
50
|
+
conf = json.loads(conf_str)
|
|
51
|
+
|
|
52
|
+
# 检查配置完整性,并插入
|
|
53
|
+
has_new = self.check_config_integrity(default_config, conf)
|
|
54
|
+
self.update(conf)
|
|
55
|
+
if has_new:
|
|
56
|
+
self.save_config()
|
|
57
|
+
|
|
58
|
+
self.update(conf)
|
|
59
|
+
|
|
60
|
+
def _config_schema_to_default_config(self, schema: dict) -> dict:
|
|
61
|
+
"""将 Schema 转换成 Config"""
|
|
62
|
+
conf = {}
|
|
63
|
+
|
|
64
|
+
def _parse_schema(schema: dict, conf: dict):
|
|
65
|
+
for k, v in schema.items():
|
|
66
|
+
if v["type"] not in DEFAULT_VALUE_MAP:
|
|
67
|
+
raise TypeError(
|
|
68
|
+
f"不受支持的配置类型 {v['type']}。支持的类型有:{DEFAULT_VALUE_MAP.keys()}"
|
|
69
|
+
)
|
|
70
|
+
if "default" in v:
|
|
71
|
+
default = v["default"]
|
|
72
|
+
else:
|
|
73
|
+
default = DEFAULT_VALUE_MAP[v["type"]]
|
|
74
|
+
|
|
75
|
+
if v["type"] == "object":
|
|
76
|
+
conf[k] = {}
|
|
77
|
+
_parse_schema(v["items"], conf[k])
|
|
78
|
+
else:
|
|
79
|
+
conf[k] = default
|
|
80
|
+
|
|
81
|
+
_parse_schema(schema, conf)
|
|
82
|
+
|
|
83
|
+
return conf
|
|
84
|
+
|
|
85
|
+
def check_config_integrity(self, refer_conf: Dict, conf: Dict, path=""):
|
|
86
|
+
"""检查配置完整性,如果有新的配置项则返回 True"""
|
|
87
|
+
has_new = False
|
|
88
|
+
for key, value in refer_conf.items():
|
|
89
|
+
if key not in conf:
|
|
90
|
+
# logger.info(f"检查到配置项 {path + "." + key if path else key} 不存在,已插入默认值 {value}")
|
|
91
|
+
path_ = path + "." + key if path else key
|
|
92
|
+
logger.info(f"检查到配置项 {path_} 不存在,已插入默认值 {value}")
|
|
93
|
+
conf[key] = value
|
|
94
|
+
has_new = True
|
|
95
|
+
else:
|
|
96
|
+
if conf[key] is None:
|
|
97
|
+
conf[key] = value
|
|
98
|
+
has_new = True
|
|
99
|
+
elif isinstance(value, dict):
|
|
100
|
+
has_new |= self.check_config_integrity(
|
|
101
|
+
value, conf[key], path + "." + key if path else key
|
|
102
|
+
)
|
|
103
|
+
return has_new
|
|
104
|
+
|
|
105
|
+
def save_config(self, replace_config: Dict = None):
|
|
106
|
+
"""将配置写入文件
|
|
107
|
+
|
|
108
|
+
如果传入 replace_config,则将配置替换为 replace_config
|
|
109
|
+
"""
|
|
110
|
+
if replace_config:
|
|
111
|
+
self.update(replace_config)
|
|
112
|
+
with open(self.config_path, "w", encoding="utf-8-sig") as f:
|
|
113
|
+
json.dump(self, f, indent=2, ensure_ascii=False)
|
|
114
|
+
|
|
115
|
+
def __getattr__(self, item):
|
|
116
|
+
try:
|
|
117
|
+
return self[item]
|
|
118
|
+
except KeyError:
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
def __delattr__(self, key):
|
|
122
|
+
try:
|
|
123
|
+
del self[key]
|
|
124
|
+
self.save_config()
|
|
125
|
+
except KeyError:
|
|
126
|
+
raise AttributeError(f"没有找到 Key: '{key}'")
|
|
127
|
+
|
|
128
|
+
def __setattr__(self, key, value):
|
|
129
|
+
self[key] = value
|
|
130
|
+
|
|
131
|
+
def check_exist(self) -> bool:
|
|
132
|
+
return os.path.exists(self.config_path)
|