models.py 3.7 KB

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