Eliot0110 commited on
Commit
f214d2f
·
1 Parent(s): c21e548

fix: recover file

Browse files
Files changed (1) hide show
  1. modules/response_generator.py +157 -0
modules/response_generator.py CHANGED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # modules/response_generator.py - 修复版本
2
+ from .ai_model import AIModel
3
+ from .knowledge_base import KnowledgeBase
4
+ from utils.logger import log
5
+
6
+ class ResponseGenerator:
7
+ def __init__(self, ai_model: AIModel, knowledge_base: KnowledgeBase):
8
+ self.ai_model = ai_model
9
+ self.kb = knowledge_base
10
+
11
+ def generate(self, user_message: str, session_state: dict) -> str:
12
+ try:
13
+ # 1. 优先使用 RAG (检索增强生成)
14
+ search_query = user_message
15
+ if session_state.get("destination"):
16
+ search_query += f" {session_state['destination']['name']}"
17
+
18
+ relevant_knowledge = self.kb.search(search_query)
19
+ if relevant_knowledge:
20
+ context = self._format_knowledge_context(relevant_knowledge)
21
+ if self.ai_model.is_available():
22
+ return self.ai_model.generate(user_message, context)
23
+
24
+ # 2. 如果没有知识库匹配,则使用基于规则的引导式对话
25
+ if not session_state.get("destination"):
26
+ return "听起来很棒!你想去欧洲的哪个城市呢?比如巴黎, 罗马, 巴塞罗那?"
27
+ if not session_state.get("duration"):
28
+ return f"好的,{session_state['destination']['name']}是个很棒的选择!你计划玩几天呢?"
29
+ if not session_state.get("persona"):
30
+ return "最后一个问题,这次旅行对你来说什么最重要呢?(例如:美食、艺术、购物、历史)"
31
+
32
+ # 3. 如果信息都收集全了,但没触发RAG,让AI生成一个通用计划
33
+ if self.ai_model.is_available():
34
+ plan_prompt = self._build_plan_prompt(session_state)
35
+ return self.ai_model.generate(plan_prompt, context="用户需要一个详细的旅行计划。")
36
+ else:
37
+ return self._generate_fallback_plan(session_state)
38
+
39
+ except Exception as e:
40
+ log.error(f"❌ 响应生成失败: {e}", exc_info=True)
41
+ return "抱歉,我在处理您的请求时遇到了问题,请稍后再试。"
42
+
43
+ def _build_plan_prompt(self, session_state: dict) -> str:
44
+ """构建AI生成计划的提示词 - 修复版本"""
45
+ destination = session_state.get("destination", {})
46
+ duration = session_state.get("duration", {})
47
+ persona = session_state.get("persona", {})
48
+
49
+ prompt = f"请为用户生成一个在 {destination.get('name', '未知城市')} 的 "
50
+ prompt += f"{duration.get('days', '几')} 天旅行计划。"
51
+
52
+ if persona:
53
+ # 使用name而不是description
54
+ persona_name = persona.get('name', '一般旅行者')
55
+ persona_style = persona.get('style', '')
56
+ prompt += f" 旅行风格: {persona_name}"
57
+ if persona_style:
58
+ prompt += f"({persona_style})"
59
+ prompt += "。"
60
+
61
+ return prompt
62
+
63
+ def _generate_fallback_plan(self, session_state: dict) -> str:
64
+ """AI不可用时的备用计划生成"""
65
+ destination = session_state.get("destination", {})
66
+ duration = session_state.get("duration", {})
67
+ persona = session_state.get("persona", {})
68
+
69
+ plan = f"为您推荐 {destination.get('name', '目的地')} {duration.get('days', '几')}天旅行计划:\n\n"
70
+
71
+ # 使用cities.json中的信息
72
+ highlights = destination.get('highlights', '精彩景点等待您的探索')
73
+ plan += f"🎯 主要景点:{highlights}\n\n"
74
+
75
+ best_season = destination.get('best_season', '全年适宜')
76
+ plan += f"🌤️ 最佳旅行时间:{best_season}\n\n"
77
+
78
+ budget = destination.get('avg_daily_budget', 100)
79
+ plan += f"💰 预算参考:约{budget}欧元/天\n\n"
80
+
81
+ if persona:
82
+ plan += f"🎨 根据您的{persona.get('name', '旅行')}风格,建议您重点关注相关的景点和体验。\n\n"
83
+
84
+ plan += "详细行程规划请稍后重试,或告诉我您的具体需求!"
85
+
86
+ return plan
87
+
88
+ def _format_knowledge_context(self, knowledge_items: list) -> str:
89
+ """格式化知识库内容作为上下文 - 完全安全版本"""
90
+ if not knowledge_items:
91
+ return "没有特定的背景知识。"
92
+
93
+ try:
94
+ # 只使用最相关的一条知识
95
+ item = knowledge_items[0]
96
+
97
+ # 安全地获取嵌套数据
98
+ knowledge = item.get('knowledge', {})
99
+ travel_knowledge = knowledge.get('travel_knowledge', {})
100
+
101
+ context_parts = []
102
+
103
+ # 1. 获取目的地信息
104
+ destination_info = travel_knowledge.get('destination_info', {})
105
+ if destination_info:
106
+ primary_destinations = destination_info.get('primary_destinations', [])
107
+ if primary_destinations:
108
+ context_parts.append(f"目的地: {', '.join(primary_destinations)}")
109
+
110
+ recommended_duration = destination_info.get('recommended_duration')
111
+ if recommended_duration:
112
+ context_parts.append(f"推荐天数: {recommended_duration}天")
113
+
114
+ travel_theme = destination_info.get('travel_theme')
115
+ if travel_theme:
116
+ context_parts.append(f"旅行主题: {travel_theme}")
117
+
118
+ # 2. 获取预算信息
119
+ budget_analysis = travel_knowledge.get('budget_analysis', {})
120
+ if budget_analysis:
121
+ total_budget = budget_analysis.get('total_budget_range')
122
+ if total_budget:
123
+ context_parts.append(f"预算参考: {total_budget}")
124
+
125
+ daily_average = budget_analysis.get('daily_average')
126
+ if daily_average:
127
+ context_parts.append(f"日均预算: {daily_average}")
128
+
129
+ # 3. 获取专业见解 - 根据实际数据结构
130
+ professional_insights = travel_knowledge.get('professional_insights', {})
131
+ if professional_insights:
132
+ # 常见错误
133
+ common_mistakes = professional_insights.get('common_mistakes', [])
134
+ if common_mistakes:
135
+ context_parts.append(f"注意事项: {', '.join(common_mistakes[:2])}")
136
+
137
+ # 内行秘籍
138
+ insider_secrets = professional_insights.get('insider_secrets', [])
139
+ if insider_secrets:
140
+ context_parts.append(f"内行贴士: {', '.join(insider_secrets[:2])}")
141
+
142
+ # 最佳月份
143
+ seasonal_info = professional_insights.get('seasonal_considerations', {})
144
+ if seasonal_info:
145
+ best_months = seasonal_info.get('best_months', [])
146
+ if best_months:
147
+ context_parts.append(f"最佳时间: {', '.join(best_months)}")
148
+
149
+ # 4. 拼接结果
150
+ if context_parts:
151
+ return "相关旅游知识:\n- " + "\n- ".join(context_parts)
152
+ else:
153
+ return "基于旅游知识库的一般建议。"
154
+
155
+ except Exception as e:
156
+ log.error(f"❌ 格式化知识库上下文失败: {e}", exc_info=True)
157
+ return "知识库处理时发生错误,使用一般旅游建议。"