初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,113 @@
|
||||
"""导入资料结构解析(纯函数,无 IO)。
|
||||
|
||||
按 ``material_type`` / ``format`` 把原始资料切片为条目草稿。只做结构解析
|
||||
(消息数组、段落、字段),语义抽取(档案 / 记忆 / 人格候选)留给后续
|
||||
模型驱动阶段。领域层禁止 IO,本模块仅产出数据结构。
|
||||
"""
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
# 5a 不切片的媒体资料(仅存元数据与授权记录,spec §18 仅预留)。
|
||||
_NON_TEXT_MATERIAL_TYPES = {"voice_sample"}
|
||||
|
||||
|
||||
@dataclass
|
||||
class ParsedItemDraft:
|
||||
"""解析产出的条目草稿;落库前由 service 补 sequence / id。"""
|
||||
|
||||
item_type: str
|
||||
role: str
|
||||
content: str
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
def parse_import(
|
||||
material_type: str, fmt: str, *, content: str | None = None
|
||||
) -> list[ParsedItemDraft]:
|
||||
"""按格式解析文本资料;媒体资料返回空。"""
|
||||
if material_type in _NON_TEXT_MATERIAL_TYPES:
|
||||
return []
|
||||
|
||||
if fmt == "json" and content:
|
||||
return _parse_json(content)
|
||||
|
||||
if content:
|
||||
return _parse_paragraphs(content)
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def _parse_json(content: str) -> list[ParsedItemDraft]:
|
||||
try:
|
||||
data = json.loads(content)
|
||||
except json.JSONDecodeError:
|
||||
return _parse_paragraphs(content)
|
||||
|
||||
if (
|
||||
isinstance(data, list)
|
||||
and data
|
||||
and isinstance(data[0], dict)
|
||||
and ("role" in data[0] or "content" in data[0])
|
||||
):
|
||||
return _parse_messages(data)
|
||||
if isinstance(data, dict):
|
||||
return _parse_fields(data)
|
||||
return _parse_paragraphs(content)
|
||||
|
||||
|
||||
def _parse_messages(messages: list[dict[str, Any]]) -> list[ParsedItemDraft]:
|
||||
drafts: list[ParsedItemDraft] = []
|
||||
for msg in messages:
|
||||
if not isinstance(msg, dict):
|
||||
continue
|
||||
text = str(msg.get("content", "")).strip()
|
||||
if not text:
|
||||
continue
|
||||
meta = {k: v for k, v in msg.items() if k not in ("role", "content")}
|
||||
drafts.append(
|
||||
ParsedItemDraft(
|
||||
item_type="message",
|
||||
role=_normalize_role(str(msg.get("role", "other"))),
|
||||
content=text,
|
||||
metadata=meta,
|
||||
)
|
||||
)
|
||||
return drafts
|
||||
|
||||
|
||||
def _parse_fields(data: dict[str, Any]) -> list[ParsedItemDraft]:
|
||||
drafts: list[ParsedItemDraft] = []
|
||||
for key, value in data.items():
|
||||
text = str(value).strip()
|
||||
if text:
|
||||
drafts.append(
|
||||
ParsedItemDraft(
|
||||
item_type="profile_field",
|
||||
role="other",
|
||||
content=text,
|
||||
metadata={"field": key},
|
||||
)
|
||||
)
|
||||
return drafts
|
||||
|
||||
|
||||
def _parse_paragraphs(text: str) -> list[ParsedItemDraft]:
|
||||
drafts: list[ParsedItemDraft] = []
|
||||
for chunk in text.split("\n\n"):
|
||||
clean = chunk.strip()
|
||||
if clean:
|
||||
drafts.append(ParsedItemDraft(item_type="paragraph", role="other", content=clean))
|
||||
return drafts
|
||||
|
||||
|
||||
def _normalize_role(role: str) -> str:
|
||||
lowered = role.lower()
|
||||
if lowered in ("user", "human"):
|
||||
return "user"
|
||||
if lowered in ("assistant", "ai", "bot"):
|
||||
return "assistant"
|
||||
if lowered == "system":
|
||||
return "system"
|
||||
return "other"
|
||||
Reference in new issue
Block a user