crtal commited on
Commit
4ce01d4
·
1 Parent(s): e556bb4

fix: add file size limit, return 400 on invalid images, use inference_mode

Browse files
Files changed (1) hide show
  1. app.py +17 -19
app.py CHANGED
@@ -2,8 +2,10 @@ from fastapi import FastAPI, File, UploadFile, HTTPException
2
  import torch
3
  import torch.nn as nn
4
  from torchvision import models, transforms
5
- from PIL import Image
6
  import io
 
 
7
 
8
  app = FastAPI(title="Food Spoilage Detection API (Swin)")
9
 
@@ -29,34 +31,31 @@ preprocess = transforms.Compose([
29
  ])
30
 
31
  CLASS_NAMES = ["fresh", "spoiled"]
32
- ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg"}
33
 
34
  @app.post("/predict")
35
  async def predict(file: UploadFile = File(...)):
36
- # 1. Validate File Extension
37
- extension = file.filename.split(".")[-1].lower()
38
- if extension not in ALLOWED_EXTENSIONS:
39
- raise HTTPException(status_code=400, detail=f"Invalid file type. Allowed: {ALLOWED_EXTENSIONS}")
40
 
41
  try:
42
- # 2. Read and Validate Image
43
- contents = await file.read()
44
  image = Image.open(io.BytesIO(contents)).convert("RGB")
45
-
46
- # 3. Preprocess
 
 
47
  input_tensor = preprocess(image)
48
  input_batch = input_tensor.unsqueeze(0).to(device)
49
-
50
- # 4. Inference
51
- with torch.no_grad():
52
  outputs = model(input_batch)
53
  probabilities = torch.nn.functional.softmax(outputs[0], dim=0)
54
  confidence, index = torch.max(probabilities, 0)
55
-
56
  conf_score = float(confidence.item())
57
-
58
- # 5. Robustness Check: Confidence Threshold
59
- # If the model is not confident enough, it might not be a food image
60
  if conf_score < 0.70:
61
  return {
62
  "status": "ambiguous",
@@ -64,7 +63,7 @@ async def predict(file: UploadFile = File(...)):
64
  "confidence": conf_score,
65
  "suggestion": "Please provide a clearer image of a fruit or vegetable."
66
  }
67
-
68
  return {
69
  "prediction": CLASS_NAMES[index.item()],
70
  "confidence": conf_score,
@@ -84,5 +83,4 @@ def read_root():
84
  }
85
 
86
  if __name__ == "__main__":
87
- import uvicorn
88
  uvicorn.run(app, host="0.0.0.0", port=8000)
 
2
  import torch
3
  import torch.nn as nn
4
  from torchvision import models, transforms
5
+ from PIL import Image, UnidentifiedImageError
6
  import io
7
+ import uvicorn
8
+
9
 
10
  app = FastAPI(title="Food Spoilage Detection API (Swin)")
11
 
 
31
  ])
32
 
33
  CLASS_NAMES = ["fresh", "spoiled"]
34
+ MAX_FILE_SIZE = 20 * 1024 * 1024 # 10 MB
35
 
36
  @app.post("/predict")
37
  async def predict(file: UploadFile = File(...)):
38
+ contents = await file.read()
39
+
40
+ if len(contents) > MAX_FILE_SIZE:
41
+ raise HTTPException(status_code=400, detail="File too large. Maximum size is 10 MB.")
42
 
43
  try:
 
 
44
  image = Image.open(io.BytesIO(contents)).convert("RGB")
45
+ except UnidentifiedImageError:
46
+ raise HTTPException(status_code=400, detail="Could not read image. Please upload a valid image file.")
47
+
48
+ try:
49
  input_tensor = preprocess(image)
50
  input_batch = input_tensor.unsqueeze(0).to(device)
51
+
52
+ with torch.inference_mode():
 
53
  outputs = model(input_batch)
54
  probabilities = torch.nn.functional.softmax(outputs[0], dim=0)
55
  confidence, index = torch.max(probabilities, 0)
56
+
57
  conf_score = float(confidence.item())
58
+
 
 
59
  if conf_score < 0.70:
60
  return {
61
  "status": "ambiguous",
 
63
  "confidence": conf_score,
64
  "suggestion": "Please provide a clearer image of a fruit or vegetable."
65
  }
66
+
67
  return {
68
  "prediction": CLASS_NAMES[index.item()],
69
  "confidence": conf_score,
 
83
  }
84
 
85
  if __name__ == "__main__":
 
86
  uvicorn.run(app, host="0.0.0.0", port=8000)