fix(audio): use captions as the default YuE2 style (#12703)

* fix(audio): use captions as the default YuE2 style

Studio sends a caption, but YuE2 requires a style request option.
Default audio-cpp style from caption while preserving explicit options
and the caller's parameter map. Document the Studio fields.

Assisted-by: Codex:gpt-6
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* fix(audio-cpp): map captions to style in backend

Move the YuE2 caption fallback into the C++ request builder as requested.
Preserve explicit style options, including empty values, and move the
regression cases from the Go layer into the backend suite.

Assisted-by: Codex:GPT-6

---------

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: localai-org-maint-bot <306269227+localai-org-maint-bot@users.noreply.github.com>
This commit is contained in:
localai-org-maint-botandlocalai-org-maint-bot authored and GitHub committed 2026-10-16 08:46:16 +02:00
1 parent fdfb171c3e
commit 62fa19b833
3 files changed
+47 -2

No files matched your search

+5 -2
View File
@@ -232,9 +232,12 @@ build_sound_generation_request(const backend::SoundGenerationRequest &request,
task.options["think"] = bool_option(request.think());
}
if (request.has_caption()) {
// Read only by irodori_tts, which advertises Tts/VoiceCloning/VoiceDesign
// and not AudioGeneration, so it is unreachable from this RPC: DEAD here.
task.options["caption"] = request.caption();
// YuE2 calls the musical caption "style". Preserve explicit options,
// including an empty style, while accepting Studio's caption field.
if (!request.caption().empty()) {
task.options.emplace("style", request.caption());
}
}
if (request.has_lyrics()) {
// Read by ace_step and heartmula.
@@ -426,6 +426,42 @@ static void test_sound_generation_minimal() {
check(!task.voice.has_value(), "sound: no voice condition");
}
static void test_sound_generation_caption_style() {
backend::SoundGenerationRequest request;
request.set_caption("slow acoustic folk");
request.set_lyrics("first line\nsecond line");
auto task = build_sound_generation_request(request, std::nullopt);
check(option_or(task.options, "style", "") == "slow acoustic folk",
"sound: caption supplies the default YuE2 style");
check(option_or(task.options, "caption", "") == "slow acoustic folk",
"sound: caption remains available under its own name");
check(option_or(task.options, "lyrics", "") == "first line\nsecond line",
"sound: style fallback preserves lyrics");
check(request.params().empty(), "sound: style fallback does not mutate params");
(*request.mutable_params())["style"] = "fast jazz";
task = build_sound_generation_request(request, std::nullopt);
check(option_or(task.options, "style", "") == "fast jazz",
"sound: explicit style overrides caption");
(*request.mutable_params())["style"] = "";
task = build_sound_generation_request(request, std::nullopt);
check(has_key(task.options, "style") && task.options.at("style").empty(),
"sound: explicit empty style overrides caption");
request.mutable_params()->clear();
request.set_caption("");
task = build_sound_generation_request(request, std::nullopt);
check(!has_key(task.options, "style"), "sound: empty caption supplies no style");
request.clear_caption();
(*request.mutable_params())["style"] = "instrumental jazz";
task = build_sound_generation_request(request, std::nullopt);
check(option_or(task.options, "style", "") == "instrumental jazz",
"sound: explicit style works without a caption");
}
static void test_sound_generation_full() {
backend::SoundGenerationRequest request;
request.set_text("a slow blues in E");
@@ -616,6 +652,7 @@ int main() {
test_tts_language_and_params();
test_tts_reference_transcript();
test_sound_generation_minimal();
test_sound_generation_caption_style();
test_sound_generation_full();
test_transform_text_absent();
test_transform_text_canonical_key();