Help us shape the future of Go! Take the 2026 Go Developer Survey

provider

package
v0.29.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package provider defines keryx's pluggable backend seams.

Every external backend — image, video, voice, music generation and rendering — sits behind a narrow interface here, with the concrete implementation chosen from user config at construction (providers.<capability>) via the registry (registry.go). Requests are provider-neutral: they carry keryx's intent (a prompt, an aspect, voice settings, a timeline), never vendor payloads; each adapter maps intent to its own API and back. Adding an adapter is purely additive — implement the interface and register a constructor; no call site changes (spec 0001 §3.4).

Index

Constants

This section is empty.

Variables

View Source
var (
	ImageFactory = NewFactory[ImageProvider]("image", "gemini")
	VideoFactory = NewFactory[VideoProvider]("video", "gemini")
	VoiceFactory = NewFactory[VoiceProvider]("voice", "elevenlabs")
	MusicFactory = NewFactory[MusicProvider]("music", "elevenlabs")
	// Rendering defaults to afmpeg so a fresh install renders with nothing but keryx
	// present (keryx #21). The shell-out ffmpeg adapter stays available as a
	// deliberate power-user choice for anyone who wants their own tuned build.
	RenderFactory = NewFactory[Renderer]("render", "afmpeg")
)

The capability factories. Adapters register their constructors against these (e.g. provider.Voice.Register("elevenlabs", newElevenLabs)); call sites use Resolve(cfg) and never name a vendor. Defaults match spec §3.4.

View Source
var ErrAudioOverrunsVideo = errors.NewSentinel(
	"keryx.audio_overruns_video", "the audio mix outlasts the video timeline")

ErrAudioOverrunsVideo is returned when a timeline's mix would still be playing after its last frame.

View Source
var ErrUnknownProvider = errors.NewSentinel("keyrx.unknown_provider", "unknown provider")

ErrUnknownProvider is returned when providers.<capability> names an adapter that has not been registered.

Functions

This section is empty.

Types

type AdvisoryReporter added in v0.18.1

type AdvisoryReporter interface {
	Advisories() string
}

AdvisoryReporter is an OPTIONAL render-backend capability: what the engine said about a run that SUCCEEDED.

An engine writes real diagnostics on runs that exit zero — a codec falling back, timestamps being reconstructed, frames dropped, an option ignored. A render can be degraded and green at once. Backends conventionally inspect stderr only when the exit code is non-zero, so all of that is discarded and the absence of a warning proves nothing: it was never kept (keryx#35).

The string is whatever the engine wrote, unparsed, and empty when it said nothing. It describes the most recent run, so callers read it straight after rendering.

type Audio

type Audio struct {
	Data   []byte
	Format string
}

Audio is generated audio: raw bytes and format ("mp3"/"wav").

type AudioTrack

type AudioTrack struct {
	Path     string
	Gain     float64
	DelaySec float64
	// FadeOut, when > 0, applies an end fade of this many seconds (the music bed).
	FadeOut float64
	// DurationSec is the clip's own length, and 0 means "not measured" rather than
	// "empty" — the music bed is assembled from a path alone and nothing probes it.
	// It exists so AudioExtentSec can say where the mix ends without a render
	// backend re-probing every input it was already handed.
	DurationSec float64
}

AudioTrack is one input to the audio mix: a file, its gain, and a delay.

type BackendReporter added in v0.12.0

type BackendReporter interface {
	Backend() (name string, declined error)
}

BackendReporter is an OPTIONAL render-backend capability: naming the engine actually in use, and the reason a faster one was passed over.

It exists because a backend can silently choose the slow path. afmpeg prefers a native driver and falls back to the WASM engine where the release publishes none for the host — correct behaviour, but the difference is minutes per render, and "it took eight minutes" is not a symptom anyone traces to a missing artefact unaided. A backend that only ever has one engine simply does not implement this.

name is empty until the backend has actually committed to an engine, which for a lazily-compiled runtime is the first probe or render. Callers must treat empty as "not yet known" rather than reporting it.

type Clip

type Clip struct {
	Data        []byte
	Format      string
	DurationSec float64
}

Clip is a generated short video: raw bytes, format, and its duration.

type Constructor

type Constructor[T any] func(cfg config.Reader) (T, error)

Constructor builds a provider of type T from the active config. It reads its own provider config block (endpoint, model, credentials via keychain/env — never committed) as needed.

type DescribeRequest

type DescribeRequest struct {
	// Image is the reference to analyse.
	Image RefImage
	// Prompt is the analysis instruction (what to extract, in what shape).
	Prompt string
	// Model optionally forces a specific provider model; empty = adapter default.
	Model string
}

DescribeRequest asks the provider to analyse a reference image into text (vision). Used to auto-capture an avatar's likeness / style / palette profile on first registration (spec 0006 §4).

type DictLocator added in v0.4.0

type DictLocator struct {
	DictionaryID string
	VersionID    string
}

DictLocator references a provider pronunciation dictionary (optionally pinned to a version); the latest version resolves at run time when VersionID is empty.

type Factory

type Factory[T any] struct {
	// contains filtered or unexported fields
}

Factory resolves the configured adapter for one capability. Construction is config-driven: providers.<capability> selects a registered constructor; a blank/unknown value falls back to the default. Adding an adapter = Register a constructor; no call-site changes (spec 0001 §3.4).

func NewFactory

func NewFactory[T any](capability, defaultName string) *Factory[T]

NewFactory creates a factory for a capability with the given default adapter name (the name its real default constructor registers under).

func (*Factory[T]) Capability

func (f *Factory[T]) Capability() string

Capability returns the config key segment (providers.<capability>).

func (*Factory[T]) Names

func (f *Factory[T]) Names() []string

Names returns the registered adapter names, sorted.

func (*Factory[T]) Register

func (f *Factory[T]) Register(name string, c Constructor[T])

Register adds a named constructor. Adapters call this from an init() so that importing the adapter package wires it in.

func (*Factory[T]) Resolve

func (f *Factory[T]) Resolve(cfg config.Reader) (T, error)

Resolve builds the configured adapter. It selects by providers.<capability> (blank → default) and errors if the selected name is not registered.

func (*Factory[T]) Selected

func (f *Factory[T]) Selected(cfg config.Reader) string

Selected returns the adapter name that would be used for the given config: providers.<capability> if set, else the default.

type Image

type Image struct {
	Data   []byte
	Format string
}

Image is a generated still: raw bytes plus their format ("png"/"jpeg").

type ImageProvider

type ImageProvider interface {
	Generate(ctx context.Context, req ImageRequest) ([]Image, error)
	// Describe analyses a reference image and returns the model's text response.
	Describe(ctx context.Context, req DescribeRequest) (string, error)
}

ImageProvider generates still images and analyses them (default adapter: Gemini / Imagen).

type ImageRequest

type ImageRequest struct {
	// Prompt is the fully-composed visual description (theme style prefix +
	// scene). Adapters append their own wordless/no-text hardening.
	Prompt string
	// Aspect is the target aspect ratio, e.g. "16:9" or "9:16".
	Aspect string
	// Count is how many candidate images to return (N-candidates, then keep a
	// clean one — spec §3.1). Zero means one.
	Count int
	// Refs are optional reference images (image-to-image; e.g. portrait).
	Refs []RefImage
	// Model optionally forces a specific provider model id (e.g. a Gemini image
	// model). Empty means the adapter chooses (config default, then its fallback
	// chain).
	Model string
}

ImageRequest asks for one or more candidate stills for a prompt. When Refs is non-empty the request is image-to-image (the adapter conditions on the reference images); otherwise it is text-to-image.

type LexiconManager added in v0.7.0

type LexiconManager interface {
	SyncLexicon(ctx context.Context, req SyncLexiconRequest) (LexiconResult, error)
}

LexiconManager is an OPTIONAL capability a VoiceProvider may also implement: managing the provider's pronunciation dictionary (spec 0022 R-GEN-35). A voice command feature-detects it with a type assertion and reports a clear error when the active provider does not support dictionary management.

type LexiconResult added in v0.7.0

type LexiconResult struct {
	DictionaryID string
	VersionID    string
	RuleCount    int
	Created      bool
}

LexiconResult reports the dictionary the sync landed on: its id, the new version, how many rules it now carries, and whether the dictionary was created.

type LexiconRule added in v0.7.0

type LexiconRule struct {
	Grapheme string
	Alias    string
	Phoneme  string
	Alphabet string
}

LexiconRule is one pronunciation-dictionary entry: a grapheme (the word as written) mapped either to an Alias (a phonetic respelling) or to a Phoneme in a named Alphabet (e.g. "ipa"). Exactly one of Alias / Phoneme is set — Alias wins if both are, and Alphabet is meaningful only alongside Phoneme.

func (LexiconRule) IsPhoneme added in v0.7.0

func (r LexiconRule) IsPhoneme() bool

IsPhoneme reports whether the rule is a phoneme rule (vs. an alias respelling).

type MusicProvider

type MusicProvider interface {
	Compose(ctx context.Context, req MusicRequest) (Audio, error)
}

MusicProvider composes a music bed (default: ElevenLabs Music).

type MusicRequest

type MusicRequest struct {
	// Prompt is the tone-matched bed description.
	Prompt string
	// LengthMS is the requested length in milliseconds — derived from the reel's
	// computed total, not hand-set (spec §3.1).
	LengthMS int
}

MusicRequest asks for a music bed of a given length.

type Progress added in v0.8.0

type Progress struct {
	Percent float64
}

Progress is one render-progress sample: the percentage complete (0..100). A struct (not a bare float) so a future sample field lands without re-threading the callback signature through the render → CLI/studio chain.

type ProgressRenderer added in v0.8.0

type ProgressRenderer interface {
	RenderProgress(ctx context.Context, fs afero.Fs, t Timeline, onProgress func(Progress)) (Video, error)
}

ProgressRenderer is an OPTIONAL render-backend capability: rendering while streaming live progress to onProgress (spec 0026). Both shipped backends now implement it — native ffmpeg by parsing `-progress`, afmpeg via its progress channel (v0.12.0). It stays optional because a third-party backend need not, and callers type-assert and fall back to Render: the reel still renders, just without a live percentage.

Percent is NEGATIVE when completion cannot be determined — a generative input with no source to consume, and an engine reporting no duration. A caller must be able to tell "0% done" from "cannot say", or a stuck bar and an unknowable one look identical.

type Quota added in v0.8.0

type Quota struct {
	Used      int       `json:"used"`
	Limit     int       `json:"limit"`
	Remaining int       `json:"remaining"`
	ResetAt   time.Time `json:"reset_at"`
}

Quota is a voice provider's account character quota for the current period: characters used, the period limit, the derived remaining, and when the counter next resets (zero if the provider reports none).

type QuotaReporter added in v0.8.0

type QuotaReporter interface {
	Quota(ctx context.Context) (Quota, error)
}

QuotaReporter is an OPTIONAL capability a VoiceProvider may also implement: reporting the account's character quota (used / limit / remaining), so the user can see how much headroom they have before spending. It is a read (no synthesis). A command feature-detects it with a type assertion and reports "unavailable" when the active provider does not track a quota.

type RefImage

type RefImage struct {
	Data []byte
	MIME string
}

RefImage is a reference image for image-to-image generation (e.g. the portrait avatar from reference photos).

type Renderer

type Renderer interface {
	Render(ctx context.Context, fs afero.Fs, t Timeline) (Video, error)
	// Probe returns a media file's duration in seconds — used for VO-driven card
	// timing, before the Timeline is built. It lives on the render backend so the
	// in-memory adapter can probe via the same engine (no system ffprobe).
	Probe(ctx context.Context, fs afero.Fs, path string) (float64, error)
}

Renderer composites a timeline into a finished video. It reads inputs from, and writes the output into, the given afero.Fs — so an in-memory backend (afmpeg) can render a project that lives entirely in memory (a RAM/git worktree fs), not just an on-disk checkout. The shell-out ffmpeg backend materialises a non-OS fs to a temp dir and back. Timeline/Probe paths are paths within fs.

type Segment

type Segment struct {
	MediaPath   string
	DurationSec float64
}

Segment is one visual element of the timeline: a media file shown for a duration. Card text/scrim compositing is owned by the renderer adapter; this is intentionally minimal and enriched by the reel core (Phase 1d).

type Silence added in v0.4.0

type Silence struct {
	StartSec float64
	EndSec   float64
}

Silence is a detected quiet interval in an audio file; EndSec is 0 when the file ends still silent.

type SilenceDetector added in v0.4.0

type SilenceDetector interface {
	DetectSilence(ctx context.Context, fs afero.Fs, path string) ([]Silence, error)
}

SilenceDetector is an OPTIONAL render-backend capability: detecting silences in an audio file (via the engine's silencedetect), used by VO take screening (spec 0023). A render backend may implement it; screening type-asserts and falls back to duration-only ranking when the active backend doesn't.

type SyncLexiconRequest added in v0.7.0

type SyncLexiconRequest struct {
	DictionaryID string
	Name         string
	Rules        []LexiconRule
}

SyncLexiconRequest pushes a set of rules to a provider pronunciation dictionary. An empty DictionaryID asks the provider to create a new dictionary named Name; otherwise the rules are upserted into the existing dictionary (a rule whose Grapheme already exists is replaced). Removed graphemes are not pruned.

type Timeline

type Timeline struct {
	Width      int
	Height     int
	FPS        int
	XFadeSec   float64
	Segments   []Segment
	Audio      []AudioTrack
	OutputPath string
}

Timeline is the provider-neutral render request: ordered visual segments crossfaded together with a mixed audio bed, at the target geometry.

func (Timeline) AudioExtentSec added in v0.18.1

func (t Timeline) AudioExtentSec() float64

AudioExtentSec is where the mix ends: the latest point any track still plays, max(DelaySec + DurationSec). Tracks of unmeasured length contribute their delay alone, so the answer is a floor rather than a guess.

func (Timeline) CheckAudioFits added in v0.18.1

func (t Timeline) CheckAudioFits() error

CheckAudioFits rejects a timeline whose mix ends after its last frame.

The two numbers are computed independently and nothing used to compare them. Video length is the segments less their crossfades; the mix is each clip delayed to its own card's start and running for its own length, so a card whose padding is trimmed to nothing puts its narration's tail past the end of the reel.

Which way that breaks depends on the engine, and NEITHER outcome is what the author asked for: a backend enforcing its output bound truncates the narration, one that does not renders long and says nothing (ffmpeg-wasi#66 was the second for every mixed output). Caught here it is legible as what it is, before an engine runs, whichever release is pinned.

func (Timeline) VideoDurationSec added in v0.18.1

func (t Timeline) VideoDurationSec() float64

VideoDurationSec is the assembled reel's length: the segments laid end to end, less one crossfade per join. It is the bound a backend renders to.

type Video

type Video struct {
	Path        string
	Width       int
	Height      int
	DurationSec float64
}

Video is the rendered result: the output path and its measured properties.

type VideoProvider

type VideoProvider interface {
	Generate(ctx context.Context, req VideoRequest) ([]Clip, error)
}

VideoProvider generates short per-panel video clips (default: Gemini Omni). Optional capability — the reel works fully with stills + uploaded media; this is enabled when a card asks for a generated video (deferred to Phase 5).

type VideoRequest

type VideoRequest struct {
	Prompt      string
	Aspect      string
	DurationSec float64
	Count       int
}

VideoRequest asks for one or more short candidate clips for a prompt.

type VoiceProvider

type VoiceProvider interface {
	Synthesize(ctx context.Context, req VoiceRequest) (Audio, error)
}

VoiceProvider synthesises narration (default: ElevenLabs).

type VoiceRequest

type VoiceRequest struct {
	// Text is the narration; it may carry provider control tags (e.g.
	// ElevenLabs SSML <break> or a phonetic spelling) — passed through verbatim.
	Text string
	// VoiceID identifies the clone in the active provider.
	VoiceID string
	// Stability / Similarity are clone settings (higher similarity favours
	// fidelity to the reference voice).
	Stability  float64
	Similarity float64
	// Style is expression/exaggeration (0 = none/most faithful; higher can drift
	// the accent). Speed is the speech rate (0.7 slow … 1.2 fast); 0 means use
	// the provider's default (1.0). SpeakerBoost toggles speaker enhancement; nil
	// means use the provider's default (on).
	Style        float64
	Speed        float64
	SpeakerBoost *bool
	// Model selects the TTS model; empty ⇒ the provider's default (spec 0022 B).
	Model string
	// AllowUnknownModel accepts a Model outside the provider's known allowlist
	// (an opt-in escape hatch for a brand-new model) instead of erroring.
	AllowUnknownModel bool
	// Pronounce is a line-scoped respelling used as the narration text on any model
	// (spec 0022 H); empty ⇒ Text is used. IPA is a phonetic rendering used on a
	// phoneme-capable model (spec 0022 I); it wins over Pronounce there and is
	// ignored on a model that can't apply phonemes.
	Pronounce string
	IPA       string
	// PronunciationDictionaries are provider pronunciation-dictionary locators
	// (spec 0022 A); empty ⇒ omitted, leaving the request byte-identical to today.
	PronunciationDictionaries []DictLocator
}

VoiceRequest is a single narration synthesis (voice clone).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL