Upload folder using huggingface_hub
Browse files- .gitattributes +2 -35
- handler.py +109 -0
- requirements.txt +4 -0
- yolov8n.pt +3 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,2 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
Yolo_Model/yolov8n.pt filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
yolov8n.pt filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handler.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# handler.py
|
| 2 |
+
from typing import Dict, Any, List
|
| 3 |
+
import base64, io, os, json
|
| 4 |
+
from PIL import Image
|
| 5 |
+
import numpy as np
|
| 6 |
+
|
| 7 |
+
# Ultralytics YOLO
|
| 8 |
+
from ultralytics import YOLO
|
| 9 |
+
|
| 10 |
+
# ---- Utilities ----
|
| 11 |
+
def load_image_from_payload(payload: Dict[str, Any]) -> Image.Image:
|
| 12 |
+
"""
|
| 13 |
+
Supports:
|
| 14 |
+
- base64 image: payload["inputs"] = "data:image/...;base64,...." or raw base64 string
|
| 15 |
+
- image URL: payload["image_url"] = "https://..."
|
| 16 |
+
"""
|
| 17 |
+
if "inputs" in payload and isinstance(payload["inputs"], str):
|
| 18 |
+
s = payload["inputs"]
|
| 19 |
+
# handle optional data URL prefix
|
| 20 |
+
if s.startswith("data:image"):
|
| 21 |
+
s = s.split(",", 1)[1]
|
| 22 |
+
img_bytes = base64.b64decode(s)
|
| 23 |
+
return Image.open(io.BytesIO(img_bytes)).convert("RGB")
|
| 24 |
+
|
| 25 |
+
if "image_url" in payload:
|
| 26 |
+
# Not recommended in restricted egress; but works if endpoint has outbound internet
|
| 27 |
+
import requests
|
| 28 |
+
r = requests.get(payload["image_url"], timeout=10)
|
| 29 |
+
r.raise_for_status()
|
| 30 |
+
return Image.open(io.BytesIO(r.content)).convert("RGB")
|
| 31 |
+
|
| 32 |
+
raise ValueError("No image provided. Use 'inputs' (base64) or 'image_url'.")
|
| 33 |
+
|
| 34 |
+
def yolo_to_coco(result) -> List[Dict[str, Any]]:
|
| 35 |
+
"""
|
| 36 |
+
Convert Ultralytics result to COCO-ish detections:
|
| 37 |
+
[{"bbox":[x,y,w,h], "score":float, "category_id":int, "category_name":str}]
|
| 38 |
+
"""
|
| 39 |
+
detections = []
|
| 40 |
+
names = result.names # id->name
|
| 41 |
+
for b in result.boxes:
|
| 42 |
+
xywh = b.xywh.cpu().numpy().tolist()[0] # [x_center,y_center,w,h]
|
| 43 |
+
# convert to top-left x,y,w,h
|
| 44 |
+
x, y, w, h = xywh
|
| 45 |
+
x0 = x - w/2
|
| 46 |
+
y0 = y - h/2
|
| 47 |
+
conf = float(b.conf.cpu().item())
|
| 48 |
+
cls_id = int(b.cls.cpu().item())
|
| 49 |
+
detections.append({
|
| 50 |
+
"bbox": [float(x0), float(y0), float(w), float(h)],
|
| 51 |
+
"score": conf,
|
| 52 |
+
"category_id": cls_id,
|
| 53 |
+
"category_name": names.get(cls_id, str(cls_id)),
|
| 54 |
+
})
|
| 55 |
+
return detections
|
| 56 |
+
|
| 57 |
+
class EndpointHandler:
|
| 58 |
+
def __init__(self, path: str = ""):
|
| 59 |
+
"""
|
| 60 |
+
`path` points to the repo files checked out on the endpoint.
|
| 61 |
+
If yolov8n.pt is present in the repo, we load it directly.
|
| 62 |
+
Otherwise we fallback to downloading 'yolov8n.pt'.
|
| 63 |
+
"""
|
| 64 |
+
weights_path = os.path.join(path, "yolov8n.pt")
|
| 65 |
+
if not os.path.exists(weights_path):
|
| 66 |
+
# Fallback: auto-download from Ultralytics/HF cache
|
| 67 |
+
weights_path = "yolov8n.pt"
|
| 68 |
+
self.model = YOLO(weights_path) # loads on first use
|
| 69 |
+
|
| 70 |
+
# Optional: warmup for faster first token (small dummy inference)
|
| 71 |
+
# Create a tiny blank image to compile the model
|
| 72 |
+
dummy = Image.new("RGB", (320, 320), (128, 128, 128))
|
| 73 |
+
_ = self.model.predict(dummy, imgsz=320, conf=0.25, verbose=False)
|
| 74 |
+
|
| 75 |
+
def __call__(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
| 76 |
+
"""
|
| 77 |
+
Expected payload:
|
| 78 |
+
{
|
| 79 |
+
"inputs": "<base64-image>" # OR "image_url": "https://..."
|
| 80 |
+
"imgsz": (optional int, default 640)
|
| 81 |
+
"conf": (optional float, default 0.25)
|
| 82 |
+
"iou": (optional float, default 0.45)
|
| 83 |
+
"max_det":(optional int, default 300)
|
| 84 |
+
}
|
| 85 |
+
Returns:
|
| 86 |
+
{
|
| 87 |
+
"detections": [ {bbox, score, category_id, category_name}, ... ],
|
| 88 |
+
"image_shape": [h,w],
|
| 89 |
+
"model": "yolov8n"
|
| 90 |
+
}
|
| 91 |
+
"""
|
| 92 |
+
imgsz = int(data.get("imgsz", 640))
|
| 93 |
+
conf = float(data.get("conf", 0.25))
|
| 94 |
+
iou = float(data.get("iou", 0.45))
|
| 95 |
+
max_det = int(data.get("max_det", 300))
|
| 96 |
+
|
| 97 |
+
img = load_image_from_payload(data)
|
| 98 |
+
w, h = img.size
|
| 99 |
+
|
| 100 |
+
results = self.model.predict(
|
| 101 |
+
img, imgsz=imgsz, conf=conf, iou=iou, max_det=max_det, verbose=False
|
| 102 |
+
)
|
| 103 |
+
detections = yolo_to_coco(results[0])
|
| 104 |
+
|
| 105 |
+
return {
|
| 106 |
+
"detections": detections,
|
| 107 |
+
"image_shape": [h, w],
|
| 108 |
+
"model": "yolov8n"
|
| 109 |
+
}
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ultralytics>=8.2.0
|
| 2 |
+
opencv-python-headless>=4.9.0
|
| 3 |
+
pillow>=10.0.0
|
| 4 |
+
numpy>=1.24.0
|
yolov8n.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f59b3d833e2ff32e194b5bb8e08d211dc7c5bdf144b90d2c8412c47ccfc83b36
|
| 3 |
+
size 6549796
|