Eliot0110 commited on
Commit
49aff10
·
1 Parent(s): 87f3ad3

improve: session manage

Browse files
Files changed (2) hide show
  1. app.py +53 -0
  2. modules/session_manager.py +170 -14
app.py CHANGED
@@ -145,6 +145,59 @@ async def reset_session(session_id: str):
145
  status_code=500,
146
  detail="Failed to reset session"
147
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
  # --- 全局异常处理 ---
150
  @app.exception_handler(Exception)
 
145
  status_code=500,
146
  detail="Failed to reset session"
147
  )
148
+
149
+ @app.get("/api/debug/sessions")
150
+ async def debug_sessions():
151
+ """调试:查看所有会话状态"""
152
+ if not SERVICE_READY or not assistant:
153
+ raise HTTPException(status_code=503, detail="Service not ready")
154
+
155
+ try:
156
+ # 先清理旧会话
157
+ cleaned = assistant.session_manager.cleanup_old_sessions()
158
+
159
+ sessions_summary = assistant.session_manager.get_all_sessions_summary()
160
+ sessions_summary["cleaned_sessions"] = cleaned
161
+
162
+ return sessions_summary
163
+ except Exception as e:
164
+ log.error(f"❌ Debug sessions error: {e}")
165
+ raise HTTPException(status_code=500, detail="Failed to get sessions")
166
+
167
+ @app.get("/api/debug/session/{session_id}")
168
+ async def debug_single_session(session_id: str):
169
+ """调试:查看单个会话详情"""
170
+ if not SERVICE_READY or not assistant:
171
+ raise HTTPException(status_code=503, detail="Service not ready")
172
+
173
+ if session_id in assistant.session_manager.sessions:
174
+ session_data = assistant.session_manager.sessions[session_id]
175
+ metadata = assistant.session_manager.session_metadata.get(session_id, {})
176
+
177
+ return {
178
+ "session_data": session_data,
179
+ "metadata": metadata,
180
+ "summary": assistant.session_manager._get_session_summary(session_id)
181
+ }
182
+ else:
183
+ raise HTTPException(status_code=404, detail="Session not found")
184
+
185
+ @app.post("/api/debug/cleanup")
186
+ async def cleanup_sessions(max_age_hours: int = 24):
187
+ """手动清理旧会话"""
188
+ if not SERVICE_READY or not assistant:
189
+ raise HTTPException(status_code=503, detail="Service not ready")
190
+
191
+ try:
192
+ cleaned_count = assistant.session_manager.cleanup_old_sessions(max_age_hours)
193
+ return {
194
+ "message": f"Cleaned {cleaned_count} old sessions",
195
+ "cleaned_sessions": cleaned_count,
196
+ "remaining_sessions": len(assistant.session_manager.sessions)
197
+ }
198
+ except Exception as e:
199
+ log.error(f"❌ Cleanup error: {e}")
200
+ raise HTTPException(status_code=500, detail="Failed to cleanup sessions")
201
 
202
  # --- 全局异常处理 ---
203
  @app.exception_handler(Exception)
modules/session_manager.py CHANGED
@@ -1,37 +1,176 @@
1
- # modules/session_manager.py
2
  import uuid
 
3
  from typing import Dict, Any
 
4
 
5
  class SessionManager:
6
  def __init__(self):
7
  self.sessions: Dict[str, Dict[str, Any]] = {}
 
8
 
9
  def get_or_create_session(self, session_id: str = None) -> Dict[str, Any]:
10
- if not session_id or session_id not in self.sessions:
11
- session_id = str(uuid.uuid4())[:8]
12
- self.sessions[session_id] = {
13
- "session_id": session_id,
14
- "destination": None,
15
- "duration": None,
16
- "persona": None,
17
- "stage": "greeting" # 对话状态机
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  }
19
- return self.sessions[session_id]
 
 
 
 
 
 
 
20
 
21
  def update_session(self, session_id: str, updates: Dict[str, Any]):
 
22
  if session_id in self.sessions:
 
23
  self.sessions[session_id].update(updates)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
  def format_session_info(self, session_state: dict) -> dict:
26
- """详细版本 - 结构化状态信息"""
27
-
 
28
  # 基础信息
29
  info = {
30
- "session_id": session_state.get('session_id', ''),
31
  "created_at": session_state.get('created_at', ''),
32
  "last_updated": session_state.get('last_updated', ''),
33
  }
34
-
35
  # 目的地信息
36
  destination = session_state.get('destination')
37
  if destination:
@@ -43,6 +182,7 @@ class SessionManager:
43
  else:
44
  info['destination'] = {'status': 'pending'}
45
 
 
46
  duration = session_state.get('duration')
47
  if duration:
48
  info['duration'] = {
@@ -87,9 +227,25 @@ class SessionManager:
87
  'total': 4,
88
  'percentage': (completed_fields / 4) * 100
89
  }
 
 
 
 
 
 
 
 
 
90
 
91
  return info
92
 
93
  def reset(self, session_id: str):
 
94
  if session_id in self.sessions:
95
  del self.sessions[session_id]
 
 
 
 
 
 
 
 
1
  import uuid
2
+ import time
3
  from typing import Dict, Any
4
+ from utils.logger import log
5
 
6
  class SessionManager:
7
  def __init__(self):
8
  self.sessions: Dict[str, Dict[str, Any]] = {}
9
+ self.session_metadata: Dict[str, Dict[str, Any]] = {} # 元数据追跟
10
 
11
  def get_or_create_session(self, session_id: str = None) -> Dict[str, Any]:
12
+ """改进的会话获取/创建逻辑"""
13
+
14
+ # 如果提供了session_id且存在,直接返回
15
+ if session_id and session_id in self.sessions:
16
+ # 更新最后访问时间
17
+ self.session_metadata[session_id]['last_accessed'] = time.time()
18
+ log.info(f"📂 使用现有会话: {session_id}")
19
+ log.info(f"📊 会话状态: {self._get_session_summary(session_id)}")
20
+ return self.sessions[session_id]
21
+
22
+ # 创建新会话
23
+ new_session_id = str(uuid.uuid4())[:8]
24
+ current_time = time.time()
25
+
26
+ self.sessions[new_session_id] = {
27
+ "session_id": new_session_id,
28
+ "destination": None,
29
+ "duration": None,
30
+ "budget": None,
31
+ "persona": None,
32
+ "stage": "greeting",
33
+ "created_at": current_time,
34
+ "last_updated": current_time,
35
+ }
36
+
37
+ # 创建元数据
38
+ self.session_metadata[new_session_id] = {
39
+ "created_at": current_time,
40
+ "last_accessed": current_time,
41
+ "message_count": 0,
42
+ "frontend_chat_id": None, # 可以存储前端对话ID
43
+ "persona_type": None,
44
+ "completion_status": {
45
+ "destination": False,
46
+ "duration": False,
47
+ "budget": False,
48
+ "persona": False
49
  }
50
+ }
51
+
52
+ if session_id:
53
+ log.info(f"⚠️ 会话ID {session_id} 不存在,创建新会话: {new_session_id}")
54
+ else:
55
+ log.info(f"🆕 创建新会话: {new_session_id}")
56
+
57
+ return self.sessions[new_session_id]
58
 
59
  def update_session(self, session_id: str, updates: Dict[str, Any]):
60
+ """增强的会话更新"""
61
  if session_id in self.sessions:
62
+ # 更新会话数据
63
  self.sessions[session_id].update(updates)
64
+ self.sessions[session_id]["last_updated"] = time.time()
65
+
66
+ # 更新元数据
67
+ if session_id in self.session_metadata:
68
+ metadata = self.session_metadata[session_id]
69
+ metadata["last_accessed"] = time.time()
70
+ metadata["message_count"] += 1
71
+
72
+ # 更新完成状态
73
+ session_data = self.sessions[session_id]
74
+ metadata["completion_status"] = {
75
+ "destination": session_data.get("destination") is not None,
76
+ "duration": session_data.get("duration") is not None,
77
+ "budget": session_data.get("budget") is not None,
78
+ "persona": session_data.get("persona") is not None
79
+ }
80
+
81
+ # 设置persona类型
82
+ if "persona" in updates and updates["persona"]:
83
+ metadata["persona_type"] = updates["persona"].get("key")
84
+
85
+ log.info(f"📝 更新会话 {session_id}: {list(updates.keys())}")
86
+ log.info(f"📊 更新后状态: {self._get_session_summary(session_id)}")
87
+ else:
88
+ log.error(f"❌ 尝试更新不存在的会话: {session_id}")
89
+
90
+ def _get_session_summary(self, session_id: str) -> str:
91
+ """获取会话摘要"""
92
+ if session_id not in self.sessions:
93
+ return "会话不存在"
94
+
95
+ session = self.sessions[session_id]
96
+ metadata = self.session_metadata.get(session_id, {})
97
+
98
+ dest = session.get('destination', {}).get('name', '未设置') if session.get('destination') else '未设置'
99
+ duration = f"{session.get('duration', {}).get('days', '?')}天" if session.get('duration') else '未设置'
100
+ budget = session.get('budget', {}).get('description', '未设置') if session.get('budget') else '未设置'
101
+ persona = session.get('persona', {}).get('name', '未设置') if session.get('persona') else '未设置'
102
+
103
+ completed = sum(metadata.get('completion_status', {}).values())
104
+
105
+ return f"目的地:{dest}, 天数:{duration}, 预算:{budget}, 风格:{persona} ({completed}/4完成)"
106
+
107
+ def get_all_sessions_summary(self) -> Dict[str, Any]:
108
+ """获取所有会话的摘要信息"""
109
+ summary = {
110
+ "total_sessions": len(self.sessions),
111
+ "active_sessions": 0,
112
+ "sessions": {}
113
+ }
114
+
115
+ current_time = time.time()
116
+
117
+ for session_id, session_data in self.sessions.items():
118
+ metadata = self.session_metadata.get(session_id, {})
119
+ last_accessed = metadata.get('last_accessed', 0)
120
+
121
+ # 判断是否为活跃会话(30分钟内有访问)
122
+ is_active = (current_time - last_accessed) < 1800
123
+ if is_active:
124
+ summary["active_sessions"] += 1
125
+
126
+ summary["sessions"][session_id] = {
127
+ "summary": self._get_session_summary(session_id),
128
+ "created_at": time.strftime('%Y-%m-%d %H:%M:%S',
129
+ time.localtime(metadata.get('created_at', 0))),
130
+ "last_accessed": time.strftime('%Y-%m-%d %H:%M:%S',
131
+ time.localtime(last_accessed)),
132
+ "message_count": metadata.get('message_count', 0),
133
+ "persona_type": metadata.get('persona_type'),
134
+ "completion_status": metadata.get('completion_status', {}),
135
+ "is_active": is_active
136
+ }
137
+
138
+ return summary
139
+
140
+ def cleanup_old_sessions(self, max_age_hours: int = 24):
141
+ """清理旧会话"""
142
+ current_time = time.time()
143
+ max_age_seconds = max_age_hours * 3600
144
+
145
+ old_sessions = []
146
+ for session_id in list(self.sessions.keys()):
147
+ metadata = self.session_metadata.get(session_id, {})
148
+ last_accessed = metadata.get('last_accessed', 0)
149
+
150
+ if (current_time - last_accessed) > max_age_seconds:
151
+ old_sessions.append(session_id)
152
+
153
+ for session_id in old_sessions:
154
+ del self.sessions[session_id]
155
+ if session_id in self.session_metadata:
156
+ del self.session_metadata[session_id]
157
+
158
+ if old_sessions:
159
+ log.info(f"🧹 清理了 {len(old_sessions)} 个旧会话")
160
+
161
+ return len(old_sessions)
162
 
163
  def format_session_info(self, session_state: dict) -> dict:
164
+ """返回详细的会话状态信息"""
165
+ session_id = session_state.get('session_id', '')
166
+
167
  # 基础信息
168
  info = {
169
+ "session_id": session_id,
170
  "created_at": session_state.get('created_at', ''),
171
  "last_updated": session_state.get('last_updated', ''),
172
  }
173
+
174
  # 目的地信息
175
  destination = session_state.get('destination')
176
  if destination:
 
182
  else:
183
  info['destination'] = {'status': 'pending'}
184
 
185
+ # 天数信息
186
  duration = session_state.get('duration')
187
  if duration:
188
  info['duration'] = {
 
227
  'total': 4,
228
  'percentage': (completed_fields / 4) * 100
229
  }
230
+
231
+ # 添加元数据信息
232
+ if session_id in self.session_metadata:
233
+ metadata = self.session_metadata[session_id]
234
+ info['metadata'] = {
235
+ 'message_count': metadata.get('message_count', 0),
236
+ 'persona_type': metadata.get('persona_type'),
237
+ 'is_active': (time.time() - metadata.get('last_accessed', 0)) < 1800
238
+ }
239
 
240
  return info
241
 
242
  def reset(self, session_id: str):
243
+ """删除指定会话"""
244
  if session_id in self.sessions:
245
  del self.sessions[session_id]
246
+ if session_id in self.session_metadata:
247
+ del self.session_metadata[session_id]
248
+ log.info(f"🗑️ 删除会话: {session_id}")
249
+ return True
250
+ else:
251
+ log.warning(f"⚠️ 尝试删除不存在的会话: {session_id}")