AstrBot 4.8.0__py3-none-any.whl → 4.9.1__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/cli/__init__.py +1 -1
- astrbot/core/agent/runners/tool_loop_agent_runner.py +0 -1
- astrbot/core/agent/tool.py +7 -2
- astrbot/core/astr_agent_tool_exec.py +5 -1
- astrbot/core/config/astrbot_config.py +4 -0
- astrbot/core/config/default.py +72 -1
- astrbot/core/config/i18n_utils.py +1 -0
- astrbot/core/core_lifecycle.py +1 -1
- astrbot/core/db/__init__.py +2 -3
- astrbot/core/db/migration/migra_3_to_4.py +2 -0
- astrbot/core/db/migration/sqlite_v3.py +6 -4
- astrbot/core/db/po.py +16 -15
- astrbot/core/db/sqlite.py +4 -3
- astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +2 -0
- astrbot/core/event_bus.py +6 -1
- astrbot/core/knowledge_base/retrieval/manager.py +5 -1
- astrbot/core/log.py +2 -1
- astrbot/core/message/components.py +9 -3
- astrbot/core/persona_mgr.py +2 -2
- astrbot/core/pipeline/content_safety_check/stage.py +1 -1
- astrbot/core/pipeline/context_utils.py +2 -1
- astrbot/core/pipeline/process_stage/method/star_request.py +1 -2
- astrbot/core/pipeline/process_stage/stage.py +1 -1
- astrbot/core/pipeline/respond/stage.py +8 -2
- astrbot/core/pipeline/result_decorate/stage.py +89 -22
- astrbot/core/pipeline/scheduler.py +5 -1
- astrbot/core/pipeline/waking_check/stage.py +10 -0
- astrbot/core/platform/astr_message_event.py +5 -3
- astrbot/core/platform/astrbot_message.py +2 -2
- astrbot/core/platform/manager.py +4 -0
- astrbot/core/platform/platform.py +11 -3
- astrbot/core/platform/platform_metadata.py +1 -1
- astrbot/core/platform/register.py +1 -0
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +8 -6
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +9 -5
- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +24 -16
- astrbot/core/platform/sources/dingtalk/dingtalk_event.py +5 -2
- astrbot/core/platform/sources/discord/client.py +16 -4
- astrbot/core/platform/sources/discord/components.py +2 -2
- astrbot/core/platform/sources/discord/discord_platform_adapter.py +52 -24
- astrbot/core/platform/sources/discord/discord_platform_event.py +29 -8
- astrbot/core/platform/sources/lark/lark_adapter.py +183 -20
- astrbot/core/platform/sources/lark/lark_event.py +39 -4
- astrbot/core/platform/sources/lark/server.py +206 -0
- astrbot/core/platform/sources/misskey/misskey_adapter.py +2 -3
- astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +62 -18
- astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +13 -7
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +5 -3
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +2 -1
- astrbot/core/platform/sources/slack/client.py +9 -2
- astrbot/core/platform/sources/slack/slack_adapter.py +15 -9
- astrbot/core/platform/sources/slack/slack_event.py +8 -7
- astrbot/core/platform/sources/telegram/tg_adapter.py +1 -1
- astrbot/core/platform/sources/telegram/tg_event.py +23 -27
- astrbot/core/platform/sources/webchat/webchat_adapter.py +2 -2
- astrbot/core/platform/sources/webchat/webchat_event.py +2 -2
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +26 -9
- astrbot/core/platform/sources/wecom/wecom_adapter.py +25 -28
- astrbot/core/platform/sources/wecom/wecom_event.py +2 -2
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +3 -3
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +30 -25
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +10 -7
- astrbot/core/provider/func_tool_manager.py +3 -3
- astrbot/core/provider/manager.py +130 -74
- astrbot/core/provider/provider.py +12 -1
- astrbot/core/provider/sources/azure_tts_source.py +31 -9
- astrbot/core/provider/sources/bailian_rerank_source.py +4 -0
- astrbot/core/provider/sources/dashscope_tts.py +3 -2
- astrbot/core/provider/sources/edge_tts_source.py +1 -1
- astrbot/core/provider/sources/fishaudio_tts_api_source.py +5 -4
- astrbot/core/provider/sources/gemini_embedding_source.py +15 -5
- astrbot/core/provider/sources/gemini_source.py +12 -10
- astrbot/core/provider/sources/minimax_tts_api_source.py +4 -2
- astrbot/core/provider/sources/openai_embedding_source.py +2 -2
- astrbot/core/provider/sources/openai_source.py +4 -0
- astrbot/core/provider/sources/sensevoice_selfhosted_source.py +5 -2
- astrbot/core/provider/sources/vllm_rerank_source.py +1 -0
- astrbot/core/provider/sources/whisper_api_source.py +1 -1
- astrbot/core/provider/sources/whisper_selfhosted_source.py +6 -2
- astrbot/core/provider/sources/xinference_rerank_source.py +10 -2
- astrbot/core/star/context.py +2 -2
- astrbot/core/star/register/star_handler.py +22 -5
- astrbot/core/star/star_handler.py +85 -4
- astrbot/core/updator.py +3 -3
- astrbot/core/utils/io.py +1 -1
- astrbot/core/utils/session_waiter.py +17 -10
- astrbot/core/utils/shared_preferences.py +32 -0
- astrbot/core/utils/t2i/__init__.py +2 -2
- astrbot/core/utils/t2i/local_strategy.py +25 -31
- astrbot/core/utils/tencent_record_helper.py +1 -1
- astrbot/core/utils/version_comparator.py +6 -3
- astrbot/core/utils/webhook_utils.py +19 -0
- astrbot/dashboard/routes/chat.py +14 -9
- astrbot/dashboard/routes/config.py +10 -20
- astrbot/dashboard/routes/conversation.py +91 -1
- astrbot/dashboard/routes/knowledge_base.py +253 -78
- astrbot/dashboard/routes/log.py +13 -8
- astrbot/dashboard/routes/platform.py +1 -1
- astrbot/dashboard/routes/plugin.py +113 -52
- astrbot/dashboard/routes/route.py +2 -0
- astrbot/dashboard/server.py +6 -3
- {astrbot-4.8.0.dist-info → astrbot-4.9.1.dist-info}/METADATA +9 -1
- {astrbot-4.8.0.dist-info → astrbot-4.9.1.dist-info}/RECORD +106 -105
- {astrbot-4.8.0.dist-info → astrbot-4.9.1.dist-info}/WHEEL +0 -0
- {astrbot-4.8.0.dist-info → astrbot-4.9.1.dist-info}/entry_points.txt +0 -0
- {astrbot-4.8.0.dist-info → astrbot-4.9.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -48,6 +48,7 @@ class KnowledgeBaseRoute(Route):
|
|
|
48
48
|
# 文档管理
|
|
49
49
|
"/kb/document/list": ("GET", self.list_documents),
|
|
50
50
|
"/kb/document/upload": ("POST", self.upload_document),
|
|
51
|
+
"/kb/document/import": ("POST", self.import_documents),
|
|
51
52
|
"/kb/document/upload/url": ("POST", self.upload_document_from_url),
|
|
52
53
|
"/kb/document/upload/progress": ("GET", self.get_upload_progress),
|
|
53
54
|
"/kb/document/get": ("GET", self.get_document),
|
|
@@ -66,6 +67,65 @@ class KnowledgeBaseRoute(Route):
|
|
|
66
67
|
def _get_kb_manager(self):
|
|
67
68
|
return self.core_lifecycle.kb_manager
|
|
68
69
|
|
|
70
|
+
def _init_task(self, task_id: str, status: str = "pending") -> None:
|
|
71
|
+
self.upload_tasks[task_id] = {
|
|
72
|
+
"status": status,
|
|
73
|
+
"result": None,
|
|
74
|
+
"error": None,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
def _set_task_result(
|
|
78
|
+
self, task_id: str, status: str, result: any = None, error: str | None = None
|
|
79
|
+
) -> None:
|
|
80
|
+
self.upload_tasks[task_id] = {
|
|
81
|
+
"status": status,
|
|
82
|
+
"result": result,
|
|
83
|
+
"error": error,
|
|
84
|
+
}
|
|
85
|
+
if task_id in self.upload_progress:
|
|
86
|
+
self.upload_progress[task_id]["status"] = status
|
|
87
|
+
|
|
88
|
+
def _update_progress(
|
|
89
|
+
self,
|
|
90
|
+
task_id: str,
|
|
91
|
+
*,
|
|
92
|
+
status: str | None = None,
|
|
93
|
+
file_index: int | None = None,
|
|
94
|
+
file_name: str | None = None,
|
|
95
|
+
stage: str | None = None,
|
|
96
|
+
current: int | None = None,
|
|
97
|
+
total: int | None = None,
|
|
98
|
+
) -> None:
|
|
99
|
+
if task_id not in self.upload_progress:
|
|
100
|
+
return
|
|
101
|
+
p = self.upload_progress[task_id]
|
|
102
|
+
if status is not None:
|
|
103
|
+
p["status"] = status
|
|
104
|
+
if file_index is not None:
|
|
105
|
+
p["file_index"] = file_index
|
|
106
|
+
if file_name is not None:
|
|
107
|
+
p["file_name"] = file_name
|
|
108
|
+
if stage is not None:
|
|
109
|
+
p["stage"] = stage
|
|
110
|
+
if current is not None:
|
|
111
|
+
p["current"] = current
|
|
112
|
+
if total is not None:
|
|
113
|
+
p["total"] = total
|
|
114
|
+
|
|
115
|
+
def _make_progress_callback(self, task_id: str, file_idx: int, file_name: str):
|
|
116
|
+
async def _callback(stage: str, current: int, total: int):
|
|
117
|
+
self._update_progress(
|
|
118
|
+
task_id,
|
|
119
|
+
status="processing",
|
|
120
|
+
file_index=file_idx,
|
|
121
|
+
file_name=file_name,
|
|
122
|
+
stage=stage,
|
|
123
|
+
current=current,
|
|
124
|
+
total=total,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
return _callback
|
|
128
|
+
|
|
69
129
|
async def _background_upload_task(
|
|
70
130
|
self,
|
|
71
131
|
task_id: str,
|
|
@@ -80,11 +140,7 @@ class KnowledgeBaseRoute(Route):
|
|
|
80
140
|
"""后台上传任务"""
|
|
81
141
|
try:
|
|
82
142
|
# 初始化任务状态
|
|
83
|
-
self.
|
|
84
|
-
"status": "processing",
|
|
85
|
-
"result": None,
|
|
86
|
-
"error": None,
|
|
87
|
-
}
|
|
143
|
+
self._init_task(task_id, status="processing")
|
|
88
144
|
self.upload_progress[task_id] = {
|
|
89
145
|
"status": "processing",
|
|
90
146
|
"file_index": 0,
|
|
@@ -100,30 +156,20 @@ class KnowledgeBaseRoute(Route):
|
|
|
100
156
|
for file_idx, file_info in enumerate(files_to_upload):
|
|
101
157
|
try:
|
|
102
158
|
# 更新整体进度
|
|
103
|
-
self.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
},
|
|
159
|
+
self._update_progress(
|
|
160
|
+
task_id,
|
|
161
|
+
status="processing",
|
|
162
|
+
file_index=file_idx,
|
|
163
|
+
file_name=file_info["file_name"],
|
|
164
|
+
stage="parsing",
|
|
165
|
+
current=0,
|
|
166
|
+
total=100,
|
|
112
167
|
)
|
|
113
168
|
|
|
114
169
|
# 创建进度回调函数
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
"status": "processing",
|
|
120
|
-
"file_index": file_idx,
|
|
121
|
-
"file_name": file_info["file_name"],
|
|
122
|
-
"stage": stage,
|
|
123
|
-
"current": current,
|
|
124
|
-
"total": total,
|
|
125
|
-
},
|
|
126
|
-
)
|
|
170
|
+
progress_callback = self._make_progress_callback(
|
|
171
|
+
task_id, file_idx, file_info["file_name"]
|
|
172
|
+
)
|
|
127
173
|
|
|
128
174
|
doc = await kb_helper.upload_document(
|
|
129
175
|
file_name=file_info["file_name"],
|
|
@@ -154,23 +200,99 @@ class KnowledgeBaseRoute(Route):
|
|
|
154
200
|
"failed_count": len(failed_docs),
|
|
155
201
|
}
|
|
156
202
|
|
|
157
|
-
self.
|
|
158
|
-
"status": "completed",
|
|
159
|
-
"result": result,
|
|
160
|
-
"error": None,
|
|
161
|
-
}
|
|
162
|
-
self.upload_progress[task_id]["status"] = "completed"
|
|
203
|
+
self._set_task_result(task_id, "completed", result=result)
|
|
163
204
|
|
|
164
205
|
except Exception as e:
|
|
165
206
|
logger.error(f"后台上传任务 {task_id} 失败: {e}")
|
|
166
207
|
logger.error(traceback.format_exc())
|
|
167
|
-
self.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
208
|
+
self._set_task_result(task_id, "failed", error=str(e))
|
|
209
|
+
|
|
210
|
+
async def _background_import_task(
|
|
211
|
+
self,
|
|
212
|
+
task_id: str,
|
|
213
|
+
kb_helper,
|
|
214
|
+
documents: list,
|
|
215
|
+
batch_size: int,
|
|
216
|
+
tasks_limit: int,
|
|
217
|
+
max_retries: int,
|
|
218
|
+
):
|
|
219
|
+
"""后台导入预切片文档任务"""
|
|
220
|
+
try:
|
|
221
|
+
# 初始化任务状态
|
|
222
|
+
self._init_task(task_id, status="processing")
|
|
223
|
+
self.upload_progress[task_id] = {
|
|
224
|
+
"status": "processing",
|
|
225
|
+
"file_index": 0,
|
|
226
|
+
"file_total": len(documents),
|
|
227
|
+
"stage": "waiting",
|
|
228
|
+
"current": 0,
|
|
229
|
+
"total": 100,
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
uploaded_docs = []
|
|
233
|
+
failed_docs = []
|
|
234
|
+
|
|
235
|
+
for file_idx, doc_info in enumerate(documents):
|
|
236
|
+
file_name = doc_info.get("file_name", f"imported_doc_{file_idx}")
|
|
237
|
+
chunks = doc_info.get("chunks", [])
|
|
238
|
+
|
|
239
|
+
try:
|
|
240
|
+
# 更新整体进度
|
|
241
|
+
self._update_progress(
|
|
242
|
+
task_id,
|
|
243
|
+
status="processing",
|
|
244
|
+
file_index=file_idx,
|
|
245
|
+
file_name=file_name,
|
|
246
|
+
stage="importing",
|
|
247
|
+
current=0,
|
|
248
|
+
total=100,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# 创建进度回调函数
|
|
252
|
+
progress_callback = self._make_progress_callback(
|
|
253
|
+
task_id, file_idx, file_name
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# 调用 upload_document,传入 pre_chunked_text
|
|
257
|
+
doc = await kb_helper.upload_document(
|
|
258
|
+
file_name=file_name,
|
|
259
|
+
file_content=None, # 预切片模式下不需要原始内容
|
|
260
|
+
file_type=doc_info.get("file_type")
|
|
261
|
+
or (
|
|
262
|
+
file_name.rsplit(".", 1)[-1].lower()
|
|
263
|
+
if "." in file_name
|
|
264
|
+
else "txt"
|
|
265
|
+
),
|
|
266
|
+
batch_size=batch_size,
|
|
267
|
+
tasks_limit=tasks_limit,
|
|
268
|
+
max_retries=max_retries,
|
|
269
|
+
progress_callback=progress_callback,
|
|
270
|
+
pre_chunked_text=chunks,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
uploaded_docs.append(doc.model_dump())
|
|
274
|
+
except Exception as e:
|
|
275
|
+
logger.error(f"导入文档 {file_name} 失败: {e}")
|
|
276
|
+
failed_docs.append(
|
|
277
|
+
{"file_name": file_name, "error": str(e)},
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# 更新任务完成状态
|
|
281
|
+
result = {
|
|
282
|
+
"task_id": task_id,
|
|
283
|
+
"uploaded": uploaded_docs,
|
|
284
|
+
"failed": failed_docs,
|
|
285
|
+
"total": len(documents),
|
|
286
|
+
"success_count": len(uploaded_docs),
|
|
287
|
+
"failed_count": len(failed_docs),
|
|
171
288
|
}
|
|
172
|
-
|
|
173
|
-
|
|
289
|
+
|
|
290
|
+
self._set_task_result(task_id, "completed", result=result)
|
|
291
|
+
|
|
292
|
+
except Exception as e:
|
|
293
|
+
logger.error(f"后台导入任务 {task_id} 失败: {e}")
|
|
294
|
+
logger.error(traceback.format_exc())
|
|
295
|
+
self._set_task_result(task_id, "failed", error=str(e))
|
|
174
296
|
|
|
175
297
|
async def list_kbs(self):
|
|
176
298
|
"""获取知识库列表
|
|
@@ -614,11 +736,7 @@ class KnowledgeBaseRoute(Route):
|
|
|
614
736
|
task_id = str(uuid.uuid4())
|
|
615
737
|
|
|
616
738
|
# 初始化任务状态
|
|
617
|
-
self.
|
|
618
|
-
"status": "pending",
|
|
619
|
-
"result": None,
|
|
620
|
-
"error": None,
|
|
621
|
-
}
|
|
739
|
+
self._init_task(task_id, status="pending")
|
|
622
740
|
|
|
623
741
|
# 启动后台任务
|
|
624
742
|
asyncio.create_task(
|
|
@@ -653,6 +771,93 @@ class KnowledgeBaseRoute(Route):
|
|
|
653
771
|
logger.error(traceback.format_exc())
|
|
654
772
|
return Response().error(f"上传文档失败: {e!s}").__dict__
|
|
655
773
|
|
|
774
|
+
def _validate_import_request(self, data: dict):
|
|
775
|
+
kb_id = data.get("kb_id")
|
|
776
|
+
if not kb_id:
|
|
777
|
+
raise ValueError("缺少参数 kb_id")
|
|
778
|
+
|
|
779
|
+
documents = data.get("documents")
|
|
780
|
+
if not documents or not isinstance(documents, list):
|
|
781
|
+
raise ValueError("缺少参数 documents 或格式错误")
|
|
782
|
+
|
|
783
|
+
for doc in documents:
|
|
784
|
+
if "file_name" not in doc or "chunks" not in doc:
|
|
785
|
+
raise ValueError("文档格式错误,必须包含 file_name 和 chunks")
|
|
786
|
+
if not isinstance(doc["chunks"], list):
|
|
787
|
+
raise ValueError("chunks 必须是列表")
|
|
788
|
+
if not all(
|
|
789
|
+
isinstance(chunk, str) and chunk.strip() for chunk in doc["chunks"]
|
|
790
|
+
):
|
|
791
|
+
raise ValueError("chunks 必须是非空字符串列表")
|
|
792
|
+
|
|
793
|
+
batch_size = data.get("batch_size", 32)
|
|
794
|
+
tasks_limit = data.get("tasks_limit", 3)
|
|
795
|
+
max_retries = data.get("max_retries", 3)
|
|
796
|
+
return kb_id, documents, batch_size, tasks_limit, max_retries
|
|
797
|
+
|
|
798
|
+
async def import_documents(self):
|
|
799
|
+
"""导入预切片文档
|
|
800
|
+
|
|
801
|
+
Body:
|
|
802
|
+
- kb_id: 知识库 ID (必填)
|
|
803
|
+
- documents: 文档列表 (必填)
|
|
804
|
+
- file_name: 文件名 (必填)
|
|
805
|
+
- chunks: 切片列表 (必填, list[str])
|
|
806
|
+
- file_type: 文件类型 (可选, 默认从文件名推断或为 txt)
|
|
807
|
+
- batch_size: 批处理大小 (可选, 默认32)
|
|
808
|
+
- tasks_limit: 并发任务限制 (可选, 默认3)
|
|
809
|
+
- max_retries: 最大重试次数 (可选, 默认3)
|
|
810
|
+
"""
|
|
811
|
+
try:
|
|
812
|
+
kb_manager = self._get_kb_manager()
|
|
813
|
+
data = await request.json
|
|
814
|
+
|
|
815
|
+
kb_id, documents, batch_size, tasks_limit, max_retries = (
|
|
816
|
+
self._validate_import_request(data)
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
# 获取知识库
|
|
820
|
+
kb_helper = await kb_manager.get_kb(kb_id)
|
|
821
|
+
if not kb_helper:
|
|
822
|
+
return Response().error("知识库不存在").__dict__
|
|
823
|
+
|
|
824
|
+
# 生成任务ID
|
|
825
|
+
task_id = str(uuid.uuid4())
|
|
826
|
+
|
|
827
|
+
# 初始化任务状态
|
|
828
|
+
self._init_task(task_id, status="pending")
|
|
829
|
+
|
|
830
|
+
# 启动后台任务
|
|
831
|
+
asyncio.create_task(
|
|
832
|
+
self._background_import_task(
|
|
833
|
+
task_id=task_id,
|
|
834
|
+
kb_helper=kb_helper,
|
|
835
|
+
documents=documents,
|
|
836
|
+
batch_size=batch_size,
|
|
837
|
+
tasks_limit=tasks_limit,
|
|
838
|
+
max_retries=max_retries,
|
|
839
|
+
),
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
return (
|
|
843
|
+
Response()
|
|
844
|
+
.ok(
|
|
845
|
+
{
|
|
846
|
+
"task_id": task_id,
|
|
847
|
+
"doc_count": len(documents),
|
|
848
|
+
"message": "import task created, processing in background",
|
|
849
|
+
},
|
|
850
|
+
)
|
|
851
|
+
.__dict__
|
|
852
|
+
)
|
|
853
|
+
|
|
854
|
+
except ValueError as e:
|
|
855
|
+
return Response().error(str(e)).__dict__
|
|
856
|
+
except Exception as e:
|
|
857
|
+
logger.error(f"导入文档失败: {e}")
|
|
858
|
+
logger.error(traceback.format_exc())
|
|
859
|
+
return Response().error(f"导入文档失败: {e!s}").__dict__
|
|
860
|
+
|
|
656
861
|
async def get_upload_progress(self):
|
|
657
862
|
"""获取上传进度和结果
|
|
658
863
|
|
|
@@ -960,11 +1165,7 @@ class KnowledgeBaseRoute(Route):
|
|
|
960
1165
|
task_id = str(uuid.uuid4())
|
|
961
1166
|
|
|
962
1167
|
# 初始化任务状态
|
|
963
|
-
self.
|
|
964
|
-
"status": "pending",
|
|
965
|
-
"result": None,
|
|
966
|
-
"error": None,
|
|
967
|
-
}
|
|
1168
|
+
self._init_task(task_id, status="pending")
|
|
968
1169
|
|
|
969
1170
|
# 启动后台任务
|
|
970
1171
|
asyncio.create_task(
|
|
@@ -1017,11 +1218,7 @@ class KnowledgeBaseRoute(Route):
|
|
|
1017
1218
|
"""后台上传URL任务"""
|
|
1018
1219
|
try:
|
|
1019
1220
|
# 初始化任务状态
|
|
1020
|
-
self.
|
|
1021
|
-
"status": "processing",
|
|
1022
|
-
"result": None,
|
|
1023
|
-
"error": None,
|
|
1024
|
-
}
|
|
1221
|
+
self._init_task(task_id, status="processing")
|
|
1025
1222
|
self.upload_progress[task_id] = {
|
|
1026
1223
|
"status": "processing",
|
|
1027
1224
|
"file_index": 0,
|
|
@@ -1033,18 +1230,7 @@ class KnowledgeBaseRoute(Route):
|
|
|
1033
1230
|
}
|
|
1034
1231
|
|
|
1035
1232
|
# 创建进度回调函数
|
|
1036
|
-
|
|
1037
|
-
if task_id in self.upload_progress:
|
|
1038
|
-
self.upload_progress[task_id].update(
|
|
1039
|
-
{
|
|
1040
|
-
"status": "processing",
|
|
1041
|
-
"file_index": 0,
|
|
1042
|
-
"file_name": f"URL: {url}",
|
|
1043
|
-
"stage": stage,
|
|
1044
|
-
"current": current,
|
|
1045
|
-
"total": total,
|
|
1046
|
-
},
|
|
1047
|
-
)
|
|
1233
|
+
progress_callback = self._make_progress_callback(task_id, 0, f"URL: {url}")
|
|
1048
1234
|
|
|
1049
1235
|
# 上传文档
|
|
1050
1236
|
doc = await kb_helper.upload_from_url(
|
|
@@ -1069,20 +1255,9 @@ class KnowledgeBaseRoute(Route):
|
|
|
1069
1255
|
"failed_count": 0,
|
|
1070
1256
|
}
|
|
1071
1257
|
|
|
1072
|
-
self.
|
|
1073
|
-
"status": "completed",
|
|
1074
|
-
"result": result,
|
|
1075
|
-
"error": None,
|
|
1076
|
-
}
|
|
1077
|
-
self.upload_progress[task_id]["status"] = "completed"
|
|
1258
|
+
self._set_task_result(task_id, "completed", result=result)
|
|
1078
1259
|
|
|
1079
1260
|
except Exception as e:
|
|
1080
1261
|
logger.error(f"后台上传URL任务 {task_id} 失败: {e}")
|
|
1081
1262
|
logger.error(traceback.format_exc())
|
|
1082
|
-
self.
|
|
1083
|
-
"status": "failed",
|
|
1084
|
-
"result": None,
|
|
1085
|
-
"error": str(e),
|
|
1086
|
-
}
|
|
1087
|
-
if task_id in self.upload_progress:
|
|
1088
|
-
self.upload_progress[task_id]["status"] = "failed"
|
|
1263
|
+
self._set_task_result(task_id, "failed", error=str(e))
|
astrbot/dashboard/routes/log.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import json
|
|
3
|
+
from typing import cast
|
|
3
4
|
|
|
5
|
+
from quart import Response as QuartResponse
|
|
4
6
|
from quart import make_response
|
|
5
7
|
|
|
6
8
|
from astrbot.core import LogBroker, logger
|
|
@@ -39,14 +41,17 @@ class LogRoute(Route):
|
|
|
39
41
|
if queue:
|
|
40
42
|
self.log_broker.unregister(queue)
|
|
41
43
|
|
|
42
|
-
response =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
response = cast(
|
|
45
|
+
QuartResponse,
|
|
46
|
+
await make_response(
|
|
47
|
+
stream(),
|
|
48
|
+
{
|
|
49
|
+
"Content-Type": "text/event-stream",
|
|
50
|
+
"Cache-Control": "no-cache",
|
|
51
|
+
"Connection": "keep-alive",
|
|
52
|
+
"Transfer-Encoding": "chunked",
|
|
53
|
+
},
|
|
54
|
+
),
|
|
50
55
|
)
|
|
51
56
|
response.timeout = None
|
|
52
57
|
return response
|
|
@@ -82,7 +82,7 @@ class PlatformRoute(Route):
|
|
|
82
82
|
"""
|
|
83
83
|
for platform in self.platform_manager.platform_insts:
|
|
84
84
|
if platform.config.get("webhook_uuid") == webhook_uuid:
|
|
85
|
-
if platform.
|
|
85
|
+
if platform.unified_webhook():
|
|
86
86
|
return platform
|
|
87
87
|
return None
|
|
88
88
|
|