wx-agent/wiki_engine/chunk_enhancer.py

101 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import hashlib
import re
from collections import Counter
from typing import Any, Dict, Iterable, List
STOPWORDS = {
"", "", "", "", "", "", "", "", "", "", "", "",
"进行", "使用", "相关", "根据", "如下", "可以", "需要", "应当", "以及",
}
def enhance_slices(
slices: Iterable[Dict[str, Any]],
file_info: Dict[str, Any],
max_slices: int,
) -> List[Dict[str, Any]]:
refs: List[Dict[str, Any]] = []
filename = str(file_info.get("filename") or file_info.get("name") or "")
kb_id = str(file_info.get("kb_id") or "")
file_id = str(file_info.get("file_id") or file_info.get("id") or "")
for idx, raw in enumerate(list(slices)[:max_slices]):
text = _slice_text(raw)
if not text.strip():
continue
slice_id = str(raw.get("id") or raw.get("slice_id") or raw.get("uuid") or f"{file_id}:{idx}")
title_path = _infer_title_path(text, filename)
keywords = extract_keywords(text, limit=12)
refs.append({
"kb_id": str(raw.get("kb_id") or kb_id),
"file_id": str(raw.get("file_id") or file_id),
"slice_id": slice_id,
"ordinal": int(raw.get("ordinal") or raw.get("index") or idx),
"filename": str(raw.get("filename") or filename),
"title_path": title_path,
"keywords": keywords,
"brief": _brief(text),
"chunk_type": _infer_chunk_type(text),
"content_hash": hashlib.sha1(text.encode("utf-8", errors="ignore")).hexdigest(),
"_text": text,
})
return refs
def extract_keywords(text: str, limit: int = 10) -> List[str]:
text = normalize_text(text)
candidates = re.findall(r"[\u4e00-\u9fff]{2,12}|[A-Za-z0-9][A-Za-z0-9_\-]{1,30}", text)
normalized: List[str] = []
for token in candidates:
token = token.strip(":,。.;;、()()[]【】")
if len(token) < 2 or token in STOPWORDS:
continue
if re.fullmatch(r"\d+", token):
continue
normalized.append(token)
counts = Counter(normalized)
return [term for term, _ in counts.most_common(limit)]
def normalize_text(text: str) -> str:
return re.sub(r"\s+", " ", text or "").strip()
def _slice_text(raw: Dict[str, Any]) -> str:
for key in ("content", "text", "page_content", "slice_content", "markdown"):
value = raw.get(key)
if isinstance(value, str) and value.strip():
return value
return ""
def _brief(text: str, limit: int = 360) -> str:
return normalize_text(text)[:limit]
def _infer_title_path(text: str, filename: str) -> List[str]:
path = []
if filename:
path.append(filename)
lines = [line.strip() for line in (text or "").splitlines() if line.strip()]
for line in lines[:6]:
line = re.sub(r"^#+\s*", "", line).strip()
if 2 <= len(line) <= 50 and not line.endswith(("", ".", "", ";")):
path.append(line)
break
return path[:4] if path else []
def _infer_chunk_type(text: str) -> str:
compact = normalize_text(text)
if "|" in text and "---" in text:
return "table"
if re.search(r"(步骤|流程|操作|检查|确认|打开|关闭|启动|停止)", compact):
return "procedure"
if re.search(r"(故障|异常|报警|失效|原因|处理|排查)", compact):
return "fault"
if re.search(r"!\[.*?\]\(.*?\)", text):
return "image"
return "text"