aetherforge-platform 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aetherforge_platform-1.0.0.dist-info/METADATA +86 -0
- aetherforge_platform-1.0.0.dist-info/RECORD +55 -0
- aetherforge_platform-1.0.0.dist-info/WHEEL +5 -0
- aetherforge_platform-1.0.0.dist-info/top_level.txt +4 -0
- ai-life-assistant-copy/ai_agent.py +145 -0
- ai-life-assistant-copy/avatar_manager.py +231 -0
- ai-life-assistant-copy/avatar_packer.py +261 -0
- ai-life-assistant-copy/backup_all.py +262 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/ai_agent.py +145 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/avatar_manager.py +231 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/avatar_packer.py +261 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/backup_all.py +262 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/commands.py +210 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/config.py +30 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/daemon/__init__.py +3 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/daemon/daemon.py +174 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/database.py +292 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/graph.py +531 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/main.py +830 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/mcp_tools.py +449 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/memory.py +92 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/memory_v2.py +333 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/mock_shopping_data.py +172 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/personality.py +159 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/speech.py +41 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/test_simple.py +127 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/tools/__init__.py +15 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/tools/amazon_tool.py +103 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/tools/calendar_tool.py +92 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/tools/reminder_tool.py +92 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/tools/weather_tool.py +45 -0
- ai-life-assistant-copy/backups/backup_20260404_193836/tree_memory.py +340 -0
- ai-life-assistant-copy/commands.py +210 -0
- ai-life-assistant-copy/config.py +30 -0
- ai-life-assistant-copy/daemon/__init__.py +3 -0
- ai-life-assistant-copy/daemon/daemon.py +174 -0
- ai-life-assistant-copy/database.py +292 -0
- ai-life-assistant-copy/graph.py +531 -0
- ai-life-assistant-copy/main.py +830 -0
- ai-life-assistant-copy/mcp_tools.py +449 -0
- ai-life-assistant-copy/memory.py +92 -0
- ai-life-assistant-copy/memory_v2.py +333 -0
- ai-life-assistant-copy/mock_shopping_data.py +172 -0
- ai-life-assistant-copy/personality.py +159 -0
- ai-life-assistant-copy/speech.py +41 -0
- ai-life-assistant-copy/test_simple.py +127 -0
- ai-life-assistant-copy/tools/__init__.py +15 -0
- ai-life-assistant-copy/tools/amazon_tool.py +103 -0
- ai-life-assistant-copy/tools/calendar_tool.py +92 -0
- ai-life-assistant-copy/tools/reminder_tool.py +92 -0
- ai-life-assistant-copy/tools/weather_tool.py +45 -0
- ai-life-assistant-copy/tree_memory.py +340 -0
- ai_agent_runtime.py +447 -0
- main.py +6752 -0
- mcp_server.py +427 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
from langgraph.graph import StateGraph, END
|
|
2
|
+
from typing import TypedDict, List, Optional, Dict, Any
|
|
3
|
+
import datetime
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
from config import GROK_API_KEY
|
|
7
|
+
from memory_v2 import memory_system_v2, Memory, MemoryType
|
|
8
|
+
from tree_memory import tree_memory_system, InvertedTreeMemory
|
|
9
|
+
from mcp_tools import mcp_tool_manager
|
|
10
|
+
|
|
11
|
+
def get_user_settings(user_id: str):
|
|
12
|
+
"""获取用户设置"""
|
|
13
|
+
try:
|
|
14
|
+
user_settings_file = os.path.join("user_data", f"{user_id}_settings.json")
|
|
15
|
+
if os.path.exists(user_settings_file):
|
|
16
|
+
with open(user_settings_file, "r", encoding="utf-8") as f:
|
|
17
|
+
return json.load(f)
|
|
18
|
+
except Exception as e:
|
|
19
|
+
print(f"Error loading user settings: {e}")
|
|
20
|
+
return {}
|
|
21
|
+
|
|
22
|
+
def get_user_memory_systems(user_id: str):
|
|
23
|
+
"""获取用户选中的 avatar 的记忆系统"""
|
|
24
|
+
settings = get_user_settings(user_id)
|
|
25
|
+
selected_avatar_id = settings.get("selected_avatar_id")
|
|
26
|
+
|
|
27
|
+
if selected_avatar_id:
|
|
28
|
+
try:
|
|
29
|
+
from avatar_manager import AvatarManager
|
|
30
|
+
avatar_manager = AvatarManager()
|
|
31
|
+
avatar = avatar_manager.load_avatar(selected_avatar_id)
|
|
32
|
+
if avatar:
|
|
33
|
+
avatar_memory_v2 = memory_system_v2
|
|
34
|
+
avatar_memory_tree = InvertedTreeMemory(avatar_id=selected_avatar_id)
|
|
35
|
+
return avatar_memory_v2, avatar_memory_tree, avatar
|
|
36
|
+
except Exception as e:
|
|
37
|
+
print(f"Error loading avatar memory: {e}")
|
|
38
|
+
|
|
39
|
+
return memory_system_v2, tree_memory_system, None
|
|
40
|
+
|
|
41
|
+
class LifeAssistantState(TypedDict):
|
|
42
|
+
user_id: str
|
|
43
|
+
message: str
|
|
44
|
+
intent: Optional[str]
|
|
45
|
+
requirements: Optional[Dict[str, Any]]
|
|
46
|
+
results: List[Dict[str, Any]]
|
|
47
|
+
cards: List[Dict[str, Any]]
|
|
48
|
+
visualization: Optional[str]
|
|
49
|
+
next_action: Optional[str]
|
|
50
|
+
status: str
|
|
51
|
+
memory: Dict[str, Any]
|
|
52
|
+
conversation_history: List[Dict[str, str]]
|
|
53
|
+
|
|
54
|
+
def parser_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
55
|
+
"""Parser Agent: 解析用户意图"""
|
|
56
|
+
try:
|
|
57
|
+
from langchain_groq import ChatGroq
|
|
58
|
+
from langchain.prompts import ChatPromptTemplate
|
|
59
|
+
|
|
60
|
+
llm = ChatGroq(
|
|
61
|
+
api_key=GROK_API_KEY,
|
|
62
|
+
model="mixtral-8x7b-32768"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
user_memory_v2, user_memory_tree, avatar = get_user_memory_systems(state["user_id"])
|
|
66
|
+
memory_v2_context = user_memory_v2.get_relevant_context(state["user_id"], state["message"])
|
|
67
|
+
memory_tree_context = user_memory_tree.get_relevant_context(state["message"])
|
|
68
|
+
|
|
69
|
+
combined_memory = memory_v2_context
|
|
70
|
+
if memory_tree_context:
|
|
71
|
+
combined_memory = f"{memory_v2_context}\n\n{memory_tree_context}"
|
|
72
|
+
|
|
73
|
+
avatar_context = ""
|
|
74
|
+
if avatar:
|
|
75
|
+
avatar_context = f"""
|
|
76
|
+
【虚拟形象信息】
|
|
77
|
+
名字: {avatar.name}
|
|
78
|
+
年龄: {avatar.age}
|
|
79
|
+
性格: {', '.join(avatar.personality)}
|
|
80
|
+
描述: {avatar.description}
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
84
|
+
("system", """你是一个AI生活助手的意图解析器。
|
|
85
|
+
请分析用户的输入,判断用户想要做什么。
|
|
86
|
+
|
|
87
|
+
可能的意图:
|
|
88
|
+
- shopping: 购物、买东西、推荐商品、找商品
|
|
89
|
+
- food: 外卖、点餐、饿了、想吃东西
|
|
90
|
+
- taxi: 打车、叫车、回家、去某个地方
|
|
91
|
+
- flight: 机票、订机票、旅行
|
|
92
|
+
- weather: 天气、气温、预报
|
|
93
|
+
- calendar: 日程、日历、安排
|
|
94
|
+
- reminder: 提醒、闹钟、通知
|
|
95
|
+
- general: 普通聊天、问候、其他问题
|
|
96
|
+
|
|
97
|
+
{avatar_info}
|
|
98
|
+
|
|
99
|
+
{user_memory}
|
|
100
|
+
|
|
101
|
+
请返回JSON格式,包含:
|
|
102
|
+
- intent: 意图类型(shopping/food/taxi/flight/weather/calendar/reminder/general)
|
|
103
|
+
- requirements: 详细需求(商品名称、数量、预算、时间、地点等)
|
|
104
|
+
|
|
105
|
+
只返回JSON,不要其他文字。"""),
|
|
106
|
+
("human", "{message}")
|
|
107
|
+
])
|
|
108
|
+
|
|
109
|
+
chain = prompt | llm
|
|
110
|
+
response = chain.invoke({
|
|
111
|
+
"message": state["message"],
|
|
112
|
+
"user_memory": combined_memory,
|
|
113
|
+
"avatar_info": avatar_context
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
parsed = json.loads(response.content)
|
|
118
|
+
state["intent"] = parsed.get("intent", "general")
|
|
119
|
+
state["requirements"] = parsed.get("requirements", {})
|
|
120
|
+
except:
|
|
121
|
+
state["intent"] = "general"
|
|
122
|
+
state["requirements"] = {}
|
|
123
|
+
|
|
124
|
+
except Exception as e:
|
|
125
|
+
print(f"Parser error: {e}")
|
|
126
|
+
state["intent"] = "general"
|
|
127
|
+
state["requirements"] = {}
|
|
128
|
+
|
|
129
|
+
return state
|
|
130
|
+
|
|
131
|
+
def router_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
132
|
+
"""Router: 根据意图路由到对应的Agent"""
|
|
133
|
+
intent = state["intent"]
|
|
134
|
+
|
|
135
|
+
if intent == "shopping":
|
|
136
|
+
state["next_action"] = "shopping"
|
|
137
|
+
elif intent == "food":
|
|
138
|
+
state["next_action"] = "food"
|
|
139
|
+
elif intent == "taxi":
|
|
140
|
+
state["next_action"] = "taxi"
|
|
141
|
+
elif intent == "flight":
|
|
142
|
+
state["next_action"] = "flight"
|
|
143
|
+
elif intent == "weather":
|
|
144
|
+
state["next_action"] = "weather"
|
|
145
|
+
elif intent == "calendar":
|
|
146
|
+
state["next_action"] = "calendar"
|
|
147
|
+
elif intent == "reminder":
|
|
148
|
+
state["next_action"] = "reminder"
|
|
149
|
+
else:
|
|
150
|
+
state["next_action"] = "general"
|
|
151
|
+
|
|
152
|
+
return state
|
|
153
|
+
|
|
154
|
+
def shopping_agent_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
155
|
+
"""Shopping Agent: 处理购物需求"""
|
|
156
|
+
from tools.amazon_tool import search_amazon
|
|
157
|
+
|
|
158
|
+
query = state["requirements"].get("query", state["message"])
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
results = search_amazon(query)
|
|
162
|
+
state["cards"] = results.get("cards", [])
|
|
163
|
+
state["results"] = results.get("items", [])
|
|
164
|
+
state["status"] = "success"
|
|
165
|
+
except Exception as e:
|
|
166
|
+
print(f"Shopping agent error: {e}")
|
|
167
|
+
state["cards"] = []
|
|
168
|
+
state["results"] = []
|
|
169
|
+
state["status"] = "error"
|
|
170
|
+
|
|
171
|
+
return state
|
|
172
|
+
|
|
173
|
+
def food_agent_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
174
|
+
"""Food Agent: 处理外卖需求"""
|
|
175
|
+
state["cards"] = []
|
|
176
|
+
state["results"] = [{"type": "food", "message": "外卖功能即将上线!"}]
|
|
177
|
+
state["status"] = "success"
|
|
178
|
+
return state
|
|
179
|
+
|
|
180
|
+
def taxi_agent_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
181
|
+
"""Taxi Agent: 处理打车需求"""
|
|
182
|
+
state["cards"] = []
|
|
183
|
+
state["results"] = [{"type": "taxi", "message": "打车功能即将上线!"}]
|
|
184
|
+
state["status"] = "success"
|
|
185
|
+
return state
|
|
186
|
+
|
|
187
|
+
def flight_agent_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
188
|
+
"""Flight Agent: 处理机票需求"""
|
|
189
|
+
state["cards"] = []
|
|
190
|
+
state["results"] = [{"type": "flight", "message": "机票功能即将上线!"}]
|
|
191
|
+
state["status"] = "success"
|
|
192
|
+
return state
|
|
193
|
+
|
|
194
|
+
def weather_agent_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
195
|
+
"""Weather Agent: 处理天气需求"""
|
|
196
|
+
from tools.weather_tool import get_weather
|
|
197
|
+
|
|
198
|
+
location = state["requirements"].get("location", "北京")
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
result = get_weather(location)
|
|
202
|
+
state["cards"] = result.get("cards", [])
|
|
203
|
+
state["results"] = [result.get("data", {})]
|
|
204
|
+
state["status"] = "success"
|
|
205
|
+
except Exception as e:
|
|
206
|
+
print(f"Weather agent error: {e}")
|
|
207
|
+
state["cards"] = []
|
|
208
|
+
state["results"] = [{"type": "weather", "message": "天气查询失败!"}]
|
|
209
|
+
state["status"] = "error"
|
|
210
|
+
|
|
211
|
+
return state
|
|
212
|
+
|
|
213
|
+
def calendar_agent_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
214
|
+
"""Calendar Agent: 处理日程需求"""
|
|
215
|
+
from tools.calendar_tool import get_events, add_event
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
if "add" in state["message"].lower() or "创建" in state["message"] or "添加" in state["message"]:
|
|
219
|
+
# 添加日程
|
|
220
|
+
title = state["requirements"].get("title", "")
|
|
221
|
+
time = state["requirements"].get("time", "")
|
|
222
|
+
date = state["requirements"].get("date", None)
|
|
223
|
+
result = add_event(title, time, date)
|
|
224
|
+
else:
|
|
225
|
+
# 获取日程
|
|
226
|
+
date = state["requirements"].get("date", None)
|
|
227
|
+
result = get_events(date)
|
|
228
|
+
|
|
229
|
+
state["cards"] = result.get("cards", [])
|
|
230
|
+
state["results"] = [result.get("events", [])]
|
|
231
|
+
state["status"] = "success"
|
|
232
|
+
except Exception as e:
|
|
233
|
+
print(f"Calendar agent error: {e}")
|
|
234
|
+
state["cards"] = []
|
|
235
|
+
state["results"] = [{"type": "calendar", "message": "日程处理失败!"}]
|
|
236
|
+
state["status"] = "error"
|
|
237
|
+
|
|
238
|
+
return state
|
|
239
|
+
|
|
240
|
+
def reminder_agent_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
241
|
+
"""Reminder Agent: 处理提醒需求"""
|
|
242
|
+
from tools.reminder_tool import set_reminder, get_reminders
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
if "设置" in state["message"] or "添加" in state["message"] or "创建" in state["message"]:
|
|
246
|
+
# 设置提醒
|
|
247
|
+
title = state["requirements"].get("title", "")
|
|
248
|
+
time = state["requirements"].get("time", "")
|
|
249
|
+
date = state["requirements"].get("date", None)
|
|
250
|
+
repeat = state["requirements"].get("repeat", None)
|
|
251
|
+
result = set_reminder(title, time, date, repeat)
|
|
252
|
+
else:
|
|
253
|
+
# 获取提醒
|
|
254
|
+
date = state["requirements"].get("date", None)
|
|
255
|
+
result = get_reminders(date)
|
|
256
|
+
|
|
257
|
+
state["cards"] = result.get("cards", [])
|
|
258
|
+
state["results"] = [result.get("reminders", [])]
|
|
259
|
+
state["status"] = "success"
|
|
260
|
+
except Exception as e:
|
|
261
|
+
print(f"Reminder agent error: {e}")
|
|
262
|
+
state["cards"] = []
|
|
263
|
+
state["results"] = [{"type": "reminder", "message": "提醒处理失败!"}]
|
|
264
|
+
state["status"] = "error"
|
|
265
|
+
|
|
266
|
+
return state
|
|
267
|
+
|
|
268
|
+
def general_agent_node(state: LifeAssistantState) -> LifeAssistantState:
|
|
269
|
+
"""General Agent: 处理普通聊天,自动决定是否调用工具"""
|
|
270
|
+
try:
|
|
271
|
+
from langchain_groq import ChatGroq
|
|
272
|
+
from langchain.prompts import ChatPromptTemplate
|
|
273
|
+
import json
|
|
274
|
+
|
|
275
|
+
llm = ChatGroq(
|
|
276
|
+
api_key=GROK_API_KEY,
|
|
277
|
+
model="mixtral-8x7b-32768"
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
context = "\n".join([
|
|
281
|
+
f"{msg['role']}: {msg['content']}"
|
|
282
|
+
for msg in state["conversation_history"][-5:]
|
|
283
|
+
])
|
|
284
|
+
|
|
285
|
+
user_memory_v2, user_memory_tree, avatar = get_user_memory_systems(state["user_id"])
|
|
286
|
+
memory_v2_context = user_memory_v2.get_relevant_context(state["user_id"], state["message"])
|
|
287
|
+
memory_tree_context = user_memory_tree.get_relevant_context(state["message"])
|
|
288
|
+
|
|
289
|
+
combined_memory = memory_v2_context
|
|
290
|
+
if memory_tree_context:
|
|
291
|
+
combined_memory = f"{memory_v2_context}\n\n{memory_tree_context}"
|
|
292
|
+
|
|
293
|
+
avatar_context = ""
|
|
294
|
+
if avatar:
|
|
295
|
+
avatar_context = f"""
|
|
296
|
+
【虚拟形象信息】
|
|
297
|
+
名字: {avatar.name}
|
|
298
|
+
年龄: {avatar.age}
|
|
299
|
+
性格: {', '.join(avatar.personality)}
|
|
300
|
+
描述: {avatar.description}
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
tools = mcp_tool_manager.list_tools()
|
|
304
|
+
|
|
305
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
306
|
+
("system", """You are a friendly AI life assistant.
|
|
307
|
+
|
|
308
|
+
Available tools:
|
|
309
|
+
{tools_list}
|
|
310
|
+
|
|
311
|
+
{avatar_info}
|
|
312
|
+
|
|
313
|
+
【User background info】
|
|
314
|
+
{user_memory}
|
|
315
|
+
|
|
316
|
+
Important guidelines:
|
|
317
|
+
1. First, decide if you need to use a tool.
|
|
318
|
+
2. If you need a tool, respond with EXACTLY this JSON format (and nothing else):
|
|
319
|
+
{{"tool": "tool_name", "params": {{"param1": "value1"}}}}
|
|
320
|
+
3. If you don't need a tool, just respond normally in text.
|
|
321
|
+
4. If you have user background info, use it to provide better help
|
|
322
|
+
5. But, don't just repeat what the user already knows
|
|
323
|
+
6. Provide new insights, suggestions, and ideas
|
|
324
|
+
7. If the user just states a fact, don't always bring it up again
|
|
325
|
+
8. Give the user space to think and discover new things
|
|
326
|
+
9. If you have avatar information, use that persona in your conversation
|
|
327
|
+
|
|
328
|
+
Please respond in a friendly, concise, natural way, like chatting with a normal person."""),
|
|
329
|
+
("human", "Conversation history:\n{context}\n\nUser's latest question: {message}")
|
|
330
|
+
])
|
|
331
|
+
|
|
332
|
+
tools_list = "\n".join([
|
|
333
|
+
f"- {tool['name']}: {tool['description']}\n Params: {', '.join(tool['params'])}"
|
|
334
|
+
for tool in tools
|
|
335
|
+
])
|
|
336
|
+
|
|
337
|
+
chain = prompt | llm
|
|
338
|
+
response = chain.invoke({
|
|
339
|
+
"context": context,
|
|
340
|
+
"message": state["message"],
|
|
341
|
+
"user_memory": combined_memory,
|
|
342
|
+
"tools_list": tools_list,
|
|
343
|
+
"avatar_info": avatar_context
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
response_text = response.content.strip()
|
|
347
|
+
|
|
348
|
+
if response_text.startswith('{') and response_text.endswith('}'):
|
|
349
|
+
try:
|
|
350
|
+
tool_call = json.loads(response_text)
|
|
351
|
+
tool_name = tool_call.get("tool")
|
|
352
|
+
tool_params = tool_call.get("params", {})
|
|
353
|
+
|
|
354
|
+
print(f"🔧 Calling tool: {tool_name} with params: {tool_params}")
|
|
355
|
+
|
|
356
|
+
result = mcp_tool_manager.execute_tool(tool_name, tool_params)
|
|
357
|
+
|
|
358
|
+
if result.get("success"):
|
|
359
|
+
state["visualization"] = result.get("result", "")
|
|
360
|
+
state["results"] = [{
|
|
361
|
+
"type": "text",
|
|
362
|
+
"content": "Here's what I found:"
|
|
363
|
+
}]
|
|
364
|
+
else:
|
|
365
|
+
state["results"] = [{
|
|
366
|
+
"type": "text",
|
|
367
|
+
"content": "Sorry, I couldn't complete that. Let me help you another way!"
|
|
368
|
+
}]
|
|
369
|
+
except Exception as e:
|
|
370
|
+
print(f"Tool call error: {e}")
|
|
371
|
+
state["results"] = [{
|
|
372
|
+
"type": "text",
|
|
373
|
+
"content": "Sorry, let's try that again!"
|
|
374
|
+
}]
|
|
375
|
+
else:
|
|
376
|
+
state["results"] = [{
|
|
377
|
+
"type": "text",
|
|
378
|
+
"content": response_text
|
|
379
|
+
}]
|
|
380
|
+
|
|
381
|
+
state["status"] = "success"
|
|
382
|
+
|
|
383
|
+
except Exception as e:
|
|
384
|
+
print(f"General agent error: {e}")
|
|
385
|
+
state["results"] = [{
|
|
386
|
+
"type": "text",
|
|
387
|
+
"content": "Sorry, I'm a bit busy right now. Please try again later!"
|
|
388
|
+
}]
|
|
389
|
+
state["status"] = "error"
|
|
390
|
+
|
|
391
|
+
return state
|
|
392
|
+
|
|
393
|
+
def should_continue(state: LifeAssistantState) -> str:
|
|
394
|
+
"""决定下一步走向"""
|
|
395
|
+
if state["next_action"] == "shopping":
|
|
396
|
+
return "shopping"
|
|
397
|
+
elif state["next_action"] == "food":
|
|
398
|
+
return "food"
|
|
399
|
+
elif state["next_action"] == "taxi":
|
|
400
|
+
return "taxi"
|
|
401
|
+
elif state["next_action"] == "flight":
|
|
402
|
+
return "flight"
|
|
403
|
+
elif state["next_action"] == "weather":
|
|
404
|
+
return "weather"
|
|
405
|
+
elif state["next_action"] == "calendar":
|
|
406
|
+
return "calendar"
|
|
407
|
+
elif state["next_action"] == "reminder":
|
|
408
|
+
return "reminder"
|
|
409
|
+
else:
|
|
410
|
+
return "general"
|
|
411
|
+
|
|
412
|
+
workflow = StateGraph(LifeAssistantState)
|
|
413
|
+
|
|
414
|
+
workflow.add_node("parser", parser_node)
|
|
415
|
+
workflow.add_node("router", router_node)
|
|
416
|
+
workflow.add_node("shopping", shopping_agent_node)
|
|
417
|
+
workflow.add_node("food", food_agent_node)
|
|
418
|
+
workflow.add_node("taxi", taxi_agent_node)
|
|
419
|
+
workflow.add_node("flight", flight_agent_node)
|
|
420
|
+
workflow.add_node("weather", weather_agent_node)
|
|
421
|
+
workflow.add_node("calendar", calendar_agent_node)
|
|
422
|
+
workflow.add_node("reminder", reminder_agent_node)
|
|
423
|
+
workflow.add_node("general", general_agent_node)
|
|
424
|
+
|
|
425
|
+
workflow.set_entry_point("parser")
|
|
426
|
+
workflow.add_edge("parser", "router")
|
|
427
|
+
|
|
428
|
+
workflow.add_conditional_edges(
|
|
429
|
+
"router",
|
|
430
|
+
should_continue,
|
|
431
|
+
{
|
|
432
|
+
"shopping": "shopping",
|
|
433
|
+
"food": "food",
|
|
434
|
+
"taxi": "taxi",
|
|
435
|
+
"flight": "flight",
|
|
436
|
+
"weather": "weather",
|
|
437
|
+
"calendar": "calendar",
|
|
438
|
+
"reminder": "reminder",
|
|
439
|
+
"general": "general"
|
|
440
|
+
}
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
workflow.add_edge("shopping", END)
|
|
444
|
+
workflow.add_edge("food", END)
|
|
445
|
+
workflow.add_edge("taxi", END)
|
|
446
|
+
workflow.add_edge("flight", END)
|
|
447
|
+
workflow.add_edge("weather", END)
|
|
448
|
+
workflow.add_edge("calendar", END)
|
|
449
|
+
workflow.add_edge("reminder", END)
|
|
450
|
+
workflow.add_edge("general", END)
|
|
451
|
+
|
|
452
|
+
app = workflow.compile()
|
|
453
|
+
|
|
454
|
+
def run_chat(message: str, user_id: str = "default", conversation_history: List[Dict[str, str]] = None):
|
|
455
|
+
"""运行聊天流程"""
|
|
456
|
+
if conversation_history is None:
|
|
457
|
+
conversation_history = []
|
|
458
|
+
|
|
459
|
+
# 解析命令
|
|
460
|
+
from commands import CommandParser
|
|
461
|
+
parser = CommandParser()
|
|
462
|
+
command_result = parser.parse(message)
|
|
463
|
+
|
|
464
|
+
if command_result["type"] == "command":
|
|
465
|
+
# 处理命令
|
|
466
|
+
if command_result["command"] == "help":
|
|
467
|
+
return {
|
|
468
|
+
"results": [{"type": "text", "content": parser.get_help()}],
|
|
469
|
+
"cards": [],
|
|
470
|
+
"status": "success"
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
# 直接设置意图和需求
|
|
474
|
+
initial_state: LifeAssistantState = {
|
|
475
|
+
"user_id": user_id,
|
|
476
|
+
"message": message,
|
|
477
|
+
"intent": command_result["intent"],
|
|
478
|
+
"requirements": command_result.get("requirements", {}),
|
|
479
|
+
"results": [],
|
|
480
|
+
"cards": [],
|
|
481
|
+
"visualization": None,
|
|
482
|
+
"next_action": command_result["intent"],
|
|
483
|
+
"status": "pending",
|
|
484
|
+
"memory": {},
|
|
485
|
+
"conversation_history": conversation_history
|
|
486
|
+
}
|
|
487
|
+
else:
|
|
488
|
+
# 正常消息
|
|
489
|
+
initial_state: LifeAssistantState = {
|
|
490
|
+
"user_id": user_id,
|
|
491
|
+
"message": message,
|
|
492
|
+
"intent": None,
|
|
493
|
+
"requirements": None,
|
|
494
|
+
"results": [],
|
|
495
|
+
"cards": [],
|
|
496
|
+
"visualization": None,
|
|
497
|
+
"next_action": None,
|
|
498
|
+
"status": "pending",
|
|
499
|
+
"memory": {},
|
|
500
|
+
"conversation_history": conversation_history
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
result = app.invoke(initial_state)
|
|
504
|
+
|
|
505
|
+
response_text = ""
|
|
506
|
+
if result.get("results"):
|
|
507
|
+
for res in result["results"]:
|
|
508
|
+
if res.get("type") == "text":
|
|
509
|
+
response_text = res.get("content", "")
|
|
510
|
+
break
|
|
511
|
+
|
|
512
|
+
user_memory_v2, user_memory_tree, avatar = get_user_memory_systems(user_id)
|
|
513
|
+
user_memory_v2.extract_and_save_memory(
|
|
514
|
+
user_id=user_id,
|
|
515
|
+
message=message,
|
|
516
|
+
response=response_text
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
if avatar:
|
|
520
|
+
user_memory_tree.extract_and_save_memory(
|
|
521
|
+
message=message,
|
|
522
|
+
response=response_text
|
|
523
|
+
)
|
|
524
|
+
else:
|
|
525
|
+
tree_memory_system.extract_and_save_memory(
|
|
526
|
+
avatar_id=user_id,
|
|
527
|
+
message=message,
|
|
528
|
+
response=response_text
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
return result
|