diff --git a/docs/mkdocs/hooks/generate_examples.py b/docs/mkdocs/hooks/generate_examples.py index 6cb601b96..f3f96eb2d 100644 --- a/docs/mkdocs/hooks/generate_examples.py +++ b/docs/mkdocs/hooks/generate_examples.py @@ -24,6 +24,16 @@ SERVING_MODE_TITLES = { "online_serving": "Online serving", } +# Generated example pages keep their source-derived URLs even when their +# navigation category changes. Quantization helpers are feature documentation, +# not user-serving examples, so keep them under the existing Features / +# Quantization section instead of creating a second top-level Quantization +# category under Examples. +EXAMPLE_NAV_TARGETS = { + "quantization": "quantization", +} +GENERATED_QUANTIZATION_EXAMPLES_TITLE = "Generated Examples" + def load_model_display_names() -> dict[str, str]: try: @@ -340,26 +350,58 @@ def update_nav_file(examples: list[Example]): examples_by_category[category] = [] examples_by_category[category].append(example) - # Build the new Examples section - start with preserved items - examples_section = preserved_items.copy() - - # Add examples grouped by category, sorted by category name - for category in sorted(examples_by_category.keys()): - category_examples = sorted(examples_by_category[category], key=lambda e: e.path.stem) - category_items = [] - for example in category_examples: + def category_items(category: str) -> list[dict[str, str]]: + items = [] + for example in sorted(examples_by_category[category], key=lambda e: e.path.stem): doc_path = EXAMPLE_DOC_DIR / example.category / f"{example.path.stem}.md" rel_path = doc_path.relative_to(ROOT_DIR / "docs") - category_items.append({example.nav_title: rel_path.as_posix()}) + items.append({example.nav_title: rel_path.as_posix()}) + return items - if category_items: - # Format category name (e.g., "offline_inference" -> "Offline Inference") + # Build the new Examples section - start with preserved items. Categories + # not explicitly routed elsewhere retain the historical Examples behavior. + examples_section = preserved_items.copy() + for category in sorted(examples_by_category.keys()): + if EXAMPLE_NAV_TARGETS.get(category, "examples") != "examples": + continue + items = category_items(category) + if items: category_title = fix_case(category.replace("_", " ").title()) - examples_section.append({category_title: category_items}) + examples_section.append({category_title: items}) # Update the nav structure nav_list[user_guide_idx]["User Guide"][examples_idx]["Examples"] = examples_section + features_content = next( + (item["Features"] for item in user_guide_content if isinstance(item, dict) and "Features" in item), + None, + ) + quantization_content = None + if isinstance(features_content, list): + quantization_content = next( + (item["Quantization"] for item in features_content if isinstance(item, dict) and "Quantization" in item), + None, + ) + + if isinstance(quantization_content, list): + # Remove only the group owned by this hook so repeated builds are + # idempotent and hand-authored Quantization navigation is retained. + quantization_content[:] = [ + item + for item in quantization_content + if not (isinstance(item, dict) and GENERATED_QUANTIZATION_EXAMPLES_TITLE in item) + ] + + quantization_examples = examples_by_category.get("quantization") + if quantization_examples: + if not isinstance(quantization_content, list): + logger.warning( + "Could not find 'User Guide' -> 'Features' -> 'Quantization' section; " + "omitting generated quantization examples from navigation" + ) + else: + quantization_content.append({GENERATED_QUANTIZATION_EXAMPLES_TITLE: category_items("quantization")}) + # Write back to file nav_data["nav"] = nav_list with open(NAV_FILE, "w", encoding="utf-8") as f: diff --git a/docs/models/recipe_coverage.yaml b/docs/models/recipe_coverage.yaml new file mode 100644 index 000000000..3389bcf98 --- /dev/null +++ b/docs/models/recipe_coverage.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project + +# This registry is keyed by an exact Hugging Face checkpoint and task. A +# Supported Models row may cover several checkpoints, but coverage entries must +# be split whenever the example or recipe differs. +version: 1 + +# The registry is incrementally audited. An absent entry means that coverage +# has not been audited yet; it is not evidence that no recipe exists. Do not +# infer recipe coverage from the implementation or hardware columns in +# supported_models.md. +entries: + - model: Qwen/Qwen3-Omni-30B-A3B-Instruct + task: omni-serving + examples: + - docs/user_guide/examples/offline_inference/qwen3_omni.md + - docs/user_guide/examples/online_serving/qwen3_omni.md + recipe: + status: repository + repository_path: recipes/Qwen/Qwen3-Omni.md + hardware: [nvidia] + + - model: Qwen/Qwen-Image + task: text-to-image + examples: + - docs/user_guide/examples/offline_inference/text_to_image.md + - docs/user_guide/examples/online_serving/text_to_image.md + recipe: + status: published + published_url: https://recipes.vllm.ai/Qwen/Qwen-Image + repository_path: recipes/Qwen/Qwen-Image.md + hardware: [nvidia] + + - model: Qwen/Qwen-Image-2512 + task: text-to-image + examples: + - docs/user_guide/examples/offline_inference/text_to_image.md + - docs/user_guide/examples/online_serving/text_to_image.md + recipe: + status: repository + repository_path: recipes/Qwen/Qwen-Image-2512.md + hardware: [nvidia] + + - model: Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice + task: text-to-speech + examples: + - docs/user_guide/examples/offline_inference/text_to_speech.md + - docs/user_guide/examples/online_serving/text_to_speech.md + recipe: + status: published + published_url: https://recipes.vllm.ai/Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice + repository_path: recipes/Qwen/Qwen3-TTS.md + hardware: [nvidia] + + - model: bosonai/higgs-audio-v3-tts-4b + task: text-to-speech + examples: + - docs/user_guide/examples/online_serving/text_to_speech.md + recipe: + status: published + published_url: https://recipes.vllm.ai/bosonai/higgs-audio-v3-tts-4b + repository_path: recipes/BosonAI/Higgs-Audio-V3-TTS.md + hardware: [nvidia] + + - model: MiniMaxAI/MiniMax-H3 + task: video-audio-generation + examples: [] + recipe: + status: published + published_url: https://recipes.vllm.ai/MiniMaxAI/MiniMax-H3 + repository_path: recipes/MiniMaxAI/MiniMax-H3.md + hardware: [nvidia, amd] diff --git a/docs/models/supported_models.md b/docs/models/supported_models.md index 585a22bdc..ab9ae311b 100644 --- a/docs/models/supported_models.md +++ b/docs/models/supported_models.md @@ -17,87 +17,121 @@ th { } -| Architecture | Models | Example HF Models | NVIDIA GPU | AMD GPU | Ascend NPU | Intel GPU | -|--------------|--------|-------------------|------------|---------|-----|-----------| -| `Qwen3OmniMoeForConditionalGeneration` | Qwen3-Omni | `Qwen/Qwen3-Omni-30B-A3B-Instruct` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `Qwen2_5OmniForConditionalGeneration` | Qwen2.5-Omni | `Qwen/Qwen2.5-Omni-7B`, `Qwen/Qwen2.5-Omni-3B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `MingFlashOmniForConditionalGeneration` + `MingImagePipeline` | Ming-flash-omni-2.0 (omni-speech + imagegen1) | `Jonathan1909/Ming-flash-omni-2.0` | ✅︎ | | | | -| `BagelForConditionalGeneration` | BAGEL (DiT-only) | `ByteDance-Seed/BAGEL-7B-MoT` | ✅︎ | ✅︎ | | ✅︎ | -| `InternVLAA1Pipeline` | InternVLA-A1 | `InternRobotics/InternVLA-A1-3B` | ✅︎ | ✅︎ | | | -| `Gr00tN1d7Pipeline` | GR00T N1.7 | `nvidia/GR00T-N1.7-3B` | ✅︎ | | | | -| `HunyuanImage3ForCausalMM` | HunyuanImage3.0 (DiT-only) | `tencent/HunyuanImage-3.0`, `tencent/HunyuanImage-3.0-Instruct` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `QwenImagePipeline` | Qwen-Image | `Qwen/Qwen-Image` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `QwenImagePipeline` | Qwen-Image-2512 | `Qwen/Qwen-Image-2512` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `QwenImageEditPipeline` | Qwen-Image-Edit | `Qwen/Qwen-Image-Edit` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `QwenImageEditPlusPipeline` | Qwen-Image-Edit-2509 | `Qwen/Qwen-Image-Edit-2509` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `QwenImageLayeredPipeline` | Qwen-Image-Layered | `Qwen/Qwen-Image-Layered` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `QwenImageEditPlusPipeline` | Qwen-Image-Edit-2511 | `Qwen/Qwen-Image-Edit-2511` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `GlmImagePipeline` | GLM-Image | `zai-org/GLM-Image` | ✅︎ | ✅︎ | | | -| `ZImagePipeline` | Z-Image | `Tongyi-MAI/Z-Image-Turbo` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `Krea2Pipeline` | Krea 2 (Raw + Turbo) | `krea/Krea-2-Raw`, `krea/Krea-2-Turbo` | ✅︎ | | | | -| `WanPipeline` | Wan2.1-T2V, Wan2.2-T2V, Wan2.2-TI2V | `Wan-AI/Wan2.1-T2V-1.3B-Diffusers`, `Wan-AI/Wan2.1-T2V-14B-Diffusers`, `Wan-AI/Wan2.2-T2V-A14B-Diffusers`, `Wan-AI/Wan2.2-TI2V-5B-Diffusers` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `WanImageToVideoPipeline` | Wan2.2-I2V | `Wan-AI/Wan2.2-I2V-A14B-Diffusers` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `Cosmos3OmniDiffusersPipeline` | Cosmos3 T2I, T2V, I2V, V2V, T2V with sound, action policy | `nvidia/Cosmos3-Nano`, `nvidia/Cosmos3-Super` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `Wan22S2VPipeline` | Wan2.2-S2V | `Wan-AI/Wan2.2-S2V-14B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `Wan22VACEPipeline` | Wan2.1-VACE | `Wan-AI/Wan2.1-VACE-1.3B-diffusers`, `Wan-AI/Wan2.1-VACE-14B-diffusers` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `Wan22VACEPipeline` | Wan2.2-VACE | `Pyros13/Wan2.2-VACE-Fun-A14B-Diffusers` | ✅︎ | | | | -| `LTX2Pipeline` | LTX-2 / LTX-2.3 one-stage T2V and I2V | `Lightricks/LTX-2`, `diffusers/LTX-2.3-Diffusers` | ✅︎ | ✅︎ | | | -| `LTX2DistilledPipeline` | LTX-2 distilled two-stage T2V and I2V | `rootonchair/LTX-2-19b-distilled` | ✅︎ | ✅︎ | | | -| `LingBotVideoPipeline` | LingBot-Video dense and MoE T2I, T2V, TI2V | `robbyant/lingbot-video-dense-1.3b`, `robbyant/lingbot-video-moe-30b-a3b` | ✅︎ | | | | -| `MiniMaxH3Pipeline` | MiniMax H3 T2VA, first/last-keyframe FL2VA, and mixed-reference Ref2VA | `MiniMaxAI/MiniMax-H3` | ✅︎ | | | | -| `DreamZeroPipeline` | DreamZero-DROID | `GEAR-Dreams/DreamZero-DROID` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `HeliosPipeline`, `HeliosPyramidPipeline` | Helios | `BestWishYsh/Helios-Base`, `BestWishYsh/Helios-Mid`, `BestWishYsh/Helios-Distilled` | ✅︎ | ✅︎ | ✅︎ | | -| `MagiHumanPipeline` | MagiHuman | `SII-GAIR/daVinci-MagiHuman-Base-1080p` | ✅︎ | ✅︎ | | | -| `OvisImagePipeline` | Ovis-Image | `OvisAI/Ovis-Image` | ✅︎ | ✅︎ | | ✅︎ | -| `LongcatImagePipeline` | LongCat-Image | `meituan-longcat/LongCat-Image` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `LongCatImageEditPipeline` | LongCat-Image-Edit | `meituan-longcat/LongCat-Image-Edit` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `BooguImagePipeline` | Boogu-Image | `Boogu/Boogu-Image-0.1-Base`, `Boogu/Boogu-Image-0.1-Edit` | ✅︎ | | | | -| `StableDiffusionXLPipeline` | Stable-Diffusion-XL | `stabilityai/stable-diffusion-xl-base-1.0` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `StableDiffusion3Pipeline` | Stable-Diffusion-3 | `stabilityai/stable-diffusion-3.5-medium` | ✅︎ | ✅︎ | | ✅︎ | -| `CosyVoice3Model` | CosyVoice3 | `FunAudioLLM/Fun-CosyVoice3-0.5B-2512` | ✅︎ | ✅︎ | | ✅︎ | -| `OmniVoiceModel` | OmniVoice | `k2-fsa/OmniVoice` | ✅︎ | | | | -| `VoxCPM2TalkerForConditionalGeneration` | VoxCPM2 | `openbmb/VoxCPM2` | ✅︎ | | | | -| `MammothModa2ForConditionalGeneration` | MammothModa2-Preview | `bytedance-research/MammothModa2-Preview` | ✅︎ | ✅︎ | | | -| `MammothModa2ForConditionalGeneration` | MammothModa2-Dev (AR-only image understanding) | `bytedance-research/MammothModa2-Dev` | ✅︎ | | | | -| `Flux2KleinPipeline` | FLUX.2-klein | `black-forest-labs/FLUX.2-klein-4B`, `black-forest-labs/FLUX.2-klein-9B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `FluxKontextPipeline` | FLUX.1-Kontext-dev | `black-forest-labs/FLUX.1-Kontext-dev` | ✅︎ | ✅︎ | | | -| `FluxPipeline` | FLUX.1-dev | `black-forest-labs/FLUX.1-dev` | ✅︎ | ✅︎ | | ✅︎ | -| `FluxPipeline` | FLUX.1-schnell | `black-forest-labs/FLUX.1-schnell` | ✅︎ | ✅︎ | | ✅︎ | -| `OmniGen2Pipeline` | OmniGen2 | `OmniGen2/OmniGen2` | ✅︎ | ✅︎ | | ✅︎ | -| `StableAudioPipeline` | Stable-Audio-Open | `stabilityai/stable-audio-open-1.0` | ✅︎ | ✅︎ | | ✅︎ | -| `SoulXSingerPipeline` | SoulX-Singer (SVS) | `Soul-AILab/SoulX-Singer` | ✅︎ | | | | -| `SoulXSingerSVCPipeline` | SoulX-Singer-SVC | `Soul-AILab/SoulX-Singer` (`model-svc.pt`) | ✅︎ | | | | -| `AudioXPipeline` | AudioX | `zhangj1an/AudioX` | ✅︎ | ✅︎ | | | -| `Qwen3TTSForConditionalGeneration` | Qwen3-TTS-12Hz-1.7B-CustomVoice | `Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `Qwen3TTSForConditionalGeneration` | Qwen3-TTS-12Hz-1.7B-VoiceDesign | `Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `Qwen3TTSForConditionalGeneration` | Qwen3-TTS-12Hz-1.7B-Base | `Qwen/Qwen3-TTS-12Hz-1.7B-Base` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -| `MingTTSForConditionalGeneration` | Ming-omni-tts dense 0.5B | `inclusionAI/Ming-omni-tts-0.5B` | ✅︎ | | | | -| `GLMTTSForConditionalGeneration` | GLM-TTS | `zai-org/GLM-TTS` | ✅︎ | | | | -| `MossTTSNanoForCausalLM` | MOSS-TTS-Nano | `OpenMOSS-Team/MOSS-TTS-Nano` | ✅︎ | | | | -| `MossTTSDelayModel` | MOSS-TTS, MOSS-TTSD, MOSS-SoundEffect, MOSS-VoiceGenerator | `OpenMOSS-Team/MOSS-VoiceGenerator` | ✅︎ | | | | -| `MossTTSRealtime` | MOSS-TTS-Realtime | `OpenMOSS-Team/MOSS-TTS-Realtime` | ✅︎ | | | | -| `HiggsAudioV2ForConditionalGeneration` | Higgs-Audio v2 | `bosonai/higgs-audio-v2-generation-3B-base` | ✅︎ | | | | -| `HiggsMultimodalQwen3ForConditionalGeneration` | Higgs-Audio v3 (TTS) | `bosonai/higgs-audio-v3-tts-4b` | ✅︎ | | | | -| `IndexTTS2TalkerForConditionalGeneration` | IndexTTS-2 | `IndexTeam/IndexTTS-2` | ✅︎ | | | | -| `NextStep11Pipeline` | NextStep-1.1 | `stepfun-ai/NextStep-1.1` | ✅︎ | ✅︎ | | ✅︎ | -| `MiMoAudioModel` | MiMo-Audio-7B-Instruct | `XiaomiMiMo/MiMo-Audio-7B-Instruct` | ✅︎ | ✅︎ | | | -| `MiMoV2ASRForCausalLM` | MiMo-V2.5-ASR | `XiaomiMiMo/MiMo-V2.5-ASR` | ✅︎ | ✅︎ | | | -| `Flux2Pipeline` | FLUX.2-dev | `black-forest-labs/FLUX.2-dev` | ✅︎ | ✅︎ | | | -| `FishSpeechSlowARForConditionalGeneration` | Fish Speech S2 Pro | `fishaudio/s2-pro` | ✅︎ | ✅︎ | | ✅︎ | -| `DreamIDOmniPipeline` | DreamID-Omni | `XuGuo699/DreamID-Omni` | ✅︎ | ✅︎ | | | -| `SenseNovaU1Pipeline` | SenseNova-U1 (DiT-only) | `SenseNova/SenseNova-U1-8B-MoT` | ✅︎ | | | | -| `LancePipeline` | Lance | `bytedance-research/Lance` | ✅︎ | | | | -| `HunyuanVideo15Pipeline` | HunyuanVideo-1.5-T2V | `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_t2v`, `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_t2v` | ✅︎ | ✅︎ | | | -| `HunyuanVideo15ImageToVideoPipeline` | HunyuanVideo-1.5-I2V | `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_i2v`, `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_i2v` | ✅︎ | ✅︎ | | | -| `VoxtralTTSForConditionalGeneration` | Voxtral TTS | `mistralai/Voxtral-4B-TTS-2603` | ✅︎ | ✅︎ | | | -| `CovoAudioForConditionalGeneration` | Covo-Audio-Chat | `tencent/Covo-Audio-Chat` | ✅︎ | | | | -|`DyninOmniForConditionalGeneration` | Dynin-Omni | `snu-aidas/Dynin-Omni` | ✅︎ | | | | -| `MiniCPMO45OmniForConditionalGeneration` | MiniCPM-o 4.5 | `openbmb/MiniCPM-o-4_5` | ✅︎ | | ✅︎ | | -| `ErnieImagePipeline` | ERNIE-Image | `baidu/ERNIE-Image`, `baidu/ERNIE-Image-Turbo` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | -|`HiDreamImagePipeline` | HiDream-I1-Full | `HiDream-ai/HiDream-I1-Full` | ✅︎ | ✅︎ | | | +| Architecture | Models | Example HF Models | NVIDIA GPU | AMD GPU | Ascend NPU | Intel GPU | Recipe | +|--------------|--------|-------------------|------------|---------|-----|-----------|--------| +| `Qwen3OmniMoeForConditionalGeneration` | Qwen3-Omni | `Qwen/Qwen3-Omni-30B-A3B-Instruct` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/Qwen/Qwen3-Omni.md) | +| `Qwen2_5OmniForConditionalGeneration` | Qwen2.5-Omni | `Qwen/Qwen2.5-Omni-7B`, `Qwen/Qwen2.5-Omni-3B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `MingFlashOmniForConditionalGeneration` + `MingImagePipeline` | Ming-flash-omni-2.0 (omni-speech + imagegen1) | `Jonathan1909/Ming-flash-omni-2.0` | ✅︎ | | | | — | +| `BagelForConditionalGeneration` | BAGEL (DiT-only) | `ByteDance-Seed/BAGEL-7B-MoT` | ✅︎ | ✅︎ | | ✅︎ | — | +| `InternVLAA1Pipeline` | InternVLA-A1 | `InternRobotics/InternVLA-A1-3B` | ✅︎ | ✅︎ | | | — | +| `Gr00tN1d7Pipeline` | GR00T N1.7 | `nvidia/GR00T-N1.7-3B` | ✅︎ | | | | — | +| `HunyuanImage3ForCausalMM` | HunyuanImage3.0 (DiT-only) | `tencent/HunyuanImage-3.0`, `tencent/HunyuanImage-3.0-Instruct` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `QwenImagePipeline` | Qwen-Image | `Qwen/Qwen-Image` | ✅︎ | | | | [Published](https://recipes.vllm.ai/Qwen/Qwen-Image) | +| `QwenImagePipeline` | Qwen-Image-2512 | `Qwen/Qwen-Image-2512` | ✅︎ | | | | [Repository](https://github.com/vllm-project/vllm-omni/blob/main/recipes/Qwen/Qwen-Image-2512.md) | +| `QwenImageEditPipeline` | Qwen-Image-Edit | `Qwen/Qwen-Image-Edit` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `QwenImageEditPlusPipeline` | Qwen-Image-Edit-2509 | `Qwen/Qwen-Image-Edit-2509` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `QwenImageLayeredPipeline` | Qwen-Image-Layered | `Qwen/Qwen-Image-Layered` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `QwenImageEditPlusPipeline` | Qwen-Image-Edit-2511 | `Qwen/Qwen-Image-Edit-2511` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `GlmImagePipeline` | GLM-Image | `zai-org/GLM-Image` | ✅︎ | ✅︎ | | | — | +| `ZImagePipeline` | Z-Image | `Tongyi-MAI/Z-Image-Turbo` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `Krea2Pipeline` | Krea 2 (Raw + Turbo) | `krea/Krea-2-Raw`, `krea/Krea-2-Turbo` | ✅︎ | | | | — | +| `WanPipeline` | Wan2.1-T2V, Wan2.2-T2V, Wan2.2-TI2V | `Wan-AI/Wan2.1-T2V-1.3B-Diffusers`, `Wan-AI/Wan2.1-T2V-14B-Diffusers`, `Wan-AI/Wan2.2-T2V-A14B-Diffusers`, `Wan-AI/Wan2.2-TI2V-5B-Diffusers` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `WanImageToVideoPipeline` | Wan2.2-I2V | `Wan-AI/Wan2.2-I2V-A14B-Diffusers` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `Cosmos3OmniDiffusersPipeline` | Cosmos3 T2I, T2V, I2V, V2V, T2V with sound, action policy | `nvidia/Cosmos3-Nano`, `nvidia/Cosmos3-Super` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `Wan22S2VPipeline` | Wan2.2-S2V | `Wan-AI/Wan2.2-S2V-14B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `Wan22VACEPipeline` | Wan2.1-VACE | `Wan-AI/Wan2.1-VACE-1.3B-diffusers`, `Wan-AI/Wan2.1-VACE-14B-diffusers` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `Wan22VACEPipeline` | Wan2.2-VACE | `Pyros13/Wan2.2-VACE-Fun-A14B-Diffusers` | ✅︎ | | | | — | +| `LTX2Pipeline` | LTX-2 / LTX-2.3 one-stage T2V and I2V | `Lightricks/LTX-2`, `diffusers/LTX-2.3-Diffusers` | ✅︎ | ✅︎ | | | — | +| `LTX2DistilledPipeline` | LTX-2 distilled two-stage T2V and I2V | `rootonchair/LTX-2-19b-distilled` | ✅︎ | ✅︎ | | | — | +| `LingBotVideoPipeline` | LingBot-Video dense and MoE T2I, T2V, TI2V | `robbyant/lingbot-video-dense-1.3b`, `robbyant/lingbot-video-moe-30b-a3b` | ✅︎ | | | | — | +| `MiniMaxH3Pipeline` | MiniMax H3 T2VA, first/last-keyframe FL2VA, and mixed-reference Ref2VA | `MiniMaxAI/MiniMax-H3` | ✅︎ | ✅︎ | | | [Published](https://recipes.vllm.ai/MiniMaxAI/MiniMax-H3) | +| `DreamZeroPipeline` | DreamZero-DROID | `GEAR-Dreams/DreamZero-DROID` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `HeliosPipeline`, `HeliosPyramidPipeline` | Helios | `BestWishYsh/Helios-Base`, `BestWishYsh/Helios-Mid`, `BestWishYsh/Helios-Distilled` | ✅︎ | ✅︎ | ✅︎ | | — | +| `MagiHumanPipeline` | MagiHuman | `SII-GAIR/daVinci-MagiHuman-Base-1080p` | ✅︎ | ✅︎ | | | — | +| `OvisImagePipeline` | Ovis-Image | `OvisAI/Ovis-Image` | ✅︎ | ✅︎ | | ✅︎ | — | +| `LongcatImagePipeline` | LongCat-Image | `meituan-longcat/LongCat-Image` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `LongCatImageEditPipeline` | LongCat-Image-Edit | `meituan-longcat/LongCat-Image-Edit` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `BooguImagePipeline` | Boogu-Image | `Boogu/Boogu-Image-0.1-Base`, `Boogu/Boogu-Image-0.1-Edit` | ✅︎ | | | | — | +| `StableDiffusionXLPipeline` | Stable-Diffusion-XL | `stabilityai/stable-diffusion-xl-base-1.0` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `StableDiffusion3Pipeline` | Stable-Diffusion-3 | `stabilityai/stable-diffusion-3.5-medium` | ✅︎ | ✅︎ | | ✅︎ | — | +| `CosyVoice3Model` | CosyVoice3 | `FunAudioLLM/Fun-CosyVoice3-0.5B-2512` | ✅︎ | ✅︎ | | ✅︎ | — | +| `OmniVoiceModel` | OmniVoice | `k2-fsa/OmniVoice` | ✅︎ | | | | — | +| `VoxCPM2TalkerForConditionalGeneration` | VoxCPM2 | `openbmb/VoxCPM2` | ✅︎ | | | | — | +| `MammothModa2ForConditionalGeneration` | MammothModa2-Preview | `bytedance-research/MammothModa2-Preview` | ✅︎ | ✅︎ | | | — | +| `MammothModa2ForConditionalGeneration` | MammothModa2-Dev (AR-only image understanding) | `bytedance-research/MammothModa2-Dev` | ✅︎ | | | | — | +| `Flux2KleinPipeline` | FLUX.2-klein | `black-forest-labs/FLUX.2-klein-4B`, `black-forest-labs/FLUX.2-klein-9B` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `FluxKontextPipeline` | FLUX.1-Kontext-dev | `black-forest-labs/FLUX.1-Kontext-dev` | ✅︎ | ✅︎ | | | — | +| `FluxPipeline` | FLUX.1-dev | `black-forest-labs/FLUX.1-dev` | ✅︎ | ✅︎ | | ✅︎ | — | +| `FluxPipeline` | FLUX.1-schnell | `black-forest-labs/FLUX.1-schnell` | ✅︎ | ✅︎ | | ✅︎ | — | +| `OmniGen2Pipeline` | OmniGen2 | `OmniGen2/OmniGen2` | ✅︎ | ✅︎ | | ✅︎ | — | +| `StableAudioPipeline` | Stable-Audio-Open | `stabilityai/stable-audio-open-1.0` | ✅︎ | ✅︎ | | ✅︎ | — | +| `SoulXSingerPipeline` | SoulX-Singer (SVS) | `Soul-AILab/SoulX-Singer` | ✅︎ | | | | — | +| `SoulXSingerSVCPipeline` | SoulX-Singer-SVC | `Soul-AILab/SoulX-Singer` (`model-svc.pt`) | ✅︎ | | | | — | +| `AudioXPipeline` | AudioX | `zhangj1an/AudioX` | ✅︎ | ✅︎ | | | — | +| `Qwen3TTSForConditionalGeneration` | Qwen3-TTS-12Hz-1.7B-CustomVoice | `Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice` | ✅︎ | | | | [Published](https://recipes.vllm.ai/Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice) | +| `Qwen3TTSForConditionalGeneration` | Qwen3-TTS-12Hz-1.7B-VoiceDesign | `Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `Qwen3TTSForConditionalGeneration` | Qwen3-TTS-12Hz-1.7B-Base | `Qwen/Qwen3-TTS-12Hz-1.7B-Base` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +| `MingTTSForConditionalGeneration` | Ming-omni-tts dense 0.5B | `inclusionAI/Ming-omni-tts-0.5B` | ✅︎ | | | | — | +| `GLMTTSForConditionalGeneration` | GLM-TTS | `zai-org/GLM-TTS` | ✅︎ | | | | — | +| `MossTTSNanoForCausalLM` | MOSS-TTS-Nano | `OpenMOSS-Team/MOSS-TTS-Nano` | ✅︎ | | | | — | +| `MossTTSDelayModel` | MOSS-TTS, MOSS-TTSD, MOSS-SoundEffect, MOSS-VoiceGenerator | `OpenMOSS-Team/MOSS-VoiceGenerator` | ✅︎ | | | | — | +| `MossTTSRealtime` | MOSS-TTS-Realtime | `OpenMOSS-Team/MOSS-TTS-Realtime` | ✅︎ | | | | — | +| `HiggsAudioV2ForConditionalGeneration` | Higgs-Audio v2 | `bosonai/higgs-audio-v2-generation-3B-base` | ✅︎ | | | | — | +| `HiggsMultimodalQwen3ForConditionalGeneration` | Higgs-Audio v3 (TTS) | `bosonai/higgs-audio-v3-tts-4b` | ✅︎ | | | | [Published](https://recipes.vllm.ai/bosonai/higgs-audio-v3-tts-4b) | +| `IndexTTS2TalkerForConditionalGeneration` | IndexTTS-2 | `IndexTeam/IndexTTS-2` | ✅︎ | | | | — | +| `NextStep11Pipeline` | NextStep-1.1 | `stepfun-ai/NextStep-1.1` | ✅︎ | ✅︎ | | ✅︎ | — | +| `MiMoAudioModel` | MiMo-Audio-7B-Instruct | `XiaomiMiMo/MiMo-Audio-7B-Instruct` | ✅︎ | ✅︎ | | | — | +| `MiMoV2ASRForCausalLM` | MiMo-V2.5-ASR | `XiaomiMiMo/MiMo-V2.5-ASR` | ✅︎ | ✅︎ | | | — | +| `Flux2Pipeline` | FLUX.2-dev | `black-forest-labs/FLUX.2-dev` | ✅︎ | ✅︎ | | | — | +| `FishSpeechSlowARForConditionalGeneration` | Fish Speech S2 Pro | `fishaudio/s2-pro` | ✅︎ | ✅︎ | | ✅︎ | — | +| `DreamIDOmniPipeline` | DreamID-Omni | `XuGuo699/DreamID-Omni` | ✅︎ | ✅︎ | | | — | +| `SenseNovaU1Pipeline` | SenseNova-U1 (DiT-only) | `SenseNova/SenseNova-U1-8B-MoT` | ✅︎ | | | | — | +| `LancePipeline` | Lance | `bytedance-research/Lance` | ✅︎ | | | | — | +| `HunyuanVideo15Pipeline` | HunyuanVideo-1.5-T2V | `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_t2v`, `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_t2v` | ✅︎ | ✅︎ | | | — | +| `HunyuanVideo15ImageToVideoPipeline` | HunyuanVideo-1.5-I2V | `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_i2v`, `hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_i2v` | ✅︎ | ✅︎ | | | — | +| `VoxtralTTSForConditionalGeneration` | Voxtral TTS | `mistralai/Voxtral-4B-TTS-2603` | ✅︎ | ✅︎ | | | — | +| `CovoAudioForConditionalGeneration` | Covo-Audio-Chat | `tencent/Covo-Audio-Chat` | ✅︎ | | | | — | +|`DyninOmniForConditionalGeneration` | Dynin-Omni | `snu-aidas/Dynin-Omni` | ✅︎ | | | | — | +| `MiniCPMO45OmniForConditionalGeneration` | MiniCPM-o 4.5 | `openbmb/MiniCPM-o-4_5` | ✅︎ | | ✅︎ | | — | +| `ErnieImagePipeline` | ERNIE-Image | `baidu/ERNIE-Image`, `baidu/ERNIE-Image-Turbo` | ✅︎ | ✅︎ | ✅︎ | ✅︎ | — | +|`HiDreamImagePipeline` | HiDream-I1-Full | `HiDream-ai/HiDream-I1-Full` | ✅︎ | ✅︎ | | | — | + +The `Recipe` column links the exact checkpoint/task entry from +[`recipe_coverage.yaml`](https://github.com/vllm-project/vllm-omni/blob/main/docs/models/recipe_coverage.yaml). +`Published` is preferred when a corresponding `recipes.vllm.ai` page exists; +otherwise the link points to the repository recipe. `—` means that the exact +checkpoint/task mapping has not been audited yet. + +For rows with an audited recipe link, the hardware checkmarks reflect hardware +explicitly documented in that recipe. Other rows retain the implementation +support metadata until their recipe coverage is audited. ✅︎ indicates the model is supported on that backend. Empty cells mean not listed as supported on that backend. +## Recipe and Example Coverage + +The table above describes implementation and backend support. It does not +imply that a model has a validated deployment recipe. + +Recipe and example coverage is tracked per exact Hugging Face checkpoint and +task in the machine-readable +[`recipe_coverage.yaml`](https://github.com/vllm-project/vllm-omni/blob/main/docs/models/recipe_coverage.yaml). +The registry is populated as coverage is audited and is the source of truth +for mapping exact checkpoints and tasks to links. Recipe files under +[`recipes/`](https://github.com/vllm-project/vllm-omni/tree/main/recipes) remain +the source of truth for commands and validation details. It uses the following +link precedence: + +1. `published`: link to the published `recipes.vllm.ai` page. +2. `repository`: link to the in-repository recipe until a published page exists. +3. `no_validated_recipe_yet`: show `No validated recipe yet` only when that + result has been explicitly audited. +4. A checkpoint/task without an entry: coverage has not been audited yet. + +Split entries whenever checkpoints, tasks, examples, or validation evidence +differ. A single Supported Models row may therefore map to multiple registry +entries. + H3 MiniMax H3 AMD GPU support is validated on gfx942 (MI300X) and gfx950 (MI350) in BF16, using the AITER `FLASH_ATTN` diffusion attention backend. Other AMD SKUs (e.g. MI325X) are not listed until their diff --git a/recipes/README.md b/recipes/README.md index a6015d9b0..005b62ce5 100644 --- a/recipes/README.md +++ b/recipes/README.md @@ -19,6 +19,12 @@ add files for this repo. Use one Markdown file per model family by default. > Individual pages resolve at `https://recipes.vllm.ai//`, > e.g. [`bosonai/higgs-audio-v3-tts-4b`](https://recipes.vllm.ai/bosonai/higgs-audio-v3-tts-4b). +The exact checkpoint/task mapping used by the Supported Models documentation +is tracked in +[`docs/models/recipe_coverage.yaml`](../docs/models/recipe_coverage.yaml). +This registry records link precedence; the recipe files in this directory +remain the source of truth for commands and validation details. + Example layout: ```text diff --git a/tests/docs/test_generate_examples.py b/tests/docs/test_generate_examples.py index 57d7d4832..34d7045f9 100644 --- a/tests/docs/test_generate_examples.py +++ b/tests/docs/test_generate_examples.py @@ -3,8 +3,10 @@ import importlib.util from pathlib import Path +from types import SimpleNamespace import pytest +import yaml pytestmark = [pytest.mark.core_model, pytest.mark.cpu] @@ -43,3 +45,113 @@ def test_model_display_names_require_string_mapping(tmp_path, monkeypatch): with pytest.raises(ValueError, match="MODEL_DISPLAY_NAMES_FILE"): generate_examples.load_model_display_names() + + +def test_quantization_examples_keep_source_urls_under_feature_navigation(tmp_path, monkeypatch): + nav_file = tmp_path / "docs" / ".nav.yml" + nav_file.parent.mkdir(parents=True) + nav_file.write_text( + yaml.safe_dump( + { + "nav": [ + { + "User Guide": [ + { + "Examples": [ + "examples/README.md", + {"Offline Inference": [{"Old": "user_guide/examples/offline_inference/old.md"}]}, + ] + }, + {"Features": [{"Quantization": [{"Overview": "user_guide/quantization/overview.md"}]}]}, + ] + } + ] + }, + sort_keys=False, + ), + encoding="utf-8", + ) + + monkeypatch.setattr(generate_examples, "ROOT_DIR", tmp_path) + monkeypatch.setattr(generate_examples, "NAV_FILE", nav_file) + monkeypatch.setattr(generate_examples, "EXAMPLE_DOC_DIR", tmp_path / "docs/user_guide/examples") + + quantization_example = SimpleNamespace( + category="quantization", + path=tmp_path / "examples/quantization/check_modelopt_fp8_export.py", + nav_title="Check Modelopt FP8 Export", + ) + offline_example = SimpleNamespace( + category="offline_inference", + path=tmp_path / "examples/offline_inference/demo.py", + nav_title="Demo", + ) + + generate_examples.update_nav_file([quantization_example, offline_example]) + generate_examples.update_nav_file([quantization_example, offline_example]) + + nav_data = yaml.safe_load(nav_file.read_text(encoding="utf-8")) + user_guide = nav_data["nav"][0]["User Guide"] + examples = next(item["Examples"] for item in user_guide if "Examples" in item) + features = next(item["Features"] for item in user_guide if "Features" in item) + quantization = next(item["Quantization"] for item in features if "Quantization" in item) + + assert not any(isinstance(item, dict) and "Quantization" in item for item in examples) + generated_examples = [ + item[generate_examples.GENERATED_QUANTIZATION_EXAMPLES_TITLE] + for item in quantization + if generate_examples.GENERATED_QUANTIZATION_EXAMPLES_TITLE in item + ] + assert len(generated_examples) == 1 + assert generated_examples[0] == [ + {"Check Modelopt FP8 Export": "user_guide/examples/quantization/check_modelopt_fp8_export.md"} + ] + + # A later build without quantization examples must not leave a stale + # generated group in the hand-authored Quantization section. + generate_examples.update_nav_file([offline_example]) + nav_data = yaml.safe_load(nav_file.read_text(encoding="utf-8")) + user_guide = nav_data["nav"][0]["User Guide"] + features = next(item["Features"] for item in user_guide if "Features" in item) + quantization = next(item["Quantization"] for item in features if "Quantization" in item) + assert not any( + isinstance(item, dict) and generate_examples.GENERATED_QUANTIZATION_EXAMPLES_TITLE in item + for item in quantization + ) + + +def test_quantization_examples_are_not_added_to_examples_without_feature_target(tmp_path, monkeypatch, caplog): + nav_file = tmp_path / "docs" / ".nav.yml" + nav_file.parent.mkdir(parents=True) + nav_file.write_text( + yaml.safe_dump( + { + "nav": [ + { + "User Guide": [ + {"Examples": ["examples/README.md"]}, + ] + } + ] + }, + sort_keys=False, + ), + encoding="utf-8", + ) + + monkeypatch.setattr(generate_examples, "ROOT_DIR", tmp_path) + monkeypatch.setattr(generate_examples, "NAV_FILE", nav_file) + monkeypatch.setattr(generate_examples, "EXAMPLE_DOC_DIR", tmp_path / "docs/user_guide/examples") + + quantization_example = SimpleNamespace( + category="quantization", + path=tmp_path / "examples/quantization/check_modelopt_fp8_export.py", + nav_title="Check Modelopt FP8 Export", + ) + + generate_examples.update_nav_file([quantization_example]) + + nav_data = yaml.safe_load(nav_file.read_text(encoding="utf-8")) + examples = nav_data["nav"][0]["User Guide"][0]["Examples"] + assert not any(isinstance(item, dict) and "Quantization" in item for item in examples) + assert "omitting generated quantization examples from navigation" in caplog.text diff --git a/tests/docs/test_recipe_coverage.py b/tests/docs/test_recipe_coverage.py new file mode 100644 index 000000000..6425dd4ad --- /dev/null +++ b/tests/docs/test_recipe_coverage.py @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project + +import re +from pathlib import Path + +import pytest +import yaml + +pytestmark = [pytest.mark.core_model, pytest.mark.cpu] + +ROOT_DIR = Path(__file__).parents[2] +COVERAGE_PATH = ROOT_DIR / "docs/models/recipe_coverage.yaml" +SUPPORTED_MODELS_PATH = ROOT_DIR / "docs/models/supported_models.md" +VALID_STATUSES = {"published", "repository", "no_validated_recipe_yet"} +VALID_HARDWARE = {"nvidia", "amd", "ascend", "intel"} +HARDWARE_COLUMNS = { + "nvidia": 4, + "amd": 5, + "ascend": 6, + "intel": 7, +} + + +def load_entries() -> list[dict]: + data = yaml.safe_load(COVERAGE_PATH.read_text(encoding="utf-8")) + assert data["version"] == 1 + assert isinstance(data["entries"], list) + return data["entries"] + + +def supported_model_ids() -> set[str]: + model_ids = set() + for line in SUPPORTED_MODELS_PATH.read_text(encoding="utf-8").splitlines(): + if not line.startswith("|"): + continue + columns = line.split("|") + if len(columns) <= 3: + continue + model_ids.update(re.findall(r"`([^`]+/[^`]+)`", columns[3])) + return model_ids + + +def supported_model_recipe_cells() -> dict[str, str]: + recipe_cells = {} + in_table = False + for line in SUPPORTED_MODELS_PATH.read_text(encoding="utf-8").splitlines(): + if line.startswith("| Architecture |"): + in_table = True + continue + if in_table and not line.startswith("|"): + break + if not in_table: + continue + + columns = line.split("|") + if len(columns) <= 8 or columns[1].strip().startswith("-"): + continue + for model_id in re.findall(r"`([^`]+/[^`]+)`", columns[3]): + recipe_cells[model_id] = columns[8].strip() + return recipe_cells + + +def expected_recipe_link(entry: dict) -> str: + recipe = entry["recipe"] + if recipe["status"] == "published": + return recipe["published_url"] + if recipe["status"] == "repository": + return f"https://github.com/vllm-project/vllm-omni/blob/main/{recipe['repository_path']}" + return "No validated recipe yet" + + +def supported_model_hardware_cells() -> dict[str, list[str]]: + hardware_cells = {} + in_table = False + for line in SUPPORTED_MODELS_PATH.read_text(encoding="utf-8").splitlines(): + if line.startswith("| Architecture |"): + in_table = True + continue + if in_table and not line.startswith("|"): + break + if not in_table: + continue + + columns = line.split("|") + if len(columns) <= 8 or columns[1].strip().startswith("-"): + continue + cells = [columns[index].strip() for index in HARDWARE_COLUMNS.values()] + for model_id in re.findall(r"`([^`]+/[^`]+)`", columns[3]): + hardware_cells[model_id] = cells + return hardware_cells + + +def test_registry_keys_are_exact_supported_checkpoints(): + entries = load_entries() + keys = [(entry["model"], entry["task"]) for entry in entries] + + assert len(keys) == len(set(keys)) + assert all(entry["model"] in supported_model_ids() for entry in entries) + + +def test_supported_models_render_registry_recipe_links(): + recipe_cells = supported_model_recipe_cells() + + for entry in load_entries(): + assert expected_recipe_link(entry) in recipe_cells[entry["model"]] + + +def test_registry_entries_have_explicit_recipe_precedence(): + for entry in load_entries(): + assert set(entry) >= {"model", "task", "examples", "recipe"} + assert isinstance(entry["examples"], list) + + recipe = entry["recipe"] + status = recipe["status"] + assert status in VALID_STATUSES + assert set(recipe.get("hardware", [])) <= VALID_HARDWARE + + if status == "published": + assert recipe["published_url"].startswith("https://recipes.vllm.ai/") + elif status == "repository": + assert recipe["repository_path"].startswith("recipes/") + assert "published_url" not in recipe + else: + assert "published_url" not in recipe + assert "repository_path" not in recipe + + paths = [*entry["examples"], recipe.get("repository_path")] + for relative_path in filter(None, paths): + path = Path(relative_path) + assert not path.is_absolute() + assert (ROOT_DIR / path).is_file(), relative_path + + +def test_supported_models_render_recipe_hardware(): + hardware_cells = supported_model_hardware_cells() + + for entry in load_entries(): + recipe_hardware = set(entry["recipe"].get("hardware", [])) + cells = hardware_cells[entry["model"]] + for hardware, cell in zip(HARDWARE_COLUMNS, cells, strict=True): + assert (cell == "✅︎") == (hardware in recipe_hardware)