Recipes are ready-to-run compositions of existing audio.cpp models. Unlike
--pipeline, a recipe does not require a JSON workflow file. The recipe defines
the stages and their data flow; the caller only selects one model for each role
and supplies the normal task inputs.
List the available recipes; the server response also includes their model roles:
audiocpp_cli --list-recipes
curl http://127.0.0.1:8080/v1/recipesany-tts generates speech with an offline TTS model and converts each generated
chunk to the supplied reference voice with Tone Color VC. The two sessions are
created once and reused for every text chunk.
audiocpp_cli --recipe any-tts --backend cuda --log \
--recipe-model tts=/path/to/kokoro.gguf \
--recipe-family tts=kokoro_tts \
--recipe-model converter=/path/to/tone-color-vc.gguf \
--recipe-family converter=tone_color_vc \
--voice-id am_michael \
--voice-ref reference.wav \
--text "The next train leaves in ten minutes." \
--request-option converter.seed=42 \
--out cloned.wavtext_chunk_size and text_chunk_mode control recipe-level text chunking.
Unprefixed request options and tts.* options go to the TTS stage;
converter.* options go to Tone Color VC. Role-prefixed options override shared
options with the same name.
Prefix CLI load and session option keys with their role too, retaining any
model-family prefix after the role prefix.
cross-language-dubbing translates input speech and sends the translated text
directly to a target-language TTS model. Canary 180M Flash is a compact choice
for its supported English, German, Spanish, and French pairs. OWSM and OWSM-CTC
expose the same translation interface for broader language coverage.
audiocpp_cli --recipe cross-language-dubbing --backend cuda --log \
--recipe-model translator=/path/to/canary-180m-flash-f32.gguf \
--recipe-family translator=canary_asr \
--recipe-model tts=/path/to/kokoro.gguf \
--recipe-family tts=kokoro_tts \
--audio german-speech.wav \
--request-option translator.language=de \
--request-option translator.target_language=en \
--voice-id am_michael \
--out english-dub.wav \
--text-out translation.txtPrefix translation options with translator.*. Unprefixed request options and
tts.* options go to the TTS stage. The translation target is required because
omitting it would turn the recipe back into same-language transcription and
re-speaking. Translator and TTS language identifiers are model-specific, so
the recipe does not infer one from the other.
Recipes use the default legacy server runtime, not the experimental parallel runtime. They use model IDs from the normal server configuration, so model loading, lazy loading, locking, and unloading retain their existing behavior. The request maps recipe roles to those IDs:
curl http://127.0.0.1:8080/v1/recipes/run \
-H "Content-Type: application/json" \
-d '{
"recipe": "cross-language-dubbing",
"models": {"translator": "canary", "tts": "kokoro"},
"request": {
"audio": "input.wav",
"voice_id": "am_michael",
"options": {
"translator.language": "de",
"translator.target_language": "en"
}
}
}'Set "stream": true to receive recipe output events and the final result over
SSE. Recipe components must be configured for the offline task and mode shown by
GET /v1/recipes.
Recipe implementations are isolated source plugins under
app/recipe/plugins/. A plugin implements IRecipe and declares one
RecipePluginRegistration factory in its own translation unit. The build
discovers plugin sources in that directory, so adding one does not require
editing the recipe registry, CLI, server, or another recipe.
The IRecipeModelExecutor boundary gives every plugin the same model execution
surface. roles() declares the required task and mode for each component, and
run() connects their in-memory TaskRequest and TaskResult values. Use
options_for_recipe_role() to isolate role-prefixed options. Source plugins are
compiled into the CLI and server; loading arbitrary binary plugins at runtime
is intentionally outside this interface.