feat: audio surfaces (TTS + transcription), imagegen.Editor, llamaswap health probe
- New leaf package `audio` (ADR-0017): SpeechModel/SpeechProvider and TranscriptionModel/TranscriptionProvider with imagegen conventions (zero value = backend default, functional options + Apply, bytes in/out, never URLs). Root re-exports added. - imagegen.Editor (ADR-0018): optional image-to-image interface — EditRequest carries the generation knobs plus Init image and denoising Strength; separate interface so existing Models keep compiling. - provider/llamaswap implements all of it: POST /v1/audio/speech (JSON, raw-audio response, MIME from Content-Type with format fallback), POST /v1/audio/transcriptions (multipart, response_format=json), ListVoices (GET /v1/audio/voices?model=, tolerant of string-list and object-list shapes), POST /sdapi/v1/img2img (txt2img wire + init_images/denoising_strength, shared image decode), and Health(ctx) (GET /health) — a cheap liveness probe for often-offline hosts. - Hermetic httptest coverage for every new wire shape and validation path; README sections + support-matrix footnote updated in the same commit (also corrects the stale /v1/images/generations claim — the image path has been SDAPI since the seed fix). First consumer: mort's llamaswap media tool cluster (status / image / TTS / STT agent tools against the netherstorm host). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AXQxVhXBw8PwFAtsVrXSmj
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
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.
|
||||
Init 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)
|
||||
|
||||
// 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)
|
||||
}
|
||||
Reference in New Issue
Block a user