Spaces:
Paused
Paused
Update main.py
Browse files
main.py
CHANGED
|
@@ -249,21 +249,44 @@ def gemini_explain(prompt: str, sys: str = None, model: str = EXPLAIN_MODEL) ->
|
|
| 249 |
return getattr(resp, "text", "").strip() or ""
|
| 250 |
|
| 251 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 252 |
-
# UTIL: Build graph & timeline from events (+ risk overlays)
|
| 253 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
import math
|
| 255 |
|
| 256 |
def normalize_risk(score: float) -> float:
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
|
| 268 |
|
| 269 |
|
|
@@ -553,10 +576,8 @@ def get_leads():
|
|
| 553 |
cur.execute(sql, args)
|
| 554 |
rows = cur.fetchall()
|
| 555 |
|
| 556 |
-
# Add normalized risk score
|
| 557 |
for row in rows:
|
| 558 |
-
|
| 559 |
-
row["risk_score_normalized"] = normalize_risk(row["risk_score"])
|
| 560 |
|
| 561 |
return jsonify({"ok": True, "data": rows})
|
| 562 |
|
|
@@ -570,9 +591,7 @@ def object_detail(object_id: int):
|
|
| 570 |
if not obj:
|
| 571 |
return jsonify({"ok": False, "error": "not_found"}), 404
|
| 572 |
|
| 573 |
-
|
| 574 |
-
if "risk_score" in obj and isinstance(obj["risk_score"], (int, float)):
|
| 575 |
-
obj["risk_score_normalized"] = normalize_risk(obj["risk_score"])
|
| 576 |
|
| 577 |
cur.execute("SELECT seq, sentence FROM provenance_sentences WHERE object_id=%s ORDER BY seq", (object_id,))
|
| 578 |
sents = cur.fetchall()
|
|
@@ -588,6 +607,7 @@ def object_detail(object_id: int):
|
|
| 588 |
return jsonify({"ok": True, "object": obj, "sentences": sents, "events": events, "risks": risks})
|
| 589 |
|
| 590 |
|
|
|
|
| 591 |
@app.get("/api/graph/<int:object_id>")
|
| 592 |
@with_db_retry
|
| 593 |
def graph(object_id: int):
|
|
|
|
| 249 |
return getattr(resp, "text", "").strip() or ""
|
| 250 |
|
| 251 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 252 |
+
# UTIL: Build risk scores, graph & timeline from events (+ risk overlays)
|
| 253 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 254 |
+
#
|
| 255 |
+
# Targets:
|
| 256 |
+
# raw 100 -> ~55
|
| 257 |
+
# raw 200 -> ~80
|
| 258 |
+
# raw 2000 -> ~99 (slow approach to 99 beyond this)
|
| 259 |
import math
|
| 260 |
|
| 261 |
def normalize_risk(score: float) -> float:
|
| 262 |
+
if score is None:
|
| 263 |
+
return None
|
| 264 |
+
s = max(float(score), 0.0)
|
| 265 |
+
|
| 266 |
+
# 0β100: quick lift to ~55 by 100
|
| 267 |
+
if s <= 100.0:
|
| 268 |
+
return round(55.0 * ((s / 100.0) ** 0.7), 2)
|
| 269 |
+
|
| 270 |
+
# 100β200: fast jump 55 -> 80
|
| 271 |
+
if s <= 200.0:
|
| 272 |
+
return round(55.0 + 25.0 * (((s - 100.0) / 100.0) ** 0.8), 2)
|
| 273 |
+
|
| 274 |
+
# 200+: slow, asymptotic approach to 99
|
| 275 |
+
# Choose k so that at s=2000, value β 98.8 (renders 99%)
|
| 276 |
+
k = math.log(100.0) / 1800.0
|
| 277 |
+
return round(99.0 - 19.0 * math.exp(-k * (s - 200.0)), 2)
|
| 278 |
+
|
| 279 |
+
# Backend-only compatibility shim
|
| 280 |
+
# Preserves the original raw value, overwrites "risk_score" for the UI,
|
| 281 |
+
# and also exposes an explicit "risk_score_normalized" key.
|
| 282 |
+
def _apply_normalized_risk_inplace(row: dict):
|
| 283 |
+
if not isinstance(row, dict):
|
| 284 |
+
return
|
| 285 |
+
rs = row.get("risk_score")
|
| 286 |
+
if isinstance(rs, (int, float)):
|
| 287 |
+
row["risk_score_raw"] = rs # keep original server-side number
|
| 288 |
+
row["risk_score"] = normalize_risk(rs) # UI keeps working without changes
|
| 289 |
+
row["risk_score_normalized"] = row["risk_score"]
|
| 290 |
|
| 291 |
|
| 292 |
|
|
|
|
| 576 |
cur.execute(sql, args)
|
| 577 |
rows = cur.fetchall()
|
| 578 |
|
|
|
|
| 579 |
for row in rows:
|
| 580 |
+
_apply_normalized_risk_inplace(row)
|
|
|
|
| 581 |
|
| 582 |
return jsonify({"ok": True, "data": rows})
|
| 583 |
|
|
|
|
| 591 |
if not obj:
|
| 592 |
return jsonify({"ok": False, "error": "not_found"}), 404
|
| 593 |
|
| 594 |
+
_apply_normalized_risk_inplace(obj)
|
|
|
|
|
|
|
| 595 |
|
| 596 |
cur.execute("SELECT seq, sentence FROM provenance_sentences WHERE object_id=%s ORDER BY seq", (object_id,))
|
| 597 |
sents = cur.fetchall()
|
|
|
|
| 607 |
return jsonify({"ok": True, "object": obj, "sentences": sents, "events": events, "risks": risks})
|
| 608 |
|
| 609 |
|
| 610 |
+
|
| 611 |
@app.get("/api/graph/<int:object_id>")
|
| 612 |
@with_db_retry
|
| 613 |
def graph(object_id: int):
|