feat: 添加测试用户到种子数据, AI改写功能优化, 前端联调修复
This commit is contained in:
@@ -274,6 +274,139 @@ class AIService:
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
async def continue_ending(
|
||||
self,
|
||||
story_title: str,
|
||||
story_category: str,
|
||||
ending_name: str,
|
||||
ending_content: str,
|
||||
user_prompt: str
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
AI续写结局,从结局开始续写新的剧情分支
|
||||
"""
|
||||
print(f"\n[continue_ending] ========== 开始调用 ==========")
|
||||
print(f"[continue_ending] story_title={story_title}, category={story_category}")
|
||||
print(f"[continue_ending] ending_name={ending_name}")
|
||||
print(f"[continue_ending] user_prompt={user_prompt}")
|
||||
print(f"[continue_ending] enabled={self.enabled}, api_key存在={bool(self.api_key)}")
|
||||
|
||||
if not self.enabled or not self.api_key:
|
||||
print(f"[continue_ending] 服务未启用或API Key为空,返回None")
|
||||
return None
|
||||
|
||||
# 构建系统提示词
|
||||
system_prompt = """你是一个专业的互动故事续写专家。用户已经到达故事的某个结局,现在想要从这个结局继续故事发展。
|
||||
|
||||
【任务】
|
||||
请从这个结局开始,创作故事的延续。新剧情必须紧接结局内容,仿佛故事并没有在此结束,而是有了新的发展。
|
||||
|
||||
【写作要求】
|
||||
1. 第一个节点必须紧密衔接原结局,像是结局之后自然发生的事
|
||||
2. 生成 4-6 个新节点,形成有层次的剧情发展(起承转合)
|
||||
3. 每个节点内容 150-300 字,要分 2-3 个自然段(用\\n\\n分隔),包含:场景描写、人物对话、心理活动
|
||||
4. 每个非结局节点有 2 个选项,选项要有明显的剧情差异和后果
|
||||
5. 严格符合用户的续写意图,围绕用户指令展开剧情
|
||||
6. 保持原故事的人物性格、语言风格和世界观
|
||||
7. 对话要自然生动,描写要有画面感
|
||||
|
||||
【关于新结局 - 极其重要!】
|
||||
★★★ 每一条分支路径的尽头必须是新结局节点 ★★★
|
||||
- 结局节点必须设置 "is_ending": true
|
||||
- 结局内容要 200-400 字,分 2-3 段,有情感冲击力
|
||||
- 结局名称 4-8 字,体现剧情走向
|
||||
- 如果有2个选项分支,最终必须有2个不同的结局
|
||||
- 每个结局必须有 "ending_score" 评分(0-100)
|
||||
|
||||
【输出格式】(严格JSON,不要有任何额外文字)
|
||||
{
|
||||
"nodes": {
|
||||
"continue_1": {
|
||||
"content": "续写剧情第一段(150-300字)...",
|
||||
"speaker": "旁白",
|
||||
"choices": [
|
||||
{"text": "选项A(5-15字)", "nextNodeKey": "continue_2a"},
|
||||
{"text": "选项B(5-15字)", "nextNodeKey": "continue_2b"}
|
||||
]
|
||||
},
|
||||
"continue_2a": {
|
||||
"content": "...",
|
||||
"speaker": "旁白",
|
||||
"choices": [
|
||||
{"text": "选项C", "nextNodeKey": "continue_ending_good"},
|
||||
{"text": "选项D", "nextNodeKey": "continue_ending_bad"}
|
||||
]
|
||||
},
|
||||
"continue_ending_good": {
|
||||
"content": "新好结局内容(200-400字)...\\n\\n【达成结局:xxx】",
|
||||
"speaker": "旁白",
|
||||
"is_ending": true,
|
||||
"ending_name": "新结局名称",
|
||||
"ending_type": "good",
|
||||
"ending_score": 90
|
||||
},
|
||||
"continue_ending_bad": {
|
||||
"content": "新坏结局内容...\\n\\n【达成结局:xxx】",
|
||||
"speaker": "旁白",
|
||||
"is_ending": true,
|
||||
"ending_name": "新结局名称",
|
||||
"ending_type": "bad",
|
||||
"ending_score": 40
|
||||
}
|
||||
},
|
||||
"entryNodeKey": "continue_1"
|
||||
}"""
|
||||
|
||||
# 构建用户提示词
|
||||
user_prompt_text = f"""【原故事信息】
|
||||
故事标题:{story_title}
|
||||
故事分类:{story_category}
|
||||
|
||||
【已达成的结局】
|
||||
结局名称:{ending_name}
|
||||
结局内容:{ending_content[:800]}
|
||||
|
||||
【用户续写指令】
|
||||
{user_prompt}
|
||||
|
||||
请从这个结局开始续写新的剧情分支(输出JSON格式):"""
|
||||
|
||||
print(f"[continue_ending] 提示词构建完成,开始调用AI...")
|
||||
|
||||
try:
|
||||
result = None
|
||||
if self.provider == "openai":
|
||||
result = await self._call_openai_long(system_prompt, user_prompt_text)
|
||||
elif self.provider == "claude":
|
||||
result = await self._call_claude(f"{system_prompt}\n\n{user_prompt_text}")
|
||||
elif self.provider == "qwen":
|
||||
result = await self._call_qwen_long(system_prompt, user_prompt_text)
|
||||
elif self.provider == "deepseek":
|
||||
result = await self._call_deepseek_long(system_prompt, user_prompt_text)
|
||||
|
||||
print(f"[continue_ending] AI调用完成,result存在={result is not None}")
|
||||
|
||||
if result and result.get("content"):
|
||||
print(f"[continue_ending] AI返回内容长度={len(result.get('content', ''))}")
|
||||
|
||||
# 解析JSON响应(复用 rewrite_branch 的解析方法)
|
||||
parsed = self._parse_branch_json(result["content"])
|
||||
print(f"[continue_ending] JSON解析结果: parsed存在={parsed is not None}")
|
||||
|
||||
if parsed:
|
||||
parsed["tokens_used"] = result.get("tokens_used", 0)
|
||||
print(f"[continue_ending] 成功! nodes数量={len(parsed.get('nodes', {}))}")
|
||||
return parsed
|
||||
else:
|
||||
print(f"[continue_ending] JSON解析失败!")
|
||||
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"[continue_ending] 异常: {type(e).__name__}: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def _parse_branch_json(self, content: str) -> Optional[Dict]:
|
||||
"""解析AI返回的分支JSON"""
|
||||
print(f"[_parse_branch_json] 开始解析,内容长度={len(content)}")
|
||||
|
||||
Reference in New Issue
Block a user