package imagegen import "context" // EditRequest is an image-to-image (edit) request: a prompt applied to an // initial image. As with Request, zero values mean "backend default" // (ADR-0018). type EditRequest struct { // Prompt is the text description of the desired edit. Prompt string // Init is the initial image the edit starts from. Required, EXCEPT when // RefImages is set — see there. Init Image // RefImages carries reference images for INSTRUCTION-EDIT models // (FLUX.1 Kontext, Qwen-Image-Edit), which are a different kind of edit // from img2img and reach the model by a different path. // // img2img noises Init and denoises it back under the prompt: the prompt // describes the DESIRED IMAGE, and how much of the original survives is a // function of Strength. An instruction-edit model instead takes the // picture as conditioning and the prompt as an INSTRUCTION about it // ("change the sign to read OPEN"), leaving everything it was not asked // to touch bit-for-bit intact — no mask, no strength, no compositing. // // Sending one of these models an Init instead of a RefImage does not // degrade gracefully, it silently does the wrong thing: measured against // FLUX.1-Kontext on 2026-07-30, "change the blue rectangle to green" via // init_images left the rectangle blue and drifted every other region, // while the same prompt via a reference image turned it green and left // the rest of the frame numerically unchanged. // // When RefImages is non-empty, Init/Mask/Strength are IGNORED: they // describe a pipeline this model does not run. RefImages []Image // Mask restricts the edit to a region (inpainting): a single-channel or // RGB image the same size as Init where WHITE pixels are repainted and // BLACK pixels are kept. Empty = whole-image edit. Backends without mask // support must reject a masked request rather than silently ignoring it. Mask Image // Strength is the denoising strength in [0,1] — how far the result may // depart from Init (0 = return the input, 1 = ignore it); nil = backend // default. Strength *float64 // N is the number of images to generate; 0 = provider default. N int // Size is the requested resolution, e.g. "1024x1024"; "" = provider // default (usually the init image's own resolution). Size string // Steps is the number of diffusion steps; nil = backend default. Steps *int // CFGScale is the classifier-free-guidance scale; nil = backend default. CFGScale *float64 // NegativePrompt steers generation away from concepts; "" = none. NegativePrompt string // Sampler selects the sampling method (e.g. "euler", "euler_a"); // "" = backend default. Sampler string // Seed fixes the RNG seed for reproducible output; nil = random. Seed *int64 } // EditOption mutates an EditRequest before it is sent. Options passed to Edit // are applied to a copy of the request, so an EditRequest value can be reused. type EditOption func(*EditRequest) // WithEditMask restricts the edit to a region (white = repaint, black = keep). func WithEditMask(m Image) EditOption { return func(r *EditRequest) { r.Mask = m } } // WithEditRefImages supplies reference images for an instruction-edit model // (Kontext / Qwen-Image-Edit). See EditRequest.RefImages — this selects a // different edit path, not a variation on img2img. func WithEditRefImages(imgs ...Image) EditOption { return func(r *EditRequest) { r.RefImages = imgs } } // WithEditStrength sets the denoising strength in [0,1]. func WithEditStrength(s float64) EditOption { return func(r *EditRequest) { r.Strength = &s } } // WithEditN sets the number of images to generate. func WithEditN(n int) EditOption { return func(r *EditRequest) { r.N = n } } // WithEditSize sets the requested resolution (e.g. "1024x1024"). func WithEditSize(size string) EditOption { return func(r *EditRequest) { r.Size = size } } // WithEditSteps overrides the number of diffusion steps. func WithEditSteps(n int) EditOption { return func(r *EditRequest) { r.Steps = &n } } // WithEditCFGScale overrides the classifier-free-guidance scale. func WithEditCFGScale(s float64) EditOption { return func(r *EditRequest) { r.CFGScale = &s } } // WithEditNegativePrompt sets a negative prompt. func WithEditNegativePrompt(s string) EditOption { return func(r *EditRequest) { r.NegativePrompt = s } } // WithEditSampler overrides the sampling method. func WithEditSampler(s string) EditOption { return func(r *EditRequest) { r.Sampler = s } } // WithEditSeed fixes the RNG seed for reproducible output. func WithEditSeed(seed int64) EditOption { return func(r *EditRequest) { r.Seed = &seed } } // Apply returns a copy of the request with all options applied. Providers // call this once at the top of Edit. func (r EditRequest) Apply(opts ...EditOption) EditRequest { for _, opt := range opts { opt(&r) } return r } // Editor is the image-to-image surface. It is a separate, optional interface // rather than a method on Model so existing Model implementations keep // compiling; callers type-assert (`m.(imagegen.Editor)`) or require it // explicitly. type Editor interface { // Edit produces one or more images derived from the request's init image // under the request's prompt. Edit(ctx context.Context, req EditRequest, opts ...EditOption) (*Result, error) }