feat: add NovelPage component with bookshelf, open book, and reading views
This commit is contained in:
185
backend/services/tools/fiction_tools.py
Normal file
185
backend/services/tools/fiction_tools.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""
|
||||
爽文工作流 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
|
||||
Reference in New Issue
Block a user