models.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. """流水线各环节的数据结构(pydantic)。字段对齐业务设计 创作知识-重构设计.md。"""
  2. from __future__ import annotations
  3. from typing import Literal, Optional
  4. from pydantic import BaseModel, Field
  5. KnowledgeType = Literal["what", "why", "how"]
  6. ScopeType = Literal["substance", "form", "feeling", "effect", "intent"]
  7. Stage = Literal["灵感", "选题", "脚本"]
  8. CardKind = Literal["image", "frame"]
  9. class Card(BaseModel):
  10. """一张"卡片":图文帖的一张图,或视频抽出的一帧。下游溯源只认 index。"""
  11. index: int # 帖内顺序号,从 0 起
  12. kind: CardKind = "image"
  13. url: str
  14. timestamp: Optional[float] = None # 仅 frame:该帧在视频中的秒数
  15. class Post(BaseModel):
  16. """fetch_post_detail 的产物:一条帖子的原始内容(文本 + 图片 + 视频)。"""
  17. id: str # xhs_<content_id>,复用为 ingest source.id
  18. platform: str = "xiaohongshu"
  19. url: str
  20. content_id: str
  21. title: str = ""
  22. content_type: str = "" # video / 图文
  23. body_text: str = ""
  24. topic_list: list[str] = Field(default_factory=list)
  25. image_urls: list[str] = Field(default_factory=list)
  26. video_urls: list[str] = Field(default_factory=list)
  27. cards: list[Card] = Field(default_factory=list) # 统一视觉卡片(图/帧)
  28. author_id: Optional[str] = None
  29. author_name: Optional[str] = None
  30. raw: dict = Field(default_factory=dict) # 原始响应,整体落 ck_post.raw
  31. class CardExtract(BaseModel):
  32. """某张卡片上提取到的知识要点(按卡片归因)。"""
  33. index: int
  34. content: str = ""
  35. class ExtractedContent(BaseModel):
  36. """extract_content 的产物:多模态汇总后的真实内容。不直接用 body_text。"""
  37. text: str = "" # 汇总后的正文/讲解
  38. cards: list[CardExtract] = Field(default_factory=list) # 按卡片归因的提取
  39. from_image: str = "" # 兼容保留:图片里提取到的知识要点
  40. from_video: str = "" # 兼容保留:视频里提取到的知识要点
  41. is_empty: bool = False # 多模态提取后仍无有效内容
  42. class ScreeningResult(BaseModel):
  43. """screen_post 的产物。"""
  44. passed: bool
  45. score: int = 0
  46. reason: str = ""
  47. class Evidence(BaseModel):
  48. """一条原文证据,链接到它出自的卡片(纯正文证据 card=None)。"""
  49. text: str
  50. card: Optional[int] = None
  51. class KnowledgeItem(BaseModel):
  52. """split_post 拆出的一个知识片段。knowledge_types 必须与非空的 what/why/how 一致。"""
  53. title: str
  54. knowledge_types: list[KnowledgeType]
  55. what: Optional[str] = None
  56. why: Optional[str] = None
  57. how: Optional[str] = None
  58. source_cards: list[int] = Field(default_factory=list) # 这条知识出自哪些卡片
  59. evidence: list[Evidence] = Field(default_factory=list)
  60. class Scope(BaseModel):
  61. scope_type: ScopeType
  62. value: str # 具体标签,不只是大类名
  63. class Deconstruction(BaseModel):
  64. """deconstruct_item 的产物:阶段 + 作用域。"""
  65. stages: list[Stage] = Field(default_factory=list)
  66. scopes: list[Scope] = Field(default_factory=list)
  67. stage_reason: str = ""
  68. scope_reason: str = ""
  69. class IngestPayload(BaseModel):
  70. """build_ingest_payload 的产物:对齐 创作知识-重构设计.md §6 的 ingest 请求体。"""
  71. source: dict
  72. title: str
  73. content: str # JSON 字符串 {"what":...,"why":...,"how":...}
  74. dim_attributes: list[str]
  75. dim_creations: list[str]
  76. scopes: list[dict]
  77. custom_ext: list[dict] = Field(default_factory=list)