122 lines
4.2 KiB
Python
122 lines
4.2 KiB
Python
from typing import Annotated, List, Literal, Optional, TypedDict
|
|
import operator
|
|
|
|
# ── 素材 ──────────────────────────────────────────────────────────────────────
|
|
|
|
class Material(TypedDict):
|
|
id: str
|
|
title: str
|
|
content: str # 截断到 500 字
|
|
source: str
|
|
published_at: str
|
|
relevance_score: float
|
|
source_type: str # "internet" | "intranet"
|
|
url: str
|
|
recUuid: str
|
|
|
|
class MaterialPackage(TypedDict):
|
|
keywords: List[str]
|
|
materials: List[Material]
|
|
summary: str
|
|
|
|
# ── 大纲 ──────────────────────────────────────────────────────────────────────
|
|
|
|
class OutlineSection(TypedDict):
|
|
section_title: str
|
|
key_points: List[str]
|
|
material_ids: List[str]
|
|
|
|
class Outline(TypedDict):
|
|
title: str
|
|
sections: List[OutlineSection]
|
|
|
|
# ── 草稿 ──────────────────────────────────────────────────────────────────────
|
|
|
|
class DraftArticle(TypedDict):
|
|
title: str
|
|
outline: Outline
|
|
full_markdown: str
|
|
word_count: int
|
|
revision_count: int
|
|
|
|
# ── 编辑审核 ──────────────────────────────────────────────────────────────────
|
|
|
|
class ReviewIssue(TypedDict):
|
|
category: str # "fact" | "logic" | "language"
|
|
severity: str # "major" | "minor"
|
|
location: str
|
|
issue: str
|
|
suggestion: str
|
|
|
|
class ReviewResult(TypedDict):
|
|
verdict: str # "pass" | "reject"
|
|
fact_score: int
|
|
logic_score: int
|
|
language_score: int
|
|
overall_score: int
|
|
pass_threshold: int
|
|
revision_notes: List[ReviewIssue]
|
|
|
|
# ── 用户干预 ──────────────────────────────────────────────────────────────────
|
|
|
|
class UserInterventionPayload(TypedDict):
|
|
action: str
|
|
approved_material_ids: List[str]
|
|
extra_keywords: List[str]
|
|
edited_outline: Optional[Outline]
|
|
outline_feedback: str
|
|
user_revision_notes: str
|
|
override_verdict: bool
|
|
|
|
# ── 主状态 ────────────────────────────────────────────────────────────────────
|
|
|
|
WritingStatus = Literal[
|
|
"researching", "awaiting_material_confirm",
|
|
"writing_outline", "awaiting_outline_confirm",
|
|
"writing_draft", "awaiting_section_help", "awaiting_draft_confirm",
|
|
"reviewing", "awaiting_review_confirm",
|
|
"revising", "done", "error",
|
|
]
|
|
|
|
|
|
class BlockedSection(TypedDict):
|
|
"""严格模式下素材不足、无法写作的章节。"""
|
|
section_title: str
|
|
reason: str
|
|
|
|
class AIWritingState(TypedDict):
|
|
# 写作配置
|
|
user_intent: str
|
|
article_type: str
|
|
target_audience: str
|
|
word_count_target: int
|
|
# 素材检索关键词数量(用户指定,1~10,默认 6)
|
|
keyword_count: int
|
|
# 写作模式:strict=严格依据素材 / loose=可结合通用知识(默认 loose)
|
|
writing_mode: str
|
|
|
|
# Agent A 输出
|
|
material_package: Optional[MaterialPackage]
|
|
|
|
# Agent B 输出
|
|
current_outline: Optional[Outline]
|
|
drafts: Annotated[List[DraftArticle], operator.add]
|
|
current_draft: Optional[DraftArticle]
|
|
|
|
# Agent C 输出
|
|
review_result: Optional[ReviewResult]
|
|
|
|
# 用户干预数据(每个干预点会覆盖)
|
|
last_user_intervention: Optional[UserInterventionPayload]
|
|
|
|
# 严格模式下素材不足、待用户决策的章节(写作节点产出,求助暂停点消费)
|
|
blocked_sections: Optional[List[BlockedSection]]
|
|
|
|
# 流程控制
|
|
revision_count: int
|
|
max_revisions: int
|
|
status: WritingStatus
|
|
|
|
# SSE 进度推送队列(每个节点追加)
|
|
progress_events: Annotated[List[dict], operator.add]
|