hudaakram commited on
Commit
32e2f2a
·
verified ·
1 Parent(s): 5ece618

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +9 -9
server.py CHANGED
@@ -18,7 +18,7 @@ import torchvision
18
  from torchvision import transforms as T
19
  from torchvision.transforms.functional import InterpolationMode
20
 
21
- # ---------------- basic config ----------------
22
  torch.set_num_threads(1)
23
  _INFER_LOCK = threading.Lock()
24
 
@@ -28,13 +28,13 @@ MAX_POINTS = int(os.getenv("MAX_POINTS", "240"))
28
 
29
  FRESHNESS_NAMES = ["Fresh", "Spoiled"]
30
 
31
- # same as your notebook (no normalization)
32
  IMG_TX = T.Compose([
33
  T.Resize((224, 224), interpolation=InterpolationMode.BICUBIC),
34
  T.ToTensor()
35
  ])
36
 
37
- # ---------------- FastAPI ----------------
38
  app = FastAPI(title="Fruit Freshness & Gas Detector")
39
  app.add_middleware(
40
  CORSMiddleware,
@@ -44,12 +44,12 @@ app.add_middleware(
44
  LAST = {"vision": None, "vision_updated": None, "gas": None, "gas_updated": None}
45
  HISTORY = deque(maxlen=MAX_POINTS)
46
 
47
- # ---------------- model (same as notebook) ----------------
48
  class Model(nn.Module):
49
  def __init__(self):
50
  super().__init__()
51
  self.alpha = 0.7
52
- # offline-safe: no download
53
  try:
54
  self.base = torchvision.models.resnet18(weights=None)
55
  except TypeError:
@@ -129,7 +129,7 @@ def predict_pil(pil: Image.Image):
129
  raw = {FRESHNESS_NAMES[i]: float(p) for i, p in enumerate(probs_t)}
130
  return {"label": label, "confidence": round(conf, 1), "raw": {"probs": raw}}
131
 
132
- # ---------------- Vision ----------------
133
  @app.post("/predict")
134
  async def predict(image: UploadFile = File(...)):
135
  try:
@@ -146,7 +146,7 @@ async def predict(image: UploadFile = File(...)):
146
  except Exception as e:
147
  return JSONResponse({"error": "inference_failed", "detail": str(e)}, status_code=500)
148
 
149
- # ---------------- Gas ----------------
150
  class GasReading(BaseModel):
151
  vrl: Optional[float] = None
152
  adc: Optional[int] = None
@@ -234,14 +234,14 @@ def export_csv():
234
  headers={"Content-Disposition": 'attachment; filename="gas_history.csv"'}
235
  )
236
 
237
- # ---------------- Summary / Health ----------------
238
  def _summarize(last: dict) -> dict:
239
  """
240
  Combine the latest vision prediction and gas ppm into a single, simple decision.
241
  - Vision only votes 'rotten' if label says spoiled/rotten AND confidence >= VISION_MIN_CONF.
242
  - Any high gas flag can mark the sample as spoiled.
243
  """
244
- # thresholds (tweak anytime)
245
  VISION_MIN_CONF = 60.0 # %
246
  CO2_HI = 2000.0 # ppm
247
  NH3_HI = 15.0 # ppm
 
18
  from torchvision import transforms as T
19
  from torchvision.transforms.functional import InterpolationMode
20
 
21
+ # basic config
22
  torch.set_num_threads(1)
23
  _INFER_LOCK = threading.Lock()
24
 
 
28
 
29
  FRESHNESS_NAMES = ["Fresh", "Spoiled"]
30
 
31
+ # preprocessing
32
  IMG_TX = T.Compose([
33
  T.Resize((224, 224), interpolation=InterpolationMode.BICUBIC),
34
  T.ToTensor()
35
  ])
36
 
37
+ # FastAPI
38
  app = FastAPI(title="Fruit Freshness & Gas Detector")
39
  app.add_middleware(
40
  CORSMiddleware,
 
44
  LAST = {"vision": None, "vision_updated": None, "gas": None, "gas_updated": None}
45
  HISTORY = deque(maxlen=MAX_POINTS)
46
 
47
+ # model
48
  class Model(nn.Module):
49
  def __init__(self):
50
  super().__init__()
51
  self.alpha = 0.7
52
+
53
  try:
54
  self.base = torchvision.models.resnet18(weights=None)
55
  except TypeError:
 
129
  raw = {FRESHNESS_NAMES[i]: float(p) for i, p in enumerate(probs_t)}
130
  return {"label": label, "confidence": round(conf, 1), "raw": {"probs": raw}}
131
 
132
+ # Vision
133
  @app.post("/predict")
134
  async def predict(image: UploadFile = File(...)):
135
  try:
 
146
  except Exception as e:
147
  return JSONResponse({"error": "inference_failed", "detail": str(e)}, status_code=500)
148
 
149
+ # Gas
150
  class GasReading(BaseModel):
151
  vrl: Optional[float] = None
152
  adc: Optional[int] = None
 
234
  headers={"Content-Disposition": 'attachment; filename="gas_history.csv"'}
235
  )
236
 
237
+ # Summary / Health
238
  def _summarize(last: dict) -> dict:
239
  """
240
  Combine the latest vision prediction and gas ppm into a single, simple decision.
241
  - Vision only votes 'rotten' if label says spoiled/rotten AND confidence >= VISION_MIN_CONF.
242
  - Any high gas flag can mark the sample as spoiled.
243
  """
244
+ # thresholds
245
  VISION_MIN_CONF = 60.0 # %
246
  CO2_HI = 2000.0 # ppm
247
  NH3_HI = 15.0 # ppm