- src/muse 新版全模块(装配/共享/上下文/任务运行/作品规划/故事世界/正文写作/审校修订/知识方法/作者经验/效果评测/交付连载/资料研究/正式变更/元数据/接入/基础设施/编排)+ 测试树(单元/契约/集成/架构/迁移/端到端/夹具) - 129 项功能全部实现与自动验证(功能覆盖.json/矩阵),含 W31 补齐的规则与代价/节奏安排/伏笔与承诺 - 旧实现按处置清单退出(702 条中 324 删,保护合同与未迁移条目留存有据);web/app.py 旧工作台退役,新工作台为唯一写入口 - 数据库/旧库迁移:真实旧库内容批次迁移链(端点守卫/PG作品正文映射/质量资产缺省投影) - 运行手册 docs/运行手册.md;W30 本机服务阶段一已运行(infra PG 为正式内容权威) - R2 执行证据与私有运行材料在 .agents.local/改造/R2-20260909/(不入库)
640 lines
25 KiB
Python
640 lines
25 KiB
Python
"""生成正文旅程:预组装、受限探索、冻结回放、无工具写作与检查入候选。
|
||
|
||
只调用各模块公开用例并按授权安排步骤;处理器在此登记为实际 Python 实现,
|
||
配置(配置/流程模板/生成正文.yaml)只选择稳定身份与版本。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import hashlib
|
||
import json
|
||
from dataclasses import asdict, replace
|
||
from datetime import UTC, datetime, timedelta
|
||
from functools import partial
|
||
from typing import Any
|
||
from uuid import uuid4
|
||
|
||
from muse.上下文.接口 import (
|
||
依赖重验检查,
|
||
保护模型发送,
|
||
回放结果,
|
||
探索条目,
|
||
来源绑定,
|
||
核对依赖,
|
||
核对范围声音,
|
||
装配材料,
|
||
记录探索,
|
||
)
|
||
from muse.任务运行.接口 import (
|
||
事件类型,
|
||
任务请求,
|
||
回合记录,
|
||
工具回传,
|
||
执行上下文,
|
||
模型请求,
|
||
步骤处理器,
|
||
步骤结果,
|
||
步骤计划,
|
||
组装角色请求,
|
||
角色策略目录,
|
||
请求字节,
|
||
配置版本管理,
|
||
)
|
||
from muse.共享.调用身份 import 内容用途
|
||
from muse.共享.错误 import Muse错误
|
||
from muse.基础设施.数据库.连接 import 数据库工厂
|
||
from muse.审校修订.接口 import 审校服务
|
||
from muse.正文写作.接口 import (
|
||
写作输出合同,
|
||
写入模型候选,
|
||
创建写作任务,
|
||
文本节点,
|
||
正文草稿,
|
||
段落,
|
||
生成正文模板,
|
||
读取当前正文依据,
|
||
)
|
||
from muse.编排.接口 import 流程登记
|
||
from muse.编排.流程版本 import 流程定义
|
||
|
||
_写作输出合同 = 写作输出合同()
|
||
|
||
流程身份 = "生成正文"
|
||
流程版本 = "1.0.0"
|
||
|
||
# 探索阶段允许的具名只读工具;与冻结范围安装的工具一致,写作阶段为空(禁工具)。
|
||
探索工具集 = ("query_work_plan", "query_facts_as_of", "read_history_document")
|
||
|
||
处理器版本集 = {
|
||
"ctx.prep": "1",
|
||
"ctx.explore": "1",
|
||
"ctx.freeze": "1",
|
||
"ctx.write": "1",
|
||
"ctx.check": "1",
|
||
}
|
||
|
||
|
||
_探索输出合同 = {"type": "object"}
|
||
|
||
|
||
class 生成正文错误(Muse错误):
|
||
"""旅程编排内的明确失败;错误说明面向作者呈现。"""
|
||
|
||
错误码 = "WRITING_FLOW_INVALID"
|
||
|
||
|
||
def _工厂(装配) -> 数据库工厂:
|
||
return 数据库工厂(装配.配置.数据库, 装配.配置.运行用途)
|
||
|
||
|
||
def 前步检查点(上下文: 执行上下文, 步骤ID: str) -> dict[str, Any]:
|
||
"""读取已提交前置步骤的检查点;缺失即旅程不完整,明确失败。"""
|
||
|
||
for 项 in 上下文.任务.步骤:
|
||
if 项.get("step_id") == 步骤ID:
|
||
检查点 = 项.get("checkpoint") or {}
|
||
if not 检查点:
|
||
raise 生成正文错误(f"前置步骤 {步骤ID} 没有可用检查点")
|
||
return 检查点
|
||
raise 生成正文错误(f"前置步骤 {步骤ID} 尚未执行")
|
||
|
||
|
||
def _探索清单从检查点(数据: list[dict[str, Any]]) -> tuple[探索条目, ...]:
|
||
return tuple(
|
||
探索条目(
|
||
调用ID=项["调用ID"],
|
||
工具名=项["工具名"],
|
||
顺序=项["顺序"],
|
||
参数=项["参数"],
|
||
来源引用=tuple(来源绑定(**绑) for 绑 in 项["来源引用"]),
|
||
消费哈希=项["消费哈希"],
|
||
)
|
||
for 项 in 数据
|
||
)
|
||
|
||
|
||
def _原文授权(装配, 任务, 请求: 模型请求, *, 方式: str) -> str:
|
||
"""为一次模型调用取得作者批准的原文授权。
|
||
|
||
探索回合走持久证据(无租约);生成回合走临时租约,字节只进受控暂存。
|
||
"""
|
||
|
||
原文 = 装配.要求原文()
|
||
哈希 = hashlib.sha256(请求字节(请求)).hexdigest()
|
||
return 原文.批准保留(
|
||
任务.任务ID,
|
||
任务.作者,
|
||
"raw-" + 请求.调用ID,
|
||
来源版本="生成正文任务",
|
||
哈希=(哈希,),
|
||
内容用途="generation",
|
||
方式=方式,
|
||
有效期=datetime.now(UTC) + timedelta(minutes=20),
|
||
调用ID=请求.调用ID,
|
||
调用请求哈希=哈希,
|
||
)
|
||
|
||
|
||
def _写手请求(
|
||
装配,
|
||
上下文: 执行上下文,
|
||
*,
|
||
阶段: str,
|
||
系统提示: str,
|
||
用户输入: str,
|
||
工具: tuple[dict[str, Any], ...] = (),
|
||
历史: tuple[回合记录, ...] = (),
|
||
) -> 模型请求:
|
||
任务 = 上下文.任务
|
||
版本 = 配置版本管理(_工厂(装配)).读取任务绑定(任务.任务ID)
|
||
声明 = 版本.内容.角色配置["writer"]
|
||
请求 = 模型请求(
|
||
调用ID=str(uuid4()),
|
||
provider=声明["provider"],
|
||
model=声明["model"],
|
||
thinking=声明.get("thinking"),
|
||
系统提示=系统提示,
|
||
用户输入=用户输入,
|
||
输出合同=_写作输出合同 if 阶段 == "生成" else _探索输出合同,
|
||
最大输出token=int(任务.冻结输入["冻结上下文"]["budget"].get("最大输出token", 8192)),
|
||
总期限秒=600.0,
|
||
工具=工具,
|
||
历史=历史,
|
||
)
|
||
return 组装角色请求(角色策略目录.从发布包(), "writer", 请求)
|
||
|
||
|
||
def 登记生成正文(登记: 流程登记, 装配, 计价) -> None:
|
||
"""登记生成正文流程的处理器、类型与恢复检查;装配提供全部实现。"""
|
||
|
||
服务 = 装配.要求上下文()
|
||
|
||
登记.登记类型(流程身份, 必需保护=("冻结上下文",))
|
||
登记.登记恢复检查(流程身份, 流程版本, 依赖重验检查(服务))
|
||
|
||
def 预组装(上下文: 执行上下文) -> 步骤结果:
|
||
范围 = 服务.恢复冻结范围(上下文.任务)
|
||
写作 = 上下文.任务.冻结输入["输入"]["写作任务"]
|
||
if 写作.get("chapter_id") != (范围.get("target_plan") or {}).get("chapter_id"):
|
||
raise 生成正文错误(f"写作任务章位 {写作.get('chapter_id')} 与冻结细纲章位不一致")
|
||
if "budget" not in 上下文.任务.冻结输入["冻结上下文"]:
|
||
raise 生成正文错误("任务缺少预算冻结输入")
|
||
return 步骤结果(
|
||
输出={"work_id": 范围["work_id"], "chapter_id": 写作["chapter_id"]},
|
||
检查点={
|
||
"work_id": 范围["work_id"],
|
||
"预组装": {"as_of": 范围["as_of"], "来源数": len(范围["source_ids"])},
|
||
},
|
||
)
|
||
|
||
def 受限探索(上下文: 执行上下文) -> 步骤结果:
|
||
任务 = 上下文.任务
|
||
工具 = 装配.要求只读工具(上下文.领取)
|
||
清单: tuple[探索条目, ...] = ()
|
||
绑定集: dict[str, 来源绑定] = {}
|
||
历史: list[回合记录] = []
|
||
轮次上限 = int(
|
||
任务.冻结输入["冻结上下文"].get("stop_conditions", {}).get("探索轮数上限", 6)
|
||
)
|
||
工具描述 = tuple(
|
||
{"name": d.名称, "description": d.说明, "parameters": d.参数合同}
|
||
for d in 工具.工具.values()
|
||
)
|
||
探索提示 = (
|
||
"你是本作品的写手,当前处于受限探索阶段。"
|
||
"使用提供的只读工具了解目标章细纲、截止时点事实与历史正文,"
|
||
"为写作收集必要材料;不要输出正文,探索完成后输出一个空 JSON 对象。"
|
||
)
|
||
for _ in range(轮次上限):
|
||
请求 = _写手请求(
|
||
装配,
|
||
上下文,
|
||
阶段="探索",
|
||
系统提示=探索提示,
|
||
用户输入=json.dumps(
|
||
{
|
||
"粒度": 任务.冻结输入["输入"]["写作任务"]["粒度"],
|
||
"用途说明": 任务.冻结输入["输入"]["写作任务"].get("用途说明", ""),
|
||
"材料需求": ["目标章细纲", "时点事实", "历史正文"],
|
||
},
|
||
ensure_ascii=False,
|
||
),
|
||
工具=工具描述,
|
||
历史=tuple(历史),
|
||
)
|
||
执行器 = 装配.要求模型执行器(上下文, 计价)
|
||
授权 = _原文授权(装配, 任务, 请求, 方式="persistent")
|
||
回合 = asyncio.run(执行器.执行回合(上下文, 请求, 阶段="探索", 原文授权ID=授权))
|
||
if 回合.结果.状态 == "tool_calls":
|
||
回传: list[工具回传] = []
|
||
for 调用 in 回合.结果.工具调用:
|
||
结果 = 工具.调用(调用)
|
||
清单 = 记录探索(清单, 调用.调用ID, 调用.名称, 调用.参数, 结果)
|
||
for 源 in 结果.来源:
|
||
绑定集.setdefault(
|
||
源.来源ID,
|
||
来源绑定(源.来源ID, 源.数据版本, 源.结构哈希, 源.投影版本),
|
||
)
|
||
回传.append(工具回传(调用, json.dumps(结果.内容, ensure_ascii=False)))
|
||
历史.append(回合记录(回合.结果, tuple(回传)))
|
||
continue
|
||
if 回合.结果.状态 != "completed":
|
||
raise 生成正文错误(f"探索回合未完成:{回合.结果.状态}")
|
||
break
|
||
else:
|
||
raise 生成正文错误("探索轮数超出停止条件上限")
|
||
if not 清单:
|
||
raise 生成正文错误("写手没有进行任何受限探索读取")
|
||
return 步骤结果(
|
||
输出={"清单长度": len(清单)},
|
||
检查点={
|
||
"清单": [asdict(项) for 项 in 清单],
|
||
"绑定": [asdict(绑) for 绑 in 绑定集.values()],
|
||
},
|
||
)
|
||
|
||
def 冻结回放(上下文: 执行上下文) -> 步骤结果:
|
||
任务 = 上下文.任务
|
||
前置 = 前步检查点(上下文, "受限探索")
|
||
清单 = _探索清单从检查点(前置["清单"])
|
||
绑定集 = {绑["来源ID"]: 来源绑定(**绑) for 绑 in 前置["绑定"]}
|
||
回放: 回放结果 = 服务.回放探索(任务.任务ID, 清单)
|
||
材料: dict[str, str] = {}
|
||
细纲投影: dict[str, Any] | None = None
|
||
事实: list[dict[str, Any]] = []
|
||
for 项 in 回放.逐项:
|
||
if 项.工具名 == "query_work_plan":
|
||
细纲投影 = 项.内容["content"]
|
||
材料["目标章细纲"] = json.dumps(项.内容["content"], ensure_ascii=False)
|
||
elif 项.工具名 == "query_facts_as_of":
|
||
事实 = list(项.内容.get("facts", []))
|
||
for 实体 in 事实:
|
||
名称 = (实体.get("content") or {}).get("名称")
|
||
if 名称:
|
||
材料["事实:" + 实体["object_id"]] = str(名称)
|
||
elif 项.工具名 == "read_history_document":
|
||
材料["历史:" + 项.调用ID] = 项.内容.get("text", "")
|
||
if 细纲投影 is None:
|
||
raise 生成正文错误("回放清单中没有目标章细纲,不能进入写作")
|
||
# 固定绑定方法参与预算取舍;入选只表示准备完成,不等同于模型消费。
|
||
from muse.上下文.接口 import 偏好绑定, 核对范围偏好, 核对范围方法
|
||
|
||
范围 = 服务.恢复冻结范围(任务)
|
||
with _工厂(装配).连接(只读=True) as 连:
|
||
声音 = 核对范围声音(连, 范围)
|
||
方法材料 = 核对范围方法(连, 范围)
|
||
偏好材料 = 核对范围偏好(连, 范围)
|
||
必读 = ("目标章细纲",)
|
||
for 条 in 偏好材料:
|
||
材料[条["材料键"]] = 条["材料"]
|
||
必读 += (条["材料键"],)
|
||
绑定集[条["preference_id"]] = 偏好绑定(条)
|
||
if 声音 is not None:
|
||
材料[声音["材料键"]] = 声音["材料"]
|
||
必读 += (声音["材料键"],)
|
||
绑定集[声音["version_id"]] = 来源绑定(
|
||
声音["version_id"],
|
||
str(声音["revision"]),
|
||
声音["schema_hash"],
|
||
声音["projection_version"],
|
||
)
|
||
方法清单 = []
|
||
for 条 in 方法材料:
|
||
键 = 条["材料键"]
|
||
材料[键] = 条["材料"]
|
||
方法清单.append({**条, "材料键": 键})
|
||
装配结果 = 装配材料(
|
||
材料,
|
||
必读,
|
||
字节上限=int(任务.冻结输入["冻结上下文"]["budget"]["context_bytes"]),
|
||
)
|
||
# 超出预算而省略的材料未进入快照,不得登记为消费。
|
||
方法清单 = [条 for 条 in 方法清单 if 条["材料键"] in 装配结果.入选来源]
|
||
for 条 in 方法清单:
|
||
绑定集[条["binding_id"]] = 来源绑定(
|
||
条["binding_id"], str(条["version"]), 条["schema_hash"], 条["projection_version"]
|
||
)
|
||
回执 = 服务.冻结上下文(任务.任务ID, 装配结果, tuple(绑定集.values()))
|
||
return 步骤结果(
|
||
输出={"snapshot_id": 回执.快照ID, "字节数": 装配结果.字节数},
|
||
检查点={
|
||
"快照ID": 回执.快照ID,
|
||
"细纲投影": 细纲投影,
|
||
"事实": 事实,
|
||
"入选": list(装配结果.入选来源),
|
||
"方法材料": [
|
||
{键: 条[键] for 键 in ("version_id", "材料键", "材料哈希")} for 条 in 方法清单
|
||
],
|
||
},
|
||
)
|
||
|
||
def 无工具写作(上下文: 执行上下文) -> 步骤结果:
|
||
任务 = 上下文.任务
|
||
前置 = 前步检查点(上下文, "冻结回放")
|
||
快照 = 服务.读取快照(前置["快照ID"])
|
||
if 快照.失效说明:
|
||
raise 生成正文错误(f"上下文快照已失效:{快照.失效说明}")
|
||
with _工厂(装配).连接(只读=True) as 连:
|
||
状态 = 核对依赖(连, 服务.恢复冻结范围(任务), 服务.规划引用解析)
|
||
if not 状态.有效:
|
||
raise 生成正文错误("冻结来源失效:" + ";".join(状态.变化项))
|
||
模板, 模板哈希 = 生成正文模板()
|
||
写作 = 任务.冻结输入["输入"]["写作任务"]
|
||
请求 = _写手请求(
|
||
装配,
|
||
上下文,
|
||
阶段="生成",
|
||
系统提示=模板,
|
||
用户输入=json.dumps(
|
||
{
|
||
"粒度": 写作["粒度"],
|
||
"用途说明": 写作.get("用途说明", ""),
|
||
"上下文快照ID": 快照.快照ID,
|
||
"装配材料": 快照.装配["文本"],
|
||
"选区": 写作.get("选区", []),
|
||
"保护区": 写作.get("保护区", []),
|
||
},
|
||
ensure_ascii=False,
|
||
),
|
||
)
|
||
执行器 = 装配.要求模型执行器(上下文, 计价)
|
||
授权 = _原文授权(装配, 任务, 请求, 方式="temporary")
|
||
交付 = asyncio.run(
|
||
执行器.执行(
|
||
上下文,
|
||
请求,
|
||
阶段="生成",
|
||
原文授权ID=授权,
|
||
临时租约ID=_租约(装配, 任务, 授权, 请求.调用ID),
|
||
发送复检=partial(
|
||
保护模型发送,
|
||
执行用途=_工厂(装配).用途,
|
||
作者=任务.作者,
|
||
任务ID=任务.任务ID,
|
||
快照ID=快照.快照ID,
|
||
模型输入=请求.用户输入,
|
||
),
|
||
)
|
||
)
|
||
# 只有真实写作交付后才登记消费,并关联模型调用;冻结不自动产生消费。
|
||
from muse.知识方法.接口 import 消费输入, 记录消费
|
||
|
||
with _工厂(装配).连接() as 连:
|
||
for 条 in 前置.get("方法材料", []):
|
||
记录消费(
|
||
连,
|
||
任务.作者,
|
||
消费输入(
|
||
method_version_id=条["version_id"],
|
||
kind="generation",
|
||
context_ref=str(前置["快照ID"]),
|
||
fragment_hash=条["材料哈希"],
|
||
result_ref="model-call:" + str(交付.调用ID),
|
||
task_id=str(任务.任务ID),
|
||
),
|
||
模型输入=请求.用户输入,
|
||
执行用途=_工厂(装配).用途,
|
||
)
|
||
段落集 = 交付.内容["paragraphs"]
|
||
for 段 in 段落集:
|
||
装配.任务运行.追加事件(
|
||
上下文.领取,
|
||
事件类型.文本片段,
|
||
{"文本": 段["text"], "模板哈希": 模板哈希},
|
||
事件ID=str(uuid4()),
|
||
)
|
||
return 步骤结果(
|
||
输出={"段落数": len(段落集)},
|
||
检查点={
|
||
"段落": [段["text"] for 段 in 段落集],
|
||
"调用ID": 交付.调用ID,
|
||
"证据回执": 交付.证据回执,
|
||
"模板哈希": 模板哈希,
|
||
},
|
||
)
|
||
|
||
def 检查与候选(上下文: 执行上下文) -> 步骤结果:
|
||
任务 = 上下文.任务
|
||
冻结点 = 前步检查点(上下文, "冻结回放")
|
||
写作点 = 前步检查点(上下文, "无工具写作")
|
||
写作 = 任务.冻结输入["输入"]["写作任务"]
|
||
草稿 = 正文草稿(
|
||
tuple(
|
||
段落(f"gen-{序}", (文本节点(文本),))
|
||
for 序, 文本 in enumerate(写作点["段落"], start=1)
|
||
)
|
||
)
|
||
出场名映射: dict[str, str] = {}
|
||
for 实体 in 冻结点.get("事实", []):
|
||
名称 = (实体.get("content") or {}).get("名称")
|
||
if 名称:
|
||
出场名映射.setdefault(实体["object_id"], str(名称))
|
||
for 身份 in 冻结点["细纲投影"].get("mustAppearEntities") or []:
|
||
出场名映射.setdefault(str(身份), str(身份))
|
||
with _工厂(装配).连接() as 连, 连.transaction():
|
||
候选 = 写入模型候选(
|
||
连,
|
||
任务.作者,
|
||
任务.任务ID,
|
||
冻结点["快照ID"],
|
||
写作["chapter_id"],
|
||
写作.get("branch_id", "main"),
|
||
int(写作["基线版本"]),
|
||
草稿,
|
||
流程版本=流程版本,
|
||
处理器版本=处理器版本集,
|
||
模型证据=[写作点["调用ID"], 写作点["证据回执"]],
|
||
提示词哈希={"生成正文": 写作点["模板哈希"]},
|
||
)
|
||
报告 = 审校服务(_工厂(装配)).检查并保存(
|
||
连,
|
||
草稿,
|
||
冻结点["细纲投影"],
|
||
出场名映射,
|
||
candidate_id=候选["candidate_id"],
|
||
candidate_revision=int(候选["revision"]),
|
||
snapshot_id=冻结点["快照ID"],
|
||
原始交付=json.dumps(
|
||
{"paragraphs": [{"text": t} for t in 写作点["段落"]]},
|
||
ensure_ascii=False,
|
||
),
|
||
)
|
||
for 类型, 载荷 in (
|
||
(
|
||
事件类型.候选保存,
|
||
{"candidate_id": 候选["candidate_id"], "revision": 候选["revision"]},
|
||
),
|
||
(事件类型.检查完成, {"verdict": 报告["verdict"], "report_id": str(报告["report_id"])}),
|
||
):
|
||
装配.任务运行.追加事件(上下文.领取, 类型, 载荷, 事件ID=str(uuid4()))
|
||
return 步骤结果(
|
||
输出={
|
||
"candidate_id": 候选["candidate_id"],
|
||
"revision": 候选["revision"],
|
||
"candidate_hash": 候选["candidate_hash"],
|
||
"verdict": 报告["verdict"],
|
||
},
|
||
检查点={"候选": 候选, "报告": str(报告["report_id"]), "verdict": 报告["verdict"]},
|
||
)
|
||
|
||
登记.登记处理器(步骤处理器("ctx.prep", "1", 预组装, "writing-task", "frozen-scope"))
|
||
登记.登记处理器(
|
||
步骤处理器(
|
||
"ctx.explore",
|
||
"1",
|
||
受限探索,
|
||
"frozen-scope",
|
||
"exploration-manifest",
|
||
角色="writer",
|
||
允许工具=探索工具集,
|
||
)
|
||
)
|
||
登记.登记处理器(
|
||
步骤处理器(
|
||
"ctx.freeze",
|
||
"1",
|
||
冻结回放,
|
||
"exploration-manifest",
|
||
"context-snapshot",
|
||
保护职责="冻结上下文",
|
||
)
|
||
)
|
||
登记.登记处理器(
|
||
步骤处理器(
|
||
"ctx.write",
|
||
"1",
|
||
无工具写作,
|
||
"context-snapshot",
|
||
"generated-draft",
|
||
角色="writer",
|
||
)
|
||
)
|
||
登记.登记处理器(步骤处理器("ctx.check", "1", 检查与候选, "generated-draft", "model-candidate"))
|
||
|
||
|
||
def _租约(装配, 任务, 授权ID: str, 调用ID: str) -> str:
|
||
原文 = 装配.要求原文()
|
||
return 原文.创建租约(
|
||
任务.任务ID,
|
||
授权ID,
|
||
"lease-" + 调用ID,
|
||
datetime.now(UTC) + timedelta(minutes=19),
|
||
最少剩余秒=0,
|
||
)
|
||
|
||
|
||
def 生成正文步骤() -> tuple[步骤计划, ...]:
|
||
return (
|
||
步骤计划("预组装", "ctx.prep", "1"),
|
||
步骤计划("受限探索", "ctx.explore", "1", 依赖=("预组装",), 角色="writer", 工具=探索工具集),
|
||
步骤计划("冻结回放", "ctx.freeze", "1", 依赖=("受限探索",)),
|
||
步骤计划("无工具写作", "ctx.write", "1", 依赖=("冻结回放",), 角色="writer"),
|
||
步骤计划("检查与候选", "ctx.check", "1", 依赖=("无工具写作",)),
|
||
)
|
||
|
||
|
||
def 流程定义_生成正文() -> 流程定义:
|
||
return 流程定义(流程身份, 流程版本, 生成正文步骤())
|
||
|
||
|
||
def 发起生成正文(
|
||
装配,
|
||
身份,
|
||
命令ID: str,
|
||
粒度: str,
|
||
*,
|
||
work_id: str,
|
||
chapter_id: str,
|
||
分支: str = "main",
|
||
用途说明: str = "",
|
||
预算: dict[str, Any] | None = None,
|
||
配置ID: str,
|
||
) -> dict[str, str]:
|
||
"""冻结写作任务与来源范围后创建生成正文任务;运行配置由作者明确选择。"""
|
||
|
||
身份 = replace(身份, 内容用途=内容用途.生成)
|
||
if 粒度 != "new_chapter":
|
||
raise 生成正文错误("扩写、压缩、润色和重写须使用带确切正文与圈选的选段修订入口")
|
||
|
||
from muse.作品规划.接口 import 读取作品范围, 读取章节归属
|
||
|
||
with _工厂(装配).连接(只读=True) as 连:
|
||
章节 = 读取章节归属(连, 身份.作者, chapter_id)
|
||
目录 = 读取作品范围(连, 身份.作者, work_id)
|
||
前文 = []
|
||
for 行 in 目录["chapters"]:
|
||
if 行["position"] >= 章节["position"]:
|
||
continue
|
||
文稿 = 读取当前正文依据(连, 身份.作者, 行["chapter_id"], 分支=分支)
|
||
if 文稿:
|
||
前文.append(
|
||
{
|
||
"chapter_id": 行["chapter_id"],
|
||
"revision": 文稿["revision"],
|
||
"branch_id": 分支,
|
||
}
|
||
)
|
||
任务合同 = 创建写作任务(
|
||
连,
|
||
身份,
|
||
命令ID,
|
||
粒度,
|
||
work_id=work_id,
|
||
chapter_id=chapter_id,
|
||
分支=分支,
|
||
用途说明=用途说明,
|
||
预算=预算,
|
||
)
|
||
范围 = 装配.要求上下文().授权任务范围(
|
||
身份,
|
||
work_id,
|
||
int(章节["position"]) - 1,
|
||
tuple(前文),
|
||
目标章ID=chapter_id,
|
||
含事实=True,
|
||
含方法=True,
|
||
含声音=True,
|
||
含偏好=True,
|
||
)
|
||
冻结上下文 = {
|
||
"source_scope": 范围,
|
||
"schema_versions": {"context": "w14", "review": "w15"},
|
||
"authorization": {
|
||
"authorized_by": 范围["authorized_by"],
|
||
"run_purpose": 范围["run_purpose"],
|
||
"content_purpose": 范围["content_purpose"],
|
||
},
|
||
"budget": 预算 or {"context_bytes": 65536, "最大输出token": 8192},
|
||
"stop_conditions": {"探索轮数上限": 6},
|
||
}
|
||
策略 = 角色策略目录.从发布包()
|
||
请求 = 任务请求(
|
||
任务类型=流程身份,
|
||
命令ID=命令ID,
|
||
作者=身份.作者,
|
||
执行用途=装配.配置.运行用途,
|
||
内容用途=身份.内容用途,
|
||
输入={"写作任务": asdict(任务合同)},
|
||
角色策略版本=策略.定义["version"],
|
||
资源发布身份=装配.配置.资源发布身份,
|
||
冻结上下文=冻结上下文,
|
||
作品ID=work_id,
|
||
)
|
||
任务ID = 装配.任务运行.创建受控任务(请求, 流程身份, 流程版本, 配置ID=配置ID)
|
||
return {"task_id": 任务ID, "writing_task_id": 任务合同.任务ID}
|
||
|
||
|
||
__all__ = [
|
||
"登记生成正文",
|
||
"发起生成正文",
|
||
"流程定义_生成正文",
|
||
"生成正文步骤",
|
||
"生成正文模板",
|
||
"流程身份",
|
||
"流程版本",
|
||
"探索工具集",
|
||
"生成正文错误",
|
||
"处理器版本集",
|
||
]
|