From f33034a92529c3b609bcf84f8fd6c929a82dbb0d Mon Sep 17 00:00:00 2001 From: localai-org-maint-bot Date: Mon, 12 Oct 2026 09:35:25 +0200 Subject: [PATCH] chore: :arrow_up: Update 0xShug0/audio.cpp to `96269554d00621fb0fca6b52b58919749eba1c8d` (#12598) * :arrow_up: Update 0xShug0/audio.cpp Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(audio-cpp): map new detection tasks Upstream adds wake-word and audio-classification task kinds. Preserve their capability names without routing them to unrelated audio RPCs. Assisted-by: Codex:gpt-6 --------- Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Co-authored-by: localai-org-maint-bot <306269227+localai-org-maint-bot@users.noreply.github.com> --- backend/cpp/audio-cpp/Makefile | 2 +- backend/cpp/audio-cpp/capability_routing.cpp | 2 ++ backend/cpp/audio-cpp/capability_routing.h | 4 +++- .../cpp/audio-cpp/capability_routing_test.cpp | 22 ++++++++++++++++++- backend/cpp/audio-cpp/loaded_model.cpp | 9 ++++++++ docs/content/features/audio-cpp.md | 3 +++ 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/backend/cpp/audio-cpp/Makefile b/backend/cpp/audio-cpp/Makefile index e40418b4b..90c35de26 100644 --- a/backend/cpp/audio-cpp/Makefile +++ b/backend/cpp/audio-cpp/Makefile @@ -9,7 +9,7 @@ # recipe is a make target (not a prepare.sh) so 'make purge && make' is a clean # rebuild and so the bump bot can see the pin. -AUDIO_CPP_VERSION?=e0f625bf5d6c801872a729ada10b3a339084eabe +AUDIO_CPP_VERSION?=96269554d00621fb0fca6b52b58919749eba1c8d AUDIO_CPP_REPO?=https://github.com/0xShug0/audio.cpp CURRENT_MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) diff --git a/backend/cpp/audio-cpp/capability_routing.cpp b/backend/cpp/audio-cpp/capability_routing.cpp index df597ef37..de974b1d4 100644 --- a/backend/cpp/audio-cpp/capability_routing.cpp +++ b/backend/cpp/audio-cpp/capability_routing.cpp @@ -31,6 +31,8 @@ const NamedTask kTaskNames[] = { {Task::Svc, "svc"}, {Task::Midi, "midi"}, {Task::TurnDetection, "turn"}, + {Task::WakeWord, "wake"}, + {Task::AudioClassification, "cls"}, }; // Accepted on input but never emitted. "spkrec" was this backend's own earlier diff --git a/backend/cpp/audio-cpp/capability_routing.h b/backend/cpp/audio-cpp/capability_routing.h index 1624b9d2e..fd33daa33 100644 --- a/backend/cpp/audio-cpp/capability_routing.h +++ b/backend/cpp/audio-cpp/capability_routing.h @@ -27,6 +27,8 @@ enum class Task { Svc, Midi, TurnDetection, + WakeWord, + AudioClassification, }; // Mirrors engine::runtime::RunMode. @@ -79,7 +81,7 @@ struct Route { Route resolve_route(Rpc rpc, const RequestShape &shape, const Capabilities &caps); // Canonical audio.cpp short names: gen, tts, clon, vc, svc, s2s, asr, align, -// vad, diar, sep, vdes, spk, midi, turn. parse_task_name additionally accepts "spkrec" as +// vad, diar, sep, vdes, spk, midi, turn, wake, cls. parse_task_name additionally accepts "spkrec" as // a legacy alias; task_name only ever emits "spk". const char *task_name(Task task); const char *mode_name(Mode mode); diff --git a/backend/cpp/audio-cpp/capability_routing_test.cpp b/backend/cpp/audio-cpp/capability_routing_test.cpp index d149b84f3..6e6270aaa 100644 --- a/backend/cpp/audio-cpp/capability_routing_test.cpp +++ b/backend/cpp/audio-cpp/capability_routing_test.cpp @@ -362,7 +362,7 @@ static void test_names_round_trip() { Task::VoiceCloning, Task::VoiceConversion, Task::SpeechToSpeech, Task::Alignment, Task::VoiceDesign, Task::SpeakerRecognition, Task::Svc, Task::Midi, - Task::TurnDetection}; + Task::TurnDetection, Task::WakeWord, Task::AudioClassification}; for (const Task t : all) { Task parsed = Task::Vad; const bool ok = parse_task_name(task_name(t), parsed); @@ -588,7 +588,27 @@ static void test_turn_detection_is_not_vad() { "turn detection has an accurate capability diagnostic"); } +static void test_detection_tasks_are_not_existing_rpcs() { + for (const auto *name : {"wake", "cls"}) { + Task task = Task::Vad; + check(parse_task_name(name, task), "upstream detection task parses"); + check(std::string(task_name(task)) == name, "detection task name round-trips"); + Capabilities caps{"detector", {{task, {Mode::Offline}}}}; + for (const auto rpc : {Rpc::Tts, Rpc::TtsStream, Rpc::AudioTranscription, + Rpc::AudioTranscriptionStream, Rpc::AudioTranscriptionLive, + Rpc::Vad, Rpc::Diarize, Rpc::SoundGeneration, Rpc::AudioTransform}) { + check(!resolve_route(rpc, RequestShape{}, caps).ok, + "detection tasks cannot serve an existing RPC"); + RequestShape pinned; + pinned.pinned_task = name; + check(!resolve_route(rpc, pinned, caps).ok, + "pinning detection tasks cannot bypass RPC admission"); + } + } +} + int main() { + test_detection_tasks_are_not_existing_rpcs(); test_turn_detection_is_not_vad(); test_plain_tts(); test_tts_with_voice_reference_prefers_cloning(); diff --git a/backend/cpp/audio-cpp/loaded_model.cpp b/backend/cpp/audio-cpp/loaded_model.cpp index 15e2e758f..aecc837a0 100644 --- a/backend/cpp/audio-cpp/loaded_model.cpp +++ b/backend/cpp/audio-cpp/loaded_model.cpp @@ -90,6 +90,11 @@ static_assert(kMirror(Task::Svc) == 12, "Task drifted from VoiceTaskKind"); static_assert(kMirror(Task::Midi) == 13, "Task drifted from VoiceTaskKind"); static_assert(kMirror(Task::TurnDetection) == 14, "Task drifted from VoiceTaskKind"); +static_assert(kEngine(engine::runtime::VoiceTaskKind::WakeWord) == 15); +static_assert(kEngine(engine::runtime::VoiceTaskKind::AudioClassification) == 16); +static_assert(kMirror(Task::WakeWord) == 15); +static_assert(kMirror(Task::AudioClassification) == 16); + static_assert(static_cast(engine::runtime::RunMode::Offline) == 0, "RunMode drifted"); static_assert(static_cast(engine::runtime::RunMode::Streaming) == 1, "engine::runtime::RunMode gained, lost or reordered a member. " @@ -248,6 +253,8 @@ engine::runtime::VoiceTaskKind to_engine_task(Task task) { case Task::Svc: return K::Svc; case Task::Midi: return K::Midi; case Task::TurnDetection: return K::TurnDetection; + case Task::WakeWord: return K::WakeWord; + case Task::AudioClassification: return K::AudioClassification; } // Unreachable for any valid enumerator. No `default:` label, so -Wswitch // still reports a member this switch stops covering. @@ -272,6 +279,8 @@ Task from_engine_task(engine::runtime::VoiceTaskKind kind) { case K::Svc: return Task::Svc; case K::Midi: return Task::Midi; case K::TurnDetection: return Task::TurnDetection; + case K::WakeWord: return Task::WakeWord; + case K::AudioClassification: return Task::AudioClassification; } return Task::Vad; } diff --git a/docs/content/features/audio-cpp.md b/docs/content/features/audio-cpp.md index 30fe25d93..599a023eb 100644 --- a/docs/content/features/audio-cpp.md +++ b/docs/content/features/audio-cpp.md @@ -224,6 +224,9 @@ unaffected. The upstream `turn` task performs turn detection. LocalAI has no RPC for this task, so requests to a model that only advertises `turn` are refused. It is not routed through voice activity detection (`vad`). +The upstream `wake` (wake-word detection) and `cls` (audio classification) tasks +are reported in capability diagnostics. They cannot serve LocalAI audio RPCs, +including VAD, even when selected with the `task` option. Two routes are unreachable by auto-routing and need `task:` in the model config, because nothing in a request distinguishes them from a task the same family also advertises: