1
0

batch_generator.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. """批量NPC对话生成器"""
  2. import sys
  3. import os
  4. import json
  5. from datetime import datetime
  6. from typing import Dict, Optional
  7. # 添加HelloAgents到Python路径
  8. sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'HelloAgents'))
  9. from hello_agents import HelloAgentsLLM
  10. from agents import NPC_ROLES
  11. class NPCBatchGenerator:
  12. """批量生成NPC对话的生成器
  13. 核心思路: 一次LLM调用生成所有NPC的对话,降低API成本和延迟
  14. """
  15. def __init__(self):
  16. """初始化批量生成器"""
  17. print("🎨 正在初始化批量对话生成器...")
  18. try:
  19. self.llm = HelloAgentsLLM()
  20. self.enabled = True
  21. print("✅ 批量生成器初始化成功")
  22. except Exception as e:
  23. print(f"❌ 批量生成器初始化失败: {e}")
  24. print("⚠️ 将使用预设对话模式")
  25. self.llm = None
  26. self.enabled = False
  27. self.npc_configs = NPC_ROLES
  28. # 预设对话库(当LLM不可用时使用)
  29. self.preset_dialogues = {
  30. "morning": {
  31. "张三": "早上好!今天要继续优化那个多智能体系统的性能。",
  32. "李四": "新的一天开始了,先整理一下今天的会议安排。",
  33. "王五": "早!先来杯咖啡提提神,然后开始设计新界面。"
  34. },
  35. "noon": {
  36. "张三": "写了一上午代码,终于把那个bug修复了!",
  37. "李四": "上午的需求评审会很顺利,下午继续推进。",
  38. "王五": "这个配色方案看起来不错,再调整一下细节。"
  39. },
  40. "afternoon": {
  41. "张三": "下午继续写代码,这个算法还需要优化一下。",
  42. "李四": "正在准备下周的产品规划会,需求文档快完成了。",
  43. "王五": "设计稿基本完成了,等会儿发给大家看看。"
  44. },
  45. "evening": {
  46. "张三": "今天的代码提交完成,明天继续!",
  47. "李四": "今天的工作差不多了,整理一下明天的待办事项。",
  48. "王五": "设计工作告一段落,明天再继续优化。"
  49. }
  50. }
  51. def generate_batch_dialogues(self, context: Optional[str] = None) -> Dict[str, str]:
  52. """批量生成所有NPC的对话
  53. Args:
  54. context: 场景上下文(如"上午工作时间"、"午餐时间"等)
  55. Returns:
  56. Dict[str, str]: NPC名称到对话内容的映射
  57. """
  58. if not self.enabled or self.llm is None:
  59. # 使用预设对话
  60. return self._get_preset_dialogues()
  61. try:
  62. # 构建批量生成提示词
  63. prompt = self._build_batch_prompt(context)
  64. # 一次LLM调用生成所有对话
  65. # 使用invoke方法而不是chat方法
  66. response = self.llm.invoke([
  67. {"role": "system", "content": "你是一个游戏NPC对话生成器,擅长创作自然真实的办公室对话。"},
  68. {"role": "user", "content": prompt}
  69. ])
  70. # 解析JSON响应
  71. dialogues = self._parse_response(response)
  72. if dialogues:
  73. print(f"✅ 批量生成成功: {len(dialogues)}个NPC对话")
  74. return dialogues
  75. else:
  76. print("⚠️ 解析失败,使用预设对话")
  77. return self._get_preset_dialogues()
  78. except Exception as e:
  79. print(f"❌ 批量生成失败: {e}")
  80. return self._get_preset_dialogues()
  81. def _build_batch_prompt(self, context: Optional[str] = None) -> str:
  82. """构建批量生成提示词"""
  83. # 根据时间自动推断场景
  84. if context is None:
  85. context = self._get_current_context()
  86. # 构建NPC描述
  87. npc_descriptions = []
  88. for name, cfg in self.npc_configs.items():
  89. desc = f"- {name}({cfg['title']}): 在{cfg['location']}{cfg['activity']},性格{cfg['personality']}"
  90. npc_descriptions.append(desc)
  91. npc_desc_text = "\n".join(npc_descriptions)
  92. prompt = f"""请为Datawhale办公室的3个NPC生成当前的对话或行为描述。
  93. 【场景】{context}
  94. 【NPC信息】
  95. {npc_desc_text}
  96. 【生成要求】
  97. 1. 每个NPC生成1句话(20-40字)
  98. 2. 内容要符合角色设定、当前活动和场景氛围
  99. 3. 可以是自言自语、工作状态描述、或简单的思考
  100. 4. 要自然真实,像真实的办公室同事
  101. 5. 可以体现一些个性化特点和情绪
  102. 6. **必须严格按照JSON格式返回**
  103. 【输出格式】(严格遵守)
  104. {{"张三": "...", "李四": "...", "王五": "..."}}
  105. 【示例输出】
  106. {{"张三": "这个bug真是见鬼了,已经调试两小时了...", "李四": "嗯,这个功能的优先级需要重新评估一下。", "王五": "这杯咖啡的拉花真不错,灵感来了!"}}
  107. 请生成(只返回JSON,不要其他内容):
  108. """
  109. return prompt
  110. def _parse_response(self, response: str) -> Optional[Dict[str, str]]:
  111. """解析LLM响应"""
  112. try:
  113. # 尝试直接解析JSON
  114. dialogues = json.loads(response)
  115. # 验证格式
  116. if isinstance(dialogues, dict) and all(name in dialogues for name in self.npc_configs.keys()):
  117. return dialogues
  118. else:
  119. print(f"⚠️ JSON格式不正确: {dialogues}")
  120. return None
  121. except json.JSONDecodeError:
  122. # 尝试提取JSON部分
  123. try:
  124. # 查找第一个{和最后一个}
  125. start = response.find('{')
  126. end = response.rfind('}') + 1
  127. if start != -1 and end > start:
  128. json_str = response[start:end]
  129. dialogues = json.loads(json_str)
  130. if isinstance(dialogues, dict):
  131. return dialogues
  132. except:
  133. pass
  134. print(f"⚠️ 无法解析响应: {response[:100]}...")
  135. return None
  136. def _get_current_context(self) -> str:
  137. """根据当前时间推断场景上下文"""
  138. hour = datetime.now().hour
  139. if 6 <= hour < 9:
  140. return "清晨时分,大家陆续到达办公室,准备开始新的一天"
  141. elif 9 <= hour < 12:
  142. return "上午工作时间,大家都在专注工作,办公室氛围专注而忙碌"
  143. elif 12 <= hour < 14:
  144. return "午餐时间,大家在休息放松,聊聊天或者看看手机"
  145. elif 14 <= hour < 17:
  146. return "下午工作时间,继续推进项目,偶尔需要喝杯咖啡提神"
  147. elif 17 <= hour < 19:
  148. return "傍晚时分,准备收尾今天的工作,整理明天的计划"
  149. else:
  150. return "夜晚时分,办公室安静下来,偶尔还有人在加班"
  151. def _get_preset_dialogues(self) -> Dict[str, str]:
  152. """获取预设对话(根据时间)"""
  153. hour = datetime.now().hour
  154. if 6 <= hour < 12:
  155. period = "morning"
  156. elif 12 <= hour < 14:
  157. period = "noon"
  158. elif 14 <= hour < 18:
  159. period = "afternoon"
  160. else:
  161. period = "evening"
  162. return self.preset_dialogues.get(period, self.preset_dialogues["morning"])
  163. # 全局单例
  164. _batch_generator = None
  165. def get_batch_generator() -> NPCBatchGenerator:
  166. """获取批量生成器单例"""
  167. global _batch_generator
  168. if _batch_generator is None:
  169. _batch_generator = NPCBatchGenerator()
  170. return _batch_generator