mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-25 09:09:07 -04:00
* fix(parakeet-cpp): darwin/metal support (libparakeet.dylib + DYLD path) The parakeet-cpp backend had no macOS support and panicked at startup on Apple/Metal nodes when purego.Dlopen could not find "libparakeet.so". Fix it across the same four layers the sibling voxtral backend already handles correctly: - main.go: default the dlopen target to libparakeet.dylib on darwin (runtime.GOOS), libparakeet.so elsewhere; PARAKEET_LIBRARY still wins. - Makefile: also stage the built libparakeet.dylib next to the Go sources. - package.sh: accept either the Linux .so[.X.Y] or the macOS .dylib when bundling instead of hard-failing when no .so is present (the macOS case); note that on Darwin only system frameworks are linked. - run.sh: on Darwin set DYLD_LIBRARY_PATH and PARAKEET_LIBRARY to the packaged .dylib; keep LD_LIBRARY_PATH + .so on Linux. Mirrors backend/go/voxtral. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(backends): darwin/metal support across purego Go backends The parakeet-cpp fix in the previous commit was an instance of a bug shared by nearly every purego/dlopen Go backend: the dlopen target was hardcoded to a .so name and run.sh exported only LD_LIBRARY_PATH, so the backend panicked at startup on macOS/Apple-Metal nodes (dyld needs the .dylib name and DYLD_LIBRARY_PATH). voxtral was the only backend handling this correctly. Apply the same four-layer fix (mirroring backend/go/voxtral) to the remaining affected backends: whisper, sherpa-onnx, ced, stablediffusion-ggml, vibevoice-cpp, qwen3-tts-cpp, omnivoice-cpp, crispasr, acestep-cpp, locate-anything-cpp, depth-anything-cpp, rfdetr-cpp, sam3-cpp, localvqe Per backend: - main.go (sherpa-onnx: backend.go, two libraries): default the dlopen target to the .dylib on darwin (runtime.GOOS), .so elsewhere; the existing <BACKEND>_LIBRARY env override still wins. - run.sh: on Darwin set DYLD_LIBRARY_PATH and point <BACKEND>_LIBRARY at the packaged .dylib; keep LD_LIBRARY_PATH + the Linux CPU-variant (avx/avx2/avx512) selection unchanged in the else branch. - package.sh: also bundle the .dylib and stop hard-failing when no .so is present (the macOS case). - Makefile: also stage the built .dylib. Notes: - stablediffusion-ggml and acestep-cpp build their lib as a CMake MODULE, which emits .so (not .dylib) on macOS; run.sh prefers .dylib and falls back to .so so both layouts work. - sherpa-onnx was already partly darwin-aware (Makefile/package.sh); only run.sh and the two dlopen defaults needed fixing. Linux behavior is unchanged. Verified gofmt-clean and `CGO_ENABLED=0 go build` for every backend. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
65 lines
1.9 KiB
Go
65 lines
1.9 KiB
Go
package main
|
|
|
|
// ced sound-classification backend. Started internally by LocalAI: one gRPC
|
|
// server per loaded model. Loads libced.so via purego and registers the flat
|
|
// C-API declared in ced_capi.h. The library name can be overridden with
|
|
// CED_LIBRARY (mirrors PARAKEET_LIBRARY / WHISPER_LIBRARY); the default looks
|
|
// for the .so next to this binary.
|
|
//
|
|
// SKETCH: requires `make protogen-go` after the backend.proto SoundDetection
|
|
// addition, and a built libced.so (see Makefile). See DESIGN.md.
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
|
|
"github.com/ebitengine/purego"
|
|
grpc "github.com/mudler/LocalAI/pkg/grpc"
|
|
)
|
|
|
|
var addr = flag.String("addr", "localhost:50051", "the address to connect to")
|
|
|
|
type libFunc struct {
|
|
ptr any
|
|
name string
|
|
}
|
|
|
|
func main() {
|
|
libName := os.Getenv("CED_LIBRARY")
|
|
if libName == "" {
|
|
if runtime.GOOS == "darwin" {
|
|
libName = "libced.dylib"
|
|
} else {
|
|
libName = "libced.so"
|
|
}
|
|
}
|
|
lib, err := purego.Dlopen(libName, purego.RTLD_NOW|purego.RTLD_GLOBAL)
|
|
if err != nil {
|
|
panic(fmt.Errorf("ced: dlopen %q: %w", libName, err))
|
|
}
|
|
|
|
// Bound 1:1 to ced_capi.h. char*-returning functions are declared uintptr
|
|
// so we can free the same pointer with ced_capi_free_string after copying
|
|
// (purego's string return would copy and leak the original).
|
|
for _, lf := range []libFunc{
|
|
{&CppAbiVersion, "ced_capi_abi_version"},
|
|
{&CppLoad, "ced_capi_load"},
|
|
{&CppFree, "ced_capi_free"},
|
|
{&CppLastError, "ced_capi_last_error"},
|
|
{&CppNumClasses, "ced_capi_num_classes"},
|
|
{&CppSampleRate, "ced_capi_sample_rate"},
|
|
{&CppClassifyPathJSON, "ced_capi_classify_path_json"},
|
|
{&CppClassifyPcmJSON, "ced_capi_classify_pcm_json"},
|
|
{&CppFreeString, "ced_capi_free_string"},
|
|
} {
|
|
purego.RegisterLibFunc(lf.ptr, lib, lf.name)
|
|
}
|
|
|
|
fmt.Fprintf(os.Stderr, "[ced] ABI=%d\n", CppAbiVersion())
|
|
flag.Parse()
|
|
if err := grpc.StartServer(*addr, &Ced{}); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|