功能深度指南:批量与流式 AEC、降噪与语音转换实战)
LocalAI 音频变换Audio Transform功能深度指南批量与流式 AEC、降噪与语音转换实战【免费下载链接】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音频变换Audio Transform是 LocalAI 中一类「音频进、音频出」的通用后端能力以主输入音频为处理对象可选叠加一路参考音频作为条件信号最终输出一路增强或转换后的音频。本文围绕 docs/content/features/audio-transform.md 展开结合仓库内的 HTTP 路由、gRPC 后端与 Go 实现源码系统讲解 LocalVQE 回声消除、噪声抑制、解混响以及基于 audio.cpp 的源分离stems与语音转换speech-to-speech的完整用法覆盖批量 REST 端点、多输出 stems、双向 WebSocket 流式端点与逐参数调优读完即可直接在本地部署并调用localvqe-v1.3-4.8m完成一次真实的实时通话语音增强。audio-transform-io.png端点类别概述一类端点多种变换audio-transform 端点接收audio in并产出audio out可以可选地以第二路参考音频信号作为条件。该类别在设计上是通用的——具体操作由所选后端决定包括联合回声消除AEC 噪声抑制 解混响由 LocalVQE 提供首个正式上线的后端语音转换voice conversion此时reference为目标说话人由 audio.cpp 后端的seed_vc、vevo2、miocodec家族提供音高变换、音频超分辨率等其它派生操作。从仓库路由注册core/http/routes/localai.go可以看到该类别实际暴露为三个入口后文逐一讲解router.POST(/audio/transformations, audioTransformHandler, ...) router.POST(/audio/transform, audioTransformHandler, ...) // 别名 router.GET(/audio/transformations/stream, localai.AudioTransformStreamEndpoint(app), ...)首个实现后端LocalVQELocalVQE 是一个约 1.3 M 参数的、基于 GGML 的模型在 16 kHz 单声道语音上进行 AEC 噪声抑制 解混响联合处理在桌面 CPU 上可达约 9.6× 实时。它派生自 Microsoft DeepVQE 论文的研究成果。仓库画廊gallery/index.yaml中对其描述为 DeepVQE-style architecture with an S4D bottleneck and an in-graph DCT-II filterbank模型文件约 5 MBF32license 为 Apache-2.0并通过huggingface://LocalAI-io/LocalVQE/...分发。源分离与语音转换则由 audio.cpp 后端承担其htdemucs与mel_band_roformer系列生成下文所述的命名 stemsseed_vc、vevo2、miocodec系列则以参考说话人为条件做语音转换。核心心智模型三个请求字段每个 audio-transform 请求都携带audio—— 主输入文件必填。reference—— 辅助信号其语义由后端决定可选回声消除场景扬声器播放的环回 / 远端far-end信号语音转换场景目标说话人的参考片段音高 / 风格迁移场景音调或风格参考省略时后端将其视为静音并优雅降级——例如 LocalVQE 在reference为空时只做降噪 解混响。params—— 一个泛化的keyvalue映射原样转发给后端LocalVQE 的键为noise_gatetrue|false与noise_gate_threshold_dbfsfloat。这种近端/远端双通道的形状在业界有清晰先例它对应 WebRTC APM API 的ProcessStream(near)/ProcessReverseStream(far)、NVIDIA Maxine 的NvAFX_Run配对流签名以及 ICASSP AEC Challenge 的双通道 WAV 约定。仓库中的 Go 后端实现backend/go/localvqe/golocalvqe.go印证了这一约定参考通道缺省时零填充且当参考短于主输入时零填充补齐、长于主输入时截断到与 mic 等长保证逐样本对齐。批量端点/audio/transformationsPOST /audio/transformations别名POST /audio/transform使用 multipart/form-data返回音频字节。字段类型必填说明modelstring是audio-transform 模型 id如localvqe-v1.3-4.8maudiofile是主输入音频referencefile否可选辅助信号response_formatstring否wav默认、mp3、ogg、flacsample_rateint否期望输出采样率Hz。省略则使用后端自身采样率否则必须在 8000~192000 之间越界将被拒绝并返回 400params[key]string否可重复出现转发给后端params[stem]string否仅多输出变换使用指定响应体携带哪个命名输出params[text]string否仅文本条件变换使用被重合成的文本行先通过画廊安装一个 audio-transform 模型示例使用localvqe-v1.3-4.8mlocal-ai run localvqe-v1.3-4.8mLocalVQE 示例回声消除 降噪 残差门控curl -X POST http://localhost:8080/audio/transformations \ -F modellocalvqe-v1.3-4.8m \ -F audiomic.wav \ -F referenceloopback.wav \ -F params[noise_gate]true \ -F params[noise_gate_threshold_dbfs]-50 \ -o enhanced.wav当省略reference时LocalVQE 将参考通道零填充操作退化为噪声抑制 解混响。源码视角请求解析与表单参数收集AudioTransformRequestcore/schema/audio_transform.go是一个仅 multipart 的 schemamodel字段实际上不通过 binder 绑定而是由中间件按名称从c.FormValue(model)取到见同文件注释response_format与sample_rate两个 snake_case 字段上的form标签是承载逻辑的——echo binder 只会绑定带显式标签的字段缺少标签曾导致这两个字段被静默忽略。collectParamsFromFormcore/http/endpoints/localai/audio_transform.go负责从表单中收集所有形如params[key]的键值重复键取最后一个值此外还提供了noise_gate与noise_gate_threshold_dbfs的裸字段快捷方式表单字段优先级更高params[*]仍然优先生效。schema 中的参数常量AudioTransformParamNoiseGate/AudioTransformParamNoiseThreshold与 Go 后端backend/go/localvqe/golocalvqe.go中的字符串保持同步。sample_rate 边界是资源约束而非审美判断validateAudioTransformSampleRatecore/http/endpoints/localai/audio_transform.go在触碰磁盘与模型之前就拒绝越界的采样率返回 HTTP 400const minAudioTransformSampleRate 8000 const maxAudioTransformSampleRate 192000源码注释解释了缘由sample_rate会被直接插值进 ffmpeg 的-ar而 ffmpeg 会毫无抱怨地接受离谱速率——-ar 999999999写一秒钟的音频会产出 3.9 GB 的 WAV 并以退出码 0 结束且GeneratedContentDir无人清扫反过来-ar 1会写出零字节文件同样返回 0随后被当作变换结果发给调用者。8000 Hz 是电话编解码器的最低速率192000 Hz 已是消费级音频硬件与 WAV 容器的常规上限且是画廊中所有模型 48 kHz 产出的 4 倍。sample_rate缺省0表示保持后端自身采样率跳过校验。后端见到上传之前LocalAI 做了什么默认情况下什么都不做文件以其原始采样率与声道数到达后端。已经是纯 16-bit PCM 的 WAV 会逐字节透传任何其它容器或编码会被转码为 16-bit PCM WAV保持原有速率与声道布局。唯一的例外是声明需要固定输入形态的后端。LocalVQE 正是如此其回声消除针对 16 kHz 单声道训练并要求主输入与参考同形因此针对它的上传会用 ffmpeg 折叠为 16 kHz mono s16。该声明是BackendCapability.AudioTransformInputMono16k位于core/config对应 core/config/backend_capabilities.go 中的AudioTransformRequiresMono16kInput而localvqe是目前唯一设置它的后端。这一点对非语音增强类任务至关重要源分离模型只接受其 checkpoint 自身的采样率已发布的 htdemucs 与 mel_band_roformer checkpoint 均为 44.1 kHz并依赖立体声像来区分居中人声与宽阔混音——16 kHz 单声道降混会同时毁掉它们接受的格式与依赖的线索。在端点实现中core/http/endpoints/localai/audio_transform.go折叠与否由后端声明config.AudioTransformRequiresMono16kInput(cfg.Backend)决定为真走utils.AudioToWav折叠到 16 kHz mono为假走utils.AudioToWavPreservingShape保持原始形态已是 PCM16 的 WAV 以硬链接方式透传而非重编码。主输入与参考按同一标准折叠保证 AEC 逐样本对齐。上传文件先落盘为audio-raw-*/reference-raw-*再规整为audio.wav/reference.wav前缀命名可避免同一 basename 双上传互相截断覆盖的竞态。多输出变换源分离 stems部分变换单次运行会产出多个命名输出htdemucs 一次即可得到drums、bass、other、vocals。由于响应体只能携带一个文件LocalAI 采用如下协议后端只运行一次并把每个 stem 写在主输出旁params[stem]name选择响应体携带哪一个缺省为vocals若模型有该 stem否则取模型的第一个输出。未知 stem 名会被拒绝并返回错误、列出真实可用的名字绝不会静默替换每个 stem包括响应体内的那个都会出现在X-Audio-Stems响应头中这是一个紧凑的 JSON 数组X-Audio-Stems: [{name:drums,url:/generated-audio/transform.drums.wav}, {name:bass,url:/generated-audio/transform.bass.wav}, {name:other,url:/generated-audio/transform.other.wav}, {name:vocals,url:/generated-audio/transform.vocals.wav}]抓取任意上述 URL 即可在不重复付费做第二次分离的前提下取得其它 stem。sample_rate与response_format会同样应用于 stems 与响应体因此整组输出保持所请求的形态。该响应头已列入Access-Control-Expose-Headers浏览器客户端可以读取。单输出变换回声消除、语音转换完全不设置该响应头对这类模型传params[stem]会被拒绝而不是被忽略。# 只取人声默认 stem然后看其它 stem 落到了哪里 curl -sS -D headers.txt -X POST http://localhost:8080/audio/transformations \ -F modelhtdemucs -F audiosong.wav -o vocals.wav grep -i ^x-audio-stems headers.txt # 或者让响应体直接携带某个指定 stem curl -sS -X POST http://localhost:8080/audio/transformations \ -F modelhtdemucs -F audiosong.wav -F params[stem]drums -o drums.wavstems 存放在生成内容目录中主输出旁的兄弟文件由/generated-audio/提供访问与其它生成产物一样不会被自动清扫。源码视角一次推理产出全部 stems后端ModelAudioTransformcore/backend/audio_transform.go把输出文件写入GeneratedContentDir/audio下的唯一文件名同时将上传的输入拷贝持久化persistAudioInput以便 React UI 历史记录回放。collectStemscore/backend/audio_transform.go把后端上报的 stems 收拢为调用方可读列表且做了安全校验每个路径必须是该请求交给后端的生成目录的直接子文件杜绝恶意后端进程返回指向/etc或他人文件的路径再经 HTTP 层原样回吐校验失败即丢弃该 stem 而非致命报错。在 HTTP 层stemsHeadercore/http/endpoints/localai/audio_transform.go将 stems 渲染为单行 JSON 数组——之所以用 JSON 而非nameurl平铺格式是因为 stem 名是模型的字符串来自 checkpoint 配置一个含逗号或等号的 stem 名会悄悄破坏手拼的分隔符格式URL 经url.PathEscape转义防止#、?、%截断或污染 URL。convertStems会对每个 stem 应用请求的sample_rate与response_format转换失败的 stem 直接从列表丢弃日志记录而不是以原速率/原格式广告——广告的 URL 文件不是调用者请求的形态正是这套设计要避免的静默错误答案。/generated-audio/前缀取自生成目录与 TTS API 同一套逻辑。CORS 暴露清单见exposedAudioTransformHeaders X-Audio-Input-Url, X-Audio-Reference-Url, X-Audio-Stems。文本条件变换语音到语音speech-to-speech大多数变换是音频进、音频出少数不是speech-to-speech 模型需要知道要重合成的文本行内容才能用另一种声音复述。由于/audio/transform没有文本字段文本通过params[text]传递curl -sS -X POST http://localhost:8080/audio/transformations \ -F modelaudio-cpp-vevo2-speech-to-speech \ -F audiosource.wav \ -F referencetarget-speaker.wav \ -F params[text]The quick brown fox jumps over the lazy dog. \ -o converted.wav对于这类模型文本是必需项而非提示缺少文本时运行会被直接拒绝。params[target_text]被接受为同义字段params[language]在文本非英语时设定语言。不接受文本的模型会忽略以上三个字段因此普通分离或降噪请求完全不受影响。流式端点/audio/transformations/streamGET /audio/transformations/stream是一个双向 WebSocket 端点。客户端第一条消息为 JSON 信封其后客户端消息为二进制 PCM 帧服务器以相同节奏回发二进制 PCM 帧。该端点只接受带audio_transformuse case 的模型不接受带realtime_audiouse case 的 any-to-any 模型。例如liquid-audio应改用 OpenAI Realtime API。这一校验在端点源码中显式实现validateAudioTransformStreamModelcore/http/endpoints/localai/audio_transform.go会对 any-to-any 模型返回 use the OpenAI Realtime API instead 的明确错误。线上格式客户端 → 服务器文本帧第一条{ type: session.update, model: localvqe-v1.3-4.8m, sample_format: S16_LE, sample_rate: 16000, frame_samples: 256, params: { noise_gate: true } }sample_format为S16_LE16-bit 有符号小端或F32_LE32-bit 浮点小端取值 [-1, 1]。frame_samples缺省为后端首选 hop 长度LocalVQE 为 256 16 ms。控制信封的完整字段结构见AudioTransformStreamControlcore/schema/audio_transform.go包含type、model、sample_format、sample_rate、frame_samples、params、reset与error。客户端 → 服务器二进制帧后续消息交错立体声 PCM通道 0 audiomic通道 1 reference。帧大小frame_samples × 2 channels × sample_size。S16_LE256 样本时为每帧 1024 字节F32_LE时为 2048 字节。参考通道无信号时发送全零。端点在读到二进制帧后会调用splitStereoFrameIntocore/http/endpoints/localai/audio_transform.go原位去交错利用每连接复用的缓冲区避免 16 ms 节奏下每次入站帧两次分配。服务器 → 客户端二进制帧同格式的单声道 PCMframe_samples × sample_size字节S16_LE为 512F32_LE为 1024。流中控制文本帧再次发送session.update且其reset字段为 true 时重置流状态session.close文本帧干净地结束会话。WebSocket 连接的每消息读取上限为 1 MiBaudioTransformWSReadLimit以容纳 hop 更长的后端在更大frame_samples下的帧。Go 后端侧backend/go/localvqe/golocalvqe.go要求首条消息必须是Config且若frame_samples非零则必须等于 hop_length流状态是每上下文per-context的因此调用经SingleThread串行化避免并发流破坏 overlap-add 缓冲区。延迟LocalVQE 具有 16 ms 算法延迟一个 hop。运行时的每帧 CPU 开销取决于模型紧凑的 1.3 M 参数模型v1.1/v1.2约 9.7× 实时约 1.6 ms/帧更宽的 v1.3 4.8 M 模型约 4.7× 实时约 3.3 ms/帧——测量环境为 4 线程的现代桌面剩余预算留给网络与下游播放。值得补充的是Go 后端的线程数策略backend/go/localvqe/golocalvqe.go会把GGML_NTHREADS封顶到 4——LocalVQE 仅 1.3 M 参数上游基准扫描显示 1–4 线程是最优区间超过约 4 线程后每帧预算被同步开销主导、p99 延迟恶化。该上限同时避免为 70B LLM 全局调优的LOCALAI_THREADSN意外拖累音频处理。后端专项调优LocalVQEparams[key]类型默认值作用noise_gateboolfalse启用 OLA 后置的基于 RMS 的残差回波门noise_gate_threshold_dbfsfloat-45.0门限值dBFS低于该值的帧被置零该门在远端单讲 / 近端静音的时间段里最有用——此时模型的残差听起来像缓冲噪声或被放大的底噪。一个合理的起始值是-50dBFS。Go 后端会按调用应用参数applyParamsbackend/go/localvqe/golocalvqe.go先以Options[]中的静态配置为底Load 时经parseOptions解析请求级params中的值逐次覆盖并通过CppSetNoiseGate下发到 C 侧结果缓存回内存避免每请求重复 CGo 往返。两个键的字符串常量与 HTTP 层、schema 层保持同步。配置一个模型LocalVQE 在画廊中发布多个权重版本localvqe-v1.3-4.8m当前默认质量最佳、localvqe-v1.2-1.3m与localvqe-v1.1-1.3m紧凑型每 hop 开销约为前者的 1/4适合低核或功耗受限主机。它们共享同一后端与请求 API仅有model文件名不同。画廊条目gallery/index.yaml以overrides.backend: localvqe绑定后端并携带audio-transform、aec、noise-suppression、dereverberation等标签用于筛选。在模型配置中可以通过Options[]设置后端级默认值每次请求的params[*]表单字段会覆盖它们name: localvqe backend: localvqe parameters: model: localvqe-v1.3-4.8M-f32.gguf # Backend-specific defaults can be set in Options[]; per-request # params[*] form fields override. # # backend and device route through the upstream localvqe options # builder so you can force a non-default GGML backend (e.g. Vulkan) or # pin to a specific GPU index. Leave both unset to keep the CPU default. options: - noise_gatetrue - noise_gate_threshold_dbfs-50 # - backendVulkan # - device0源码层面backend/go/localvqe/golocalvqe.go确认了Options[]的解析规则支持keyvalue与key:value两种分隔形式backend与device经由上游 options builderCppOptionsNew setter CppNewWithOptions构造上下文从而可强制非默认 GGML 后端或钉住某块 GPU其余键noise_gate、noise_gate_threshold_dbfs在本地消费。加载时会断言模型采样率恰为 16000 Hz、hop 与 FFT 尺寸为正否则拒绝加载并给出清晰错误而不是放 C 侧返回垃圾数据。端到端调用链小结一次典型的批量增强请求在仓库中走如下链路可作为排障时的参考路由层router.POST(/audio/transformations)命中AudioTransformEndpointcore/http/routes/localai.go中间件setModelNameFromRequest从表单取model并解析模型配置model字段不依赖 echo binder端点校验先验sample_rate边界400 拒绝再接收audio文件可选接收reference按后端声明决定是否折叠到 16 kHz monosaveMultipartFileAsWAV参数收集collectParamsFromForm汇总params[*]并与 schema body 参数合并表单优先后端执行backend.ModelAudioTransform持久化输入、获取全局后端槽位AcquireGlobalBackendSlot、下发proto.AudioTransformRequest并收集 stemsLocalVQE 侧经 purego 绑定调用 C 库的localvqe_process_f32缺参考则零填充产物处理按需AudioResampleAudioConvert设置X-Audio-Input-Url/X-Audio-Reference-Url/X-Audio-Stems头与 CORS 暴露清单最后以附件形式返回音频字节。流式路径则在AudioTransformStreamEndpoint中完成 WebSocket 升级lockedConn串行化写入、避免 Gorilla 单并发写者约束下的数据竞争、首帧session.update校验、后端双向 gRPC 流桥接与立体声帧去交错整个会话以session.close干净收尾。See also音频变换的官方功能文档本文依据的原始文档含线格式与参数表的权威表述音频变换端点实现批量与流式端点、采样率边界、stems 头与 CORS音频变换后端服务层gRPC 调用、输入持久化与 stems 路径安全LocalVQE Go 后端实现参数解析、16 kHz 断言、流式帧处理与线程策略audio-transform 请求/流控制 schema字段标签、协议常量LocalVQE 画廊条目v1.1 / v1.2 / v1.3 各权重版本的下载地址与 sha256【免费下载链接】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),仅供参考