Skip to content

Commit 4f2c805

Browse files
committed
feat(core): add verification to manual import + concatenated file support
- verify GGUFs on manual import - show warning when dealing with concatenated files such as mradermacher's split GGUFs (partXofX)
1 parent 88875e3 commit 4f2c805

File tree

2 files changed

+75
-22
lines changed

2 files changed

+75
-22
lines changed

src/AutoGGUF.py

+66-22
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,14 @@ def create_label(self, text, tooltip):
11561156
label.setToolTip(tooltip)
11571157
return label
11581158

1159+
def verify_gguf(self, file_path):
1160+
try:
1161+
with open(file_path, "rb") as f:
1162+
magic = f.read(4)
1163+
return magic == b"GGUF"
1164+
except Exception:
1165+
return False
1166+
11591167
def load_models(self):
11601168
self.logger.info(LOADING_MODELS)
11611169
models_dir = self.models_input.text()
@@ -1164,58 +1172,88 @@ def load_models(self):
11641172

11651173
sharded_models = {}
11661174
single_models = []
1175+
concatenated_models = []
11671176

1168-
# Regex pattern to match sharded model filenames
11691177
shard_pattern = re.compile(r"(.*)-(\d+)-of-(\d+)\.gguf$")
1178+
concat_pattern = re.compile(r"(.*)\.gguf\.part(\d+)of(\d+)$")
11701179

1171-
# Load models from the models directory
11721180
for file in os.listdir(models_dir):
1181+
full_path = os.path.join(models_dir, file)
11731182
if file.endswith(".gguf"):
1183+
if not self.verify_gguf(full_path):
1184+
show_error(self.logger, INVALID_GGUF_FILE.format(file))
1185+
continue
1186+
11741187
match = shard_pattern.match(file)
11751188
if match:
1176-
# This is a sharded model
11771189
base_name, shard_num, total_shards = match.groups()
11781190
if base_name not in sharded_models:
11791191
sharded_models[base_name] = []
11801192
sharded_models[base_name].append((int(shard_num), file))
11811193
else:
11821194
single_models.append(file)
1195+
else:
1196+
match = concat_pattern.match(file)
1197+
if match:
1198+
concatenated_models.append(file)
11831199

1184-
# Add imported models
11851200
if hasattr(self, "imported_models"):
11861201
for imported_model in self.imported_models:
11871202
file_name = os.path.basename(imported_model)
1188-
if file_name not in single_models:
1189-
single_models.append(file_name)
1203+
if (
1204+
file_name not in single_models
1205+
and file_name not in concatenated_models
1206+
):
1207+
if self.verify_gguf(imported_model):
1208+
single_models.append(file_name)
1209+
else:
1210+
show_error(
1211+
self.logger, INVALID_GGUF_FILE.format(imported_model)
1212+
)
11901213

1191-
# Add sharded models to the tree
11921214
for base_name, shards in sharded_models.items():
11931215
parent_item = QTreeWidgetItem(self.model_tree)
1194-
parent_item.setText(0, f"{base_name} ({SHARDED})")
1216+
parent_item.setText(0, SHARDED_MODEL_NAME.format(base_name))
11951217
first_shard = sorted(shards, key=lambda x: x[0])[0][1]
11961218
parent_item.setData(0, Qt.ItemDataRole.UserRole, first_shard)
11971219
for _, shard_file in sorted(shards):
11981220
child_item = QTreeWidgetItem(parent_item)
11991221
child_item.setText(0, shard_file)
12001222
child_item.setData(0, Qt.ItemDataRole.UserRole, shard_file)
12011223

1202-
# Add single models to the tree
12031224
for model in sorted(single_models):
1204-
item = QTreeWidgetItem(self.model_tree)
1205-
item.setText(0, model)
1206-
if hasattr(self, "imported_models") and model in [
1207-
os.path.basename(m) for m in self.imported_models
1208-
]:
1209-
full_path = next(
1210-
m for m in self.imported_models if os.path.basename(m) == model
1211-
)
1212-
item.setData(0, Qt.ItemDataRole.UserRole, full_path)
1213-
item.setToolTip(0, IMPORTED_MODEL_TOOLTIP.format(full_path))
1214-
else:
1215-
item.setData(0, Qt.ItemDataRole.UserRole, model)
1225+
self.add_model_to_tree(model)
1226+
1227+
for model in sorted(concatenated_models):
1228+
item = self.add_model_to_tree(model)
1229+
item.setForeground(0, Qt.gray)
1230+
item.setToolTip(0, CONCATENATED_FILE_WARNING)
12161231

12171232
self.model_tree.expandAll()
1218-
self.logger.info(LOADED_MODELS.format(len(single_models) + len(sharded_models)))
1233+
self.logger.info(
1234+
LOADED_MODELS.format(
1235+
len(single_models) + len(sharded_models) + len(concatenated_models)
1236+
)
1237+
)
1238+
if concatenated_models:
1239+
self.logger.warning(
1240+
CONCATENATED_FILES_FOUND.format(len(concatenated_models))
1241+
)
1242+
1243+
def add_model_to_tree(self, model):
1244+
item = QTreeWidgetItem(self.model_tree)
1245+
item.setText(0, model)
1246+
if hasattr(self, "imported_models") and model in [
1247+
os.path.basename(m) for m in self.imported_models
1248+
]:
1249+
full_path = next(
1250+
m for m in self.imported_models if os.path.basename(m) == model
1251+
)
1252+
item.setData(0, Qt.ItemDataRole.UserRole, full_path)
1253+
item.setToolTip(0, IMPORTED_MODEL_TOOLTIP.format(full_path))
1254+
else:
1255+
item.setData(0, Qt.ItemDataRole.UserRole, model)
1256+
return item
12191257

12201258
def validate_quantization_inputs(self):
12211259
self.logger.debug(VALIDATING_QUANTIZATION_INPUTS)
@@ -1469,6 +1507,12 @@ def import_model(self):
14691507
)
14701508
if file_path:
14711509
file_name = os.path.basename(file_path)
1510+
1511+
# Verify GGUF file
1512+
if not self.verify_gguf(file_path):
1513+
show_error(self.logger, INVALID_GGUF_FILE.format(file_name))
1514+
return
1515+
14721516
reply = QMessageBox.question(
14731517
self,
14741518
CONFIRM_IMPORT,

src/Localizations.py

+9
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ def __init__(self):
3434
self.IMPORTING_MODEL = "Importing model"
3535
self.IMPORTED_MODEL_TOOLTIP = "Imported model: {}"
3636

37+
# GGUF Verification
38+
self.INVALID_GGUF_FILE = "Invalid GGUF file: {}"
39+
self.SHARDED_MODEL_NAME = "{} (Sharded)"
40+
self.IMPORTED_MODEL_TOOLTIP = "Imported model: {}"
41+
self.CONCATENATED_FILE_WARNING = "This is a concatenated file part. It will not work with llama-quantize; please concat the file first."
42+
self.CONCATENATED_FILES_FOUND = (
43+
"Found {} concatenated file parts. Please concat the files first."
44+
)
45+
3746
# GPU Monitoring
3847
self.GPU_USAGE = "GPU Usage:"
3948
self.GPU_USAGE_FORMAT = "GPU: {:.1f}% | VRAM: {:.1f}% ({} MB / {} MB)"

0 commit comments

Comments
 (0)