lumen-resources 0.2.0__py3-none-any.whl

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.
@@ -0,0 +1,89 @@
1
+ """Lumen Resources - Unified Model Resource Management.
2
+
3
+ Configuration-driven tool for managing ML model resources with production-grade
4
+ YAML configuration, JSON Schema validation, and Pydantic models. Provides a
5
+ unified interface for downloading models from multiple platforms including
6
+ HuggingFace Hub and ModelScope.
7
+
8
+ This package offers:
9
+ - Configuration-driven YAML setup for ML model resources
10
+ - Multi-platform support (HuggingFace Hub, ModelScope)
11
+ - Runtime flexibility (ONNX, PyTorch, TensorFlow, RKNN)
12
+ - Production-grade validation using JSON Schema and Pydantic
13
+ - CLI interface for command-line operations
14
+ - Programmatic API for integration into other applications
15
+
16
+ Example:
17
+ >>> from lumen_resources import load_and_validate_config, Downloader
18
+ >>>
19
+ >>> # Load and validate configuration
20
+ >>> config = load_and_validate_config("config.yaml")
21
+ >>>
22
+ >>> # Download models
23
+ >>> downloader = Downloader(config, verbose=True)
24
+ >>> results = downloader.download_all()
25
+ >>>
26
+ >>> # Check results
27
+ >>> for model_type, result in results.items():
28
+ ... if result.success:
29
+ ... print(f"Downloaded: {model_type} to {result.model_path}")
30
+ ... else:
31
+ ... print(f"Failed: {model_type} - {result.error}")
32
+
33
+ The package follows a layered architecture:
34
+ - Configuration layer: Pydantic models for type-safe config handling
35
+ - Validation layer: JSON Schema and Pydantic validation
36
+ - Platform layer: Unified interface for different model repositories
37
+ - Download layer: Efficient model downloading with validation
38
+ - CLI layer: User-friendly command-line interface
39
+ """
40
+
41
+ from .lumen_config import LumenConfig, Runtime, Region
42
+ from .downloader import Downloader, DownloadResult
43
+ from .exceptions import (
44
+ ResourceError,
45
+ ConfigError,
46
+ DownloadError,
47
+ PlatformUnavailableError,
48
+ ValidationError,
49
+ ModelInfoError,
50
+ )
51
+ from .lumen_config_validator import load_and_validate_config
52
+
53
+ from .model_info import ModelInfo, Source, Runtimes, Metadata
54
+ from .model_info_validator import load_and_validate_model_info
55
+ from .result_schemas import (
56
+ EmbeddingV1,
57
+ FaceV1,
58
+ LabelsV1
59
+ )
60
+
61
+ __version__ = "0.1.0"
62
+
63
+ __all__ = [
64
+ # Configuration
65
+ "LumenConfig",
66
+ "Runtime",
67
+ "Region",
68
+ "load_and_validate_config",
69
+ # Model Info
70
+ "ModelInfo",
71
+ "Source",
72
+ "Runtimes",
73
+ "Metadata",
74
+ "load_and_validate_model_info",
75
+ # Response Validation
76
+ "FaceV1",
77
+ "EmbeddingV1",
78
+ "LabelsV1",
79
+ # Downloader
80
+ "Downloader",
81
+ "DownloadResult",
82
+ # Exceptions
83
+ "ResourceError",
84
+ "ConfigError",
85
+ "DownloadError",
86
+ "PlatformUnavailableError",
87
+ "ValidationError",
88
+ "ModelInfoError",
89
+ ]
lumen_resources/cli.py ADDED
@@ -0,0 +1,402 @@
1
+ """
2
+ Command Line Interface for Lumen Resources
3
+
4
+ Provides user-friendly commands for downloading and managing model resources.
5
+ """
6
+
7
+ import argparse
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ from .downloader import Downloader, DownloadResult
12
+ from .lumen_config_validator import ConfigValidator, load_and_validate_config
13
+ from .model_info_validator import (
14
+ ModelInfoValidator,
15
+ load_and_validate_model_info,
16
+ )
17
+
18
+
19
+ def print_banner():
20
+ """Print welcome banner.
21
+
22
+ Displays the Lumen Resources application banner with formatting
23
+ to provide a professional command-line interface experience.
24
+ """
25
+ print("=" * 60)
26
+ print(" Lumen Resources - Model Resource Manager")
27
+ print("=" * 60)
28
+
29
+
30
+ def print_summary(results: dict[str, DownloadResult]) -> None:
31
+ """Print download summary with results and statistics.
32
+
33
+ Args:
34
+ results: Dictionary mapping model type identifiers to DownloadResult objects.
35
+ Contains information about download success status, file paths, and errors.
36
+ """
37
+ print("\n" + "=" * 60)
38
+ print("📊 Download Summary")
39
+ print("=" * 60)
40
+
41
+ success_count = sum(1 for r in results.values() if r.success)
42
+ total_count = len(results)
43
+
44
+ for model_type, result in results.items():
45
+ status = "✅" if result.success else "❌"
46
+ print(f"{status} {model_type.upper()}")
47
+ if result.success:
48
+ print(f" Path: {result.model_path}")
49
+ if result.missing_files:
50
+ print(f" ⚠️ Missing: {', '.join(result.missing_files)}")
51
+ else:
52
+ print(f" Error: {result.error}")
53
+
54
+ print("\n" + "=" * 60)
55
+ print(f"🎉 Completed: {success_count}/{total_count} successful")
56
+ print("=" * 60)
57
+
58
+
59
+ def cmd_download(args: argparse.Namespace) -> None:
60
+ """Handle download command for model resources.
61
+
62
+ Downloads all enabled models from the configuration file, with support for
63
+ forced re-downloading and detailed progress reporting. Validates configuration
64
+ before downloading and provides a comprehensive summary of results.
65
+
66
+ Args:
67
+ args: Parsed command line arguments containing:
68
+ - config: Path to configuration YAML file
69
+ - force: Whether to force re-download even if models are cached
70
+
71
+ Raises:
72
+ SystemExit: If configuration validation fails or downloads encounter errors.
73
+ """
74
+ config_path = Path(args.config)
75
+
76
+ try:
77
+ # Load and validate configuration
78
+ print("📋 Loading configuration...")
79
+ config = load_and_validate_config(config_path)
80
+
81
+ print(f"🌍 Region: {config.metadata.region.value}")
82
+ print(f"📁 Cache directory: {config.metadata.cache_dir}")
83
+
84
+ # Count enabled models
85
+ enabled_models = []
86
+ for service_name, service_config in config.services.items():
87
+ if service_config.enabled:
88
+ for alias in service_config.models.keys():
89
+ enabled_models.append(f"{service_name}:{alias}")
90
+ print(f"🎯 Enabled models: {', '.join(enabled_models)}")
91
+
92
+ # Download resources
93
+ print("\n🚀 Starting download...")
94
+ downloader = Downloader(config, verbose=True)
95
+ results = downloader.download_all(force=args.force)
96
+
97
+ # Print summary
98
+ print_summary(results)
99
+
100
+ # Exit with error if any downloads failed
101
+ if not all(r.success for r in results.values()):
102
+ sys.exit(1)
103
+
104
+ except Exception as e:
105
+ print(f"\n❌ Error: {e}")
106
+ sys.exit(1)
107
+
108
+
109
+ def cmd_validate(args: argparse.Namespace) -> None:
110
+ """Handle validate command for configuration files.
111
+
112
+ Validates YAML configuration files against the Lumen configuration schema
113
+ with options for strict Pydantic validation or flexible JSON Schema validation.
114
+ Displays detailed configuration information when validation succeeds.
115
+
116
+ Args:
117
+ args: Parsed command line arguments containing:
118
+ - config: Path to configuration YAML file
119
+ - strict: Whether to use strict Pydantic validation
120
+
121
+ Raises:
122
+ SystemExit: If configuration validation fails.
123
+ """
124
+ config_path = Path(args.config)
125
+
126
+ try:
127
+ print("📋 Validating configuration...")
128
+
129
+ # Use new Pydantic-based validator
130
+ validator = ConfigValidator()
131
+ is_valid, errors = validator.validate_file(config_path, strict=args.strict)
132
+
133
+ if not is_valid:
134
+ print("❌ Validation failed:\n")
135
+ for error in errors:
136
+ print(f" • {error}")
137
+ sys.exit(1)
138
+
139
+ # Load the validated config
140
+ config = load_and_validate_config(config_path)
141
+
142
+ print("✅ Configuration is valid!")
143
+ print(f"\n🌍 Region: {config.metadata.region.value}")
144
+ print(f"📁 Cache directory: {config.metadata.cache_dir}")
145
+ print(f"🚀 Deployment mode: {config.deployment.mode}")
146
+
147
+ if config.deployment.mode == "single":
148
+ print(f" Service: {config.deployment.service}")
149
+ else:
150
+ services_list = [s.root for s in (config.deployment.services or [])]
151
+ print(f" Services: {', '.join(services_list)}")
152
+
153
+ print("\n🌐 Server:")
154
+ print(f" Port: {config.server.port}")
155
+ print(f" Host: {config.server.host}")
156
+ if config.server.mdns and config.server.mdns.enabled:
157
+ print(f" mDNS: {config.server.mdns.service_name}")
158
+
159
+ print("\n📦 Services:")
160
+ for service_name, service_config in config.services.items():
161
+ status = "✅ enabled" if service_config.enabled else "⚪ disabled"
162
+ print(f" • {service_name} ({status})")
163
+ if service_config.enabled:
164
+ print(f" Package: {service_config.package}")
165
+ print(f" Models: {', '.join(service_config.models.keys())}")
166
+ for alias, model in service_config.models.items():
167
+ print(f" - {alias}: {model.model} ({model.runtime.value})")
168
+ if model.dataset:
169
+ print(f" Dataset: {model.dataset}")
170
+
171
+ except Exception as e:
172
+ print(f"❌ Validation failed: {e}")
173
+ sys.exit(1)
174
+
175
+
176
+ def cmd_validate_model_info(args: argparse.Namespace) -> None:
177
+ """Handle validate-model-info command for model metadata files.
178
+
179
+ Validates model_info.json files against the model information schema
180
+ with options for strict Pydantic validation or flexible JSON Schema validation.
181
+ Displays comprehensive model information when validation succeeds.
182
+
183
+ Args:
184
+ args: Parsed command line arguments containing:
185
+ - model_info: Path to model_info.json file
186
+ - strict: Whether to use strict Pydantic validation
187
+
188
+ Raises:
189
+ SystemExit: If model_info.json validation fails.
190
+ """
191
+ model_info_path = Path(args.model_info)
192
+
193
+ try:
194
+ print("📋 Validating model_info.json...")
195
+
196
+ # Use ModelInfoValidator
197
+ validator = ModelInfoValidator()
198
+ is_valid, errors = validator.validate_file(model_info_path, strict=args.strict)
199
+
200
+ if not is_valid:
201
+ print("❌ Validation failed:\n")
202
+ for error in errors:
203
+ print(f" • {error}")
204
+ sys.exit(1)
205
+
206
+ # Load the validated model info
207
+ model_info = load_and_validate_model_info(model_info_path)
208
+
209
+ print("✅ Model info is valid!")
210
+ print(f"\n📦 Model: {model_info.name}")
211
+ print(f" Version: {model_info.version}")
212
+ print(f" Type: {model_info.model_type}")
213
+ print(f" Embedding dimension: {model_info.embedding_dim}")
214
+
215
+ print("\n📥 Source:")
216
+ print(f" Format: {model_info.source.format.value}")
217
+ print(f" Repository: {model_info.source.repo_id}")
218
+
219
+ print("\n🔧 Runtimes:")
220
+ for runtime_name, runtime_config in model_info.runtimes.items():
221
+ status = "✅ available" if runtime_config.available else "⚪ not available"
222
+ print(f" • {runtime_name} ({status})")
223
+ if runtime_config.available and runtime_config.files:
224
+ if isinstance(runtime_config.files, list):
225
+ print(f" Files: {len(runtime_config.files)} file(s)")
226
+ else:
227
+ total_files = sum(
228
+ len(files) for files in runtime_config.files.values()
229
+ )
230
+ devices_count = len(runtime_config.files)
231
+ print(
232
+ f" Files: {total_files} file(s) across {devices_count} device(s)"
233
+ )
234
+ if runtime_config.devices:
235
+ print(f" Devices: {', '.join(runtime_config.devices)}")
236
+
237
+ if model_info.datasets:
238
+ print("\n📊 Datasets:")
239
+ for dataset_name, dataset_file in model_info.datasets.items():
240
+ print(f" • {dataset_name}: {dataset_file}")
241
+
242
+ if model_info.metadata:
243
+ print("\n📝 Metadata:")
244
+ if model_info.metadata.license:
245
+ print(f" License: {model_info.metadata.license}")
246
+ if model_info.metadata.author:
247
+ print(f" Author: {model_info.metadata.author}")
248
+ if model_info.metadata.created_at:
249
+ print(f" Created: {model_info.metadata.created_at}")
250
+ if model_info.metadata.tags:
251
+ print(f" Tags: {', '.join(model_info.metadata.tags)}")
252
+
253
+ except Exception as e:
254
+ print(f"❌ Validation failed: {e}")
255
+ sys.exit(1)
256
+
257
+
258
+ def cmd_list(args: argparse.Namespace) -> None:
259
+ """Handle list command for cached models.
260
+
261
+ Lists all models currently cached in the specified cache directory,
262
+ showing model information including version, available runtimes, and
263
+ file contents when model_info.json files are available.
264
+
265
+ Args:
266
+ args: Parsed command line arguments containing:
267
+ - cache_dir: Path to cache directory (defaults to ~/.lumen/)
268
+ """
269
+ cache_dir = Path(args.cache_dir).expanduser()
270
+ models_dir = cache_dir / "models"
271
+
272
+ if not models_dir.exists():
273
+ print(f"No models found in {cache_dir}")
274
+ return
275
+
276
+ print(f"📦 Models in {cache_dir}:")
277
+ print()
278
+
279
+ model_dirs = sorted([d for d in models_dir.iterdir() if d.is_dir()])
280
+
281
+ if not model_dirs:
282
+ print(" (empty)")
283
+ return
284
+
285
+ for model_dir in model_dirs:
286
+ print(f" 📁 {model_dir.name}")
287
+
288
+ # Check for model_info.json
289
+ info_file = model_dir / "model_info.json"
290
+ if info_file.exists():
291
+ import json
292
+
293
+ try:
294
+ with open(info_file, "r") as f:
295
+ info = json.load(f)
296
+ print(f" Version: {info.get('version', 'unknown')}")
297
+ runtimes = info.get("runtimes", {})
298
+ available_runtimes = [
299
+ r for r, data in runtimes.items() if data.get("available")
300
+ ]
301
+ if available_runtimes:
302
+ print(f" Runtimes: {', '.join(available_runtimes)}")
303
+ except Exception:
304
+ pass
305
+
306
+ # List subdirectories
307
+ subdirs = [d.name for d in model_dir.iterdir() if d.is_dir()]
308
+ if subdirs:
309
+ print(f" Contents: {', '.join(subdirs)}")
310
+
311
+ print()
312
+
313
+
314
+ def main() -> None:
315
+ """Main CLI entry point.
316
+
317
+ Sets up the argument parser with subcommands for different operations
318
+ (download, validate, validate-model-info, list) and dispatches to the
319
+ appropriate handler functions. Handles help display and error cases.
320
+
321
+ Raises:
322
+ SystemExit: If no command is provided or if a command handler exits with an error.
323
+ """
324
+ parser = argparse.ArgumentParser(
325
+ prog="lumen-resources",
326
+ description="Lumen Resources - Model Resource Manager",
327
+ formatter_class=argparse.RawDescriptionHelpFormatter,
328
+ )
329
+
330
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
331
+
332
+ # Download command
333
+ download_parser = subparsers.add_parser(
334
+ "download", help="Download model resources from configuration"
335
+ )
336
+ _ = download_parser.add_argument("config", help="Path to configuration YAML file")
337
+ _ = download_parser.add_argument(
338
+ "--force", action="store_true", help="Force re-download even if cached"
339
+ )
340
+ download_parser.set_defaults(func=cmd_download)
341
+
342
+ # Validate command
343
+ validate_parser = subparsers.add_parser(
344
+ "validate", help="Validate configuration file"
345
+ )
346
+ _ = validate_parser.add_argument("config", help="Path to configuration YAML file")
347
+ _ = validate_parser.add_argument(
348
+ "--strict",
349
+ action="store_true",
350
+ default=True,
351
+ help="Use strict Pydantic validation (default: True)",
352
+ )
353
+ _ = validate_parser.add_argument(
354
+ "--schema-only",
355
+ action="store_false",
356
+ dest="strict",
357
+ help="Use JSON Schema validation only (less strict)",
358
+ )
359
+ validate_parser.set_defaults(func=cmd_validate)
360
+
361
+ # Validate model info command
362
+ validate_model_parser = subparsers.add_parser(
363
+ "validate-model-info", help="Validate model_info.json file"
364
+ )
365
+ _ = validate_model_parser.add_argument(
366
+ "model_info", help="Path to model_info.json file"
367
+ )
368
+ _ = validate_model_parser.add_argument(
369
+ "--strict",
370
+ action="store_true",
371
+ default=True,
372
+ help="Use strict Pydantic validation (default: True)",
373
+ )
374
+ _ = validate_model_parser.add_argument(
375
+ "--schema-only",
376
+ action="store_false",
377
+ dest="strict",
378
+ help="Use JSON Schema validation only (less strict)",
379
+ )
380
+ validate_model_parser.set_defaults(func=cmd_validate_model_info)
381
+
382
+ # List command
383
+ list_parser = subparsers.add_parser("list", help="List cached models")
384
+ _ = list_parser.add_argument(
385
+ "cache_dir", nargs="?", default="~/.lumen/", help="Cache directory path"
386
+ )
387
+ list_parser.set_defaults(func=cmd_list)
388
+
389
+ args: argparse.Namespace = parser.parse_args()
390
+
391
+ if not args.command:
392
+ parser.print_help()
393
+ sys.exit(1)
394
+
395
+ print_banner()
396
+ print()
397
+
398
+ args.func(args)
399
+
400
+
401
+ if __name__ == "__main__":
402
+ main()