diff --git a/README.md b/README.md index 161ad77d70..d1f1299ede 100644 --- a/README.md +++ b/README.md @@ -357,7 +357,7 @@ recordings with the same evaluation scope. - **MOSS-Transcribe-Diarize** brings long-form ASR, timestamps, and anonymous speaker labels to FunASR services, Docker, Kubernetes, vLLM/SGLang workflows, and FunClip. [Deploy MOSS ->](./docs/moss_transcribe_diarize.md) - **FunASR 1.4.15** adds tested NumPy 2 compatibility and fixes streaming KWS/VAD boundaries and checkpoint ranking. Install with `python -m pip install -U "funasr==1.4.15"`. [Release and verification scope ->](https://github.com/modelscope/FunASR/releases/tag/v1.4.15) -- **Production deployment** now includes faster, more resilient realtime serving and verified llama.cpp archives for ten Linux, macOS, and Windows targets. [GPU services ->](./docs/vllm_guide.md) · [CPU/edge packages ->](https://www.funasr.com/en/deploy/llama-cpp.html) +- **Native Transformers:** Fun-ASR-Nano [merged upstream](https://github.com/huggingface/transformers/pull/46180). Use the official `-hf` checkpoint and pinned source; stable 5.16.1 does not include it. [Installation and inference ->](./docs/transformers_native.md) > See [GitHub Releases](https://github.com/modelscope/FunASR/releases) for the complete changelog and downloadable assets. diff --git a/README_ja.md b/README_ja.md index 6077868a2b..ed65e1f79b 100644 --- a/README_ja.md +++ b/README_ja.md @@ -105,7 +105,7 @@ CER/WER をそろえて比較してください。オフラインのスループ - **MOSS-Transcribe-Diarize** を FunASR service、Docker、Kubernetes、vLLM/SGLang workflow、FunClip に統合し、長時間 ASR、timestamp、匿名 speaker label を一度に処理できます。[MOSS をデプロイ ->](./docs/moss_transcribe_diarize.md) - **FunASR 1.4.15** はテスト済みの NumPy 2 互換性を追加し、ストリーミング KWS/VAD の境界処理と checkpoint の順位付けを修正します。`python -m pip install -U "funasr==1.4.15"`。[リリースと検証範囲 ->](https://github.com/modelscope/FunASR/releases/tag/v1.4.15) -- **Production deployment** に、より高速で安定した realtime serving と、Linux、macOS、Windows の 10 target 向け llama.cpp package を追加しました。[GPU service ->](./docs/vllm_guide.md) · [CPU / edge package ->](https://www.funasr.com/en/deploy/llama-cpp.html) · [v0.2.6 binaries ->](https://github.com/modelscope/FunASR/releases/tag/runtime-llamacpp-v0.2.6) +- **ネイティブ Transformers:** Fun-ASR-Nano が[上流にマージ](https://github.com/huggingface/transformers/pull/46180)されました。公式 `-hf` checkpoint と固定ソースを使用します。安定版 5.16.1 には未収録です。[導入ガイド(英語) ->](./docs/transformers_native.md) > 完全な変更履歴と download asset は [GitHub Releases](https://github.com/modelscope/FunASR/releases) を参照してください。 diff --git a/README_ko.md b/README_ko.md index a6c01f3969..4005ab2e5f 100644 --- a/README_ko.md +++ b/README_ko.md @@ -104,7 +104,7 @@ checkpoint/revision, 오디오 집합, 하드웨어, 배치, 워밍업, 측정 - **MOSS-Transcribe-Diarize**를 FunASR service, Docker, Kubernetes, vLLM/SGLang workflow, FunClip에 통합해 긴 오디오 ASR, timestamp, 익명 speaker label을 한 번에 처리합니다. [MOSS 배포 ->](./docs/moss_transcribe_diarize.md) - **FunASR 1.4.15**는 테스트를 거친 NumPy 2 호환성을 추가하고 스트리밍 KWS/VAD 경계 처리와 checkpoint 순위 산정을 수정합니다. `python -m pip install -U "funasr==1.4.15"`. [릴리스 및 검증 범위 ->](https://github.com/modelscope/FunASR/releases/tag/v1.4.15) -- **Production deployment**에 더 빠르고 안정적인 realtime serving과 Linux, macOS, Windows 10개 target용 llama.cpp package를 추가했습니다. [GPU service ->](./docs/vllm_guide.md) · [CPU / edge package ->](https://www.funasr.com/en/deploy/llama-cpp.html) · [v0.2.6 binaries ->](https://github.com/modelscope/FunASR/releases/tag/runtime-llamacpp-v0.2.6) +- **네이티브 Transformers:** Fun-ASR-Nano가 [업스트림에 병합](https://github.com/huggingface/transformers/pull/46180)되었습니다. 공식 `-hf` checkpoint와 고정 소스를 사용하세요. 안정 버전 5.16.1에는 아직 포함되지 않았습니다. [설치 가이드(영문) ->](./docs/transformers_native.md) > 전체 변경 기록과 download asset은 [GitHub Releases](https://github.com/modelscope/FunASR/releases)에서 확인할 수 있습니다. diff --git a/README_zh.md b/README_zh.md index 27b52905e2..cab445800b 100644 --- a/README_zh.md +++ b/README_zh.md @@ -150,7 +150,7 @@ checkpoint/revision、音频集、硬件、批量大小、预热、计时范围 - **MOSS-Transcribe-Diarize** 已接入 FunASR 服务、Docker、Kubernetes、vLLM/SGLang 工作流和 FunClip,一次完成长音频转写、时间戳与匿名说话人标注。[部署 MOSS ->](./docs/moss_transcribe_diarize_zh.md) - **FunASR 1.4.15** 新增经过测试的 NumPy 2 兼容支持,修复流式 KWS/VAD 边界处理和 checkpoint 排序。升级命令:`python -m pip install -U "funasr==1.4.15"`。[发布说明与验证范围 ->](https://github.com/modelscope/FunASR/releases/tag/v1.4.15) -- **工业部署** 新增更快、更稳定的实时服务,以及覆盖 Linux、macOS、Windows 十种目标的 llama.cpp 预编译包。[GPU 服务 ->](./docs/vllm_guide_zh.md) · [CPU/端侧包 ->](https://www.funasr.com/deploy/llama-cpp.html) +- **原生 Transformers:** Fun-ASR-Nano [已合入上游](https://github.com/huggingface/transformers/pull/46180)。使用官方 `-hf` checkpoint 与固定源码;稳定版 5.16.1 尚未包含。[安装与推理 ->](./docs/transformers_native_zh.md) > 完整改动记录和可下载资产请查看 [GitHub Releases](https://github.com/modelscope/FunASR/releases)。 diff --git a/docs/README.md b/docs/README.md index 7780bd9698..2280afec0f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,6 +12,7 @@ | Install and check the Python environment | [Installation](installation/installation.md) / [中文](installation/installation_zh.md) | | Choose a model, language, or timestamp capability | [Model selection](model_selection.md) / [中文](model_selection_zh.md) | | Run the first transcription | [Quickstart](tutorial/README.md) / [中文](tutorial/README_zh.md) / [CLI](cli.md) | +| Use native Hugging Face Transformers APIs | [Fun-ASR-Nano native guide](transformers_native.md) / [中文](transformers_native_zh.md) | | Configure AutoModel, generate, and streaming cache | [Python SDK](python_api.md) / [中文](python_api_zh.md) | | Move from Whisper or a cloud API | [Migration](migration_from_whisper.md) / [中文](migration_from_whisper_zh.md) | diff --git a/docs/deployment_matrix.md b/docs/deployment_matrix.md index f69bef1f7c..4aa7810e40 100644 --- a/docs/deployment_matrix.md +++ b/docs/deployment_matrix.md @@ -6,6 +6,7 @@ Use this page to choose the shortest deployment path for a product, demo, benchm | Path | Best for | Start here | Operational notes | |---|---|---|---| +| Native Transformers | Python applications using Hugging Face processors and generation | [Native Fun-ASR-Nano guide](./transformers_native.md) | Official `-hf` checkpoint and pinned source; stable 5.16.1 lacks support at the 2026-09-09 check. Python inference, not an HTTP or realtime server. | | Colab notebook | Browser smoke tests, first evaluation, shareable demos | [Colab quickstart](../examples/colab/) | No local setup; first run downloads model files, GPU runtime is faster. | | Python API | Notebooks, offline jobs, first model evaluation | [README quick start](../README.md#quick-start) | Lowest ceremony; caller owns batching, retries, and files. | | OpenAI-compatible API | Private speech API, agents, Dify/LangChain/AutoGen-style clients | [OpenAI API example](../examples/openai_api/) | Easiest integration for apps that already support OpenAI audio APIs. | diff --git a/docs/deployment_matrix_zh.md b/docs/deployment_matrix_zh.md index 0cd126cbe1..b4468a8816 100644 --- a/docs/deployment_matrix_zh.md +++ b/docs/deployment_matrix_zh.md @@ -6,6 +6,7 @@ | 路径 | 适合场景 | 从这里开始 | 运维提示 | |---|---|---|---| +| 原生 Transformers | 已使用 Hugging Face 处理器与生成接口的 Python 应用 | [原生 Fun-ASR-Nano 指南](./transformers_native_zh.md) | 官方 `-hf` checkpoint 与固定源码;2026-09-09 核验的稳定版 5.16.1 尚未包含。是 Python 推理入口,不是 HTTP 或实时服务器。 | | Colab Notebook | 浏览器 smoke test、首次评估、可分享 demo | [Colab 快速体验](../examples/colab/README_zh.md) | 不需要本地环境;首次运行会下载模型,GPU runtime 更快。 | | Python API | Notebook、离线任务、首次模型评测 | [README 快速开始](../README_zh.md#快速开始) | 最简单;调用方自己负责批处理、重试和文件管理。 | | OpenAI 兼容 API | 私有语音 API、Agent、Dify/LangChain/AutoGen 风格客户端 | [OpenAI API 示例](../examples/openai_api/README_zh.md) | 已支持 OpenAI audio API 的应用最容易接入。 | diff --git a/docs/transformers_native.md b/docs/transformers_native.md new file mode 100644 index 0000000000..3415b62554 --- /dev/null +++ b/docs/transformers_native.md @@ -0,0 +1,208 @@ +# Fun-ASR-Nano with native Transformers + +[简体中文](./transformers_native_zh.md) | English + +Use this path when your Python application already works with Hugging Face +processors and generation APIs. It runs Fun-ASR-Nano through native Transformers +classes, without the FunASR toolkit or checkpoint-provided remote Python code. +For a managed HTTP service, start with the [deployment matrix](./deployment_matrix.md); +this guide does not add an OpenAI endpoint, request queue or realtime server. + +## What was merged, and what was released? + +On **2026-09-09**, [Transformers PR #46180](https://github.com/huggingface/transformers/pull/46180) +was merged as `fc501343edfccdc840eb8594a6cafa8185c2de53`. +At verification time that day, the latest stable **5.16.1 did not contain this +model**: both its release tag and actual wheel were inspected. A merge is not +a stable release. The source build identifies itself as `5.17.0.dev0`; that is +not a promised release version or date. Pin the tested source below, or check +that a later released package really contains `fun_asr_nano` before migrating. + +## Choose the checkpoint and the interface together + +| Path | Checkpoint | Entry point | +| --- | --- | --- | +| FunASR toolkit | `FunAudioLLM/Fun-ASR-Nano-2512` | `funasr.AutoModel`; separate documented split-engine path | +| Native Transformers | `FunAudioLLM/Fun-ASR-Nano-2512-hf` | `AutoProcessor` + `AutoModelForSpeechSeq2Seq` | +| Native vLLM | `FunAudioLLM/Fun-ASR-Nano-2512-vllm` | [Official native vLLM guide](./vllm_official_native_validation.md) | +| Native C++ | Converted GGUF files for the chosen runtime | [llama.cpp guide](../runtime/llama.cpp/README.md) | + +These are different artifacts and API contracts. Renaming a model ID or passing +`backend="vllm"` does not convert weights. Native Transformers support does not +make the `-hf` checkpoint a vLLM, GGUF or FunASR HTTP-server checkpoint. + +The official [native HF checkpoint](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512-hf/tree/d93b302ee7fd505e1b3576120fc142fc6f7820e1) +is public and ungated at revision `d93b302ee7fd505e1b3576120fc142fc6f7820e1`. +Its configuration maps to `FunAsrNanoForConditionalGeneration`. Its feature +extractor is embedded in `processor_config.json`; a separate +`preprocessor_config.json` is not required for this snapshot. + +## Independent CPU environment + +Use a new directory for the virtual environment; do not upgrade an existing +FunASR or vLLM service environment in place. The following is **Linux x86-64, +Python 3.12, CPU-only**, not a CUDA or macOS installation recipe. + +```bash +python3.12 -m venv .venv-funasr-native +. .venv-funasr-native/bin/activate +python -m pip install --index-url https://download.pytorch.org/whl/cpu \ + 'torch==2.10.0+cpu' 'torchaudio==2.10.0+cpu' +python -m pip install 'numpy==1.26.4' 'librosa==0.11.0' 'soundfile==0.13.1' \ + 'huggingface-hub==1.30.0' 'tokenizers==0.23.2' \ + 'https://github.com/huggingface/transformers/archive/fc501343edfccdc840eb8594a6cafa8185c2de53.zip' +python -m pip check +``` + +The verification environment installed a wheel built from the exact source +commit above. Matching **torch and torchaudio** are required for this native +feature extractor: it calls `torchaudio.compliance.kaldi.fbank`. The toolkit's +optional audio dependencies do not imply that torchaudio is optional here. +Older prepared environments failed dependency gates; do not disable those gates +or mix incompatible Hub/tokenizers versions to get an import to succeed. +This is a tested environment, not a complete lock of every transitive dependency; +record `python -m pip freeze`, platform details and model revision in your own run. + +## Check preprocessing without loading weights + +This downloads the public configuration, tokenizer and chat template, **not +model weights**. One second of synthetic silence checks the entry point; it is +not a speech-recognition quality test. + + +```python +import numpy as np +from transformers import AutoProcessor + +model_id = "FunAudioLLM/Fun-ASR-Nano-2512-hf" +revision = "d93b302ee7fd505e1b3576120fc142fc6f7820e1" +processor = AutoProcessor.from_pretrained( + model_id, revision=revision, trust_remote_code=False, token=False +) +inputs = processor.apply_transcription_request( + audio=np.zeros(16000, dtype=np.float32), + language="en", + processor_kwargs={ + "return_tensors": "pt", + "audio_kwargs": {"sampling_rate": 16000}, + }, +) +print({name: tuple(value.shape) for name, value in inputs.items()}) +``` + +In the verified environment the text tensors have shape `(1, 42)`, audio features +`(1, 17, 560)`, and feature mask `(1, 17)`. There are 17 audio placeholder tokens +and 17 valid feature frames. These shapes depend on input length and template; +do not hard-code them for real recordings. + +## Transcribe one recording + +Prepare a non-empty **mono 16 kHz WAV** named `audio.wav` in your working directory. +The code deliberately rejects a different sample rate or channel layout rather +than silently assigning 16 kHz to arbitrary samples. Resample/downmix with an +explicit policy before this step and preserve the original recording for review. + +The first model load downloads the weights unless the pinned snapshot is already +cached. It needs substantially more memory and time than preprocessing. This +example uses CPU float32 explicitly; GPU placement, mixed precision, attention +backends and service concurrency need separate validation. + + +```python +import soundfile as sf +import torch +from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor + +model_id = "FunAudioLLM/Fun-ASR-Nano-2512-hf" +revision = "d93b302ee7fd505e1b3576120fc142fc6f7820e1" +audio, sample_rate = sf.read("audio.wav", dtype="float32") +if sample_rate != 16000 or audio.ndim != 1 or audio.size == 0: + raise ValueError("Use a non-empty mono 16 kHz WAV file") + +processor = AutoProcessor.from_pretrained( + model_id, revision=revision, trust_remote_code=False, token=False +) +model = AutoModelForSpeechSeq2Seq.from_pretrained( + model_id, revision=revision, trust_remote_code=False, token=False, + dtype=torch.float32, +).to("cpu").eval() +inputs = processor.apply_transcription_request( + audio=audio, language="zh", + processor_kwargs={ + "return_tensors": "pt", + "audio_kwargs": {"sampling_rate": sample_rate}, + }, +) +with torch.inference_mode(): + generated = model.generate(**inputs, max_new_tokens=128, do_sample=False) +new_tokens = generated[:, inputs.input_ids.shape[1]:] +print(processor.batch_decode(new_tokens, skip_special_tokens=True)[0]) +``` + +`generated` includes the input prompt. Slice off `inputs.input_ids.shape[1]` +before decoding so prompt framing is not mistaken for recognized speech. +`max_new_tokens=128` bounds this short-file example; hitting the limit can +truncate output. A longer limit is not proof of complete coverage. +Use `language="en"` or `language="ja"` for the corresponding target language; +language selection is a transcription instruction, not a promise of translation. + +## Context, hotwords and batches + +`apply_transcription_request` accepts `prompt` for context and `keywords` for +hotwords. These are native processor arguments, not the toolkit's `hotword` +parameter or a vLLM HTTP field. The source API accepts one language for the batch +or a language list matching its length; per-recording prompt and nested keyword +lists must also match the batch. Keep the decoded results in input order. + +Do not infer quality gains from a template accepting a keyword. Evaluate names, +numbers and unusual terms against authorized, representative recordings. +Batch padding, memory use and generated-text correctness must be tested together +before turning a single-file example into a production batch worker. + +## Evidence and limits + +The documented single-recording recipe was also executed on the official Chinese +sample, followed by an English single recording, a Chinese keyword request and a +Chinese/English batch. All returned non-empty text and EOS before the 128-token +limit. These are functional checks on two short public samples, not a CER/WER or +capacity evaluation. CPU: Intel Xeon Platinum 8480+, float32, four Torch threads; +matching torch/torchaudio 2.10.0+cpu and librosa 0.11.0. Model weights were loaded +from a previously downloaded official cache whose SHA/size were rechecked. + +Samples came from the original model's +[fixed example directory](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512/tree/272c57b82523ada6fd87095e955f8e29100979ab/example), +not from an invented -hf example directory. The mono 48 kHz Chinese MP3 was +explicitly resampled with librosa's default soxr_hq and written as float32 16 kHz +WAV before running the unmodified recipe. Its raw text was +`开饭时间早上九点至下午五点。`; adding the candidate keyword `开放时间` did not force that +spelling into the output. A keyword is a hint, not an enforced vocabulary. + +Synthetic processor tests exercised language aliases, context/keyword lists and +two-length batches. The empty-list case still raises an upstream `IndexError` +before its intended validation; reject empty batches in your application. +The guide's explicit non-empty waveform check avoids that entry path. Successful +cases do not erase this observed limitation. Initial resampling also exposed the +old librosa 0.10.1 dependency on removed `pkg_resources`; the final environment +uses 0.11.0 and was retested. + +The 2026-09-09 isolated CPU verification passed package dependency checks, +native configuration/class resolution and synthetic preprocessing with the +pinned official revision. Installed configuration, modeling, processing and +feature-extraction files were byte-identical to the merged upstream source. +A preprocessing pass is **not an accuracy or capacity result**. It does not +establish word timestamps, diarization, realtime behavior, GPU compatibility, +or performance equivalence with vLLM. + +For anonymous speakers and segment timestamps, see the third-party OpenMOSS +[MOSS guide](./moss_transcribe_diarize.md); for other choices see the +[Model Zoo](../model_zoo/readme.md). Do not infer timestamp or identity support +from a model returning text. Preserve input hashes, versions, raw responses and +an authorized human review when assessing an application. Never attach private +recordings or credentials to a public issue. + +## Sources and next steps + +- [Merged implementation and usage documentation](https://github.com/huggingface/transformers/blob/fc501343edfccdc840eb8594a6cafa8185c2de53/docs/source/en/model_doc/fun_asr_nano.md). +- [Native processor](https://github.com/huggingface/transformers/blob/fc501343edfccdc840eb8594a6cafa8185c2de53/src/transformers/models/fun_asr_nano/processing_fun_asr_nano.py) and [audio feature extractor](https://github.com/huggingface/transformers/blob/fc501343edfccdc840eb8594a6cafa8185c2de53/src/transformers/models/fun_asr_nano/feature_extraction_fun_asr_nano.py). +- [Why the checkpoint suffix matters](https://www.funasr.com/en/blog/fun-asr-nano-transformers.html), an application-oriented walkthrough. +- [Fun-ASR model project](https://github.com/QwenAudio/Fun-ASR) and [FunASR toolkit](https://github.com/modelscope/FunASR). diff --git a/docs/transformers_native_zh.md b/docs/transformers_native_zh.md new file mode 100644 index 0000000000..0c06ac22d5 --- /dev/null +++ b/docs/transformers_native_zh.md @@ -0,0 +1,181 @@ +# 用原生 Transformers 接入 Fun-ASR-Nano + +简体中文 | [English](./transformers_native.md) + +如果 Python 应用已经使用 Hugging Face 的处理器和生成接口,可以选择这条路径。 +它通过 Transformers 原生类运行 Fun-ASR-Nano,不依赖 FunASR 工具包或 checkpoint +中的远程 Python 代码。需要 HTTP 服务时先看[部署矩阵](./deployment_matrix_zh.md): +本指南不会自动提供 OpenAI 接口、请求队列或实时服务器。 + +## 合入主线,不等于已经发布 + +**2026-09-09**,[Transformers PR #46180](https://github.com/huggingface/transformers/pull/46180) +合入提交 `fc501343edfccdc840eb8594a6cafa8185c2de53`。 +当天核验时,最新稳定版 **5.16.1 不包含这个模型**,其 tag 和实际 wheel 均已检查。 +源码构建显示 `5.17.0.dev0`,不代表下一稳定版的版本或发布日期承诺。 +请固定下方经过验证的源码提交;改用后续稳定版前,实际确认安装包包含 `fun_asr_nano`。 + +## 模型格式和接口一起选 + +| 路径 | Checkpoint | 入口 | +| --- | --- | --- | +| FunASR 工具包 | `FunAudioLLM/Fun-ASR-Nano-2512` | `funasr.AutoModel`;拆分引擎另见对应文档 | +| 原生 Transformers | `FunAudioLLM/Fun-ASR-Nano-2512-hf` | `AutoProcessor` + `AutoModelForSpeechSeq2Seq` | +| 原生 vLLM | `FunAudioLLM/Fun-ASR-Nano-2512-vllm` | [官方原生 vLLM 指南](./vllm_official_native_validation_zh.md) | +| 原生 C++ | 对应运行时转换后的 GGUF 文件 | [llama.cpp 指南](../runtime/llama.cpp/README.md) | + +这些产物及 API 契约不同。改模型 ID 的名字或传 `backend="vllm"` 不会转换权重; +原生 Transformers 支持不意味着 `-hf` 可以交给 vLLM、GGUF 运行时或 FunASR HTTP 服务。 + +官方[原生 HF checkpoint](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512-hf/tree/d93b302ee7fd505e1b3576120fc142fc6f7820e1) +在 revision `d93b302ee7fd505e1b3576120fc142fc6f7820e1` 公开且无需申请访问。 +配置映射到 `FunAsrNanoForConditionalGeneration`,特征提取器嵌在 +`processor_config.json` 中。此快照不需要另一个 `preprocessor_config.json`。 + +## 准备独立的 CPU 环境 + +使用新目录创建虚拟环境,不要直接升级正在运行的 FunASR/vLLM 服务环境。 +下面对应 **Linux x86-64、Python 3.12、仅 CPU**,不是 CUDA 或 macOS 安装方案。 + +```bash +python3.12 -m venv .venv-funasr-native +. .venv-funasr-native/bin/activate +python -m pip install --index-url https://download.pytorch.org/whl/cpu \ + 'torch==2.10.0+cpu' 'torchaudio==2.10.0+cpu' +python -m pip install 'numpy==1.26.4' 'librosa==0.11.0' 'soundfile==0.13.1' \ + 'huggingface-hub==1.30.0' 'tokenizers==0.23.2' \ + 'https://github.com/huggingface/transformers/archive/fc501343edfccdc840eb8594a6cafa8185c2de53.zip' +python -m pip check +``` + +验证环境安装的是从上述精确提交构建的 wheel。原生特征提取器调用 +`torchaudio.compliance.kaldi.fbank`,因此需要匹配的 **torch 和 torchaudio**。 +FunASR 工具包的可选音频依赖策略不能套用到这里。旧环境曾被过旧的 Hub/tokenizers +依赖挡住;不要关闭依赖检查或混搭版本来强行导入。 +这是经过验证的环境,不是所有传递依赖的完整锁文件;自己的运行还应记录 +`python -m pip freeze`、平台信息和模型 revision。 + +## 先验证预处理,不加载权重 + +这一步仅下载公开的配置、tokenizer 和聊天模板,**不下载模型权重**。 +一秒合成静音用来检查入口,不是识别质量测试。 + + +```python +import numpy as np +from transformers import AutoProcessor + +model_id = "FunAudioLLM/Fun-ASR-Nano-2512-hf" +revision = "d93b302ee7fd505e1b3576120fc142fc6f7820e1" +processor = AutoProcessor.from_pretrained( + model_id, revision=revision, trust_remote_code=False, token=False +) +inputs = processor.apply_transcription_request( + audio=np.zeros(16000, dtype=np.float32), + language="en", + processor_kwargs={ + "return_tensors": "pt", + "audio_kwargs": {"sampling_rate": 16000}, + }, +) +print({name: tuple(value.shape) for name, value in inputs.items()}) +``` + +验证环境中文字张量形状是 `(1, 42)`,音频特征是 `(1, 17, 560)`, +特征 mask 是 `(1, 17)`;17 个音频占位 token 与 17 帧有效特征对应。 +这些形状随输入时长和模板变化,不应在真实应用里写死。 + +## 转写一份录音 + +在工作目录准备非空、**单声道 16 kHz WAV** 文件 `audio.wav`。 +代码明确拒绝其他采样率或声道布局,而不是把任意采样直接标成 16 kHz。 +重采样和混音请使用明确的策略,在这一步之前完成,并保留原录音便于回听。 + +首次加载模型会下载权重,已有固定 revision 缓存时复用缓存。 +其内存和耗时明显高于仅预处理。下面显式使用 CPU float32; +GPU 放置、混合精度、attention 后端和服务并发需要分别验证。 + + +```python +import soundfile as sf +import torch +from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor + +model_id = "FunAudioLLM/Fun-ASR-Nano-2512-hf" +revision = "d93b302ee7fd505e1b3576120fc142fc6f7820e1" +audio, sample_rate = sf.read("audio.wav", dtype="float32") +if sample_rate != 16000 or audio.ndim != 1 or audio.size == 0: + raise ValueError("Use a non-empty mono 16 kHz WAV file") + +processor = AutoProcessor.from_pretrained( + model_id, revision=revision, trust_remote_code=False, token=False +) +model = AutoModelForSpeechSeq2Seq.from_pretrained( + model_id, revision=revision, trust_remote_code=False, token=False, + dtype=torch.float32, +).to("cpu").eval() +inputs = processor.apply_transcription_request( + audio=audio, language="zh", + processor_kwargs={ + "return_tensors": "pt", + "audio_kwargs": {"sampling_rate": sample_rate}, + }, +) +with torch.inference_mode(): + generated = model.generate(**inputs, max_new_tokens=128, do_sample=False) +new_tokens = generated[:, inputs.input_ids.shape[1]:] +print(processor.batch_decode(new_tokens, skip_special_tokens=True)[0]) +``` + +`generated` 包含输入 prompt。解码前去掉 `inputs.input_ids.shape[1]`, +避免把提示模板当作识别结果。`max_new_tokens=128` 限定这份短文件示例的生成上限; +触顶可能截断输出,调大也不保证整段覆盖。对应语言可改为 `language="en"` 或 +`language="ja"`;这里是转写语言指令,不是翻译能力承诺。 + +## 上下文、热词和批处理 + +`apply_transcription_request` 使用 `prompt` 传上下文、`keywords` 传热词, +不是工具包的 `hotword` 参数或 vLLM HTTP 字段。源码 API 接受全批统一语言, +或与批大小一致的语言列表;逐录音的 prompt 和嵌套关键词列表也必须与批大小匹配。 +结果应保持输入顺序。 + +模板接收了关键词,不等于识别更准确。应在获授权且有代表性的录音中检查专名、 +数字和生僻词。把单文件示例变成生产批处理之前,应一起测试 padding、内存和生成文本, +而不是只检查请求张量的形状。 + +## 验证范围与边界 + +本指南的单录音代码还实际运行了官方中文样本,随后测试了英文单录音、中文关键词请求及 +中英混合批量。各请求均返回非空文本,并在 128 token 上限之前生成 EOS。 +这只是两份公开短样本的功能检查,不是 CER/WER 或容量评测。 +CPU 为 Intel Xeon Platinum 8480+,float32、Torch 四线程;torch/torchaudio +2.10.0+cpu、librosa 0.11.0。模型来自先前下载的官方缓存,本轮重新检查了 SHA 和文件大小。 + +样本来自原始模型的[固定 example 目录](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512/tree/272c57b82523ada6fd87095e955f8e29100979ab/example), +不是假定存在的 -hf 示例目录。中文源文件是单声道 48 kHz MP3,先用 librosa 默认的 +soxr_hq 明确重采样,再写成 float32 16 kHz WAV,运行未改写的指南代码。 +原始文本为 `开饭时间早上九点至下午五点。`;传入候选关键词 `开放时间` 也没有强制产生该词形。 +热词是提示,不是强制词表约束。 + +合成处理器测试覆盖了语言别名、上下文/关键词列表和不同长度的批量输入。 +空列表仍会在上游预期校验前抛 `IndexError`,应用应提前拒绝空批量;指南已显式拒绝空波形, +不经过这一路径。成功用例不能抹去这个限制。最初的重采样也暴露出 librosa 0.10.1 +依赖已移除的 `pkg_resources`;最终环境使用 0.11.0 并重新验证。 + +2026-09-09 的独立 CPU 验证通过依赖检查、原生配置/类解析和固定官方 revision 的合成预处理。 +已安装的配置、模型、处理器、特征提取器源码逐字节匹配上游合并提交。 +预处理通过**不代表准确率或容量结论**,也不证明字级时间戳、说话人分离、实时行为、 +GPU 兼容性或与 vLLM 的性能一致。 + +需要匿名说话人与段级时间戳时,参考第三方 OpenMOSS 的 +[MOSS 指南](./moss_transcribe_diarize_zh.md);其他路径见 +[Model Zoo](../model_zoo/readme_zh.md)。不能从“返回了文本”推导时间戳或身份识别能力。 +应用验收应保留输入散列、固定版本、原始输出和获授权的人工回听记录; +不要把私有录音或凭据附到公开 issue 中。 + +## 来源与下一步 + +- [合并后的实现与官方用法](https://github.com/huggingface/transformers/blob/fc501343edfccdc840eb8594a6cafa8185c2de53/docs/source/en/model_doc/fun_asr_nano.md)。 +- [原生处理器](https://github.com/huggingface/transformers/blob/fc501343edfccdc840eb8594a6cafa8185c2de53/src/transformers/models/fun_asr_nano/processing_fun_asr_nano.py)与[音频特征提取器](https://github.com/huggingface/transformers/blob/fc501343edfccdc840eb8594a6cafa8185c2de53/src/transformers/models/fun_asr_nano/feature_extraction_fun_asr_nano.py)。 +- [为什么 checkpoint 后缀重要](https://www.funasr.com/blog/fun-asr-nano-transformers.html):面向应用的专题解读。 +- [Fun-ASR 模型项目](https://github.com/QwenAudio/Fun-ASR)与[FunASR 工具包](https://github.com/modelscope/FunASR)。 diff --git a/model_zoo/readme.md b/model_zoo/readme.md index 3da96f4d7d..8c18140dc2 100644 --- a/model_zoo/readme.md +++ b/model_zoo/readme.md @@ -21,6 +21,16 @@ the [deployment matrix](../docs/deployment_matrix.md) for serving options. ## Model Usage +### Native Transformers checkpoint + +Use [FunAudioLLM/Fun-ASR-Nano-2512-hf](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512-hf) +with `AutoProcessor` and `AutoModelForSpeechSeq2Seq`, not the original toolkit, +native vLLM or GGUF loader. [Installation and inference](../docs/transformers_native.md) +pin the merged source and official revision. As checked on 2026-09-09, stable +Transformers 5.16.1 does not contain this native model. Matching torchaudio is required. + +### FunASR toolkit + Start with the [installation guide](../docs/installation/installation.md) and [Python tutorial](../docs/tutorial/README.md). Use an explicit hub and record the resolved checkpoint/revision, FunASR version, device and inference options. diff --git a/model_zoo/readme_zh.md b/model_zoo/readme_zh.md index 744f3114fa..6caaf8ec6a 100644 --- a/model_zoo/readme_zh.md +++ b/model_zoo/readme_zh.md @@ -20,6 +20,16 @@ ## 模型用法 +### 原生 Transformers checkpoint + +[FunAudioLLM/Fun-ASR-Nano-2512-hf](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512-hf) +使用 `AutoProcessor` 和 `AutoModelForSpeechSeq2Seq`,不是原始工具包、原生 vLLM 或 +GGUF 的加载路径。[安装与推理指南](../docs/transformers_native_zh.md)固定了上游提交和官方 +模型 revision。2026-09-09 核验的稳定版 Transformers 5.16.1 尚未包含该原生模型, +并且这条路径需要匹配的 torchaudio。 + +### FunASR 工具包 + 先完成[安装](../docs/installation/installation_zh.md)和 [Python 教程](../docs/tutorial/README_zh.md)。显式选择 hub,并记录实际下载的 checkpoint/revision、FunASR 版本、设备和推理选项。 diff --git a/web-pages/product-site/content/legacy-manifest.json b/web-pages/product-site/content/legacy-manifest.json index 2070a60b7c..2653b16c97 100644 --- a/web-pages/product-site/content/legacy-manifest.json +++ b/web-pages/product-site/content/legacy-manifest.json @@ -3,6 +3,9 @@ "source": "https://www.funasr.com/ public static corpus", "captured": "2026-07-26", "files": { + "blog/fun-asr-nano-transformers.html": "e9834f5d62f3d172abcbb9d9157e19bc0fed8ff0f68bc4e7030dd7b1e65fb0ff", + "en/blog/fun-asr-nano-transformers.html": "67fe99f396c537915828978c7b2a755360ed8bcb24b3eb082a743f41744e102f", + "img/fun-asr-nano-native-waveform.png": "930517464ffb47bc7f9051dbdcb5422e1b3daa5c6abaa455a8bf072359ae0f0b", "7ec404429c825fe9a9a030731bbca986.txt": "e0e4c945481cb03f52426d8420c3407ea18cd3b46cb2482590bd50e5aab117d2", "blog/cantonese-speech-recognition.html": "f4a674f2b8f15963a386d586bb79d62f9f75c20d704ca2eafba21a800f52d4df", "blog/chinese-speech-recognition.html": "a78eeb4e5ea38ce95ad05ebc54eceb0185d8dddd2286769b5ba1b7dd00e8b615", @@ -24,7 +27,7 @@ "blog/funclip-v2-1-0-video-clipping-release.html": "88f6c44e5332d1746c4db0fc97d755ef82f12e46d8f1c1c0ad9351152ff9dfc1", "blog/funclip-v2-2-0-moss-speaker-clipping.html": "0d50747d3992301fb3062ad2cdf903bd427bec3db1f1e4fab1f06de207928bc9", "blog/generate-subtitles-srt-vtt-from-audio-video.html": "f1133235673d441cc654310581f59a319f182314ab7c0b0824af87da9f4a0591", - "blog/index.html": "f966d5ad5c713a4180df05ff84216fd5ad65f831c57968b9feb7e3f4712bc136", + "blog/index.html": "bd04951ed11b340a6786c7b38a25beace6554f7269274c2d25d4228ebaaf2a0e", "blog/japanese-speech-recognition.html": "399f5ce84e68ac00854bdf70b52b1cde6795efca7c800fd6492035a37a7c1b68", "blog/lightweight-speech-recognition-cpu.html": "d6270066222ed5baef0df108e6a4155f4a87bb5482169f23f218794d371f3281", "blog/meeting-transcript-acceptance.html": "3e35d1f283c7005977ad8cbd079e38c51e14b51f04f50cedb5636e2d4baf38bd", @@ -66,7 +69,7 @@ "en/blog/funclip-v2-1-0-video-clipping-release.html": "229baf59adf2c3290541d9b3c8a6243992406ba84b712714e9d14599205cb1d4", "en/blog/funclip-v2-2-0-moss-speaker-clipping.html": "644159267f0fa4e7aab9d0eda98f68cd2b6365a9985038b639c626a5ea5ea7e8", "en/blog/generate-subtitles-srt-vtt-from-audio-video.html": "1530d4b9e94820a0b60d801e8d1c19b7aeb031b2f2b76c092657392e47706c6d", - "en/blog/index.html": "363b5b77b4702ed1f5d7f62fa2eeadb7e4bfa1a56b86ca9c22527d6c7666bec7", + "en/blog/index.html": "fe18072fb67da6b9cc274fa26b8dabc5854c426a9a38210bb2317219e8123900", "en/blog/japanese-speech-recognition.html": "c476adcc2be1ed7c19e2345cc91b8ee6a0e04efd794b9b6476dd5d9b3a2c8b04", "en/blog/lightweight-speech-recognition-cpu.html": "0e02c0e0853b12613d32c250f593c05c2052f18231207b63ee01d6e6600a86f7", "en/blog/meeting-transcript-acceptance.html": "3183682d2cae0ce18f68e3bd33e22b9effb4de699f6a4d821938cc03dd6835bf", @@ -85,7 +88,7 @@ "en/ecosystem.html": "f02ee516440dfc3757165df801fbf93b403b2ef1fdbee1a2dee26cd2a3ef9fa3", "en/index.html": "d86effc3bf4d218eabd465cbbe026f62c98dd50110ddd58251d9d271a64882a2", "en/llama-cpp.html": "dbfbd125ebbf07f7d923c91b122818f8b09484ce54c1e80eba66a89d22dfb5b4", - "en/models.html": "87ef70a357dcd430703c290eff4319d2b4ffefcde2f854d91bc250bbd29b9fa2", + "en/models.html": "5802ec4902b145d2ea398e172a07680cbef61188a3dc611f4d313db1dc12b1d8", "en/quickstart.html": "7453cd7d582079eb4082373bce6e5de26492458b73c41617bbb1bd4248bda6ac", "en/vs-whisper.html": "4833b93195957210436f791a9d8ebc726f0af93b809d740a5cee1e53de0ac390", "favicon.ico": "e5edd9f12088fa920b848485c62c72a093f27bfba7b6a46b4e7b63c34eb5126a", @@ -110,7 +113,7 @@ "lang-redirect.js": "e1189080a8e81eb76cf39e0538d0378b6631f5aa87e4679c0fd4fd34d1f6c197", "llama-cpp.html": "892b5c05e3375bcc7cd0af343b629f069d8ec4f372e6470cd830cdf2181a11d5", "logo.png": "ac0ff97f2b0203c3fad4ac5e90231d93e36d98cc8e90d383483de150b0dd0728", - "models.html": "01209193cd48363f00789061fbfad0a2b387582e2507ae5e875687773ef52fbc", + "models.html": "1e16794d389275a1ecca05bcc218a9c89311582aebcec7e62ec4b1ecd4379d40", "quickstart.html": "a543bf07c2cfc9a69ef3831f15c9e9d3e571a826a73cf7e4bdc8e9eb7b910254", "robots.txt": "1305b0f680b3e9f73b01301dc474423230dffab85731a379a694f30c73c07f2d", "sitemap.xml": "1fc88be1d337d7fac6acf0dd61e6b3416f6808f5d6e8fc0006fb9b15cba6e039", diff --git a/web-pages/product-site/data/documentation.json b/web-pages/product-site/data/documentation.json index e3f85fbbae..97c7a93ffd 100644 --- a/web-pages/product-site/data/documentation.json +++ b/web-pages/product-site/data/documentation.json @@ -15,6 +15,7 @@ {"id": "reference", "zh": "协议与参考", "en": "Protocols & reference"} ], "pages": [ + {"slug": "native-transformers", "group": "models", "zh": "Transformers 原生 Fun-ASR-Nano", "en": "Native Transformers Fun-ASR-Nano", "source_zh": "docs/transformers_native_zh.md", "source_en": "docs/transformers_native.md"}, {"slug": "installation", "group": "start", "zh": "安装与环境验证", "en": "Installation & environment checks", "source_zh": "docs/installation/installation_zh.md", "source_en": "docs/installation/installation.md"}, {"slug": "quickstart", "group": "start", "zh": "第一次转写", "en": "Your first transcription", "source_zh": "docs/tutorial/README_zh.md", "source_en": "docs/tutorial/README.md"}, {"slug": "python-api", "group": "start", "zh": "Python SDK: AutoModel", "en": "Python SDK: AutoModel", "source_zh": "docs/python_api_zh.md", "source_en": "docs/python_api.md"}, diff --git a/web-pages/product-site/export_docs.py b/web-pages/product-site/export_docs.py index ee6d597413..39a866fe05 100644 --- a/web-pages/product-site/export_docs.py +++ b/web-pages/product-site/export_docs.py @@ -14,6 +14,7 @@ ORIGIN = 'https://www.funasr.com' ALIASES = { + 'native-transformers': 'native-transformers.html', 'quickstart': 'tutorial.html', 'training': 'training.html', 'model-registration': 'model-registration.html', diff --git a/web-pages/product-site/legacy/blog/fun-asr-nano-transformers.html b/web-pages/product-site/legacy/blog/fun-asr-nano-transformers.html new file mode 100644 index 0000000000..5d5ae14f12 --- /dev/null +++ b/web-pages/product-site/legacy/blog/fun-asr-nano-transformers.html @@ -0,0 +1,57 @@ + + + +Fun-ASR-Nano + Transformers:先选对权重,再接入应用 | FunASR + + + + + + + +
+

Fun-ASR-Nano + Transformers:先选对权重,再接入应用

+

2026-09-09 · 生态技术与应用 · 阅读约 7 分钟

+

在已有 Hugging Face 应用里接入语音识别,最容易踩的坑往往不是模型大小,而是把“同一模型家族”当成“同一种权重和接口”。Fun-ASR-Nano 已进入 Transformers 主线。这篇文章从 checkpoint、处理器到生成结果,解释如何把这次集成接到自己的应用中。

+

先确认安装包,不只看合并状态

+

PR #46180 于 2026-09-09 合并。当天核验的稳定版 5.16.1 还没有原生 fun_asr_nano 文件;源码包显示的 5.17.0.dev0 也不是下一稳定版发布承诺。请从固定版本接入指南安装明确的源码提交,不要只执行一次无版本约束的升级就假定已经兼容。

+

这种区别影响排障方向:未知模型类型可能是安装包未包含实现,不一定是 checkpoint 损坏;模型能下载也不代表所选运行时认识它。

+

同一模型家族,四条不同路径

+
+ + + + +
应用已有的接口选择什么不要混淆
FunASR AutoModelFun-ASR-Nano-2512原始工具包路径;拆分引擎看对应文档。
Transformers processor / generateFun-ASR-Nano-2512-hf本篇的原生接口,不是 vLLM 的转换包。
原生 vLLM HTTP 服务Fun-ASR-Nano-2512-vllm使用独立运行时、模型格式及服务参数。
C++ / GGML 运行时与运行时匹配的 GGUF不是把 Transformers 目录改后缀。
+

这几个官方模型仓库位于 FunAudioLLM 下。原生 Transformers 路径加载 官方 -hf checkpoint,模型和处理器代码来自固定的 Transformers 安装,不需要执行 checkpoint 的远程 Python 代码。它减少了一种接入依赖,并不自动提供鉴权、队列或服务监控。

+

如果目标是多客户端并发请求,直接查看原生 vLLM 部署页;如果目标是离线 C++ 运行,查看llama.cpp 部署页。原生 Python 接口是一个可组合入口,不是所有服务的替换品。

+

从声音到文本,中间实际经过什么?

+
  1. 音频样本。采样率与声道是数据含义的一部分。48 kHz 的数组不能只改参数标成 16 kHz;那会改变模型看到的时间尺度。指南先要求明确的单声道 16 kHz WAV。
  2. +
  3. 音频特征。原生特征提取器用 torchaudio 的 Kaldi fbank,再做 LFR 堆叠与降采样。这里仍需要匹配版本的 torchaudio;不能套用 FunASR 工具包的可选依赖结论。
  4. +
  5. 转写请求。apply_transcription_request 把音频、语言、上下文和关键词整理成模型的聊天模板,并对齐音频占位 token 与特征。
  6. +
  7. 生成和解码。AutoModelForSpeechSeq2Seq 返回 token。去掉输入 prompt 的长度后再解码,才能避免把模板混进转写文本。
+
用于功能检查的官方中文样本波形,横轴为秒,纵轴为振幅
官方中文样本原始波形:约 5.62 秒、单声道 48 kHz。运行指南前应明确重采样为 16 kHz。波形图不是准确率或性能结果。
+

先用合成静音验证配置和张量形状,可以把依赖、模板错误与权重加载问题分开。但预处理没有调用生成模型,不能据此宣布“识别通过”。

+

应用上下文应该放在哪里?

+

业务词表通过原生 keywords 参数传入,相关背景通过 prompt 传入。它们不是工具包的 hotword 参数,也不是 HTTP 层字段。给两份录音分别传上下文时,语言、prompt 和嵌套关键词列表应与录音数量一致。输出顺序应回到同一份输入清单。

+

例如客服录音里的人名、产品名,可以作为候选关键词;但“模板中出现了关键词”和“模型在噪声中识别对了这个词”是两项测试。不要把拼写纠正或摘要改写后的文本冒充原始 ASR 输出。

+

当前固定快照默认左侧 padding;批量示例仍可显式设置 padding 以便阅读。生成返回值要按整批输入张量的宽度去除 prompt,不是各条 attention mask 有效长度。空录音和空列表应在应用边界提前拒绝。

+

一次真实短录音检查说明了什么?

+

在固定源码、官方 -hf revision 和 CPU float32 环境中,我们运行了中文单录音、英文单录音、中英混合批量,以及一个带关键词的中文请求。四个请求均返回文本并在上限前生成 EOS;批量结果顺序正确。这是两份公开短音频的功能检查,不是准确率排行榜。

+
+ + +
同一份中文音频原始输出
不传关键词开饭时间早上九点至下午五点。
候选关键词:开放时间开饭时间:早上九点至下午五点。
+

这个例子没有显示关键词强制生效,不能包装成“加热词就会识别对”。API 参数被接收、输出发生变化和业务词写对,是不同结论。保留原文,再结合人工参考检查;不要用提示词替代验收。环境、样本来源与重采样口径见验证记录

+

接入成功之后,还要验收什么?

+
  • 范围。这条 -hf 路径用于生成式转写,不包含原生 CTC 分支;不能把结果文本当作字级时间戳或说话人分离输出。
  • +
  • 完整性。短文件示例的生成上限是 128 个新 token。触顶可能截断;增加上限不会自动证明长录音没有漏句。
  • +
  • 资源。独立 CPU 示例不是 CUDA、服务并发或 vLLM 性能测试。分别记录下载、模型加载和生成,不把首次下载算成模型推理,也不把一次短录音当作容量规划。
  • +
  • 质量与隐私。在授权录音中回听关键数字、否定词和末尾,保留固定版本与原始结果;公开反馈不要携带客户录音、token 或身份信息。
+

需要段级时间戳和匿名说话人时,可比较 OpenMOSS 的第三方 MOSS 统一转写与分离路径。匿名标签不是人物身份,模型选型仍应从应用真正需要的输出开始。

+

从哪里开始

+

先打开原生 Transformers 安装与推理指南,完成独立 CPU 环境、无权重预处理和短录音生成,再决定是否需要批量或服务化。模型页和 Model Zoo保留格式入口;会议录音验收清单帮助把结果交付到应用。

+

源码依据:固定提交的官方模型文档固定 revision 的模型卡。模型项目与贡献入口见 Fun-ASRFunASR

+ +
+ diff --git a/web-pages/product-site/legacy/blog/index.html b/web-pages/product-site/legacy/blog/index.html index e1f6299345..c2f5acba14 100644 --- a/web-pages/product-site/legacy/blog/index.html +++ b/web-pages/product-site/legacy/blog/index.html @@ -50,6 +50,7 @@
2026-08-31 · FunClip v2.2.0

MOSS 多说话人转写进入 FunClip:从一句话到带说话人的片段

通过经真实双说话人音频验证的 vLLM 路径,把第三方 MOSS 模型的段级时间戳和说话人标签直接用于 SRT 与说话人片段导出。

查看部署与剪辑边界 →
2026-09-09 · 应用工程

HTTP 200 不等于转写成功:会议录音的验收清单

区分文本、匿名说话人、时间戳和尾部覆盖;用经过测试的 Python 检查器开始验收,不把结构合法当作质量合格。

2026-09-04 · 正式 Release

FunASR v1.4.14:可移植源码包、MOSS 入口与十平台运行时

修复 Git archive 与源码安装的可移植性,补齐 MOSS 服务入口,并提供 PyPI 包、十平台运行时与 SHA-256 清单。

2026-08-28 · 正式 Release

FunASR v1.4.5:更轻的 Python 推理与九平台 llama.cpp 运行时

默认安装不再硬依赖 torchaudio,可选 kaldi-native-fbank,并提供 PyPI 包、九平台运行时与 SHA-256 清单。

2026-08-21 · 正式 Release

FunASR v1.4.3:可选 Silero VAD 与大规模固定 K 说话人聚类

新增毫秒级 Silero VAD 适配器,降低已知说话人数的大规模聚类内存压力,并提供 12 个带 SHA-256 的发布资产。

2026-07-31 · 正式 Release

FunASR v1.4.0:更完整的 PyPI 安装包与更安全的 AutoModel 参数

修复 SenseVoice 与 RWKV-BAT 包数据,提前拒绝 vda_model 误拼写,并提供 12 个带 SHA-256 的发布资产。

+
2026-09-09 · 生态技术与应用

Fun-ASR-Nano + Transformers:先选对权重,再接入应用

原生 Transformers 支持已合并:分清 -hf、原始权重、vLLM 和 GGUF,理解音频预处理、生成结果与应用验收,附固定版本接入指南。

2026-08-03 · 生态集成

Subtitle Edit 5.2:Fun-ASR Nano / SenseVoice 本地视频字幕

在 Windows、macOS 与 Linux 的成熟字幕工作区中直接选择本地 ASR 引擎,支持 Q4、Q8、F16。

FunASR 技术博客

2026-06-23

语音识别带时间戳(字级 timestamps)Python 实战:每个字精确到毫秒

FunASR Paraformer 原生字级时间戳:每个字带 [起始毫秒,结束毫秒],一次调用即有。可做逐字高亮、点击跳转、字幕对齐。附真实实测+配对代码。

2026-06-23

标点恢复 Python 实战:给无标点文本/ASR 结果自动加标点

FunASR ct-punc 开源标点恢复,中英双语,3 行 Python 补全 ,。?(英文还做句首大写),也能一行挂到 ASR 上。附真实实测。

2026-06-22

中文语音识别(普通话)Python 实战:用 FunASR 又快又准

FunASR 专为中文打造:默认旗舰 Fun-ASR-Nano(CER 8.06%),CPU 用 SenseVoice(7.81%)/ Paraformer(10.18%,时间戳/热词),都远好于 Whisper(~20%)。3 行 Python。

2026-06-22

自托管语音转文字:Google / AWS / Azure 云语音 API 的免费开源替代

开源免费(MIT)、本地推理、不按分钟计费、数据不出内网、中文强,OpenAI 兼容改 base_url 即可迁移。附实测代码 + FunASR vs 云 API 对比 + 成本分析。

2026-06-22

Python 语音活动检测(VAD):检测语音、去静音、按停顿切分音频

FunASR fsmn-vad 3 行代码返回每段语音的起止毫秒。实测 13s 录音 0.12s 切成 2 段、去除 18% 静音;可去静音、切分长录音、给 Whisper 等做预处理防幻觉。

2026-06-22

日语语音识别:SenseVoice 一个模型搞定日语转写+标点+情感

同一段日语音频实测:SenseVoice 写对同音字 転売、自动加标点,Whisper-small 误为 天売、无标点。原生 ja 支持 + 自动语种识别 + 情感事件,3 行 Python。

2026-06-23

从 Deepgram / AssemblyAI 迁移到自托管 FunASR:接入与验收清单

评估自托管转写迁移:映射请求和结果契约,检查鉴权、返回格式、模型质量与运维成本。提供 FunASR 本地 JSON 示例,不承诺厂商 API 或 SDK 直接替换。

2026-06-23

选哪个 FunASR 模型?Nano vs MLT-Nano vs SenseVoice vs Paraformer

模型选型表 + 场景代码:中英日及中文方言/口音选旗舰 Nano,31 语种选独立 MLT-Nano,CPU 再选 SenseVoice 或 Paraformer。

2026-06-22

轻量语音识别:CPU 上约 250MB 跑中文 ASR

单二进制 + 254MB q8 模型,无需 GPU/Python,CPU 0.16s,中文 CER 7.99%——比 whisper.cpp small 还小且准 3 倍。

2026-06-21

粤语语音识别:SenseVoice 原生支持粤语口语(Whisper 会转成普通话)

同一段粤语音频实测:SenseVoice 保留 呢/唔/嘅,Whisper 转成普通话书面语。原生 yue 支持 + 自动语种识别,3 行 Python。

2026-06-21

FunASR vs faster-whisper:中文与粤语实测对比

粤语被 faster-whisper 误判为普通话、日语同音字错;SenseVoice 原生支持粤语+语种识别,中文 CER 低约 2.7 倍。实测。

2026-06-20

FunASR 跑进 llama.cpp:中文 ASR 的 whisper.cpp 替代品(CPU/零 Python)

单个自包含二进制、内置 VAD、吃任意音频,下载即用转写中文;中文 CPU 上比 whisper.cpp 准约 2.7 倍。3 步实测。

2026-06-18

Python 语音转文字:用 FunASR 本地免费转写音频

几行 Python 把音频转成文本,带时间戳/说话人/批量;本地、免费、无 API key、中文强。

2026-06-18

用 FunASR 自动生成字幕:音频/视频一键出 SRT 和 VTT

一行命令出 SRT,Python 同时导出 VTT,带说话人和真实时间戳;本地、免费、中文强。

2026-06-18

自托管 OpenAI Whisper API 替代:FunASR 接入与安全边界

用 FunASR 部署本地文件转写:显式 loopback 监听、基本 JSON 调用、SDK 接入、格式限制与网关安全。区分部分接口兼容与完整云服务替换。

2026-06-18

用 FunASR 命令行转写音频:文本/JSON/SRT 字幕

一行命令出文字/字幕/JSON,--spk 带说话人;还能 funasr-server 起 OpenAI 兼容 API。

2026-06-17 · 更新于 2026-09-09

长录音转写:VAD 分段、批处理与结果验收

核对完整音频加载、VAD 参数和 CPU 批处理行为,再检查长静音、切分边界与末尾覆盖。

2026-06-17

用 FunASR 实现实时流式语音识别(边说边出字)

600ms 级低延迟流式 ASR:分块+cache 边说边出字,含 2-pass(流式+离线)最佳实践。

2026-06-17

超越转写:用 SenseVoice 识别语言、情感与声学事件

一次非自回归前向同时输出转写+语种+情感+音频事件,Whisper 做不到的四合一。

2026-06-17

用 FunASR 做说话人分离:谁在何时说了什么

一次 generate 调用同时输出转写+说话人标签+时间戳,替代 pyannote+Whisper,无需 HF 授权。

2026-06-16

FunASR vs Whisper 实测对比:谁更快更准

184 中文文件 H100 实测:SenseVoice 169.6x、CER 7.81%,完整速度+准确率数据。

2026-06-16

Fun-ASR-Nano 使用指南:800M 端到端语音识别大模型

主力旗舰,中英日 + 7 大中文方言/26 种口音,热词/流式/说话人分离;31 语种请用 MLT-Nano。

2026-06-16

SenseVoice 部署指南:五语种识别、情感与音频事件

3 行代码跑通多语言识别,含语种/情感/事件检测、VAD、GPU/CPU。

更多:快速上手 · 模型

diff --git a/web-pages/product-site/legacy/en/blog/fun-asr-nano-transformers.html b/web-pages/product-site/legacy/en/blog/fun-asr-nano-transformers.html new file mode 100644 index 0000000000..1874e3e2c2 --- /dev/null +++ b/web-pages/product-site/legacy/en/blog/fun-asr-nano-transformers.html @@ -0,0 +1,57 @@ + + + +Fun-ASR-Nano + Transformers: choose the checkpoint before the API | FunASR + + + + + + + +
+

Fun-ASR-Nano + Transformers: choose the checkpoint before the API

+

2026-09-09 · Ecosystem engineering · 7-minute read

+

When adding speech recognition to a Hugging Face application, a common failure is treating one model family as one interchangeable checkpoint format. Fun-ASR-Nano is now on the Transformers main branch. Here is how to connect the new native path to an application, from model selection to decoding the generated result.

+

Check the package, not just the merge

+

PR #46180 merged on 2026-09-09. The stable 5.16.1 package checked that day did not contain native fun_asr_nano files. The source build's 5.17.0.dev0 label is not a promise of the next stable version or release date. Use the explicit source commit in the pinned setup guide; an unversioned upgrade alone is not evidence of compatibility.

+

This distinction changes troubleshooting: an unknown model type may mean that the installed package lacks the implementation, not that the checkpoint is corrupt. A successful model download does not prove that the selected runtime can load it.

+

One family, four different paths

+
+ + + + +
Your application interfaceArtifactImportant distinction
FunASR AutoModelFun-ASR-Nano-2512Original toolkit path; split-engine has its own guide.
Transformers processor / generateFun-ASR-Nano-2512-hfThe native path described here, not a vLLM conversion.
Native vLLM HTTP serviceFun-ASR-Nano-2512-vllmSeparate runtime, checkpoint format and service options.
C++ / GGML runtimeMatching converted GGUF filesNot a renamed Transformers directory.
+

The official model repositories are under FunAudioLLM. Native Transformers loads the official -hf checkpoint, while the model and processor code come from the pinned Transformers installation. It does not need to execute checkpoint-provided remote Python code. That removes one integration dependency; it does not supply authentication, queues or service monitoring.

+

For concurrent clients, inspect the native vLLM deployment. For offline C++, inspect llama.cpp deployment. A composable Python interface is not a replacement for every serving stack.

+

What happens between audio and text?

+
  1. Audio samples. Sample rate and channel layout are part of the data's meaning. Labeling a 48 kHz array as 16 kHz changes the time scale seen by the model. The guide requires an explicitly prepared mono 16 kHz WAV.
  2. +
  3. Audio features. The native extractor computes Kaldi fbank through torchaudio, then applies low-frame-rate stacking and subsampling. Matching torchaudio is required here, regardless of the toolkit's optional-dependency policy.
  4. +
  5. The transcription request. apply_transcription_request prepares the checkpoint's chat template from audio, language, context and keywords, aligning audio placeholder tokens with features.
  6. +
  7. Generation and decoding. AutoModelForSpeechSeq2Seq returns tokens. Remove the input prompt width before decoding to avoid mixing template framing into recognized speech.
+
Official Chinese functional-test sample waveform, time in seconds and amplitude
The official Chinese sample: approximately 5.62 seconds, mono, originally 48 kHz. Explicitly resample it to 16 kHz before the guide's input step. A waveform is not an accuracy or performance result.
+

A synthetic-silence preprocessing check separates dependency and template failures from weight loading. It does not run the generation model, so it cannot establish successful speech recognition.

+

Where does application context belong?

+

Pass a vocabulary through native keywords and relevant background through prompt. These are not the toolkit's hotword argument or HTTP fields. For separate recording contexts, language, prompt and nested keyword lists must match the number of audio inputs. Map results back to the same input manifest in order.

+

Customer-service recordings may benefit from candidate product or person names. But “the template includes this keyword” and “the recognizer recovered it in noise” are different tests. Do not present a spelling correction or summary rewrite as raw ASR output.

+

The pinned checkpoint defaults to left padding; explicit padding still makes a batch example easier to inspect. Remove the full input tensor width from generated sequences, not each row's valid attention-mask length. Reject empty recordings and empty batches at your application boundary.

+

What did the short-recording check establish?

+

With pinned source, official -hf revision and CPU float32, we ran a Chinese recording, an English recording, a mixed Chinese/English batch and a Chinese keyword request. All four requests returned text and EOS before the limit, with the batch in input order. These are functional checks on two public short recordings, not an accuracy ranking.

+
+ + +
The same Chinese audioRaw output
No keywords开饭时间早上九点至下午五点。
Candidate keyword: 开放时间开饭时间:早上九点至下午五点。
+

The hint did not force the requested spelling. Accepting a parameter, changing the output and recovering the intended business term are different conclusions. Keep the raw result and check it against a human reference; prompts do not replace acceptance testing. See the verification record for environment, sample provenance and resampling details.

+

What remains after the interface works?

+
  • Output scope. This -hf path is generation-based transcription and omits the native CTC branch. Text is not a word-timestamp or speaker-diarization result.
  • +
  • Completeness. The short-file example allows 128 new tokens. Reaching the limit can truncate output; raising it does not prove complete long-recording coverage.
  • +
  • Resources. A CPU example is not a CUDA, concurrent-serving or vLLM performance test. Measure download, model loading and generation separately. One short file is not capacity planning.
  • +
  • Quality and privacy. Review important numbers, negation and the recording's end in authorized audio. Preserve fixed versions and raw output. Never attach customer recordings, tokens or identity data to a public report.
+

For segment timestamps and anonymous speakers, compare the third-party OpenMOSS MOSS unified transcription and diarization path. Anonymous labels are not known-person identities. Choose the output the application actually needs.

+

Start with a reproducible recording

+

Follow the native Transformers installation and inference guide: an independent CPU environment, preprocessing without weights, then a short recording. Only then extend to batching or serving. The Model Zoo preserves format-specific entry points; the meeting acceptance checklist covers downstream delivery.

+

Primary sources: official model documentation at the merged commit and the pinned model card. Explore the model and contribute through Fun-ASR and FunASR.

+ +
+ diff --git a/web-pages/product-site/legacy/en/blog/index.html b/web-pages/product-site/legacy/en/blog/index.html index 1a49f79a7d..c7de746e1b 100644 --- a/web-pages/product-site/legacy/en/blog/index.html +++ b/web-pages/product-site/legacy/en/blog/index.html @@ -50,6 +50,7 @@
August 31, 2026 · FunClip v2.2.0

MOSS Multi-Speaker Transcription in FunClip: From One Prompt to Speaker Clips

Use the vLLM path validated on real two-speaker audio to turn the third-party MOSS model's segment timestamps and speaker labels into SRT and speaker-specific clip exports.

Read the deployment and clipping boundaries →
2026-09-09 · Application engineering

HTTP 200 is not a usable transcript: a meeting-audio acceptance checklist

Separate words, anonymous speakers, timestamps and tail coverage. Start with a tested Python checker without mistaking structural validity for quality.

September 4, 2026 · Stable release

FunASR v1.4.14: Portable Source Archives, MOSS Discovery, and Ten Runtimes

Portable Git archives and source installs, clearer MOSS service discovery, plus PyPI packages, ten runtimes, and SHA-256 checksums.

August 28, 2026 · Stable release

FunASR v1.4.5: Lighter Python Inference and Nine llama.cpp Runtimes

No hard torchaudio dependency in the default install, optional kaldi-native-fbank, plus PyPI packages, nine runtimes, and SHA-256 checksums.

August 21, 2026 · Stable release

FunASR v1.4.3: Optional Silero VAD and Fixed-K Speaker Clustering

Millisecond Silero VAD segments, lower-memory clustering for large known-speaker workloads, and 12 SHA-256-addressed release assets.

July 31, 2026 · Stable release

FunASR v1.4.0: Complete PyPI Packages and Safer AutoModel Arguments

SenseVoice and RWKV-BAT package-data fixes, an early vda_model typo guard, and 12 SHA-256-addressed release assets.

+
2026-09-09 · Ecosystem engineering

Fun-ASR-Nano + Transformers: choose the checkpoint before the API

Native Transformers support has merged. Separate -hf, original, vLLM and GGUF artifacts, understand preprocessing and generation, and follow a pinned application guide.

August 3, 2026 · Ecosystem

Subtitle Edit 5.2: Local Video Subtitles with Fun-ASR Nano or SenseVoice

Select a local ASR engine inside a mature subtitle workspace on Windows, macOS, or Linux, with Q4, Q8, and F16 models.

FunASR Blog

2026-06-23

Speech-to-Text with Word/Character-Level Timestamps in Python

FunASR Paraformer gives native character timestamps: every char has [start_ms, end_ms] in one call. Build word highlighting, click-to-seek, subtitle alignment. Real output + pairing code.

2026-06-23

Punctuation Restoration in Python — Add Punctuation to Text / ASR Output

FunASR ct-punc: open-source bilingual (zh+en) punctuation restoration. 3 lines of Python to add ,。? (and capitalize English), or attach to ASR in one line. Real output.

2026-06-22

Chinese (Mandarin) Speech Recognition in Python — Fast & Accurate with FunASR

Purpose-built for Chinese: default flagship Fun-ASR-Nano (CER 8.06%), with SenseVoice (7.81%) / Paraformer (10.18%, timestamps/hotwords) for CPU — all far better than Whisper (~20%).

2026-06-22

Self-Hosted Speech-to-Text — Free Alternative to Google / AWS / Azure Cloud Speech APIs

Open-source (MIT), local inference, no per-minute billing, audio stays on your network, strong Chinese, OpenAI-compatible (migrate via base_url). Runnable code + FunASR vs cloud comparison + cost analysis.

2026-06-22

Voice Activity Detection in Python — Detect Speech, Remove Silence, Split Audio

FunASR fsmn-vad returns millisecond speech spans in 3 lines. Measured: a 13s clip split into 2 segments in 0.12s, 18% silence removed. Trim silence, split long audio, preprocess Whisper to cut hallucinations.

2026-06-22

Japanese Speech Recognition in Python — SenseVoice: Transcription + Punctuation + Emotion in One Pass

Real side-by-side on one Japanese clip: SenseVoice writes 転売 correctly and adds punctuation; Whisper-small gives 天売 with none. Native ja support + auto language ID + emotion/events, 3 lines of Python.

2026-06-23

Migrating from Deepgram / AssemblyAI to Self-Hosted FunASR: Integration and Acceptance

Plan a self-hosted transcription migration: map request and response contracts, authentication, formats, model quality and operating costs. Includes a local FunASR JSON recipe, not a drop-in vendor SDK replacement.

2026-06-23

Which FunASR Model? Nano vs MLT-Nano vs SenseVoice vs Paraformer

A decision table with code: flagship Nano for zh/en/ja plus Chinese dialects/accents, separate MLT-Nano for 31 languages, and CPU choices SenseVoice or Paraformer.

2026-06-22

Lightweight Speech Recognition: Chinese ASR in ~250MB on CPU

One binary + a 254MB q8 model, no GPU/Python, 0.16s on CPU, 7.99% CER — smaller than whisper.cpp small and ~3x more accurate.

2026-06-21

Cantonese Speech Recognition in Python — SenseVoice Keeps Real Cantonese (Whisper Doesn't)

Real side-by-side on one Cantonese clip: SenseVoice keeps 呢/唔/嘅, Whisper rewrites to Mandarin. Native yue support + auto language ID, 3 lines of Python.

2026-06-21

FunASR vs faster-whisper: Chinese & Cantonese Compared

faster-whisper mislabels Cantonese as Mandarin + Japanese homophone errors; SenseVoice handles Cantonese natively, ~2.7x lower CER on Chinese.

2026-06-20

FunASR on llama.cpp — a whisper.cpp Alternative for Chinese ASR (CPU, no Python)

One self-contained binary, built-in VAD, any audio — download and transcribe Chinese; ~2.7x more accurate than whisper.cpp on CPU.

2026-06-18

Speech to Text in Python with FunASR

Transcribe audio in a few lines of Python — timestamps, speakers, batching. Local, free, no API key.

2026-06-18

Auto-Generate Subtitles (SRT & VTT) from Audio or Video with FunASR

One command for SRT, Python for VTT too, with speaker labels and real timestamps. Local, free, strong on Chinese.

2026-06-18

Self-Hosted OpenAI Whisper API Alternative: FunASR Integration and Security

Integrate local FunASR file transcription with explicit loopback binding, JSON requests, SDK checks, response-format limits and gateway security. Partial API support is not complete cloud-service parity.

2026-06-18

Transcribe Audio from the Command Line with FunASR

One command -> text/SRT/JSON, --spk for speakers; plus funasr-server for an OpenAI-compatible API.

2026-06-17 · Updated 2026-09-09

Long-File Transcription: VAD Segmentation, Batching and Acceptance

Check full-file loading, VAD parameters and CPU batching, then audit long silences, segment boundaries and tail coverage.

2026-06-17

Real-Time Streaming Speech-to-Text with FunASR

~600ms low-latency streaming ASR with chunks + cache, plus the 2-pass (streaming + offline) best practice.

2026-06-17

Beyond Transcription: Language, Emotion & Audio Events with SenseVoice

Transcription + language + emotion + audio events in one pass — the 4-in-1 Whisper cannot do.

2026-06-17

Speaker Diarization with FunASR: Who Spoke When

Transcription + speaker labels + timestamps in one generate() call. A pyannote+Whisper alternative, no HF gated access.

2026-06-16

FunASR vs Whisper: Real Chinese ASR Benchmark

Measured on 184 Chinese files (H100): SenseVoice 169.6x, 7.81% CER — full speed & accuracy data.

2026-06-16

Fun-ASR-Nano Guide: 800M End-to-End ASR LLM

Flagship for zh/en/ja plus 7 Chinese dialect groups and 26 accents; choose MLT-Nano for 31 languages.

2026-06-16

SenseVoice Deployment Guide: Five-Language ASR, Emotion and Audio Events

Multilingual ASR in 3 lines, with language/emotion/event tags, VAD, GPU/CPU.

More: Quickstart · Models

diff --git a/web-pages/product-site/legacy/en/models.html b/web-pages/product-site/legacy/en/models.html index f1341fc8d9..e660afcfb5 100644 --- a/web-pages/product-site/legacy/en/models.html +++ b/web-pages/product-site/legacy/en/models.html @@ -89,6 +89,7 @@

ASR Models

Fun-ASR-Nano ⭐ Flagship / default
800M params · LLM-based (SenseVoice encoder + Qwen3-0.6B) · GitHub · HuggingFace
+

Native Transformers support is merged upstream. Use the official -hf checkpoint, distinct from original, -vllm and GGUF artifacts. The pinned installation and inference guide explains why stable 5.16.1 is not sufficient.

Next-generation LLM-based ASR model. Combines SenseVoice's audio encoder with Qwen3-0.6B language model for superior context understanding. Supports vLLM acceleration for high-throughput batch inference and real-time streaming. The released model.pt checkpoint does not provide reliable checkpoint-native character timestamps (issue #106).
vLLM accelerated diff --git a/web-pages/product-site/legacy/img/fun-asr-nano-native-waveform.png b/web-pages/product-site/legacy/img/fun-asr-nano-native-waveform.png new file mode 100644 index 0000000000..392b7f65e4 Binary files /dev/null and b/web-pages/product-site/legacy/img/fun-asr-nano-native-waveform.png differ diff --git a/web-pages/product-site/legacy/models.html b/web-pages/product-site/legacy/models.html index b564f14f73..bd11a2d947 100644 --- a/web-pages/product-site/legacy/models.html +++ b/web-pages/product-site/legacy/models.html @@ -89,6 +89,7 @@

ASR 模型

Fun-ASR-Nano ⭐ 旗舰 / 默认推荐
800M 参数 · LLM 架构 (SenseVoice 编码器 + Qwen3-0.6B) · GitHub · HuggingFace
+

原生 Transformers 路径已合入上游:使用 官方 -hf checkpoint,不要与原始权重、-vllm 或 GGUF 混用。固定版本的安装与推理指南说明 5.16.1 稳定版尚未包含的边界。

新一代 LLM 架构 ASR 模型。融合 SenseVoice 音频编码器与 Qwen3-0.6B 语言模型,具备更强的上下文理解能力。支持 vLLM 加速的高吞吐批量推理与实时流式服务。发布的 model.pt checkpoint 不提供可靠的原生字级时间戳(issue #106)。
vLLM 加速 diff --git a/web-pages/product-site/tests/browser/native-transformers.spec.ts b/web-pages/product-site/tests/browser/native-transformers.spec.ts new file mode 100644 index 0000000000..bc3d4023b6 --- /dev/null +++ b/web-pages/product-site/tests/browser/native-transformers.spec.ts @@ -0,0 +1,51 @@ +import { expect, test } from '@playwright/test'; + +for (const prefix of ['', 'en/']) { + for (const width of [390, 1440]) { + test(`native Transformers article and guide ${prefix || 'zh'} ${width}`, async ({ page }, testInfo) => { + await page.setViewportSize({ width, height: 900 }); + const route = `/${prefix}blog/fun-asr-nano-transformers.html`; + await page.goto(`/${prefix}blog/`); + await page.locator(`a.post-card[href="${route}"]`).click(); + await expect(page).toHaveURL(new RegExp(route.replaceAll('.', '\\.'))); + const layout = await page.evaluate(() => ({ + overflow: document.documentElement.scrollWidth - document.documentElement.clientWidth, + headingTop: document.querySelector('article h1')!.getBoundingClientRect().top, + navBottom: document.querySelector('nav')!.getBoundingClientRect().bottom, + })); + expect(layout.overflow).toBeLessThanOrEqual(1); + expect(layout.headingTop).toBeGreaterThanOrEqual(layout.navBottom); + await page.screenshot({ path: testInfo.outputPath('article-top.png') }); + const waveform = page.locator('article img'); + await waveform.scrollIntoViewIfNeeded(); + await expect(waveform).toBeVisible(); + expect(await waveform.evaluate((node: HTMLImageElement) => node.complete && node.naturalWidth === 1800)).toBeTruthy(); + await page.screenshot({ path: testInfo.outputPath('waveform.png') }); + const table = page.locator('[data-native-section="formats"] table'); + await table.scrollIntoViewIfNeeded(); + const scroll = await table.evaluate((tableNode) => { + const node = tableNode.closest('.table-wrap')!; + node.scrollLeft = node.scrollWidth; + const rect = node.getBoundingClientRect(); + return { left: rect.left, right: rect.right, scroll: node.scrollLeft, + width: node.clientWidth, content: node.scrollWidth }; + }); + expect(scroll.left).toBeGreaterThanOrEqual(0); + expect(scroll.right).toBeLessThanOrEqual(width); + if (width === 390) expect(scroll.scroll).toBeGreaterThan(0); + await page.locator(`article a[href="/${prefix}docs/native-transformers.html"]`).first().click(); + await expect(page.locator('[data-source-link]')).toHaveAttribute( + 'href', new RegExp(`/docs/transformers_native${prefix ? '' : '_zh'}\\.md$`), + ); + await expect(page.locator('.docs-article')).toContainText('torchaudio==2.10.0+cpu'); + expect(await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth)).toBeLessThanOrEqual(1); + await page.screenshot({ path: testInfo.outputPath('guide-top.png') }); + await page.goto(`/${prefix}models.html`); + await page.locator(`a[href="/${prefix}docs/native-transformers.html"]`).click(); + await expect(page).toHaveURL(new RegExp('/docs/native-transformers\\.html$')); + await page.goto(`/__pages/${prefix ? '' : 'zh/'}native-transformers.html`); + await expect(page.locator('.docs-article')).toContainText('FunAudioLLM/Fun-ASR-Nano-2512-hf'); + expect(await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth)).toBeLessThanOrEqual(1); + }); + } +} diff --git a/web-pages/product-site/tests/test_native_transformers_docs.py b/web-pages/product-site/tests/test_native_transformers_docs.py new file mode 100644 index 0000000000..e2fda7b700 --- /dev/null +++ b/web-pages/product-site/tests/test_native_transformers_docs.py @@ -0,0 +1,134 @@ +"""Native Transformers adoption documentation, without model downloads.""" +import ast +import json +import re +import sys +from pathlib import Path + +import pytest +from bs4 import BeautifulSoup + +SITE = Path(__file__).resolve().parents[1] +ROOT = SITE.parents[1] +sys.path.insert(0, str(SITE)) +from build import build +from export_docs import export_documentation + +SLUG = "native-transformers" +BLOG = "fun-asr-nano-transformers.html" +HEAD = "fc501343edfccdc840eb8594a6cafa8185c2de53" +REVISION = "d93b302ee7fd505e1b3576120fc142fc6f7820e1" +MODEL = "FunAudioLLM/Fun-ASR-Nano-2512-hf" + + +def guide(suffix=""): + path = ROOT / f"docs/transformers_native{suffix}.md" + assert path.is_file(), "Missing native Transformers guide" + return path.read_text() + + +def example(text, name): + pattern = rf"\s*\x60\x60\x60python\n(.*?)\x60\x60\x60" + matches = re.findall(pattern, text, re.S) + assert len(matches) == 1, f"Missing unique {name} example" + return matches[0] + + +def test_catalogue_and_pages_export_own_both_native_guides(): + data = json.loads((SITE / "data/documentation.json").read_text()) + entries = [p for p in data["pages"] if p["slug"] == SLUG] + assert len(entries) == 1 + assert entries[0]["source_en"] == "docs/transformers_native.md" + assert entries[0]["source_zh"] == "docs/transformers_native_zh.md" + from export_docs import ALIASES + assert ALIASES[SLUG] == "native-transformers.html" + + +@pytest.mark.parametrize("suffix", ["", "_zh"]) +def test_native_guide_pins_format_runtime_and_audio_dependency(suffix): + text = guide(suffix) + for expected in (MODEL, REVISION, HEAD, "torchaudio==2.10.0+cpu", + "torch==2.10.0+cpu", "5.16.1", "2026-09-09", + "vllm", "GGUF", "46180"): + assert expected in text + assert re.search(r"not.*stable|stable.*not|稳定版.*不|不.*稳定版", text, re.I) + assert re.search(r"not.*(?:capacity|accuracy)|不.*(?:容量|准确率)", text, re.I) + + +@pytest.mark.parametrize("name", ["processor", "transcribe"]) +def test_bilingual_recipes_are_identical_and_use_fixed_native_checkpoint(name): + en = example(guide(), name) + zh = example(guide("_zh"), name) + assert en == zh + tree = ast.parse(en) + constants = {node.value for node in ast.walk(tree) if isinstance(node, ast.Constant) and isinstance(node.value, str)} + assert MODEL in constants and REVISION in constants + calls = [node for node in ast.walk(tree) if isinstance(node, ast.Call)] + loaders = [node for node in calls if isinstance(node.func, ast.Attribute) and node.func.attr == "from_pretrained"] + assert loaders + for node in loaders: + names = {kw.arg for kw in node.keywords} + assert {"revision", "trust_remote_code"} <= names + assert next(kw.value for kw in node.keywords if kw.arg == "trust_remote_code").value is False + assert "apply_transcription_request" in en + if name == "processor": + assert not any(isinstance(node.func, ast.Attribute) and node.func.attr == "generate" for node in calls) + else: + assert "inference_mode" in en and "max_new_tokens" in en + assert "generated[:, inputs.input_ids.shape[1]:]" in en + assert "batch_decode" in en + assert "16000" in en and "ndim" in en + + +@pytest.mark.parametrize("name,heading", [ + ("README.md", "What's new"), ("README_zh.md", "最新动态"), + ("README_ja.md", "最新情報"), ("README_ko.md", "최신 소식"), +]) +def test_readme_news_stays_three_items_with_native_guide(name, heading): + text = (ROOT / name).read_text() + section = text.split("## " + heading, 1)[1].split("\n## ", 1)[0] + bullets = re.findall(r"^- .*", section, re.M) + assert len(bullets) == 3 + assert any("Transformers" in row and "transformers_native" in row for row in bullets) + assert any("1.4.15" in row for row in bullets) + assert any("MOSS" in row for row in bullets) + + +@pytest.mark.parametrize("suffix", ["", "_zh"]) +def test_model_zoo_and_deployment_matrix_link_native_format(suffix): + zoo = (ROOT / f"model_zoo/readme{suffix}.md").read_text() + matrix = (ROOT / f"docs/deployment_matrix{suffix}.md").read_text() + assert MODEL in zoo and f"transformers_native{suffix}.md" in zoo + assert f"transformers_native{suffix}.md" in matrix + + +@pytest.fixture(scope="module") +def rendered(tmp_path_factory): + output = tmp_path_factory.mktemp("native-transformers-site") + build(output) + pages = tmp_path_factory.mktemp("native-transformers-pages") + export_documentation(output, pages) + return output, pages + + +@pytest.mark.parametrize("prefix,suffix,pages_prefix", [("", "_zh", "zh/"), ("en/", "", "")]) +def test_rendered_blog_models_guide_and_pages_are_connected(rendered, prefix, suffix, pages_prefix): + output, pages = rendered + route = f"/{prefix}docs/{SLUG}.html" + article_path = output / prefix / "blog" / BLOG + assert article_path.is_file() + article = BeautifulSoup(article_path.read_text(), "html.parser") + assert article.select_one(f'article a[href="{route}"]') + assert article.select_one('link[rel="canonical"]')["href"] == f"https://www.funasr.com/{prefix}blog/{BLOG}" + body = article.select_one("article").get_text(" ", strip=True) + for term in ["Transformers", "-hf", "vLLM", "GGUF", "2026-09-09"]: + assert term in body + index = BeautifulSoup((output / prefix / "blog/index.html").read_text(), "html.parser") + assert len(index.select(f'a.post-card[href="/{prefix}blog/{BLOG}"]')) == 1 + models = BeautifulSoup((output / prefix / "models.html").read_text(), "html.parser") + assert models.select_one(f'a[href="{route}"]') + native = BeautifulSoup((output / prefix / "docs" / f"{SLUG}.html").read_text(), "html.parser") + assert native.select_one("[data-source-link]")["href"].endswith(f"/docs/transformers_native{suffix}.md") + exported = BeautifulSoup((pages / pages_prefix / "native-transformers.html").read_text(), "html.parser") + assert MODEL in exported.get_text() + assert exported.select_one('link[rel="canonical"]')["href"] == "https://www.funasr.com" + route