feat: 新增风险规则生成引擎与知识图谱可视化

后端新增风险规则自动生成和模板执行服务,支持从规则资产
批量生成并持久化风险规则文件;知识库入库日志增强图谱
查询和本地 RAG 回退,前端审计页面增加风险规则模型和流
程图组件,知识入库面板拆分为图谱可视化子组件,报销创
建页面增加引导式流程模型,更新知识库索引数据。
This commit is contained in:
caoxiaozhu
2026-05-23 19:54:42 +08:00
parent 5b388d08c0
commit 575f093c74
63 changed files with 35497 additions and 1517 deletions

View File

@@ -480,6 +480,7 @@ def _build_initial_knowledge_ingest_document(
"entity_count": 0,
"relation_count": 0,
"entities": [],
"entity_chunks": [],
"relations": [],
"events": [
{
@@ -677,7 +678,7 @@ def _build_ingest_graph(knowledge_ingest: dict[str, Any]) -> dict[str, Any]:
documents = [
item for item in list(knowledge_ingest.get("documents") or []) if isinstance(item, dict)
]
entities = _dedupe_text_items(
entities = _dedupe_entities(
entity for document in documents for entity in list(document.get("entities") or [])
)
relations = _dedupe_relations(
@@ -692,20 +693,52 @@ def _build_ingest_graph(knowledge_ingest: dict[str, Any]) -> dict[str, Any]:
}
def _dedupe_text_items(items: Any) -> list[str]:
deduped: list[str] = []
def _dedupe_entities(items: Any) -> list[dict[str, Any]]:
deduped: list[dict[str, Any]] = []
seen: set[str] = set()
for item in items:
text = str(item or "").strip()
if not text or text in seen:
if isinstance(item, dict):
name = str(
item.get("name")
or item.get("entity")
or item.get("entity_id")
or item.get("title")
or item.get("id")
or ""
).strip()
entity = dict(item)
else:
name = str(item or "").strip()
entity = {}
if not name or name in seen:
continue
seen.add(text)
deduped.append(text)
seen.add(name)
entity["name"] = name
entity["type"] = str(
entity.get("type")
or entity.get("entity_type")
or entity.get("category")
or entity.get("kind")
or "实体"
).strip()
description = str(entity.get("description") or "").strip()
descriptions = entity.get("descriptions")
if not isinstance(descriptions, list):
descriptions = [description] if description else []
entity["description"] = description
entity["descriptions"] = [
str(description_item or "").strip()
for description_item in descriptions
if str(description_item or "").strip()
][:5]
if not isinstance(entity.get("properties"), dict):
entity["properties"] = {}
deduped.append(entity)
return deduped
def _dedupe_relations(items: Any) -> list[dict[str, str]]:
deduped: list[dict[str, str]] = []
def _dedupe_relations(items: Any) -> list[dict[str, Any]]:
deduped: list[dict[str, Any]] = []
seen: set[tuple[str, str, str]] = set()
for item in items:
if not isinstance(item, dict):
@@ -717,7 +750,7 @@ def _dedupe_relations(items: Any) -> list[dict[str, str]]:
if not source or not target or key in seen:
continue
seen.add(key)
deduped.append({"source": source, "target": target, "type": relation_type})
deduped.append({**item, "source": source, "target": target, "type": relation_type})
return deduped