Files
Shixun/ai-service/app/api/imaging.py
T
2026-07-31 12:27:41 +08:00

90 lines
3.6 KiB
Python

from __future__ import annotations
import logging
from pathlib import Path
from fastapi import APIRouter, File, Form, HTTPException, UploadFile
from app.schemas.models import ImagingAnalyzeResponse
from app.services.monai_preprocess import load_image_bgr, preprocess
from app.services.report_generator import build_imaging_texts, generate_imaging_report, make_full_report
from app.schemas.models import ImagingReportRequest
from app.services.yolo_detector import get_detector
from app.services.yolo_manager import get_yolo_manager
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/imaging", tags=["imaging"])
@router.post("/analyze", response_model=ImagingAnalyzeResponse)
async def analyze_imaging(
file: UploadFile | None = File(default=None),
image_path: str | None = Form(default=None),
study_type: str = Form(default="CT"),
body_part: str = Form(default=""),
patient_summary: str = Form(default=""),
) -> ImagingAnalyzeResponse:
raw = await _read_bytes(file, image_path)
try:
image_bgr = load_image_bgr(raw)
prep = preprocess(image_bgr)
detector = get_detector()
detections = detector.detect(image_bgr, study_type=study_type)
annotated = detector.annotate(image_bgr, detections)
findings, diagnosis, recommendations, confidence = build_imaging_texts(
study_type, body_part, detections, detector.mode
)
report = generate_imaging_report(
ImagingReportRequest(
study_type=study_type,
body_part=body_part,
patient_summary=patient_summary,
preliminary_diagnosis=diagnosis,
findings=findings,
detections=detections,
confidence=confidence,
)
)
backend = prep.get("backend", "opencv")
model_version = f"yolo-{detector.mode}+{backend}+{report.model_version}"
try:
get_yolo_manager().record_inference(
mode=detector.mode,
detections=detections,
study_type=study_type,
model_version=model_version,
)
except Exception as e:
logger.warning("记录 YOLO 统计失败: %s", e)
return ImagingAnalyzeResponse(
detections=detections,
annotated_image_base64=annotated,
preliminary_diagnosis=report.impression or diagnosis,
findings=report.findings or findings,
recommendations=report.recommendations or recommendations,
confidence=confidence,
model_version=model_version,
mode=detector.mode, # type: ignore[arg-type]
full_report=report.full_report
or make_full_report(study_type, body_part, findings, diagnosis, recommendations, patient_summary),
)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e)) from e
except Exception as e:
logger.exception("影像分析失败")
raise HTTPException(status_code=500, detail=f"影像分析失败: {e}") from e
async def _read_bytes(file: UploadFile | None, image_path: str | None) -> bytes:
if file is not None:
data = await file.read()
if not data:
raise HTTPException(status_code=400, detail="上传文件为空")
return data
if image_path:
path = Path(image_path)
if not path.is_file():
raise HTTPException(status_code=400, detail=f"影像路径不存在: {image_path}")
return path.read_bytes()
raise HTTPException(status_code=400, detail="请提供 file 或 image_path")