Splicr interface

Splicr

A long-document audio workflow built for my own research: configurable chunking, ordered speech generation, saved progress, and continuous audio without restarting completed work after a provider failure. The published pipeline is separate from an expanded local toolkit still being integrated.

Role
Product architecture and full-stack implementation
Context
I wanted an affordable way to turn long research documents into continuous audio, with control over pacing, pronunciation, and recovery. The services I tried did not fit the volume or workflow I needed.
PythonFastAPISQLiteBackground processingDockerCI
problem

Continuous audio from research documents, not a pile of fragments

I built Splicr because I wanted to listen to my own research, including documents running to dozens or hundreds of pages. Existing services did not give me the combination of affordability, output control, and long-document handling I needed. A document-length task also does not fit one reliable API call: request limits, rate limits, interruptions, and separate audio responses turn it into a sequence of operations whose order and progress have to survive partial failure.

ownership

Own the pipeline, isolate the speech provider

My work spans the Python/FastAPI service, chunk planning, provider adapters, SQLite state, file storage, audio assembly, and browser workflow. The core design keeps transport handlers thin and puts synthesis orchestration behind explicit provider contracts. That lets the interface, CLI, and different speech services use the same processing model instead of becoming separate implementations.

constraints

Provider limits and local storage are both real boundaries

The first Gemini-based workflow hit a per-request input limit, so I separated a document into configurable chunks, sequenced generation, retained completed audio, and assembled it in order. After several runs, aggregate quota became another constraint; chunking alone did not solve dependence on one provider. That led toward configurable provider boundaries rather than another provider-specific rewrite. The current pipeline must also account for text transforms changing request size, local storage and assembly capacity, and ordered output. These constraints do not establish unlimited tested document size or compatibility with every text-to-audio API.

implementation

From source document to a completed audio artifact

  1. ImportNormalize source text and document structure
  2. Plan chunksNatural boundaries within provider limits
  3. Persist the jobSQLite job and chunk state
  4. Synthesize and checkpointSequential calls and durable PCM fragments
  5. AssembleValidate order and publish one completed WAV
Import normalizes the source, chunk planning respects natural boundaries and provider limits, and the job is persisted before synthesis. Each successful audio fragment is checkpointed and recorded. Final assembly uses validated fragments in source order; interruption resumes from valid committed progress rather than declaring partial audio complete.
decisions

Preserve reading boundaries without exceeding the request budget

The chunker prefers paragraph boundaries, then falls back through sentences, clauses, words, and Unicode-safe splitting when a section is too large. It checks more than a character count: UTF-8 bytes, word limits, and provider-specific estimators can all matter. Planning can account for transformed text and steering overhead before submission, and the studio exposes a chunk preview without starting a synthesis job.

implementation

Recover the checkpoint, not just the status flag

SQLite tracks jobs and chunks, while raw PCM files retain completed audio. The service writes a checkpoint atomically before marking its chunk complete. On restart, it can admit a valid checkpoint that was written before a database status update and reuse that audio instead of requesting it again. Missing or corrupt checkpoint bytes are not accepted merely because a record says completed. Recovery begins at valid durable progress; it is not an exactly-once guarantee for every possible failure around a remote provider call.

decisions

Retry the right failure, not the entire document

Provider calls are sequential and use pacing plus bounded retry/backoff behavior. A failed later chunk does not invalidate earlier valid audio. The tests also distinguish a transient provider failure from failure to store an already returned response: a local checkpoint error pauses the job instead of automatically repeating the billable call. Retry budgets and server-requested delays remain part of the job's processing policy rather than a browser-only timer.

implementation

A resumed job should not silently change its endpoint contract

API resources describe endpoint shape, request templates, limits, response extraction, and retry policy. Editing a resource appends an immutable revision, and jobs retain the revision they were created against. That prevents a later configuration edit from silently changing a resumed job's request format. Credentials remain a separate server-side concern rather than being copied into exported resource definitions or job configuration; credential rotation can therefore remain effective without rewriting historical endpoint contracts.

implementation

Normalize the audio before joining it

Provider adapters normalize supported responses to mono, signed 16-bit PCM at 24 kHz. Assembly consumes validated raw frames in source order and writes one WAV container rather than concatenating complete WAV files and their headers. Frame and size checks prevent invalid fragments or oversized output from being presented as a successful master. A partial export uses a separate snapshot path and leaves the job's completed result distinct.

implementation

Make long-running work inspectable from the studio

The same-origin browser studio exposes source import, provider settings, chunk preview, progress, retry, playback, and download. Paused, cancelled, failed, and completed work are different states, not one generic spinner. The job and its checkpoints outlive the request that started it, so the interface can return to durable progress instead of owning the only copy of the workflow. The hosted studio is a private workspace and requires sign-in. Separately, my expanded local toolkit links highlighted source text to the chunk being processed and adds listener-oriented preprocessing: turning tables into prose and headings into spoken transitions, plus targeted word and phrase pronunciation corrections. Those additions respond to defects I heard while making personal audio. The local expansion and its ongoing Studio/Narrator integration are not a claim that every editing feature is available in the hosted release.

implementation

Use failures as executable examples

  • Exercise paragraph and sentence packing, multibyte text, oversized tokens, and provider-specific transformed-text limits.
  • Fail a later chunk and verify that retry reuses the earlier completed checkpoint.
  • Restart between an atomic file write and the database completion update, then recover without another provider call for that checkpoint.
  • Inject a local checkpoint failure and confirm that it does not trigger automatic repetition of the successful provider call.
  • Verify PCM ordering, WAV metadata, distinct partial-output paths, immutable resource revisions, and secret-free resource serialization using deterministic fake providers.
impact

Hundreds of pages used personally, with recoverable intermediate work

I have processed hundreds of pages for testing and podcast-like audio from my own research. The practical benefit is being able to inspect and continue meaningful work instead of starting an entire document again. I have not measured hours or dollars saved, and this is personal use rather than a professional client deployment. Focused tests support the pipeline's recovery and integration behavior; they do not establish comparative voice quality, universal provider compatibility, or production-scale reliability.

retrospective

Keep the recovery contract as the workspace grows

Each new constraint changed the design: request limits led to chunk orchestration, aggregate quota led to provider independence, and mispronounced acronyms led to targeted correction. The durable boundary is the document-to-audio workflow, not a particular engine. The earlier published pipeline and the larger local toolkit are distinct stages; Studio/Narrator integration remains development work until its release and validation are complete.