Spaces:
Runtime error
Runtime error
| from fastapi import FastAPI, File, UploadFile, HTTPException | |
| from fastapi.responses import JSONResponse | |
| from ultralytics import YOLO | |
| import numpy as np | |
| import cv2 | |
| from io import BytesIO | |
| from PIL import Image | |
| import base64 | |
| app = FastAPI(title="Car Parts & Damage Detection API") | |
| # Load YOLO models | |
| try: | |
| car_part_model = YOLO("car_part_detector_model.pt") | |
| damage_model = YOLO("damage_general_model.pt") | |
| except Exception as e: | |
| raise RuntimeError(f"Failed to load models: {str(e)}") | |
| def image_to_base64(img: np.ndarray) -> str: | |
| """Convert numpy image to base64 string for JSON response.""" | |
| _, buffer = cv2.imencode(".png", img) | |
| return base64.b64encode(buffer).decode("utf-8") | |
| async def predict(file: UploadFile = File(...)): | |
| """ | |
| Upload an image and get car parts and damage detection results. | |
| Returns annotated images as base64 strings and text descriptions. | |
| """ | |
| try: | |
| # Read and process image | |
| contents = await file.read() | |
| image = Image.open(BytesIO(contents)).convert("RGB") | |
| img = np.array(image) | |
| # Initialize default blank images (gray placeholder) | |
| blank_img = np.full((img.shape[0], img.shape[1], 3), 128, dtype=np.uint8) | |
| car_part_img = blank_img.copy() | |
| damage_img = blank_img.copy() | |
| # Initialize text results | |
| car_part_text = "Car Parts: No detections" | |
| damage_text = "Damage: No detections" | |
| # Process car parts detection | |
| try: | |
| car_part_results = car_part_model(img)[0] | |
| if car_part_results.boxes: | |
| car_part_img = car_part_results.plot()[..., ::-1] # BGR to RGB | |
| car_part_text = "Car Parts:\n" + "\n".join( | |
| f"- {car_part_results.names[int(cls)]} ({conf:.2f})" | |
| for conf, cls in zip(car_part_results.boxes.conf, car_part_results.boxes.cls) | |
| ) | |
| except Exception as e: | |
| car_part_text = f"Car Parts: Error: {str(e)}" | |
| # Process damage detection | |
| try: | |
| damage_results = damage_model(img)[0] | |
| if damage_results.boxes: | |
| damage_img = damage_results.plot()[..., ::-1] # BGR to RGB | |
| damage_text = "Damage:\n" + "\n".join( | |
| f"- {damage_results.names[int(cls)]} ({conf:.2f})" | |
| for conf, cls in zip(damage_results.boxes.conf, damage_results.boxes.cls) | |
| ) | |
| except Exception as e: | |
| damage_text = f"Damage: Error: {str(e)}" | |
| # Convert output images to base64 | |
| car_part_img_base64 = image_to_base64(car_part_img) | |
| damage_img_base64 = image_to_base64(damage_img) | |
| return JSONResponse({ | |
| "car_part_image": car_part_img_base64, | |
| "car_part_text": car_part_text, | |
| "damage_image": damage_img_base64, | |
| "damage_text": damage_text | |
| }) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Inference error: {str(e)}") | |
| async def root(): | |
| """Check if the API is running.""" | |
| return {"message": "Car Parts & Damage Detection API is running"} |