159 lines
5.6 KiB
Python

"""按完整目录读取当前稿用于回看;疑点交回逐章改稿入口。"""
from uuid import NAMESPACE_URL, uuid5
from muse.交付连载.文字校对 import 文字疑点
from muse.交付连载.模型 import 交付错误, 全书修订
from muse.作品规划.接口 import 读取作品范围
from muse.正式变更.接口 import 作者动作, 固定哈希, 审阅内容, 提交计划
from muse.正文写作.接口 import (
准备派生候选,
可见文本,
应用选段,
批量读取当前正文依据,
段落哈希,
段落文本,
读取正文依据,
)
def 读取全书数据(连, author, work_id):
"""同事务批量获取目录与全书当前正文依据。"""
directory = 读取作品范围(连, author, work_id)
chapter_ids = [c["chapter_id"] for c in directory["chapters"]]
body_map = 批量读取当前正文依据(连, author, work_id, chapter_ids)
return directory, body_map
def 整理全书工作面(work_id, directory, body_map, *, names=None, exceptions=()):
"""纯内存整理工作面结构、段落偏移与文字疑点,不占用数据库连接。"""
chapters, problems = [], []
for chapter in directory["chapters"]:
body = body_map.get(chapter["chapter_id"])
if body is None:
chapters.append({**chapter, "state": "missing", "revision": None})
problems.append({"chapter_id": chapter["chapter_id"], "kind": "missing_body"})
continue
text = 可见文本(body["document"])
state = "ready" if text.strip() else "empty"
paragraphs, offset = [], 0
for p in body["document"].paragraphs:
value = 段落文本(p)
paragraphs.append(
{
"paragraph_id": p.paragraph_id,
"paragraph_hash": 段落哈希(p),
"text": value,
"start": offset,
"end": offset + len(value),
}
)
offset += len(value) + 1
chapters.append(
{
**chapter,
"state": state,
"branch_id": "main",
"revision": body["revision"],
"document_hash": body["document_hash"],
"text": text,
"paragraph_locations": paragraphs,
}
)
if state == "empty":
problems.append({"chapter_id": chapter["chapter_id"], "kind": "empty_body"})
findings = 文字疑点([c for c in chapters if c["revision"] is not None], names, exceptions)
return {
"work_id": work_id,
"directory_revision": directory["revision"],
"chapters": chapters,
"problems": problems,
"copyedit": findings,
"can_freeze": bool(chapters) and not problems,
"literary_status": "not_assessed",
"review_scope": ["directory", "body_presence", "copyedit"],
}
def 全书工作面(连, author, work_id, *, names=None, exceptions=()):
directory, body_map = 读取全书数据(连, author, work_id)
return 整理全书工作面(work_id, directory, body_map, names=names, exceptions=exceptions)
def 跨章候选身份(author, req, chapter):
return str(
uuid5(
NAMESPACE_URL,
"muse:B08:book-revision:"
+ 固定哈希(
[
author,
req.batch_id,
chapter.chapter_id,
chapter.branch_id,
]
),
)
)
def _准备跨章(连, 身份, req):
读取作品范围(连, 身份.作者, req.work_id)
dependencies, operations = {}, []
for selected in req.chapters:
if not selected.patches:
raise 交付错误("BOOK_REVISION_INVALID", "每个入选章须点名原文与修改")
body = 读取正文依据(
连,
身份.作者,
selected.chapter_id,
selected.revision,
分支=selected.branch_id,
)
if body["work_id"] != req.work_id or body["document_hash"] != selected.document_hash:
raise 交付错误("SOURCE_STALE", "跨章修改的作品、原文或版本不一致")
changed = 应用选段(body["document"], selected.patches)
current, plan = 准备派生候选(
连,
身份,
跨章候选身份(身份.作者, req, selected),
selected.chapter_id,
selected.branch_id,
selected.revision,
changed,
)
for ref in current.依赖:
dependencies[(ref.种类, ref.对象ID)] = ref
operations.extend(plan.操作)
return tuple(dependencies.values()), tuple(operations)
class 跨章修订入口:
身份 = "B08.book_revision"
请求类型 = 全书修订
def 查看(self, 连, 身份, 命令):
req = 命令.业务请求
refs, _ = _准备跨章(连, 身份, req)
target = 跨章候选身份(身份.作者, req, req.chapters[0])
digest = 固定哈希(req)
return 审阅内容(
target,
0,
None,
None,
None,
digest,
None,
None,
digest,
("candidates",),
refs,
)
def 准备(self, 连, 身份, 命令, 当前):
if 命令.动作 is not 作者动作.人工保存:
raise 交付错误("BOOK_REVISION_INVALID", "跨章修改只生成作者可审候选")
_, operations = _准备跨章(连, 身份, 命令.业务请求)
return 提交计划(operations)