hysts HF Staff commited on
Commit
d61d9b0
·
1 Parent(s): 5d863ef

Add files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* 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
 
 
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
36
+ *.jpg filter=lfs diff=lfs merge=lfs -text
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
README.md CHANGED
@@ -4,6 +4,7 @@ emoji: 🔥
4
  colorFrom: yellow
5
  colorTo: green
6
  sdk: gradio
 
7
  sdk_version: 6.5.1
8
  app_file: app.py
9
  pinned: false
 
4
  colorFrom: yellow
5
  colorTo: green
6
  sdk: gradio
7
+ python_version: 3.12.12
8
  sdk_version: 6.5.1
9
  app_file: app.py
10
  pinned: false
app.py ADDED
@@ -0,0 +1,343 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pathlib import Path
3
+
4
+ import gradio as gr
5
+ import numpy as np
6
+ import spaces
7
+ import torch
8
+ from detection_viewer import DetectionViewer
9
+ from PIL import Image
10
+ from transformers import (
11
+ AutoImageProcessor,
12
+ AutoModelForZeroShotObjectDetection,
13
+ AutoProcessor,
14
+ Mask2FormerForUniversalSegmentation,
15
+ RTDetrForObjectDetection,
16
+ RTDetrImageProcessor,
17
+ VitPoseForPoseEstimation,
18
+ )
19
+
20
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
21
+ USE_SMALL_MODELS = os.environ.get("USE_SMALL_MODELS", "0") == "1"
22
+ ASSETS_DIR = Path(__file__).parent / "assets"
23
+
24
+ # ============================================================
25
+ # RT-DETR (Object Detection)
26
+ # ============================================================
27
+ RTDETR_MODEL_ID = "PekingU/rtdetr_r18vd" if USE_SMALL_MODELS else "PekingU/rtdetr_r101vd"
28
+ rtdetr_processor = RTDetrImageProcessor.from_pretrained(RTDETR_MODEL_ID)
29
+ rtdetr_model = RTDetrForObjectDetection.from_pretrained(RTDETR_MODEL_ID).eval().to(device)
30
+
31
+ # ============================================================
32
+ # Grounding DINO (Zero-Shot Detection)
33
+ # ============================================================
34
+ GDINO_MODEL_ID = "IDEA-Research/grounding-dino-tiny" if USE_SMALL_MODELS else "IDEA-Research/grounding-dino-base"
35
+ gdino_processor = AutoProcessor.from_pretrained(GDINO_MODEL_ID)
36
+ gdino_model = AutoModelForZeroShotObjectDetection.from_pretrained(GDINO_MODEL_ID).eval().to(device)
37
+
38
+ # ============================================================
39
+ # Mask2Former (Instance Segmentation)
40
+ # ============================================================
41
+ M2F_MODEL_ID = (
42
+ "facebook/mask2former-swin-tiny-coco-instance"
43
+ if USE_SMALL_MODELS
44
+ else "facebook/mask2former-swin-large-coco-instance"
45
+ )
46
+ m2f_processor = AutoImageProcessor.from_pretrained(M2F_MODEL_ID)
47
+ m2f_model = Mask2FormerForUniversalSegmentation.from_pretrained(M2F_MODEL_ID).eval().to(device)
48
+
49
+ # ============================================================
50
+ # ViTPose (Pose Estimation)
51
+ # ============================================================
52
+ VITPOSE_DET_MODEL_ID = "PekingU/rtdetr_r18vd" if USE_SMALL_MODELS else "PekingU/rtdetr_r50vd"
53
+ vitpose_det_processor = AutoProcessor.from_pretrained(VITPOSE_DET_MODEL_ID)
54
+ vitpose_det_model = RTDetrForObjectDetection.from_pretrained(VITPOSE_DET_MODEL_ID).eval().to(device)
55
+ PERSON_LABEL_ID = next(k for k, v in vitpose_det_model.config.id2label.items() if v == "person")
56
+
57
+ VITPOSE_MODEL_ID = "usyd-community/vitpose-base-simple" if USE_SMALL_MODELS else "usyd-community/vitpose-plus-large"
58
+ VITPOSE_IS_MOE = not USE_SMALL_MODELS # vitpose-plus models use Mixture-of-Experts heads
59
+ vitpose_processor = AutoProcessor.from_pretrained(VITPOSE_MODEL_ID)
60
+ vitpose_model = VitPoseForPoseEstimation.from_pretrained(VITPOSE_MODEL_ID).eval().to(device)
61
+ SKELETON = vitpose_model.config.edges
62
+
63
+ COCO_KEYPOINT_NAMES = [
64
+ "nose",
65
+ "left_eye",
66
+ "right_eye",
67
+ "left_ear",
68
+ "right_ear",
69
+ "left_shoulder",
70
+ "right_shoulder",
71
+ "left_elbow",
72
+ "right_elbow",
73
+ "left_wrist",
74
+ "right_wrist",
75
+ "left_hip",
76
+ "right_hip",
77
+ "left_knee",
78
+ "right_knee",
79
+ "left_ankle",
80
+ "right_ankle",
81
+ ]
82
+
83
+
84
+ # ============================================================
85
+ # Utilities
86
+ # ============================================================
87
+ def _mask_to_rle(mask: np.ndarray) -> dict:
88
+ """Convert a binary mask to uncompressed RLE (column-major / COCO format)."""
89
+ h, w = mask.shape
90
+ flat = mask.ravel(order="F")
91
+ changes = np.diff(flat)
92
+ change_idx = np.flatnonzero(changes)
93
+ runs = np.diff(np.concatenate([[-1], change_idx, [len(flat) - 1]]))
94
+ counts = runs.tolist()
95
+ if flat[0] == 1:
96
+ counts = [0, *counts]
97
+ return {"counts": counts, "size": [h, w]}
98
+
99
+
100
+ def _mask_to_bbox(mask: np.ndarray) -> dict:
101
+ """Compute bounding box from a binary mask."""
102
+ ys, xs = np.where(mask)
103
+ x_min, x_max = int(xs.min()), int(xs.max())
104
+ y_min, y_max = int(ys.min()), int(ys.max())
105
+ return {"x": x_min, "y": y_min, "width": x_max - x_min + 1, "height": y_max - y_min + 1}
106
+
107
+
108
+ # ============================================================
109
+ # Inference helpers
110
+ # ============================================================
111
+ def _detect_rtdetr(image: Image.Image, _labels: str, threshold: float) -> tuple[Image.Image, list[dict], dict]:
112
+ inputs = rtdetr_processor(images=image, return_tensors="pt").to(device)
113
+ outputs = rtdetr_model(**inputs)
114
+ results = rtdetr_processor.post_process_object_detection(
115
+ outputs,
116
+ target_sizes=torch.tensor([(image.height, image.width)]),
117
+ threshold=threshold,
118
+ )[0]
119
+
120
+ annotations = []
121
+ for score, label_id, box in zip(results["scores"], results["labels"], results["boxes"], strict=True):
122
+ x_min, y_min, x_max, y_max = box.tolist()
123
+ annotations.append(
124
+ {
125
+ "bbox": {"x": x_min, "y": y_min, "width": x_max - x_min, "height": y_max - y_min},
126
+ "score": round(score.item(), 3),
127
+ "label": rtdetr_model.config.id2label[label_id.item()],
128
+ }
129
+ )
130
+
131
+ return image, annotations, {"score_threshold": (threshold, 1.0)}
132
+
133
+
134
+ def _detect_gdino(image: Image.Image, labels: str, threshold: float) -> tuple[Image.Image, list[dict], dict]:
135
+ text = labels.strip().rstrip(".")
136
+ candidate_labels = [part.strip() for part in text.split(",") if part.strip()]
137
+ text_prompt = ". ".join(candidate_labels) + "."
138
+
139
+ inputs = gdino_processor(images=image, text=text_prompt, return_tensors="pt").to(device)
140
+ outputs = gdino_model(**inputs)
141
+ results = gdino_processor.post_process_grounded_object_detection(
142
+ outputs,
143
+ input_ids=inputs["input_ids"],
144
+ target_sizes=[(image.height, image.width)],
145
+ threshold=threshold,
146
+ text_threshold=threshold,
147
+ )[0]
148
+
149
+ annotations = []
150
+ for score, label, box in zip(results["scores"], results["labels"], results["boxes"], strict=True):
151
+ x_min, y_min, x_max, y_max = box.tolist()
152
+ annotations.append(
153
+ {
154
+ "bbox": {"x": x_min, "y": y_min, "width": x_max - x_min, "height": y_max - y_min},
155
+ "score": round(float(score), 3),
156
+ "label": label,
157
+ }
158
+ )
159
+
160
+ return image, annotations, {"score_threshold": (threshold, 1.0)}
161
+
162
+
163
+ def _detect_m2f(image: Image.Image, _labels: str, threshold: float) -> tuple[Image.Image, list[dict], dict]:
164
+ inputs = m2f_processor(images=image, return_tensors="pt").to(device)
165
+ outputs = m2f_model(**inputs)
166
+ results = m2f_processor.post_process_instance_segmentation(
167
+ outputs,
168
+ target_sizes=[(image.height, image.width)],
169
+ threshold=threshold,
170
+ )[0]
171
+
172
+ segmentation = results["segmentation"].cpu().numpy().astype(np.uint8)
173
+ annotations = []
174
+ for segment in results["segments_info"]:
175
+ binary_mask = (segmentation == segment["id"]).astype(np.uint8)
176
+ if binary_mask.sum() == 0:
177
+ continue
178
+ annotations.append(
179
+ {
180
+ "bbox": _mask_to_bbox(binary_mask),
181
+ "mask": _mask_to_rle(binary_mask),
182
+ "score": round(float(segment["score"]), 3),
183
+ "label": m2f_model.config.id2label[int(segment["label_id"])],
184
+ }
185
+ )
186
+
187
+ return image, annotations, {"score_threshold": (threshold, 1.0)}
188
+
189
+
190
+ def _detect_vitpose(
191
+ image: Image.Image, _labels: str, threshold: float
192
+ ) -> tuple[Image.Image, list[dict], dict] | tuple[Image.Image, list]:
193
+ # Step 1: Detect persons with RT-DETR
194
+ det_inputs = vitpose_det_processor(images=image, return_tensors="pt").to(device)
195
+ det_outputs = vitpose_det_model(**det_inputs)
196
+ det_results = vitpose_det_processor.post_process_object_detection(
197
+ det_outputs,
198
+ target_sizes=torch.tensor([(image.height, image.width)]),
199
+ threshold=threshold,
200
+ )[0]
201
+
202
+ person_mask = det_results["labels"] == PERSON_LABEL_ID
203
+ person_boxes_voc = det_results["boxes"][person_mask].cpu().numpy()
204
+ person_scores = det_results["scores"][person_mask].cpu().numpy()
205
+
206
+ if len(person_boxes_voc) == 0:
207
+ return image, []
208
+
209
+ # Convert VOC (x1, y1, x2, y2) to COCO (x, y, w, h)
210
+ person_boxes_coco = person_boxes_voc.copy()
211
+ person_boxes_coco[:, 2] = person_boxes_voc[:, 2] - person_boxes_voc[:, 0]
212
+ person_boxes_coco[:, 3] = person_boxes_voc[:, 3] - person_boxes_voc[:, 1]
213
+
214
+ # Step 2: Estimate keypoints with ViTPose
215
+ pose_inputs = vitpose_processor(image, boxes=[person_boxes_coco], return_tensors="pt").to(device)
216
+ forward_kwargs = dict(pose_inputs)
217
+ if VITPOSE_IS_MOE:
218
+ # COCO dataset index = 0 for vitpose-plus MoE heads
219
+ forward_kwargs["dataset_index"] = torch.zeros(pose_inputs["pixel_values"].shape[0], dtype=torch.long, device=device)
220
+ pose_outputs = vitpose_model(**forward_kwargs)
221
+ pose_results = vitpose_processor.post_process_pose_estimation(pose_outputs, boxes=[person_boxes_coco])
222
+
223
+ # Step 3: Build annotations
224
+ annotations = []
225
+ for i, pose_result in enumerate(pose_results[0]):
226
+ keypoints_xy = pose_result["keypoints"].cpu().numpy()
227
+ keypoints_scores = pose_result["scores"].cpu().numpy()
228
+
229
+ x1, y1, x2, y2 = person_boxes_voc[i]
230
+ keypoints = [
231
+ {
232
+ "x": float(keypoints_xy[j][0]),
233
+ "y": float(keypoints_xy[j][1]),
234
+ "name": COCO_KEYPOINT_NAMES[j],
235
+ "confidence": round(float(keypoints_scores[j]), 3),
236
+ }
237
+ for j in range(len(keypoints_xy))
238
+ ]
239
+
240
+ annotations.append(
241
+ {
242
+ "bbox": {"x": float(x1), "y": float(y1), "width": float(x2 - x1), "height": float(y2 - y1)},
243
+ "score": round(float(person_scores[i]), 3),
244
+ "label": "person",
245
+ "keypoints": keypoints,
246
+ "connections": SKELETON,
247
+ }
248
+ )
249
+
250
+ return image, annotations, {"score_threshold": (threshold, 1.0)}
251
+
252
+
253
+ # ============================================================
254
+ # Dispatcher
255
+ # ============================================================
256
+ TASK_OBJECT_DETECTION = "Object Detection"
257
+ TASK_ZERO_SHOT_DETECTION = "Zero-Shot Detection"
258
+ TASK_INSTANCE_SEGMENTATION = "Instance Segmentation"
259
+ TASK_POSE_ESTIMATION = "Pose Estimation"
260
+
261
+ TASK_CHOICES = [
262
+ TASK_OBJECT_DETECTION,
263
+ TASK_ZERO_SHOT_DETECTION,
264
+ TASK_INSTANCE_SEGMENTATION,
265
+ TASK_POSE_ESTIMATION,
266
+ ]
267
+
268
+
269
+ _TASK_DISPATCH = {
270
+ TASK_OBJECT_DETECTION: _detect_rtdetr,
271
+ TASK_ZERO_SHOT_DETECTION: _detect_gdino,
272
+ TASK_INSTANCE_SEGMENTATION: _detect_m2f,
273
+ TASK_POSE_ESTIMATION: _detect_vitpose,
274
+ }
275
+
276
+
277
+ @spaces.GPU
278
+ @torch.inference_mode()
279
+ def run_detection(
280
+ image: Image.Image, task: str, labels: str, threshold: float
281
+ ) -> tuple[Image.Image, list[dict], dict] | None:
282
+ if image is None:
283
+ return None
284
+ if task == TASK_ZERO_SHOT_DETECTION and not labels.strip():
285
+ return None
286
+ return _TASK_DISPATCH[task](image, labels, threshold) # type: ignore[return-value]
287
+
288
+
289
+ # ============================================================
290
+ # UI
291
+ # ============================================================
292
+ with gr.Blocks(title="Detection Viewer Demo") as demo:
293
+ gr.Markdown("# Detection Viewer Demo")
294
+ gr.Markdown(
295
+ "Showcase of the **Detection Viewer** Gradio custom component "
296
+ "— visualizing bounding boxes, segmentation masks, keypoints, and skeleton connections."
297
+ )
298
+
299
+ with gr.Row():
300
+ with gr.Column():
301
+ input_image = gr.Image(label="Input Image", type="pil")
302
+ task_selector = gr.Radio(
303
+ choices=TASK_CHOICES,
304
+ value=TASK_OBJECT_DETECTION,
305
+ label="Task",
306
+ )
307
+ labels_input = gr.Textbox(
308
+ label="Labels (comma-separated)",
309
+ placeholder="person, dog, car, chair",
310
+ value="person, dog, cat, car",
311
+ visible=False,
312
+ )
313
+ threshold = gr.Slider(label="Confidence Threshold", minimum=0.0, maximum=1.0, step=0.05, value=0.3)
314
+ run_btn = gr.Button("Detect", variant="primary")
315
+ with gr.Column():
316
+ viewer = DetectionViewer(label="Detection Results", keypoint_threshold=0.3)
317
+
318
+ task_selector.change(
319
+ fn=lambda task: gr.update(visible=task == TASK_ZERO_SHOT_DETECTION),
320
+ inputs=task_selector,
321
+ outputs=labels_input,
322
+ )
323
+
324
+ run_btn.click(
325
+ fn=run_detection,
326
+ inputs=[input_image, task_selector, labels_input, threshold],
327
+ outputs=viewer,
328
+ )
329
+
330
+ gr.Examples(
331
+ examples=[
332
+ [str(ASSETS_DIR / "kitchen.jpg"), TASK_OBJECT_DETECTION, "", 0.3],
333
+ [str(ASSETS_DIR / "office.jpg"), TASK_ZERO_SHOT_DETECTION, "person, laptop, notebook, pencil, glasses, watch, potted plant, bookshelf, window", 0.3],
334
+ [str(ASSETS_DIR / "traffic.jpg"), TASK_INSTANCE_SEGMENTATION, "", 0.3],
335
+ [str(ASSETS_DIR / "people.jpg"), TASK_POSE_ESTIMATION, "", 0.3],
336
+ ],
337
+ inputs=[input_image, task_selector, labels_input, threshold],
338
+ fn=run_detection,
339
+ outputs=viewer,
340
+ )
341
+
342
+ if __name__ == "__main__":
343
+ demo.launch()
assets/kitchen.jpg ADDED

Git LFS Details

  • SHA256: 221f1b0b53de86f3a88fd2ae490cde6fb5467e2bb80478c96c7279bf98a3a39e
  • Pointer size: 132 Bytes
  • Size of remote file: 1.63 MB
assets/office.jpg ADDED

Git LFS Details

  • SHA256: 5e4b5339cb682faee2430524008d9247c39e7db9857436687c97395d013cdc46
  • Pointer size: 131 Bytes
  • Size of remote file: 150 kB
assets/people.jpg ADDED

Git LFS Details

  • SHA256: 0500121b9044cb1d4c7913e48ebe5e2374848d57d6a2905f3b7c9469f959f2fe
  • Pointer size: 131 Bytes
  • Size of remote file: 648 kB
assets/traffic.jpg ADDED

Git LFS Details

  • SHA256: 2de03892c6f6624a45fc67a283aeb33d4534fecc76e51d83e43fe40b58ce2351
  • Pointer size: 131 Bytes
  • Size of remote file: 670 kB
pyproject.toml ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "detection-viewer-demo"
3
+ version = "0.1.0"
4
+ description = "Combined demo Space for the Detection Viewer component"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "detection-viewer",
9
+ "gradio>=6.5.1",
10
+ "scipy>=1.17.0",
11
+ "spaces>=0.34.0",
12
+ "torch==2.9.1",
13
+ "transformers>=5.1.0",
14
+ ]
15
+
16
+ [dependency-groups]
17
+ dev = [
18
+ "ruff>=0.15.1",
19
+ ]
20
+ hf-spaces = [
21
+ "datasets>=4.5.0",
22
+ ]
23
+
24
+ [tool.ruff]
25
+ line-length = 119
26
+ exclude = ["*.pyi"]
27
+
28
+ [tool.ruff.lint]
29
+ select = ["ALL"]
30
+ ignore = [
31
+ "COM812", # missing-trailing-comma
32
+ "D203", # one-blank-line-before-class
33
+ "D213", # multi-line-summary-second-line
34
+ "E501", # line-too-long
35
+ "SIM117", # multiple-with-statements
36
+ #
37
+ "D100", # undocumented-public-module
38
+ "D101", # undocumented-public-class
39
+ "D102", # undocumented-public-method
40
+ "D103", # undocumented-public-function
41
+ "D104", # undocumented-public-package
42
+ "D105", # undocumented-magic-method
43
+ "D107", # undocumented-public-init
44
+ "EM101", # raw-string-in-exception
45
+ "FBT001", # boolean-type-hint-positional-argument
46
+ "FBT002", # boolean-default-value-positional-argument
47
+ "ISC001", # single-line-implicit-string-concatenation
48
+ "PGH003", # blanket-type-ignore
49
+ "PLR0913", # too-many-arguments
50
+ "PLR0915", # too-many-statements
51
+ "TRY003", # raise-vanilla-args
52
+ ]
53
+ unfixable = [
54
+ "F401", # unused-import
55
+ ]
56
+
57
+ [tool.ruff.lint.pydocstyle]
58
+ convention = "google"
59
+
60
+ [tool.ruff.lint.per-file-ignores]
61
+ "app.py" = ["INP001"]
62
+
63
+ [tool.ruff.format]
64
+ docstring-code-format = true
65
+
66
+ [tool.uv.sources]
67
+ detection-viewer = { url = "https://huggingface.co/spaces/hysts-gradio-custom-html/detection-viewer/resolve/main/dist/detection_viewer-0.1.0-py3-none-any.whl" }
requirements.txt ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv export --format requirements.txt --no-hashes --no-emit-package typer-slim -o requirements.txt
3
+ aiofiles==24.1.0
4
+ # via gradio
5
+ annotated-doc==0.0.4
6
+ # via
7
+ # fastapi
8
+ # typer
9
+ annotated-types==0.7.0
10
+ # via pydantic
11
+ anyio==4.12.1
12
+ # via
13
+ # gradio
14
+ # httpx
15
+ # starlette
16
+ audioop-lts==0.2.2 ; python_full_version >= '3.13'
17
+ # via gradio
18
+ brotli==1.2.0
19
+ # via gradio
20
+ certifi==2026.1.4
21
+ # via
22
+ # httpcore
23
+ # httpx
24
+ # requests
25
+ charset-normalizer==3.4.4
26
+ # via requests
27
+ click==8.3.1
28
+ # via
29
+ # typer
30
+ # uvicorn
31
+ colorama==0.4.6 ; sys_platform == 'win32'
32
+ # via
33
+ # click
34
+ # tqdm
35
+ detection-viewer @ https://huggingface.co/spaces/hysts-gradio-custom-html/detection-viewer/resolve/main/dist/detection_viewer-0.1.0-py3-none-any.whl
36
+ # via detection-viewer-demo
37
+ fastapi==0.129.0
38
+ # via gradio
39
+ ffmpy==1.0.0
40
+ # via gradio
41
+ filelock==3.24.2
42
+ # via
43
+ # huggingface-hub
44
+ # torch
45
+ fsspec==2025.10.0
46
+ # via
47
+ # gradio-client
48
+ # huggingface-hub
49
+ # torch
50
+ gradio==6.5.1
51
+ # via
52
+ # detection-viewer
53
+ # detection-viewer-demo
54
+ # spaces
55
+ gradio-client==2.0.3
56
+ # via gradio
57
+ groovy==0.1.2
58
+ # via gradio
59
+ h11==0.16.0
60
+ # via
61
+ # httpcore
62
+ # uvicorn
63
+ hf-xet==1.2.0 ; platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
64
+ # via huggingface-hub
65
+ httpcore==1.0.9
66
+ # via httpx
67
+ httpx==0.28.1
68
+ # via
69
+ # gradio
70
+ # gradio-client
71
+ # huggingface-hub
72
+ # safehttpx
73
+ # spaces
74
+ huggingface-hub==1.4.1
75
+ # via
76
+ # gradio
77
+ # gradio-client
78
+ # tokenizers
79
+ # transformers
80
+ idna==3.11
81
+ # via
82
+ # anyio
83
+ # httpx
84
+ # requests
85
+ jinja2==3.1.6
86
+ # via
87
+ # gradio
88
+ # torch
89
+ markdown-it-py==4.0.0
90
+ # via rich
91
+ markupsafe==3.0.3
92
+ # via
93
+ # gradio
94
+ # jinja2
95
+ mdurl==0.1.2
96
+ # via markdown-it-py
97
+ mpmath==1.3.0
98
+ # via sympy
99
+ networkx==3.6.1
100
+ # via torch
101
+ numpy==2.4.2
102
+ # via
103
+ # gradio
104
+ # pandas
105
+ # scipy
106
+ # transformers
107
+ nvidia-cublas-cu12==12.8.4.1 ; platform_machine == 'x86_64' and sys_platform == 'linux'
108
+ # via
109
+ # nvidia-cudnn-cu12
110
+ # nvidia-cusolver-cu12
111
+ # torch
112
+ nvidia-cuda-cupti-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
113
+ # via torch
114
+ nvidia-cuda-nvrtc-cu12==12.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux'
115
+ # via torch
116
+ nvidia-cuda-runtime-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
117
+ # via torch
118
+ nvidia-cudnn-cu12==9.10.2.21 ; platform_machine == 'x86_64' and sys_platform == 'linux'
119
+ # via torch
120
+ nvidia-cufft-cu12==11.3.3.83 ; platform_machine == 'x86_64' and sys_platform == 'linux'
121
+ # via torch
122
+ nvidia-cufile-cu12==1.13.1.3 ; platform_machine == 'x86_64' and sys_platform == 'linux'
123
+ # via torch
124
+ nvidia-curand-cu12==10.3.9.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
125
+ # via torch
126
+ nvidia-cusolver-cu12==11.7.3.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
127
+ # via torch
128
+ nvidia-cusparse-cu12==12.5.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux'
129
+ # via
130
+ # nvidia-cusolver-cu12
131
+ # torch
132
+ nvidia-cusparselt-cu12==0.7.1 ; platform_machine == 'x86_64' and sys_platform == 'linux'
133
+ # via torch
134
+ nvidia-nccl-cu12==2.27.5 ; platform_machine == 'x86_64' and sys_platform == 'linux'
135
+ # via torch
136
+ nvidia-nvjitlink-cu12==12.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux'
137
+ # via
138
+ # nvidia-cufft-cu12
139
+ # nvidia-cusolver-cu12
140
+ # nvidia-cusparse-cu12
141
+ # torch
142
+ nvidia-nvshmem-cu12==3.3.20 ; platform_machine == 'x86_64' and sys_platform == 'linux'
143
+ # via torch
144
+ nvidia-nvtx-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux'
145
+ # via torch
146
+ orjson==3.11.7
147
+ # via gradio
148
+ packaging==26.0
149
+ # via
150
+ # gradio
151
+ # gradio-client
152
+ # huggingface-hub
153
+ # spaces
154
+ # transformers
155
+ pandas==3.0.0
156
+ # via gradio
157
+ pillow==12.1.1
158
+ # via gradio
159
+ psutil==5.9.8
160
+ # via spaces
161
+ pydantic==2.12.5
162
+ # via
163
+ # fastapi
164
+ # gradio
165
+ # spaces
166
+ pydantic-core==2.41.5
167
+ # via pydantic
168
+ pydub==0.25.1
169
+ # via gradio
170
+ pygments==2.19.2
171
+ # via rich
172
+ python-dateutil==2.9.0.post0
173
+ # via pandas
174
+ python-multipart==0.0.22
175
+ # via gradio
176
+ pytz==2025.2
177
+ # via gradio
178
+ pyyaml==6.0.3
179
+ # via
180
+ # gradio
181
+ # huggingface-hub
182
+ # transformers
183
+ regex==2026.1.15
184
+ # via transformers
185
+ requests==2.32.5
186
+ # via spaces
187
+ rich==14.3.2
188
+ # via typer
189
+ ruff==0.15.1
190
+ safehttpx==0.1.7
191
+ # via gradio
192
+ safetensors==0.7.0
193
+ # via transformers
194
+ scipy==1.17.0
195
+ # via detection-viewer-demo
196
+ semantic-version==2.10.0
197
+ # via gradio
198
+ setuptools==82.0.0
199
+ # via torch
200
+ shellingham==1.5.4
201
+ # via
202
+ # huggingface-hub
203
+ # typer
204
+ six==1.17.0
205
+ # via python-dateutil
206
+ spaces==0.47.0
207
+ # via detection-viewer-demo
208
+ starlette==0.52.1
209
+ # via
210
+ # fastapi
211
+ # gradio
212
+ sympy==1.14.0
213
+ # via torch
214
+ tokenizers==0.22.2
215
+ # via transformers
216
+ tomlkit==0.13.3
217
+ # via gradio
218
+ torch==2.9.1
219
+ # via detection-viewer-demo
220
+ tqdm==4.67.3
221
+ # via
222
+ # huggingface-hub
223
+ # transformers
224
+ transformers==5.2.0
225
+ # via detection-viewer-demo
226
+ triton==3.5.1 ; platform_machine == 'x86_64' and sys_platform == 'linux'
227
+ # via torch
228
+ typer==0.24.0
229
+ # via
230
+ # gradio
231
+ # typer-slim
232
+ typing-extensions==4.15.0
233
+ # via
234
+ # anyio
235
+ # fastapi
236
+ # gradio
237
+ # gradio-client
238
+ # huggingface-hub
239
+ # pydantic
240
+ # pydantic-core
241
+ # spaces
242
+ # starlette
243
+ # torch
244
+ # typing-inspection
245
+ typing-inspection==0.4.2
246
+ # via
247
+ # fastapi
248
+ # pydantic
249
+ tzdata==2025.3 ; sys_platform == 'emscripten' or sys_platform == 'win32'
250
+ # via pandas
251
+ urllib3==2.6.3
252
+ # via requests
253
+ uvicorn==0.41.0
254
+ # via gradio
uv.lock ADDED
The diff for this file is too large to render. See raw diff