Skip to content

Commit 5104ae6

Browse files
authored
Merge pull request #3489 from modelscope/codex/site-sensevoice-native-server-20260813
docs(site): add SenseVoice native server deployment
2 parents 5c1db4f + 2469fb7 commit 5104ae6

4 files changed

Lines changed: 163 additions & 0 deletions

File tree

web-pages/product-site/data/deployments.json

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,95 @@
236236
}
237237
}
238238
},
239+
{
240+
"id": "sensevoice-native-server",
241+
"routes": {"zh": "/deploy/sensevoice-native-server.html", "en": "/en/deploy/sensevoice-native-server.html"},
242+
"maturity": "production-verified",
243+
"selector_rank": 20.5,
244+
"workloads": ["private-api", "realtime", "edge"],
245+
"hardware": ["cpu", "nvidia-gpu"],
246+
"priorities": ["compatibility", "portability"],
247+
"models": ["SenseVoiceSmall-GGUF", "FSMN-VAD-GGUF"],
248+
"operating_systems": ["Linux"],
249+
"interfaces": ["OpenAI-compatible HTTP", "OpenAI realtime WebSocket", "WS /v1/realtime?intent=transcription", "SSE", "SRT/VTT"],
250+
"tested": {
251+
"funasr": "SenseVoice main@b054623c",
252+
"runtime": "sensevoice-server@558bd67c",
253+
"verified": "2026-08-13"
254+
},
255+
"commands": {
256+
"install": [
257+
"git clone https://github.com/QwenAudio/SenseVoice.git && cd SenseVoice",
258+
"git checkout b054623cca8f015b73ec471dce4f473ac47413da",
259+
"python3 -m pip install -U huggingface_hub",
260+
"bash runtime/llama.cpp/download-funasr-model.sh sensevoice model",
261+
"cmake -S runtime/llama.cpp -B runtime/llama.cpp/build -DCMAKE_BUILD_TYPE=Release",
262+
"cmake --build runtime/llama.cpp/build --target sensevoice-server -j"
263+
],
264+
"launch": [
265+
"runtime/llama.cpp/build/bin/sensevoice-server -m model/sensevoice-small-q8.gguf -vad model/fsmn-vad.gguf --threads 8 --max-connections 4 --max-audio-seconds 300 127.0.0.1 8040"
266+
],
267+
"health": [
268+
"curl -fsS http://127.0.0.1:8040/health",
269+
"curl -fsS http://127.0.0.1:8040/v1/models"
270+
],
271+
"smoke": [
272+
"curl -fsS http://127.0.0.1:8040/v1/audio/transcriptions -F file=@speech.wav",
273+
"curl -fsS http://127.0.0.1:8040/v1/audio/transcriptions -F file=@speech.wav -F response_format=vtt | tee transcript.vtt && grep -q WEBVTT transcript.vtt",
274+
"curl -fsSN http://127.0.0.1:8040/v1/audio/transcriptions -F file=@speech.wav -F stream=true | grep -q transcript.text.done",
275+
"python3 runtime/llama.cpp/tests/stream_client.py 127.0.0.1 8040 speech_16k.wav 200"
276+
]
277+
},
278+
"evidence": [
279+
{
280+
"label": "merged SenseVoice server contribution",
281+
"url": "https://github.com/QwenAudio/SenseVoice/pull/341"
282+
},
283+
{
284+
"label": "source and operating guide at the verified merge",
285+
"url": "https://github.com/QwenAudio/SenseVoice/blob/b054623cca8f015b73ec471dce4f473ac47413da/runtime/llama.cpp/sensevoice-server/README.md"
286+
},
287+
{
288+
"label": "pull-request build, unit, and contract workflow",
289+
"url": "https://github.com/QwenAudio/SenseVoice/actions/runs/31633373807"
290+
},
291+
{
292+
"label": "main-branch build, unit, and contract workflow",
293+
"url": "https://github.com/QwenAudio/SenseVoice/actions/runs/31633730096"
294+
},
295+
{
296+
"label": "server regression and contract tests",
297+
"url": "https://github.com/QwenAudio/SenseVoice/tree/b054623cca8f015b73ec471dce4f473ac47413da/runtime/llama.cpp/tests"
298+
}
299+
],
300+
"benchmarks": [],
301+
"translations": {
302+
"zh": {
303+
"name": "SenseVoice 原生 OpenAI 实时服务",
304+
"summary": "用一个无 Python 运行时的 C++ 二进制提供 SenseVoice REST、SSE、SRT/VTT 与 OpenAI Realtime WebSocket 转写。",
305+
"fit": ["本地或内网 OpenAI 兼容语音接口", "CPU 优先、可选 CUDA 的低依赖部署", "需要文件转写、流式 partial/final 与服务端 VAD"],
306+
"not_fit": ["需要预编译跨平台发布包", "需要多租户认证、计费或持久任务队列", "没有在目标硬件完成容量测试就直接暴露公网"],
307+
"selection_reason": "原生 GGUF 服务把 REST 文件转写和实时 WebSocket 放进同一个受资源上限保护的二进制,适合私有兼容接口和边缘流式场景。",
308+
"primary_limitation": "当前官方验证覆盖 Linux 源码构建;服务不内置生产认证、TLS、多租户配额或持久队列,必须由网关和基础设施补齐。",
309+
"status_label": "生产验证",
310+
"operations": ["固定 merge commit、SenseVoice GGUF 与 FSMN-VAD GGUF", "显式设置连接上限、单请求音频上限和读取超时", "发布前分别压测 REST、SSE 和 WebSocket,并保留旧二进制回滚"],
311+
"security": ["默认绑定 127.0.0.1 或可信内网", "在反向代理实施 TLS、认证、MIME、请求体大小、速率和并发限制", "只加载经过来源与摘要校验的 GGUF"],
312+
"troubleshooting": ["先用 CPU、已知 16 kHz WAV 和 REST JSON 路径验证", "确认模型文件名为 sensevoice-small-q8.gguf 与 fsmn-vad.gguf", "WebSocket 客户端发送 16 kHz 单声道 PCM16 的 base64 chunk"]
313+
},
314+
"en": {
315+
"name": "SenseVoice native OpenAI realtime server",
316+
"summary": "Use one C++ binary with no Python runtime to serve SenseVoice over REST, SSE, SRT/VTT, and OpenAI realtime WebSocket transcription.",
317+
"fit": ["A local or private OpenAI-compatible speech endpoint", "CPU-first deployment with optional CUDA and few runtime dependencies", "File transcription, streaming partial/final results, and server-side VAD"],
318+
"not_fit": ["Prebuilt cross-platform release packages are required", "Built-in multi-tenant authentication, billing, or durable job queues are required", "Public exposure before capacity testing on the target hardware"],
319+
"selection_reason": "The native GGUF server combines REST file transcription and realtime WebSocket in one resource-bounded binary for private compatible APIs and edge streaming.",
320+
"primary_limitation": "Official verification currently covers Linux source builds; the server does not include production authentication, TLS, tenant quotas, or durable queues, so provide them at the gateway and infrastructure layers.",
321+
"status_label": "Production verified",
322+
"operations": ["Pin the merge commit plus the SenseVoice and FSMN-VAD GGUF files", "Set the connection limit, per-request audio limit, and read timeout explicitly", "Load-test REST, SSE, and WebSocket separately before rollout, and retain the previous binary for rollback"],
323+
"security": ["Bind to 127.0.0.1 or a trusted private network by default", "Enforce TLS, authentication, MIME, request-body size, rate, and concurrency at the reverse proxy", "Load only GGUF files with verified provenance and digests"],
324+
"troubleshooting": ["Validate CPU, a known 16 kHz WAV, and the REST JSON path first", "Confirm the model files are named sensevoice-small-q8.gguf and fsmn-vad.gguf", "Send base64 chunks of 16 kHz mono PCM16 from WebSocket clients"]
325+
}
326+
}
327+
},
239328
{
240329
"id": "audio-cpp",
241330
"routes": {"zh": "/deploy/audio-cpp.html", "en": "/en/deploy/audio-cpp.html"},

web-pages/product-site/tests/test_output.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,30 @@ def test_llama_cpp_pages_render_v020_download_matrix(built_site, relative, bound
7777
assert boundary in soup.get_text(' ', strip=True)
7878

7979

80+
@pytest.mark.parametrize(
81+
('relative', 'language_marker'),
82+
(
83+
('deploy/sensevoice-native-server.html', '连接上限'),
84+
('en/deploy/sensevoice-native-server.html', 'connection limit'),
85+
),
86+
)
87+
def test_sensevoice_native_server_pages_render_operational_contract(
88+
built_site, relative, language_marker
89+
):
90+
soup = read_soup(built_site / relative)
91+
text = soup.get_text(' ', strip=True)
92+
93+
for marker in (
94+
'sensevoice-server',
95+
'/v1/audio/transcriptions',
96+
'/v1/realtime?intent=transcription',
97+
'--max-connections',
98+
'--max-audio-seconds',
99+
language_marker,
100+
):
101+
assert marker in text
102+
103+
80104
def test_benchmark_rows_have_complete_conditions(built_site):
81105
registry = load_registry(SITE_ROOT / 'data' / 'deployments.json')
82106
records = [record for entry in registry['deployments'] for record in entry['benchmarks']]

web-pages/product-site/tests/test_registry.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
'vllm',
1919
'sensevoice-tensorrt',
2020
'llama-cpp',
21+
'sensevoice-native-server',
2122
'audio-cpp',
2223
'openai-api',
2324
'realtime',
@@ -185,6 +186,54 @@ def test_llama_cpp_contract_tracks_v020_release_assets(valid_registry):
185186
assert 'AMD' in entry['translations']['en']['primary_limitation']
186187

187188

189+
def test_sensevoice_native_server_contract_tracks_merged_runtime(valid_registry):
190+
entry = next(
191+
item for item in valid_registry['deployments']
192+
if item['id'] == 'sensevoice-native-server'
193+
)
194+
llama_cpp = next(item for item in valid_registry['deployments'] if item['id'] == 'llama-cpp')
195+
audio_cpp = next(item for item in valid_registry['deployments'] if item['id'] == 'audio-cpp')
196+
197+
assert valid_registry['verified'] == '2026-08-13'
198+
assert entry['maturity'] == 'production-verified'
199+
assert llama_cpp['selector_rank'] < entry['selector_rank'] < audio_cpp['selector_rank']
200+
assert entry['tested'] == {
201+
'funasr': 'SenseVoice main@b054623c',
202+
'runtime': 'sensevoice-server@558bd67c',
203+
'verified': '2026-08-13',
204+
}
205+
assert entry['models'] == ['SenseVoiceSmall-GGUF', 'FSMN-VAD-GGUF']
206+
assert entry['operating_systems'] == ['Linux']
207+
assert {
208+
'OpenAI-compatible HTTP',
209+
'OpenAI realtime WebSocket',
210+
'SSE',
211+
'SRT/VTT',
212+
} <= set(entry['interfaces'])
213+
assert any(
214+
'git checkout b054623cca8f015b73ec471dce4f473ac47413da' in command
215+
for command in entry['commands']['install']
216+
)
217+
assert any(
218+
'download-funasr-model.sh sensevoice' in command
219+
for command in entry['commands']['install']
220+
)
221+
launch = '\n'.join(entry['commands']['launch'])
222+
for marker in ('sensevoice-server', '--max-connections', '--max-audio-seconds'):
223+
assert marker in launch
224+
smoke = '\n'.join(entry['commands']['smoke'])
225+
for marker in ('/v1/audio/transcriptions', 'response_format=vtt', 'stream_client.py'):
226+
assert marker in smoke
227+
assert any('/health' in command for command in entry['commands']['health'])
228+
assert any('/v1/models' in command for command in entry['commands']['health'])
229+
evidence_urls = {item['url'] for item in entry['evidence']}
230+
assert 'https://github.com/QwenAudio/SenseVoice/pull/341' in evidence_urls
231+
assert 'https://github.com/QwenAudio/SenseVoice/actions/runs/31633730096' in evidence_urls
232+
limitation = entry['translations']['en']['primary_limitation'].lower()
233+
assert 'linux' in limitation
234+
assert 'authentication' in limitation
235+
236+
188237
def test_download_assets_require_https_and_sha256(valid_registry):
189238
data = copy.deepcopy(valid_registry)
190239
entry = next(item for item in data['deployments'] if item['id'] == 'llama-cpp')

web-pages/product-site/tests/test_selector.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def entries():
2323
[
2424
('batch', 'nvidia-gpu', 'throughput', 'vllm'),
2525
('edge', 'cpu', 'portability', 'llama-cpp'),
26+
('realtime', 'cpu', 'compatibility', 'sensevoice-native-server'),
2627
('private-api', 'kubernetes', 'compatibility', 'containers'),
2728
('realtime', 'nvidia-gpu', 'latency', 'realtime'),
2829
],

0 commit comments

Comments
 (0)