"""Pydantic schemas for the Human Voice Rewrite demo API. Aligned with PRD v1.1 §31 (AI 输出结构建议): - §31.1 First Analysis -> AnalyzeRequest / AnalyzeResponse - §31.2 Human Voice Diagnosis -> DiagnoseRequest / DiagnoseResponse - §31.3 Recheck -> RecheckRequest / RecheckResponse Plus Progressive Help endpoints (PRD §22: Scaffold → Reference). """ from typing import Literal from pydantic import BaseModel, Field # ---------------------------------------------------------------- analyze class AnalyzeRequest(BaseModel): prompt: str = "" word_limit: int | None = None paragraphs: list[str] = Field(min_length=1) constraints: list[str] = [] # advisor constraints already known before first pass class ParagraphUnderstanding(BaseModel): id: str = "" original_text: str = "" natural_meaning_zh: str = "" # 接近自然翻译的一段中文 semantic_anchor: str = "" # 必须保留的核心意思 optional_content_opportunity: str = "" class PromptAlignment(BaseModel): prompt_intent: str = "" current_alignment: str = "" optional_opportunity: str = "" class AnalyzeResponse(BaseModel): essay_summary: str = "" prompt_alignment: PromptAlignment = PromptAlignment() paragraphs: list[ParagraphUnderstanding] = [] # ---------------------------------------------------------------- diagnose class DiagnoseRequest(BaseModel): prompt: str = "" word_limit: int | None = None paragraphs: list[str] = Field(min_length=1) # 优先级(PRD §10.1):顾问确认理解 > 顾问补充约束 > 模型初始理解 confirmed_anchors: list[str] = [] # 与 paragraphs 等长;非空条目覆盖模型初判 global_constraints: list[str] = [] paragraph_constraints: dict[str, list[str]] = {} initial_analysis: AnalyzeResponse | None = None PatternCategory = Literal["rhetoric", "repeat", "growth", "structure"] class Pattern(BaseModel): pattern_id: str = "" name: str = "" category: str = "" # rhetoric / repeat / growth / structure affected_paragraphs: list[str] = [] evidence: list[str] = [] # 必须能在原文中找到的片段 why_ai_like: str = "" human_impact: str = "" transformation_rule: str = "" class Annotation(BaseModel): annotation_id: str = "" pattern_id: str = "" category: str = "rhetoric" kind_label: str = "" title: str = "" evidence: list[str] = [] observation: str = "" rewrite_action: str = "" why_ai_like: str = "" class ParagraphBrief(BaseModel): paragraph_id: str = "" confirmed_meaning: str = "" rewrite_goal: str = "" ai_focus: str = "" must_preserve: list[str] = [] annotations: list[Annotation] = [] context_hint: str = "" scaffold: str = "" reference_snippet: str = "" class DiagnoseResponse(BaseModel): overall_diagnosis: str = "" patterns: list[Pattern] = [] paragraph_briefs: list[ParagraphBrief] = [] optional_suggestion: str = "" # PRD §16 Optional 进阶建议(不阻塞) # ---------------------------------------------------------------- recheck class GlobalChecks(BaseModel): semantic_preservation: str = "pass" voice_consistency: str = "pass" pattern_reduction: str = "pass" new_pattern: str = "pass" coherence: str = "pass" reference_copying: str = "pass" word_limit: str = "pass" class RevisionTarget(BaseModel): paragraph_id: str = "p1" blocking_issue: str = "" evidence: list[str] = [] single_revision_goal: str = "" # 单一明确返工目标 class RecheckResponse(BaseModel): status: Literal["pass", "revision_required"] checked_rewrite_version: str = "" global_checks: GlobalChecks revision_targets: list[RevisionTarget] = [] class RecheckRequest(BaseModel): prompt: str = "" word_limit: int | None = None original_paragraphs: list[str] = Field(min_length=1) confirmed_anchors: list[str] = [] global_constraints: list[str] = [] paragraph_constraints: dict[str, list[str]] = {} rewrite_paragraphs: list[str] = Field(min_length=1) diagnosis: DiagnoseResponse | None = None references_shown: list[str] = [] # 仅用户实际展开过的参考 scaffolds_shown: list[str] = [] # 仅用户实际展开过的支架 rewrite_version: str = "" previous_recheck: RecheckResponse | None = None previous_revision_target: RevisionTarget | None = None # ---------------------------------------------------------------- progressive help class ScaffoldRequest(BaseModel): paragraph_id: str original_text: str semantic_anchor: str rewrite_goal: str = "" global_constraints: list[str] = [] paragraph_constraints: list[str] = [] class ScaffoldResponse(BaseModel): paragraph_id: str = "" scaffold: str = "" class ReferenceRequest(BaseModel): paragraph_id: str original_text: str semantic_anchor: str rewrite_goal: str = "" primary_goal: str = "" # 兼容旧字段名 global_constraints: list[str] = [] paragraph_constraints: list[str] = [] class ReferenceResponse(BaseModel): paragraph_id: str = "" starter: str = "" # 1-2 句英文局部参考,非整段 reference_snippet: str = "" # ------------------------------------------------------- 体验优化:中文对照翻译 class TranslateRequest(BaseModel): text: str = Field(min_length=1) # 段落上下文(可选):帮助模型稳定语气,不参与翻译输出 paragraph_id: str = "" class TranslateResponse(BaseModel): paragraph_id: str = "" translation: str = ""