Spaces:
Sleeping
Sleeping
Commit ·
091223d
1
Parent(s): 91db04e
refactor(analyze): use shared json_safe.sanitize()
Browse filesReplaces the module-level _sanitize() definition with an import from
the new shared module. All existing call sites unchanged (imported
under the same local name).
backend/api/routes/analyze.py
CHANGED
|
@@ -8,8 +8,6 @@ from slowapi import Limiter
|
|
| 8 |
from slowapi.util import get_remote_address
|
| 9 |
import hashlib
|
| 10 |
import time
|
| 11 |
-
import math as _math
|
| 12 |
-
import numpy as _np
|
| 13 |
from typing import List
|
| 14 |
|
| 15 |
from backend.services.image_forensics import ImageForensics
|
|
@@ -20,41 +18,11 @@ from backend.core.cache import forensics_cache
|
|
| 20 |
from backend.services.metrics_collector import record_analysis
|
| 21 |
from backend.core.audit_log import log_analysis
|
| 22 |
from backend.core.config import settings
|
|
|
|
| 23 |
|
| 24 |
logger = setup_logger(__name__)
|
| 25 |
|
| 26 |
|
| 27 |
-
def _sanitize(obj):
|
| 28 |
-
"""Recursively replace NaN/Infinity floats with 0.0 (F-8, F-27).
|
| 29 |
-
|
| 30 |
-
json.dumps() happily emits the literal tokens NaN/Infinity, which
|
| 31 |
-
are not valid per RFC 8259 and many non-Python JSON parsers reject
|
| 32 |
-
outright. Division-by-zero guards throughout the signal detectors
|
| 33 |
-
(e.g. "+ 1e-8" denominators in several cosine-similarity calcs)
|
| 34 |
-
mean a signal can legitimately produce a non-finite float.
|
| 35 |
-
|
| 36 |
-
This single shared helper replaces the two near-duplicate copies
|
| 37 |
-
that used to live inline in analyze_image() -- one for the
|
| 38 |
-
cache-miss path, one for the cache-hit path (_sanitize_hit) -- which
|
| 39 |
-
is exactly the kind of drift risk this project has been bitten by
|
| 40 |
-
before (see F-4). It is now called ONCE, immediately after
|
| 41 |
-
generate_forensic_report() returns and before the report is cached,
|
| 42 |
-
sent to any webhook, or written to the audit log -- previously all
|
| 43 |
-
three saw the raw, unsanitized report, and only the direct HTTP
|
| 44 |
-
response (sanitized too late, right before returning) was
|
| 45 |
-
guaranteed clean.
|
| 46 |
-
"""
|
| 47 |
-
if isinstance(obj, _np.generic):
|
| 48 |
-
return obj.item()
|
| 49 |
-
if isinstance(obj, float):
|
| 50 |
-
return 0.0 if (_math.isnan(obj) or _math.isinf(obj)) else obj
|
| 51 |
-
if isinstance(obj, dict):
|
| 52 |
-
return {k: _sanitize(v) for k, v in obj.items()}
|
| 53 |
-
if isinstance(obj, list):
|
| 54 |
-
return [_sanitize(v) for v in obj]
|
| 55 |
-
return obj
|
| 56 |
-
|
| 57 |
-
|
| 58 |
def _correct_exif_orientation(file_bytes: bytes) -> bytes:
|
| 59 |
"""Apply EXIF orientation before all forensic analysis.
|
| 60 |
|
|
|
|
| 8 |
from slowapi.util import get_remote_address
|
| 9 |
import hashlib
|
| 10 |
import time
|
|
|
|
|
|
|
| 11 |
from typing import List
|
| 12 |
|
| 13 |
from backend.services.image_forensics import ImageForensics
|
|
|
|
| 18 |
from backend.services.metrics_collector import record_analysis
|
| 19 |
from backend.core.audit_log import log_analysis
|
| 20 |
from backend.core.config import settings
|
| 21 |
+
from backend.utils.json_safe import sanitize as _sanitize
|
| 22 |
|
| 23 |
logger = setup_logger(__name__)
|
| 24 |
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
def _correct_exif_orientation(file_bytes: bytes) -> bytes:
|
| 27 |
"""Apply EXIF orientation before all forensic analysis.
|
| 28 |
|