muse-agent-example/tests/集成/test_作品与人工正文.py

209 lines
9.1 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""人工创作入口使用真实owner、元数据、S01和隔离PG;不需要模型评分。"""
import pytest
from muse.作品规划.接口 import 作品服务, 档案保存, 登记作品参与者
from muse.元数据.接口 import 元数据服务, 导入内置结构
from muse.共享.标识 import 任务标识
from muse.共享.调用身份 import 内容用途, 用途, 调用身份
from muse.正式变更.接口 import 参与者目录, 正式变更服务
pytestmark = pytest.mark.数据库
@pytest.fixture
def 作品环境(应用测试库):
with 应用测试库[用途.维护].连接() as 连, 连.transaction():
导入内置结构(元数据服务(连))
目录 = 参与者目录()
from muse.任务运行.接口 import 任务服务, 登记任务参与者
from muse.编排.接口 import 流程登记
登记任务参与者(目录, 任务服务(应用测试库[用途.生产], 流程登记()))
登记作品参与者(目录)
正式 = 正式变更服务(应用测试库[用途.生产], 目录)
服务 = 作品服务(应用测试库[用途.生产], 正式)
作者 = 调用身份("author", 任务标识("manual-create"), 用途.生产, 内容用途.规划)
结构 = 服务.新档案结构(作者, "work-new", "work_core", 1)
输入 = 档案保存(
"work-new", 0, {"名称": "新故事", "题材定位": "未定题材", "主题立意": "关于选择"}, 结构
)
return 服务, 作者, 输入, 应用测试库
def test_创建动态作品档案经S01且同命令不重复__aa1101(作品环境):
服务, 作者, 输入, 应用测试库 = 作品环境
回执 = 服务.保存档案(作者, "create-work", 输入)
assert 服务.保存档案(作者, "create-work", 输入) == 回执
作品 = 服务.读取作品(作者, "work-new")
assert 作品["revision"] == 1
assert 作品["content"] == {"名称": "新故事", "题材定位": "未定题材", "主题立意": "关于选择"}
assert 作品["schema_binding"]["schema_id"] == "work_core"
with 应用测试库[用途.生产].连接() as 连:
assert 连.execute("SELECT count(*) FROM muse_work_version").fetchone()[0] == 1
def test_章节重排只改目录顺序保留稳定身份__aa1102(作品环境):
服务, 作者, 输入, _ = 作品环境
服务.保存档案(作者, "create-work", 输入)
服务.添加章节(作者, "chapter-A", "work-new", "chapter-a", "开篇", 预期目录版本=0)
服务.添加章节(作者, "chapter-B", "work-new", "chapter-b", "随后", 预期目录版本=1)
回执 = 服务.重排章节(作者, "reorder", "work-new", ("chapter-b", "chapter-a"), 预期目录版本=2)
assert (
服务.重排章节(作者, "reorder", "work-new", ("chapter-b", "chapter-a"), 预期目录版本=2)
== 回执
)
目录 = 服务.读取目录(作者, "work-new")
assert 目录["revision"] == 3
assert [(v["chapter_id"], v["title"], v["position"]) for v in 目录["chapters"]] == [
("chapter-b", "随后", 1),
("chapter-a", "开篇", 2),
]
def test_人工正文保存重开与回退保留中文和历史__aa1103(作品环境):
from dataclasses import replace
from muse.正式变更.接口 import 变更错误
from muse.正文写作.接口 import 可见文本, 文本节点, 正文服务, 正文草稿, 段落, 登记正文参与者
作品, 作者, 输入, 库 = 作品环境
登记正文参与者(作品.正式.目录)
作品.保存档案(作者, "create-work", 输入)
作品.添加章节(作者, "chapter-A", "work-new", "chapter-a", "开篇", 预期目录版本=0)
正文 = 正文服务(库[用途.生产], 作品.正式)
草稿 = 正文草稿(
(
段落("p1", (文本节点(" 「中文」 e\u0301 🧑‍🏽 "),)),
段落("p2", ()),
段落("p3", (文本节点("最后一段。"),)),
)
)
首次 = 正文.保存人工(作者, "save-1", "chapter-a", 0, 草稿)
assert 正文.保存人工(作者, "save-1", "chapter-a", 0, 草稿) == 首次
重开 = 正文.读取正文(作者, "chapter-a")
assert 重开["revision"] == 1 and 重开["visible_text"] == 可见文本(草稿)
assert [p["paragraph_id"] for p in 重开["document"]["paragraphs"]] == ["p1", "p2", "p3"]
第二稿 = replace(
草稿, paragraphs=(*草稿.paragraphs[:2], 段落("p3", (文本节点("作者更新的末段。"),)))
)
正文.保存人工(作者, "save-2", "chapter-a", 1, 第二稿)
回退 = 正文.回退正文(作者, "restore-1", "chapter-a", 2, 1)
assert 回退["results"][0]["revision"] == 3
assert 正文.读取正文(作者, "chapter-a")["visible_text"] == 可见文本(草稿)
assert 正文.读取正文(作者, "chapter-a", 版本=2)["visible_text"] == 可见文本(第二稿)
with pytest.raises(变更错误) as 捕获:
正文.保存人工(作者, "stale-save", "chapter-a", 1, 第二稿)
assert 捕获.value.错误码 == "REVISION_CONFLICT"
assert 正文.读取正文(作者, "chapter-a")["revision"] == 3
def test_人工正文CLI使用实际装配并返回相同文稿__aa1104(作品环境, tmp_path):
文稿 = _核对CLI正文(作品环境, tmp_path, " CLI 原文「保持不变」🧑‍🏽\n")
assert 文稿["visible_text"] == " CLI 原文「保持不变」🧑‍🏽\n"
def test_大段中文引号换行与反斜杠经CLI和PG往返__125b0c(作品环境, tmp_path):
big = '中文"引号"\n换行\\反斜杠' * 5000
文稿 = _核对CLI正文(作品环境, tmp_path, big)
assert 文稿["visible_text"] == big
def _核对CLI正文(作品环境, tmp_path, 原文):
import json
import subprocess
import sys
from dataclasses import asdict
from muse.正文写作.接口 import 文本节点, 正文草稿, 段落
作品, 作者, 输入, _ = 作品环境
作品.保存档案(作者, "create-work", 输入)
作品.添加章节(作者, "chapter-A", "work-new", "chapter-a", "开篇", 预期目录版本=0)
配置文件 = tmp_path / "人工.toml"
配置文件.write_text("""["数据库"]
"取值方式"="受控存储"
"位置"="production.txt"
["资源"]
"发布身份"="test"
["HTTP"]
"口令文件"="作者口令.txt"
"作者ID"="author"
""")
草稿 = 正文草稿(
tuple(段落(f"cli-p{i}", (文本节点(行),)) for i, 行 in enumerate(原文.split("\n")))
)
请求文件 = tmp_path / "正文请求.json"
请求文件.write_text(
json.dumps(
{
"command_id": "cli-save",
"chapter_id": "chapter-a",
"expected_revision": 0,
"document": asdict(草稿),
},
ensure_ascii=False,
)
)
base = [sys.executable, "-m", "muse", "作品", str(配置文件)]
def 执行(*args):
p = subprocess.run([*base, *args], cwd="/", capture_output=True, text=True, timeout=15)
assert p.returncode == 0, p.stderr
return json.loads(p.stdout)
回执 = 执行("保存正文", str(请求文件))
assert 执行("保存正文", str(请求文件)) == 回执
文稿 = 执行("正文", "chapter-a")
assert 文稿["revision"] == 1
return 文稿
def test_档案读取当前绑定而不沿用上次写值结构__aa1105(作品环境):
from dataclasses import replace
from muse.作品规划.接口 import 档案保存, 档案结构
from muse.元数据.接口 import 值规则, 启用命令, 字段定义
作品, 作者, 输入, 库 = 作品环境
作品.保存档案(作者, "create-work", 输入)
# 这里只设置已完成的兼容升级;作者升级确认旅程由W11另验。
with 库[用途.维护].连接() as 连, 连.transaction():
元数据 = 元数据服务(连)
旧 = 元数据.读取结构("work_core", 1)
新 = replace(
旧,
schema_version=2,
父版本=1,
字段=(*旧.字段, 字段定义("work_core.读者约定", "读者约定", "读者约定", 值规则("text"))),
)
元数据.登记结构候选(新)
元数据.发布结构("work_core", 2, 新.内容哈希)
有效 = 元数据.读取有效结构("work_core", 2)
元数据.启用绑定(
"work:work-new",
"work-new",
有效,
启用命令(
"synthetic-upgrade",
有效.effective_schema_hash,
1,
"synthetic-reviewed-upgrade",
"work:work-new",
),
)
当前 = 作品.读取作品(作者, "work-new")
assert 当前["revision"] == 1 and 当前["schema_binding"]["base_version"] == 2
frame = 当前["schema_binding"]
结构 = 档案结构(
frame["schema_id"],
frame["base_version"],
frame["effective_schema_hash"],
当前["projection_version"],
frame["extension_version"],
)
作品.保存档案(
作者, "save-new-field", 档案保存("work-new", 1, {"读者约定": "先抛问题,再给答案"}, 结构)
)
assert 作品.读取作品(作者, "work-new")["content"]["读者约定"] == "先抛问题,再给答案"