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
+52 -120
View File
@@ -1,5 +1,5 @@
"""灵感模式API - 通过对话引导创建项目"""
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Dict, Any
import json
@@ -7,97 +7,13 @@ import json
from app.database import get_db
from app.services.ai_service import AIService
from app.api.settings import get_user_ai_service
from app.services.prompt_service import prompt_service, PromptService
from app.logger import get_logger
router = APIRouter(prefix="/inspiration", tags=["灵感模式"])
logger = get_logger(__name__)
# 灵感模式提示词模板
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个类型标签"
}
}
# 不同阶段的temperature设置(递减以保持一致性)
TEMPERATURE_SETTINGS = {
"title": 0.8, # 书名阶段可以更有创意
@@ -153,6 +69,8 @@ def validate_options_response(result: Dict[str, Any], step: str, max_retries: in
@router.post("/generate-options")
async def generate_options(
data: Dict[str, Any],
http_request: Request,
db: AsyncSession = Depends(get_db),
ai_service: AIService = Depends(get_user_ai_service)
) -> Dict[str, Any]:
"""
@@ -183,28 +101,49 @@ async def generate_options(
logger.info(f"灵感模式:生成{step}阶段的选项(第{attempt + 1}次尝试)")
# 获取对应的提示词模板
if step not in INSPIRATION_PROMPTS:
# 获取用户ID
user_id = getattr(http_request.state, 'user_id', None)
# 获取对应的提示词模板(根据step确定模板key)
template_key_map = {
"title": "INSPIRATION_TITLE",
"description": "INSPIRATION_DESCRIPTION",
"theme": "INSPIRATION_THEME",
"genre": "INSPIRATION_GENRE"
}
template_key = template_key_map.get(step)
if not template_key:
return {
"error": f"不支持的步骤: {step}",
"prompt": "",
"options": []
}
prompt_template = INSPIRATION_PROMPTS[step]
# 获取自定义提示词模板
prompt_template_str = await PromptService.get_template(template_key, user_id, db)
# 准备格式化参数(提供默认值避免KeyError
# 关键改进:保持initial_idea在所有阶段传递,确保内容关联性
# 准备格式化参数
format_params = {
"initial_idea": context.get("initial_idea", context.get("description", "")), # 优先使用initial_idea,兼容旧数据
"initial_idea": context.get("initial_idea", context.get("description", "")),
"title": context.get("title", ""),
"description": context.get("description", ""),
"theme": context.get("theme", "")
}
# 格式化系统提示词
system_prompt = prompt_template["system"].format(**format_params)
user_prompt = prompt_template["user"].format(**format_params)
# 格式化提示词(灵感模式的模板是特殊格式,包含system和user两部分)
# 尝试解析为JSON格式的字典
try:
prompt_template = json.loads(prompt_template_str)
system_prompt = prompt_template["system"].format(**format_params)
user_prompt = prompt_template["user"].format(**format_params)
except (json.JSONDecodeError, KeyError):
# 如果不是JSON格式,降级使用原有方法
prompt_template = prompt_service.get_inspiration_prompt(step)
if not prompt_template:
return {"error": f"无法获取提示词模板: {step}", "prompt": "", "options": []}
system_prompt = prompt_template["system"].format(**format_params)
user_prompt = prompt_template["user"].format(**format_params)
# 如果是重试,在提示词中强调格式要求
if attempt > 0:
@@ -302,6 +241,8 @@ async def generate_options(
@router.post("/quick-generate")
async def quick_generate(
data: Dict[str, Any],
http_request: Request,
db: AsyncSession = Depends(get_db),
ai_service: AIService = Depends(get_user_ai_service)
) -> Dict[str, Any]:
"""
@@ -326,6 +267,9 @@ async def quick_generate(
try:
logger.info("灵感模式:智能补全")
# 获取用户ID
user_id = getattr(http_request.state, 'user_id', None)
# 构建补全提示词
existing_info = []
if data.get("title"):
@@ -339,35 +283,23 @@ async def quick_generate(
existing_text = "\n".join(existing_info) if existing_info else "暂无信息"
system_prompt = """你是一位专业的小说创作顾问。用户提供了部分小说信息,请补全缺失的字段。
用户已提供的信息:
{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,不要有其他文字。"""
# 获取自定义提示词模板
prompt_template_str = await PromptService.get_template("INSPIRATION_QUICK_COMPLETE", user_id, db)
user_prompt = "请补全小说信息"
# 格式化提示词
try:
prompts = json.loads(prompt_template_str)
# 格式化参数
prompts["system"] = prompts["system"].replace("{existing}", existing_text)
prompts["user"] = prompts["user"].replace("{existing}", existing_text)
except (json.JSONDecodeError, KeyError):
# 降级使用原有方法
prompts = prompt_service.get_inspiration_quick_complete_prompt(existing=existing_text)
# 调用AI
response = await ai_service.generate_text(
prompt=user_prompt,
system_prompt=system_prompt.format(existing=existing_text),
prompt=prompts["user"],
system_prompt=prompts["system"],
temperature=0.7
)