from abc import ABC, abstractmethod from dataclasses import dataclass from typing import List import numpy as np from .defect_classes import max_severity @dataclass class DefectBox: class_id: int class_name: str class_name_zh: str confidence: float severity: str # fatal / major / minor / rework / none box_xyxy: List[float] @dataclass class DetectResult: defects: List[DefectBox] duration_ms: float image_width: int image_height: int model_version: str @property def defect_count(self) -> int: return len(self.defects) @property def max_severity(self) -> str: return max_severity([d.severity for d in self.defects]) if self.defects else "none" @property def avg_confidence(self) -> float: if not self.defects: return 0.0 return round(sum(d.confidence for d in self.defects) / len(self.defects), 4) @property def verdict(self) -> str: return "fail" if self.defects else "pass" class BaseInferenceEngine(ABC): @abstractmethod def detect(self, image: np.ndarray, conf: float = 0.45) -> DetectResult: ... @abstractmethod def warmup(self) -> None: ... @property @abstractmethod def model_version(self) -> str: ...