LawrenceBai commited on
Commit
ff120d2
·
1 Parent(s): 62eb709

更新了

Browse files
Files changed (2) hide show
  1. app.py +56 -58
  2. core/database/base.py +9 -9
app.py CHANGED
@@ -18,6 +18,7 @@ from pathlib import Path
18
  from contextlib import asynccontextmanager
19
  import uuid
20
  import asyncio
 
21
 
22
  # 本專案整合版:單一 app.py 作為後端入口,前端靜態檔(index.html/app.js/style.css)放在根目錄
23
 
@@ -1210,71 +1211,68 @@ async def websocket_endpoint_with_jwt(websocket: WebSocket, token: str = Query(N
1210
 
1211
  finally:
1212
  pass
1213
- elif message_type == "env_snapshot":
1214
  # ===== 環境快照上報 =====
1215
- try:
1216
- lat = float(message_data.get("lat")) if message_data.get("lat") is not None else None
1217
- lon = float(message_data.get("lon")) if message_data.get("lon") is not None else None
1218
- acc = message_data.get("accuracy_m")
1219
- acc = float(acc) if acc is not None else None
1220
- heading_deg = message_data.get("heading_deg")
1221
- heading_deg = float(heading_deg) if heading_deg is not None else None
1222
- tz = message_data.get("tz")
1223
- locale = message_data.get("locale")
1224
- device = message_data.get("device")
1225
-
1226
- # 後端節流:距離<100m且方位差<25度則忽略
1227
- do_write_snapshot = False
1228
- last = manager.last_env.get(user_id)
1229
- if last and lat is not None and lon is not None and last.get("lat") is not None:
1230
- dist = _haversine_m(last.get("lat",0), last.get("lon",0), lat, lon)
1231
- deg_diff = abs((heading_deg or 0) - (last.get("heading_deg") or 0))
1232
- if dist >= 100 or deg_diff >= 25:
 
 
 
1233
  do_write_snapshot = True
1234
- else:
1235
- do_write_snapshot = True
1236
-
1237
- from geohash2 import encode as gh_encode
1238
- geohash7 = gh_encode(lat, lon, precision=7) if (lat is not None and lon is not None) else None
1239
- heading_cardinal = _heading_to_cardinal(heading_deg) if heading_deg is not None else None
1240
- env_payload = {
1241
- "lat": lat,
1242
- "lon": lon,
1243
- "accuracy_m": acc,
1244
- "heading_deg": heading_deg,
1245
- "heading_cardinal": heading_cardinal,
1246
- "tz": tz,
1247
- "locale": locale,
1248
- "device": device,
1249
- "geohash_7": geohash7,
1250
- }
1251
-
1252
- # 更新會話暫存
1253
- manager.last_env[user_id] = env_payload
1254
- info = manager.get_client_info(user_id) or {}
1255
- info['env_context'] = env_payload
1256
- manager.set_client_info(user_id, info)
1257
 
1258
- try:
1259
- await set_user_env_current(user_id, env_payload)
1260
- except Exception as e:
1261
- logger.warning(f"寫入環境現況失敗: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1262
 
1263
- if do_write_snapshot:
1264
  try:
1265
- snap = env_payload.copy()
1266
- snap['reason'] = 'threshold'
1267
- await add_user_env_snapshot(user_id, snap)
1268
  except Exception as e:
1269
- logger.warning(f"寫入環境快照失敗: {e}")
1270
 
1271
- await websocket.send_json({"type": "env_ack", "success": True, "geohash_7": geohash7, "heading": heading_cardinal})
1272
- except Exception as e:
1273
- logger.error(f"處理 env_snapshot 失敗: {e}")
1274
- await websocket.send_json({"type": "env_ack", "success": False, "error": str(e)})
1275
- else:
1276
- await manager.send_message(f"未知的消息類型: {message_type}", user_id, "error")
 
1277
 
 
 
 
 
1278
  except json.JSONDecodeError:
1279
  await manager.send_message("消息格式錯誤,無法解析", user_id, "error")
1280
  except Exception as e:
@@ -2249,7 +2247,7 @@ async def list_devices(current_user: dict = Depends(get_current_user_optional)):
2249
  device_bindings = firestore_db.collection('device_bindings')
2250
 
2251
  devices = []
2252
- query = device_bindings.where("user_id", "==", current_user["sub"]).where("status", "==", "active")
2253
  docs = query.get()
2254
 
2255
  for doc in docs:
 
18
  from contextlib import asynccontextmanager
19
  import uuid
20
  import asyncio
21
+ from google.cloud.firestore import FieldFilter
22
 
23
  # 本專案整合版:單一 app.py 作為後端入口,前端靜態檔(index.html/app.js/style.css)放在根目錄
24
 
 
1211
 
1212
  finally:
1213
  pass
 
1214
  # ===== 環境快照上報 =====
1215
+ if message_type == "env_snapshot":
1216
+ try:
1217
+ lat = float(message_data.get("lat")) if message_data.get("lat") is not None else None
1218
+ lon = float(message_data.get("lon")) if message_data.get("lon") is not None else None
1219
+ acc = message_data.get("accuracy_m")
1220
+ acc = float(acc) if acc is not None else None
1221
+ heading_deg = message_data.get("heading_deg")
1222
+ heading_deg = float(heading_deg) if heading_deg is not None else None
1223
+ tz = message_data.get("tz")
1224
+ locale = message_data.get("locale")
1225
+ device = message_data.get("device")
1226
+
1227
+ # 後端節流:距離<100m且方位差<25度則忽略
1228
+ do_write_snapshot = False
1229
+ last = manager.last_env.get(user_id)
1230
+ if last and lat is not None and lon is not None and last.get("lat") is not None:
1231
+ dist = _haversine_m(last.get("lat",0), last.get("lon",0), lat, lon)
1232
+ deg_diff = abs((heading_deg or 0) - (last.get("heading_deg") or 0))
1233
+ if dist >= 100 or deg_diff >= 25:
1234
+ do_write_snapshot = True
1235
+ else:
1236
  do_write_snapshot = True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1237
 
1238
+ from geohash2 import encode as gh_encode
1239
+ geohash7 = gh_encode(lat, lon, precision=7) if (lat is not None and lon is not None) else None
1240
+ heading_cardinal = _heading_to_cardinal(heading_deg) if heading_deg is not None else None
1241
+ env_payload = {
1242
+ "lat": lat,
1243
+ "lon": lon,
1244
+ "accuracy_m": acc,
1245
+ "heading_deg": heading_deg,
1246
+ "heading_cardinal": heading_cardinal,
1247
+ "tz": tz,
1248
+ "locale": locale,
1249
+ "device": device,
1250
+ "geohash_7": geohash7,
1251
+ }
1252
+
1253
+ # 更新會話暫存
1254
+ manager.last_env[user_id] = env_payload
1255
+ info = manager.get_client_info(user_id) or {}
1256
+ info['env_context'] = env_payload
1257
+ manager.set_client_info(user_id, info)
1258
 
 
1259
  try:
1260
+ await set_user_env_current(user_id, env_payload)
 
 
1261
  except Exception as e:
1262
+ logger.warning(f"寫入環境現況失敗: {e}")
1263
 
1264
+ if do_write_snapshot:
1265
+ try:
1266
+ snap = env_payload.copy()
1267
+ snap['reason'] = 'threshold'
1268
+ await add_user_env_snapshot(user_id, snap)
1269
+ except Exception as e:
1270
+ logger.warning(f"寫入環境快照失敗: {e}")
1271
 
1272
+ await websocket.send_json({"type": "env_ack", "success": True, "geohash_7": geohash7, "heading_cardinal": heading_cardinal})
1273
+ except Exception as e:
1274
+ logger.error(f"處理 env_snapshot 失敗: {e}")
1275
+ await websocket.send_json({"type": "env_ack", "success": False, "error": str(e)})
1276
  except json.JSONDecodeError:
1277
  await manager.send_message("消息格式錯誤,無法解析", user_id, "error")
1278
  except Exception as e:
 
2247
  device_bindings = firestore_db.collection('device_bindings')
2248
 
2249
  devices = []
2250
+ query = device_bindings.where(filter=FieldFilter("user_id", "==", current_user["sub"])).where(filter=FieldFilter("status", "==", "active"))
2251
  docs = query.get()
2252
 
2253
  for doc in docs:
core/database/base.py CHANGED
@@ -175,7 +175,7 @@ async def get_user_history(user_id, limit=20):
175
  try:
176
  import asyncio as _asyncio
177
  def _fetch_messages():
178
- docs = messages_collection.where("user_id", "==", user_id)\
179
  .order_by("timestamp")\
180
  .limit(limit)\
181
  .stream()
@@ -374,7 +374,7 @@ async def get_user_chats(user_id):
374
  try:
375
  import asyncio as _asyncio
376
  def _fetch_chats():
377
- docs = chats_collection.where("user_id", "==", user_id)\
378
  .order_by("updated_at", direction=firestore.Query.DESCENDING)\
379
  .stream()
380
  chats = []
@@ -422,7 +422,7 @@ async def get_chat(chat_id):
422
  def _fetch_msgs():
423
  q = (
424
  messages_collection
425
- .where("chat_id", "==", chat_id)
426
  .order_by("timestamp", direction=_fs.Query.ASCENDING)
427
  )
428
  return [d.to_dict() for d in q.stream()]
@@ -490,7 +490,7 @@ async def get_chat_messages(chat_id: str, limit: int | None = None, ascending: b
490
  from google.cloud import firestore as _fs
491
 
492
  def _query():
493
- q = messages_collection.where("chat_id", "==", chat_id)
494
  direction = _fs.Query.ASCENDING if ascending else _fs.Query.DESCENDING
495
  q = q.order_by("timestamp", direction=direction)
496
  if limit and limit > 0:
@@ -731,7 +731,7 @@ async def save_memory(
731
 
732
  def _find_existing():
733
  docs = (
734
- col_ref.where("content_hash", "==", content_hash)
735
  .limit(1)
736
  .stream()
737
  )
@@ -936,9 +936,9 @@ async def get_user_memories(
936
 
937
  def _fetch_memories():
938
  col_ref = _get_user_memories_collection(user_id)
939
- query = col_ref.where("importance", ">=", min_importance)
940
  if memory_type:
941
- query = query.where("type", "==", memory_type)
942
  docs = (
943
  query.order_by("importance", direction=firestore.Query.DESCENDING)
944
  .order_by("updated_at", direction=firestore.Query.DESCENDING)
@@ -1112,8 +1112,8 @@ async def cleanup_old_memories(user_id: str, days_old: int = 90, min_importance:
1112
  def _delete_old():
1113
  col_ref = _get_user_memories_collection(user_id)
1114
  docs = (
1115
- col_ref.where("importance", "<", min_importance)
1116
- .where("updated_at", "<", cutoff_date)
1117
  .stream()
1118
  )
1119
  deleted_count = 0
 
175
  try:
176
  import asyncio as _asyncio
177
  def _fetch_messages():
178
+ docs = messages_collection.where(filter=FieldFilter("user_id", "==", user_id))\
179
  .order_by("timestamp")\
180
  .limit(limit)\
181
  .stream()
 
374
  try:
375
  import asyncio as _asyncio
376
  def _fetch_chats():
377
+ docs = chats_collection.where(filter=FieldFilter("user_id", "==", user_id))\
378
  .order_by("updated_at", direction=firestore.Query.DESCENDING)\
379
  .stream()
380
  chats = []
 
422
  def _fetch_msgs():
423
  q = (
424
  messages_collection
425
+ .where(filter=FieldFilter("chat_id", "==", chat_id))
426
  .order_by("timestamp", direction=_fs.Query.ASCENDING)
427
  )
428
  return [d.to_dict() for d in q.stream()]
 
490
  from google.cloud import firestore as _fs
491
 
492
  def _query():
493
+ q = messages_collection.where(filter=FieldFilter("chat_id", "==", chat_id))
494
  direction = _fs.Query.ASCENDING if ascending else _fs.Query.DESCENDING
495
  q = q.order_by("timestamp", direction=direction)
496
  if limit and limit > 0:
 
731
 
732
  def _find_existing():
733
  docs = (
734
+ col_ref.where(filter=FieldFilter("content_hash", "==", content_hash))
735
  .limit(1)
736
  .stream()
737
  )
 
936
 
937
  def _fetch_memories():
938
  col_ref = _get_user_memories_collection(user_id)
939
+ query = col_ref.where(filter=FieldFilter("importance", ">=", min_importance))
940
  if memory_type:
941
+ query = query.where(filter=FieldFilter("type", "==", memory_type))
942
  docs = (
943
  query.order_by("importance", direction=firestore.Query.DESCENDING)
944
  .order_by("updated_at", direction=firestore.Query.DESCENDING)
 
1112
  def _delete_old():
1113
  col_ref = _get_user_memories_collection(user_id)
1114
  docs = (
1115
+ col_ref.where(filter=FieldFilter("importance", "<", min_importance))
1116
+ .where(filter=FieldFilter("updated_at", "<", cutoff_date))
1117
  .stream()
1118
  )
1119
  deleted_count = 0