Files
SillyTavern_replica/backend/services/fiction_prompt_utils.py

126 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
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.
"""
爽文提示词解析 — 用户自然语言 + 内部 JSON 输出格式(不暴露给前端)。
"""
from __future__ import annotations
from typing import Dict
# 新建书籍时的默认用户向提示(自然语言,不含 JSON 结构)
USER_DEFAULT_PROMPTS: Dict[str, str] = {
"openBook": (
"你是爽文开书优化助手。根据用户创作灵感,提炼书名、优化简介,"
"并生成主角人设、核心爽点、读者体验策略与创作禁区。"
"从情绪流目录中挑选 14 个最匹配的条目。"
),
"coarseOutline": (
"你是爽文大纲助手。根据本书设定与进度,生成事件链级别的粗纲,"
"每个事件包含标题与概要,节奏紧凑、爽点清晰。"
),
"eventPlan": (
"你是爽文事件规划助手。将粗纲中的事件展开为章节级计划,"
"结合情绪流起承转合,为每章规划核心冲突与爽点。"
),
"chapter": (
"你是爽文章节写作助手。根据事件计划、guide 设定与上文撰写正文,"
"节奏明快、对话推动冲突、章末留钩子。"
),
"nudge": (
"你是爽文创作教练。根据当前进度与读者体验目标,"
"给出 13 条简短的下一步写作建议,不直接写正文。"
),
}
# 调用 LLM 时在系统提示末尾追加的输出格式(用户 UI 不可见)
_INTERNAL_FORMAT: Dict[str, str] = {
"openBook": """
【输出格式】只输出 JSON不要 markdown 代码块外的文字:
{
"title": "书名",
"optimizedIntro": "优化后的开书灵感",
"guide": {
"persona": "主角人设:身份、性格、欲望、能力边界与成长方向",
"highlight": "核心爽点:本书最稳定兑现的爽点、打脸方式、升级/获得感",
"experience": "用户体验:视角/人称、听感、节奏、世界感与读者情绪承诺",
"forbiddenZones": "创作禁区:不能写、不能破坏、不能弱化的内容"
},
"allowedFlowIds": ["flow-id"]
}""",
"volumeOutline": """
【输出格式】只输出 JSON不要 markdown 代码块外的文字:
{
"id": "vol_001",
"order": 1,
"title": "卷名",
"goal": "本卷目标",
"coreConflict": "本卷核心冲突",
"powerProgression": "本卷成长/变化",
"emotionalPromise": "本卷情绪承诺",
"endingHook": "本卷结尾钩子",
"targetChapterCount": 20,
"primaryEmotionFlowId": "emotion-flow-id",
"status": "active"
}""",
"eventChain": """
【输出格式】只输出 JSON不要 markdown 代码块外的文字:
{
"events": [
{
"id": "evt_0001",
"volumeId": "vol_001",
"order": 1,
"title": "事件标题",
"summary": "事件概要",
"purpose": "事件作用",
"conflict": "事件冲突",
"turningPoint": "事件转折",
"expectedPayoff": "预期兑现",
"targetChapterCount": 3,
"emotionFlowId": "emotion-flow-id",
"emotionStepKey": "情感链步骤 key",
"emotionStepText": "情感链步骤 text",
"status": "planned"
}
]
}""",
"chapterPlan": """
【输出格式】只输出 JSON不要 markdown 代码块外的文字:
{
"chapterPlan": [
{
"title": "章标题",
"goal": "本章目标",
"opening": "开场内容",
"mainConflict": "本章主要冲突",
"emotionalTurn": "本章情绪变化",
"emotionStepKey": "情感链步骤 key",
"emotionGoal": "本章情绪目标",
"payoff": "本章兑现",
"endingHook": "章末信息",
"forbidden": "本章禁止事项",
"targetWords": 2000,
"status": "planned"
}
]
}""",
"chapter": """
【输出格式】只输出 JSON
{ "title": "章标题", "body": "正文(可分段)" }""",
"nudge": "",
}
def resolve_prompt(prompt_key: str, user_text: str | None) -> str:
"""合并用户自然语言指令与内部 JSON 输出格式,供 LLM 系统提示使用。"""
base = (user_text or "").strip()
if not base:
base = USER_DEFAULT_PROMPTS.get(prompt_key, "")
fmt = _INTERNAL_FORMAT.get(prompt_key, "")
if fmt and fmt.strip() not in base:
return base + fmt
return base