--- name: sdcli_generate kind: function lang: go domain: ml version: "1.0.0" purity: impure signature: "func SdcliGenerate(ctx context.Context, bin SdcliBinary, cfg GenerationConfig, outPath string, onProgress SdcliProgressCallback) (ImageGenResult, error)" description: "Ejecuta el binario sd de stable-diffusion.cpp para generar una imagen. Construye los args CLI via GenconfigToSdcliArgs, lanza el proceso via SubprocessStream, parsea el progreso de stderr en tiempo real via SdcliParseProgress, y retorna ImageGenResult con los bytes PNG, metadata y duration_ms." tags: [ml, sdcli, stablediffusion, imagegen, subprocess, inference, cpp, pendiente-usar] uses_functions: - subprocess_stream_go_core - genconfig_to_sdcli_args_go_ml - sdcli_parse_progress_go_ml uses_types: - generation_config_go_ml - image_gen_result_go_ml returns: [] returns_optional: false error_type: "error_go_core" imports: ["context", "fmt", "os", "strconv", "strings", "time", "fn-registry/functions/core"] params: - name: ctx desc: "Context para cancelacion y timeout. Se pasa a SubprocessStream que gestiona SIGTERM -> grace 2s -> SIGKILL." - name: bin desc: "Binario sd resuelto via SdcliResolveBinary. Contiene path absoluto y version." - name: cfg desc: "Parametros de generacion: prompt, seed, steps, sampler, model, loras, etc." - name: outPath desc: "Path donde sd escribe la imagen PNG generada. El archivo se lee y se incluye en ImageGenResult.ImageBytes." - name: onProgress desc: "Callback opcional llamado con cada SdcliProgress parseado de stderr. Nil es valido." output: "ImageGenResult con ImageBytes (bytes del PNG), Format='png', Meta (backend, binary_path, model, seed, steps, etc.) y DurationMs medido desde el inicio de la llamada." tested: true tests: - "integration test skipped when sd binary not in PATH" test_file_path: "functions/ml/sdcli_test.go" file_path: "functions/ml/sdcli_generate.go" --- ## Ejemplo ```go ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) defer cancel() bin, err := SdcliResolveBinary("") if err != nil { log.Fatal(err) } cfg := GenerationConfig{ Prompt: "a red apple on a wooden table", Seed: 42, Steps: 20, CfgScale: 7.0, Sampler: "euler_a", Width: 512, Height: 512, Model: ModelRef{ Name: "sd15", ModelType: "sd15", Quantization: "fp16", Path: "/path/to/model.safetensors", }, } result, err := SdcliGenerate(ctx, bin, cfg, "/tmp/out.png", func(p SdcliProgress) { fmt.Printf("step %d/%d (%.1f%%)\n", p.Step, p.TotalSteps, p.Percent) }) if err != nil { log.Fatal(err) } fmt.Printf("generated %d bytes in %dms\n", len(result.ImageBytes), result.DurationMs) ``` ## Notas El binario `sd` de stable-diffusion.cpp escribe la imagen directamente en disco (`-o outPath`). La funcion lee el archivo tras la finalizacion del proceso y carga los bytes en `ImageGenResult.ImageBytes`. Si el proceso termina con `ExitCode != 0`, el error incluye las ultimas 10 lineas de stderr para facilitar el diagnostico. El callback `onProgress` se llama desde la goroutine de lectura de eventos. Si el callback hace I/O o es lento, considera usar un canal con buffer para desacoplar. Para modelos SD Turbo / SDXL Turbo con `steps <= 4` y `cfg_scale = 1.0`, el sampler `euler_a` es el recomendado. Para SD 1.5 estandar usar `euler` o `dpm++2m` con `steps >= 20`.