botInfinity commited on
Commit
93fc243
·
verified ·
1 Parent(s): 582d196

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +86 -0
main.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import io
3
+ import logging
4
+ from typing import Tuple
5
+
6
+ from fastapi import FastAPI, File, UploadFile, HTTPException
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from pydantic import BaseModel
9
+ from PIL import Image
10
+
11
+ # Roboflow inference
12
+ from inference import get_model
13
+
14
+ logging.basicConfig(level=logging.INFO)
15
+ logger = logging.getLogger("vehicle-predictor")
16
+
17
+ # FastAPI setup
18
+ app = FastAPI(title="Vehicle Type Predictor")
19
+
20
+ app.add_middleware(
21
+ CORSMiddleware,
22
+ allow_origins=["*"], # you can tighten this later if needed
23
+ allow_credentials=True,
24
+ allow_methods=["*"],
25
+ allow_headers=["*"],
26
+ )
27
+
28
+ # Load Roboflow model at startup
29
+ ROBOFLOW_API_KEY = os.environ.get("ROBOFLOW_API_KEY")
30
+ MODEL_ID = "vehicle-classification-eapcd/19"
31
+
32
+ if ROBOFLOW_API_KEY is None:
33
+ logger.error("❌ ROBOFLOW_API_KEY not found in environment variables")
34
+ model = None
35
+ else:
36
+ try:
37
+ logger.info("🚀 Loading Roboflow model...")
38
+ model = get_model(model_id=MODEL_ID, api_key=ROBOFLOW_API_KEY)
39
+ logger.info("✅ Roboflow model loaded successfully")
40
+ except Exception as e:
41
+ logger.exception("❌ Failed to load Roboflow model")
42
+ model = None
43
+
44
+
45
+ # Response model
46
+ class PredictionResponse(BaseModel):
47
+ label: str
48
+ confidence: float
49
+
50
+
51
+ @app.post("/predict", response_model=PredictionResponse)
52
+ async def predict(file: UploadFile = File(...)):
53
+ if model is None:
54
+ raise HTTPException(status_code=503, detail="Model not loaded")
55
+
56
+ if not file.content_type.startswith("image/"):
57
+ raise HTTPException(status_code=400, detail="File must be an image")
58
+
59
+ try:
60
+ contents = await file.read()
61
+
62
+ # Roboflow accepts PIL Image directly
63
+ img = Image.open(io.BytesIO(contents)).convert("RGB")
64
+
65
+ # Run inference
66
+ result = model.infer(img)
67
+
68
+ if not result.get("predictions"):
69
+ raise HTTPException(status_code=500, detail="No predictions returned")
70
+
71
+ # Take top prediction
72
+ pred = result["predictions"][0]
73
+ label = pred.get("class", "Unknown")
74
+ confidence = float(pred.get("confidence", 0.0))
75
+
76
+ logger.info(f"Predicted {label} ({confidence:.4f}) for {file.filename}")
77
+ return PredictionResponse(label=label, confidence=confidence)
78
+
79
+ except Exception as e:
80
+ logger.exception("Prediction failed")
81
+ raise HTTPException(status_code=500, detail="Prediction failed")
82
+
83
+
84
+ @app.get("/health")
85
+ def health():
86
+ return {"status": "ok", "model_loaded": model is not None}