assemble/_build_volatile 加 directive 参数(仅入 volatile,守缓存前缀不变量 #9);stream_draft 加可选 body {directive} 透传;不持久化、无迁移;directive 长度入 log 不记原文。新 DraftStreamRequest schema + 重生成 TS 客户端。后端门禁绿: ruff/mypy/pytest。契约记 memory/contracts.md。
153 lines
4.8 KiB
Python
153 lines
4.8 KiB
Python
"""项目(立项)与章节草稿的请求/响应 schema(C3 / ARCH §7.2)。
|
||
|
||
snake_case;前端经 OpenAPI 生成 TS 类型消费。改字段 → 前端必须 `pnpm gen:api`。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import uuid
|
||
from typing import Any, Literal
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
|
||
class ProjectCreateRequest(BaseModel):
|
||
"""POST /projects:立项向导字段(owner_id 由后端补 stub,不入参)。"""
|
||
|
||
title: str = Field(min_length=1)
|
||
genre: str | None = None
|
||
logline: str | None = None
|
||
premise: str | None = None
|
||
theme: str | None = None
|
||
selling_points: list[Any] = Field(default_factory=list)
|
||
structure: str | None = None
|
||
|
||
|
||
class ProjectResponse(BaseModel):
|
||
"""项目视图(创建/列表/详情共用)。"""
|
||
|
||
id: uuid.UUID
|
||
title: str
|
||
genre: str | None = None
|
||
logline: str | None = None
|
||
premise: str | None = None
|
||
theme: str | None = None
|
||
selling_points: list[Any] = Field(default_factory=list)
|
||
structure: str | None = None
|
||
|
||
|
||
class ProjectListResponse(BaseModel):
|
||
"""GET /projects:项目列表。"""
|
||
|
||
projects: list[ProjectResponse] = Field(default_factory=list)
|
||
|
||
|
||
class DraftStreamRequest(BaseModel):
|
||
"""POST /projects/:id/chapters/:no/draft:本章生成的可选输入(T4-b)。
|
||
|
||
`directive` = 作者本章指令(覆盖/补充大纲节拍)。临时输入,不持久化、无迁移;
|
||
后端只入 volatile(守缓存前缀不变量 #9)。无 body 时退化为纯按大纲生成(向后兼容)。
|
||
"""
|
||
|
||
directive: str | None = None
|
||
|
||
|
||
class DraftSaveRequest(BaseModel):
|
||
"""PUT /projects/:id/chapters/:no/draft:自动保存草稿正文。"""
|
||
|
||
text: str
|
||
|
||
|
||
class DraftResponse(BaseModel):
|
||
"""草稿保存结果(脱敏:只回元信息 + 长度,不回灌正文以外的衍生)。"""
|
||
|
||
project_id: uuid.UUID
|
||
chapter_no: int
|
||
volume: int
|
||
status: str
|
||
version: int
|
||
length: int
|
||
|
||
|
||
class DraftView(BaseModel):
|
||
"""GET .../draft:回灌已保存草稿(含正文,供工作台重载编辑器)。
|
||
|
||
与 PUT 的 `DraftResponse` 同元信息,**额外带 `content`**——读侧需要正文以重建编辑器,
|
||
保存侧不回灌正文故不带。`length` 仍按 content 字符数派生。
|
||
"""
|
||
|
||
project_id: uuid.UUID
|
||
chapter_no: int
|
||
volume: int
|
||
status: str
|
||
version: int
|
||
content: str
|
||
length: int
|
||
|
||
|
||
# ---- 审稿(T2.5)----
|
||
|
||
|
||
class ReviewRequest(BaseModel):
|
||
"""POST /projects/:id/chapters/:no/review:可选携带待审草稿正文。
|
||
|
||
不传 `draft` 时端点回退到已保存的草稿(chapter_repo)。
|
||
"""
|
||
|
||
draft: str | None = None
|
||
|
||
|
||
class ReviewHistoryItem(BaseModel):
|
||
"""单条审稿留痕(GET .../reviews 历史项;snake_case)。"""
|
||
|
||
id: uuid.UUID
|
||
project_id: uuid.UUID
|
||
chapter_no: int
|
||
chapter_version: int | None = None
|
||
conflicts: list[dict[str, Any]] = Field(default_factory=list)
|
||
foreshadow_sug: list[dict[str, Any]] = Field(default_factory=list)
|
||
style: dict[str, Any] | None = None
|
||
pace: dict[str, Any] | None = None
|
||
health_score: int | None = None
|
||
decisions: dict[str, Any] | None = None
|
||
|
||
|
||
class ReviewHistoryResponse(BaseModel):
|
||
"""GET /projects/:id/chapters/:no/reviews:审稿历史(新→旧)。"""
|
||
|
||
reviews: list[ReviewHistoryItem] = Field(default_factory=list)
|
||
|
||
|
||
# ---- 验收(T2.4)----
|
||
|
||
# 每个冲突的裁决:采纳改法 / 忽略 / 手改(R5)。
|
||
Verdict = Literal["accept", "ignore", "manual"]
|
||
|
||
|
||
class ConflictDecision(BaseModel):
|
||
"""对最近一次审稿留痕里**某个冲突**(按其在 conflicts 列表的下标定位)的裁决。"""
|
||
|
||
conflict_index: int = Field(ge=0, description="冲突在最近审稿 conflicts 列表中的下标")
|
||
verdict: Verdict = Field(description="采纳改法 / 忽略 / 手改")
|
||
note: str | None = Field(default=None, description="可选裁决备注(如手改说明)")
|
||
|
||
|
||
class AcceptRequest(BaseModel):
|
||
"""POST /projects/:id/chapters/:no/accept:裁决清单 + 可能改过的终稿。"""
|
||
|
||
final_text: str = Field(min_length=1, description="作者裁决/改稿后的最终验收文本")
|
||
decisions: list[ConflictDecision] = Field(
|
||
default_factory=list, description="对最近审稿每个冲突的裁决(每冲突必有其一,R5)"
|
||
)
|
||
|
||
|
||
class AcceptResponse(BaseModel):
|
||
"""验收「本次将更新」清单(ARCH §7.2 写回结果)。"""
|
||
|
||
project_id: uuid.UUID
|
||
chapter_no: int
|
||
accepted_version: int = Field(description="晋升到的 accepted 版次(max+1)")
|
||
digest_added: bool = Field(description="是否新增了一行 chapter_digests")
|
||
decisions_recorded: int = Field(description="本次写回的裁决条数")
|
||
review_id: uuid.UUID | None = Field(default=None, description="写回裁决的审稿留痕行 id")
|