File size: 2,611 Bytes
3483eb1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
"""Scaffold miner for manak0/Detect-fire (specialized public package).

Required chute contract:
  - class named Miner
  - method predict_batch(batch_images, offset, n_keypoints) -> list[TVFrameResult]
  - this file lives at the root of the HF model repo

This scaffold is intentionally element-specialized (object labels,
element metadata). Weights are placeholder; distill/train fills real
ONNX/PT artifacts under the 30 MB hard cap.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

from pydantic import BaseModel


class BoundingBox(BaseModel):
    x1: int
    y1: int
    x2: int
    y2: int
    cls_id: int
    conf: float


class Polygon(BaseModel):
    cls_id: int
    conf: float
    points: list[tuple[int, int]]


class TVFrameResult(BaseModel):
    frame_id: int
    boxes: list[BoundingBox] | None = None
    polygons: list[Polygon] | None = None
    keypoints: list[tuple[int, int]] | None = None


ELEMENT_ID = 'manak0/Detect-fire'
SHORT_NAME = 'fire'
OBJECT_LABELS = (
    'fire',
    'smoke',
    'flame',
    'ember',
    'torch',
)


class Miner:
    """Specialist detector package for manak0/Detect-fire."""

    def __init__(self, path_hf_repo: Path) -> None:
        self.path_hf_repo = Path(path_hf_repo)
        self.element_id = ELEMENT_ID
        self.object_labels = list(OBJECT_LABELS)
        self._weights = self._discover_weights()

    def _discover_weights(self) -> Path | None:
        for name in ("model.onnx", "weights.onnx", "model.pt", "weights.pt"):
            cand = self.path_hf_repo / name
            if cand.is_file():
                return cand
        return None

    def __repr__(self) -> str:
        wname = self._weights.name if self._weights else None
        return (
            "Miner(element=%r, labels=%d, weights=%s)"
            % (self.element_id, len(self.object_labels), wname)
        )

    def predict_batch(
        self,
        batch_images: list[Any],
        offset: int,
        n_keypoints: int,
    ) -> list[TVFrameResult]:
        """Return frame results. Scaffold emits empty boxes (schema-valid).

        Live distillation replaces this with a tiny specialist detector.
        """
        results: list[TVFrameResult] = []
        kps = [(0, 0) for _ in range(max(0, int(n_keypoints)))]
        for i in range(len(batch_images)):
            results.append(
                TVFrameResult(
                    frame_id=offset + i,
                    boxes=[],
                    polygons=[],
                    keypoints=list(kps),
                )
            )
        return results