File size: 2,635 Bytes
aac350d 23d337e aac350d 23d337e aac350d 23d337e aac350d 23d337e aac350d 23d337e aac350d 23d337e aac350d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | """
Explainer — turns a ConfidenceScore or UnifiedFaceReport into a
multi-line human-readable string for display in the UI / logs.
"""
from __future__ import annotations
from models.reports import (
ConfidenceScore,
ConflictReport,
UnifiedFaceReport,
)
class Explainer:
"""Renders confidence + report as human-readable text."""
@staticmethod
def explain_score(score: ConfidenceScore) -> str:
lines = [f"Overall confidence: {score.overall:.2%} ({score.method})"]
if score.explanation:
lines.append(f" {score.explanation}")
if score.components:
lines.append(" Components:")
for k, v in score.components.items():
lines.append(f" - {k}: {v:.3f}" if isinstance(v, float) else f" - {k}: {v}")
return "\n".join(lines)
@staticmethod
def explain_conflicts(conflicts: list[ConflictReport]) -> str:
if not conflicts:
return "No conflicts detected."
lines = [f"{len(conflicts)} conflict(s) detected:"]
for c in conflicts:
lines.append(
f" [{c.severity.upper()}] {c.kind}: {c.description} "
f"(providers: {', '.join(c.providers)})"
)
return "\n".join(lines)
@staticmethod
def explain_report(report: UnifiedFaceReport) -> str:
m = report.metadata
lines = [
f"Job {m.job_id} — {m.total_elapsed_ms:.0f}ms total",
f" Providers invoked: {', '.join(m.providers_invoked) or 'none'}",
f" Succeeded: {', '.join(m.providers_succeeded) or 'none'}",
f" Failed: {', '.join(m.providers_failed) or 'none'}",
f" Detections: {len(report.detections)}",
f" Matches: {len(report.matches)}",
f" Scraped images: {len(report.scraped_images)}",
f" Reverse matches: {len(report.reverse_matches)}",
f" Image analyses: {len(report.image_analyses)}",
f" Metadata extractions: {len(report.metadata_extractions)}",
f" Forensics: {len(report.forensics)}",
f" Conflicts: {len(report.conflicts)}",
]
if m.limitations:
lines.append(" Limitations:")
for lim in m.limitations:
lines.append(f" - {lim}")
if report.overall_confidence:
lines.append("")
lines.append(Explainer.explain_score(report.overall_confidence))
if report.conflicts:
lines.append("")
lines.append(Explainer.explain_conflicts(report.conflicts))
return "\n".join(lines)
|