deepdetection / src /fusion /fuser.py
akagtag's picture
Initial commit
4e75170
from __future__ import annotations
import numpy as np
from src.types import DetectionResponse, EngineResult
ENGINE_WEIGHTS = {
"fingerprint": 0.45,
"coherence": 0.35,
"sstgnn": 0.20,
}
ENGINE_WEIGHTS_VIDEO = {
"fingerprint": 0.30,
"coherence": 0.50,
"sstgnn": 0.20,
}
ATTRIBUTION_PRIORITY = {
"fingerprint": 1,
"sstgnn": 2,
"coherence": 3,
}
def _normalize_generator(value: str | None) -> str:
if not value:
return "real"
return str(value).strip().lower().replace(" ", "_")
def fuse(results: list[EngineResult], is_video: bool = False) -> tuple[str, float, str]:
"""Return (verdict, confidence_for_verdict, attributed_generator)."""
weights = ENGINE_WEIGHTS_VIDEO if is_video else ENGINE_WEIGHTS
active = [result for result in results if result.verdict != "UNKNOWN"]
if not active:
return "UNKNOWN", 0.5, "unknown_gan"
wf = sum(
result.confidence * weights.get(result.engine, 0.1)
for result in active
if result.verdict == "FAKE"
)
wr = sum(
(1.0 - result.confidence) * weights.get(result.engine, 0.1)
for result in active
if result.verdict == "REAL"
)
denom = wf + wr + 1e-9
fake_prob = float(np.clip(wf / denom, 0.0, 1.0))
verdict = "FAKE" if fake_prob > 0.5 else "REAL"
confidence = fake_prob if verdict == "FAKE" else (1.0 - fake_prob)
generator = "real"
if verdict == "FAKE":
for result in sorted(active, key=lambda r: ATTRIBUTION_PRIORITY.get(r.engine, 9)):
candidate = _normalize_generator(result.attributed_generator)
if candidate and candidate != "real":
generator = candidate
break
if generator == "real":
generator = "unknown_gan"
return verdict, confidence, generator
class Fuser:
"""Compatibility wrapper returning `DetectionResponse` objects."""
def fuse(
self,
results: list[EngineResult],
media_type: str = "image",
total_ms: float = 0.0,
) -> DetectionResponse:
if not results:
return DetectionResponse(
verdict="REAL",
confidence=0.5,
attributed_generator="unknown_gan",
explanation="No engine results available.",
processing_time_ms=round(total_ms, 2),
engine_breakdown=[],
)
verdict, confidence, generator = fuse(results, is_video=(media_type == "video"))
if verdict == "UNKNOWN":
explanation = "No active engine outputs were available."
else:
summary = ", ".join(
f"{result.engine}:{result.verdict}({result.confidence:.2f})"
for result in results
)
explanation = f"Fused {media_type} analysis from engines: {summary}."
return DetectionResponse(
verdict=verdict,
confidence=confidence,
attributed_generator=generator,
explanation=explanation,
processing_time_ms=round(total_ms, 2),
engine_breakdown=results,
)