gencmd

package
v0.17.0 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Dry run (R-GLOBAL-5): price a generation without performing it. The commands that spend — cover, portrait, voice gen, music gen, cards gen — each expose this as `--dry-run`, so an operator (or an agent driving the CLI, or an MCP client that cannot answer an interactive prompt) can ask what a request would cost before committing to it. That is the workable form of R-MCP-3's confirm posture: the `reel make` guard is an interactive prompt, which cannot function over MCP.

Package gencmd holds workspace-aware take generation for the authoring loop: generate N candidate takes from a workspace's storyboard into <kind>/takes/, to be auditioned and selected (internal/takes). Generation is finite and bounded (R-GLOBAL-11) and every provider call is context-timed (R-GLOBAL-12).

Index

Constants

This section is empty.

Variables

View Source
var ErrNoQuota = errors.NewSentinel("keyrx.no_quota", "the configured voice provider does not report a character quota")

ErrNoQuota is returned when the configured voice provider does not report a character quota (an optional capability — spec 0016).

Functions

func CardTakes

func CardTakes(ctx context.Context, p *props.Props, slug string, card, n int, themeKw, avatarName string, force bool) error

CardTakes generates n candidate illustrations per target card into cards/takes/. card == 0 targets every overlay card that has a scene; otherwise just that 1-based card. Each card's prompt is the reel theme's illustration style + the card scene + the wordless hardening.

func DictLocators added in v0.4.0

func DictLocators(dictID string) []provider.DictLocator

DictLocators turns a theme/voice pronunciation-dictionary id into request locators (the latest version resolves at run time); empty ⇒ nil ⇒ omitted.

func EmitDryRun added in v0.12.0

func EmitDryRun(command string, dr DryRun) error

EmitDryRun reports a preview on stdout — the estimate in text, or the whole DryRun as structured data under `--output json` (R-GLOBAL-3), which is the form an MCP client reads (R-MCP-4).

func GenerateInto

func GenerateInto(ctx context.Context, p *props.Props, fs afero.Fs, req Request) ([]string, error)

GenerateInto runs one bounded, timed generation, writing Count candidate takes into the request's slot on fs and returning their paths (fs-relative). It is the single FS-explicit core the studio drives for every media kind — image (card / cover / portrait) and audio (VO / music) — on its active worktree (which may be an in-memory remote). Prompt/voice + take layout are shared with the CLI commands, so studio and CLI takes are identical.

func MusicTakes

func MusicTakes(ctx context.Context, p *props.Props, slug string, n int, themeKw string, lengthMS int, force bool) error

MusicTakes generates n candidate beds into music/takes/ (the CLI wrapper). lengthMS sizes the bed: 0 means "default to the VO-driven total" (the bed should cover the whole reel); a positive value is an explicit override (--length).

func ParseLines added in v0.4.0

func ParseLines(s string) ([]int, error)

ParseLines parses a `--lines` value — a comma list ("3,5,7"), a range ("3-6"), or a mix ("1,3-5,8") of 1-based storyboard lines — into a sorted, deduped list (spec 0023 §3.1).

func ResolveQuota added in v0.8.0

func ResolveQuota(cfg config.Reader) (provider.QuotaReporter, error)

ResolveQuota resolves the configured voice provider and its optional quota capability, returning ErrNoQuota when the provider tracks none. Shared by the `voice quota` CLI and the studio quota widget so both resolve identically.

func VOTakes

func VOTakes(ctx context.Context, p *props.Props, slug string, line, n int, themeKw, model string, allowUnknown, force bool) error

VOTakes generates n VO takes for storyboard line (1-based) into vo/takes/ (the CLI wrapper over the FS-explicit GenerateInto, on p.FS).

func VOTakesLines added in v0.4.0

func VOTakesLines(ctx context.Context, p *props.Props, slug string, lines []int, n int, themeKw, model string, allowUnknown, force bool) error

VOTakesLines re-rolls exactly the named lines — n fresh candidate takes each — leaving every other line's takes and selections untouched (R-GEN-36). Each line resolves its own per-card voice overrides, as the single-line path does.

Types

type DryRun added in v0.12.0

type DryRun struct {
	Target string     `json:"target"`
	Count  int        `json:"count"`
	Cost   spend.Cost `json:"cost"`
	// OverCap names the spend-guard axis the estimate crosses ("amount" |
	// "characters"), empty when it stays under both. The guard is not applied here —
	// a dry run spends nothing, so there is nothing to gate.
	OverCap string `json:"over_cap,omitempty"`
	// Noun is what one unit of the output is called in the TEXT form, where "take"
	// would be wrong — a storyboard draft is a board, not a candidate to choose
	// between. Empty means "take". Off the wire deliberately: it is prose, and the
	// JSON shape is a contract an MCP client reads.
	Noun string `json:"-"`
	// Uncached suppresses the "served from the cache without spending" line, which
	// is true of every media generation (R-GLOBAL-9) and false of a storyboard
	// draft — there is no content cache on the chat path, so a re-run pays again.
	// Someone acts on that sentence, so it must not be said where it is untrue.
	Uncached bool `json:"-"`
}

DryRun is what a generation would do and what it would cost. Count is the number of billable units the run would produce — takes for a single target, takes × cards for a whole-board card run — so it matches Cost.Count rather than the request's per-item `--takes`.

The estimate is an upper bound, not a prediction: an unchanged request is served from the content cache without spending (R-GLOBAL-9), and a real run may therefore cost nothing at all.

func Preview added in v0.12.0

func Preview(ctx context.Context, p *props.Props, fs afero.Fs, req Request) (DryRun, error)

Preview prices req without calling a provider and without writing anything. It reads the storyboard (to size VO narration and count the cards a whole-board run would generate) and the config (for rates and the cap), which is why it takes the same fs the real run would use.

func PreviewInWorkspace added in v0.12.0

func PreviewInWorkspace(ctx context.Context, p *props.Props, slug string, req Request) (DryRun, error)

PreviewInWorkspace prices a workspace-scoped generation (cards / VO / music) from its slug, mirroring CardTakes/VOTakes/MusicTakes so the slug→dir resolution stays in one place. Cover and portrait are not workspace-scoped and call Preview directly.

type Request

type Request struct {
	Target Target
	Dir    string // workspace dir on the target fs
	Card   int    // TargetCard: 1-based card index
	Line   int    // TargetVO: 1-based storyboard line
	Scene  string // TargetCard/TargetCover: the illustration scene
	Theme  string // theme keyword, resolved against the target's theme type
	// Aspect overrides the generated image's frame shape (TargetCover): a reel
	// cover follows the reel's aspect (0029 §9 note 27), not the article theme's.
	Aspect string
	Refs   []provider.RefImage // TargetPortrait: reference photos (image-to-image)
	// Avatars is the card's cast (TargetCard): registered avatar names whose likeness
	// is directed into the scene via image-to-image (spec 0034 D4). Empty = a plain
	// text-to-image card in the theme style (the pre-avatar behaviour).
	Avatars []string
	Count   int // candidate takes
	// LengthMS is the requested music bed length (TargetMusic): 0 = default to the
	// VO-driven total, positive = explicit override.
	LengthMS int
	// Model overrides the TTS model (TargetVO); empty ⇒ theme/default. AllowUnknown
	// accepts a Model outside the allowlist (spec 0022 B).
	Model        string
	AllowUnknown bool
	// Force bypasses the content cache (R-GEN-8): regenerate + refresh the cached set
	// even when the request is unchanged. Maps to the CLI `--force`.
	Force bool
}

Request is a provider-neutral studio generation request: keryx's intent (what to make, under which theme), not a vendor payload.

type Target

type Target int

Target selects what a workspace generation produces: a per-card illustration, the cover bookend, or an avatar portrait. Each maps to a theme type, a request shape, and a takes slot — the one mechanism behind the studio's card/cover/portrait media (spec 0013 §4).

const (
	TargetCard Target = iota
	TargetCover
	TargetPortrait
	TargetVO    // per storyboard line (Request.Line) — vo/takes/NN-T.mp3
	TargetMusic // one bed per workspace — music/takes/T.mp3
)

Jump to

Keyboard shortcuts

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