- engine/defect_classes: HRIPCB 6类缺陷定义 + 4类扩展 + severity排序 - engine/base: DefectBox / DetectResult 数据类 + BaseInferenceEngine 抽象基类 - engine/ultralytics_adapter: YOLOv8 .pt 推理适配器 + warmup - engine/annotator: 按 severity 着色的标注图生成 + base64 编码 - engine/loader: 单例管理 + asyncio.Lock 推理串行化 + 热重载支持 - config: Pydantic v1 BaseSettings,读取 .env - schema: DetectResponse / HealthResponse / ReloadRequest 等响应模型 - api/detect: POST /api/detect,内存读图,推理锁保护 - api/health: GET /api/health - api/model: POST /api/model/reload 热重载接口 - main: FastAPI lifespan 启动加载模型 测试通过:/api/health 200,/api/detect 空图返回 pass,标注图 base64 正常 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
44 lines
1.4 KiB
Python
44 lines
1.4 KiB
Python
import asyncio
|
|
from typing import Optional
|
|
|
|
from .base import BaseInferenceEngine
|
|
|
|
_engine: Optional[BaseInferenceEngine] = None
|
|
# 懒初始化,确保在事件循环启动后创建
|
|
_inference_lock: Optional[asyncio.Lock] = None
|
|
|
|
|
|
def get_engine() -> BaseInferenceEngine:
|
|
if _engine is None:
|
|
raise RuntimeError("推理引擎未初始化,请先调用 init_engine()")
|
|
return _engine
|
|
|
|
|
|
def get_inference_lock() -> asyncio.Lock:
|
|
global _inference_lock
|
|
if _inference_lock is None:
|
|
_inference_lock = asyncio.Lock()
|
|
return _inference_lock
|
|
|
|
|
|
def init_engine(model_path: str, runtime: str = "ultralytics") -> BaseInferenceEngine:
|
|
global _engine
|
|
if runtime == "onnx":
|
|
from .onnx_adapter import OnnxRuntimeAdapter
|
|
_engine = OnnxRuntimeAdapter(model_path)
|
|
else:
|
|
from .ultralytics_adapter import UltralyticsAdapter
|
|
_engine = UltralyticsAdapter(model_path)
|
|
|
|
print(f"[mingxi-vision] 加载模型: {model_path}")
|
|
_engine.warmup()
|
|
print(f"[mingxi-vision] 引擎就绪: {_engine.__class__.__name__} · {_engine.model_version}")
|
|
return _engine
|
|
|
|
|
|
def reload_engine(model_path: str, runtime: str = "ultralytics") -> BaseInferenceEngine:
|
|
"""热重载模型,调用方必须持有推理锁"""
|
|
global _engine
|
|
_engine = None # 释放旧引用,让 GC 回收显存
|
|
return init_engine(model_path, runtime)
|