camera-ui-ml 1.2.2__tar.gz → 1.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/PKG-INFO +1 -1
  2. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/detectors/base.py +2 -0
  3. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/detectors/clip.py +8 -19
  4. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/model_manager.py +11 -9
  5. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml.egg-info/PKG-INFO +1 -1
  6. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/pyproject.toml +1 -1
  7. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/LICENSE.md +0 -0
  8. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/README.md +0 -0
  9. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/__init__.py +0 -0
  10. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/backend.py +0 -0
  11. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/detectors/__init__.py +0 -0
  12. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/detectors/box.py +0 -0
  13. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/detectors/embedder.py +0 -0
  14. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/detectors/ocr.py +0 -0
  15. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/geometry.py +0 -0
  16. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/parsing.py +0 -0
  17. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/pipeline.py +0 -0
  18. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/pipelines.py +0 -0
  19. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/preprocess.py +0 -0
  20. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml/py.typed +0 -0
  21. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml.egg-info/SOURCES.txt +0 -0
  22. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml.egg-info/dependency_links.txt +0 -0
  23. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml.egg-info/requires.txt +0 -0
  24. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/camera_ui_ml.egg-info/top_level.txt +0 -0
  25. {camera_ui_ml-1.2.2 → camera_ui_ml-1.2.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camera-ui-ml
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: Shared ML inference framework for camera.ui detection plugins (onnx, openvino, coreml, ncnn)
5
5
  Author-email: seydx <hi@seydx.dev>
6
6
  Maintainer-email: seydx <hi@seydx.dev>
@@ -38,6 +38,7 @@ class BaseDetector:
38
38
 
39
39
  async def _do_initialize(self, model_name: str) -> None:
40
40
  try:
41
+ self.logger.log(f"Loading {self.name}: {model_name}...")
41
42
  self.backend = await self.manager.ensure_backend(model_name)
42
43
  if self.closed:
43
44
  return
@@ -46,6 +47,7 @@ class BaseDetector:
46
47
  self.logger.success(f"Loaded {self.name}: {model_name}")
47
48
  except Exception as error:
48
49
  self.logger.error(f"Failed to initialize {self.name}: {error}")
50
+ raise
49
51
  finally:
50
52
  self._init_task = None
51
53
 
@@ -38,9 +38,7 @@ class ClipEncoder:
38
38
  if self.initialized:
39
39
  return
40
40
  if self._init_task is None:
41
- self._init_task = asyncio.create_task(
42
- self._do_initialize(vision_model, text_model)
43
- )
41
+ self._init_task = asyncio.create_task(self._do_initialize(vision_model, text_model))
44
42
  await self._init_task
45
43
 
46
44
  async def close(self) -> None:
@@ -83,10 +81,7 @@ class ClipEncoder:
83
81
  async def embed_frames(self, frames: list[VideoFrameData]) -> list[list[float]]:
84
82
  if not self._ready():
85
83
  return [[] for _ in frames]
86
- return [
87
- await self.embed_frame(frame["width"], frame["height"], frame["data"])
88
- for frame in frames
89
- ]
84
+ return [await self.embed_frame(frame["width"], frame["height"], frame["data"]) for frame in frames]
90
85
 
91
86
  def _ready(self) -> bool:
92
87
  return (
@@ -98,35 +93,29 @@ class ClipEncoder:
98
93
 
99
94
  async def _do_initialize(self, vision_model: str, text_model: str) -> None:
100
95
  try:
96
+ self.logger.log(f"Loading CLIP: {vision_model} + {text_model}...")
101
97
  self.vision = await self.manager.ensure_backend(vision_model)
102
98
  self.text = await self.manager.ensure_backend(text_model)
103
99
  processor_dir = await self.manager.ensure_clip_processor()
104
100
  if processor_dir is None:
105
- raise RuntimeError(
106
- "CLIP processor files are not bundled (clip_processor_files is empty)"
107
- )
108
- self.processor = await asyncio.to_thread(
109
- CLIPProcessor.from_pretrained, processor_dir
110
- )
101
+ raise RuntimeError("CLIP processor files are not bundled (clip_processor_files is empty)")
102
+ self.processor = await asyncio.to_thread(CLIPProcessor.from_pretrained, processor_dir)
111
103
  if self.closed:
112
104
  return
113
105
  self.initialized = True
114
106
  self.logger.success(f"Loaded CLIP: {vision_model} + {text_model}")
115
107
  except Exception as error:
116
108
  self.logger.error(f"Failed to initialize CLIP encoder: {error}")
109
+ raise
117
110
  finally:
118
111
  self._init_task = None
119
112
 
120
113
  def _vision_input(self, pil: Any) -> NDArray:
121
- inputs = self.processor(
122
- images=pil, return_tensors="np", padding="max_length", truncation=True
123
- )
114
+ inputs = self.processor(images=pil, return_tensors="np", padding="max_length", truncation=True)
124
115
  return np.asarray(inputs["pixel_values"], dtype=np.float32)
125
116
 
126
117
  def _text_input(self, text: str) -> tuple[NDArray, NDArray]:
127
- inputs = self.processor(
128
- text=text, return_tensors="np", padding="max_length", truncation=True
129
- )
118
+ inputs = self.processor(text=text, return_tensors="np", padding="max_length", truncation=True)
130
119
  return (
131
120
  np.asarray(inputs["input_ids"], dtype=np.int64),
132
121
  np.asarray(inputs["attention_mask"], dtype=np.int64),
@@ -27,13 +27,19 @@ class BaseModelManager(ABC):
27
27
  self.logger = logger
28
28
  self.model_path = os.path.join(storage_path, "models", version)
29
29
  self._load_tasks: dict[str, asyncio.Task[InferenceBackend]] = {}
30
+ self._build_lock = asyncio.Lock()
30
31
 
31
32
  async def ensure_backend(self, model_name: str) -> InferenceBackend:
32
33
  task = self._load_tasks.get(model_name)
33
34
  if task is None:
34
35
  task = asyncio.create_task(self._load(model_name))
35
36
  self._load_tasks[model_name] = task
36
- return await task
37
+ try:
38
+ return await task
39
+ except Exception:
40
+ if self._load_tasks.get(model_name) is task:
41
+ del self._load_tasks[model_name]
42
+ raise
37
43
 
38
44
  def reset(self) -> None:
39
45
  self._load_tasks.clear()
@@ -57,9 +63,7 @@ class BaseModelManager(ABC):
57
63
  """Map of file key → (download_url, path relative to ``model_path``)."""
58
64
 
59
65
  @abstractmethod
60
- async def build_backend(
61
- self, model_name: str, paths: Mapping[str, str]
62
- ) -> InferenceBackend:
66
+ async def build_backend(self, model_name: str, paths: Mapping[str, str]) -> InferenceBackend:
63
67
  """Build the runtime backend from the (already downloaded) local paths."""
64
68
 
65
69
  async def _load(self, model_name: str) -> InferenceBackend:
@@ -67,11 +71,9 @@ class BaseModelManager(ABC):
67
71
  for url, rel in files.values():
68
72
  await self._download(url, rel)
69
73
 
70
- paths = {
71
- key: os.path.join(self.model_path, rel)
72
- for key, (_url, rel) in files.items()
73
- }
74
- return await self.build_backend(model_name, paths)
74
+ paths = {key: os.path.join(self.model_path, rel) for key, (_url, rel) in files.items()}
75
+ async with self._build_lock:
76
+ return await self.build_backend(model_name, paths)
75
77
 
76
78
  async def _download(self, url: str, rel: str) -> None:
77
79
  full_path = os.path.join(self.model_path, rel)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: camera-ui-ml
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: Shared ML inference framework for camera.ui detection plugins (onnx, openvino, coreml, ncnn)
5
5
  Author-email: seydx <hi@seydx.dev>
6
6
  Maintainer-email: seydx <hi@seydx.dev>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "camera-ui-ml"
7
- version = "1.2.2"
7
+ version = "1.2.3"
8
8
  description = "Shared ML inference framework for camera.ui detection plugins (onnx, openvino, coreml, ncnn)"
9
9
  keywords = ["camera.ui", "python", "ml", "inference", "detection"]
10
10
  readme = "README.md"
File without changes
File without changes
File without changes