finhdev commited on
Commit
825b375
·
verified ·
1 Parent(s): 233acb0

Update handler.py

Browse files
Files changed (1) hide show
  1. handler.py +16 -12
handler.py CHANGED
@@ -6,32 +6,37 @@ import open_clip
6
  class EndpointHandler:
7
  """
8
  Zero‑shot classifier for MobileCLIP‑B (OpenCLIP).
9
- Request:
10
- {
11
- "image": "<base64‑png/jpeg>",
 
 
12
  "candidate_labels": ["cat", "dog", ...]
13
  }
14
- Response: list[{"label": str, "score": float}]
15
  """
16
 
17
  def __init__(self, path: str = ""):
18
- weights = f"{path}/mobileclip_b.pt" # ckpt in your repo
19
  self.model, _, self.preprocess = open_clip.create_model_and_transforms(
20
  "MobileCLIP-B", pretrained=weights
21
  )
22
  self.model.eval()
23
 
24
  self.tokenizer = open_clip.get_tokenizer("MobileCLIP-B")
25
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
26
  self.model.to(self.device)
27
 
28
  def __call__(self, data):
29
- img_b64 = data["image"]
30
- labels = data.get("candidate_labels", [])
 
 
 
31
  if not labels:
32
  return {"error": "candidate_labels list is empty"}
33
 
34
- # Decode + preprocess image
35
  image = Image.open(io.BytesIO(base64.b64decode(img_b64))).convert("RGB")
36
  img_tensor = self.preprocess(image).unsqueeze(0).to(self.device)
37
 
@@ -44,11 +49,10 @@ class EndpointHandler:
44
  txt_feat = self.model.encode_text(text_tokens)
45
  img_feat = img_feat / img_feat.norm(dim=-1, keepdim=True)
46
  txt_feat = txt_feat / txt_feat.norm(dim=-1, keepdim=True)
47
- probs = (100 * img_feat @ txt_feat.T).softmax(dim=-1)[0].tolist()
48
 
49
- # Return sorted results
50
  return [
51
  {"label": l, "score": float(p)}
52
  for l, p in sorted(zip(labels, probs), key=lambda x: x[1], reverse=True)
53
  ]
54
-
 
6
  class EndpointHandler:
7
  """
8
  Zero‑shot classifier for MobileCLIP‑B (OpenCLIP).
9
+
10
+ Expected client JSON *to the endpoint*:
11
+ {
12
+ "inputs": {
13
+ "image": "<base64 PNG/JPEG>",
14
  "candidate_labels": ["cat", "dog", ...]
15
  }
16
+ }
17
  """
18
 
19
  def __init__(self, path: str = ""):
20
+ weights = f"{path}/mobileclip_b.pt"
21
  self.model, _, self.preprocess = open_clip.create_model_and_transforms(
22
  "MobileCLIP-B", pretrained=weights
23
  )
24
  self.model.eval()
25
 
26
  self.tokenizer = open_clip.get_tokenizer("MobileCLIP-B")
27
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
28
  self.model.to(self.device)
29
 
30
  def __call__(self, data):
31
+ # ── unwrap Hugging Face's `inputs` envelope ───────────
32
+ payload = data.get("inputs", data)
33
+
34
+ img_b64 = payload["image"]
35
+ labels = payload.get("candidate_labels", [])
36
  if not labels:
37
  return {"error": "candidate_labels list is empty"}
38
 
39
+ # Decode & preprocess image
40
  image = Image.open(io.BytesIO(base64.b64decode(img_b64))).convert("RGB")
41
  img_tensor = self.preprocess(image).unsqueeze(0).to(self.device)
42
 
 
49
  txt_feat = self.model.encode_text(text_tokens)
50
  img_feat = img_feat / img_feat.norm(dim=-1, keepdim=True)
51
  txt_feat = txt_feat / txt_feat.norm(dim=-1, keepdim=True)
52
+ probs = (100 * img_feat @ txt_feat.T).softmax(dim=-1)[0].tolist()
53
 
54
+ # Sorted output
55
  return [
56
  {"label": l, "score": float(p)}
57
  for l, p in sorted(zip(labels, probs), key=lambda x: x[1], reverse=True)
58
  ]