Skip to content

Commit e327ade

Browse files
authored
Merge pull request #3233 from modelscope/codex/llamacpp-download-variant
fix(llama.cpp): download one GGUF variant by default
2 parents 5990412 + 916c175 commit e327ade

5 files changed

Lines changed: 209 additions & 19 deletions

File tree

.github/workflows/build-llamacpp-binaries.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ jobs:
129129
env:
130130
GH_TOKEN: ${{ github.token }}
131131
run: |
132-
gh release create "${{ github.ref_name }}" dist/* \
132+
tag="${{ github.ref_name }}"
133+
version="${tag#runtime-llamacpp-}"
134+
docs="https://github.com/${{ github.repository }}/blob/$tag/runtime/llama.cpp/README.md"
135+
gh release create "$tag" dist/* \
133136
--repo "${{ github.repository }}" \
134-
--title "FunASR llama.cpp runtime ${{ github.ref_name }}" \
135-
--notes "Prebuilt self-contained binaries for the FunASR llama.cpp / GGUF runtimeSenseVoice, Paraformer and Fun-ASR-Nano with built-in FSMN-VAD (a whisper.cpp-style on-device ASR, strong on Chinese). Get a model with \`bash download-funasr-model.sh <sensevoice|paraformer|nano>\`, then run \`llama-funasr-cli\` / \`llama-funasr-sensevoice\` / \`llama-funasr-paraformer\`. Use the default x64 asset for maximum CPU compatibility; use the x64-avx2 asset on CPUs with AVX2/FMA/F16C/BMI2 for higher throughput. No Python, no build. Docs: runtime/llama.cpp/README.md"
137+
--title "FunASR llama.cpp runtime $version" \
138+
--notes "Prebuilt self-contained binaries for the FunASR llama.cpp / GGUF runtime: SenseVoice, Paraformer and Fun-ASR-Nano with built-in FSMN-VAD. Download the default quantized model with \`bash download-funasr-model.sh <sensevoice|paraformer|nano>\` (the helper requires the Hugging Face CLI: \`pip install -U huggingface_hub\`), then run \`llama-funasr-cli\` / \`llama-funasr-sensevoice\` / \`llama-funasr-paraformer\`. Use the default x64 asset for maximum CPU compatibility; use the x64-avx2 asset on CPUs with AVX2/FMA/F16C/BMI2 for higher throughput. No Python ASR runtime or local build is required. Docs: $docs"

runtime/llama.cpp/README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,28 @@ and the audio embeddings are injected into it via `llama_decode`'s embedding inp
2929
build/convert/run quickstart, validation numbers, and gotchas.
3030

3131
## Download pre-built GGUF (fastest — no Python ML env)
32+
33+
The helper requires the Hugging Face CLI (`pip install -U huggingface_hub`). By
34+
default it downloads one practical quantized variant plus FSMN-VAD, rather than
35+
every GGUF in the repository:
36+
3237
```bash
33-
./download-funasr-model.sh sensevoice # or: paraformer | nano | fsmn-vad
38+
./download-funasr-model.sh sensevoice # q8 (default) + FSMN-VAD
39+
./download-funasr-model.sh paraformer # q8 (default) + FSMN-VAD
40+
./download-funasr-model.sh nano # encoder-f16 + q8_0 (default) + FSMN-VAD
41+
./download-funasr-model.sh fsmn-vad # FSMN-VAD only
3442
```
43+
44+
Use the optional third argument to choose another variant. SenseVoice and
45+
Paraformer support `q8`, `f16`, `f32`, or `all`; Nano supports `q8_0`, `q4km`,
46+
`q5km`, or `all`. The optional second argument is the output directory:
47+
48+
```bash
49+
./download-funasr-model.sh sensevoice funasr-gguf f16
50+
./download-funasr-model.sh nano funasr-gguf q4km
51+
./download-funasr-model.sh paraformer funasr-gguf all # explicitly download every GGUF
52+
```
53+
3554
Pre-converted GGUF on Hugging Face: [SenseVoiceSmall-GGUF](https://huggingface.co/FunAudioLLM/SenseVoiceSmall-GGUF) · [Paraformer-GGUF](https://huggingface.co/FunAudioLLM/Paraformer-GGUF) · [Fun-ASR-Nano-GGUF](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-GGUF) · [fsmn-vad-GGUF](https://huggingface.co/FunAudioLLM/fsmn-vad-GGUF). Or convert yourself with `convert-funasr-to-gguf.py`.
3655

3756
## Build (standalone, CI-friendly)
Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,80 @@
11
#!/usr/bin/env bash
2-
# Download pre-converted FunASR GGUF models from Hugging Face — one command, no Python ML env.
3-
# ./download-funasr-model.sh sensevoice [outdir]
4-
# ./download-funasr-model.sh paraformer | nano | fsmn-vad
2+
# Download pre-converted FunASR GGUF models from Hugging Face in one command.
3+
# ./download-funasr-model.sh sensevoice [outdir] [q8|f16|f32|all]
4+
# ./download-funasr-model.sh paraformer [outdir] [q8|f16|f32|all]
5+
# ./download-funasr-model.sh nano [outdir] [q8_0|q4km|q5km|all]
6+
# ./download-funasr-model.sh fsmn-vad [outdir]
57
# ASR models also pull fsmn-vad.gguf (needed for built-in --vad long-audio segmentation).
68
set -euo pipefail
7-
usage(){ echo "usage: $0 {sensevoice|paraformer|nano|fsmn-vad} [outdir]"; exit 1; }
8-
[ $# -ge 1 ] || usage
9-
MODEL="$1"; OUT="${2:-funasr-gguf}"
9+
usage(){
10+
cat >&2 <<EOF
11+
usage: $0 {sensevoice|paraformer|nano|fsmn-vad} [outdir] [variant]
12+
sensevoice/paraformer variants: q8 (default), f16, f32, all
13+
nano variants: q8_0 (default), q4km, q5km, all
14+
EOF
15+
exit 1
16+
}
17+
[ $# -ge 1 ] && [ $# -le 3 ] || usage
18+
MODEL="$1"; OUT="${2:-funasr-gguf}"; VARIANT="${3:-}"
1019
case "$MODEL" in
11-
sensevoice) REPO="FunAudioLLM/SenseVoiceSmall-GGUF" ;;
12-
paraformer) REPO="FunAudioLLM/Paraformer-GGUF" ;;
13-
nano) REPO="FunAudioLLM/Fun-ASR-Nano-GGUF" ;;
14-
fsmn-vad|vad) REPO="FunAudioLLM/fsmn-vad-GGUF" ;;
20+
sensevoice)
21+
REPO="FunAudioLLM/SenseVoiceSmall-GGUF"
22+
case "${VARIANT:-q8}" in
23+
q8) FILES=(sensevoice-small-q8.gguf) ;;
24+
f16) FILES=(sensevoice-small-f16.gguf) ;;
25+
f32) FILES=(sensevoice-small.gguf) ;;
26+
all) FILES=() ;;
27+
*) usage ;;
28+
esac
29+
;;
30+
paraformer)
31+
REPO="FunAudioLLM/Paraformer-GGUF"
32+
case "${VARIANT:-q8}" in
33+
q8) FILES=(paraformer-q8.gguf) ;;
34+
f16) FILES=(paraformer-f16.gguf) ;;
35+
f32) FILES=(paraformer.gguf) ;;
36+
all) FILES=() ;;
37+
*) usage ;;
38+
esac
39+
;;
40+
nano)
41+
REPO="FunAudioLLM/Fun-ASR-Nano-GGUF"
42+
case "${VARIANT:-q8_0}" in
43+
q8|q8_0) FILES=(funasr-encoder-f16.gguf qwen3-0.6b-q8_0.gguf) ;;
44+
q4|q4km) FILES=(funasr-encoder-f16.gguf qwen3-0.6b-q4km.gguf) ;;
45+
q5|q5km) FILES=(funasr-encoder-f16.gguf qwen3-0.6b-q5km.gguf) ;;
46+
all) FILES=() ;;
47+
*) usage ;;
48+
esac
49+
;;
50+
fsmn-vad|vad)
51+
[ -z "$VARIANT" ] || usage
52+
REPO="FunAudioLLM/fsmn-vad-GGUF"
53+
FILES=(fsmn-vad.gguf)
54+
;;
1555
*) usage ;;
1656
esac
1757
# huggingface_hub ships `hf` (new CLI); older versions only have `huggingface-cli` (deprecated). Use whichever exists.
1858
if command -v hf >/dev/null 2>&1; then HF=hf
1959
elif command -v huggingface-cli >/dev/null 2>&1; then HF=huggingface-cli
20-
else echo "need the Hugging Face CLI: pip install -U huggingface_hub"; exit 1; fi
60+
else echo "error: need the Hugging Face CLI: pip install -U huggingface_hub" >&2; exit 1; fi
2161
mkdir -p "$OUT"
22-
echo "downloading $REPO ..."; "$HF" download "$REPO" --include "*.gguf" --local-dir "$OUT"
62+
echo "downloading $REPO ..."
63+
if [ ${#FILES[@]} -eq 0 ]; then
64+
"$HF" download "$REPO" --include "*.gguf" --local-dir "$OUT"
65+
else
66+
"$HF" download "$REPO" "${FILES[@]}" --local-dir "$OUT"
67+
fi
2368
if [ "$MODEL" != "fsmn-vad" ] && [ "$MODEL" != "vad" ]; then
24-
echo "downloading FSMN-VAD (for --vad) ..."; "$HF" download FunAudioLLM/fsmn-vad-GGUF --include "*.gguf" --local-dir "$OUT"
69+
echo "downloading FSMN-VAD (for --vad) ..."
70+
"$HF" download FunAudioLLM/fsmn-vad-GGUF fsmn-vad.gguf --local-dir "$OUT"
71+
fi
72+
shopt -s nullglob
73+
GGUF_FILES=("$OUT"/*.gguf)
74+
shopt -u nullglob
75+
if [ ${#GGUF_FILES[@]} -eq 0 ]; then
76+
echo "error: no GGUF files found in $OUT" >&2
77+
exit 1
2578
fi
26-
echo "done -> $OUT"; ls -1 "$OUT"/*.gguf
79+
echo "done -> $OUT"
80+
printf '%s\n' "${GGUF_FILES[@]}"

runtime/llama.cpp/tests/run_regression.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ ensure_models(){ local key="$1"; shift
2424
local missing=0; for f in "$@"; do [ -f "$MODELS/$f" ] || missing=1; done
2525
[ "$missing" = 0 ] && return 0
2626
{ [ "$key" = fsmn-vad ] || [ "$RUN_FULL" = 1 ]; } || return 1 # only auto-fetch the tiny VAD unless RUN_FULL
27-
"$RT/download-funasr-model.sh" "$key" "$MODELS" >/dev/null 2>&1 || return 1
27+
local args=("$key" "$MODELS")
28+
case "$key" in
29+
sensevoice|paraformer) args+=(f16) ;;
30+
nano) args+=(q8_0) ;;
31+
esac
32+
"$RT/download-funasr-model.sh" "${args[@]}" >/dev/null 2>&1 || return 1
2833
for f in "$@"; do [ -f "$MODELS/$f" ] || return 1; done; return 0
2934
}
3035
check(){ local name="$1" golden="$2" got="$3"
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
5+
SCRIPT="$ROOT/download-funasr-model.sh"
6+
TMP=$(mktemp -d)
7+
trap 'rm -rf "$TMP"' EXIT
8+
9+
mkdir -p "$TMP/bin"
10+
cat >"$TMP/bin/hf" <<'EOF'
11+
#!/usr/bin/env bash
12+
set -euo pipefail
13+
14+
printf '%s\n' "$*" >>"$HF_LOG"
15+
16+
if [[ "${HF_SKIP_CREATE:-0}" == 1 ]]; then
17+
exit 0
18+
fi
19+
20+
out=
21+
args=("$@")
22+
for ((i = 0; i < ${#args[@]}; i++)); do
23+
if [[ "${args[$i]}" == "--local-dir" ]]; then
24+
out="${args[$((i + 1))]}"
25+
break
26+
fi
27+
done
28+
29+
[[ -n "$out" ]]
30+
mkdir -p "$out"
31+
for arg in "${args[@]}"; do
32+
case "$arg" in
33+
'*.gguf') : >"$out/all.gguf" ;;
34+
*.gguf) : >"$out/$arg" ;;
35+
esac
36+
done
37+
EOF
38+
chmod +x "$TMP/bin/hf"
39+
40+
export PATH="$TMP/bin:$PATH"
41+
export HF_LOG="$TMP/hf.log"
42+
43+
reset_case() {
44+
: >"$HF_LOG"
45+
rm -rf "$TMP/out"
46+
}
47+
48+
assert_log() {
49+
grep -F -- "$1" "$HF_LOG" >/dev/null
50+
}
51+
52+
assert_no_log() {
53+
if grep -F -- "$1" "$HF_LOG" >/dev/null; then
54+
printf 'unexpected log entry: %s\n' "$1" >&2
55+
cat "$HF_LOG" >&2
56+
exit 1
57+
fi
58+
}
59+
60+
reset_case
61+
bash "$SCRIPT" sensevoice "$TMP/out" >/dev/null
62+
assert_log "download FunAudioLLM/SenseVoiceSmall-GGUF sensevoice-small-q8.gguf --local-dir $TMP/out"
63+
assert_log "download FunAudioLLM/fsmn-vad-GGUF fsmn-vad.gguf --local-dir $TMP/out"
64+
assert_no_log "--include *.gguf"
65+
66+
reset_case
67+
bash "$SCRIPT" paraformer "$TMP/out" f16 >/dev/null
68+
assert_log "download FunAudioLLM/Paraformer-GGUF paraformer-f16.gguf --local-dir $TMP/out"
69+
70+
reset_case
71+
bash "$SCRIPT" nano "$TMP/out" >/dev/null
72+
assert_log "download FunAudioLLM/Fun-ASR-Nano-GGUF funasr-encoder-f16.gguf qwen3-0.6b-q8_0.gguf --local-dir $TMP/out"
73+
74+
reset_case
75+
bash "$SCRIPT" nano "$TMP/out" q4km >/dev/null
76+
assert_log "download FunAudioLLM/Fun-ASR-Nano-GGUF funasr-encoder-f16.gguf qwen3-0.6b-q4km.gguf --local-dir $TMP/out"
77+
78+
reset_case
79+
bash "$SCRIPT" sensevoice "$TMP/out" all >/dev/null
80+
assert_log "download FunAudioLLM/SenseVoiceSmall-GGUF --include *.gguf --local-dir $TMP/out"
81+
82+
reset_case
83+
bash "$SCRIPT" fsmn-vad "$TMP/out" >/dev/null
84+
assert_log "download FunAudioLLM/fsmn-vad-GGUF fsmn-vad.gguf --local-dir $TMP/out"
85+
[[ $(wc -l <"$HF_LOG") -eq 1 ]]
86+
87+
reset_case
88+
if bash "$SCRIPT" sensevoice "$TMP/out" q4km >/dev/null 2>&1; then
89+
echo "sensevoice accepted an unsupported q4km variant" >&2
90+
exit 1
91+
fi
92+
[[ ! -s "$HF_LOG" ]]
93+
94+
mkdir -p "$TMP/empty-bin"
95+
if PATH="$TMP/empty-bin" /bin/bash "$SCRIPT" sensevoice "$TMP/out" >"$TMP/stdout" 2>"$TMP/stderr"; then
96+
echo "download succeeded without a Hugging Face CLI" >&2
97+
exit 1
98+
fi
99+
[[ ! -s "$TMP/stdout" ]]
100+
grep -F "need the Hugging Face CLI" "$TMP/stderr" >/dev/null
101+
102+
reset_case
103+
if HF_SKIP_CREATE=1 bash "$SCRIPT" sensevoice "$TMP/out" >"$TMP/stdout" 2>"$TMP/stderr"; then
104+
echo "download succeeded without producing a GGUF file" >&2
105+
exit 1
106+
fi
107+
grep -F "no GGUF files found in $TMP/out" "$TMP/stderr" >/dev/null
108+
109+
echo "download-funasr-model contract tests passed"

0 commit comments

Comments
 (0)