LocalAI 声音事件分类实战:/v1/audio/classification 端点与 ced 后端实现解析
2026/9/8 22:52:53 网站建设 项目流程

LocalAI 声音事件分类实战:/v1/audio/classification 端点与 ced 后端实现解析

【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI

声音事件分类(Sound-event classification,又称音频打标)回答的问题是"我在听到什么?":给定一段音频片段,模型返回一组带分数的 AudioSet 标签,例如Baby cry, infant cryGlass breakingDog barkAlarm。LocalAI 通过 OpenAI 风格的/v1/audio/classification端点暴露该能力,参考后端为 ced.cpp(CED,一个 527 类的 AudioSet 打标器,一个跑在 log-mel 频谱图上的小型 ViT,已移植到 ggml 并与 PyTorch 完全对齐)。读完本文,你将掌握该端点的完整请求/响应协议、模型安装与 curl 调用方式,并能从源码层面理解 LocalAI 如何把一次 HTTP 音频上传拆解为 gRPC 后端调用。

什么是声音事件分类

与语音转文字("说了什么")不同,声音分类关心的是声音本身的内容。输入一段任意格式的音频,输出是一组候选事件标签及其置信度。由于同一时刻多种声音可以共存(比如婴儿哭闹的同时伴随玻璃碎裂),CED 采用的是多标签(multi-label)独立分类:每个类别的概率相互独立,因此所有分数加起来不必等于 1。

LocalAI 将分类建模为一个常规的 OpenAI 风格端点,与/v1/audio/transcriptions同构——任何 HTTP 客户端都可以直接调用,消费端不需要任何 Python 依赖。

端点:POST /v1/audio/classification

在 core/http/routes/openai.go 中可以看到,该端点同时注册了两个路径:

POST /v1/audio/classification POST /audio/classification Content-Type: multipart/form-data

请求字段

字段类型说明
filefile(必填)音频文件,接受ffmpeg支持的任意格式
modelstring(必填)支持声音分类的模型名(例如ced-base-f16
top_kint返回的标签数量(0 = 使用后端默认值)
thresholdfloat丢弃得分低于该阈值的标签

从源码看,HTTP 层通过parseFormInt/parseFormFloat解析这两个可选参数,默认值均为 0(即不生效),见 core/http/endpoints/openai/sound_classification.go:

req := backend.SoundDetectionRequest{ TopK: int32(parseFormInt(c, "top_k", 0)), Threshold: float32(parseFormFloat(c, "threshold", 0)), }

top_k <= 0时,ced 后端会回落到默认值 10(见 backend/go/ced/goced.go):

topK := req.GetTopK() if topK <= 0 { topK = 10 // sensible default for a tagging response }

响应格式

{ "model": "ced-base-f16", "detections": [ {"index": 23, "label": "Baby cry, infant cry", "score": 0.87}, {"index": 22, "label": "Crying, sobbing", "score": 0.41} ] }

响应体由 core/schema/sound_classification.go 定义:detections中每一项包含index(模型本体论中的类别索引)、label(人类可读的 AudioSet 类名)和score(该类别的独立概率)。检测结果是按分数降序返回的——后端先排序一次,Go 侧在 core/backend/sound_classification.go 还会做一次稳定的二次排序以保证顺序:

sort.SliceStable(out.Detections, func(i, j int) bool { return out.Detections[i].Score > out.Detections[j].Score })

由于分数是多标签独立概率,它们不要求加和为 1

实战:安装模型并调用

第一步,从模型库(gallery)安装一个支持声音分类的模型(下文示例使用ced-base-f16):

local-ai run ced-base-f16

仓库中的 gallery/ced.yaml 给出了 ced 系列模型的标准配置模板:

name: "ced-sound-classification" config_file: | backend: ced known_usecases: - sound_classification

其中known_usecases: sound_classification是端点路由的关键——/v1/audio/classification中间件会按FLAG_SOUND_CLASSIFICATION过滤出声明了该 usecase 的模型(core/http/routes/openai.go),因此自定义模型配置时必须保留这一声明。

然后上传一段音频进行分类:

curl http://localhost:8080/v1/audio/classification \ -H "Content-Type: multipart/form-data" \ -F file="@/path/to/clip.wav" \ -F model="ced-base-f16" \ -F top_k=10

按需追加-F threshold=0.2可以只保留置信度较高的标签,减少噪声标签。

源码走读:一次分类请求的完整链路

从源码结构看,一次请求经历四层:

1. HTTP 端点层(core/http/endpoints/openai/sound_classification.go)。处理器接收 multipart 上传后,将音频落盘到服务器自建的临时目录(os.MkdirTemp("", "sound-classification")),请求结束后defer os.RemoveAll(dir)清理。代码注释明确说明了安全性考虑:目标文件名由服务端生成的临时目录与上传文件名的path.Base拼接,路径穿越风险已被排除。

2. 后端调度层(core/backend/sound_classification.go)。SoundDetectionRequest携带音频路径与TopKThreshold,经toProto转换为 gRPC 的SoundDetectionRequest后发给后端。loadSoundDetectionModel会校验模型必须配置了后端:

if modelConfig.Backend == "" { return nil, fmt.Errorf("sound classification: model %q has no backend set; supported backends include ced", modelConfig.Name) }

3. gRPC 后端层(backend/go/ced/main.go)。ced 后端是一个由 LocalAI 内部启动的 gRPC 服务,每个已加载模型对应一个实例。它通过purego动态加载libced.so(macOS 下为libced.dylib),并绑定ced_capi.h声明的整套 C API:ced_capi_loadced_capi_num_classesced_capi_sample_rateced_capi_classify_path_jsonced_capi_classify_pcm_json等。库路径可用环境变量CED_LIBRARY覆盖(与PARAKEET_LIBRARY/WHISPER_LIBRARY的约定一致),默认查找二进制同目录下的.so

4. C 引擎层(backend/go/ced/goced.go)。SoundDetection方法调用ced_capi_classify_path_json得到 JSON 格式的标签列表,然后在 Go 侧应用threshold过滤(score < threshold的标签被丢弃),最后按分数降序排序返回。由于 C 侧每个上下文是单线程的,实现上用engineMu互斥锁串行化对引擎的访问。

CED_LIBRARYced_capi_*函数名等细节均可在 backend/go/ced/main.go 的绑定表中逐一核对。

ced 后端的构建与硬件加速

backend/go/ced/Makefile 揭示了 ced 后端与上游 ced.cpp 的集成方式:

  • 版本固定CED_VERSION锁定到具体的上游 commit,CED_REPO指向localai-org/ced.cpp,遵循 LocalAI 其他 C++ 后端(parakeet-cpp、whisper.cpp)的惯例;
  • 静态自包含:cmake 参数包含-DCED_SHARED=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON,并把 ggml 以 PIC 方式静态链入libced.so,这样dlopen时不需要旁边再放一个libggml*.so
  • 纯 Go 侧零 CGOced-grpc目标以CGO_ENABLED=0构建,因为 C 交互全部走purego动态绑定,而非 CGO 编译期链接;
  • 可选加速后端:通过BUILD_TYPE切换,映射到 ced.cpp 的CED_GGML_*cmake 开关——cublas(CUDA + CUDA graphs)、openblashipblas(ROCm)、vulkan;默认NATIVE=false关闭 ggml native 以换取跨机器可移植性。

CED 的权重为 Apache-2.0 许可,可作为 GGUF 自由再分发;模型加载时Load方法要求提供 GGUF 文件路径(opts.ModelFile),调用ced_capi_load打开 C API 上下文(backend/go/ced/goced.go)。

相关功能

  • 音频转文字 —— 语音转文字(transcription)
  • 说话人分离 —— 谁在什么时候说话

【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询