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.
Files changed (55) hide show
  1. aetherforge_platform-1.0.0.dist-info/METADATA +86 -0
  2. aetherforge_platform-1.0.0.dist-info/RECORD +55 -0
  3. aetherforge_platform-1.0.0.dist-info/WHEEL +5 -0
  4. aetherforge_platform-1.0.0.dist-info/top_level.txt +4 -0
  5. ai-life-assistant-copy/ai_agent.py +145 -0
  6. ai-life-assistant-copy/avatar_manager.py +231 -0
  7. ai-life-assistant-copy/avatar_packer.py +261 -0
  8. ai-life-assistant-copy/backup_all.py +262 -0
  9. ai-life-assistant-copy/backups/backup_20260404_193836/ai_agent.py +145 -0
  10. ai-life-assistant-copy/backups/backup_20260404_193836/avatar_manager.py +231 -0
  11. ai-life-assistant-copy/backups/backup_20260404_193836/avatar_packer.py +261 -0
  12. ai-life-assistant-copy/backups/backup_20260404_193836/backup_all.py +262 -0
  13. ai-life-assistant-copy/backups/backup_20260404_193836/commands.py +210 -0
  14. ai-life-assistant-copy/backups/backup_20260404_193836/config.py +30 -0
  15. ai-life-assistant-copy/backups/backup_20260404_193836/daemon/__init__.py +3 -0
  16. ai-life-assistant-copy/backups/backup_20260404_193836/daemon/daemon.py +174 -0
  17. ai-life-assistant-copy/backups/backup_20260404_193836/database.py +292 -0
  18. ai-life-assistant-copy/backups/backup_20260404_193836/graph.py +531 -0
  19. ai-life-assistant-copy/backups/backup_20260404_193836/main.py +830 -0
  20. ai-life-assistant-copy/backups/backup_20260404_193836/mcp_tools.py +449 -0
  21. ai-life-assistant-copy/backups/backup_20260404_193836/memory.py +92 -0
  22. ai-life-assistant-copy/backups/backup_20260404_193836/memory_v2.py +333 -0
  23. ai-life-assistant-copy/backups/backup_20260404_193836/mock_shopping_data.py +172 -0
  24. ai-life-assistant-copy/backups/backup_20260404_193836/personality.py +159 -0
  25. ai-life-assistant-copy/backups/backup_20260404_193836/speech.py +41 -0
  26. ai-life-assistant-copy/backups/backup_20260404_193836/test_simple.py +127 -0
  27. ai-life-assistant-copy/backups/backup_20260404_193836/tools/__init__.py +15 -0
  28. ai-life-assistant-copy/backups/backup_20260404_193836/tools/amazon_tool.py +103 -0
  29. ai-life-assistant-copy/backups/backup_20260404_193836/tools/calendar_tool.py +92 -0
  30. ai-life-assistant-copy/backups/backup_20260404_193836/tools/reminder_tool.py +92 -0
  31. ai-life-assistant-copy/backups/backup_20260404_193836/tools/weather_tool.py +45 -0
  32. ai-life-assistant-copy/backups/backup_20260404_193836/tree_memory.py +340 -0
  33. ai-life-assistant-copy/commands.py +210 -0
  34. ai-life-assistant-copy/config.py +30 -0
  35. ai-life-assistant-copy/daemon/__init__.py +3 -0
  36. ai-life-assistant-copy/daemon/daemon.py +174 -0
  37. ai-life-assistant-copy/database.py +292 -0
  38. ai-life-assistant-copy/graph.py +531 -0
  39. ai-life-assistant-copy/main.py +830 -0
  40. ai-life-assistant-copy/mcp_tools.py +449 -0
  41. ai-life-assistant-copy/memory.py +92 -0
  42. ai-life-assistant-copy/memory_v2.py +333 -0
  43. ai-life-assistant-copy/mock_shopping_data.py +172 -0
  44. ai-life-assistant-copy/personality.py +159 -0
  45. ai-life-assistant-copy/speech.py +41 -0
  46. ai-life-assistant-copy/test_simple.py +127 -0
  47. ai-life-assistant-copy/tools/__init__.py +15 -0
  48. ai-life-assistant-copy/tools/amazon_tool.py +103 -0
  49. ai-life-assistant-copy/tools/calendar_tool.py +92 -0
  50. ai-life-assistant-copy/tools/reminder_tool.py +92 -0
  51. ai-life-assistant-copy/tools/weather_tool.py +45 -0
  52. ai-life-assistant-copy/tree_memory.py +340 -0
  53. ai_agent_runtime.py +447 -0
  54. main.py +6752 -0
  55. 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