feat: 前端页面优化与入库任务重试/删除

- 概览与检索合并为单一概览页
- 类目/文档管理/入库整合为树形目录知识库页(Library),支持文档搜索
- 入库进度改为右侧 Drawer,支持任务详情、重试、删除
- 后端新增任务重试与删除接口
This commit is contained in:
2026-08-04 12:58:11 +08:00
parent f0fc20a9b6
commit 35b7decd49
16 changed files with 1630 additions and 1432 deletions
+50
View File
@@ -80,6 +80,7 @@ class IngestTaskManager:
task_id = uuid.uuid4().hex
now = _utc_now_iso()
filename = self._extract_filename(doc)
source = self._extract_source(doc)
dedup = get_dedup_strategy(self._redis)
# 1. 去重命中:直接置 done,复用旧结果,不调 _run
@@ -95,6 +96,7 @@ class IngestTaskManager:
"result": result_dict,
"error": None,
"filename": filename,
"source": source,
}
self._schedule_mirror(task_id)
logger.info(
@@ -113,6 +115,7 @@ class IngestTaskManager:
"result": None,
"error": None,
"filename": filename,
"source": source,
}
self._schedule_mirror(task_id)
background = asyncio.create_task(self._run(task_id, doc, dedup))
@@ -190,15 +193,62 @@ class IngestTaskManager:
"""从文档输入提取展示用文件名:优先 metadata.original_filename,其次 title"""
return doc.metadata.get("original_filename") or doc.title or None
@staticmethod
def _extract_source(doc: DocumentInput) -> dict[str, Any]:
"""从文档输入提取重试所需的源信息(供 retry 复用,含文件路径/大小)"""
return {
"text": doc.text,
"title": doc.title,
"source": doc.source,
"metadata": dict(doc.metadata),
}
async def retry(self, task_id: str) -> str | None:
"""重试失败/已完成的入库任务:用原 source 重新提交一个新任务
返回新 task_id;任务不存在或缺少 source 时返回 None。
"""
record = await self.get(task_id)
if record is None:
return None
source = record.get("source")
if not isinstance(source, dict) or not source.get("text"):
return None
doc = DocumentInput(
text=source["text"],
title=source.get("title") or "",
source=source.get("source") or "",
metadata=source.get("metadata") or {},
)
return await self.submit(doc)
async def delete(self, task_id: str) -> bool:
"""删除入库任务(内存注册表 + Redis 镜像),不存在返回 False"""
existed = self._tasks.pop(task_id, None) is not None
if self._redis is not None:
try:
get_client = getattr(self._redis, "_get_client", None)
if callable(get_client):
await get_client().delete(f"{REDIS_KEY_PREFIX}{task_id}")
existed = True
except Exception:
logger.warning("删除 Redis 任务镜像失败", task_id=task_id, exc_info=True)
return existed
@staticmethod
def _to_list_item(record: dict[str, Any]) -> dict[str, Any]:
"""从完整任务记录提取列表展示字段"""
result = record.get("result")
doc_id = result.get("document_id") if isinstance(result, dict) else None
source = record.get("source") or {}
metadata = source.get("metadata") or {}
return {
"task_id": record.get("task_id"),
"status": record.get("status"),
"filename": record.get("filename"),
"title": source.get("title"),
"source": source.get("source"),
"size_bytes": metadata.get("original_size_bytes"),
"created_at": record.get("created_at"),
"updated_at": record.get("updated_at"),
"doc_id": doc_id,