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 ¶
- Variables
- type AdvisoryReporter
- type Audio
- type AudioTrack
- type BackendReporter
- type Clip
- type Constructor
- type DescribeRequest
- type DictLocator
- type Factory
- type Image
- type ImageProvider
- type ImageRequest
- type LexiconManager
- type LexiconResult
- type LexiconRule
- type MusicProvider
- type MusicRequest
- type Progress
- type ProgressRenderer
- type Quota
- type QuotaReporter
- type RefImage
- type Renderer
- type Segment
- type Silence
- type SilenceDetector
- type SyncLexiconRequest
- type Timeline
- type Video
- type VideoProvider
- type VideoRequest
- type VoiceProvider
- type VoiceRequest
Constants ¶
This section is empty.
Variables ¶
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.
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.
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 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
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 Constructor ¶
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
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 ¶
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 ¶
Capability returns the config key segment (providers.<capability>).
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.
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
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
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
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 ¶
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 ¶
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
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
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
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
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 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 ¶
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).