Files
SillyTavern_replica/backend/services/tools/fiction_tools.py

186 lines
6.9 KiB
Python

"""
爽文工作流 Tool 注册。
"""
from __future__ import annotations
import json
from typing import Any, Dict, Optional
try:
from backend.models.agent import TurnContext
from backend.services.fiction_chapter_service import run_chapter
from backend.services.fiction_coarse_service import run_coarse_outline
from backend.services.fiction_event_plan_service import run_event_plan
from backend.services.fiction_open_book_service import run_open_book
from backend.services.tool_registry import ToolRegistry
except ImportError:
from models.agent import TurnContext
from services.fiction_chapter_service import run_chapter
from services.fiction_coarse_service import run_coarse_outline
from services.fiction_event_plan_service import run_event_plan
from services.fiction_open_book_service import run_open_book
from services.tool_registry import ToolRegistry
async def fiction_open_book(ctx: TurnContext) -> None:
"""fiction.open_book — 根据用户灵感优化开书方案(不创建书籍目录)。"""
request = ctx.request_data or {}
inspiration = str(request.get("inspiration") or request.get("intro") or "").strip()
profile_id = request.get("profile_id") or request.get("profileId")
api_config = request.get("api_config") or request.get("apiConfig")
result = await run_open_book(
inspiration,
profile_id=profile_id,
api_config=api_config,
)
payload = result.model_dump()
ctx.request_data["fictionOpenBookResult"] = payload
ctx.generated_content = json.dumps(payload, ensure_ascii=False)
async def fiction_coarse(ctx: TurnContext) -> None:
"""fiction.coarse — 生成本书粗纲事件链,写入 metadata.json。"""
request = ctx.request_data or {}
book_id = str(request.get("book_id") or request.get("bookId") or "").strip()
if not book_id:
raise ValueError("book_id 不能为空")
profile_id = request.get("profile_id") or request.get("profileId")
api_config = request.get("api_config") or request.get("apiConfig")
result = await run_coarse_outline(
book_id,
profile_id=profile_id,
api_config=api_config,
)
payload = result.model_dump()
ctx.request_data["fictionCoarseResult"] = payload
ctx.generated_content = json.dumps(payload, ensure_ascii=False)
async def fiction_event_plan(ctx: TurnContext) -> None:
"""fiction.event_plan — 为粗纲事件生成 flowStepsPlan + chapterPlan。"""
request = ctx.request_data or {}
book_id = str(request.get("book_id") or request.get("bookId") or "").strip()
if not book_id:
raise ValueError("book_id 不能为空")
profile_id = request.get("profile_id") or request.get("profileId")
api_config = request.get("api_config") or request.get("apiConfig")
event_id = request.get("event_id") or request.get("eventId")
result = await run_event_plan(
book_id,
profile_id=profile_id,
api_config=api_config,
event_id=event_id,
)
payload = result.model_dump()
ctx.request_data["fictionEventPlanResult"] = payload
ctx.generated_content = json.dumps(payload, ensure_ascii=False)
async def fiction_chapter(ctx: TurnContext) -> None:
"""fiction.chapter — 根据 chapterPlan brief 撰写正文,写入 chapters/{seq}.json。"""
request = ctx.request_data or {}
book_id = str(request.get("book_id") or request.get("bookId") or "").strip()
if not book_id:
raise ValueError("book_id 不能为空")
profile_id = request.get("profile_id") or request.get("profileId")
api_config = request.get("api_config") or request.get("apiConfig")
seq = request.get("seq") or request.get("chapterSeq")
result = await run_chapter(
book_id,
profile_id=profile_id,
api_config=api_config,
seq=int(seq) if seq is not None else None,
)
payload = result.model_dump()
ctx.request_data["fictionChapterResult"] = payload
ctx.generated_content = json.dumps(payload, ensure_ascii=False)
def register_fiction_tools(registry: ToolRegistry) -> None:
registry.register(
"fiction.open_book",
fiction_open_book,
description="根据用户创作灵感优化爽文开书方案,返回 guide 草稿与推荐情绪流",
parameters={
"type": "object",
"properties": {
"inspiration": {"type": "string", "description": "用户创作灵感/简介"},
"profile_id": {"type": "string", "description": "API 配置 profile ID"},
"api_config": {
"type": "object",
"description": "可选 inline API 配置",
},
},
"required": ["inspiration"],
},
)
registry.register(
"fiction.coarse",
fiction_coarse,
description="根据本书 guide 与 L1 全局指南生成粗纲,写入 metadata.coarseOutline",
parameters={
"type": "object",
"properties": {
"book_id": {"type": "string", "description": "书籍 ID"},
"profile_id": {"type": "string", "description": "API 配置 profile ID"},
"api_config": {"type": "object", "description": "可选 inline API 配置"},
},
"required": ["book_id"],
},
)
registry.register(
"fiction.event_plan",
fiction_event_plan,
description="为粗纲事件随机选情绪流并生成 flowStepsPlan + chapterPlan",
parameters={
"type": "object",
"properties": {
"book_id": {"type": "string", "description": "书籍 ID"},
"event_id": {
"type": "string",
"description": "可选,仅规划指定粗纲事件;缺省则规划全部",
},
"profile_id": {"type": "string", "description": "API 配置 profile ID"},
"api_config": {"type": "object", "description": "可选 inline API 配置"},
},
"required": ["book_id"],
},
)
registry.register(
"fiction.chapter",
fiction_chapter,
description="根据 chapterPlan brief 撰写章节正文,写入 chapters 目录",
parameters={
"type": "object",
"properties": {
"book_id": {"type": "string", "description": "书籍 ID"},
"seq": {
"type": "integer",
"description": "可选,指定章节序号;缺省则写下一未写章",
},
"profile_id": {"type": "string", "description": "API 配置 profile ID"},
"api_config": {"type": "object", "description": "可选 inline API 配置"},
},
"required": ["book_id"],
},
)
# 模块加载时注册到默认 registry
try:
from services.tool_registry import default_tool_registry
register_fiction_tools(default_tool_registry)
except Exception:
pass