From db4695ef423541e8efba2aae1587d4c24d5e65e5 Mon Sep 17 00:00:00 2001 From: xiamuceer Date: Mon, 5 Jan 2026 21:04:36 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E5=BC=95=E5=85=A5=E8=A7=92=E8=89=B2/=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E7=9A=84=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E6=B7=BB=E5=8A=A0=E6=95=B0=E6=8D=AE=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/outlines.py | 64 ++++++++++++++----- .../app/services/auto_character_service.py | 26 ++------ frontend/src/pages/Outline.tsx | 7 +- 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/backend/app/api/outlines.py b/backend/app/api/outlines.py index b5da33a..08901fe 100644 --- a/backend/app/api/outlines.py +++ b/backend/app/api/outlines.py @@ -909,7 +909,8 @@ async def _continue_outline( stage_instruction = stage_instructions.get(request.plot_stage, "") # 🎭 【方案A】先角色后大纲:在生成大纲前预测并创建角色 - if request.enable_auto_characters: + # 🔧 判断:如果confirmed_organizations存在,说明已经是组织确认阶段,跳过角色处理 + if request.enable_auto_characters and not request.confirmed_organizations: # 检查是否有用户确认的角色列表 if request.confirmed_characters: # 直接使用用户确认的角色列表创建角色 @@ -920,8 +921,18 @@ async def _continue_outline( auto_char_service = get_auto_character_service(user_ai_service) + # 🔧 去重检查:获取现有角色名称列表,避免重复创建 + existing_character_names = {char.name for char in characters} + actually_created_count = 0 + for char_data in request.confirmed_characters: try: + # 检查角色是否已存在 + char_name = char_data.get("name") or char_data.get("character_name") + if char_name in existing_character_names: + logger.warning(f"⚠️ 角色 '{char_name}' 已存在,跳过创建") + continue + # 生成角色详细信息 character_data = await auto_char_service._generate_character_details( spec=char_data, @@ -951,6 +962,8 @@ async def _continue_outline( ) characters.append(character) + existing_character_names.add(character.name) # 更新已存在的角色名称集合 + actually_created_count += 1 logger.info(f"✅ 创建确认的角色: {character.name}") except Exception as e: @@ -958,7 +971,11 @@ async def _continue_outline( continue # 提交角色到数据库 - await db.commit() + if actually_created_count > 0: + await db.commit() + logger.info(f"✅ 【确认模式】实际创建了 {actually_created_count} 个新角色(跳过了 {len(request.confirmed_characters) - actually_created_count} 个已存在的角色)") + else: + logger.info(f"ℹ️ 【确认模式】所有角色均已存在,无需创建") # 更新角色信息(供后续大纲生成使用) characters_info = "\n".join([ @@ -967,8 +984,6 @@ async def _continue_outline( for char in characters ]) - logger.info(f"✅ 【确认模式】成功创建 {len(request.confirmed_characters)} 个用户确认的角色") - except Exception as e: logger.error(f"⚠️ 【确认模式】创建确认角色失败: {e}", exc_info=True) else: @@ -2058,8 +2073,10 @@ async def continue_outline_generator( # 🎭 【方案A】先角色后大纲:在生成大纲前预测并创建角色 enable_auto_characters = data.get("enable_auto_characters", True) confirmed_characters = data.get("confirmed_characters") + confirmed_organizations = data.get("confirmed_organizations") - if enable_auto_characters: + # 🔧 判断:如果confirmed_organizations存在,说明已经是组织确认阶段,跳过角色处理 + if enable_auto_characters and not confirmed_organizations: # 检查是否有用户确认的角色列表 if confirmed_characters: # 直接使用用户确认的角色列表创建角色 @@ -2075,9 +2092,18 @@ async def continue_outline_generator( auto_char_service = get_auto_character_service(user_ai_service) - created_count = 0 + # 🔧 去重检查:获取现有角色名称列表,避免重复创建 + existing_character_names = {char.name for char in characters} + actually_created_count = 0 + for char_data in confirmed_characters: try: + # 检查角色是否已存在 + char_name = char_data.get("name") or char_data.get("character_name") + if char_name in existing_character_names: + logger.warning(f"⚠️ 角色 '{char_name}' 已存在,跳过创建") + continue + # 生成角色详细信息 character_data = await auto_char_service._generate_character_details( spec=char_data, @@ -2107,7 +2133,8 @@ async def continue_outline_generator( ) characters.append(character) - created_count += 1 + existing_character_names.add(character.name) # 更新已存在的角色名称集合 + actually_created_count += 1 logger.info(f"✅ 创建确认的角色: {character.name}") except Exception as e: @@ -2115,13 +2142,19 @@ async def continue_outline_generator( continue # 提交角色到数据库 - await db.commit() - - yield await SSEResponse.send_progress( - f"✅ 【确认模式】成功创建 {created_count} 个角色", - 28 - ) - logger.info(f"✅ 【确认模式】成功创建 {created_count} 个用户确认的角色") + if actually_created_count > 0: + await db.commit() + yield await SSEResponse.send_progress( + f"✅ 【确认模式】实际创建了 {actually_created_count} 个新角色(跳过 {len(confirmed_characters) - actually_created_count} 个已存在)", + 28 + ) + logger.info(f"✅ 【确认模式】实际创建了 {actually_created_count} 个新角色(跳过了 {len(confirmed_characters) - actually_created_count} 个已存在的角色)") + else: + yield await SSEResponse.send_progress( + f"ℹ️ 【确认模式】所有角色均已存在,无需创建", + 28 + ) + logger.info(f"ℹ️ 【确认模式】所有角色均已存在,无需创建") except Exception as e: logger.error(f"⚠️ 【确认模式】创建确认角色失败: {e}", exc_info=True) @@ -2261,7 +2294,8 @@ async def continue_outline_generator( # 🏛️ 【组织引入】在生成大纲前预测并创建组织 enable_auto_organizations = data.get("enable_auto_organizations", True) - confirmed_organizations = data.get("confirmed_organizations") + # confirmed_organizations在上面已经获取了,这里注释掉避免重复 + # confirmed_organizations = data.get("confirmed_organizations") if enable_auto_organizations: from app.models.relationship import Organization diff --git a/backend/app/services/auto_character_service.py b/backend/app/services/auto_character_service.py index 84bd545..78eeb18 100644 --- a/backend/app/services/auto_character_service.py +++ b/backend/app/services/auto_character_service.py @@ -354,26 +354,14 @@ class AutoCharacterService: mcp_references="" # 暂时不使用MCP增强 ) - # 调用AI生成(使用统一的JSON调用方法) + # 调用AI生成(禁用MCP,避免累积超时导致卡死) try: - if enable_mcp and user_id: - result = await self.ai_service.generate_text_with_mcp( - prompt=prompt, - user_id=user_id, - db_session=db, - enable_mcp=True, - max_tool_rounds=2 - ) - content = result.get("content", "") - # 使用统一的JSON清洗方法 - cleaned = self.ai_service._clean_json_response(content) - character_data = json.loads(cleaned) - else: - # 非MCP调用:使用带自动重试的JSON调用 - character_data = await self.ai_service.call_with_json_retry( - prompt=prompt, - max_retries=3 - ) + # 🔧 优化:角色详情生成不使用MCP,只在分析阶段使用MCP + # 这样可以减少大量的外部工具调用,避免超时和卡死 + character_data = await self.ai_service.call_with_json_retry( + prompt=prompt, + max_retries=2 # 减少重试次数以加快速度 + ) char_name = character_data.get('name', '未知') logger.info(f" ✅ 角色详情生成成功: {char_name}") diff --git a/frontend/src/pages/Outline.tsx b/frontend/src/pages/Outline.tsx index f286444..ac44f7b 100644 --- a/frontend/src/pages/Outline.tsx +++ b/frontend/src/pages/Outline.tsx @@ -1892,8 +1892,10 @@ export default function Outline() { setSSEModalVisible(true); // 准备请求数据,添加确认的组织 + // ⚠️ 移除 confirmed_characters,避免重复创建角色 + const { confirmed_characters, ...baseData } = pendingGenerateData; const requestData = { - ...pendingGenerateData, + ...baseData, confirmed_organizations: selectedOrganizations }; @@ -1953,8 +1955,9 @@ export default function Outline() { setSSEModalVisible(true); // 准备请求数据,禁用自动组织引入 + const { confirmed_characters, ...baseData } = pendingGenerateData; const requestData = { - ...pendingGenerateData, + ...baseData, enable_auto_organizations: false // 禁用自动组织引入 };