XiaoBai1221 commited on
Commit
b740c8f
·
1 Parent(s): 801ae57

修復 app.py 縮排錯誤並更新 requirements.txt

Browse files
Files changed (2) hide show
  1. app.py +84 -76
  2. requirements.txt +1 -1
app.py CHANGED
@@ -62,6 +62,8 @@ from services.voice_login import VoiceAuthService, VoiceLoginConfig
62
  from services.welcome import compose_welcome
63
  from core.pipeline import ChatPipeline, PipelineResult
64
  from core.memory_system import memory_manager
 
 
65
 
66
 
67
  # -----------------------------
@@ -457,6 +459,32 @@ class ConnectionManager:
457
  manager = ConnectionManager()
458
 
459
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
460
  # -----------------------------
461
  # 語音綁定狀態管理器(關鍵字匹配,無 GPT)
462
  # -----------------------------
@@ -1178,90 +1206,70 @@ async def websocket_endpoint_with_jwt(websocket: WebSocket, token: str = Query(N
1178
  "timestamp": time.time()
1179
  })
1180
 
1181
- else:
 
 
1182
  # ===== 環境快照上報 =====
1183
- if message_type == "env_snapshot":
1184
- try:
1185
- lat = float(message_data.get("lat")) if message_data.get("lat") is not None else None
1186
- lon = float(message_data.get("lon")) if message_data.get("lon") is not None else None
1187
- acc = message_data.get("accuracy_m")
1188
- acc = float(acc) if acc is not None else None
1189
- heading_deg = message_data.get("heading_deg")
1190
- heading_deg = float(heading_deg) if heading_deg is not None else None
1191
- tz = message_data.get("tz")
1192
- locale = message_data.get("locale")
1193
- device = message_data.get("device")
1194
-
1195
- # 後端節流:距離<100m且方位差<25度則忽略
1196
- do_write_snapshot = False
1197
- last = manager.last_env.get(user_id)
1198
- if last and lat is not None and lon is not None and last.get("lat") is not None:
1199
- dist = _haversine_m(last.get("lat",0), last.get("lon",0), lat, lon)
1200
- deg_diff = abs((heading_deg or 0) - (last.get("heading_deg") or 0))
1201
- if dist >= 100 or deg_diff >= 25:
1202
- do_write_snapshot = True
1203
- else:
1204
  do_write_snapshot = True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1205
 
1206
- from geohash2 import encode as gh_encode
1207
- geohash7 = gh_encode(lat, lon, precision=7) if (lat is not None and lon is not None) else None
1208
- heading_cardinal = _heading_to_cardinal(heading_deg) if heading_deg is not None else None
1209
- env_payload = {
1210
- "lat": lat,
1211
- "lon": lon,
1212
- "accuracy_m": acc,
1213
- "heading_deg": heading_deg,
1214
- "heading_cardinal": heading_cardinal,
1215
- "tz": tz,
1216
- "locale": locale,
1217
- "device": device,
1218
- "geohash_7": geohash7,
1219
- }
1220
-
1221
- # 更新會話暫存
1222
- manager.last_env[user_id] = env_payload
1223
- info = manager.get_client_info(user_id) or {}
1224
- info['env_context'] = env_payload
1225
- manager.set_client_info(user_id, info)
1226
 
 
1227
  try:
1228
- await set_user_env_current(user_id, env_payload)
 
 
1229
  except Exception as e:
1230
- logger.warning(f"寫入環境現況失敗: {e}")
1231
-
1232
- if do_write_snapshot:
1233
- try:
1234
- snap = env_payload.copy()
1235
- snap['reason'] = 'threshold'
1236
- await add_user_env_snapshot(user_id, snap)
1237
- except Exception as e:
1238
- logger.warning(f"寫入環境快照失敗: {e}")
1239
-
1240
- await websocket.send_json({"type": "env_ack", "success": True, "geohash_7": geohash7, "heading": heading_cardinal})
1241
- except Exception as e:
1242
- logger.error(f"處理 env_snapshot 失敗: {e}")
1243
- await websocket.send_json({"type": "env_ack", "success": False, "error": str(e)})
1244
- # 保存 Agent 回應(已在 handle_message 中保存)
1245
-
1246
- _async_lib.create_task(_process_voice_chat())
1247
- else:
1248
- await websocket.send_json({
1249
- "type": "error",
1250
- "message": "未找到音頻 session"
1251
- })
1252
- else:
1253
- await websocket.send_json({
1254
- "type": "error",
1255
- "message": "語音服務未初始化"
1256
- })
1257
 
 
1258
  except Exception as e:
1259
- logger.exception(f" 語音對話處理失敗: {e}")
1260
- await websocket.send_json({
1261
- "type": "error",
1262
- "message": f"語音對話處理失敗: {str(e)}"
1263
- })
1264
-
1265
  else:
1266
  await manager.send_message(f"未知的消息類型: {message_type}", user_id, "error")
1267
 
 
62
  from services.welcome import compose_welcome
63
  from core.pipeline import ChatPipeline, PipelineResult
64
  from core.memory_system import memory_manager
65
+ # 環境 Context 寫入 API
66
+ from core.database import set_user_env_current, add_user_env_snapshot
67
 
68
 
69
  # -----------------------------
 
459
  manager = ConnectionManager()
460
 
461
 
462
+ # 地理工具函式(內部使用)
463
+ def _haversine_m(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
464
+ from math import radians, sin, cos, asin, sqrt
465
+ if None in (lat1, lon1, lat2, lon2):
466
+ return 0.0
467
+ R = 6371000.0
468
+ dlat = radians(lat2 - lat1)
469
+ dlon = radians(lon2 - lon1)
470
+ a = sin(dlat/2)**2 + cos(radians(lat1))*cos(radians(lat2))*sin(dlon/2)**2
471
+ c = 2 * asin(sqrt(a))
472
+ return R * c
473
+
474
+
475
+ def _heading_to_cardinal(deg: float) -> str:
476
+ try:
477
+ val = float(deg)
478
+ except Exception:
479
+ return ""
480
+ dirs = [
481
+ "N","NNE","NE","ENE","E","ESE","SE","SSE",
482
+ "S","SSW","SW","WSW","W","WNW","NW","NNW"
483
+ ]
484
+ ix = int((val % 360) / 22.5 + 0.5) % 16
485
+ return dirs[ix]
486
+
487
+
488
  # -----------------------------
489
  # 語音綁定狀態管理器(關鍵字匹配,無 GPT)
490
  # -----------------------------
 
1206
  "timestamp": time.time()
1207
  })
1208
 
1209
+ finally:
1210
+ pass
1211
+ elif message_type == "env_snapshot":
1212
  # ===== 環境快照上報 =====
1213
+ try:
1214
+ lat = float(message_data.get("lat")) if message_data.get("lat") is not None else None
1215
+ lon = float(message_data.get("lon")) if message_data.get("lon") is not None else None
1216
+ acc = message_data.get("accuracy_m")
1217
+ acc = float(acc) if acc is not None else None
1218
+ heading_deg = message_data.get("heading_deg")
1219
+ heading_deg = float(heading_deg) if heading_deg is not None else None
1220
+ tz = message_data.get("tz")
1221
+ locale = message_data.get("locale")
1222
+ device = message_data.get("device")
1223
+
1224
+ # 後端節流:距離<100m且方位差<25度則忽略
1225
+ do_write_snapshot = False
1226
+ last = manager.last_env.get(user_id)
1227
+ if last and lat is not None and lon is not None and last.get("lat") is not None:
1228
+ dist = _haversine_m(last.get("lat",0), last.get("lon",0), lat, lon)
1229
+ deg_diff = abs((heading_deg or 0) - (last.get("heading_deg") or 0))
1230
+ if dist >= 100 or deg_diff >= 25:
 
 
 
1231
  do_write_snapshot = True
1232
+ else:
1233
+ do_write_snapshot = True
1234
+
1235
+ from geohash2 import encode as gh_encode
1236
+ geohash7 = gh_encode(lat, lon, precision=7) if (lat is not None and lon is not None) else None
1237
+ heading_cardinal = _heading_to_cardinal(heading_deg) if heading_deg is not None else None
1238
+ env_payload = {
1239
+ "lat": lat,
1240
+ "lon": lon,
1241
+ "accuracy_m": acc,
1242
+ "heading_deg": heading_deg,
1243
+ "heading_cardinal": heading_cardinal,
1244
+ "tz": tz,
1245
+ "locale": locale,
1246
+ "device": device,
1247
+ "geohash_7": geohash7,
1248
+ }
1249
+
1250
+ # 更新會話暫存
1251
+ manager.last_env[user_id] = env_payload
1252
+ info = manager.get_client_info(user_id) or {}
1253
+ info['env_context'] = env_payload
1254
+ manager.set_client_info(user_id, info)
1255
 
1256
+ try:
1257
+ await set_user_env_current(user_id, env_payload)
1258
+ except Exception as e:
1259
+ logger.warning(f"寫入環境現況失敗: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1260
 
1261
+ if do_write_snapshot:
1262
  try:
1263
+ snap = env_payload.copy()
1264
+ snap['reason'] = 'threshold'
1265
+ await add_user_env_snapshot(user_id, snap)
1266
  except Exception as e:
1267
+ logger.warning(f"寫入環境快照失敗: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1268
 
1269
+ await websocket.send_json({"type": "env_ack", "success": True, "geohash_7": geohash7, "heading": heading_cardinal})
1270
  except Exception as e:
1271
+ logger.error(f"處理 env_snapshot 失敗: {e}")
1272
+ await websocket.send_json({"type": "env_ack", "success": False, "error": str(e)})
 
 
 
 
1273
  else:
1274
  await manager.send_message(f"未知的消息類型: {message_type}", user_id, "error")
1275
 
requirements.txt CHANGED
@@ -24,7 +24,7 @@ matplotlib==3.7.1
24
  jsonschema>=4.17.0
25
 
26
  # Geospatial / directions
27
- geohash2==1.1
28
 
29
  # Machine Learning dependencies
30
  numpy>=1.24.0,<2.0.0
 
24
  jsonschema>=4.17.0
25
 
26
  # Geospatial / directions
27
+ geohash2
28
 
29
  # Machine Learning dependencies
30
  numpy>=1.24.0,<2.0.0