Public API reference
Import these names from kenkui. This page covers kenkui.__all__; signatures and
fields below are rendered from the source at documentation build time. Underscore
modules and operation implementation classes are private, even when a type annotation
mentions them. Prefer the constructors and fluent methods to creating
Pipeline.operations directly. __version__ is the installed package's version
string.
See the usage guide for complete workflows, operation ordering, checkpoint reuse, publication semantics, and examples.
Constructors and convenience rendering
book() and epub() record a path without opening it. magic_run() performs
resolution and rendering, returning the same result as Pipeline.write().
kenkui.book
book(path: str | PathLike[str]) -> Pipeline
Dispatch a supported source by its format marker without reading it.
kenkui.epub
epub(path: str | PathLike[str]) -> Pipeline
Record EPUB source intent without opening or parsing the path.
kenkui.magic_run
magic_run(
book_path: str | PathLike[str],
*,
narrator: str,
multi: bool = False,
model: str = "openrouter/deepseek/deepseek-v4-flash",
) -> Result
Render an EPUB with one narrator or an automatically assigned cast.
Pipeline and source
Intent methods return new immutable branches. pipe() immediately calls an ordinary
function; validate() reads inexpensive local state; inspect() parses the selected
source or returns a saved checkpoint. resolve() may load local models, make provider
calls, and save casting/series records. write() and write_m4b() validate and
publish an M4B using spawned synthesis processes. Call effectful workflows from a
guarded script entry point.
attribute(), silence(), and the scoped form of pronounce() declare per-book
tuning rules addressed with where=; annotations() and write_annotations() load
and save them as a JSON sidecar. select() and preview() narrow a render to part of
a book for a quick probe. identity, tuning, and style summarize a pipeline's
declared intent by tier. See tuning a book and the dial-in
loop for the full workflow.
kenkui.Source
dataclass
A lazily recorded readable source.
path
instance-attribute
path: Path
format
instance-attribute
format: Literal['epub']
kenkui.Pipeline
dataclass
A source plus ordered immutable audiobook intent.
source
instance-attribute
source: Source
operations
class-attribute
instance-attribute
operations: tuple[Operation, ...] = ()
metadata_intent
property
metadata_intent: MetadataIntent | None
Return recorded metadata intent, if present.
identity
property
identity: TierSummary
Return this book's identity-tier intent: what makes it this book.
A tuple scan over operations with no parse and no I/O. repr
is the summary; iterate it for the declared operations themselves.
tuning
property
tuning: TuningSummary
Return this book's tuning rules, grouped by kind and marked unsaved.
A tuple scan over operations with no parse and no I/O. repr
is a truncated summary; iterate it for every declared rule.
style
property
style: TierSummary
Return this book's style-tier intent: reusable taste, not this book.
A tuple scan over operations with no parse and no I/O. Style
settings replace rather than accumulate, so each entry already shows
its effective value. repr is the summary; iterate it for the
declared operations themselves.
pipe
pipe(
function: Callable[
Concatenate[Pipeline, _PipeArgs], _PipeResult
],
/,
*args: args,
**kwargs: kwargs,
) -> _PipeResult
Pass this pipeline to an ordinary function and return its result.
The function runs immediately with this pipeline as its first argument. Return a pipeline to continue chaining, or a report to leave the chain. Any effects and exceptions belong to the supplied function.
select_chapters
select_chapters(*chapter_ids: str) -> Pipeline
Return a branch selecting explicit stable chapter IDs.
select_chapter_range
select_chapter_range(
start_id: str, end_id: str
) -> Pipeline
Return a branch selecting an inclusive stable-ID spine range.
select
select(
*patterns: Pattern | Mapping[str, object],
) -> Pipeline
Select a union of grid subtrees while retaining source paths and casting.
Patterns use the original book's coordinates and sibling counts. They combine in source order without duplication. Full-render chunks wholly inside each selected interval retain their cache identities; chunks at either edge are clipped to the requested text.
pronounce
pronounce(
lexicon: Mapping[str, str] | None = None,
*,
where: WhereArg = None,
numbers: str | None = None,
builtin: bool | None = None,
**features: bool,
) -> Pipeline
Return a branch shaping what the engine says, not what it counts.
This is the only stage that rewrites text for speech. It runs last, per segment, and its output is thrown away after synthesis: canonical text, the billable character count, attribution offsets, and chapter identity are all unaffected. Normalization -- NFC, line endings, Unicode spaces, whitespace runs -- is not part of this and is not optional; it happens when the source is parsed.
Off unless called. What it does when called:
- replaces entries from
lexicon, then a small built-in pronunciation table unlessbuiltin=False; - reads numbers aloud, at the depth
numbersselects --"off","conservative"(the default),"standard"or"aggressive"; - collapses hyphenated vocal gestures the engine would otherwise read
out as letter names -- an elongation ("Ah-h-h" becomes "Ahhh") and a
stammer ("S-s-sorry" becomes "Sssorry"). Both are on, and each is
declined by name:
elongation,stammer. Ordinary hyphenation is untouched, including reduplication such as "drip-drip-drip".
numbers is a preset over individually switchable features, each
of which may be overridden by keyword: currency, percent,
ordinals, units, decimals, integers, years,
clock, roman, fractions, numbered. Passing False
declines a feature the tier supplies; passing True asks for one
it does not, without accepting the rest of the tier that carries it.
pipeline.pronounce(numbers="standard", roman=False)
Features compose rather than nest, so declining a specific form
leaves a general one free to match inside it: currency=False
alone reads "£5" as "£five", because the integer rule still applies.
Decline integers too to leave the digits alone.
Lexicons accumulate as scoped tuning rules selected by where.
A tuple of patterns or mappings adds one rule per selector in order.
A whole-book rule applies everywhere; a scoped one overrides it inside
its own region and shares the keys it does not mention.
Number presets, built-in pronunciation, and feature switches are global settings rather than rules, and each keeps its last stated value. Adding a pronunciation therefore leaves the style a house function already chose alone -- only naming a setting changes it.
attribute
attribute(
character_id: str, *, where: WhereArg = None
) -> Pipeline
Return a branch attributing matched units to one character.
Calls accumulate ordered rules. Narrower match sets take precedence; later declarations break ties between equal or incomparable match sets. A tuple of patterns or mappings adds one rule per selector in order.
annotations
annotations(
path: str | PathLike[str] | None = None,
) -> Pipeline
Load one immutable tuning baseline beneath inline declarations.
Reads only the sidecar. The digest identifies exactly the bytes parsed; later edits to that file cannot change this pipeline branch. Exact duplicates across the file/code boundary retain their loaded copy and anchor metadata. Other inline rules follow the loaded prefix.
A book that has never been saved has no sidecar yet: that is a no-op
baseline, not an error. A sidecar that exists but cannot be read or
parsed is a different problem -- a damaged correction file -- and
still raises INVALID_SIDECAR.
write_annotations
write_annotations(
path: str | PathLike[str] | None = None,
) -> Path
Save tuning with current text anchors, without changing this branch.
Annotation scope is the source book, independent of render selection. Writing explicitly inspects that book and builds only touched grids.
silence
silence(
duration_ms: int, *, where: WhereArg = None
) -> Pipeline
Return a branch replacing the silence after matched positions.
Zero removes a derived pause. A subtree anchors to its final leaf; declaration records that intent without reading or resolving the book. A tuple of patterns or mappings adds one rule per selector in order.
pauses
pauses(
*,
chapter_ms: int = 0,
heading_before_ms: int = 0,
heading_after_ms: int = 0,
paragraph_ms: int = 0,
line_ms: int = 0,
) -> Pipeline
Return a branch requesting silence at structural boundaries.
Off unless called. Durations are retunable without re-synthesis: only turning a tier on or off changes segment identity, because only that changes where a segment ends.
infer_characters
infer_characters(
model: str,
*,
identity: str | None = DEFAULT_IDENTITY_MODEL,
) -> Pipeline
Return a branch that will derive a character roster.
identity selects the reasoning model that merges aliases and
removes non-people from a spaCy roster. None stays fully offline.
attribute_quotes
attribute_quotes(model: str) -> Pipeline
Return a branch that will assign a speaker to each quoted run.
assign_voice
assign_voice(voice: str | Voice) -> Pipeline
Return a branch assigning one stable voice ID to all speech.
The degenerate cast: narrator only. One VoicePlan and one renderer serve this and a full character cast alike.
assign_voices
assign_voices(
*,
narrator: str | Voice,
unknown: str | Voice | None = None,
cast: Mapping[str, str | Voice] | None = None,
method: str = "gendered",
) -> Pipeline
Return a branch casting narrator, unknown, and named characters.
unknown defaults to the narrator's voice, so a line nobody could
place sounds like narration rather than vanishing.
tts
tts() -> Pipeline
Return a branch with explicit synthesis intent.
metadata
metadata(
*,
title: str | None = None,
author: str | None = None,
cover: Literal["source"]
| PathLike[str]
| None = "source",
) -> Pipeline
Return a branch with output metadata inheritance and overrides.
series
series(
series_id: str,
*,
book: int | None = None,
allow_recast: bool = False,
allow_narrator_change: bool = False,
) -> Pipeline
Return a branch tying this book to a series.
A character the series already cast keeps their voice, and voices
continue spreading across volumes rather than restarting. book is
stored in pipeline intent as an ordering hint; it does not schedule or
sort volumes. Continuity is decided by identity, not by volume number.
Two ways a series can be contradicted fail validation before any
model call: a pinned voice missing from the pool, and a narrator
differing from the one the series recorded. allow_recast and
allow_narrator_change each waive their matching failure so the
render proceeds instead of refusing.
resolve
resolve(
*,
until: Literal["characters", "casting"] = "casting",
cancel: CancellationToken | None = None,
on_event: Callable[[ExecutionEvent], None]
| None = None,
) -> Pipeline
Resolve voices, attribution, and casting, returning a new Pipeline.
Optional. write() resolves internally, so this exists only to pay
the model cost early and inspect the outcome. It is an effect -- it
reaches the network and writes the store -- but it is immutable,
idempotent for unchanged source bytes, and leaves intent untouched.
Use until="characters" to stop after discovery without requiring
voices or attributing quotes. inspect().roster exposes that result;
with_characters() records corrections before continuing.
After source changes, a roster checkpoint must be refreshed with
resolve(until="characters") and reviewed again. Pipelines without
roster checkpoints can refresh their cast with ordinary resolve().
Rendering an old checkpoint raises source_changed.
Pass a cancellation token to stop between model calls and before committing series changes. A running provider call must return before cooperative cancellation can take effect.
on_event receives discovery and attribution stage progress on the
calling thread, between Started and Completed events. An unchanged
checkpoint emits only those run events because no stages repeat.
with_characters
with_characters(roster: CharacterRoster) -> Pipeline
Return a branch using a reviewed character-discovery checkpoint.
First call resolve(until="characters"). Changes replace the roster,
preserve its source snapshot, and invalidate attribution and casting.
This method performs no I/O.
validate
validate() -> ValidationResult
Perform inexpensive source and operation validation without parsing.
script
script() -> Script
Inspect canonical review rows lazily, without resolution or model calls.
inspect
inspect() -> BookInspection
Inspect this checkpoint without synthesis or model calls.
Before resolution, parse and select current source text. Afterwards, return the frozen source, roster, attribution, and cast snapshot.
write
write(
output: str | PathLike[str],
*,
on_event: Callable[[ExecutionEvent], None]
| None = None,
cancel: CancellationToken | None = None,
workers: int | Literal["auto"] = "auto",
overwrite: bool = False,
keep_audio_cache: bool = False,
) -> Result
Write an M4B through the private execution orchestration boundary.
write_m4b
write_m4b(
output: str | PathLike[str],
*,
on_event: Callable[[ExecutionEvent], None]
| None = None,
cancel: CancellationToken | None = None,
workers: int | Literal["auto"] = "auto",
overwrite: bool = False,
keep_audio_cache: bool = False,
) -> Result
Validate controls and execute using privately bound rendering resources.
preview
preview(
output: str | PathLike[str],
*,
on_event: Callable[[ExecutionEvent], None]
| None = None,
workers: int | Literal["auto"] = "auto",
overwrite: bool = False,
) -> Result
Write a PCM WAV probe and retain synthesized segments for later reuse.
Requires assigned voices and adds TTS intent on a temporary branch
when needed. The original pipeline is unchanged. The destination must end in
.wav. Bibliographic metadata, cover art, and chapter markers are
omitted from the artifact; normal execution events still report work.
kenkui.MetadataIntent
dataclass
Semantic output metadata overrides and cover choice.
title
class-attribute
instance-attribute
title: str | None = None
author
class-attribute
instance-attribute
author: str | None = None
cover
class-attribute
instance-attribute
cover: Literal['source'] | Path | None = 'source'
The tuning read model
Pipeline.script() returns a Script: one ScriptRow per grid unit, carrying the
effective speaker, its provenance, and the silence that follows it, without
resolving voices or calling a model.
kenkui.Script
dataclass
A chapter-lazy read model whose iteration yields rows in source order.
script[path] returns a single row (a partial path must be unambiguous).
at(pattern) yields matching rows. This is mapping-like, rather than a
Mapping subclass, because iteration yields rows instead of keys.
Construction inspects source text without resolution or model calls.
Grids are built only on access, once per chapter. materialized and
warnings are cheap immutable snapshots; neither triggers more work.
materialized
property
materialized: tuple[str, ...]
Return cached chapter IDs in their first-access order.
warnings
property
warnings: tuple[ValidationIssue, ...]
Return drift findings discovered so far, in declaration order.
at
at(
pattern: Pattern | Mapping[str, object],
) -> Iterator[ScriptRow]
Yield matches while materializing only chapters the pattern selects.
kenkui.ScriptRow
dataclass
One canonical unit and the effective speaker and following silence.
Whitespace-only units retain their text and path but carry zero silence; their gaps settle onto the preceding speech-bearing row, as in planning.
path
instance-attribute
path: Path
text
instance-attribute
text: str
character
instance-attribute
character: str | None
provenance
instance-attribute
provenance: Provenance
rule_index
instance-attribute
rule_index: int | None
silence_after_ms
instance-attribute
silence_after_ms: int
is_dialogue
instance-attribute
is_dialogue: bool
is_emphasised
instance-attribute
is_emphasised: bool
Inspection and character review
BookInspection.roster is populated at a character-review checkpoint;
BookInspection.casting is populated after full resolution. They are absent before
the corresponding work is done. Span offsets refer to the normalized chapter text in
the same inspection. Edit frozen records using dataclasses.replace() and pass a
reviewed roster to with_characters().
kenkui.BookInspection
dataclass
Source information plus casting when this pipeline has been resolved.
metadata
instance-attribute
metadata: BookMetadata
chapters
instance-attribute
chapters: tuple[ChapterInspection, ...]
casting
class-attribute
instance-attribute
casting: CastingInspection | None = None
roster
class-attribute
instance-attribute
roster: CharacterRoster | None = None
kenkui.BookMetadata
dataclass
Bibliographic metadata materialized from a readable source.
title
class-attribute
instance-attribute
title: str | None = None
author
class-attribute
instance-attribute
author: str | None = None
cover_available
class-attribute
instance-attribute
cover_available: bool = False
kenkui.ChapterInspection
dataclass
Stable chapter information available without rendering.
id
instance-attribute
id: str
index
instance-attribute
index: int
title
instance-attribute
title: str
speech_characters
instance-attribute
speech_characters: int | None
text
class-attribute
instance-attribute
text: str = ''
headings
class-attribute
instance-attribute
headings: tuple[str, ...] = ()
emphasis
class-attribute
instance-attribute
emphasis: tuple[tuple[int, int], ...] = ()
heading_ranges
class-attribute
instance-attribute
heading_ranges: tuple[tuple[int, int], ...] = ()
kenkui.CharacterRoster
dataclass
Discovered or reviewed characters before quote attribution.
Chapter IDs describe where a name was found, when known. Speech counts
are measured later, after attribution. narrator_id identifies a
first-person narrating character, independently of the narrator voice.
characters
instance-attribute
characters: tuple[CharacterProfile, ...]
narrator_id
class-attribute
instance-attribute
narrator_id: str | None = None
kenkui.CharacterProfile
dataclass
One speaking character, measured in normalized speech characters.
spoken_characters is the prominence weight throughout, matching the unit chunking, progress, and billing already use.
id
instance-attribute
id: str
display_name
instance-attribute
display_name: str
gender
instance-attribute
gender: str | None
spoken_characters
instance-attribute
spoken_characters: int
chapter_ids
instance-attribute
chapter_ids: tuple[str, ...]
aliases
class-attribute
instance-attribute
aliases: tuple[str, ...] = ()
kenkui.CastingInspection
dataclass
A resolved roster, cast, and attribution without rendering resources.
Assignments are immutable (character_id, voice_id) pairs. Collisions
describe expected voice sharing within chapters when voices are limited.
Span offsets refer to the normalized chapter text in the same inspection.
narrator_voice_id
instance-attribute
narrator_voice_id: str
unknown_voice_id
instance-attribute
unknown_voice_id: str
characters
class-attribute
instance-attribute
characters: tuple[CharacterProfile, ...] = ()
assignments
class-attribute
instance-attribute
assignments: tuple[tuple[str, str], ...] = ()
spans
class-attribute
instance-attribute
spans: tuple[SpeakerSpan, ...] = ()
collisions
class-attribute
instance-attribute
collisions: tuple[Collision, ...] = ()
kenkui.SpeakerSpan
dataclass
One contiguous run of a chapter's normalized text with a single speaker.
chapter_id
instance-attribute
chapter_id: str
start
instance-attribute
start: int
end
instance-attribute
end: int
character_id
instance-attribute
character_id: str | None
kenkui.Collision
dataclass
Two characters sharing one voice inside one chapter.
chapter_id
instance-attribute
chapter_id: str
first
instance-attribute
first: str
second
instance-attribute
second: str
voice_id
instance-attribute
voice_id: str
Voices and provisioning
list_voices() reads catalog/local state. Registration, loading, unloading, and
removal modify local voice state; loading may download assets or compile a supplied
WAV. Rendering never provisions voices implicitly. See
provisioning for state transitions and models and
voices for asset requirements.
kenkui.Voice
dataclass
Reusable voice identity, content, compatibility, and rights metadata.
id
instance-attribute
id: str
name
instance-attribute
name: str
enabled
instance-attribute
enabled: bool
provenance
instance-attribute
provenance: str | None
license_id
instance-attribute
license_id: str | None
commercial_use_allowed
instance-attribute
commercial_use_allowed: bool | None
language
class-attribute
instance-attribute
language: str | None = None
content_fingerprint
class-attribute
instance-attribute
content_fingerprint: str | None = None
compatible_model_revisions
class-attribute
instance-attribute
compatible_model_revisions: tuple[str, ...] = ()
variety
class-attribute
instance-attribute
variety: VoiceVariety = 'built-in'
state
class-attribute
instance-attribute
state: VoiceState = 'registered'
asset_bytes
class-attribute
instance-attribute
asset_bytes: int | None = None
engine
class-attribute
instance-attribute
engine: Engine | None = None
perceived_gender
class-attribute
instance-attribute
perceived_gender: PerceivedGender = None
voice_rights
class-attribute
instance-attribute
voice_rights: str | None = None
kenkui.Engine
dataclass
A provisioned per-language synthesis engine.
id
instance-attribute
id: str
language
instance-attribute
language: str
model_revision
instance-attribute
model_revision: str
cloning_capable
instance-attribute
cloning_capable: bool
size_bytes
instance-attribute
size_bytes: int
kenkui.list_voices
list_voices(
*, manifest: Path | None = None
) -> tuple[Voice, ...]
Return every known voice, unioning the catalog with the manifest.
No network and no hashing: asset presence is a stat. This is the only enumeration primitive, so multi-voice work composes over it.
kenkui.add_voice
add_voice(
path: str | PathLike[str],
*,
voice_id: str,
name: str,
language: str,
provenance: str,
license_id: str,
commercial_use_allowed: bool,
voice_rights: str,
perceived_gender: PerceivedGender = None,
manifest: Path | None = None,
) -> Voice
Register a local WAV or safetensors voice with explicit rights metadata.
Cheap and offline: hashes the source, records the rights fields verbatim,
and writes a registered entry. Call load_voice to make it renderable.
kenkui.load_voice
load_voice(
voice_id: str, *, manifest: Path | None = None
) -> Voice
Make one voice renderable, downloading or compiling only if required.
Idempotent: a voice whose asset is present and hash-verified performs no network access at all.
kenkui.unload_voice
unload_voice(
voice_id: str, *, manifest: Path | None = None
) -> Voice
Delete a voice's asset, keep its rights metadata, and prune its engine.
kenkui.remove_voice
remove_voice(
voice_id: str, *, manifest: Path | None = None
) -> None
Delete a voice entry entirely, including hand-entered rights metadata.
Equivalent to unload_voice for a built-in, whose catalog registration
cannot be deleted.
Pronunciation lexicons
builtin_lexicon() returns a fresh dictionary. read_lexicon() reads and validates a
local JSON file. Pass either result to Pipeline.pronounce(); reading a lexicon does
not change a pipeline by itself.
kenkui.builtin_lexicon
builtin_lexicon() -> dict[str, str]
Return a copy of the pronunciation table Kenkui ships.
A copy rather than the cached table itself, so a caller extending it cannot corrupt what every later pipeline in the process reads.
kenkui.read_lexicon
read_lexicon(path: str | PathLike[str]) -> dict[str, str]
Read a pronunciation table from a JSON file, validated as a literal is.
Accepts a plain object of word to replacement, or the shape the shipped
table uses. The result is an ordinary dict: merge it, edit it, or pass it
straight to Pipeline.pronounce.
Stored casts and series
These functions use the managed casting database by default. Their optional path
argument selects a database file, not a voice manifest. list_castings() returns
immutable records with cast_id, attribution_id, method, narrator_voice_id,
unknown_voice_id, and assignments fields. Each assignment is a (character_id,
voice_id, pinned) tuple. The record's implementation class is private; use its fields
and the public removal verbs. Removing attribution cascades to its stored casts and
requires new attribution work later. Removing a series forgets its continuity pins.
kenkui.list_castings
list_castings(
path: Path | None = None,
) -> tuple[CastRecord, ...]
Return every stored cast. Filtering composes over this.
kenkui.remove_casting
remove_casting(
cast_id: str, path: Path | None = None
) -> None
Discard one cast. The pure solver rebuilds it for free.
kenkui.remove_attribution
remove_attribution(
attribution_id: str, path: Path | None = None
) -> None
Discard one attribution and every cast beneath it.
Distinct from remove_casting because the costs differ by orders of magnitude: rebuilding a cast is free, re-deriving attribution is a fresh model pass. One verb doing both would hide that.
kenkui.list_series
list_series(
path: Path | None = None,
) -> tuple[SeriesRecord, ...]
Return every stored series. Filtering composes over this.
kenkui.remove_series
remove_series(
series_id: str, path: Path | None = None
) -> None
Drop a series and its pins. The next volume is cast fresh.
kenkui.SeriesRecord
dataclass
A series' cast, ordered by accumulated speech.
Keyed on the series and the character, never on an attribution: a volume re-read by a different model must not re-cast the series.
series_id
instance-attribute
series_id: str
narrator_voice_id
instance-attribute
narrator_voice_id: str
characters
instance-attribute
characters: tuple[SeriesCharacter, ...]
kenkui.SeriesCharacter
dataclass
One person across a series, and the voice they keep.
canonical_id
instance-attribute
canonical_id: str
display_name
instance-attribute
display_name: str
gender
instance-attribute
gender: str | None
voice_id
instance-attribute
voice_id: str
spoken_characters
instance-attribute
spoken_characters: int
aliases
instance-attribute
aliases: tuple[str, ...]
contributions
class-attribute
instance-attribute
contributions: tuple[tuple[str, int], ...] = ()
Validation and execution results
validate() reports issues as values; execution methods raise the relevant exception
if validation fails. A successful Result.output is the published path. Its
statistics describe semantic work even when synthesis uses cached audio; they do not
measure provider charges.
kenkui.ValidationIssue
dataclass
One inexpensive pipeline validation finding.
code
instance-attribute
code: ErrorCode
message
instance-attribute
message: str
severity
class-attribute
instance-attribute
severity: Literal['error', 'warning'] = 'error'
kenkui.ValidationResult
dataclass
All inexpensive validation findings for a pipeline.
issues
class-attribute
instance-attribute
issues: tuple[ValidationIssue, ...] = ()
errors
property
errors: tuple[ValidationIssue, ...]
Issues severe enough to block rendering.
warnings
property
warnings: tuple[ValidationIssue, ...]
Issues worth surfacing but not severe enough to block rendering.
is_valid
property
is_valid: bool
Whether validation found no errors.
kenkui.Result
dataclass
A published artifact and its execution statistics.
output
instance-attribute
output: Path
stats
instance-attribute
stats: ExecutionStats
kenkui.ExecutionStats
dataclass
Stable technical statistics for one successful execution.
normalized_speech_characters
instance-attribute
normalized_speech_characters: int
synthesized_characters
instance-attribute
synthesized_characters: int
synthesized_segments
instance-attribute
synthesized_segments: int
rendered_chapters
instance-attribute
rendered_chapters: int
duration_ms
instance-attribute
duration_ms: int
Events and cancellation
Callbacks receive immutable ExecutionEvent values. Sequence numbers describe
delivery order. See events for the
pre-publication callback failure boundary and best-effort terminal events.
Cancellation is cooperative; a running model call cannot be forcibly recalled.
kenkui.ExecutionEvent
module-attribute
ExecutionEvent: TypeAlias = (
CastResolved
| Started
| StageStarted
| StageProgress
| StageCompleted
| Warning
| Completed
)
kenkui.Started
dataclass
An execution run started.
sequence
instance-attribute
sequence: int
kenkui.StageStarted
dataclass
A named execution stage started.
sequence
instance-attribute
sequence: int
stage
instance-attribute
stage: str
kenkui.StageProgress
dataclass
A named stage made measurable progress.
sequence
instance-attribute
sequence: int
stage
instance-attribute
stage: str
completed
instance-attribute
completed: int
total
instance-attribute
total: int
chapter_id
class-attribute
instance-attribute
chapter_id: str | None = None
kenkui.StageCompleted
dataclass
A named stage completed.
sequence
instance-attribute
sequence: int
stage
instance-attribute
stage: str
elapsed_ms
class-attribute
instance-attribute
elapsed_ms: int | None = None
kenkui.CastResolved
dataclass
The character-to-voice assignment resolved for this run.
Emitted before any worker exists, so a caller may inspect the cast and cancel without paying for a render. Single-voice runs emit it with no assignments, keeping one event shape for both castings.
sequence
instance-attribute
sequence: int
stage
instance-attribute
stage: str
narrator_voice_id
instance-attribute
narrator_voice_id: str
unknown_voice_id
instance-attribute
unknown_voice_id: str
assignments
class-attribute
instance-attribute
assignments: tuple[tuple[str, str], ...] = ()
kenkui.Warning
dataclass
A recoverable condition was observed.
sequence
instance-attribute
sequence: int
stage
instance-attribute
stage: str
code
instance-attribute
code: str
message
instance-attribute
message: str
chapter_id
class-attribute
instance-attribute
chapter_id: str | None = None
kenkui.Completed
dataclass
An execution run completed successfully.
sequence
instance-attribute
sequence: int
elapsed_ms
class-attribute
instance-attribute
elapsed_ms: int | None = None
kenkui.CancellationToken
Thread-safe cooperative cancellation state shared with one execution.
cancelled
property
cancelled: bool
Whether cancellation has been requested.
cancel
cancel() -> None
Request cancellation idempotently.
raise_if_cancelled
raise_if_cancelled() -> None
Raise the stable public cancellation failure when requested.
Errors
Catch KenkuiError or a narrower subclass and branch on error.code, an ErrorCode
member. Human-readable messages are not a stable matching interface. See
troubleshooting for recovery actions.
kenkui.ErrorCode
Bases: StrEnum
Machine-readable public failure codes.
UNSUPPORTED_FORMAT
class-attribute
instance-attribute
UNSUPPORTED_FORMAT = 'unsupported_format'
SOURCE_NOT_FOUND
class-attribute
instance-attribute
SOURCE_NOT_FOUND = 'source_not_found'
SOURCE_NOT_READABLE
class-attribute
instance-attribute
SOURCE_NOT_READABLE = 'source_not_readable'
SOURCE_CHANGED
class-attribute
instance-attribute
SOURCE_CHANGED = 'source_changed'
DUPLICATE_OPERATION
class-attribute
instance-attribute
DUPLICATE_OPERATION = 'duplicate_operation'
INVALID_OPERATION_ORDER
class-attribute
instance-attribute
INVALID_OPERATION_ORDER = 'invalid_operation_order'
EMPTY_SELECTION
class-attribute
instance-attribute
EMPTY_SELECTION = 'empty_selection'
DUPLICATE_CHAPTER_ID
class-attribute
instance-attribute
DUPLICATE_CHAPTER_ID = 'duplicate_chapter_id'
INVALID_VOICE
class-attribute
instance-attribute
INVALID_VOICE = 'invalid_voice'
VOICE_REQUIRED
class-attribute
instance-attribute
VOICE_REQUIRED = 'voice_required'
VOICE_UNRESOLVED
class-attribute
instance-attribute
VOICE_UNRESOLVED = 'voice_unresolved'
VOICE_DISABLED
class-attribute
instance-attribute
VOICE_DISABLED = 'voice_disabled'
VOICE_INCOMPATIBLE
class-attribute
instance-attribute
VOICE_INCOMPATIBLE = 'voice_incompatible'
VOICE_PROVENANCE_REQUIRED
class-attribute
instance-attribute
VOICE_PROVENANCE_REQUIRED = 'voice_provenance_required'
VOICE_NOT_PROVISIONED
class-attribute
instance-attribute
VOICE_NOT_PROVISIONED = 'voice_not_provisioned'
VOICE_UNKNOWN
class-attribute
instance-attribute
VOICE_UNKNOWN = 'voice_unknown'
ENGINE_NOT_CLONING_CAPABLE
class-attribute
instance-attribute
ENGINE_NOT_CLONING_CAPABLE = 'engine_not_cloning_capable'
VOICE_VARIETY_INVALID
class-attribute
instance-attribute
VOICE_VARIETY_INVALID = 'voice_variety_invalid'
CASTING_METHOD_UNKNOWN
class-attribute
instance-attribute
CASTING_METHOD_UNKNOWN = 'casting_method_unknown'
CAST_POOL_EMPTY
class-attribute
instance-attribute
CAST_POOL_EMPTY = 'cast_pool_empty'
CAST_LANGUAGE_MIXED
class-attribute
instance-attribute
CAST_LANGUAGE_MIXED = 'cast_language_mixed'
CHARACTER_UNKNOWN
class-attribute
instance-attribute
CHARACTER_UNKNOWN = 'character_unknown'
CAST_UNATTRIBUTED
class-attribute
instance-attribute
CAST_UNATTRIBUTED = 'cast_unattributed'
INVALID_SERIES
class-attribute
instance-attribute
INVALID_SERIES = 'invalid_series'
INVALID_MODEL
class-attribute
instance-attribute
INVALID_MODEL = 'invalid_model'
INVALID_ROSTER
class-attribute
instance-attribute
INVALID_ROSTER = 'invalid_roster'
ROSTER_UNAVAILABLE
class-attribute
instance-attribute
ROSTER_UNAVAILABLE = 'roster_unavailable'
INVALID_RESOLUTION_STAGE
class-attribute
instance-attribute
INVALID_RESOLUTION_STAGE = 'invalid_resolution_stage'
MODEL_CALL_FAILED
class-attribute
instance-attribute
MODEL_CALL_FAILED = 'model_call_failed'
MODEL_RESPONSE_INVALID
class-attribute
instance-attribute
MODEL_RESPONSE_INVALID = 'model_response_invalid'
SPACY_PACKAGE_MISSING
class-attribute
instance-attribute
SPACY_PACKAGE_MISSING = 'spacy_package_missing'
SPACY_PIPELINE_MISSING
class-attribute
instance-attribute
SPACY_PIPELINE_MISSING = 'spacy_pipeline_missing'
ATTRIBUTION_UNAVAILABLE
class-attribute
instance-attribute
ATTRIBUTION_UNAVAILABLE = 'attribution_unavailable'
TTS_REQUIRED
class-attribute
instance-attribute
TTS_REQUIRED = 'tts_required'
EMPTY_SPEECH
class-attribute
instance-attribute
EMPTY_SPEECH = 'empty_speech'
INVALID_SOURCE_HASH
class-attribute
instance-attribute
INVALID_SOURCE_HASH = 'invalid_source_hash'
INVALID_MODEL_REVISION
class-attribute
instance-attribute
INVALID_MODEL_REVISION = 'invalid_model_revision'
INVALID_METADATA
class-attribute
instance-attribute
INVALID_METADATA = 'invalid_metadata'
INVALID_PRONUNCIATION
class-attribute
instance-attribute
INVALID_PRONUNCIATION = 'invalid_pronunciation'
INVALID_PAUSE
class-attribute
instance-attribute
INVALID_PAUSE = 'invalid_pause'
INVALID_WORKERS
class-attribute
instance-attribute
INVALID_WORKERS = 'invalid_workers'
INVALID_OUTPUT
class-attribute
instance-attribute
INVALID_OUTPUT = 'invalid_output'
OUTPUT_EXISTS
class-attribute
instance-attribute
OUTPUT_EXISTS = 'output_exists'
MALFORMED_EPUB
class-attribute
instance-attribute
MALFORMED_EPUB = 'malformed_epub'
UNSAFE_ARCHIVE_PATH
class-attribute
instance-attribute
UNSAFE_ARCHIVE_PATH = 'unsafe_archive_path'
ARCHIVE_LIMIT
class-attribute
instance-attribute
ARCHIVE_LIMIT = 'archive_limit'
CHAPTER_NOT_FOUND
class-attribute
instance-attribute
CHAPTER_NOT_FOUND = 'chapter_not_found'
EMPTY_CHAPTER
class-attribute
instance-attribute
EMPTY_CHAPTER = 'empty_chapter'
REVERSED_CHAPTER_RANGE
class-attribute
instance-attribute
REVERSED_CHAPTER_RANGE = 'reversed_chapter_range'
RENDERER_UNAVAILABLE
class-attribute
instance-attribute
RENDERER_UNAVAILABLE = 'renderer_unavailable'
POCKET_PACKAGE_MISSING
class-attribute
instance-attribute
POCKET_PACKAGE_MISSING = 'pocket_package_missing'
POCKET_VERSION_UNSUPPORTED
class-attribute
instance-attribute
POCKET_VERSION_UNSUPPORTED = 'pocket_version_unsupported'
POCKET_MODEL_INVALID
class-attribute
instance-attribute
POCKET_MODEL_INVALID = 'pocket_model_invalid'
POCKET_VOICE_INVALID
class-attribute
instance-attribute
POCKET_VOICE_INVALID = 'pocket_voice_invalid'
POCKET_MODEL_LOAD_FAILED
class-attribute
instance-attribute
POCKET_MODEL_LOAD_FAILED = 'pocket_model_load_failed'
POCKET_VOICE_LOAD_FAILED
class-attribute
instance-attribute
POCKET_VOICE_LOAD_FAILED = 'pocket_voice_load_failed'
POCKET_INFERENCE_FAILED
class-attribute
instance-attribute
POCKET_INFERENCE_FAILED = 'pocket_inference_failed'
FFMPEG_NOT_FOUND
class-attribute
instance-attribute
FFMPEG_NOT_FOUND = 'ffmpeg_not_found'
FFPROBE_NOT_FOUND
class-attribute
instance-attribute
FFPROBE_NOT_FOUND = 'ffprobe_not_found'
FFMPEG_UNSUPPORTED
class-attribute
instance-attribute
FFMPEG_UNSUPPORTED = 'ffmpeg_unsupported'
FFPROBE_UNSUPPORTED
class-attribute
instance-attribute
FFPROBE_UNSUPPORTED = 'ffprobe_unsupported'
SYNTHESIS_FAILED
class-attribute
instance-attribute
SYNTHESIS_FAILED = 'synthesis_failed'
INVALID_AUDIO
class-attribute
instance-attribute
INVALID_AUDIO = 'invalid_audio'
ASSEMBLY_FAILED
class-attribute
instance-attribute
ASSEMBLY_FAILED = 'assembly_failed'
ENCODING_FAILED
class-attribute
instance-attribute
ENCODING_FAILED = 'encoding_failed'
COVER_FAILED
class-attribute
instance-attribute
COVER_FAILED = 'cover_failed'
COVER_INVALID
class-attribute
instance-attribute
COVER_INVALID = 'cover_invalid'
PROBE_FAILED
class-attribute
instance-attribute
PROBE_FAILED = 'probe_failed'
DECODE_FAILED
class-attribute
instance-attribute
DECODE_FAILED = 'decode_failed'
INVALID_ARTIFACT
class-attribute
instance-attribute
INVALID_ARTIFACT = 'invalid_artifact'
PUBLICATION_FAILED
class-attribute
instance-attribute
PUBLICATION_FAILED = 'publication_failed'
CALLBACK_FAILED
class-attribute
instance-attribute
CALLBACK_FAILED = 'callback_failed'
CANCELLED
class-attribute
instance-attribute
CANCELLED = 'cancelled'
SERIES_VOICE_MISSING
class-attribute
instance-attribute
SERIES_VOICE_MISSING = 'series_voice_missing'
SERIES_NARRATOR_CHANGED
class-attribute
instance-attribute
SERIES_NARRATOR_CHANGED = 'series_narrator_changed'
INVALID_PATH
class-attribute
instance-attribute
INVALID_PATH = 'invalid_path'
INVALID_PATTERN
class-attribute
instance-attribute
INVALID_PATTERN = 'invalid_pattern'
INVALID_SIDECAR
class-attribute
instance-attribute
INVALID_SIDECAR = 'invalid_sidecar'
RULE_OVERLAP
class-attribute
instance-attribute
RULE_OVERLAP = 'rule_overlap'
ANCHOR_DIGEST_MISMATCH
class-attribute
instance-attribute
ANCHOR_DIGEST_MISMATCH = 'anchor_digest_mismatch'
PATTERN_MATCH_COUNT_DRIFT
class-attribute
instance-attribute
PATTERN_MATCH_COUNT_DRIFT = 'pattern_match_count_drift'
kenkui.KenkuiError
Bases: Exception
Base class for sanitized public failures.
code
instance-attribute
code: ErrorCode
message
instance-attribute
message: str | None