# Copyright 2026 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # LocalAI audio backend (TTS/STT/audio-generation model families) built from # LocalAI's gRPC wrapper and the pinned audio.cpp engine it embeds. Installs # entirely under /usr/libexec/local-ai/backends/. EAPI=8 inherit cmake local-ai-backend local-ai-rocm # The audio.cpp commit LocalAI v4.11.0 builds against. Source of truth: # backend/cpp/audio-cpp/Makefile (AUDIO_CPP_VERSION) at the release tag. AUDIOCPP_COMMIT="9a02e61326aaaf9d462b584ca5e0daba22c0abfc" DESCRIPTION="LocalAI audio backend (audio.cpp gRPC server)" HOMEPAGE="https://localai.io https://github.com/mudler/LocalAI" SRC_URI=" ${LOCAL_AI_SRC_URI} https://github.com/0xShug0/audio.cpp/archive/${AUDIOCPP_COMMIT}.tar.gz -> audio.cpp-${AUDIOCPP_COMMIT}.tar.gz " # The backend directory is itself the CMake project root; it expects the # engine checkout at ./audio.cpp (moved into place in src_unpack). S="${WORKDIR}/LocalAI-${PV}/backend/cpp/audio-cpp" LICENSE="MIT" SLOT="0" KEYWORDS="~amd64" IUSE="+cpu cuda native rocm test vulkan" # Same CPU kernel gates as local-ai-ggml.eclass (audio-cpp predates it); # see that eclass for the option-gated-kernels rationale. _ggml_cpu_flags=( avx avx2 avx512f bmi2 f16c fma3 ) IUSE+=" ${_ggml_cpu_flags[*]/#/cpu_flags_x86_}" unset _ggml_cpu_flags # Each enabled flag builds its own co-installable backend variant # (upstream's model: cpu-/cuda-/rocm-/vulkan-audio-cpp, all aliased to # audio-cpp — the server resolves the alias by host capability, and a # model YAML can pin a concrete variant, e.g. cpu-audio-cpp to spare # VRAM). Tests are engine-logic tests; one build of them suffices. REQUIRED_USE=" || ( cpu cuda rocm vulkan ) rocm? ( ${ROCM_REQUIRED_USE} ) test? ( cpu ) " RESTRICT="!test? ( test )" RDEPEND=" dev-cpp/abseil-cpp:= dev-libs/protobuf:= net-libs/grpc:= vulkan? ( media-libs/vulkan-loader ) cuda? ( dev-util/nvidia-cuda-toolkit:= ) rocm? ( >=dev-util/hip-${ROCM_VERSION}:= >=sci-libs/hipBLAS-${ROCM_VERSION}:= >=sci-libs/rocBLAS-${ROCM_VERSION}:= ) " DEPEND="${RDEPEND} vulkan? ( dev-util/vulkan-headers ) " BDEPEND=" dev-libs/protobuf net-libs/grpc vulkan? ( media-libs/shaderc ) " src_unpack() { default mv "${WORKDIR}/audio.cpp-${AUDIOCPP_COMMIT}" "${S}/audio.cpp" || die } src_prepare() { cmake_src_prepare # System abseil requires C++20 tree-wide here: sentencepiece links it, # and the cxx_std_20 INTERFACE feature propagates through it to the # whole tree. The engine's sources are C++17-clean except for u8 # string literals (char8_t* since C++20); stripping the prefix yields # byte-identical plain UTF-8 literals in either standard. local files=() readarray -t files < <(grep -rl 'CMAKE_CXX_STANDARD 17' .) [[ ${#files[@]} -gt 0 ]] || die "no CMAKE_CXX_STANDARD 17 anchors found — engine build layout changed" local-ai-backend_bump_cxx20 "${files[@]}" einfo "Stripping u8 string literal prefixes from engine sources" find "${S}/audio.cpp/src" \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/\bu8"/"/g' {} + || die # The method form of the same char8_t break: path::u8string() returns # std::u8string since C++20 (std::string in C++17, which upstream # builds as); the bytes are identical UTF-8 either way on Linux. einfo "Replacing path::u8string() calls in engine sources" find "${S}/audio.cpp/src" \( -name '*.cpp' -o -name '*.h' \) -exec sed -i 's/\.u8string()/.string()/g' {} + || die } # Enabled variants, in the order they build. audio_cpp_variants() { use cpu && echo cpu use cuda && echo cuda use rocm && echo rocm use vulkan && echo vulkan return 0 } src_configure() { local v for v in $(audio_cpp_variants); do local BUILD_DIR="${WORKDIR}/${P}_build-${v}" local mycmakeargs=( # No C++20 modules anywhere in the tree: the scan otherwise # runs clang-scan-deps (from a DIFFERENT llvm than rocm's # clang) against every hipcc command as plain C++. -DCMAKE_CXX_SCAN_FOR_MODULES=OFF # Compiles the model_specs catalog into the binary so the installed # backend needs no model_specs directory (upstream deployment mode). -DAUDIOCPP_DEPLOYMENT_BUILD=ON # sentencepiece's absl shim headers reuse real abseil's include # guards and shadow it via -I third_party, which cannot coexist # with the system protobuf headers (they include real abseil). # The "package" provider replaces the shim directory with a # symlink to the system abseil headers: one absl for every # translation unit. (SPM_PROTOBUF_PROVIDER stays "package" — # upstream FORCEs it, see their CMakeLists for the two-runtimes # ABI war story.) -DSPM_ABSL_PROVIDER=package # One host-targeted build (per CFLAGS) instead of upstream's # dlopen-able per-microarch ggml fan-out for fat container images. -DENGINE_ENABLE_CPU_ALL_VARIANTS=OFF -DGGML_NATIVE=$(usex native) # Tree-style CPU kernel gates, matching local-ai-ggml.eclass. -DGGML_AVX=$(usex cpu_flags_x86_avx) -DGGML_AVX2=$(usex cpu_flags_x86_avx2) -DGGML_AVX512=$(usex cpu_flags_x86_avx512f) -DGGML_BMI2=$(usex cpu_flags_x86_bmi2) -DGGML_F16C=$(usex cpu_flags_x86_f16c) -DGGML_FMA=$(usex cpu_flags_x86_fma3) -DENGINE_ENABLE_CUDA=$([[ ${v} == cuda ]] && echo ON || echo OFF) -DENGINE_ENABLE_HIP=$([[ ${v} == rocm ]] && echo ON || echo OFF) -DENGINE_ENABLE_VULKAN=$([[ ${v} == vulkan ]] && echo ON || echo OFF) # Engine-logic tests: built once, in the cpu variant. -DAUDIO_CPP_GRPC_BUILD_TESTS=$([[ ${v} == cpu ]] && usex test || echo OFF) ) if [[ ${v} == rocm ]]; then ( # Upstream drives this build with ROCm clang rather than # hipcc: hipcc treats every .cpp as HIP source and # device-compiles it for its built-in default arch # (gfx906) when no offload arch is passed — the kernels' # archs already travel via CMAKE_HIP_ARCHITECTURES. The # subshell keeps CC/CXX out of the other variants; # CMake caches the compilers, so compile needs no env. local hipclang hipclang=$(hipconfig --hipclangpath) && [[ -n ${hipclang} ]] \ || die "hipconfig --hipclangpath failed" local -x CC="${hipclang}/clang" CXX="${hipclang}/clang++" local amdgpu_flags amdgpu_flags=$(get_amdgpu_flags) amdgpu_flags=${amdgpu_flags%;} mycmakeargs+=( -DAMDGPU_TARGETS="${amdgpu_flags}" -DGPU_TARGETS="${amdgpu_flags}" -DCMAKE_HIP_ARCHITECTURES="${amdgpu_flags}" ) cmake_src_configure ) || die else cmake_src_configure fi done } src_compile() { local v for v in $(audio_cpp_variants); do local BUILD_DIR="${WORKDIR}/${P}_build-${v}" cmake_src_compile done } src_test() { local BUILD_DIR="${WORKDIR}/${P}_build-cpu" cmake_src_test } src_install() { local v for v in $(audio_cpp_variants); do local BUILD_DIR="${WORKDIR}/${P}_build-${v}" # Models without an explicit backend: option run on this # variant's engine backend (the wrapper's env fallback patch). local-ai-backend_gen_run_sh -e "AUDIOCPP_DEFAULT_BACKEND=${v}" \ grpc-server LD_LIBRARY_PATH=lib local-ai-backend_install "${v}-audio-cpp" --alias audio-cpp \ "${BUILD_DIR}"/grpc-server done }