nexaai 1.0.12rc1__cp310-cp310-macosx_13_0_x86_64.whl → 1.0.13rc2__cp310-cp310-macosx_13_0_x86_64.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.cpython-310-darwin.so +0 -0
- nexaai/_version.py +1 -1
- nexaai/binds/__init__.py +1 -0
- nexaai/binds/libnexa_bridge.dylib +0 -0
- nexaai/binds/nexa_llama_cpp/libnexa_plugin.dylib +0 -0
- nexaai/binds/vlm_bind.cpython-310-darwin.so +0 -0
- nexaai/utils/manifest_utils.py +78 -34
- nexaai/utils/model_manager.py +202 -60
- nexaai/vlm_impl/pybind_vlm_impl.py +6 -17
- {nexaai-1.0.12rc1.dist-info → nexaai-1.0.13rc2.dist-info}/METADATA +1 -1
- {nexaai-1.0.12rc1.dist-info → nexaai-1.0.13rc2.dist-info}/RECORD +13 -14
- nexaai/binds/libcrypto.dylib +0 -0
- nexaai/binds/libssl.dylib +0 -0
- {nexaai-1.0.12rc1.dist-info → nexaai-1.0.13rc2.dist-info}/WHEEL +0 -0
- {nexaai-1.0.12rc1.dist-info → nexaai-1.0.13rc2.dist-info}/top_level.txt +0 -0
|
Binary file
|
nexaai/_version.py
CHANGED
nexaai/binds/__init__.py
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
nexaai/utils/manifest_utils.py
CHANGED
|
@@ -11,7 +11,7 @@ This module provides utilities to:
|
|
|
11
11
|
import os
|
|
12
12
|
import json
|
|
13
13
|
from datetime import datetime
|
|
14
|
-
from typing import Dict, Any, List, Optional
|
|
14
|
+
from typing import Dict, Any, List, Optional, Union
|
|
15
15
|
|
|
16
16
|
from .quantization_utils import (
|
|
17
17
|
extract_quantization_from_filename,
|
|
@@ -101,7 +101,7 @@ def save_download_metadata(directory_path: str, metadata: Dict[str, Any]) -> Non
|
|
|
101
101
|
pass
|
|
102
102
|
|
|
103
103
|
|
|
104
|
-
def create_gguf_manifest(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any]) -> Dict[str, Any]:
|
|
104
|
+
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) -> Dict[str, Any]:
|
|
105
105
|
"""Create GGUF format manifest."""
|
|
106
106
|
|
|
107
107
|
# Load existing manifest to merge GGUF files if it exists
|
|
@@ -111,14 +111,27 @@ def create_gguf_manifest(repo_id: str, files: List[str], directory_path: str, ol
|
|
|
111
111
|
if existing_manifest and "ModelFile" in existing_manifest:
|
|
112
112
|
model_files = existing_manifest["ModelFile"].copy()
|
|
113
113
|
|
|
114
|
+
# Initialize MMProjFile from existing manifest or empty
|
|
115
|
+
mmproj_file = {
|
|
116
|
+
"Name": "",
|
|
117
|
+
"Downloaded": False,
|
|
118
|
+
"Size": 0
|
|
119
|
+
}
|
|
120
|
+
if existing_manifest and "MMProjFile" in existing_manifest:
|
|
121
|
+
mmproj_file = existing_manifest["MMProjFile"].copy()
|
|
122
|
+
|
|
114
123
|
# Process GGUF files
|
|
115
|
-
for
|
|
116
|
-
if
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
for current_file_name in files:
|
|
125
|
+
if current_file_name.endswith('.gguf'):
|
|
126
|
+
# Check if this file is an mmproj file
|
|
127
|
+
is_current_mmproj = 'mmproj' in current_file_name.lower()
|
|
128
|
+
|
|
129
|
+
# If we're downloading specific files and this is marked as mmproj, respect that
|
|
130
|
+
if is_mmproj and file_name is not None:
|
|
131
|
+
filenames_to_check = file_name if isinstance(file_name, list) else [file_name]
|
|
132
|
+
is_current_mmproj = current_file_name in filenames_to_check
|
|
120
133
|
|
|
121
|
-
file_path = os.path.join(directory_path,
|
|
134
|
+
file_path = os.path.join(directory_path, current_file_name)
|
|
122
135
|
file_size = 0
|
|
123
136
|
if os.path.exists(file_path):
|
|
124
137
|
try:
|
|
@@ -126,22 +139,31 @@ def create_gguf_manifest(repo_id: str, files: List[str], directory_path: str, ol
|
|
|
126
139
|
except (OSError, IOError):
|
|
127
140
|
pass
|
|
128
141
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
142
|
+
if is_current_mmproj:
|
|
143
|
+
# This is an mmproj file, put it in MMProjFile
|
|
144
|
+
mmproj_file = {
|
|
145
|
+
"Name": current_file_name,
|
|
146
|
+
"Downloaded": True,
|
|
147
|
+
"Size": file_size
|
|
148
|
+
}
|
|
149
|
+
else:
|
|
150
|
+
# Regular model file, put in ModelFile
|
|
151
|
+
# Use the new enum-based quantization extraction
|
|
152
|
+
quantization_type = extract_quantization_from_filename(current_file_name)
|
|
153
|
+
quant_level = quantization_type.value if quantization_type else "UNKNOWN"
|
|
154
|
+
|
|
155
|
+
model_files[quant_level] = {
|
|
156
|
+
"Name": current_file_name,
|
|
157
|
+
"Downloaded": True,
|
|
158
|
+
"Size": file_size
|
|
159
|
+
}
|
|
134
160
|
|
|
135
161
|
manifest = {
|
|
136
162
|
"Name": repo_id,
|
|
137
163
|
"ModelType": PIPELINE_TO_MODEL_TYPE.get(old_metadata.get('pipeline_tag'), "other"),
|
|
138
164
|
"PluginId": "llama_cpp",
|
|
139
165
|
"ModelFile": model_files,
|
|
140
|
-
"MMProjFile":
|
|
141
|
-
"Name": "",
|
|
142
|
-
"Downloaded": False,
|
|
143
|
-
"Size": 0
|
|
144
|
-
},
|
|
166
|
+
"MMProjFile": mmproj_file,
|
|
145
167
|
"TokenizerFile": {
|
|
146
168
|
"Name": "",
|
|
147
169
|
"Downloaded": False,
|
|
@@ -157,20 +179,27 @@ def create_gguf_manifest(repo_id: str, files: List[str], directory_path: str, ol
|
|
|
157
179
|
return manifest
|
|
158
180
|
|
|
159
181
|
|
|
160
|
-
def create_mlx_manifest(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any]) -> Dict[str, Any]:
|
|
182
|
+
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]:
|
|
161
183
|
"""Create MLX format manifest."""
|
|
162
184
|
|
|
163
185
|
model_files = {}
|
|
164
186
|
extra_files = []
|
|
165
187
|
|
|
188
|
+
# Initialize MMProjFile
|
|
189
|
+
mmproj_file = {
|
|
190
|
+
"Name": "",
|
|
191
|
+
"Downloaded": False,
|
|
192
|
+
"Size": 0
|
|
193
|
+
}
|
|
194
|
+
|
|
166
195
|
# Try different methods to extract quantization for MLX models
|
|
167
196
|
quantization_type = detect_quantization_for_mlx(repo_id, directory_path)
|
|
168
197
|
|
|
169
198
|
# Use the detected quantization or default to "DEFAULT"
|
|
170
199
|
quant_level = quantization_type.value if quantization_type else "DEFAULT"
|
|
171
200
|
|
|
172
|
-
for
|
|
173
|
-
file_path = os.path.join(directory_path,
|
|
201
|
+
for current_file_name in files:
|
|
202
|
+
file_path = os.path.join(directory_path, current_file_name)
|
|
174
203
|
file_size = 0
|
|
175
204
|
if os.path.exists(file_path):
|
|
176
205
|
try:
|
|
@@ -178,17 +207,32 @@ def create_mlx_manifest(repo_id: str, files: List[str], directory_path: str, old
|
|
|
178
207
|
except (OSError, IOError):
|
|
179
208
|
pass
|
|
180
209
|
|
|
210
|
+
# Check if this file is an mmproj file
|
|
211
|
+
is_current_mmproj = 'mmproj' in current_file_name.lower()
|
|
212
|
+
|
|
213
|
+
# If we're downloading specific files and this is marked as mmproj, respect that
|
|
214
|
+
if is_mmproj and file_name is not None:
|
|
215
|
+
filenames_to_check = file_name if isinstance(file_name, list) else [file_name]
|
|
216
|
+
is_current_mmproj = current_file_name in filenames_to_check
|
|
217
|
+
|
|
218
|
+
if is_current_mmproj:
|
|
219
|
+
# This is an mmproj file, put it in MMProjFile
|
|
220
|
+
mmproj_file = {
|
|
221
|
+
"Name": current_file_name,
|
|
222
|
+
"Downloaded": True,
|
|
223
|
+
"Size": file_size
|
|
224
|
+
}
|
|
181
225
|
# Check if this is a main model file (safetensors but not index files)
|
|
182
|
-
|
|
226
|
+
elif (current_file_name.endswith('.safetensors') and not current_file_name.endswith('.index.json')):
|
|
183
227
|
model_files[quant_level] = {
|
|
184
|
-
"Name":
|
|
228
|
+
"Name": current_file_name,
|
|
185
229
|
"Downloaded": True,
|
|
186
230
|
"Size": file_size
|
|
187
231
|
}
|
|
188
232
|
else:
|
|
189
233
|
# Add to extra files
|
|
190
234
|
extra_files.append({
|
|
191
|
-
"Name":
|
|
235
|
+
"Name": current_file_name,
|
|
192
236
|
"Downloaded": True,
|
|
193
237
|
"Size": file_size
|
|
194
238
|
})
|
|
@@ -198,11 +242,7 @@ def create_mlx_manifest(repo_id: str, files: List[str], directory_path: str, old
|
|
|
198
242
|
"ModelType": PIPELINE_TO_MODEL_TYPE.get(old_metadata.get('pipeline_tag'), "other"),
|
|
199
243
|
"PluginId": "mlx",
|
|
200
244
|
"ModelFile": model_files,
|
|
201
|
-
"MMProjFile":
|
|
202
|
-
"Name": "",
|
|
203
|
-
"Downloaded": False,
|
|
204
|
-
"Size": 0
|
|
205
|
-
},
|
|
245
|
+
"MMProjFile": mmproj_file,
|
|
206
246
|
"TokenizerFile": {
|
|
207
247
|
"Name": "",
|
|
208
248
|
"Downloaded": False,
|
|
@@ -232,7 +272,7 @@ def detect_model_type(files: List[str]) -> str:
|
|
|
232
272
|
return "mlx"
|
|
233
273
|
|
|
234
274
|
|
|
235
|
-
def create_manifest_from_files(repo_id: str, files: List[str], directory_path: str, old_metadata: Dict[str, Any]) -> Dict[str, Any]:
|
|
275
|
+
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]:
|
|
236
276
|
"""
|
|
237
277
|
Create appropriate manifest format based on detected model type.
|
|
238
278
|
|
|
@@ -241,6 +281,8 @@ def create_manifest_from_files(repo_id: str, files: List[str], directory_path: s
|
|
|
241
281
|
files: List of files in the model directory
|
|
242
282
|
directory_path: Path to the model directory
|
|
243
283
|
old_metadata: Existing metadata (pipeline_tag, download_time, avatar_url)
|
|
284
|
+
is_mmproj: Whether the downloaded file is an mmproj file
|
|
285
|
+
file_name: The specific file(s) that were downloaded (None if entire repo was downloaded)
|
|
244
286
|
|
|
245
287
|
Returns:
|
|
246
288
|
Dict containing the appropriate manifest format
|
|
@@ -248,12 +290,12 @@ def create_manifest_from_files(repo_id: str, files: List[str], directory_path: s
|
|
|
248
290
|
model_type = detect_model_type(files)
|
|
249
291
|
|
|
250
292
|
if model_type == "gguf":
|
|
251
|
-
return create_gguf_manifest(repo_id, files, directory_path, old_metadata)
|
|
293
|
+
return create_gguf_manifest(repo_id, files, directory_path, old_metadata, is_mmproj, file_name)
|
|
252
294
|
else: # mlx or other
|
|
253
|
-
return create_mlx_manifest(repo_id, files, directory_path, old_metadata)
|
|
295
|
+
return create_mlx_manifest(repo_id, files, directory_path, old_metadata, is_mmproj, file_name)
|
|
254
296
|
|
|
255
297
|
|
|
256
|
-
def save_manifest_with_files_metadata(repo_id: str, local_dir: str, old_metadata: Dict[str, Any]) -> None:
|
|
298
|
+
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:
|
|
257
299
|
"""
|
|
258
300
|
Create and save manifest based on files found in the directory.
|
|
259
301
|
|
|
@@ -261,6 +303,8 @@ def save_manifest_with_files_metadata(repo_id: str, local_dir: str, old_metadata
|
|
|
261
303
|
repo_id: Repository ID
|
|
262
304
|
local_dir: Local directory containing the model files
|
|
263
305
|
old_metadata: Existing metadata to preserve
|
|
306
|
+
is_mmproj: Whether the downloaded file is an mmproj file
|
|
307
|
+
file_name: The specific file(s) that were downloaded (None if entire repo was downloaded)
|
|
264
308
|
"""
|
|
265
309
|
# Get list of files in the directory
|
|
266
310
|
files = []
|
|
@@ -274,7 +318,7 @@ def save_manifest_with_files_metadata(repo_id: str, local_dir: str, old_metadata
|
|
|
274
318
|
pass
|
|
275
319
|
|
|
276
320
|
# Create appropriate manifest
|
|
277
|
-
manifest = create_manifest_from_files(repo_id, files, local_dir, old_metadata)
|
|
321
|
+
manifest = create_manifest_from_files(repo_id, files, local_dir, old_metadata, is_mmproj, file_name)
|
|
278
322
|
|
|
279
323
|
# Save manifest
|
|
280
324
|
save_download_metadata(local_dir, manifest)
|
nexaai/utils/model_manager.py
CHANGED
|
@@ -21,6 +21,13 @@ from .manifest_utils import (
|
|
|
21
21
|
# Default path for model storage
|
|
22
22
|
DEFAULT_MODEL_SAVING_PATH = "~/.cache/nexa.ai/nexa_sdk/models/"
|
|
23
23
|
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class MMProjInfo:
|
|
27
|
+
"""Data class for mmproj file information."""
|
|
28
|
+
mmproj_path: Optional[str] = None
|
|
29
|
+
size: int = 0
|
|
30
|
+
|
|
24
31
|
@dataclass
|
|
25
32
|
class DownloadedModel:
|
|
26
33
|
"""Data class representing a downloaded model with all its metadata."""
|
|
@@ -34,6 +41,7 @@ class DownloadedModel:
|
|
|
34
41
|
pipeline_tag: Optional[str] = None # Pipeline tag from HuggingFace model info
|
|
35
42
|
download_time: Optional[str] = None # ISO format timestamp of download
|
|
36
43
|
avatar_url: Optional[str] = None # Avatar URL for the model author
|
|
44
|
+
mmproj_info: Optional[MMProjInfo] = None # mmproj file information
|
|
37
45
|
|
|
38
46
|
def to_dict(self) -> Dict[str, Any]:
|
|
39
47
|
"""Convert to dictionary format for backward compatibility."""
|
|
@@ -47,7 +55,11 @@ class DownloadedModel:
|
|
|
47
55
|
'full_repo_download_complete': self.full_repo_download_complete,
|
|
48
56
|
'pipeline_tag': self.pipeline_tag,
|
|
49
57
|
'download_time': self.download_time,
|
|
50
|
-
'avatar_url': self.avatar_url
|
|
58
|
+
'avatar_url': self.avatar_url,
|
|
59
|
+
'mmproj_info': {
|
|
60
|
+
'mmproj_path': self.mmproj_info.mmproj_path,
|
|
61
|
+
'size': self.mmproj_info.size
|
|
62
|
+
} if self.mmproj_info else None
|
|
51
63
|
}
|
|
52
64
|
return result
|
|
53
65
|
|
|
@@ -125,6 +137,46 @@ def _has_valid_metadata(directory_path: str) -> bool:
|
|
|
125
137
|
return os.path.exists(manifest_path) or os.path.exists(old_metadata_path)
|
|
126
138
|
|
|
127
139
|
|
|
140
|
+
def _extract_mmproj_info(manifest: Dict[str, Any], local_path: str) -> Optional[MMProjInfo]:
|
|
141
|
+
"""
|
|
142
|
+
Extract mmproj information from manifest data.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
manifest: Dictionary containing manifest data
|
|
146
|
+
local_path: Local path to the model directory
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
MMProjInfo object if mmproj file exists, None otherwise
|
|
150
|
+
"""
|
|
151
|
+
# Check if manifest has MMProjFile information
|
|
152
|
+
mmproj_file_info = manifest.get('MMProjFile')
|
|
153
|
+
if not mmproj_file_info or not mmproj_file_info.get('Downloaded') or not mmproj_file_info.get('Name'):
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
mmproj_filename = mmproj_file_info.get('Name', '')
|
|
157
|
+
if not mmproj_filename:
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
# Construct full path to mmproj file
|
|
161
|
+
mmproj_path = os.path.join(local_path, mmproj_filename)
|
|
162
|
+
|
|
163
|
+
# Get size from manifest, but verify file exists
|
|
164
|
+
mmproj_size = mmproj_file_info.get('Size', 0)
|
|
165
|
+
if os.path.exists(mmproj_path):
|
|
166
|
+
try:
|
|
167
|
+
# Verify size matches actual file size
|
|
168
|
+
actual_size = os.path.getsize(mmproj_path)
|
|
169
|
+
mmproj_size = actual_size # Use actual size if different
|
|
170
|
+
except (OSError, IOError):
|
|
171
|
+
# If we can't get actual size, use size from manifest
|
|
172
|
+
pass
|
|
173
|
+
else:
|
|
174
|
+
# File doesn't exist, don't include mmproj info
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
return MMProjInfo(mmproj_path=mmproj_path, size=mmproj_size)
|
|
178
|
+
|
|
179
|
+
|
|
128
180
|
def _scan_for_repo_folders(base_path: str) -> List[DownloadedModel]:
|
|
129
181
|
"""Scan a directory for repository folders and return model information."""
|
|
130
182
|
models = []
|
|
@@ -159,6 +211,10 @@ def _scan_for_repo_folders(base_path: str) -> List[DownloadedModel]:
|
|
|
159
211
|
# Load metadata if it exists
|
|
160
212
|
repo_id = f"{item}/{subitem}"
|
|
161
213
|
metadata = load_download_metadata(subitem_path, repo_id)
|
|
214
|
+
|
|
215
|
+
# Extract mmproj information
|
|
216
|
+
mmproj_info = _extract_mmproj_info(metadata, subitem_path)
|
|
217
|
+
|
|
162
218
|
models.append(DownloadedModel(
|
|
163
219
|
repo_id=repo_id,
|
|
164
220
|
files=files,
|
|
@@ -169,7 +225,8 @@ def _scan_for_repo_folders(base_path: str) -> List[DownloadedModel]:
|
|
|
169
225
|
full_repo_download_complete=download_complete,
|
|
170
226
|
pipeline_tag=metadata.get('pipeline_tag'),
|
|
171
227
|
download_time=metadata.get('download_time'),
|
|
172
|
-
avatar_url=metadata.get('avatar_url')
|
|
228
|
+
avatar_url=metadata.get('avatar_url'),
|
|
229
|
+
mmproj_info=mmproj_info
|
|
173
230
|
))
|
|
174
231
|
else:
|
|
175
232
|
direct_files.append(subitem)
|
|
@@ -188,6 +245,10 @@ def _scan_for_repo_folders(base_path: str) -> List[DownloadedModel]:
|
|
|
188
245
|
# Load metadata if it exists
|
|
189
246
|
repo_id = item
|
|
190
247
|
metadata = load_download_metadata(item_path, repo_id)
|
|
248
|
+
|
|
249
|
+
# Extract mmproj information
|
|
250
|
+
mmproj_info = _extract_mmproj_info(metadata, item_path)
|
|
251
|
+
|
|
191
252
|
models.append(DownloadedModel(
|
|
192
253
|
repo_id=repo_id,
|
|
193
254
|
files=files,
|
|
@@ -198,7 +259,8 @@ def _scan_for_repo_folders(base_path: str) -> List[DownloadedModel]:
|
|
|
198
259
|
full_repo_download_complete=download_complete,
|
|
199
260
|
pipeline_tag=metadata.get('pipeline_tag'),
|
|
200
261
|
download_time=metadata.get('download_time'),
|
|
201
|
-
avatar_url=metadata.get('avatar_url')
|
|
262
|
+
avatar_url=metadata.get('avatar_url'),
|
|
263
|
+
mmproj_info=mmproj_info
|
|
202
264
|
))
|
|
203
265
|
|
|
204
266
|
except (OSError, IOError):
|
|
@@ -236,6 +298,7 @@ def list_downloaded_models(local_dir: Optional[str] = None) -> List[DownloadedMo
|
|
|
236
298
|
- pipeline_tag: Optional[str] - Pipeline tag from HuggingFace model info
|
|
237
299
|
- download_time: Optional[str] - ISO format timestamp when the model was downloaded
|
|
238
300
|
- avatar_url: Optional[str] - Avatar URL for the model author
|
|
301
|
+
- mmproj_info: Optional[MMProjInfo] - mmproj file information with mmproj_path and size
|
|
239
302
|
"""
|
|
240
303
|
|
|
241
304
|
# Set up local directory
|
|
@@ -727,7 +790,7 @@ class HuggingFaceDownloader:
|
|
|
727
790
|
# If no expected size, just check that file is not empty
|
|
728
791
|
return os.path.getsize(file_path) > 0
|
|
729
792
|
|
|
730
|
-
def _fetch_and_save_metadata(self, repo_id: str, local_dir: str) -> None:
|
|
793
|
+
def _fetch_and_save_metadata(self, repo_id: str, local_dir: str, is_mmproj: bool = False, file_name: Optional[Union[str, List[str]]] = None) -> None:
|
|
731
794
|
"""Fetch model info and save metadata after successful download."""
|
|
732
795
|
# Initialize metadata with defaults to ensure manifest is always created
|
|
733
796
|
old_metadata = {
|
|
@@ -757,7 +820,7 @@ class HuggingFaceDownloader:
|
|
|
757
820
|
|
|
758
821
|
# CRITICAL: Always create the manifest file, regardless of metadata fetch failures
|
|
759
822
|
try:
|
|
760
|
-
save_manifest_with_files_metadata(repo_id, local_dir, old_metadata)
|
|
823
|
+
save_manifest_with_files_metadata(repo_id, local_dir, old_metadata, is_mmproj, file_name)
|
|
761
824
|
print(f"[OK] Successfully created nexa.manifest for {repo_id}")
|
|
762
825
|
except Exception as e:
|
|
763
826
|
# This is critical - if manifest creation fails, we should know about it
|
|
@@ -819,7 +882,7 @@ class HuggingFaceDownloader:
|
|
|
819
882
|
progress_tracker.stop_tracking()
|
|
820
883
|
|
|
821
884
|
# Save metadata after successful download
|
|
822
|
-
self._fetch_and_save_metadata(repo_id, file_local_dir)
|
|
885
|
+
self._fetch_and_save_metadata(repo_id, file_local_dir, self._current_is_mmproj, self._current_file_name)
|
|
823
886
|
|
|
824
887
|
return downloaded_path
|
|
825
888
|
|
|
@@ -864,7 +927,7 @@ class HuggingFaceDownloader:
|
|
|
864
927
|
progress_tracker.stop_tracking()
|
|
865
928
|
|
|
866
929
|
# Save metadata after successful download
|
|
867
|
-
self._fetch_and_save_metadata(repo_id, repo_local_dir)
|
|
930
|
+
self._fetch_and_save_metadata(repo_id, repo_local_dir, self._current_is_mmproj, self._current_file_name)
|
|
868
931
|
|
|
869
932
|
return downloaded_path
|
|
870
933
|
|
|
@@ -926,7 +989,7 @@ class HuggingFaceDownloader:
|
|
|
926
989
|
progress_tracker.stop_tracking()
|
|
927
990
|
|
|
928
991
|
# Save metadata after successful download
|
|
929
|
-
self._fetch_and_save_metadata(repo_id, repo_local_dir)
|
|
992
|
+
self._fetch_and_save_metadata(repo_id, repo_local_dir, self._current_is_mmproj, self._current_file_name)
|
|
930
993
|
|
|
931
994
|
return repo_local_dir
|
|
932
995
|
|
|
@@ -951,7 +1014,8 @@ class HuggingFaceDownloader:
|
|
|
951
1014
|
local_dir: Optional[str] = None,
|
|
952
1015
|
progress_callback: Optional[Callable[[Dict[str, Any]], None]] = None,
|
|
953
1016
|
show_progress: bool = True,
|
|
954
|
-
force_download: bool = False
|
|
1017
|
+
force_download: bool = False,
|
|
1018
|
+
is_mmproj: bool = False
|
|
955
1019
|
) -> str:
|
|
956
1020
|
"""
|
|
957
1021
|
Main download method that handles all download scenarios.
|
|
@@ -970,6 +1034,10 @@ class HuggingFaceDownloader:
|
|
|
970
1034
|
# Validate and normalize parameters
|
|
971
1035
|
repo_id, file_name = self._validate_and_setup_params(repo_id, file_name)
|
|
972
1036
|
|
|
1037
|
+
# Store parameters as instance variables for use in _fetch_and_save_metadata
|
|
1038
|
+
self._current_is_mmproj = is_mmproj
|
|
1039
|
+
self._current_file_name = file_name
|
|
1040
|
+
|
|
973
1041
|
# Set up local directory
|
|
974
1042
|
local_dir = self._created_dir_if_not_exists(local_dir)
|
|
975
1043
|
|
|
@@ -1038,7 +1106,8 @@ def download_from_huggingface(
|
|
|
1038
1106
|
show_progress: bool = True,
|
|
1039
1107
|
token: Union[bool, str, None] = None,
|
|
1040
1108
|
custom_endpoint: Optional[str] = None,
|
|
1041
|
-
force_download: bool = False
|
|
1109
|
+
force_download: bool = False,
|
|
1110
|
+
is_mmproj: Optional[bool] = None
|
|
1042
1111
|
) -> str:
|
|
1043
1112
|
"""
|
|
1044
1113
|
Download models or files from HuggingFace Hub or custom mirror endpoints.
|
|
@@ -1065,6 +1134,9 @@ def download_from_huggingface(
|
|
|
1065
1134
|
The endpoint will be used to initialize HfApi for all downloads.
|
|
1066
1135
|
force_download (bool, optional): If True, download files even if they already exist locally.
|
|
1067
1136
|
Default False (skip existing files).
|
|
1137
|
+
is_mmproj (bool, optional): Whether the file being downloaded is an mmproj file. Only used when
|
|
1138
|
+
file_name is not None. If None, defaults to True if 'mmproj' is in
|
|
1139
|
+
the filename, False otherwise.
|
|
1068
1140
|
|
|
1069
1141
|
Returns:
|
|
1070
1142
|
str: Path to the downloaded file or directory
|
|
@@ -1101,6 +1173,15 @@ def download_from_huggingface(
|
|
|
1101
1173
|
}
|
|
1102
1174
|
}
|
|
1103
1175
|
"""
|
|
1176
|
+
# Set default value for is_mmproj based on filename if not explicitly provided
|
|
1177
|
+
if is_mmproj is None and file_name is not None:
|
|
1178
|
+
# Check if any filename contains 'mmproj'
|
|
1179
|
+
filenames_to_check = file_name if isinstance(file_name, list) else [file_name]
|
|
1180
|
+
is_mmproj = any('mmproj' in filename.lower() for filename in filenames_to_check)
|
|
1181
|
+
elif is_mmproj is None:
|
|
1182
|
+
# Default to False if no file_name is provided
|
|
1183
|
+
is_mmproj = False
|
|
1184
|
+
|
|
1104
1185
|
# Create downloader instance with custom endpoint if provided
|
|
1105
1186
|
downloader = HuggingFaceDownloader(
|
|
1106
1187
|
endpoint=custom_endpoint,
|
|
@@ -1115,7 +1196,8 @@ def download_from_huggingface(
|
|
|
1115
1196
|
local_dir=local_dir,
|
|
1116
1197
|
progress_callback=progress_callback,
|
|
1117
1198
|
show_progress=show_progress,
|
|
1118
|
-
force_download=force_download
|
|
1199
|
+
force_download=force_download,
|
|
1200
|
+
is_mmproj=is_mmproj
|
|
1119
1201
|
)
|
|
1120
1202
|
|
|
1121
1203
|
|
|
@@ -1124,15 +1206,66 @@ def download_from_huggingface(
|
|
|
1124
1206
|
##########################################################################
|
|
1125
1207
|
|
|
1126
1208
|
|
|
1209
|
+
def _download_model_if_needed(
|
|
1210
|
+
model_path: str,
|
|
1211
|
+
param_name: str,
|
|
1212
|
+
progress_callback: Optional[Callable[[Dict[str, Any]], None]] = None,
|
|
1213
|
+
token: Union[bool, str, None] = None,
|
|
1214
|
+
is_mmproj: bool = False
|
|
1215
|
+
) -> str:
|
|
1216
|
+
"""
|
|
1217
|
+
Helper function to download a model from HuggingFace if it doesn't exist locally.
|
|
1218
|
+
|
|
1219
|
+
Args:
|
|
1220
|
+
model_path: The model path that may be local or remote
|
|
1221
|
+
param_name: Name of the parameter (for error messages)
|
|
1222
|
+
progress_callback: Callback function for download progress updates
|
|
1223
|
+
token: HuggingFace authentication token for private repositories
|
|
1224
|
+
|
|
1225
|
+
Returns:
|
|
1226
|
+
str: Local path to the model (either existing or downloaded)
|
|
1227
|
+
|
|
1228
|
+
Raises:
|
|
1229
|
+
RuntimeError: If download fails
|
|
1230
|
+
"""
|
|
1231
|
+
# Check if model_path exists locally (file or directory)
|
|
1232
|
+
if os.path.exists(model_path):
|
|
1233
|
+
# Local path exists, return as-is
|
|
1234
|
+
return model_path
|
|
1235
|
+
|
|
1236
|
+
# Model path doesn't exist locally, try to download from HuggingFace
|
|
1237
|
+
try:
|
|
1238
|
+
# Parse model_path to extract repo_id and filename
|
|
1239
|
+
repo_id, file_name = _parse_model_path(model_path)
|
|
1240
|
+
|
|
1241
|
+
# Download the model
|
|
1242
|
+
downloaded_path = download_from_huggingface(
|
|
1243
|
+
repo_id=repo_id,
|
|
1244
|
+
file_name=file_name,
|
|
1245
|
+
local_dir=None, # Use default cache directory
|
|
1246
|
+
enable_transfer=True,
|
|
1247
|
+
progress_callback=progress_callback,
|
|
1248
|
+
show_progress=True,
|
|
1249
|
+
token=token,
|
|
1250
|
+
is_mmproj=is_mmproj
|
|
1251
|
+
)
|
|
1252
|
+
|
|
1253
|
+
return downloaded_path
|
|
1254
|
+
|
|
1255
|
+
except Exception as e:
|
|
1256
|
+
# Only handle download-related errors
|
|
1257
|
+
raise RuntimeError(f"Could not load model from '{param_name}={model_path}': {e}")
|
|
1258
|
+
|
|
1259
|
+
|
|
1127
1260
|
def auto_download_model(func: Callable) -> Callable:
|
|
1128
1261
|
"""
|
|
1129
1262
|
Decorator that automatically downloads models from HuggingFace if they don't exist locally.
|
|
1130
1263
|
|
|
1131
|
-
This decorator should be applied to __init__ methods that take a name_or_path parameter
|
|
1132
|
-
If
|
|
1133
|
-
it from HuggingFace Hub using the download_from_huggingface function.
|
|
1264
|
+
This decorator should be applied to __init__ methods that take a name_or_path parameter
|
|
1265
|
+
and optionally an mmproj_path parameter. If these paths don't exist as local files/directories,
|
|
1266
|
+
it will attempt to download them from HuggingFace Hub using the download_from_huggingface function.
|
|
1134
1267
|
|
|
1135
|
-
The name_or_path can be in formats like:
|
|
1268
|
+
The name_or_path and mmproj_path can be in formats like:
|
|
1136
1269
|
- "microsoft/DialoGPT-small" (downloads entire repo)
|
|
1137
1270
|
- "microsoft/DialoGPT-small/pytorch_model.bin" (downloads specific file)
|
|
1138
1271
|
- "Qwen/Qwen3-4B-GGUF/Qwen3-4B-Q4_K_M.gguf" (downloads specific file)
|
|
@@ -1149,21 +1282,6 @@ def auto_download_model(func: Callable) -> Callable:
|
|
|
1149
1282
|
"""
|
|
1150
1283
|
@functools.wraps(func)
|
|
1151
1284
|
def wrapper(*args, **kwargs):
|
|
1152
|
-
# Find name_or_path in arguments
|
|
1153
|
-
# Assuming name_or_path is the first argument after self
|
|
1154
|
-
if len(args) >= 2:
|
|
1155
|
-
name_or_path = args[1]
|
|
1156
|
-
args_list = list(args)
|
|
1157
|
-
path_index = 1
|
|
1158
|
-
is_positional = True
|
|
1159
|
-
elif 'name_or_path' in kwargs:
|
|
1160
|
-
name_or_path = kwargs['name_or_path']
|
|
1161
|
-
path_index = None
|
|
1162
|
-
is_positional = False
|
|
1163
|
-
else:
|
|
1164
|
-
# No name_or_path found, call original function
|
|
1165
|
-
return func(*args, **kwargs)
|
|
1166
|
-
|
|
1167
1285
|
# Extract progress_callback and token from arguments
|
|
1168
1286
|
progress_callback = None
|
|
1169
1287
|
if 'progress_callback' in kwargs:
|
|
@@ -1173,39 +1291,63 @@ def auto_download_model(func: Callable) -> Callable:
|
|
|
1173
1291
|
if 'token' in kwargs:
|
|
1174
1292
|
token = kwargs.pop('token') # Remove from kwargs to avoid passing to original func
|
|
1175
1293
|
|
|
1176
|
-
#
|
|
1177
|
-
|
|
1178
|
-
|
|
1294
|
+
# Handle name_or_path parameter
|
|
1295
|
+
name_or_path = None
|
|
1296
|
+
name_path_index = None
|
|
1297
|
+
is_name_positional = False
|
|
1298
|
+
|
|
1299
|
+
# Find name_or_path in arguments
|
|
1300
|
+
# Assuming name_or_path is the first argument after self
|
|
1301
|
+
if len(args) >= 2:
|
|
1302
|
+
name_or_path = args[1]
|
|
1303
|
+
args_list = list(args)
|
|
1304
|
+
name_path_index = 1
|
|
1305
|
+
is_name_positional = True
|
|
1306
|
+
elif 'name_or_path' in kwargs:
|
|
1307
|
+
name_or_path = kwargs['name_or_path']
|
|
1308
|
+
is_name_positional = False
|
|
1309
|
+
|
|
1310
|
+
# Handle mmproj_path parameter
|
|
1311
|
+
mmproj_path = None
|
|
1312
|
+
if 'mmproj_path' in kwargs:
|
|
1313
|
+
mmproj_path = kwargs['mmproj_path']
|
|
1314
|
+
|
|
1315
|
+
# If neither parameter is found, call original function
|
|
1316
|
+
if name_or_path is None and mmproj_path is None:
|
|
1179
1317
|
return func(*args, **kwargs)
|
|
1180
1318
|
|
|
1181
|
-
#
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1319
|
+
# Download name_or_path if needed
|
|
1320
|
+
if name_or_path is not None:
|
|
1321
|
+
try:
|
|
1322
|
+
downloaded_name_path = _download_model_if_needed(
|
|
1323
|
+
name_or_path, 'name_or_path', progress_callback, token
|
|
1324
|
+
)
|
|
1325
|
+
|
|
1326
|
+
# Replace name_or_path with downloaded path
|
|
1327
|
+
if is_name_positional:
|
|
1328
|
+
if name_path_index is not None:
|
|
1329
|
+
args_list[name_path_index] = downloaded_name_path
|
|
1330
|
+
args = tuple(args_list)
|
|
1331
|
+
else:
|
|
1332
|
+
kwargs['name_or_path'] = downloaded_name_path
|
|
1333
|
+
|
|
1334
|
+
except Exception as e:
|
|
1335
|
+
raise e # Re-raise the error from _download_model_if_needed
|
|
1336
|
+
|
|
1337
|
+
# Download mmproj_path if needed
|
|
1338
|
+
if mmproj_path is not None:
|
|
1339
|
+
try:
|
|
1340
|
+
downloaded_mmproj_path = _download_model_if_needed(
|
|
1341
|
+
mmproj_path, 'mmproj_path', progress_callback, token, is_mmproj=True
|
|
1342
|
+
)
|
|
1343
|
+
|
|
1344
|
+
# Replace mmproj_path with downloaded path
|
|
1345
|
+
kwargs['mmproj_path'] = downloaded_mmproj_path
|
|
1346
|
+
|
|
1347
|
+
except Exception as e:
|
|
1348
|
+
raise e # Re-raise the error from _download_model_if_needed
|
|
1207
1349
|
|
|
1208
|
-
# Call original function with updated
|
|
1350
|
+
# Call original function with updated paths (outside try-catch to let model creation errors bubble up)
|
|
1209
1351
|
return func(*args, **kwargs)
|
|
1210
1352
|
|
|
1211
1353
|
return wrapper
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Generator, Optional, List, Dict, Any, Union
|
|
2
2
|
import queue
|
|
3
3
|
import threading
|
|
4
|
-
import base64
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
|
|
7
6
|
from nexaai.common import ModelConfig, GenerationConfig, MultiModalMessage, PluginID
|
|
@@ -102,26 +101,16 @@ class PyBindVLMImpl(VLM):
|
|
|
102
101
|
t = c["type"]
|
|
103
102
|
if t == "text":
|
|
104
103
|
blocks.append({"type": "text", "text": c.get("text","") or ""})
|
|
104
|
+
elif t == "image":
|
|
105
|
+
# Pass through the original structure - let vlm-bind.cpp handle field extraction
|
|
106
|
+
blocks.append(c)
|
|
105
107
|
else:
|
|
106
|
-
|
|
107
|
-
src = c.get("url") or c.get("path")
|
|
108
|
-
if not src:
|
|
109
|
-
raise ValueError(f"No url/path for {t}")
|
|
110
|
-
# read local file or strip data URI
|
|
111
|
-
if Path(src).exists():
|
|
112
|
-
raw = Path(src).read_bytes()
|
|
113
|
-
b64 = base64.b64encode(raw).decode("ascii")
|
|
114
|
-
blocks.append({"type": t, "text": b64})
|
|
115
|
-
elif src.startswith("data:"):
|
|
116
|
-
b64 = src.split(",",1)[1]
|
|
117
|
-
blocks.append({"type": t, "text": b64})
|
|
118
|
-
else:
|
|
119
|
-
# remote URL
|
|
120
|
-
blocks.append({"type": t, "text": src})
|
|
108
|
+
raise ValueError(f"Unsupported content type: {t}. Use 'text' or 'image' to match the golden reference in vlm.cpp")
|
|
121
109
|
|
|
122
110
|
payload.append({"role": role, "content": blocks})
|
|
123
111
|
|
|
124
|
-
|
|
112
|
+
result = vlm_bind.ml_vlm_apply_chat_template(self._handle, payload, tools)
|
|
113
|
+
return result
|
|
125
114
|
|
|
126
115
|
def generate_stream(self, prompt: str, g_cfg: GenerationConfig = GenerationConfig()) -> Generator[str, None, None]:
|
|
127
116
|
"""Generate text with streaming."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
nexaai/__init__.py,sha256=jXdC4vv6DBK1fVewYTYSUhOOYfvf_Mk81UIeMGGIKUg,2029
|
|
2
|
-
nexaai/_stub.cpython-310-darwin.so,sha256=
|
|
3
|
-
nexaai/_version.py,sha256=
|
|
2
|
+
nexaai/_stub.cpython-310-darwin.so,sha256=6Rm0bf_EO8r2MetZDjJ7E65gIcteq6ZDkPSLYh2NJj4,49832
|
|
3
|
+
nexaai/_version.py,sha256=phWIqzyUJzHhqe_9HXfqatPXqoSNklwhM8R24HQckh8,143
|
|
4
4
|
nexaai/asr.py,sha256=NljMXDErwPNMOPaRkJZMEDka9Nk8xyur7L8i924TStY,2054
|
|
5
5
|
nexaai/base.py,sha256=N8PRgDFA-XPku2vWnQIofQ7ipz3pPlO6f8YZGnuhquE,982
|
|
6
6
|
nexaai/common.py,sha256=yBnIbqYaQYnfrl7IczOBh6MDibYZVxwaRJEglYcKgGs,3422
|
|
@@ -15,20 +15,19 @@ nexaai/vlm.py,sha256=3voXmAVnGlXnOiwA3wcX4p0Lvmp0X1VKkQVPObJdwBY,4649
|
|
|
15
15
|
nexaai/asr_impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
nexaai/asr_impl/mlx_asr_impl.py,sha256=eosd8-TIWAOwV0HltmoFrLwzXHcU4jyxtncvuZE9pgA,3257
|
|
17
17
|
nexaai/asr_impl/pybind_asr_impl.py,sha256=pE9Hb_hMi5yAc4MF83bLVOb8zDtreCkB3_u7XED9YpA,1516
|
|
18
|
-
nexaai/binds/__init__.py,sha256=
|
|
18
|
+
nexaai/binds/__init__.py,sha256=eYuay_8DDXeOUWz2_R9HFSabohxs6hvZn391t2L0Po0,104
|
|
19
19
|
nexaai/binds/common_bind.cpython-310-darwin.so,sha256=7xH5yNkK6Ot-2f9vxmultr9NIeTemlmN5tHIYp8SZHs,233960
|
|
20
20
|
nexaai/binds/embedder_bind.cpython-310-darwin.so,sha256=eQwf9m58Yrl_ZZzWlstBHfHD-s3UMFi0JNPty-Pc524,202032
|
|
21
|
-
nexaai/binds/
|
|
22
|
-
nexaai/binds/libnexa_bridge.dylib,sha256=w0XiFs2v3uoojLBFLag9mSMAydDHmaJFrT-yFaRZRyA,250592
|
|
23
|
-
nexaai/binds/libssl.dylib,sha256=JHPTSbRFnImmoWDO9rFdiKb0lJMT3q78VEsx-5-S0sk,889520
|
|
21
|
+
nexaai/binds/libnexa_bridge.dylib,sha256=uJ6vhHoU5Q-QE8jC2PHPqVGAKhgUig_GWZ-HODXrYqs,250376
|
|
24
22
|
nexaai/binds/llm_bind.cpython-310-darwin.so,sha256=08DuSv91LIVCS5BSfSx3Nuz088h62lm3MV2yDTSIKt4,183008
|
|
23
|
+
nexaai/binds/vlm_bind.cpython-310-darwin.so,sha256=x1hxuCx09P69swsVj46FXHKUH5Ln39ISBjBscyJWESM,183000
|
|
25
24
|
nexaai/binds/nexa_llama_cpp/libggml-base.dylib,sha256=GyOkHOM-5uHp7NUZ4Sr9BWak6BYpcc9aqI9A-zPnQp4,629528
|
|
26
25
|
nexaai/binds/nexa_llama_cpp/libggml-cpu.so,sha256=cnLUQ7WdX-5iiDaH8v45u1kX1NUmK8DanpzSMGCpXPE,1039800
|
|
27
26
|
nexaai/binds/nexa_llama_cpp/libggml-metal.so,sha256=Xhhl_tLg1xmCIQVrKjqPFaLHAlx_2wUFiwDyUk0wJ-E,713680
|
|
28
27
|
nexaai/binds/nexa_llama_cpp/libggml.dylib,sha256=12Q1Z98oM81hxzT_GMQsW5rlhC8DOMsX6luWVCFQHcI,58336
|
|
29
28
|
nexaai/binds/nexa_llama_cpp/libllama.dylib,sha256=ORoTILXdGGX6MLMh-IWLIp4P5UEPOjE4lvWOKM18pCk,1982280
|
|
30
29
|
nexaai/binds/nexa_llama_cpp/libmtmd.dylib,sha256=1plWvthTQf8IXbXthMG0MZXzWhbzV6ghdVzVFIb1FnU,701504
|
|
31
|
-
nexaai/binds/nexa_llama_cpp/libnexa_plugin.dylib,sha256=
|
|
30
|
+
nexaai/binds/nexa_llama_cpp/libnexa_plugin.dylib,sha256=3Dpj5aDJUcJ0CGyl7hstBBsorDwM3U0vVsCjmDB34dg,2025496
|
|
32
31
|
nexaai/cv_impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
32
|
nexaai/cv_impl/mlx_cv_impl.py,sha256=gKECQOv8iaWwG3bl7xeqVy2NN_9K7tYerIFzfn4eLo4,3228
|
|
34
33
|
nexaai/cv_impl/pybind_cv_impl.py,sha256=uSmwBste4cT7c8DQmXzRLmzwDf773PAbXNYWW1UzVls,1064
|
|
@@ -358,15 +357,15 @@ nexaai/tts_impl/mlx_tts_impl.py,sha256=i_uNPdvlXYtL3e01oKjDlP9jgkWCRt1bBHsExaaiJ
|
|
|
358
357
|
nexaai/tts_impl/pybind_tts_impl.py,sha256=mpn44r6pfYLIl-NrEy2dXHjGtWtNCmM7HRyxiANxUI4,1444
|
|
359
358
|
nexaai/utils/avatar_fetcher.py,sha256=bWy8ujgbOiTHFCjFxTwkn3uXbZ84PgEGUkXkR3MH4bI,3821
|
|
360
359
|
nexaai/utils/decode.py,sha256=61n4Zf6c5QLyqGoctEitlI9BX3tPlP2a5aaKNHbw3T4,404
|
|
361
|
-
nexaai/utils/manifest_utils.py,sha256=
|
|
362
|
-
nexaai/utils/model_manager.py,sha256=
|
|
360
|
+
nexaai/utils/manifest_utils.py,sha256=sR9Nme4GbD3Cb3fMd55yLvGZpqxb71vd6b2XZTsrIGM,12328
|
|
361
|
+
nexaai/utils/model_manager.py,sha256=p2kJKK63Zk-rEUucFsgY0T5PyXi_IvJY0gKewUVcAV4,56081
|
|
363
362
|
nexaai/utils/model_types.py,sha256=-DER8L4lAUR_iLS99F0r57avwqWtuN21ug5pX2p24_E,1369
|
|
364
363
|
nexaai/utils/progress_tracker.py,sha256=jdUqtmPqyhwC9uSKvQcJEYETwSt-OhP4oitdJ94614o,15394
|
|
365
364
|
nexaai/utils/quantization_utils.py,sha256=4gvp6UQfSO9G1FYBwnFtQspTzH9sDbi1PBXw2t1N69M,7650
|
|
366
365
|
nexaai/vlm_impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
367
366
|
nexaai/vlm_impl/mlx_vlm_impl.py,sha256=od1R1mRoIgPG3NHC7JiDlcB_YJY8aklX8Em3ZkeHNpE,10734
|
|
368
|
-
nexaai/vlm_impl/pybind_vlm_impl.py,sha256=
|
|
369
|
-
nexaai-1.0.
|
|
370
|
-
nexaai-1.0.
|
|
371
|
-
nexaai-1.0.
|
|
372
|
-
nexaai-1.0.
|
|
367
|
+
nexaai/vlm_impl/pybind_vlm_impl.py,sha256=n4lBTeDA9i07Fz1sq4694XkA2XQtnJnR9RaaKK0CrcM,8458
|
|
368
|
+
nexaai-1.0.13rc2.dist-info/METADATA,sha256=QDTSLe7dtUuRQzCK7l0wE49_GoDsm8QN5W_3mPhdlfc,1201
|
|
369
|
+
nexaai-1.0.13rc2.dist-info/WHEEL,sha256=0KYp5feZ1CMUhsfFXKpSQTbSmQbXy4mv6yPPVBXg2EM,110
|
|
370
|
+
nexaai-1.0.13rc2.dist-info/top_level.txt,sha256=LRE2YERlrZk2vfuygnSzsEeqSknnZbz3Z1MHyNmBU4w,7
|
|
371
|
+
nexaai-1.0.13rc2.dist-info/RECORD,,
|
nexaai/binds/libcrypto.dylib
DELETED
|
Binary file
|
nexaai/binds/libssl.dylib
DELETED
|
Binary file
|
|
File without changes
|
|
File without changes
|