nexaai 1.0.19rc6__cp310-cp310-win_amd64.whl → 1.0.19rc7__cp310-cp310-win_amd64.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.
Potentially problematic release.
This version of nexaai might be problematic. Click here for more details.
- nexaai/_stub.cp310-win_amd64.pyd +0 -0
- nexaai/_version.py +1 -1
- nexaai/binds/common_bind.cp310-win_amd64.pyd +0 -0
- nexaai/binds/embedder_bind.cp310-win_amd64.pyd +0 -0
- nexaai/binds/llm_bind.cp310-win_amd64.pyd +0 -0
- nexaai/binds/nexa_bridge.dll +0 -0
- nexaai/binds/nexa_llama_cpp/ggml-base.dll +0 -0
- nexaai/binds/nexa_llama_cpp/ggml-cpu.dll +0 -0
- nexaai/binds/nexa_llama_cpp/ggml-cuda.dll +0 -0
- nexaai/binds/nexa_llama_cpp/ggml-vulkan.dll +0 -0
- nexaai/binds/nexa_llama_cpp/ggml.dll +0 -0
- nexaai/binds/nexa_llama_cpp/llama.dll +0 -0
- nexaai/binds/nexa_llama_cpp/mtmd.dll +0 -0
- nexaai/binds/nexa_llama_cpp/nexa_plugin.dll +0 -0
- nexaai/binds/nexa_nexaml/ggml-base.dll +0 -0
- nexaai/binds/nexa_nexaml/ggml-cpu.dll +0 -0
- nexaai/binds/nexa_nexaml/ggml-cuda.dll +0 -0
- nexaai/binds/nexa_nexaml/ggml-vulkan.dll +0 -0
- nexaai/binds/nexa_nexaml/ggml.dll +0 -0
- nexaai/binds/nexa_nexaml/nexa_plugin.dll +0 -0
- nexaai/binds/vlm_bind.cp310-win_amd64.pyd +0 -0
- nexaai/utils/manifest_utils.py +222 -15
- nexaai/utils/model_manager.py +83 -7
- nexaai/utils/model_types.py +2 -0
- {nexaai-1.0.19rc6.dist-info → nexaai-1.0.19rc7.dist-info}/METADATA +1 -1
- {nexaai-1.0.19rc6.dist-info → nexaai-1.0.19rc7.dist-info}/RECORD +28 -28
- {nexaai-1.0.19rc6.dist-info → nexaai-1.0.19rc7.dist-info}/WHEEL +0 -0
- {nexaai-1.0.19rc6.dist-info → nexaai-1.0.19rc7.dist-info}/top_level.txt +0 -0
nexaai/_stub.cp310-win_amd64.pyd
CHANGED
|
Binary file
|
nexaai/_version.py
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
nexaai/binds/nexa_bridge.dll
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
nexaai/utils/manifest_utils.py
CHANGED
|
@@ -22,6 +22,11 @@ from .model_types import (
|
|
|
22
22
|
MODEL_TYPE_TO_PIPELINE
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
+
MODEL_FILE_TYPE_TO_PLUGIN_ID_MAPPING = {
|
|
26
|
+
'npu': 'npu',
|
|
27
|
+
'mlx': 'mlx',
|
|
28
|
+
'gguf': 'llama_cpp'
|
|
29
|
+
}
|
|
25
30
|
|
|
26
31
|
def process_manifest_metadata(manifest: Dict[str, Any], repo_id: str) -> Dict[str, Any]:
|
|
27
32
|
"""Process manifest metadata to handle null/missing fields."""
|
|
@@ -94,12 +99,20 @@ def save_download_metadata(directory_path: str, metadata: Dict[str, Any]) -> Non
|
|
|
94
99
|
pass
|
|
95
100
|
|
|
96
101
|
|
|
97
|
-
def
|
|
102
|
+
def _get_plugin_id_from_model_file_type(model_file_type: Optional[str], default: str = "llama_cpp") -> str:
|
|
103
|
+
"""Map model file type to PluginId."""
|
|
104
|
+
return MODEL_FILE_TYPE_TO_PLUGIN_ID_MAPPING.get(model_file_type, default)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def create_gguf_manifest(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any], is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None, **kwargs) -> Dict[str, Any]:
|
|
98
108
|
"""Create GGUF format manifest."""
|
|
99
109
|
|
|
100
110
|
# Load existing manifest to merge GGUF files if it exists
|
|
101
111
|
existing_manifest = load_nexa_manifest(directory_path)
|
|
102
112
|
|
|
113
|
+
# Check if there's a downloaded nexa.manifest from the repo
|
|
114
|
+
downloaded_manifest = old_metadata.get('downloaded_manifest', {})
|
|
115
|
+
|
|
103
116
|
model_files = {}
|
|
104
117
|
if existing_manifest and "ModelFile" in existing_manifest:
|
|
105
118
|
model_files = existing_manifest["ModelFile"].copy()
|
|
@@ -151,10 +164,41 @@ def create_gguf_manifest(repo_id: str, files: List[str], directory_path: str, ol
|
|
|
151
164
|
"Size": file_size
|
|
152
165
|
}
|
|
153
166
|
|
|
167
|
+
# Determine PluginId with priority: kwargs > downloaded_manifest > model_file_type > default
|
|
168
|
+
plugin_id = kwargs.get('plugin_id')
|
|
169
|
+
if not plugin_id:
|
|
170
|
+
model_file_type = old_metadata.get('model_file_type')
|
|
171
|
+
if downloaded_manifest.get('PluginId'):
|
|
172
|
+
plugin_id = downloaded_manifest.get('PluginId')
|
|
173
|
+
elif model_file_type:
|
|
174
|
+
plugin_id = _get_plugin_id_from_model_file_type(model_file_type)
|
|
175
|
+
else:
|
|
176
|
+
plugin_id = "llama_cpp"
|
|
177
|
+
|
|
178
|
+
# Determine ModelType with priority: kwargs > downloaded_manifest > pipeline_tag mapping
|
|
179
|
+
model_type = kwargs.get('model_type')
|
|
180
|
+
if not model_type:
|
|
181
|
+
if downloaded_manifest.get('ModelType'):
|
|
182
|
+
model_type = downloaded_manifest.get('ModelType')
|
|
183
|
+
else:
|
|
184
|
+
model_type = PIPELINE_TO_MODEL_TYPE.get(old_metadata.get('pipeline_tag'), "other")
|
|
185
|
+
|
|
186
|
+
# Determine ModelName with priority: kwargs > downloaded_manifest > empty string
|
|
187
|
+
model_name = kwargs.get('model_name')
|
|
188
|
+
if not model_name:
|
|
189
|
+
model_name = downloaded_manifest.get('ModelName', '')
|
|
190
|
+
|
|
191
|
+
# Get DeviceId and MinSDKVersion from kwargs or default to empty string
|
|
192
|
+
device_id = kwargs.get('device_id', '')
|
|
193
|
+
min_sdk_version = kwargs.get('min_sdk_version', '')
|
|
194
|
+
|
|
154
195
|
manifest = {
|
|
155
196
|
"Name": repo_id,
|
|
156
|
-
"
|
|
157
|
-
"
|
|
197
|
+
"ModelName": model_name,
|
|
198
|
+
"ModelType": model_type,
|
|
199
|
+
"PluginId": plugin_id,
|
|
200
|
+
"DeviceId": device_id,
|
|
201
|
+
"MinSDKVersion": min_sdk_version,
|
|
158
202
|
"ModelFile": model_files,
|
|
159
203
|
"MMProjFile": mmproj_file,
|
|
160
204
|
"TokenizerFile": {
|
|
@@ -172,12 +216,15 @@ def create_gguf_manifest(repo_id: str, files: List[str], directory_path: str, ol
|
|
|
172
216
|
return manifest
|
|
173
217
|
|
|
174
218
|
|
|
175
|
-
def create_mlx_manifest(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any], is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None) -> Dict[str, Any]:
|
|
219
|
+
def create_mlx_manifest(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any], is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None, **kwargs) -> Dict[str, Any]:
|
|
176
220
|
"""Create MLX format manifest."""
|
|
177
221
|
|
|
178
222
|
# Load existing manifest to merge MLX files if it exists
|
|
179
223
|
existing_manifest = load_nexa_manifest(directory_path)
|
|
180
224
|
|
|
225
|
+
# Check if there's a downloaded nexa.manifest from the repo
|
|
226
|
+
downloaded_manifest = old_metadata.get('downloaded_manifest', {})
|
|
227
|
+
|
|
181
228
|
model_files = {}
|
|
182
229
|
extra_files = []
|
|
183
230
|
|
|
@@ -233,10 +280,153 @@ def create_mlx_manifest(repo_id: str, files: List[str], directory_path: str, old
|
|
|
233
280
|
"Size": file_size
|
|
234
281
|
})
|
|
235
282
|
|
|
283
|
+
# Determine PluginId with priority: kwargs > downloaded_manifest > model_file_type > default
|
|
284
|
+
plugin_id = kwargs.get('plugin_id')
|
|
285
|
+
if not plugin_id:
|
|
286
|
+
model_file_type = old_metadata.get('model_file_type')
|
|
287
|
+
if downloaded_manifest.get('PluginId'):
|
|
288
|
+
plugin_id = downloaded_manifest.get('PluginId')
|
|
289
|
+
elif model_file_type:
|
|
290
|
+
plugin_id = _get_plugin_id_from_model_file_type(model_file_type)
|
|
291
|
+
else:
|
|
292
|
+
plugin_id = "mlx"
|
|
293
|
+
|
|
294
|
+
# Determine ModelType with priority: kwargs > downloaded_manifest > pipeline_tag mapping
|
|
295
|
+
model_type = kwargs.get('model_type')
|
|
296
|
+
if not model_type:
|
|
297
|
+
if downloaded_manifest.get('ModelType'):
|
|
298
|
+
model_type = downloaded_manifest.get('ModelType')
|
|
299
|
+
else:
|
|
300
|
+
model_type = PIPELINE_TO_MODEL_TYPE.get(old_metadata.get('pipeline_tag'), "other")
|
|
301
|
+
|
|
302
|
+
# Determine ModelName with priority: kwargs > downloaded_manifest > empty string
|
|
303
|
+
model_name = kwargs.get('model_name')
|
|
304
|
+
if not model_name:
|
|
305
|
+
model_name = downloaded_manifest.get('ModelName', '')
|
|
306
|
+
|
|
307
|
+
# Get DeviceId and MinSDKVersion from kwargs or default to empty string
|
|
308
|
+
device_id = kwargs.get('device_id', '')
|
|
309
|
+
min_sdk_version = kwargs.get('min_sdk_version', '')
|
|
310
|
+
|
|
311
|
+
manifest = {
|
|
312
|
+
"Name": repo_id,
|
|
313
|
+
"ModelName": model_name,
|
|
314
|
+
"ModelType": model_type,
|
|
315
|
+
"PluginId": plugin_id,
|
|
316
|
+
"DeviceId": device_id,
|
|
317
|
+
"MinSDKVersion": min_sdk_version,
|
|
318
|
+
"ModelFile": model_files,
|
|
319
|
+
"MMProjFile": mmproj_file,
|
|
320
|
+
"TokenizerFile": {
|
|
321
|
+
"Name": "",
|
|
322
|
+
"Downloaded": False,
|
|
323
|
+
"Size": 0
|
|
324
|
+
},
|
|
325
|
+
"ExtraFiles": extra_files if extra_files else None,
|
|
326
|
+
# Preserve old metadata fields
|
|
327
|
+
"pipeline_tag": old_metadata.get('pipeline_tag') if old_metadata.get('pipeline_tag') else existing_manifest.get('pipeline_tag'),
|
|
328
|
+
"download_time": old_metadata.get('download_time') if old_metadata.get('download_time') else existing_manifest.get('download_time'),
|
|
329
|
+
"avatar_url": old_metadata.get('avatar_url') if old_metadata.get('avatar_url') else existing_manifest.get('avatar_url')
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return manifest
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def create_npu_manifest(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any], is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None, **kwargs) -> Dict[str, Any]:
|
|
336
|
+
"""Create NPU format manifest."""
|
|
337
|
+
|
|
338
|
+
# Load existing manifest to merge NPU files if it exists
|
|
339
|
+
existing_manifest = load_nexa_manifest(directory_path)
|
|
340
|
+
|
|
341
|
+
# Check if there's a downloaded nexa.manifest from the repo
|
|
342
|
+
downloaded_manifest = old_metadata.get('downloaded_manifest', {})
|
|
343
|
+
|
|
344
|
+
model_files = {}
|
|
345
|
+
extra_files = []
|
|
346
|
+
|
|
347
|
+
# Initialize MMProjFile
|
|
348
|
+
mmproj_file = {
|
|
349
|
+
"Name": "",
|
|
350
|
+
"Downloaded": False,
|
|
351
|
+
"Size": 0
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
for current_file_name in files:
|
|
355
|
+
file_path = os.path.join(directory_path, current_file_name)
|
|
356
|
+
file_size = 0
|
|
357
|
+
if os.path.exists(file_path):
|
|
358
|
+
try:
|
|
359
|
+
file_size = os.path.getsize(file_path)
|
|
360
|
+
except (OSError, IOError):
|
|
361
|
+
pass
|
|
362
|
+
|
|
363
|
+
# Check if this file is an mmproj file
|
|
364
|
+
is_current_mmproj = 'mmproj' in current_file_name.lower()
|
|
365
|
+
|
|
366
|
+
# If we're downloading specific files and this is marked as mmproj, respect that
|
|
367
|
+
if is_mmproj and file_name is not None:
|
|
368
|
+
filenames_to_check = file_name if isinstance(file_name, list) else [file_name]
|
|
369
|
+
is_current_mmproj = current_file_name in filenames_to_check
|
|
370
|
+
|
|
371
|
+
if is_current_mmproj:
|
|
372
|
+
# This is an mmproj file, put it in MMProjFile
|
|
373
|
+
mmproj_file = {
|
|
374
|
+
"Name": current_file_name,
|
|
375
|
+
"Downloaded": True,
|
|
376
|
+
"Size": file_size
|
|
377
|
+
}
|
|
378
|
+
else:
|
|
379
|
+
# For NPU, all non-mmproj files go to extra_files
|
|
380
|
+
extra_files.append({
|
|
381
|
+
"Name": current_file_name,
|
|
382
|
+
"Downloaded": True,
|
|
383
|
+
"Size": file_size
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
# Pick the first file from extra_files and add it to ModelFile with key "N/A"
|
|
387
|
+
if extra_files:
|
|
388
|
+
first_file = extra_files[0]
|
|
389
|
+
model_files["N/A"] = {
|
|
390
|
+
"Name": first_file["Name"],
|
|
391
|
+
"Downloaded": first_file["Downloaded"],
|
|
392
|
+
"Size": first_file["Size"]
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
# Determine PluginId with priority: kwargs > downloaded_manifest > model_file_type > default
|
|
396
|
+
plugin_id = kwargs.get('plugin_id')
|
|
397
|
+
if not plugin_id:
|
|
398
|
+
model_file_type = old_metadata.get('model_file_type')
|
|
399
|
+
if downloaded_manifest.get('PluginId'):
|
|
400
|
+
plugin_id = downloaded_manifest.get('PluginId')
|
|
401
|
+
elif model_file_type:
|
|
402
|
+
plugin_id = _get_plugin_id_from_model_file_type(model_file_type)
|
|
403
|
+
else:
|
|
404
|
+
plugin_id = "npu"
|
|
405
|
+
|
|
406
|
+
# Determine ModelType with priority: kwargs > downloaded_manifest > pipeline_tag mapping
|
|
407
|
+
model_type = kwargs.get('model_type')
|
|
408
|
+
if not model_type:
|
|
409
|
+
if downloaded_manifest.get('ModelType'):
|
|
410
|
+
model_type = downloaded_manifest.get('ModelType')
|
|
411
|
+
else:
|
|
412
|
+
model_type = PIPELINE_TO_MODEL_TYPE.get(old_metadata.get('pipeline_tag'), "other")
|
|
413
|
+
|
|
414
|
+
# Determine ModelName with priority: kwargs > downloaded_manifest > empty string
|
|
415
|
+
model_name = kwargs.get('model_name')
|
|
416
|
+
if not model_name:
|
|
417
|
+
model_name = downloaded_manifest.get('ModelName', '')
|
|
418
|
+
|
|
419
|
+
# Get DeviceId and MinSDKVersion from kwargs or default to empty string
|
|
420
|
+
device_id = kwargs.get('device_id', '')
|
|
421
|
+
min_sdk_version = kwargs.get('min_sdk_version', '')
|
|
422
|
+
|
|
236
423
|
manifest = {
|
|
237
424
|
"Name": repo_id,
|
|
238
|
-
"
|
|
239
|
-
"
|
|
425
|
+
"ModelName": model_name,
|
|
426
|
+
"ModelType": model_type,
|
|
427
|
+
"PluginId": plugin_id,
|
|
428
|
+
"DeviceId": device_id,
|
|
429
|
+
"MinSDKVersion": min_sdk_version,
|
|
240
430
|
"ModelFile": model_files,
|
|
241
431
|
"MMProjFile": mmproj_file,
|
|
242
432
|
"TokenizerFile": {
|
|
@@ -254,8 +444,21 @@ def create_mlx_manifest(repo_id: str, files: List[str], directory_path: str, old
|
|
|
254
444
|
return manifest
|
|
255
445
|
|
|
256
446
|
|
|
257
|
-
def detect_model_type(files: List[str]) -> str:
|
|
258
|
-
"""Detect if this is a GGUF or
|
|
447
|
+
def detect_model_type(files: List[str], old_metadata: Dict[str, Any] = None) -> str:
|
|
448
|
+
"""Detect if this is a GGUF, MLX, or NPU model based on file extensions and metadata.
|
|
449
|
+
|
|
450
|
+
Args:
|
|
451
|
+
files: List of files in the model directory
|
|
452
|
+
old_metadata: Metadata dict that may contain 'model_file_type'
|
|
453
|
+
|
|
454
|
+
Returns:
|
|
455
|
+
Model type string: 'gguf', 'mlx', or 'npu'
|
|
456
|
+
"""
|
|
457
|
+
# Check if model_file_type is explicitly set to NPU
|
|
458
|
+
if old_metadata and old_metadata.get('model_file_type') == 'npu':
|
|
459
|
+
return "npu"
|
|
460
|
+
|
|
461
|
+
# Otherwise, detect based on file extensions
|
|
259
462
|
has_gguf = any(f.endswith('.gguf') for f in files)
|
|
260
463
|
has_safetensors = any(f.endswith('.safetensors') or 'safetensors' in f for f in files)
|
|
261
464
|
|
|
@@ -268,7 +471,7 @@ def detect_model_type(files: List[str]) -> str:
|
|
|
268
471
|
return "mlx"
|
|
269
472
|
|
|
270
473
|
|
|
271
|
-
def create_manifest_from_files(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any], is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None) -> Dict[str, Any]:
|
|
474
|
+
def create_manifest_from_files(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any], is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None, **kwargs) -> Dict[str, Any]:
|
|
272
475
|
"""
|
|
273
476
|
Create appropriate manifest format based on detected model type.
|
|
274
477
|
|
|
@@ -276,22 +479,25 @@ def create_manifest_from_files(repo_id: str, files: List[str], directory_path: s
|
|
|
276
479
|
repo_id: Repository ID
|
|
277
480
|
files: List of files in the model directory
|
|
278
481
|
directory_path: Path to the model directory
|
|
279
|
-
old_metadata: Existing metadata (pipeline_tag, download_time, avatar_url)
|
|
482
|
+
old_metadata: Existing metadata (pipeline_tag, download_time, avatar_url, model_file_type)
|
|
280
483
|
is_mmproj: Whether the downloaded file is an mmproj file
|
|
281
484
|
file_name: The specific file(s) that were downloaded (None if entire repo was downloaded)
|
|
485
|
+
**kwargs: Additional metadata including plugin_id, model_name, model_type, device_id, min_sdk_version
|
|
282
486
|
|
|
283
487
|
Returns:
|
|
284
488
|
Dict containing the appropriate manifest format
|
|
285
489
|
"""
|
|
286
|
-
model_type = detect_model_type(files)
|
|
490
|
+
model_type = detect_model_type(files, old_metadata)
|
|
287
491
|
|
|
288
492
|
if model_type == "gguf":
|
|
289
|
-
return create_gguf_manifest(repo_id, files, directory_path, old_metadata, is_mmproj, file_name)
|
|
493
|
+
return create_gguf_manifest(repo_id, files, directory_path, old_metadata, is_mmproj, file_name, **kwargs)
|
|
494
|
+
elif model_type == "npu":
|
|
495
|
+
return create_npu_manifest(repo_id, files, directory_path, old_metadata, is_mmproj, file_name, **kwargs)
|
|
290
496
|
else: # mlx or other
|
|
291
|
-
return create_mlx_manifest(repo_id, files, directory_path, old_metadata, is_mmproj, file_name)
|
|
497
|
+
return create_mlx_manifest(repo_id, files, directory_path, old_metadata, is_mmproj, file_name, **kwargs)
|
|
292
498
|
|
|
293
499
|
|
|
294
|
-
def save_manifest_with_files_metadata(repo_id: str, local_dir: str, old_metadata: Dict[str, Any], is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None) -> None:
|
|
500
|
+
def save_manifest_with_files_metadata(repo_id: str, local_dir: str, old_metadata: Dict[str, Any], is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None, **kwargs) -> None:
|
|
295
501
|
"""
|
|
296
502
|
Create and save manifest based on files found in the directory.
|
|
297
503
|
|
|
@@ -301,6 +507,7 @@ def save_manifest_with_files_metadata(repo_id: str, local_dir: str, old_metadata
|
|
|
301
507
|
old_metadata: Existing metadata to preserve
|
|
302
508
|
is_mmproj: Whether the downloaded file is an mmproj file
|
|
303
509
|
file_name: The specific file(s) that were downloaded (None if entire repo was downloaded)
|
|
510
|
+
**kwargs: Additional metadata including plugin_id, model_name, model_type, device_id, min_sdk_version
|
|
304
511
|
"""
|
|
305
512
|
# Get list of files in the directory
|
|
306
513
|
files = []
|
|
@@ -314,7 +521,7 @@ def save_manifest_with_files_metadata(repo_id: str, local_dir: str, old_metadata
|
|
|
314
521
|
pass
|
|
315
522
|
|
|
316
523
|
# Create appropriate manifest
|
|
317
|
-
manifest = create_manifest_from_files(repo_id, files, local_dir, old_metadata, is_mmproj, file_name)
|
|
524
|
+
manifest = create_manifest_from_files(repo_id, files, local_dir, old_metadata, is_mmproj, file_name, **kwargs)
|
|
318
525
|
|
|
319
526
|
# Save manifest
|
|
320
527
|
save_download_metadata(local_dir, manifest)
|
nexaai/utils/model_manager.py
CHANGED
|
@@ -595,6 +595,7 @@ class HuggingFaceDownloader:
|
|
|
595
595
|
self.enable_transfer = enable_transfer
|
|
596
596
|
self.original_hf_transfer = None
|
|
597
597
|
self.endpoint = endpoint # Store endpoint for avatar fetching
|
|
598
|
+
self._model_info_cache: Dict[str, Any] = {} # Cache for model_info results
|
|
598
599
|
|
|
599
600
|
def _create_repo_directory(self, local_dir: str, repo_id: str) -> str:
|
|
600
601
|
"""Create a directory structure for the repository following HF convention."""
|
|
@@ -618,6 +619,32 @@ class HuggingFaceDownloader:
|
|
|
618
619
|
os.makedirs(local_dir, exist_ok=True)
|
|
619
620
|
return local_dir
|
|
620
621
|
|
|
622
|
+
def _get_model_info_cached(self, repo_id: str, files_metadata: bool = False):
|
|
623
|
+
"""Get model info with caching to avoid rate limiting.
|
|
624
|
+
|
|
625
|
+
Args:
|
|
626
|
+
repo_id: Repository ID
|
|
627
|
+
files_metadata: Whether to include files metadata
|
|
628
|
+
|
|
629
|
+
Returns:
|
|
630
|
+
Model info object from HuggingFace API
|
|
631
|
+
"""
|
|
632
|
+
# Create cache key based on repo_id and files_metadata flag
|
|
633
|
+
cache_key = f"{repo_id}:files={files_metadata}"
|
|
634
|
+
|
|
635
|
+
# Return cached result if available
|
|
636
|
+
if cache_key in self._model_info_cache:
|
|
637
|
+
return self._model_info_cache[cache_key]
|
|
638
|
+
|
|
639
|
+
# Fetch from API and cache the result
|
|
640
|
+
try:
|
|
641
|
+
info = self.api.model_info(repo_id, files_metadata=files_metadata, token=self.token)
|
|
642
|
+
self._model_info_cache[cache_key] = info
|
|
643
|
+
return info
|
|
644
|
+
except Exception:
|
|
645
|
+
# Don't cache errors, re-raise
|
|
646
|
+
raise
|
|
647
|
+
|
|
621
648
|
def _get_repo_info_for_progress(
|
|
622
649
|
self,
|
|
623
650
|
repo_id: str,
|
|
@@ -625,7 +652,7 @@ class HuggingFaceDownloader:
|
|
|
625
652
|
) -> tuple[int, int]:
|
|
626
653
|
"""Get total repository size and file count for progress tracking."""
|
|
627
654
|
try:
|
|
628
|
-
info = self.
|
|
655
|
+
info = self._get_model_info_cached(repo_id, files_metadata=True)
|
|
629
656
|
|
|
630
657
|
total_size = 0
|
|
631
658
|
file_count = 0
|
|
@@ -720,7 +747,7 @@ class HuggingFaceDownloader:
|
|
|
720
747
|
):
|
|
721
748
|
"""Validate repository exists and get info."""
|
|
722
749
|
try:
|
|
723
|
-
info = self.
|
|
750
|
+
info = self._get_model_info_cached(repo_id, files_metadata=False)
|
|
724
751
|
return info
|
|
725
752
|
except RepositoryNotFoundError:
|
|
726
753
|
error_msg = f"Repository '{repo_id}' not found. Please check the repository ID."
|
|
@@ -789,6 +816,36 @@ class HuggingFaceDownloader:
|
|
|
789
816
|
# If no expected size, just check that file is not empty
|
|
790
817
|
return os.path.getsize(file_path) > 0
|
|
791
818
|
|
|
819
|
+
def _extract_model_file_type_from_tags(self, repo_id: str) -> Optional[str]:
|
|
820
|
+
"""Extract model file type from repo tags with priority: NPU > MLX > GGUF."""
|
|
821
|
+
try:
|
|
822
|
+
info = self._get_model_info_cached(repo_id, files_metadata=False)
|
|
823
|
+
if hasattr(info, 'tags') and info.tags:
|
|
824
|
+
# Convert tags to lowercase for case-insensitive matching
|
|
825
|
+
tags_lower = [tag.lower() for tag in info.tags]
|
|
826
|
+
|
|
827
|
+
# Check with priority: NPU > MLX > GGUF
|
|
828
|
+
if 'npu' in tags_lower:
|
|
829
|
+
return 'npu'
|
|
830
|
+
elif 'mlx' in tags_lower:
|
|
831
|
+
return 'mlx'
|
|
832
|
+
elif 'gguf' in tags_lower:
|
|
833
|
+
return 'gguf'
|
|
834
|
+
except Exception:
|
|
835
|
+
pass
|
|
836
|
+
return None
|
|
837
|
+
|
|
838
|
+
def _load_downloaded_manifest(self, local_dir: str) -> Dict[str, Any]:
|
|
839
|
+
"""Load nexa.manifest from the downloaded repository if it exists."""
|
|
840
|
+
manifest_path = os.path.join(local_dir, 'nexa.manifest')
|
|
841
|
+
if os.path.exists(manifest_path):
|
|
842
|
+
try:
|
|
843
|
+
with open(manifest_path, 'r', encoding='utf-8') as f:
|
|
844
|
+
return json.load(f)
|
|
845
|
+
except (json.JSONDecodeError, IOError):
|
|
846
|
+
pass
|
|
847
|
+
return {}
|
|
848
|
+
|
|
792
849
|
def _fetch_and_save_metadata(self, repo_id: str, local_dir: str, is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None, **kwargs) -> None:
|
|
793
850
|
"""Fetch model info and save metadata after successful download."""
|
|
794
851
|
# Initialize metadata with defaults to ensure manifest is always created
|
|
@@ -800,8 +857,8 @@ class HuggingFaceDownloader:
|
|
|
800
857
|
|
|
801
858
|
# Try to fetch additional metadata, but don't let failures prevent manifest creation
|
|
802
859
|
try:
|
|
803
|
-
# Fetch model info to get pipeline_tag
|
|
804
|
-
info = self.
|
|
860
|
+
# Fetch model info to get pipeline_tag (using cache)
|
|
861
|
+
info = self._get_model_info_cached(repo_id, files_metadata=False)
|
|
805
862
|
if hasattr(info, 'pipeline_tag') and info.pipeline_tag:
|
|
806
863
|
old_metadata['pipeline_tag'] = info.pipeline_tag
|
|
807
864
|
except Exception as e:
|
|
@@ -810,11 +867,21 @@ class HuggingFaceDownloader:
|
|
|
810
867
|
|
|
811
868
|
# Use input avater url if provided
|
|
812
869
|
old_metadata['avatar_url'] = kwargs.get('avatar_url')
|
|
870
|
+
|
|
871
|
+
# Extract model file type from tags
|
|
872
|
+
model_file_type = self._extract_model_file_type_from_tags(repo_id)
|
|
873
|
+
if model_file_type:
|
|
874
|
+
old_metadata['model_file_type'] = model_file_type
|
|
875
|
+
|
|
876
|
+
# Load existing nexa.manifest from downloaded repo (if exists)
|
|
877
|
+
downloaded_manifest = self._load_downloaded_manifest(local_dir)
|
|
878
|
+
if downloaded_manifest:
|
|
879
|
+
old_metadata['downloaded_manifest'] = downloaded_manifest
|
|
813
880
|
|
|
814
881
|
|
|
815
882
|
# CRITICAL: Always create the manifest file, regardless of metadata fetch failures
|
|
816
883
|
try:
|
|
817
|
-
save_manifest_with_files_metadata(repo_id, local_dir, old_metadata, is_mmproj, file_name)
|
|
884
|
+
save_manifest_with_files_metadata(repo_id, local_dir, old_metadata, is_mmproj, file_name, **kwargs)
|
|
818
885
|
print(f"[OK] Successfully created nexa.manifest for {repo_id}")
|
|
819
886
|
except Exception as e:
|
|
820
887
|
# This is critical - if manifest creation fails, we should know about it
|
|
@@ -823,8 +890,11 @@ class HuggingFaceDownloader:
|
|
|
823
890
|
try:
|
|
824
891
|
minimal_manifest = {
|
|
825
892
|
"Name": repo_id,
|
|
826
|
-
"
|
|
827
|
-
"
|
|
893
|
+
"ModelName": kwargs.get('model_name', ''),
|
|
894
|
+
"ModelType": kwargs.get('model_type', 'other'),
|
|
895
|
+
"PluginId": kwargs.get('plugin_id', 'unknown'),
|
|
896
|
+
"DeviceId": kwargs.get('device_id', ''),
|
|
897
|
+
"MinSDKVersion": kwargs.get('min_sdk_version', ''),
|
|
828
898
|
"ModelFile": {},
|
|
829
899
|
"MMProjFile": {"Name": "", "Downloaded": False, "Size": 0},
|
|
830
900
|
"TokenizerFile": {"Name": "", "Downloaded": False, "Size": 0},
|
|
@@ -1136,6 +1206,12 @@ def download_from_huggingface(
|
|
|
1136
1206
|
is_mmproj (bool, optional): Whether the file being downloaded is an mmproj file. Only used when
|
|
1137
1207
|
file_name is not None. If None, defaults to True if 'mmproj' is in
|
|
1138
1208
|
the filename, False otherwise.
|
|
1209
|
+
**kwargs: Additional parameters including:
|
|
1210
|
+
- plugin_id (str): Override PluginId in nexa.manifest (highest priority)
|
|
1211
|
+
- model_name (str): Override ModelName in nexa.manifest (highest priority)
|
|
1212
|
+
- model_type (str): Override ModelType in nexa.manifest (highest priority)
|
|
1213
|
+
- device_id (str): Set DeviceId in nexa.manifest (highest priority)
|
|
1214
|
+
- min_sdk_version (str): Set MinSDKVersion in nexa.manifest (highest priority)
|
|
1139
1215
|
|
|
1140
1216
|
Returns:
|
|
1141
1217
|
str: Path to the downloaded file or directory
|
nexaai/utils/model_types.py
CHANGED
|
@@ -13,6 +13,8 @@ class ModelTypeMapping(Enum):
|
|
|
13
13
|
"""Enum for mapping HuggingFace pipeline_tag to our ModelType."""
|
|
14
14
|
TEXT_GENERATION = ("text-generation", "llm")
|
|
15
15
|
IMAGE_TEXT_TO_TEXT = ("image-text-to-text", "vlm")
|
|
16
|
+
ANY_TO_ANY = ("any-to-any", "ata")
|
|
17
|
+
AUTOMATIC_SPEECH_RECOGNITION = ("automatic-speech-recognition", "asr")
|
|
16
18
|
|
|
17
19
|
def __init__(self, pipeline_tag: str, model_type: str):
|
|
18
20
|
self.pipeline_tag = pipeline_tag
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
nexaai/__init__.py,sha256=mbzzeXrEHHI_E3BQ0_OukD9wNajKJJVk0ykxT0rz8uM,2267
|
|
2
|
-
nexaai/_stub.cp310-win_amd64.pyd,sha256=
|
|
3
|
-
nexaai/_version.py,sha256=
|
|
2
|
+
nexaai/_stub.cp310-win_amd64.pyd,sha256=zIM70Tbkrp9mqaDcx3zqzwZFrDadwwWqH4vPMg_c7LE,10752
|
|
3
|
+
nexaai/_version.py,sha256=xFTKTqHsqiHFmS11AE7zPpRDLT7x9fF0oXMGA8Zz1tE,147
|
|
4
4
|
nexaai/asr.py,sha256=_fsGaxpiU137bUtO5ujtFSYCI1RLsyeEm3Gf4GhHVRk,2118
|
|
5
5
|
nexaai/base.py,sha256=qQBCiQVNzgpkQjZX9aiFDEdbAAe56TROKC3WnWra2Zg,1021
|
|
6
6
|
nexaai/common.py,sha256=muQqFY-WllwL5IO83tImexbuUcoEQsKg73u4gWL2lNs,3548
|
|
@@ -17,29 +17,29 @@ nexaai/asr_impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
17
17
|
nexaai/asr_impl/mlx_asr_impl.py,sha256=XwMX3LYMeulp8cDS0TCCYcjvttFHAyDWQ_oMvABwQmI,3349
|
|
18
18
|
nexaai/asr_impl/pybind_asr_impl.py,sha256=20o5SOPzhF9x41ra8L_qIM7YxCkYeLb5csSrNde-dds,1560
|
|
19
19
|
nexaai/binds/__init__.py,sha256=ENl-uoIF9-3XGIXitVgZ2QmJ6p7Yet4h1-X7nUDZ0Hk,108
|
|
20
|
-
nexaai/binds/common_bind.cp310-win_amd64.pyd,sha256=
|
|
21
|
-
nexaai/binds/embedder_bind.cp310-win_amd64.pyd,sha256=
|
|
20
|
+
nexaai/binds/common_bind.cp310-win_amd64.pyd,sha256=C9cPLDyWJxxN1N_E2moZid1Wmzkf9p9fCEhgaaQfXTM,205824
|
|
21
|
+
nexaai/binds/embedder_bind.cp310-win_amd64.pyd,sha256=zf9wF_ZHl0ZNbiioifymc3cHshnJ5uLcTd0t2uMt-bY,182784
|
|
22
22
|
nexaai/binds/libcrypto-3-x64.dll,sha256=X7hDuQPMn6eRe58dTGJxTmRPKFWgd5i6Gjoy9QPLmPg,7315968
|
|
23
23
|
nexaai/binds/libssl-3-x64.dll,sha256=GRw0cOaGUaR2QHRvBFuU_9S9iNgkyVgm0NIpZMnReAw,1313792
|
|
24
|
-
nexaai/binds/llm_bind.cp310-win_amd64.pyd,sha256=
|
|
25
|
-
nexaai/binds/nexa_bridge.dll,sha256=
|
|
26
|
-
nexaai/binds/vlm_bind.cp310-win_amd64.pyd,sha256=
|
|
27
|
-
nexaai/binds/nexa_llama_cpp/ggml-base.dll,sha256=
|
|
28
|
-
nexaai/binds/nexa_llama_cpp/ggml-cpu.dll,sha256=
|
|
29
|
-
nexaai/binds/nexa_llama_cpp/ggml-cuda.dll,sha256=
|
|
30
|
-
nexaai/binds/nexa_llama_cpp/ggml-vulkan.dll,sha256=
|
|
31
|
-
nexaai/binds/nexa_llama_cpp/ggml.dll,sha256=
|
|
32
|
-
nexaai/binds/nexa_llama_cpp/llama.dll,sha256=
|
|
33
|
-
nexaai/binds/nexa_llama_cpp/mtmd.dll,sha256=
|
|
34
|
-
nexaai/binds/nexa_llama_cpp/nexa_plugin.dll,sha256=
|
|
35
|
-
nexaai/binds/nexa_nexaml/ggml-base.dll,sha256=
|
|
36
|
-
nexaai/binds/nexa_nexaml/ggml-cpu.dll,sha256=
|
|
37
|
-
nexaai/binds/nexa_nexaml/ggml-cuda.dll,sha256=
|
|
38
|
-
nexaai/binds/nexa_nexaml/ggml-vulkan.dll,sha256=
|
|
39
|
-
nexaai/binds/nexa_nexaml/ggml.dll,sha256=
|
|
24
|
+
nexaai/binds/llm_bind.cp310-win_amd64.pyd,sha256=NL-Jg-yC5JnI-jvVbL2i4UHNp-trEOanuqYzK6GRU3A,162816
|
|
25
|
+
nexaai/binds/nexa_bridge.dll,sha256=BdWmJM61sWqh65Ej6bhNOOok8OXy8zpb1EhZLCa__QI,173568
|
|
26
|
+
nexaai/binds/vlm_bind.cp310-win_amd64.pyd,sha256=10IXagWNoatpcUR8ZA0BC2gsK1zaD9b602IPV9nIBVM,168960
|
|
27
|
+
nexaai/binds/nexa_llama_cpp/ggml-base.dll,sha256=W0NpwMFho6U2Bx-lMhmtRL0MNZsda9RYN1S5xdek_1Y,534528
|
|
28
|
+
nexaai/binds/nexa_llama_cpp/ggml-cpu.dll,sha256=iJqvUGbdEgk32EooRNQ_RBEkGkvG5_flEklL80z1sAA,699904
|
|
29
|
+
nexaai/binds/nexa_llama_cpp/ggml-cuda.dll,sha256=6C6rwh6lKdEmya-Zk_r-X0K_SgJ0Y3D4DPKs4RG9QaA,339632128
|
|
30
|
+
nexaai/binds/nexa_llama_cpp/ggml-vulkan.dll,sha256=2jwqgP5QRhoZQOD9-BqtRYXKLzRtkdT2ebH6QfyiPTc,38050816
|
|
31
|
+
nexaai/binds/nexa_llama_cpp/ggml.dll,sha256=VFNSdaeVnkpqvdDIxWDzIpkXo177IrGzU9KhjnSYE7o,66560
|
|
32
|
+
nexaai/binds/nexa_llama_cpp/llama.dll,sha256=iKEeyvmAw77GkPTcAaaozMU7UjddTuqoGIvbL426rz4,1649664
|
|
33
|
+
nexaai/binds/nexa_llama_cpp/mtmd.dll,sha256=VfgsUlUrCKwG4_gKxvUTigjcs0m9k6Spi_-osLecw4k,565248
|
|
34
|
+
nexaai/binds/nexa_llama_cpp/nexa_plugin.dll,sha256=q_3N5dZd3DWoaIDvdIPsBwjhNOaW96UDGaFU6oB1bCI,1420800
|
|
35
|
+
nexaai/binds/nexa_nexaml/ggml-base.dll,sha256=W0NpwMFho6U2Bx-lMhmtRL0MNZsda9RYN1S5xdek_1Y,534528
|
|
36
|
+
nexaai/binds/nexa_nexaml/ggml-cpu.dll,sha256=iJqvUGbdEgk32EooRNQ_RBEkGkvG5_flEklL80z1sAA,699904
|
|
37
|
+
nexaai/binds/nexa_nexaml/ggml-cuda.dll,sha256=6C6rwh6lKdEmya-Zk_r-X0K_SgJ0Y3D4DPKs4RG9QaA,339632128
|
|
38
|
+
nexaai/binds/nexa_nexaml/ggml-vulkan.dll,sha256=2jwqgP5QRhoZQOD9-BqtRYXKLzRtkdT2ebH6QfyiPTc,38050816
|
|
39
|
+
nexaai/binds/nexa_nexaml/ggml.dll,sha256=VFNSdaeVnkpqvdDIxWDzIpkXo177IrGzU9KhjnSYE7o,66560
|
|
40
40
|
nexaai/binds/nexa_nexaml/nexa-mm-process.dll,sha256=oDnqTaAUeZrWJePQEDuIYKEOMP-ndu221mMFHht4bSY,4642816
|
|
41
41
|
nexaai/binds/nexa_nexaml/nexa-sampling.dll,sha256=PNtidsRbGO8dTfbf7-VMdhQRbF328yvLnmDjMy2Tb7Y,4265984
|
|
42
|
-
nexaai/binds/nexa_nexaml/nexa_plugin.dll,sha256=
|
|
42
|
+
nexaai/binds/nexa_nexaml/nexa_plugin.dll,sha256=hlMcnpXR5ZdYJ3fBd_kz8zRmq_BGewwqEA1VPGr6N2A,602112
|
|
43
43
|
nexaai/binds/nexa_nexaml/nexaproc.dll,sha256=9X4TF6p7wOiIXi_SA7uHLoEmrvcTlH2WpfijK7HxZgY,2668544
|
|
44
44
|
nexaai/binds/nexa_nexaml/qwen3-vl.dll,sha256=Es-etUDiMmK_BwOki8V79Nja-NY4kBbrkhtnesXfMMU,5870592
|
|
45
45
|
nexaai/binds/nexa_nexaml/qwen3vl-vision.dll,sha256=HFAk0FxWlf_lko3AQL6uBXTIhm6AzDFi5PjxI0lxONI,1184256
|
|
@@ -62,15 +62,15 @@ nexaai/tts_impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
62
62
|
nexaai/tts_impl/mlx_tts_impl.py,sha256=LcH9bVdIl3Q6lOzSUB_X2s-_nWFmlCl1yL7XSUK0fYI,3195
|
|
63
63
|
nexaai/tts_impl/pybind_tts_impl.py,sha256=n3z4zmPQayQJgAwcvETw0IBUCp8IYROuYFSg0tAy_8Y,1487
|
|
64
64
|
nexaai/utils/decode.py,sha256=0Z9jDH4ICzw4YXj8nD4L-sMouDaev-TISGRQ4KzidWE,421
|
|
65
|
-
nexaai/utils/manifest_utils.py,sha256=
|
|
66
|
-
nexaai/utils/model_manager.py,sha256=
|
|
67
|
-
nexaai/utils/model_types.py,sha256=
|
|
65
|
+
nexaai/utils/manifest_utils.py,sha256=E07t_bNq-EDrqVYZW7uyX8zsKsFklvqqwSvic0in0tQ,21800
|
|
66
|
+
nexaai/utils/model_manager.py,sha256=qzlGP4sZLYsO72vg-EUCVA0RUknVKtLYMmDDfPmG45g,60999
|
|
67
|
+
nexaai/utils/model_types.py,sha256=q2m7diYLOpLvRl1ixL2eMq5_kdTj8KqPBGWX4p6Ob08,1532
|
|
68
68
|
nexaai/utils/progress_tracker.py,sha256=BztrFqtjwNUmeREwZ5m7H6ZcrVzQEbpZfsxndWh4z0A,15778
|
|
69
69
|
nexaai/utils/quantization_utils.py,sha256=FxnZ6-uAE_bl_vQ5jsRXlpU0NBn-U4Y8iN9_O6aCdPA,8070
|
|
70
70
|
nexaai/vlm_impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
71
|
nexaai/vlm_impl/mlx_vlm_impl.py,sha256=MgqJO7OzuPd79gOZZKhSXXMNSP2eBuhhrdCX8XHn6aQ,11090
|
|
72
72
|
nexaai/vlm_impl/pybind_vlm_impl.py,sha256=NuQ_Ep1TnjmGAkjJuUS0Lb6z7iPu3wroLVOx7kiAwlE,8827
|
|
73
|
-
nexaai-1.0.
|
|
74
|
-
nexaai-1.0.
|
|
75
|
-
nexaai-1.0.
|
|
76
|
-
nexaai-1.0.
|
|
73
|
+
nexaai-1.0.19rc7.dist-info/METADATA,sha256=Oi-IEJ-LoN_XTayfu_mRxglBDbRtxwT8GDZjbpeHVVg,1233
|
|
74
|
+
nexaai-1.0.19rc7.dist-info/WHEEL,sha256=KUuBC6lxAbHCKilKua8R9W_TM71_-9Sg5uEP3uDWcoU,101
|
|
75
|
+
nexaai-1.0.19rc7.dist-info/top_level.txt,sha256=LRE2YERlrZk2vfuygnSzsEeqSknnZbz3Z1MHyNmBU4w,7
|
|
76
|
+
nexaai-1.0.19rc7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|