llm-gguf-tools/safetensors2gguf.py
2025-08-07 18:29:12 +01:00

95 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""Direct SafeTensors to GGUF converter for unsupported architectures.
This script attempts to convert SafeTensors models to GGUF format directly,
without relying on llama.cpp's architecture-specific conversion logic.
"""
from __future__ import annotations
import sys
import traceback
from argparse import ArgumentParser
from pathlib import Path
from helpers.logger import logger
from helpers.services.gguf import GGUFConverter
from helpers.utils.config_parser import ConfigParser
from helpers.utils.tensor_mapping import TensorMapper
def convert_safetensors_to_gguf(
model_path: Path, output_path: Path, force_architecture: str | None = None
) -> bool:
"""Convert SafeTensors model to GGUF format with comprehensive metadata handling.
Orchestrates the complete conversion workflow: loads configuration, maps
architecture to known GGUF types, creates writer with proper metadata,
processes all tensor files with name mapping, and adds tokeniser data.
Handles BFloat16 conversion and provides fallback architecture mapping
for unsupported model types to ensure maximum compatibility.
Returns:
True if conversion was successful, False otherwise.
"""
# Use ConfigParser to load configuration
config_parser = ConfigParser()
model_config = config_parser.load_model_config(model_path)
arch_name = model_config.architectures[0]
model_type = model_config.model_type
logger.info(f"Architecture: {arch_name}")
logger.info(f"Model type: {model_type}")
# Use forced architecture or try to map to a known one
if force_architecture:
arch = force_architecture
logger.warning(f"Using forced architecture: {arch}")
else:
# Use ConfigParser's architecture mapping
arch = config_parser.get_architecture_mapping(arch_name)
if arch != arch_name:
logger.warning(f"Unknown architecture {arch_name}, using {arch} as fallback")
# Use the new GGUFConverter for the conversion
tensor_mapper = TensorMapper()
return GGUFConverter.convert_safetensors(
model_path, output_path, model_config, arch, tensor_mapper
)
def main() -> None:
"""Main entry point for SafeTensors to GGUF conversion command-line interface.
Parses command-line arguments, validates input paths, and orchestrates the
conversion process with proper error handling. Supports forced architecture
mapping and flexible output path specification. Provides comprehensive
error reporting and exit codes for integration with automated workflows.
"""
parser = ArgumentParser(description="Convert SafeTensors to GGUF directly")
parser.add_argument("model_path", help="Path to SafeTensors model directory")
parser.add_argument("-o", "--output", help="Output GGUF file path")
parser.add_argument("--force-arch", help="Force a specific architecture mapping")
args = parser.parse_args()
model_path = Path(args.model_path)
if not model_path.exists():
logger.error(f"Model path not found: {model_path}")
sys.exit(1)
output_path = Path(args.output) if args.output else model_path / f"{model_path.name}-f32.gguf"
try:
success = convert_safetensors_to_gguf(model_path, output_path, args.force_arch)
sys.exit(0 if success else 1)
except Exception as e:
logger.error(f"Conversion failed: {e}")
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()