---
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`.
