yoelngl/funasr
FunASR Chinese STT Microservice
Mandarin speech-to-text backend for chatbots. paraformer-zh (ASR) + fsmn-vad (voice activity detection / segmentation) + ct-punc (punctuation restoration), served over FastAPI, with a small Gradio demo UI mounted at /ui (Docker SDK is gated behind HF PRO now, so this deploys on the free Gradio SDK instead — app.py runs its own FastAPI app under uvicorn, gr.mount_gradio_app just bolts the demo UI onto it).
API
GET /
Health check. Returns {"status": "ok"}.
GET /ui
Gradio demo — upload/record audio, see the transcript.
POST /asr
multipart/form-data, field name file. Accepts .wav, .mp3, .m4a, .ogg (converted to 16kHz mono wav via ffmpeg before inference). Max 25MB.
Response:
{ "text": "你好,今天天气怎么样?", "duration_sec": 3.42 }Errors return JSON {"detail": "..."} with the matching HTTP status (400 bad/empty/unsupported audio, 413 too large, 504 inference timeout, 500 unexpected).
Notes
- Gradio SDK has no build-time hook, so models download on first process start instead of being baked into an image layer (that only worked on Docker SDK).
download_models.py/Dockerfileare kept in this repo for if you ever upgrade to PRO and switch back to Docker SDK — unused by the current Gradio SDK deploy. - Hardware: ZeroGPU (free, shared H200 slices). ZeroGPU only attaches a real GPU for the duration of an
@spaces.GPU-decorated call, so the model is loaded lazily on the first/asrrequest instead of at import time — there's no CUDA device visible in the base process.torch/torchaudioare pinned to2.11.0per HF's supported-versions list for ZeroGPU (plain+cpuwheels aren't valid here). If FunASR's device handling turns out not to play well with ZeroGPU's per-call GPU attach/detach, fall back to Settings → Space hardware → CPU basic and repin torch to a+cpuwheel. - Single uvicorn worker + an
asyncio.Semaphore(1)serialize inference requests; a 45s timeout guard prevents one bad file from hanging the worker. - Free Spaces sleep after ~48h idle.
.github/workflows/keep-alive.ymlpingsGET /every 25 minutes to keep it warm — set theSPACE_URLrepo variable/secret to your Space's URL. In practice this means the Space never sleeps, so the runtime model download only happens once per deploy/restart, not on every cold wake. packages.txtinstalls ffmpeg (apt),requirements.txtinstalls the Python deps — this replaces what the Dockerfile did for Docker SDK.
