Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -5,7 +5,6 @@ import uuid
|
|
| 5 |
import re
|
| 6 |
import time
|
| 7 |
import json
|
| 8 |
-
import base64
|
| 9 |
import traceback
|
| 10 |
import inflect
|
| 11 |
from datetime import datetime, timezone
|
|
@@ -49,45 +48,52 @@ IDX_FACES = "enterprise-faces"
|
|
| 49 |
IDX_OBJECTS = "enterprise-objects"
|
| 50 |
|
| 51 |
# ════════════════════════════════════════════════════════════════
|
| 52 |
-
#
|
| 53 |
# HF Space Secrets needed:
|
| 54 |
-
#
|
| 55 |
-
#
|
| 56 |
-
# LOKI_PASSWORD → your Grafana Cloud API token (Logs:Write scope)
|
| 57 |
# ════════════════════════════════════════════════════════════════
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
LOKI_PASSWORD = os.getenv("LOKI_PASSWORD", "")
|
| 61 |
|
| 62 |
-
async def
|
| 63 |
-
"""Fire-and-forget
|
| 64 |
-
if not (
|
| 65 |
return
|
| 66 |
try:
|
| 67 |
import aiohttp
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
async with aiohttp.ClientSession() as s:
|
| 80 |
-
async with s.post(
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
|
|
|
|
|
|
|
|
|
| 85 |
except Exception as exc:
|
| 86 |
-
_log_fn("DEBUG", f"
|
| 87 |
|
| 88 |
def log(level: str, event: str, **data):
|
| 89 |
"""
|
| 90 |
-
Log to console +
|
| 91 |
Usage: log("INFO", "upload.complete", user_id="x", files=3, duration_ms=340)
|
| 92 |
"""
|
| 93 |
clean = {k: v for k, v in data.items()}
|
|
@@ -95,7 +101,7 @@ def log(level: str, event: str, **data):
|
|
| 95 |
try:
|
| 96 |
loop = asyncio.get_event_loop()
|
| 97 |
if loop.is_running():
|
| 98 |
-
asyncio.create_task(
|
| 99 |
except Exception:
|
| 100 |
pass
|
| 101 |
|
|
|
|
| 5 |
import re
|
| 6 |
import time
|
| 7 |
import json
|
|
|
|
| 8 |
import traceback
|
| 9 |
import inflect
|
| 10 |
from datetime import datetime, timezone
|
|
|
|
| 48 |
IDX_OBJECTS = "enterprise-objects"
|
| 49 |
|
| 50 |
# ════════════════════════════════════════════════════════════════
|
| 51 |
+
# SUPABASE LOGGING — async, fire-and-forget, never crashes API
|
| 52 |
# HF Space Secrets needed:
|
| 53 |
+
# SUPABASE_URL → https://xxxx.supabase.co
|
| 54 |
+
# SUPABASE_SERVICE_KEY → your Supabase service_role key (not anon!)
|
|
|
|
| 55 |
# ════════════════════════════════════════════════════════════════
|
| 56 |
+
SUPABASE_URL = os.getenv("SUPABASE_URL", "")
|
| 57 |
+
SUPABASE_SERVICE_KEY = os.getenv("SUPABASE_SERVICE_KEY", "")
|
|
|
|
| 58 |
|
| 59 |
+
async def _supabase_log_push(level: str, event: str, data: dict):
|
| 60 |
+
"""Fire-and-forget insert into Supabase app_logs table."""
|
| 61 |
+
if not (SUPABASE_URL and SUPABASE_SERVICE_KEY):
|
| 62 |
return
|
| 63 |
try:
|
| 64 |
import aiohttp
|
| 65 |
+
row = {
|
| 66 |
+
"level": level.upper(),
|
| 67 |
+
"event": event,
|
| 68 |
+
"user_id": str(data.get("user_id", "anonymous")),
|
| 69 |
+
"ip": str(data.get("ip", "")),
|
| 70 |
+
"mode": str(data.get("mode", "")),
|
| 71 |
+
"page": str(data.get("page", "")),
|
| 72 |
+
"duration_ms": int(data["duration_ms"]) if "duration_ms" in data else None,
|
| 73 |
+
"error": str(data["error"]) if "error" in data else None,
|
| 74 |
+
"data": data,
|
| 75 |
+
}
|
| 76 |
+
headers = {
|
| 77 |
+
"Content-Type": "application/json",
|
| 78 |
+
"apikey": SUPABASE_SERVICE_KEY,
|
| 79 |
+
"Authorization": f"Bearer {SUPABASE_SERVICE_KEY}",
|
| 80 |
+
"Prefer": "return=minimal",
|
| 81 |
+
}
|
| 82 |
async with aiohttp.ClientSession() as s:
|
| 83 |
+
async with s.post(
|
| 84 |
+
f"{SUPABASE_URL}/rest/v1/app_logs",
|
| 85 |
+
json=row, headers=headers,
|
| 86 |
+
timeout=aiohttp.ClientTimeout(total=5)
|
| 87 |
+
) as r:
|
| 88 |
+
if r.status not in (200, 201):
|
| 89 |
+
body = await r.text()
|
| 90 |
+
_log_fn("WARNING", f"Supabase log insert failed {r.status}: {body[:200]}")
|
| 91 |
except Exception as exc:
|
| 92 |
+
_log_fn("DEBUG", f"Supabase log push skipped: {exc}")
|
| 93 |
|
| 94 |
def log(level: str, event: str, **data):
|
| 95 |
"""
|
| 96 |
+
Log to console + Supabase app_logs table (background task).
|
| 97 |
Usage: log("INFO", "upload.complete", user_id="x", files=3, duration_ms=340)
|
| 98 |
"""
|
| 99 |
clean = {k: v for k, v in data.items()}
|
|
|
|
| 101 |
try:
|
| 102 |
loop = asyncio.get_event_loop()
|
| 103 |
if loop.is_running():
|
| 104 |
+
asyncio.create_task(_supabase_log_push(level, event, data))
|
| 105 |
except Exception:
|
| 106 |
pass
|
| 107 |
|