split.py 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. """拆分:把帖子拆成一个或多个 What/Why/How 知识片段。"""
  2. from __future__ import annotations
  3. from typing import Optional
  4. from creation_knowledge.integrations.llm import ChatFn, default_chat
  5. from creation_knowledge.models import ExtractedContent, KnowledgeItem, Post
  6. from creation_knowledge.prompts import load_prompt
  7. from creation_knowledge.stages._common import content_for_llm, norm_text, norm_types
  8. SYSTEM = "你是创作知识拆分助手,原文有什么提什么,不编造。"
  9. def _to_item(raw: dict) -> Optional[KnowledgeItem]:
  10. what = norm_text(raw.get("what"))
  11. why = norm_text(raw.get("why"))
  12. how = norm_text(raw.get("how"))
  13. # knowledge_types 以非空字段为准(模型给的若不一致,用实际有内容的对齐)
  14. types = norm_types(raw.get("knowledge_types"))
  15. actual = [t for t, v in (("what", what), ("why", why), ("how", how)) if v]
  16. types = [t for t in types if t in actual] or actual
  17. if not types:
  18. return None # 三个都空,丢弃
  19. title = norm_text(raw.get("title")) or (what or why or how or "")[:20]
  20. evidence = [e for e in (raw.get("evidence") or []) if norm_text(e)]
  21. return KnowledgeItem(
  22. title=title, knowledge_types=types, what=what, why=why, how=how,
  23. evidence=[str(e).strip() for e in evidence],
  24. )
  25. def split_post(
  26. post: Post,
  27. content: ExtractedContent,
  28. *,
  29. chat: Optional[ChatFn] = None,
  30. env_file: str = ".env",
  31. ) -> list[KnowledgeItem]:
  32. chat = chat or default_chat(env_file)
  33. user = load_prompt("split").format(
  34. title=post.title or "(无)",
  35. topics="、".join(post.topic_list) or "(无)",
  36. content=content_for_llm(post, content) or "(空)",
  37. )
  38. data = chat(SYSTEM, user)
  39. items = [_to_item(raw) for raw in (data.get("items") or [])]
  40. return [it for it in items if it is not None]