lumen-resources 0.4.1__tar.gz → 0.4.2__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 (38) hide show
  1. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/PKG-INFO +1 -1
  2. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/cli.py +1 -1
  3. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/downloader.py +42 -104
  4. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/lumen_config.py +2 -2
  5. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/lumen_config_validator.py +3 -3
  6. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/model_info_validator.py +3 -3
  7. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/schemas/config-schema.yaml +1 -1
  8. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources.egg-info/PKG-INFO +1 -1
  9. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/.gitignore +0 -0
  10. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/README.md +0 -0
  11. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/docs/examples/clip_torch_cn.yaml +0 -0
  12. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/docs/examples/hub-service.yaml +0 -0
  13. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/docs/examples/model_info_template.json +0 -0
  14. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/docs/examples/single-service.yaml +0 -0
  15. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/pyproject.toml +0 -0
  16. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/setup.cfg +0 -0
  17. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/__init__.py +0 -0
  18. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/exceptions.py +0 -0
  19. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/model_info.py +0 -0
  20. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/platform.py +0 -0
  21. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/result_schemas/README.md +0 -0
  22. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/result_schemas/__init__.py +0 -0
  23. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/result_schemas/embedding_v1.py +0 -0
  24. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/result_schemas/face_v1.py +0 -0
  25. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/result_schemas/labels_v1.py +0 -0
  26. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/result_schemas/ocr_v1.py +0 -0
  27. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/result_schemas/text_generation_v1.py +0 -0
  28. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/schemas/model_info-schema.json +0 -0
  29. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/schemas/result_schemas/embedding_v1.json +0 -0
  30. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/schemas/result_schemas/face_v1.json +0 -0
  31. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/schemas/result_schemas/labels_v1.json +0 -0
  32. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/schemas/result_schemas/ocr_v1.json +0 -0
  33. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources/schemas/result_schemas/text_generation_v1.json +0 -0
  34. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources.egg-info/SOURCES.txt +0 -0
  35. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources.egg-info/dependency_links.txt +0 -0
  36. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources.egg-info/entry_points.txt +0 -0
  37. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources.egg-info/requires.txt +0 -0
  38. {lumen_resources-0.4.1 → lumen_resources-0.4.2}/src/lumen_resources.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lumen-resources
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: Unified model resource management for Lumen ML services
5
5
  Author-email: EdwinZhanCN <support@lumilio.org>
6
6
  License: MIT
@@ -291,7 +291,7 @@ def cmd_list(args: argparse.Namespace) -> None:
291
291
  import json
292
292
 
293
293
  try:
294
- with open(info_file, "r") as f:
294
+ with open(info_file) as f:
295
295
  info = json.load(f)
296
296
  print(f" Version: {info.get('version', 'unknown')}")
297
297
  runtimes = info.get("runtimes", {})
@@ -139,18 +139,15 @@ class Downloader:
139
139
 
140
140
  for alias, model_config in service_config.models.items():
141
141
  model_type = f"{service_name}:{alias}"
142
- prefer_fp16 = False
143
- if service_config.backend_settings:
144
- prefer_fp16 = service_config.backend_settings.prefer_fp16 or False
145
142
 
146
143
  if self.verbose:
147
144
  print(f"\n📦 Processing {model_type.upper()}")
148
145
  print(f" Model: {model_config.model}")
149
146
  print(f" Runtime: {model_config.runtime.value}")
147
+ if model_config.precision:
148
+ print(f" Precision: {model_config.precision}")
150
149
 
151
- result = self._download_model(
152
- model_type, model_config, force, prefer_fp16
153
- )
150
+ result = self._download_model(model_type, model_config, force)
154
151
  results[model_type] = result
155
152
 
156
153
  # Print result
@@ -168,22 +165,25 @@ class Downloader:
168
165
 
169
166
  return results
170
167
 
171
- def _get_runtime_patterns(self, runtime: Runtime, pref_fp16: bool) -> list[str]:
172
- """Get file patterns to download based on runtime.
168
+ def _get_runtime_patterns(
169
+ self, runtime: Runtime, precision: str | None
170
+ ) -> list[str]:
171
+ """Get file patterns to download based on runtime and precision.
173
172
 
174
173
  Determines which file patterns to include in downloads based on the
175
- model runtime. Always includes model_info.json and config files.
174
+ model runtime and precision configuration. Always includes model_info.json
175
+ and config files.
176
176
 
177
177
  Args:
178
178
  runtime: The model runtime (torch, onnx, rknn).
179
- pref_fp16: Whether to prefer FP16 models over FP32.
179
+ precision: The precision variant (fp32, fp16, int8, q4fp16, etc.).
180
180
 
181
181
  Returns:
182
182
  List of file glob patterns for the download.
183
183
 
184
184
  Example:
185
- >>> patterns = downloader._get_runtime_patterns(Runtime.torch, False)
186
- >>> print("model_info.json" in patterns)
185
+ >>> patterns = downloader._get_runtime_patterns(Runtime.onnx, "fp16")
186
+ >>> print("*.fp16.onnx" in patterns)
187
187
  True
188
188
  """
189
189
  patterns = [
@@ -215,11 +215,12 @@ class Downloader:
215
215
  "preprocessor_config.json",
216
216
  ]
217
217
  )
218
- # Only add one precision based on preference to save space
219
- if pref_fp16:
220
- patterns.extend(["*.fp16.onnx"])
218
+ # Add precision-specific ONNX model files if precision is specified
219
+ if precision:
220
+ patterns.extend([f"*.{precision}.onnx"])
221
221
  else:
222
- patterns.extend(["*.fp32.onnx"])
222
+ # If no precision specified, include all common precisions
223
+ patterns.extend(["*.fp32.onnx", "*.fp16.onnx", "*.int8.onnx"])
223
224
  elif runtime == Runtime.rknn:
224
225
  patterns.extend(
225
226
  [
@@ -230,79 +231,45 @@ class Downloader:
230
231
  "preprocessor_config.json",
231
232
  ]
232
233
  )
234
+ # RKNN files are already quantized, precision field may indicate variant
235
+ if precision:
236
+ patterns.extend([f"*.{precision}.rknn"])
237
+ else:
238
+ patterns.extend(["*.rknn"])
233
239
 
234
240
  return patterns
235
241
 
236
242
  def _download_model(
237
- self, model_type: str, model_config: ModelConfig, force: bool, pref_fp16: bool
243
+ self, model_type: str, model_config: ModelConfig, force: bool
238
244
  ) -> DownloadResult:
239
- """Download a single model with its runtime files using fallback strategy.
245
+ """Download a single model with its runtime files.
240
246
 
241
- First attempts to download with the preferred precision (FP16/FP32),
242
- and if that fails due to file mismatch, falls back to the other precision.
243
- This ensures model availability while minimizing storage usage.
247
+ Uses the precision specified in model_config to download the appropriate
248
+ model variant. If no precision is specified for ONNX/RKNN runtimes, will
249
+ download all available precision variants.
244
250
 
245
251
  Args:
246
252
  model_type: Identifier for the model (e.g., "clip:default").
247
253
  model_config: Model configuration from LumenConfig.
248
254
  force: Whether to force re-download even if already cached.
249
- pref_fp16: Whether to prefer FP16 models over FP32.
250
255
 
251
256
  Returns:
252
257
  DownloadResult with success status, file paths, and error details.
253
258
 
254
259
  Raises:
255
- DownloadError: If platform download fails for both precisions.
260
+ DownloadError: If platform download fails.
256
261
  ModelInfoError: If model_info.json is missing or invalid.
257
262
  ValidationError: If model configuration is not supported.
258
263
  """
259
- # First attempt with preferred precision
260
- preferred_patterns = self._get_runtime_patterns(model_config.runtime, pref_fp16)
261
- fallback_patterns = self._get_runtime_patterns(
262
- model_config.runtime, not pref_fp16
264
+ # Get file patterns based on runtime and precision from ModelConfig
265
+ patterns = self._get_runtime_patterns(
266
+ model_config.runtime, model_config.precision
263
267
  )
264
268
 
265
- # Try preferred precision first
266
- try:
267
- return self._download_model_with_patterns(
268
- model_type, model_config, force, preferred_patterns, pref_fp16
269
- )
270
- except DownloadError as e:
271
- # Check if this is a "no matching files" error that warrants fallback
272
- if (
273
- self._should_fallback_download(str(e))
274
- and model_config.runtime == Runtime.onnx
275
- ):
276
- precision = "FP16" if pref_fp16 else "FP32"
277
- fallback_precision = "FP32" if pref_fp16 else "FP16"
278
- if self.verbose:
279
- print(
280
- f" ⚠️ {precision} model not found, trying {fallback_precision}"
281
- )
282
-
283
- try:
284
- return self._download_model_with_patterns(
285
- model_type,
286
- model_config,
287
- force,
288
- fallback_patterns,
289
- not pref_fp16,
290
- )
291
- except DownloadError as fallback_error:
292
- # If fallback also fails, report both errors
293
- return DownloadResult(
294
- model_type=model_type,
295
- model_name=model_config.model,
296
- runtime=model_config.runtime.value
297
- if hasattr(model_config.runtime, "value")
298
- else str(model_config.runtime),
299
- success=False,
300
- error=f"Failed to download with {precision}: {e}. "
301
- f"Fallback with {fallback_precision} also failed: {fallback_error}",
302
- )
303
-
304
- # Non-fallbackable error or non-ONNX runtime, just report original error
305
- raise
269
+ # Download with the determined patterns
270
+ return self._download_model_with_patterns(
271
+ model_type, model_config, force, patterns
272
+ )
306
273
 
307
274
  def _download_model_with_patterns(
308
275
  self,
@@ -310,7 +277,6 @@ class Downloader:
310
277
  model_config: ModelConfig,
311
278
  force: bool,
312
279
  patterns: list[str],
313
- is_fp16: bool | None = None,
314
280
  ) -> DownloadResult:
315
281
  """Download a model with specific file patterns.
316
282
 
@@ -381,9 +347,7 @@ class Downloader:
381
347
  )
382
348
 
383
349
  # Final: File integrity validation
384
- missing = self._validate_files(
385
- model_path, model_info, model_config, is_fp16
386
- )
350
+ missing = self._validate_files(model_path, model_info, model_config)
387
351
  result.missing_files = missing
388
352
 
389
353
  if missing:
@@ -406,29 +370,6 @@ class Downloader:
406
370
 
407
371
  return result
408
372
 
409
- def _should_fallback_download(self, error_message: str) -> bool:
410
- """Determine if a download error should trigger fallback to another precision.
411
-
412
- Args:
413
- error_message: The error message from the download attempt.
414
-
415
- Returns:
416
- True if the error suggests we should try the other precision, False otherwise.
417
- """
418
- # Common patterns that indicate file matching issues
419
- fallback_indicators = [
420
- "No matching files found",
421
- "No files matched the pattern",
422
- "Cannot find any files matching",
423
- "File pattern matched no files",
424
- "No such file or directory", # Sometimes used for remote files
425
- ]
426
-
427
- error_lower = error_message.lower()
428
- return any(
429
- indicator.lower() in error_lower for indicator in fallback_indicators
430
- )
431
-
432
373
  def _load_model_info(self, model_path: Path) -> ModelInfo:
433
374
  """Load and parse model_info.json using validator.
434
375
 
@@ -499,20 +440,16 @@ class Downloader:
499
440
  model_path: Path,
500
441
  model_info: ModelInfo,
501
442
  model_config: ModelConfig,
502
- is_fp16: bool | None = None,
503
443
  ) -> list[str]:
504
444
  """Validate that all required files are present after download.
505
445
 
506
446
  Checks model files, tokenizer files, and dataset files against
507
- the model_info.json metadata based on the actual precision
508
- downloaded.
447
+ the model_info.json metadata based on the runtime configuration.
509
448
 
510
449
  Args:
511
450
  model_path: Local path where model files are located.
512
451
  model_info: Parsed model information.
513
452
  model_config: Model configuration to validate.
514
- is_fp16: Whether FP16 files were downloaded (None for non-ONNX
515
- runtimes).
516
453
 
517
454
  Returns:
518
455
  List of missing file paths. Empty list if all files present.
@@ -534,13 +471,14 @@ class Downloader:
534
471
  runtime_files = runtime_config.files
535
472
 
536
473
  # For ONNX runtime, filter by precision if specified
537
- if runtime_str == "onnx" and is_fp16 is not None:
538
- precision_str = "fp16" if is_fp16 else "fp32"
474
+ if runtime_str == "onnx" and model_config.precision:
539
475
  runtime_files = [
540
476
  f
541
477
  for f in runtime_files
542
- if not f.endswith((".fp16.onnx", ".fp32.onnx"))
543
- or f.endswith(f".{precision_str}.onnx")
478
+ if not f.endswith(
479
+ (".fp16.onnx", ".fp32.onnx", ".int8.onnx", ".q4fp16.onnx")
480
+ )
481
+ or f.endswith(f".{model_config.precision}.onnx")
544
482
  ]
545
483
  elif isinstance(runtime_config.files, dict) and model_config.rknn_device:
546
484
  # RKNN files are organized by device
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: config-schema.yaml
3
- # timestamp: 2025-12-23T18:16:59+00:00
3
+ # timestamp: 2025-12-30T14:26:42+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -225,7 +225,7 @@ class Services(BaseModel):
225
225
  """
226
226
  Python package name
227
227
  """
228
- import_info: ImportInfo | None = None
228
+ import_info: ImportInfo
229
229
  backend_settings: BackendSettings | None = None
230
230
  models: dict[str, ModelConfig]
231
231
  """
@@ -57,7 +57,7 @@ class ConfigValidator:
57
57
  if not schema_path.exists():
58
58
  raise FileNotFoundError(f"Schema file not found: {schema_path}")
59
59
 
60
- with open(schema_path, "r", encoding="utf-8") as f:
60
+ with open(schema_path, encoding="utf-8") as f:
61
61
  self.schema = yaml.safe_load(f)
62
62
 
63
63
  self.validator = Draft7Validator(self.schema)
@@ -93,7 +93,7 @@ class ConfigValidator:
93
93
  return False, [f"Configuration file not found: {config_path}"]
94
94
 
95
95
  try:
96
- with open(config_path, "r", encoding="utf-8") as f:
96
+ with open(config_path, encoding="utf-8") as f:
97
97
  config_data = yaml.safe_load(f)
98
98
  except yaml.YAMLError as e:
99
99
  return False, [f"Invalid YAML syntax: {e}"]
@@ -207,7 +207,7 @@ class ConfigValidator:
207
207
  raise ConfigError(error_msg)
208
208
 
209
209
  # Load and construct the validated configuration
210
- with open(config_path, "r", encoding="utf-8") as f:
210
+ with open(config_path, encoding="utf-8") as f:
211
211
  config_data = yaml.safe_load(f)
212
212
 
213
213
  return LumenConfig(**config_data)
@@ -54,7 +54,7 @@ class ModelInfoValidator:
54
54
  if not schema_path.exists():
55
55
  raise FileNotFoundError(f"Schema file not found: {schema_path}")
56
56
 
57
- with open(schema_path, "r", encoding="utf-8") as f:
57
+ with open(schema_path, encoding="utf-8") as f:
58
58
  self.schema: dict[str, Any] = json.load(f)
59
59
 
60
60
  self.validator = Draft7Validator(self.schema)
@@ -89,7 +89,7 @@ class ModelInfoValidator:
89
89
  return False, [f"File not found: {path}"]
90
90
 
91
91
  try:
92
- with open(path, "r", encoding="utf-8") as f:
92
+ with open(path, encoding="utf-8") as f:
93
93
  data = json.load(f)
94
94
  except json.JSONDecodeError as e:
95
95
  return False, [f"Invalid JSON: {e}"]
@@ -196,7 +196,7 @@ class ModelInfoValidator:
196
196
  )
197
197
  raise ValueError(error_msg)
198
198
 
199
- with open(path, "r", encoding="utf-8") as f:
199
+ with open(path, encoding="utf-8") as f:
200
200
  data = json.load(f)
201
201
 
202
202
  return ModelInfo.model_validate(data)
@@ -137,7 +137,7 @@ properties:
137
137
  required:
138
138
  - enabled
139
139
  - package
140
- - import
140
+ - import_info
141
141
  - models
142
142
 
143
143
  properties:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lumen-resources
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: Unified model resource management for Lumen ML services
5
5
  Author-email: EdwinZhanCN <support@lumilio.org>
6
6
  License: MIT