// Command convert converts HuggingFace models (safetensors) to .mak format // // Pure Go implementation - no Python dependencies! // // Usage: // // convert /path/to/model output.mak // convert /path/to/model output.mak --quant q4_k // convert /path/to/model output.mak --quant q4_k --mix package main import ( "flag" "fmt" "os" "strings" "makarna/pkg/convert" _ "makarna/pkg/model/models" "makarna/pkg/quant" ) func main() { fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError) quantType := fs.String("quant", "", "Quantization type: q2_k, q3_k, q4_k, q5_k, q6_k, q8_k (empty = F32)") mixMode := fs.Bool("mix", false, "Enable smart mix quantization") workers := fs.Int("workers", 0, "Number of parallel workers for conversion (0 = GOMAXPROCS)") maxInFlightMB := fs.Int("max-inflight-mb", 0, "Max in-flight tensor memory (decoded+output) in MB (0 = auto)") // Go's standard flag package stops parsing at the first non-flag argument. // Users often pass: convert --quant q4_k --mix // Pre-scan to allow flags to appear anywhere. flagArgs, posArgs := splitFlagsAndPositionals(os.Args[1:]) _ = fs.Parse(flagArgs) args := posArgs if len(args) < 2 { fmt.Println("Usage: convert [--quant TYPE] [--mix]") os.Exit(1) } modelPath := args[0] outputPath := args[1] var baseQuant quant.QuantType if *quantType != "" { baseQuant = quant.QuantType(*quantType) switch baseQuant { case quant.TypeQ2K, quant.TypeQ3K, quant.TypeQ4K, quant.TypeQ5K, quant.TypeQ6K, quant.TypeQ8K: // OK default: fmt.Printf("Unknown quant type: %s\n", *quantType) os.Exit(1) } } fmt.Printf("convert: model=%s out=%s quant=%s mix=%v workers=%d max_inflight_mb=%d\n", modelPath, outputPath, baseQuant, *mixMode, *workers, *maxInFlightMB) opts := convert.Options{ BaseQuant: baseQuant, MixMode: *mixMode, Workers: *workers, MaxInFlightBytes: uint64(*maxInFlightMB) * 1024 * 1024, } if err := convert.ConvertDirectory(modelPath, outputPath, opts); err != nil { fmt.Printf("convert failed: %v\n", err) os.Exit(1) } } func splitFlagsAndPositionals(argv []string) (flagArgs []string, posArgs []string) { // Known flags for this command. Values indicate whether the flag expects a separate value. expectsValue := map[string]bool{ "--quant": true, "-quant": true, "--workers": true, "-workers": true, "--max-inflight-mb": true, "-max-inflight-mb": true, "--mix": false, "-mix": false, } for i := 0; i < len(argv); i++ { a := argv[i] if !strings.HasPrefix(a, "-") { posArgs = append(posArgs, a) continue } // Support --flag=value form. if strings.Contains(a, "=") { flagArgs = append(flagArgs, a) continue } flagArgs = append(flagArgs, a) if expectsValue[a] { if i+1 < len(argv) && !strings.HasPrefix(argv[i+1], "-") { flagArgs = append(flagArgs, argv[i+1]) i++ } } } return flagArgs, posArgs }