mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-18 21:58:58 -04:00
* feat(backend): add depth-anything (Depth Anything 3) C++/ggml backend + gallery Mirrors the locate-anything-cpp backend to register a new depth-anything backend that wraps the Depth Anything 3 ggml port (depth-anything.cpp) via purego (cgo-less, no Python at inference). - backend/go/depth-anything-cpp/: gRPC backend (Load + Predict + GenerateImage), purego binding to the da_capi_* C ABI, CMake/Makefile/run/package/test scripts building depth-anything.cpp's DA_SHARED static .so per CPU variant. - backend/index.yaml: depth-anything backend meta + all hardware-variant capability entries (cpu/cuda12/cuda13/intel-sycl-f32+f16/vulkan/nvidia-l4t). - gallery/index.yaml: 8 Depth Anything 3 GGUF models (base q4_k/q8_0/f16/f32, small, large, giant, mono-large). - .github/backend-matrix.yml: one build entry per hardware variant. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(depth): typed Depth RPC + REST endpoint exposing full DA3 data Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(depth): pin depth-anything.cpp to e0b6814 (ABI 3 dense C-API) The Depth RPC handler calls da_capi_depth_dense / da_capi_points (C-API ABI 3); pin the native build to the commit that exports them. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(depth): pin depth-anything.cpp to v0.1.0 release (b515c31) Repoint the native version from the now-orphaned e0b6814 to the b515c31 release commit, kept alive by the upstream v0.1.0 tag. C-API is unchanged (da_capi_abi_version == 3). Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(depth): wire depth-anything-cpp into build, CI bump, and importer The backend dir, gallery index, and CI build-matrix were present but the backend was never wired into the integration points that adding-backends.md requires: - root Makefile: add to .NOTPARALLEL, the test-extra chain, a BACKEND_* definition, the docker-build target eval, and docker-build-backends (mirrors parakeet-cpp; the backend's own Makefile already documented that its `test` target is driven by test-extra). - bump_deps.yaml: register the DEPTHANYTHING_VERSION pin so the daily auto-bump bot tracks mudler/depth-anything.cpp master (it cannot see an unregistered Makefile pin). - import form: add a preference-only KnownBackend entry so depth-anything is selectable at /import-model (mirrors sam3-cpp; no reliable GGUF auto-detect signal, so pref-only per the doc's default). changed-backends.js needs no entry: the generic golang suffix branch already resolves backend/go/depth-anything-cpp/. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(depth): auto-detect importer for depth-anything GGUFs Replace the preference-only entry with a real auto-detect importer (mirrors parakeet-cpp / locate-anything): - DepthAnythingImporter matches a .gguf whose name carries a depth-anything token (depth-anything-<size>-<quant>.gguf), so /import-model recognises mudler/depth-anything.cpp-gguf repos and direct GGUF URLs without an explicit backend preference. preferences.backend= "depth-anything" still forces it. - Registered before LlamaCPPImporter so its GGUF bundles aren't claimed by the generic .gguf importer; the narrow name match means it cannot claim arbitrary llama GGUFs or the upstream safetensors PyTorch repos. - Multi-quant repos pick the smallest quant by default (q4_k -> ... -> f32, depth stays >0.998 corr even at q4_k); quantizations preference overrides. - Drops the now-redundant knownPrefOnlyBackends entry (importer-backed backends are not listed there, matching parakeet-cpp). - Table-driven Ginkgo test covers detection, negative cases (llama GGUF, upstream safetensors), default/override/fallback quant pick, and direct URL import. 10/10 specs pass. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(depth): check conn.Close error in grpc Depth client (errcheck) The new Depth() client method used a bare `defer conn.Close()`. golangci-lint runs with new-from-merge-base, so although the 39 sibling methods use the same bare form (grandfathered), the newly added line trips errcheck. Drop the result explicitly to satisfy the linter. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Assisted-by: Claude:claude-opus-4-8 * fix(depth): bump depth-anything.cpp to v0.1.1 (embeddable CMake) v0.1.0 (b515c31) used ${CMAKE_SOURCE_DIR} for its include dirs, which points at the parent project when built via add_subdirectory() as this backend does, so the container build failed with missing stb_image.h / da_gguf_keys.h. v0.1.1 (2d42897) switches to project-relative paths. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Assisted-by: Claude:claude-opus-4-8 * fix(depth): resolve gosec findings in the backend wrapper The code-scanning gate flagged three new failure-level alerts in godepthanythingcpp.go (gosec runs with -no-fail; GitHub gates on new alerts): - G301: export dirs were created with 0o755. Tighten to 0o750 (no world access needed for backend-written export output). - G304: writeDepthPNG creates req.GetDst(). That path is chosen by the LocalAI core as the intended output destination (same pattern every image backend uses), not attacker input, so annotate with #nosec G304 and document why. The remaining G103 "audit unsafe" notes on the unsafe.Slice C-buffer copies are warning-level (the same purego interop whisper/parakeet use) and do not gate the check, per the supertonic exclusion precedent in secscan.yaml. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Assisted-by: Claude:claude-opus-4-8 * fix(depth): bump depth-anything.cpp to v0.1.2 (CUDA cross-build arch) v0.1.1 forced CMAKE_CUDA_ARCHITECTURES=native, which breaks the GPU-less l4t/cublas CI builds (nvcc "Unsupported gpu architecture 'compute_'" on CMake 3.22). v0.1.2 (442eea4) drops the override and lets ggml pick its default cross-build arch list. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Assisted-by: Claude:claude-opus-4-8 --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
228 lines
6.6 KiB
Go
228 lines
6.6 KiB
Go
package base
|
|
|
|
// This is a wrapper to satisfy the GRPC service interface
|
|
// It is meant to be used by the main executable that is the server for the specific backend type (falcon, gpt3, etc)
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
|
|
pb "github.com/mudler/LocalAI/pkg/grpc/proto"
|
|
gopsutil "github.com/shirou/gopsutil/v3/process"
|
|
)
|
|
|
|
// Base is a base class for all backends to implement
|
|
// Note: the backends that does not support multiple requests
|
|
// should use SingleThread instead
|
|
type Base struct {
|
|
}
|
|
|
|
func (llm *Base) Locking() bool {
|
|
return false
|
|
}
|
|
|
|
func (llm *Base) Lock() {
|
|
panic("not implemented")
|
|
}
|
|
|
|
func (llm *Base) Unlock() {
|
|
panic("not implemented")
|
|
}
|
|
|
|
func (llm *Base) Busy() bool {
|
|
return false
|
|
}
|
|
|
|
func (llm *Base) Load(opts *pb.ModelOptions) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) Predict(opts *pb.PredictOptions) (string, error) {
|
|
return "", fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) PredictStream(opts *pb.PredictOptions, results chan string) error {
|
|
close(results)
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) Embeddings(opts *pb.PredictOptions) ([]float32, error) {
|
|
return []float32{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) GenerateImage(*pb.GenerateImageRequest) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) GenerateVideo(*pb.GenerateVideoRequest) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) AudioTranscription(context.Context, *pb.TranscriptRequest) (pb.TranscriptResult, error) {
|
|
return pb.TranscriptResult{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) AudioTranscriptionStream(context.Context, *pb.TranscriptRequest, chan *pb.TranscriptStreamResponse) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) TTS(*pb.TTSRequest) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) TTSStream(*pb.TTSRequest, chan []byte) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) SoundGeneration(*pb.SoundGenerationRequest) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) Detect(*pb.DetectOptions) (pb.DetectResponse, error) {
|
|
return pb.DetectResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) Depth(*pb.DepthRequest) (pb.DepthResponse, error) {
|
|
return pb.DepthResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) FaceVerify(*pb.FaceVerifyRequest) (pb.FaceVerifyResponse, error) {
|
|
return pb.FaceVerifyResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) FaceAnalyze(*pb.FaceAnalyzeRequest) (pb.FaceAnalyzeResponse, error) {
|
|
return pb.FaceAnalyzeResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) VoiceVerify(*pb.VoiceVerifyRequest) (pb.VoiceVerifyResponse, error) {
|
|
return pb.VoiceVerifyResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) VoiceAnalyze(*pb.VoiceAnalyzeRequest) (pb.VoiceAnalyzeResponse, error) {
|
|
return pb.VoiceAnalyzeResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) VoiceEmbed(*pb.VoiceEmbedRequest) (pb.VoiceEmbedResponse, error) {
|
|
return pb.VoiceEmbedResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) Diarize(*pb.DiarizeRequest) (pb.DiarizeResponse, error) {
|
|
return pb.DiarizeResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) TokenizeString(opts *pb.PredictOptions) (pb.TokenizationResponse, error) {
|
|
return pb.TokenizationResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) ModelMetadata(opts *pb.ModelOptions) (*pb.ModelMetadataResponse, error) {
|
|
return nil, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
// backends may wish to call this to capture the gopsutil info, then enhance with additional memory usage details?
|
|
func (llm *Base) Status() (pb.StatusResponse, error) {
|
|
return pb.StatusResponse{
|
|
Memory: memoryUsage(),
|
|
}, nil
|
|
}
|
|
|
|
func (llm *Base) StoresSet(*pb.StoresSetOptions) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) StoresGet(*pb.StoresGetOptions) (pb.StoresGetResult, error) {
|
|
return pb.StoresGetResult{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) StoresDelete(*pb.StoresDeleteOptions) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) StoresFind(*pb.StoresFindOptions) (pb.StoresFindResult, error) {
|
|
return pb.StoresFindResult{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) VAD(*pb.VADRequest) (pb.VADResponse, error) {
|
|
return pb.VADResponse{}, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) AudioEncode(*pb.AudioEncodeRequest) (*pb.AudioEncodeResult, error) {
|
|
return nil, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) AudioDecode(*pb.AudioDecodeRequest) (*pb.AudioDecodeResult, error) {
|
|
return nil, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) AudioTransform(*pb.AudioTransformRequest) (*pb.AudioTransformResult, error) {
|
|
return nil, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) AudioTransformStream(in <-chan *pb.AudioTransformFrameRequest, out chan<- *pb.AudioTransformFrameResponse) error {
|
|
close(out)
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) AudioToAudioStream(in <-chan *pb.AudioToAudioRequest, out chan<- *pb.AudioToAudioResponse) error {
|
|
close(out)
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) Forward(ctx context.Context, in <-chan *pb.ForwardRequest, out chan<- *pb.ForwardReply) error {
|
|
close(out)
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) StartFineTune(*pb.FineTuneRequest) (*pb.FineTuneJobResult, error) {
|
|
return nil, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) FineTuneProgress(*pb.FineTuneProgressRequest, chan *pb.FineTuneProgressUpdate) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) StopFineTune(*pb.FineTuneStopRequest) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) ListCheckpoints(*pb.ListCheckpointsRequest) (*pb.ListCheckpointsResponse, error) {
|
|
return nil, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) ExportModel(*pb.ExportModelRequest) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) StartQuantization(*pb.QuantizationRequest) (*pb.QuantizationJobResult, error) {
|
|
return nil, fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) QuantizationProgress(*pb.QuantizationProgressRequest, chan *pb.QuantizationProgressUpdate) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func (llm *Base) StopQuantization(*pb.QuantizationStopRequest) error {
|
|
return fmt.Errorf("unimplemented")
|
|
}
|
|
|
|
func memoryUsage() *pb.MemoryUsageData {
|
|
mud := pb.MemoryUsageData{
|
|
Breakdown: make(map[string]uint64),
|
|
}
|
|
|
|
pid := int32(os.Getpid())
|
|
|
|
backendProcess, err := gopsutil.NewProcess(pid)
|
|
|
|
if err == nil {
|
|
memInfo, err := backendProcess.MemoryInfo()
|
|
if err == nil {
|
|
mud.Total = memInfo.VMS // TEST, but rss seems reasonable first guess. Does include swap, but we might care about that.
|
|
mud.Breakdown["gopsutil-RSS"] = memInfo.RSS
|
|
}
|
|
}
|
|
return &mud
|
|
}
|
|
func (llm *Base) Free() error {
|
|
return nil
|
|
}
|