feat: 修复 AI 风险语义并隔离 Mock 数据
This commit is contained in:
@@ -5,6 +5,7 @@ MODEL_MODE = os.getenv("MODEL_MODE", "mock")
|
||||
MODEL_PATH = os.getenv("MODEL_PATH", "models/best.onnx")
|
||||
# YOLO 类别(二分类训练基线:healthy/sick;7 类病种扩展后再调整)
|
||||
MODEL_LABELS = os.getenv("MODEL_LABELS", "healthy,sick").split(",")
|
||||
MODEL_VERSION = os.getenv("MODEL_VERSION", "mock-2026.08.14" if MODEL_MODE == "mock" else "best.onnx")
|
||||
# mock 模式返回的固定结果
|
||||
MOCK_CLASS = os.getenv("MOCK_CLASS", "healthy")
|
||||
MOCK_CONFIDENCE = float(os.getenv("MOCK_CONFIDENCE", "0.95"))
|
||||
|
||||
@@ -5,6 +5,52 @@ from abc import ABC, abstractmethod
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def _label_set(labels) -> set[str]:
|
||||
return {label.strip().lower() for label in labels if label.strip()}
|
||||
|
||||
|
||||
def abnormal_probability(detections: list[dict], labels: tuple[str, ...] | list[str]) -> float:
|
||||
"""单帧异常概率:取异常类检测的最高置信度,避免多框求和造成虚高。"""
|
||||
abnormal = _label_set(labels) - {"healthy"}
|
||||
best = 0.0
|
||||
for detection in detections:
|
||||
class_name = str(detection.get("class_name", "")).strip().lower()
|
||||
if class_name in ("", "healthy", "unknown"):
|
||||
continue
|
||||
if abnormal and class_name not in abnormal:
|
||||
continue
|
||||
try:
|
||||
confidence = float(detection.get("confidence", 0))
|
||||
except (TypeError, ValueError):
|
||||
confidence = 0.0
|
||||
best = max(best, min(1.0, max(0.0, confidence)))
|
||||
return best
|
||||
|
||||
|
||||
def detection_status(detections: list[dict], labels: tuple[str, ...] | list[str]) -> str:
|
||||
"""空检测或 unknown 类不再被当作 healthy。"""
|
||||
if not detections:
|
||||
return "unknown"
|
||||
abnormal = _label_set(labels) - {"healthy"}
|
||||
healthy_seen = False
|
||||
unknown_seen = False
|
||||
for detection in detections:
|
||||
class_name = str(detection.get("class_name", "")).strip().lower()
|
||||
if abnormal and class_name in abnormal:
|
||||
return "abnormal"
|
||||
if not abnormal and class_name not in ("", "healthy", "unknown"):
|
||||
return "abnormal"
|
||||
if class_name == "healthy":
|
||||
healthy_seen = True
|
||||
elif class_name in ("", "unknown"):
|
||||
unknown_seen = True
|
||||
else:
|
||||
unknown_seen = True
|
||||
if healthy_seen and not unknown_seen:
|
||||
return "healthy"
|
||||
return "unknown"
|
||||
|
||||
|
||||
class Detector(ABC):
|
||||
@abstractmethod
|
||||
def detect(self, image_bytes: bytes) -> list[dict]:
|
||||
|
||||
+13
-2
@@ -6,7 +6,7 @@ import time
|
||||
from fastapi import FastAPI, File, HTTPException, Request, UploadFile
|
||||
|
||||
from . import config
|
||||
from .detector import MockDetector, ONNXDetector
|
||||
from .detector import MockDetector, ONNXDetector, abnormal_probability, detection_status
|
||||
from .stream_tasks import StreamTaskWorker, is_allowed_stream_ref
|
||||
|
||||
app = FastAPI(title="Silk AI Service", version="0.1.0")
|
||||
@@ -36,7 +36,12 @@ else:
|
||||
|
||||
@app.get("/health")
|
||||
def health():
|
||||
return {"status": "ok", "model": config.MODEL_MODE}
|
||||
return {
|
||||
"status": "ok",
|
||||
"model": config.MODEL_MODE,
|
||||
"modelVersion": config.MODEL_VERSION,
|
||||
"isMock": isinstance(detector, MockDetector),
|
||||
}
|
||||
|
||||
|
||||
@app.post("/detect")
|
||||
@@ -50,6 +55,10 @@ async def detect(file: UploadFile = File(...)):
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
return {
|
||||
"model": config.MODEL_MODE,
|
||||
"modelVersion": config.MODEL_VERSION,
|
||||
"isMock": isinstance(detector, MockDetector),
|
||||
"status": detection_status(detections, config.MODEL_LABELS),
|
||||
"abnormalProbability": abnormal_probability(detections, config.MODEL_LABELS),
|
||||
"detections": [
|
||||
{
|
||||
"bbox": d["bbox"],
|
||||
@@ -112,6 +121,8 @@ def metrics():
|
||||
gpu = None
|
||||
return {
|
||||
"model": config.MODEL_MODE,
|
||||
"modelVersion": config.MODEL_VERSION,
|
||||
"isMock": isinstance(detector, MockDetector),
|
||||
"uptimeSeconds": int(time.time() - START_TIME),
|
||||
"requests": reqs,
|
||||
"avgLatencyMs": round(avg, 2),
|
||||
|
||||
Reference in New Issue
Block a user