update:1.开放系统内置提示词,支持用户自定义模板

This commit is contained in:
xiamuceer
2025-11-29 22:01:02 +08:00
parent e772676621
commit d102328b75
23 changed files with 2325 additions and 746 deletions
+30 -117
View File
@@ -1,7 +1,8 @@
"""章节重新生成服务"""
from typing import Dict, Any, AsyncGenerator, Optional, List
from sqlalchemy.ext.asyncio import AsyncSession
from app.services.ai_service import AIService
from app.services.prompt_service import prompt_service
from app.services.prompt_service import prompt_service, PromptService
from app.models.chapter import Chapter
from app.models.memory import PlotAnalysis
from app.schemas.regeneration import ChapterRegenerateRequest, PreserveElementsConfig
@@ -24,7 +25,9 @@ class ChapterRegenerator:
analysis: Optional[PlotAnalysis],
regenerate_request: ChapterRegenerateRequest,
project_context: Dict[str, Any],
style_content: str = ""
style_content: str = "",
user_id: str = None,
db: AsyncSession = None
) -> AsyncGenerator[Dict[str, Any], None]:
"""
根据反馈重新生成章节(流式)
@@ -34,6 +37,9 @@ class ChapterRegenerator:
analysis: 分析结果(可选)
regenerate_request: 重新生成请求参数
project_context: 项目上下文(项目信息、角色、大纲等)
style_content: 写作风格
user_id: 用户ID(用于获取自定义提示词)
db: 数据库会话(用于查询自定义提示词)
Yields:
包含类型和数据的字典: {'type': 'progress'/'chunk', 'data': ...}
@@ -52,12 +58,14 @@ class ChapterRegenerator:
# 2. 构建完整提示词
yield {'type': 'progress', 'progress': 10, 'message': '正在构建生成提示词...'}
full_prompt = self._build_regeneration_prompt(
full_prompt = await self._build_regeneration_prompt(
chapter=chapter,
modification_instructions=modification_instructions,
project_context=project_context,
regenerate_request=regenerate_request,
style_content=style_content
style_content=style_content,
user_id=user_id,
db=db
)
logger.info(f"🎯 提示词构建完成,开始AI生成")
@@ -158,126 +166,31 @@ class ChapterRegenerator:
return "\n".join(instructions)
def _build_regeneration_prompt(
async def _build_regeneration_prompt(
self,
chapter: Chapter,
modification_instructions: str,
project_context: Dict[str, Any],
regenerate_request: ChapterRegenerateRequest,
style_content: str = ""
style_content: str = "",
user_id: str = None,
db: AsyncSession = None
) -> str:
"""构建完整的重新生成提示词"""
prompt_parts = []
# 系统角色
prompt_parts.append("""你是一位经验丰富的专业小说编辑和作家。现在需要根据反馈意见重新创作一个章节。
你的任务是:
1. 仔细理解原章节的内容和意图
2. 认真分析所有的修改要求
3. 在保持故事连贯性的前提下,创作一个改进后的新版本
4. 确保新版本在艺术性和可读性上都有明显提升
---
""")
# 原始章节信息
prompt_parts.append(f"""## 📖 原始章节信息
**章节**:第{chapter.chapter_number}
**标题**{chapter.title}
**字数**{chapter.word_count}
**原始内容**
{chapter.content}
---
""")
# 修改指令
prompt_parts.append(modification_instructions)
prompt_parts.append("\n---\n")
# 项目背景信息
prompt_parts.append(f"""## 🌍 项目背景信息
**小说标题**{project_context.get('project_title', '未知')}
**题材**{project_context.get('genre', '未设定')}
**主题**{project_context.get('theme', '未设定')}
**叙事视角**{project_context.get('narrative_perspective', '第三人称')}
**世界观设定**
- 时代背景:{project_context.get('time_period', '未设定')}
- 地理位置:{project_context.get('location', '未设定')}
- 氛围基调:{project_context.get('atmosphere', '未设定')}
---
""")
# 角色信息
if project_context.get('characters_info'):
prompt_parts.append(f"""## 👥 角色信息
{project_context['characters_info']}
---
""")
# 章节大纲
if project_context.get('chapter_outline'):
prompt_parts.append(f"""## 📝 本章大纲
{project_context['chapter_outline']}
---
""")
# 前置章节上下文
if project_context.get('previous_context'):
prompt_parts.append(f"""## 📚 前置章节上下文
{project_context['previous_context']}
---
""")
# 写作风格要求(如果提供)
if style_content:
prompt_parts.append(f"""## 🎨 写作风格要求
{style_content}
请在重新创作时严格遵循上述写作风格。
---
""")
# 创作要求
prompt_parts.append(f"""## ✨ 创作要求
1. **解决问题**:针对上述修改指令中提到的所有问题进行改进
2. **保持连贯**:确保与前后章节的情节、人物、风格保持一致
3. **提升质量**:在节奏、情感、描写等方面明显优于原版
4. **保留精华**:保持原章节中优秀的部分和关键情节
5. **字数控制**:目标字数约{regenerate_request.target_word_count}字(可适当浮动±20%
{f'6. **风格一致**:严格按照上述写作风格进行创作' if style_content else ''}
---
## 🎬 开始创作
请现在开始创作改进后的新版本章节内容。
**重要提示**
- 直接输出章节正文内容,从故事内容开始写
- **不要**输出章节标题(如"第X章""第X章:XXX"等)
- **不要**输出任何额外的说明、注释或元数据
- 只需要纯粹的故事正文内容
现在开始:
""")
return "\n".join(prompt_parts)
# 获取自定义提示词模板
template = await PromptService.get_template("CHAPTER_REGENERATION", user_id, db)
# 格式化提示词
return PromptService.format_prompt(
template,
chapter_number=chapter.chapter_number,
title=chapter.title,
word_count=chapter.word_count,
content=chapter.content,
modification_instructions=modification_instructions,
project_context=project_context,
style_content=style_content,
target_word_count=regenerate_request.target_word_count
)
def calculate_content_diff(
self,
+4 -18
View File
@@ -13,6 +13,7 @@ from app.models.settings import Settings as UserSettings
from app.mcp.registry import mcp_registry
from app.services.ai_service import create_user_ai_service
from app.schemas.mcp_plugin import MCPTestResult
from app.services.prompt_service import prompt_service
from app.logger import get_logger
from app.user_manager import User
@@ -168,26 +169,11 @@ class MCPTestService:
logger.debug(f"📋 OpenAI工具列表: {[t['function']['name'] for t in openai_tools]}")
# 调用AI选择工具
prompt = f"""你是MCP插件测试助手,需要测试插件 '{plugin.plugin_name}' 的功能。
⚠️ 重要规则:生成参数时,必须严格使用工具 schema 中定义的原始参数名称,不要转换为 snake_case 或其他格式。
例如:如果 schema 中是 'nextThoughtNeeded',就必须使用 'nextThoughtNeeded',不能改成 'next_thought_needed'
请选择一个合适的工具进行测试,优先选择搜索、查询类工具。
生成真实有效的测试参数(例如搜索"人工智能最新进展"而不是"test")。
现在开始测试这个插件。"""
system_prompt = """你是专业的API测试工具。当给定工具列表时,选择一个工具并使用合适的参数调用它。
⚠️ 关键规则:调用工具时,必须严格使用 schema 中定义的原始参数名,不要自行转换命名风格。
- 如果参数名是 camelCase(如 nextThoughtNeeded),就使用 camelCase
- 如果参数名是 snake_case(如 next_thought),就使用 snake_case
- 保持与 schema 中定义的完全一致,包括大小写和命名风格"""
prompts = prompt_service.get_mcp_tool_test_prompts(plugin.plugin_name)
ai_response = await ai_service.generate_text(
prompt=prompt,
system_prompt=system_prompt,
prompt=prompts["user"],
system_prompt=prompts["system"],
tools=openai_tools,
tool_choice="required"
)
+12 -166
View File
@@ -1,6 +1,8 @@
"""剧情分析服务 - 自动分析章节的钩子、伏笔、冲突等元素"""
from typing import Dict, Any, List, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from app.services.ai_service import AIService
from app.services.prompt_service import prompt_service, PromptService
from app.logger import get_logger
import json
import re
@@ -11,169 +13,6 @@ logger = get_logger(__name__)
class PlotAnalyzer:
"""剧情分析器 - 使用AI分析章节内容"""
# AI分析提示词模板
ANALYSIS_PROMPT = """你是一位专业的小说编辑和剧情分析师。请深度分析以下章节内容:
**章节信息:**
- 章节: 第{chapter_number}
- 标题: {title}
- 字数: {word_count}
**章节内容:**
{content}
---
**分析任务:**
请从专业编辑的角度,全面分析这一章节:
### 1. 剧情钩子 (Hooks) - 吸引读者的元素
识别能够吸引读者继续阅读的关键元素:
- **悬念钩子**: 未解之谜、疑问、谜团
- **情感钩子**: 引发共鸣的情感点、触动心弦的时刻
- **冲突钩子**: 矛盾对抗、紧张局势
- **认知钩子**: 颠覆认知的信息、惊人真相
每个钩子需要:
- 类型分类
- 具体内容描述
- 强度评分(1-10)
- 出现位置(开头/中段/结尾)
- **关键词**: 【必填】从章节原文中逐字复制一段关键文本(8-25字),必须是原文中真实存在的连续文字,用于在文本中精确定位。不要概括或改写,必须原样复制!
### 2. 伏笔分析 (Foreshadowing)
- **埋下的新伏笔**: 描述内容、预期作用、隐藏程度(1-10)
- **回收的旧伏笔**: 呼应哪一章、回收效果评分
- **伏笔质量**: 巧妙性和合理性评估
- **关键词**: 【必填】从章节原文中逐字复制一段关键文本(8-25字),必须是原文中真实存在的连续文字,用于在文本中精确定位。不要概括或改写,必须原样复制!
### 3. 冲突分析 (Conflict)
- 冲突类型: 人与人/人与己/人与环境/人与社会
- 冲突各方及其立场
- 冲突强度评分(1-10)
- 冲突解决进度(0-100%)
### 4. 情感曲线 (Emotional Arc)
- 主导情绪: 紧张/温馨/悲伤/激昂/平静等
- 情感强度(1-10)
- 情绪变化轨迹描述
### 5. 角色状态追踪 (Character Development)
对每个出场角色分析:
- 心理状态变化(前→后)
- 关系变化
- 关键行动和决策
- 成长或退步
### 6. 关键情节点 (Plot Points)
列出3-5个核心情节点:
- 情节内容
- 类型(revelation/conflict/resolution/transition)
- 重要性(0.0-1.0)
- 对故事的影响
- **关键词**: 【必填】从章节原文中逐字复制一段关键文本(8-25字),必须是原文中真实存在的连续文字,用于在文本中精确定位。不要概括或改写,必须原样复制!
### 7. 场景与节奏
- 主要场景
- 叙事节奏(快/中/慢)
- 对话与描写的比例
### 8. 质量评分
- 节奏把控: 1-10分
- 吸引力: 1-10分
- 连贯性: 1-10分
- 整体质量: 1-10分
### 9. 改进建议
提供3-5条具体的改进建议
---
**输出格式(纯JSON,不要markdown标记):**
{{
"hooks": [
{{
"type": "悬念",
"content": "具体描述",
"strength": 8,
"position": "中段",
"keyword": "必须从原文逐字复制的文本片段"
}}
],
"foreshadows": [
{{
"content": "伏笔内容",
"type": "planted",
"strength": 7,
"subtlety": 8,
"reference_chapter": null,
"keyword": "必须从原文逐字复制的文本片段"
}}
],
"conflict": {{
"types": ["人与人", "人与己"],
"parties": ["主角-复仇", "反派-维护现状"],
"level": 8,
"description": "冲突描述",
"resolution_progress": 0.3
}},
"emotional_arc": {{
"primary_emotion": "紧张",
"intensity": 8,
"curve": "平静→紧张→高潮→释放",
"secondary_emotions": ["期待", "焦虑"]
}},
"character_states": [
{{
"character_name": "张三",
"state_before": "犹豫",
"state_after": "坚定",
"psychological_change": "心理变化描述",
"key_event": "触发事件",
"relationship_changes": {{"李四": "关系改善"}}
}}
],
"plot_points": [
{{
"content": "情节点描述",
"type": "revelation",
"importance": 0.9,
"impact": "推动故事发展",
"keyword": "必须从原文逐字复制的文本片段"
}}
],
"scenes": [
{{
"location": "地点",
"atmosphere": "氛围",
"duration": "时长估计"
}}
],
"pacing": "varied",
"dialogue_ratio": 0.4,
"description_ratio": 0.3,
"scores": {{
"pacing": 8,
"engagement": 9,
"coherence": 8,
"overall": 8.5
}},
"plot_stage": "发展",
"suggestions": [
"具体建议1",
"具体建议2"
]
}}
**重要提示:**
1. 每个钩子、伏笔、情节点的keyword字段是必填的,不能为空
2. keyword必须是从章节原文中逐字复制的文本,长度8-25字
3. keyword用于在前端标注文本位置,所以必须能在原文中精确找到
4. 不要使用概括性语句或改写后的文字作为keyword
只返回JSON,不要其他说明。"""
def __init__(self, ai_service: AIService):
"""
初始化剧情分析器
@@ -189,7 +28,9 @@ class PlotAnalyzer:
chapter_number: int,
title: str,
content: str,
word_count: int
word_count: int,
user_id: str = None,
db: AsyncSession = None
) -> Optional[Dict[str, Any]]:
"""
分析单章内容
@@ -199,6 +40,8 @@ class PlotAnalyzer:
title: 章节标题
content: 章节内容
word_count: 字数
user_id: 用户ID(用于获取自定义提示词)
db: 数据库会话(用于查询自定义提示词)
Returns:
分析结果字典,失败返回None
@@ -209,8 +52,11 @@ class PlotAnalyzer:
# 如果内容过长,截取前8000字(避免超token)
analysis_content = content[:8000] if len(content) > 8000 else content
# 构建提示词
prompt = self.ANALYSIS_PROMPT.format(
# 获取自定义提示词模板
template = await PromptService.get_template("PLOT_ANALYSIS", user_id, db)
# 格式化提示词
prompt = PromptService.format_prompt(
template,
chapter_number=chapter_number,
title=title,
word_count=word_count,
+55 -268
View File
@@ -9,6 +9,7 @@ from app.models.project import Project
from app.models.character import Character
from app.models.chapter import Chapter
from app.services.ai_service import AIService
from app.services.prompt_service import prompt_service, PromptService
from app.logger import get_logger
logger = get_logger(__name__)
@@ -107,15 +108,27 @@ class PlotExpansionService:
# 获取大纲上下文(前后大纲)
context_info = await self._get_outline_context(outline, project.id, db)
# 构建分析提示词
prompt = self._build_expansion_prompt(
outline=outline,
project=project,
characters_info=characters_info,
# 获取自定义提示词模板
template = await PromptService.get_template("PLOT_EXPANSION_SINGLE_BATCH", project.user_id, db)
# 格式化提示词
prompt = PromptService.format_prompt(
template,
project_title=project.title,
project_genre=project.genre or '通用',
project_theme=project.theme or '未设定',
project_narrative_perspective=project.narrative_perspective or '第三人称',
project_world_time_period=project.world_time_period or '未设定',
project_world_location=project.world_location or '未设定',
project_world_atmosphere=project.world_atmosphere or '未设定',
characters_info=characters_info or '暂无角色',
outline_order_index=outline.order_index,
outline_title=outline.title,
outline_content=outline.content,
context_info=context_info,
strategy_instruction=expansion_strategy,
target_chapter_count=target_chapter_count,
expansion_strategy=expansion_strategy,
enable_scene_analysis=enable_scene_analysis
scene_instruction="", # 暂时为空
scene_field="" # 暂时为空
)
# 调用AI生成章节规划
@@ -182,17 +195,43 @@ class PlotExpansionService:
await progress_callback(batch_num + 1, total_batches, current_start_index, current_batch_size)
# 构建当前批次的提示词(包含已生成章节的上下文)
prompt = self._build_batch_expansion_prompt(
outline=outline,
project=project,
characters_info=characters_info,
previous_context = ""
if all_chapter_plans:
previous_summaries = []
for ch in all_chapter_plans[-3:]: # 只显示最近3章
previous_summaries.append(
f"{ch['sub_index']}节《{ch['title']}》: {ch['plot_summary'][:100]}..."
)
previous_context = f"""
【已生成章节概要】(接续生成,注意衔接)
{chr(10).join(previous_summaries)}
⚠️ 当前是第{current_start_index}-{current_start_index + current_batch_size - 1}节(共{target_chapter_count}节中的一部分)
"""
# 获取自定义提示词模板
template = await PromptService.get_template("PLOT_EXPANSION_MULTI_BATCH", project.user_id, db)
# 格式化提示词
prompt = PromptService.format_prompt(
template,
project_title=project.title,
project_genre=project.genre or '通用',
project_theme=project.theme or '未设定',
project_narrative_perspective=project.narrative_perspective or '第三人称',
project_world_time_period=project.world_time_period or '未设定',
project_world_location=project.world_location or '未设定',
project_world_atmosphere=project.world_atmosphere or '未设定',
characters_info=characters_info or '暂无角色',
outline_order_index=outline.order_index,
outline_title=outline.title,
outline_content=outline.content,
context_info=context_info,
target_chapter_count=current_batch_size,
expansion_strategy=expansion_strategy,
enable_scene_analysis=enable_scene_analysis,
previous_context=previous_context,
strategy_instruction=expansion_strategy,
start_index=current_start_index,
previous_chapters=all_chapter_plans,
total_chapters=target_chapter_count
end_index=current_start_index + current_batch_size - 1,
target_chapter_count=current_batch_size,
scene_instruction="", # 暂时为空
scene_field="" # 暂时为空
)
# 调用AI生成当前批次
@@ -452,258 +491,6 @@ class PlotExpansionService:
return context if context else "(无前后文)"
def _build_expansion_prompt(
self,
outline: Outline,
project: Project,
characters_info: str,
context_info: str,
target_chapter_count: int,
expansion_strategy: str,
enable_scene_analysis: bool
) -> str:
"""构建大纲展开提示词"""
strategy_desc = {
"balanced": "均衡展开:每章剧情量相当,节奏平稳",
"climax": "高潮重点:重点章节剧情丰富,其他章节简洁过渡",
"detail": "细节丰富:每章都深入描写,场景和情感细腻"
}
strategy_instruction = strategy_desc.get(expansion_strategy, strategy_desc["balanced"])
# 场景字段(避免f-string中的反斜杠)
scene_field = ',\n "main_scenes": ["场景1", "场景2"]' if enable_scene_analysis else ''
scene_instruction = ""
if enable_scene_analysis:
scene_instruction = """
5. 场景分析(每章需包含):
- 主要场景地点
- 场景氛围
- 关键道具/环境元素
"""
prompt = f"""你是专业的小说情节架构师。请分析以下大纲节点,将其展开为 {target_chapter_count} 个章节的详细规划。
【项目信息】
小说名称:{project.title}
类型:{project.genre or '通用'}
主题:{project.theme or '未设定'}
叙事视角:{project.narrative_perspective or '第三人称'}
【世界观背景】
时间背景:{project.world_time_period or '未设定'}
地理位置:{project.world_location or '未设定'}
氛围基调:{project.world_atmosphere or '未设定'}
【角色信息】
{characters_info or '暂无角色'}
【当前大纲节点 - 展开对象】
序号:第 {outline.order_index}
标题:{outline.title}
内容:{outline.content}
【上下文参考】
{context_info}
【展开策略】
{strategy_instruction}
【⚠️ 重要约束 - 必须严格遵守】
1. **内容边界约束**
- ✅ 只能展开【当前大纲节点】中明确描述的内容
- ❌ 绝对不能推进到后续大纲的内容(如果有【后一节】信息)
- ❌ 不要让剧情快速推进,要深化而非跨越
2. **展开原则**
- 将当前大纲的单一事件拆解为多个细节丰富的章节
- 深入挖掘情感、心理、环境、对话等细节
- 放慢叙事节奏,让读者充分体验当前阶段的剧情
- 每个章节都应该是当前大纲内容的不同侧面或阶段
3. **如何避免剧情越界**
- 如果当前大纲描述"主角遇到困境",展开时应详写困境的发现、分析、情感冲击等
- 不要直接写到"解决困境",除非原大纲明确包含解决过程
- 如果看到【后一节】的内容,那些是禁区,绝不提前展开
【任务要求】
1. 深度分析该大纲的剧情容量和叙事节奏
2. 识别关键剧情点、冲突点和情感转折点(仅限当前大纲范围内)
3. 将大纲拆解为 {target_chapter_count} 个章节,每章需包含:
- sub_index: 子章节序号(1, 2, 3...
- title: 章节标题(体现该章核心冲突或情感)
- plot_summary: 剧情摘要(200-300字,详细描述该章发生的事件,仅限当前大纲内容)
- key_events: 关键事件列表(3-5个关键剧情点,必须在当前大纲范围内)
- character_focus: 角色焦点(主要涉及的角色名称)
- emotional_tone: 情感基调(如:紧张、温馨、悲伤、激动等)
- narrative_goal: 叙事目标(该章要达成的叙事效果)
- conflict_type: 冲突类型(如:内心挣扎、人际冲突、环境挑战等)
- estimated_words: 预计字数(建议2000-5000字)
{scene_instruction}
4. 确保章节间:
- 衔接自然流畅
- 剧情递进合理(但不超出当前大纲边界)
- 节奏张弛有度
- 每章都有明确的叙事价值
- 最后一章结束时,剧情发展程度应恰好完成当前大纲描述的内容,不多不少
【输出格式】
请严格按照以下JSON数组格式输出,不要添加任何其他文字:
[
{{
"sub_index": 1,
"title": "章节标题",
"plot_summary": "该章详细剧情摘要...",
"key_events": ["关键事件1", "关键事件2", "关键事件3"],
"character_focus": ["角色A", "角色B"],
"emotional_tone": "情感基调",
"narrative_goal": "叙事目标",
"conflict_type": "冲突类型",
"estimated_words": 3000{scene_field}
}}
]
请开始分析并生成章节规划:
"""
return prompt
def _build_batch_expansion_prompt(
self,
outline: Outline,
project: Project,
characters_info: str,
context_info: str,
target_chapter_count: int,
expansion_strategy: str,
enable_scene_analysis: bool,
start_index: int,
previous_chapters: List[Dict[str, Any]],
total_chapters: int
) -> str:
"""构建分批展开提示词"""
strategy_desc = {
"balanced": "均衡展开:每章剧情量相当,节奏平稳",
"climax": "高潮重点:重点章节剧情丰富,其他章节简洁过渡",
"detail": "细节丰富:每章都深入描写,场景和情感细腻"
}
strategy_instruction = strategy_desc.get(expansion_strategy, strategy_desc["balanced"])
# 场景字段
scene_field = ',\n "main_scenes": ["场景1", "场景2"]' if enable_scene_analysis else ''
scene_instruction = ""
if enable_scene_analysis:
scene_instruction = """
5. 场景分析(每章需包含):
- 主要场景地点
- 场景氛围
- 关键道具/环境元素
"""
# 构建已生成章节的摘要
previous_context = ""
if previous_chapters:
previous_summaries = []
for ch in previous_chapters[-3:]: # 只显示最近3章
previous_summaries.append(
f"{ch['sub_index']}节《{ch['title']}》: {ch['plot_summary'][:100]}..."
)
previous_context = f"""
【已生成章节概要】(接续生成,注意衔接)
{chr(10).join(previous_summaries)}
⚠️ 当前是第{start_index}-{start_index + target_chapter_count - 1}节(共{total_chapters}节中的一部分)
"""
prompt = f"""你是专业的小说情节架构师。请继续分析以下大纲节点,将其展开为第{start_index}-{start_index + target_chapter_count - 1}节(共{target_chapter_count}个章节)的详细规划。
【项目信息】
小说名称:{project.title}
类型:{project.genre or '通用'}
主题:{project.theme or '未设定'}
叙事视角:{project.narrative_perspective or '第三人称'}
【世界观背景】
时间背景:{project.world_time_period or '未设定'}
地理位置:{project.world_location or '未设定'}
氛围基调:{project.world_atmosphere or '未设定'}
【角色信息】
{characters_info or '暂无角色'}
【当前大纲节点 - 展开对象】
序号:第 {outline.order_index}
标题:{outline.title}
内容:{outline.content}
【上下文参考】
{context_info}
{previous_context}
【展开策略】
{strategy_instruction}
【⚠️ 重要约束 - 必须严格遵守】
1. **内容边界约束**
- ✅ 只能展开【当前大纲节点】中明确描述的内容
- ❌ 绝对不能推进到后续大纲的内容(如果有【后一节】信息)
- ❌ 不要让剧情快速推进,要深化而非跨越
2. **分批连续性约束**
- 这是第{start_index}-{start_index + target_chapter_count - 1}节,是整个展开的一部分
- 必须与前面已生成的章节自然衔接
- 从第{start_index}节开始编号(sub_index从{start_index}开始)
- 继续深化当前大纲的内容,保持叙事连贯性
3. **展开原则**
- 将当前大纲的单一事件拆解为多个细节丰富的章节
- 深入挖掘情感、心理、环境、对话等细节
- 放慢叙事节奏,让读者充分体验当前阶段的剧情
- 每个章节都应该是当前大纲内容的不同侧面或阶段
【任务要求】
1. 深度分析该大纲的剧情容量和叙事节奏
2. 识别关键剧情点、冲突点和情感转折点(仅限当前大纲范围内)
3. 生成第{start_index}-{start_index + target_chapter_count - 1}节的章节规划,每章需包含:
- sub_index: 子章节序号(从{start_index}开始)
- title: 章节标题(体现该章核心冲突或情感)
- plot_summary: 剧情摘要(200-300字,详细描述该章发生的事件)
- key_events: 关键事件列表(3-5个关键剧情点)
- character_focus: 角色焦点(主要涉及的角色名称)
- emotional_tone: 情感基调(如:紧张、温馨、悲伤、激动等)
- narrative_goal: 叙事目标(该章要达成的叙事效果)
- conflict_type: 冲突类型(如:内心挣扎、人际冲突、环境挑战等)
- estimated_words: 预计字数(建议2000-5000字)
{scene_instruction}
4. 确保章节间:
- 与前面章节衔接自然流畅
- 剧情递进合理(但不超出当前大纲边界)
- 节奏张弛有度
- 每章都有明确的叙事价值
【输出格式】
请严格按照以下JSON数组格式输出,不要添加任何其他文字:
[
{{
"sub_index": {start_index},
"title": "章节标题",
"plot_summary": "该章详细剧情摘要...",
"key_events": ["关键事件1", "关键事件2", "关键事件3"],
"character_focus": ["角色A", "角色B"],
"emotional_tone": "情感基调",
"narrative_goal": "叙事目标",
"conflict_type": "冲突类型",
"estimated_words": 3000{scene_field}
}}
]
请开始分析并生成第{start_index}-{start_index + target_chapter_count - 1}节的章节规划:
"""
return prompt
def _parse_expansion_response(
self,
+913
View File
@@ -851,7 +851,510 @@ class PromptService:
1. 只返回纯JSON对象,不要有```json```这样的标记
2. 所有内容描述中严禁使用任何特殊符号
3. 不要有任何额外的文字说明"""
# 情节分析提示词
PLOT_ANALYSIS = """你是一位专业的小说编辑和剧情分析师。请深度分析以下章节内容:
**章节信息:**
- 章节: 第{chapter_number}
- 标题: {title}
- 字数: {word_count}
**章节内容:**
{content}
---
**分析任务:**
请从专业编辑的角度,全面分析这一章节:
### 1. 剧情钩子 (Hooks) - 吸引读者的元素
识别能够吸引读者继续阅读的关键元素:
- **悬念钩子**: 未解之谜、疑问、谜团
- **情感钩子**: 引发共鸣的情感点、触动心弦的时刻
- **冲突钩子**: 矛盾对抗、紧张局势
- **认知钩子**: 颠覆认知的信息、惊人真相
每个钩子需要:
- 类型分类
- 具体内容描述
- 强度评分(1-10)
- 出现位置(开头/中段/结尾)
- **关键词**: 【必填】从章节原文中逐字复制一段关键文本(8-25字),必须是原文中真实存在的连续文字,用于在文本中精确定位。不要概括或改写,必须原样复制!
### 2. 伏笔分析 (Foreshadowing)
- **埋下的新伏笔**: 描述内容、预期作用、隐藏程度(1-10)
- **回收的旧伏笔**: 呼应哪一章、回收效果评分
- **伏笔质量**: 巧妙性和合理性评估
- **关键词**: 【必填】从章节原文中逐字复制一段关键文本(8-25字),必须是原文中真实存在的连续文字,用于在文本中精确定位。不要概括或改写,必须原样复制!
### 3. 冲突分析 (Conflict)
- 冲突类型: 人与人/人与己/人与环境/人与社会
- 冲突各方及其立场
- 冲突强度评分(1-10)
- 冲突解决进度(0-100%)
### 4. 情感曲线 (Emotional Arc)
- 主导情绪: 紧张/温馨/悲伤/激昂/平静等
- 情感强度(1-10)
- 情绪变化轨迹描述
### 5. 角色状态追踪 (Character Development)
对每个出场角色分析:
- 心理状态变化(前→后)
- 关系变化
- 关键行动和决策
- 成长或退步
### 6. 关键情节点 (Plot Points)
列出3-5个核心情节点:
- 情节内容
- 类型(revelation/conflict/resolution/transition)
- 重要性(0.0-1.0)
- 对故事的影响
- **关键词**: 【必填】从章节原文中逐字复制一段关键文本(8-25字),必须是原文中真实存在的连续文字,用于在文本中精确定位。不要概括或改写,必须原样复制!
### 7. 场景与节奏
- 主要场景
- 叙事节奏(快/中/慢)
- 对话与描写的比例
### 8. 质量评分
- 节奏把控: 1-10分
- 吸引力: 1-10分
- 连贯性: 1-10分
- 整体质量: 1-10分
### 9. 改进建议
提供3-5条具体的改进建议
---
**输出格式(纯JSON,不要markdown标记):**
{{
"hooks": [
{{
"type": "悬念",
"content": "具体描述",
"strength": 8,
"position": "中段",
"keyword": "必须从原文逐字复制的文本片段"
}}
],
"foreshadows": [
{{
"content": "伏笔内容",
"type": "planted",
"strength": 7,
"subtlety": 8,
"reference_chapter": null,
"keyword": "必须从原文逐字复制的文本片段"
}}
],
"conflict": {{
"types": ["人与人", "人与己"],
"parties": ["主角-复仇", "反派-维护现状"],
"level": 8,
"description": "冲突描述",
"resolution_progress": 0.3
}},
"emotional_arc": {{
"primary_emotion": "紧张",
"intensity": 8,
"curve": "平静→紧张→高潮→释放",
"secondary_emotions": ["期待", "焦虑"]
}},
"character_states": [
{{
"character_name": "张三",
"state_before": "犹豫",
"state_after": "坚定",
"psychological_change": "心理变化描述",
"key_event": "触发事件",
"relationship_changes": {{"李四": "关系改善"}}
}}
],
"plot_points": [
{{
"content": "情节点描述",
"type": "revelation",
"importance": 0.9,
"impact": "推动故事发展",
"keyword": "必须从原文逐字复制的文本片段"
}}
],
"scenes": [
{{
"location": "地点",
"atmosphere": "氛围",
"duration": "时长估计"
}}
],
"pacing": "varied",
"dialogue_ratio": 0.4,
"description_ratio": 0.3,
"scores": {{
"pacing": 8,
"engagement": 9,
"coherence": 8,
"overall": 8.5
}},
"plot_stage": "发展",
"suggestions": [
"具体建议1",
"具体建议2"
]
}}
**重要提示:**
1. 每个钩子、伏笔、情节点的keyword字段是必填的,不能为空
2. keyword必须是从章节原文中逐字复制的文本,长度8-25字
3. keyword用于在前端标注文本位置,所以必须能在原文中精确找到
4. 不要使用概括性语句或改写后的文字作为keyword
只返回JSON,不要其他说明。"""
# 大纲单批次展开提示词
PLOT_EXPANSION_SINGLE_BATCH = """你是专业的小说情节架构师。请分析以下大纲节点,将其展开为 {target_chapter_count} 个章节的详细规划。
【项目信息】
小说名称:{project_title}
类型:{project_genre}
主题:{project_theme}
叙事视角:{project_narrative_perspective}
【世界观背景】
时间背景:{project_world_time_period}
地理位置:{project_world_location}
氛围基调:{project_world_atmosphere}
【角色信息】
{characters_info}
【当前大纲节点 - 展开对象】
序号:第 {outline_order_index}
标题:{outline_title}
内容:{outline_content}
【上下文参考】
{context_info}
【展开策略】
{strategy_instruction}
【⚠️ 重要约束 - 必须严格遵守】
1. **内容边界约束**
- ✅ 只能展开【当前大纲节点】中明确描述的内容
- ❌ 绝对不能推进到后续大纲的内容(如果有【后一节】信息)
- ❌ 不要让剧情快速推进,要深化而非跨越
2. **展开原则**
- 将当前大纲的单一事件拆解为多个细节丰富的章节
- 深入挖掘情感、心理、环境、对话等细节
- 放慢叙事节奏,让读者充分体验当前阶段的剧情
- 每个章节都应该是当前大纲内容的不同侧面或阶段
3. **如何避免剧情越界**
- 如果当前大纲描述"主角遇到困境",展开时应详写困境的发现、分析、情感冲击等
- 不要直接写到"解决困境",除非原大纲明确包含解决过程
- 如果看到【后一节】的内容,那些是禁区,绝不提前展开
【任务要求】
1. 深度分析该大纲的剧情容量和叙事节奏
2. 识别关键剧情点、冲突点和情感转折点(仅限当前大纲范围内)
3. 将大纲拆解为 {target_chapter_count} 个章节,每章需包含:
- sub_index: 子章节序号(1, 2, 3...
- title: 章节标题(体现该章核心冲突或情感)
- plot_summary: 剧情摘要(200-300字,详细描述该章发生的事件,仅限当前大纲内容)
- key_events: 关键事件列表(3-5个关键剧情点,必须在当前大纲范围内)
- character_focus: 角色焦点(主要涉及的角色名称)
- emotional_tone: 情感基调(如:紧张、温馨、悲伤、激动等)
- narrative_goal: 叙事目标(该章要达成的叙事效果)
- conflict_type: 冲突类型(如:内心挣扎、人际冲突、环境挑战等)
- estimated_words: 预计字数(建议2000-5000字)
{scene_instruction}
4. 确保章节间:
- 衔接自然流畅
- 剧情递进合理(但不超出当前大纲边界)
- 节奏张弛有度
- 每章都有明确的叙事价值
- 最后一章结束时,剧情发展程度应恰好完成当前大纲描述的内容,不多不少
【输出格式】
请严格按照以下JSON数组格式输出,不要添加任何其他文字:
[
{{
"sub_index": 1,
"title": "章节标题",
"plot_summary": "该章详细剧情摘要...",
"key_events": ["关键事件1", "关键事件2", "关键事件3"],
"character_focus": ["角色A", "角色B"],
"emotional_tone": "情感基调",
"narrative_goal": "叙事目标",
"conflict_type": "冲突类型",
"estimated_words": 3000{scene_field}
}}
]
请开始分析并生成章节规划:
"""
# 大纲分批展开提示词
PLOT_EXPANSION_MULTI_BATCH = """你是专业的小说情节架构师。请继续分析以下大纲节点,将其展开为第{start_index}-{end_index}节(共{target_chapter_count}个章节)的详细规划。
【项目信息】
小说名称:{project_title}
类型:{project_genre}
主题:{project_theme}
叙事视角:{project_narrative_perspective}
【世界观背景】
时间背景:{project_world_time_period}
地理位置:{project_world_location}
氛围基调:{project_world_atmosphere}
【角色信息】
{characters_info}
【当前大纲节点 - 展开对象】
序号:第 {outline_order_index}
标题:{outline_title}
内容:{outline_content}
【上下文参考】
{context_info}
{previous_context}
【展开策略】
{strategy_instruction}
【⚠️ 重要约束 - 必须严格遵守】
1. **内容边界约束**
- ✅ 只能展开【当前大纲节点】中明确描述的内容
- ❌ 绝对不能推进到后续大纲的内容(如果有【后一节】信息)
- ❌ 不要让剧情快速推进,要深化而非跨越
2. **分批连续性约束**
- 这是第{start_index}-{end_index}节,是整个展开的一部分
- 必须与前面已生成的章节自然衔接
- 从第{start_index}节开始编号(sub_index从{start_index}开始)
- 继续深化当前大纲的内容,保持叙事连贯性
3. **展开原则**
- 将当前大纲的单一事件拆解为多个细节丰富的章节
- 深入挖掘情感、心理、环境、对话等细节
- 放慢叙事节奏,让读者充分体验当前阶段的剧情
- 每个章节都应该是当前大纲内容的不同侧面或阶段
【任务要求】
1. 深度分析该大纲的剧情容量和叙事节奏
2. 识别关键剧情点、冲突点和情感转折点(仅限当前大纲范围内)
3. 生成第{start_index}-{end_index}节的章节规划,每章需包含:
- sub_index: 子章节序号(从{start_index}开始)
- title: 章节标题(体现该章核心冲突或情感)
- plot_summary: 剧情摘要(200-300字,详细描述该章发生的事件)
- key_events: 关键事件列表(3-5个关键剧情点)
- character_focus: 角色焦点(主要涉及的角色名称)
- emotional_tone: 情感基调(如:紧张、温馨、悲伤、激动等)
- narrative_goal: 叙事目标(该章要达成的叙事效果)
- conflict_type: 冲突类型(如:内心挣扎、人际冲突、环境挑战等)
- estimated_words: 预计字数(建议2000-5000字)
{scene_instruction}
4. 确保章节间:
- 与前面章节衔接自然流畅
- 剧情递进合理(但不超出当前大纲边界)
- 节奏张弛有度
- 每章都有明确的叙事价值
【输出格式】
请严格按照以下JSON数组格式输出,不要添加任何其他文字:
[
{{
"sub_index": {start_index},
"title": "章节标题",
"plot_summary": "该章详细剧情摘要...",
"key_events": ["关键事件1", "关键事件2", "关键事件3"],
"character_focus": ["角色A", "角色B"],
"emotional_tone": "情感基调",
"narrative_goal": "叙事目标",
"conflict_type": "冲突类型",
"estimated_words": 3000{scene_field}
}}
]
请开始分析并生成第{start_index}-{end_index}节的章节规划:
"""
# 章节重写系统提示词
CHAPTER_REGENERATION_SYSTEM = """你是一位经验丰富的专业小说编辑和作家。现在需要根据反馈意见重新创作一个章节。
你的任务是:
1. 仔细理解原始章节的内容和意图
2. 认真分析所有的修改要求
3. 在保持故事连贯性的前提下,创作一个改进后的新版本
4. 确保新版本在艺术性和可读性上都有明显提升
---
"""
# MCP工具测试提示词
MCP_TOOL_TEST = """你是MCP插件测试助手,需要测试插件 '{plugin_name}' 的功能。
⚠️ 重要规则:生成参数时,必须严格使用工具 schema 中定义的原始参数名称,不要转换为 snake_case 或其他格式。
例如:如果 schema 中是 'nextThoughtNeeded',就必须使用 'nextThoughtNeeded',不能改成 'next_thought_needed'
请选择一个合适的工具进行测试,优先选择搜索、查询类工具。
生成真实有效的测试参数(例如搜索"人工智能最新进展"而不是"test")。
现在开始测试这个插件。"""
MCP_TOOL_TEST_SYSTEM = """你是专业的API测试工具。当给定工具列表时,选择一个工具并使用合适的参数调用它。
⚠️ 关键规则:调用工具时,必须严格使用 schema 中定义的原始参数名,不要自行转换命名风格。
- 如果参数名是 camelCase(如 nextThoughtNeeded),就使用 camelCase
- 如果参数名是 snake_case(如 next_thought),就使用 snake_case
- 保持与 schema 中定义的完全一致,包括大小写和命名风格"""
# 灵感模式提示词字典
INSPIRATION_PROMPTS = {
"title": {
"system": """你是一位专业的小说创作顾问。
用户的原始想法:{initial_idea}
请根据用户的想法,生成6个吸引人的书名建议,要求:
1. 紧扣用户的原始想法和核心故事构思
2. 富有创意和吸引力
3. 涵盖不同的风格倾向
返回JSON格式:
{{
"prompt": "根据你的想法,我为你准备了几个书名建议:",
"options": ["书名1", "书名2", "书名3", "书名4", "书名5", "书名6"]
}}
只返回纯JSON,不要有其他文字。""",
"user": "用户的想法:{initial_idea}\n请生成6个书名建议"
},
"description": {
"system": """你是一位专业的小说创作顾问。
用户的原始想法:{initial_idea}
已确定的书名:{title}
请生成6个精彩的小说简介,要求:
1. 必须紧扣用户的原始想法,确保简介是原始想法的具体展开
2. 符合已确定的书名风格
3. 简洁有力,每个50-100字
4. 包含核心冲突
5. 涵盖不同的故事走向,但都基于用户的原始构思
返回JSON格式:
{{"prompt":"选择一个简介:","options":["简介1","简介2","简介3","简介4","简介5","简介6"]}}
只返回纯JSON,不要有其他文字,不要换行。""",
"user": "原始想法:{initial_idea}\n书名:{title}\n请生成6个简介选项"
},
"theme": {
"system": """你是一位专业的小说创作顾问。
用户的原始想法:{initial_idea}
小说信息:
- 书名:{title}
- 简介:{description}
请生成6个深刻的主题选项,要求:
1. 必须与用户的原始想法保持高度一致
2. 符合书名和简介的风格
3. 有深度和思想性
4. 每个50-150字
5. 涵盖不同角度(如:成长、复仇、救赎、探索等),但都围绕用户的核心构思
返回JSON格式:
{{"prompt":"这本书的核心主题是什么?","options":["主题1","主题2","主题3","主题4","主题5","主题6"]}}
只返回纯JSON,不要有其他文字,不要换行。""",
"user": "原始想法:{initial_idea}\n书名:{title}\n简介:{description}\n请生成6个主题选项"
},
"genre": {
"system": """你是一位专业的小说创作顾问。
用户的原始想法:{initial_idea}
小说信息:
- 书名:{title}
- 简介:{description}
- 主题:{theme}
请生成6个合适的类型标签(每个2-4字),要求:
1. 必须符合用户原始想法中暗示的类型倾向
2. 符合小说整体风格
3. 可以多选组合
常见类型:玄幻、都市、科幻、武侠、仙侠、历史、言情、悬疑、奇幻、修仙等
返回JSON格式:
{{"prompt":"选择类型标签(可多选):","options":["类型1","类型2","类型3","类型4","类型5","类型6"]}}
只返回紧凑的纯JSON,不要换行,不要有其他文字。""",
"user": "原始想法:{initial_idea}\n书名:{title}\n简介:{description}\n主题:{theme}\n请生成6个类型标签"
}
}
# 灵感模式智能补全提示词
INSPIRATION_QUICK_COMPLETE = """你是一位专业的小说创作顾问。用户提供了部分小说信息,请补全缺失的字段。
用户已提供的信息:
{existing}
请生成完整的小说方案,包含:
1. title: 书名(3-6字,如果用户已提供则保持原样)
2. description: 简介(50-100字,必须基于用户提供的信息,不要偏离原意)
3. theme: 核心主题(30-50字,必须与用户提供的信息保持一致)
4. genre: 类型标签数组(2-3个)
重要:所有补全的内容都必须与用户提供的信息保持高度关联,确保前后一致性。
返回JSON格式:
{{
"title": "书名",
"description": "简介内容...",
"theme": "主题内容...",
"genre": ["类型1", "类型2"]
}}
只返回纯JSON,不要有其他文字。"""
# 世界观资料收集提示词(MCP增强用)
MCP_WORLD_BUILDING_PLANNING = """你正在为小说《{title}》设计世界观。
【小说信息】
- 题材:{genre}
- 主题:{theme}
- 简介:{description}
【任务】
请使用可用工具搜索相关背景资料,帮助构建更真实、更有深度的世界观设定。
你可以查询:
1. 历史背景(如果是历史题材)
2. 地理环境和文化特征
3. 相关领域的专业知识
4. 类似作品的设定参考
请查询最关键的1个问题(不要超过1个)。"""
# 角色资料收集提示词(MCP增强用)
MCP_CHARACTER_PLANNING = """你正在为小说《{title}》设计角色。
【小说信息】
- 题材:{genre}
- 主题:{theme}
- 时代背景:{time_period}
- 地理位置:{location}
【任务】
请使用可用工具搜索相关参考资料,帮助设计更真实、更有深度的角色。
你可以查询:
1. 该时代/地域的真实历史人物特征
2. 文化背景和社会习俗
3. 职业特点和生活方式
4. 相关领域的人物原型
请查询最关键的1个问题(不要超过1个)。"""
# 大纲展开为多章节的提示词
OUTLINE_EXPANSION = """你是专业的小说情节架构师。请分析以下大纲节点,将其展开为 {target_chapters} 个章节的详细规划。
@@ -1339,7 +1842,417 @@ class PromptService:
scene_instruction=scene_instruction,
scene_field=scene_field
)
@classmethod
def get_plot_analysis_prompt(cls, chapter_number: int, title: str,
content: str, word_count: int) -> str:
"""获取章节剧情分析提示词"""
return cls.format_prompt(
cls.PLOT_ANALYSIS,
chapter_number=chapter_number,
title=title,
content=content,
word_count=word_count
)
@classmethod
def get_plot_expansion_single_batch_prompt(cls, project_title: str, project_genre: str, project_theme: str,
project_narrative_perspective: str, project_world_time_period: str,
project_world_location: str, project_world_atmosphere: str,
characters_info: str, outline_order_index: int, outline_title: str,
outline_content: str, context_info: str, strategy_instruction: str,
target_chapter_count: int, scene_instruction: str, scene_field: str) -> str:
"""获取大纲单批次展开提示词"""
return cls.format_prompt(
cls.PLOT_EXPANSION_SINGLE_BATCH,
project_title=project_title, project_genre=project_genre, project_theme=project_theme,
project_narrative_perspective=project_narrative_perspective, project_world_time_period=project_world_time_period,
project_world_location=project_world_location, project_world_atmosphere=project_world_atmosphere,
characters_info=characters_info, outline_order_index=outline_order_index, outline_title=outline_title,
outline_content=outline_content, context_info=context_info, strategy_instruction=strategy_instruction,
target_chapter_count=target_chapter_count, scene_instruction=scene_instruction, scene_field=scene_field
)
@classmethod
def get_plot_expansion_multi_batch_prompt(cls, project_title: str, project_genre: str, project_theme: str,
project_narrative_perspective: str, project_world_time_period: str,
project_world_location: str, project_world_atmosphere: str,
characters_info: str, outline_order_index: int, outline_title: str,
outline_content: str, context_info: str, previous_context: str,
strategy_instruction: str, start_index: int, end_index: int,
target_chapter_count: int, scene_instruction: str, scene_field: str) -> str:
"""获取大纲分批展开提示词"""
return cls.format_prompt(
cls.PLOT_EXPANSION_MULTI_BATCH,
project_title=project_title, project_genre=project_genre, project_theme=project_theme,
project_narrative_perspective=project_narrative_perspective, project_world_time_period=project_world_time_period,
project_world_location=project_world_location, project_world_atmosphere=project_world_atmosphere,
characters_info=characters_info, outline_order_index=outline_order_index, outline_title=outline_title,
outline_content=outline_content, context_info=context_info, previous_context=previous_context,
strategy_instruction=strategy_instruction, start_index=start_index, end_index=end_index,
target_chapter_count=target_chapter_count, scene_instruction=scene_instruction, scene_field=scene_field
)
@classmethod
def get_chapter_regeneration_prompt(cls, chapter_number: int, title: str, word_count: int, content: str,
modification_instructions: str, project_context: Dict[str, Any],
style_content: str, target_word_count: int) -> str:
"""获取章节重写提示词"""
prompt_parts = [cls.CHAPTER_REGENERATION_SYSTEM]
# 原始章节信息
prompt_parts.append(f"""## 📖 原始章节信息
**章节**:第{chapter_number}
**标题**{title}
**字数**{word_count}
**原始内容**
{content}
---
""")
# 修改指令
prompt_parts.append(modification_instructions)
prompt_parts.append("\n---\n")
# 项目背景信息
prompt_parts.append(f"""## 🌍 项目背景信息
**小说标题**{project_context.get('project_title', '未知')}
**题材**{project_context.get('genre', '未设定')}
**主题**{project_context.get('theme', '未设定')}
**叙事视角**{project_context.get('narrative_perspective', '第三人称')}
**世界观设定**
- 时代背景:{project_context.get('time_period', '未设定')}
- 地理位置:{project_context.get('location', '未设定')}
- 氛围基调:{project_context.get('atmosphere', '未设定')}
---
""")
# 角色信息
if project_context.get('characters_info'):
prompt_parts.append(f"""## 👥 角色信息
{project_context['characters_info']}
---
""")
# 章节大纲
if project_context.get('chapter_outline'):
prompt_parts.append(f"""## 📝 本章大纲
{project_context['chapter_outline']}
---
""")
# 前置章节上下文
if project_context.get('previous_context'):
prompt_parts.append(f"""## 📚 前置章节上下文
{project_context['previous_context']}
---
""")
# 写作风格要求
if style_content:
prompt_parts.append(f"""## 🎨 写作风格要求
{style_content}
请在重新创作时严格遵循上述写作风格。
---
""")
# 创作要求
prompt_parts.append(f"""## ✨ 创作要求
1. **解决问题**:针对上述修改指令中提到的所有问题进行改进
2. **保持连贯**:确保与前后章节的情节、人物、风格保持一致
3. **提升质量**:在节奏、情感、描写等方面明显优于原版
4. **保留精华**:保持原章节中优秀的部分和关键情节
5. **字数控制**:目标字数约{target_word_count}字(可适当浮动±20%
{f'6. **风格一致**:严格按照上述写作风格进行创作' if style_content else ''}
---
## 🎬 开始创作
请现在开始创作改进后的新版本章节内容。
**重要提示**
- 直接输出章节正文内容,从故事内容开始写
- **不要**输出章节标题(如"第X章""第X章:XXX"等)
- **不要**输出任何额外的说明、注释或元数据
- 只需要纯粹的故事正文内容
现在开始:
""")
return "\n".join(prompt_parts)
@classmethod
def get_inspiration_prompt(cls, step: str) -> Optional[Dict[str, str]]:
"""获取灵感模式指定步骤的提示词"""
return cls.INSPIRATION_PROMPTS.get(step)
@classmethod
def get_inspiration_quick_complete_prompt(cls, existing: str) -> Dict[str, str]:
"""获取灵感模式智能补全的提示词"""
return {
"system": cls.format_prompt(cls.INSPIRATION_QUICK_COMPLETE, existing=existing),
"user": "请补全小说信息"
}
@classmethod
def get_mcp_tool_test_prompts(cls, plugin_name: str) -> Dict[str, str]:
"""获取MCP工具测试的提示词"""
return {
"user": cls.format_prompt(cls.MCP_TOOL_TEST, plugin_name=plugin_name),
"system": cls.MCP_TOOL_TEST_SYSTEM
}
# 创建全局提示词服务实例
# ========== 自定义提示词支持 ==========
@classmethod
async def get_template_with_fallback(cls,
template_key: str,
user_id: str = None,
db = None) -> str:
"""
获取提示词模板(优先用户自定义,支持降级)
Args:
template_key: 模板键名
user_id: 用户ID(可选,如果不提供则直接返回系统默认)
db: 数据库会话(可选)
Returns:
提示词模板内容
"""
# 如果没有提供user_id或db,直接返回系统默认
if not user_id or not db:
return getattr(cls, template_key, None)
# 尝试获取用户自定义模板
return await cls.get_template(template_key, user_id, db)
@classmethod
async def get_template(cls,
template_key: str,
user_id: str,
db) -> str:
"""
获取提示词模板(优先用户自定义)
Args:
template_key: 模板键名
user_id: 用户ID
db: 数据库会话
Returns:
提示词模板内容
"""
from sqlalchemy import select
from app.models.prompt_template import PromptTemplate
from app.logger import get_logger
logger = get_logger(__name__)
# 1. 尝试从数据库获取用户自定义模板
result = await db.execute(
select(PromptTemplate).where(
PromptTemplate.user_id == user_id,
PromptTemplate.template_key == template_key,
PromptTemplate.is_active == True
)
)
custom_template = result.scalar_one_or_none()
if custom_template:
logger.info(f"✅ 使用用户自定义提示词: user_id={user_id}, template_key={template_key}, template_name={custom_template.template_name}")
return custom_template.template_content
# 2. 降级到系统默认模板
logger.info(f"⚪ 使用系统默认提示词: user_id={user_id}, template_key={template_key} (未找到自定义模板)")
return getattr(cls, template_key, None)
@classmethod
def get_all_system_templates(cls) -> list:
"""
获取所有系统默认模板的信息
Returns:
系统模板列表
"""
templates = []
# 定义所有模板及其元信息
template_definitions = {
"WORLD_BUILDING": {
"name": "世界构建",
"category": "世界构建",
"description": "用于生成小说世界观设定,包括时间背景、地理位置、氛围基调和世界规则",
"parameters": ["title", "theme", "genre"]
},
"CHARACTERS_BATCH_GENERATION": {
"name": "批量角色生成",
"category": "角色生成",
"description": "批量生成多个角色和组织,建立角色关系网络",
"parameters": ["count", "time_period", "location", "atmosphere", "rules", "theme", "genre", "requirements"]
},
"SINGLE_CHARACTER_GENERATION": {
"name": "单个角色生成",
"category": "角色生成",
"description": "生成单个角色的详细设定",
"parameters": ["project_context", "user_input"]
},
"SINGLE_ORGANIZATION_GENERATION": {
"name": "组织生成",
"category": "角色生成",
"description": "生成组织/势力的详细设定",
"parameters": ["project_context", "user_input"]
},
"COMPLETE_OUTLINE_GENERATION": {
"name": "完整大纲生成",
"category": "大纲生成",
"description": "根据项目信息生成完整的章节大纲",
"parameters": ["title", "theme", "genre", "chapter_count", "narrative_perspective", "target_words",
"time_period", "location", "atmosphere", "rules", "characters_info", "requirements", "mcp_references"]
},
"OUTLINE_CONTINUE_GENERATION": {
"name": "大纲续写",
"category": "大纲生成",
"description": "基于已有章节续写大纲",
"parameters": ["title", "theme", "genre", "narrative_perspective", "chapter_count", "time_period",
"location", "atmosphere", "rules", "characters_info", "current_chapter_count",
"all_chapters_brief", "recent_plot", "memory_context", "mcp_references",
"plot_stage_instruction", "start_chapter", "end_chapter", "story_direction", "requirements"]
},
"OUTLINE_GENERATION": {
"name": "基础大纲生成",
"category": "大纲生成",
"description": "生成基础章节大纲框架",
"parameters": ["genre", "theme", "target_words", "requirements"]
},
"OUTLINE_EXPANSION": {
"name": "大纲展开",
"category": "大纲生成",
"description": "将单个大纲节点展开为多个章节",
"parameters": ["title", "genre", "theme", "narrative_perspective", "time_period", "location",
"atmosphere", "rules", "characters_info", "outline_order", "outline_title",
"outline_content", "context_info", "strategy_instruction", "target_chapters",
"scene_instruction", "scene_field"]
},
"CHAPTER_GENERATION": {
"name": "章节创作",
"category": "章节创作",
"description": "根据大纲创作章节内容",
"parameters": ["title", "theme", "genre", "narrative_perspective", "time_period", "location",
"atmosphere", "rules", "characters_info", "outlines_context", "chapter_number",
"chapter_title", "chapter_outline", "target_word_count", "max_word_count"]
},
"CHAPTER_GENERATION_WITH_CONTEXT": {
"name": "章节创作(带上下文)",
"category": "章节创作",
"description": "基于前置章节内容创作新章节",
"parameters": ["title", "theme", "genre", "narrative_perspective", "time_period", "location",
"atmosphere", "rules", "characters_info", "outlines_context", "previous_content",
"memory_context", "chapter_number", "chapter_title", "chapter_outline",
"target_word_count", "max_word_count"]
},
"CHAPTER_REGENERATION_SYSTEM": {
"name": "章节重写系统提示",
"category": "章节重写",
"description": "用于章节重写的系统提示词",
"parameters": ["chapter_number", "title", "word_count", "content", "modification_instructions",
"project_context", "style_content", "target_word_count"]
},
"AI_DENOISING": {
"name": "AI去味",
"category": "辅助功能",
"description": "将AI生成的文本改写得更自然",
"parameters": ["original_text"]
},
"PLOT_ANALYSIS": {
"name": "情节分析",
"category": "情节分析",
"description": "深度分析章节的剧情、钩子、伏笔等",
"parameters": ["chapter_number", "title", "content", "word_count"]
},
"PLOT_EXPANSION_SINGLE_BATCH": {
"name": "大纲单批次展开",
"category": "情节展开",
"description": "将大纲节点展开为详细章节规划(单批次)",
"parameters": ["project_title", "project_genre", "project_theme", "project_narrative_perspective",
"project_world_time_period", "project_world_location", "project_world_atmosphere",
"characters_info", "outline_order_index", "outline_title", "outline_content",
"context_info", "strategy_instruction", "target_chapter_count", "scene_instruction", "scene_field"]
},
"PLOT_EXPANSION_MULTI_BATCH": {
"name": "大纲分批展开",
"category": "情节展开",
"description": "将大纲节点展开为详细章节规划(分批)",
"parameters": ["project_title", "project_genre", "project_theme", "project_narrative_perspective",
"project_world_time_period", "project_world_location", "project_world_atmosphere",
"characters_info", "outline_order_index", "outline_title", "outline_content",
"context_info", "previous_context", "strategy_instruction", "start_index",
"end_index", "target_chapter_count", "scene_instruction", "scene_field"]
},
"MCP_TOOL_TEST": {
"name": "MCP工具测试",
"category": "MCP测试",
"description": "用于测试MCP插件功能",
"parameters": ["plugin_name"]
},
"MCP_WORLD_BUILDING_PLANNING": {
"name": "MCP世界观规划",
"category": "MCP增强",
"description": "使用MCP工具搜索资料辅助世界观设计",
"parameters": ["title", "genre", "theme", "description"]
},
"MCP_CHARACTER_PLANNING": {
"name": "MCP角色规划",
"category": "MCP增强",
"description": "使用MCP工具搜索资料辅助角色设计",
"parameters": ["title", "genre", "theme", "time_period", "location"]
}
}
for key, info in template_definitions.items():
template_content = getattr(cls, key, None)
if template_content:
templates.append({
"template_key": key,
"template_name": info["name"],
"category": info["category"],
"description": info["description"],
"parameters": info["parameters"],
"content": template_content
})
return templates
@classmethod
def get_system_template_info(cls, template_key: str) -> dict:
"""
获取指定系统模板的信息
Args:
template_key: 模板键名
Returns:
模板信息字典
"""
all_templates = cls.get_all_system_templates()
for template in all_templates:
if template["template_key"] == template_key:
return template
return None
prompt_service = PromptService()