Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eff452b7f1 | ||
|
|
573aadccf3 |
No files matched your search
+14
-4
@@ -16,21 +16,31 @@ nav:
|
|||||||
- Examples:
|
- Examples:
|
||||||
- examples/README.md
|
- examples/README.md
|
||||||
- Offline Inference:
|
- Offline Inference:
|
||||||
|
- GLM-Image Multistage End-to-End Inference: user_guide/examples/offline_inference/glm_image.md
|
||||||
|
- HunyuanImage-3.0 Image-to-Text Inference: user_guide/examples/offline_inference/hunyuan_image3.md
|
||||||
- Image-To-Image: user_guide/examples/offline_inference/image_to_image.md
|
- Image-To-Image: user_guide/examples/offline_inference/image_to_image.md
|
||||||
- Image-To-Video: user_guide/examples/offline_inference/image_to_video.md
|
- Image-To-Video: user_guide/examples/offline_inference/image_to_video.md
|
||||||
- Speech-To-Video: user_guide/examples/offline_inference/speech_to_video.md
|
- InternVLA-A1: user_guide/examples/offline_inference/internvla_a1.md
|
||||||
|
- MiMo-Audio: user_guide/examples/offline_inference/mimo_audio.md
|
||||||
|
- Qwen2.5-Omni: user_guide/examples/offline_inference/qwen2_5_omni.md
|
||||||
|
- Qwen3-Omni: user_guide/examples/offline_inference/qwen3_omni.md
|
||||||
- Text-To-Audio: user_guide/examples/offline_inference/text_to_audio.md
|
- Text-To-Audio: user_guide/examples/offline_inference/text_to_audio.md
|
||||||
- Text-To-Image: user_guide/examples/offline_inference/text_to_image.md
|
- Text-To-Image: user_guide/examples/offline_inference/text_to_image.md
|
||||||
- Text-To-Speech: user_guide/examples/offline_inference/text_to_speech.md
|
- Text-To-Speech: user_guide/examples/offline_inference/text_to_speech.md
|
||||||
- Text-To-Video: user_guide/examples/offline_inference/text_to_video.md
|
- Text-To-Video: user_guide/examples/offline_inference/text_to_video.md
|
||||||
- X-To-Text: user_guide/examples/offline_inference/x_to_text.md
|
|
||||||
- X-To-Video-Audio: user_guide/examples/offline_inference/x_to_video_audio.md
|
- X-To-Video-Audio: user_guide/examples/offline_inference/x_to_video_audio.md
|
||||||
- Online Serving:
|
- Online Serving:
|
||||||
|
- BAGEL-7B-MoT: user_guide/examples/online_serving/bagel.md
|
||||||
|
- vLLM-Omni Helm Chart: user_guide/examples/online_serving/chart-helm.md
|
||||||
|
- Diffusers Backend Adapter: user_guide/examples/online_serving/diffusers_pipeline_adapter.md
|
||||||
|
- GLM-Image Online Serving: user_guide/examples/online_serving/glm_image.md
|
||||||
- Image-To-Image: user_guide/examples/online_serving/image_to_image.md
|
- Image-To-Image: user_guide/examples/online_serving/image_to_image.md
|
||||||
- Image-To-Video: user_guide/examples/online_serving/image_to_video.md
|
- Image-To-Video: user_guide/examples/online_serving/image_to_video.md
|
||||||
- Speech-To-Video: user_guide/examples/online_serving/speech_to_video.md
|
- MiMo-Audio: user_guide/examples/online_serving/mimo_audio.md
|
||||||
- Text-To-Image: user_guide/examples/online_serving/text_to_image.md
|
- Qwen2.5-Omni: user_guide/examples/online_serving/qwen2_5_omni.md
|
||||||
|
- Qwen3-Omni: user_guide/examples/online_serving/qwen3_omni.md
|
||||||
- Text-To-Speech: user_guide/examples/online_serving/text_to_speech.md
|
- Text-To-Speech: user_guide/examples/online_serving/text_to_speech.md
|
||||||
|
- Text-To-Image: user_guide/examples/online_serving/text_to_image.md
|
||||||
- Text-To-Video: user_guide/examples/online_serving/text_to_video.md
|
- Text-To-Video: user_guide/examples/online_serving/text_to_video.md
|
||||||
- General:
|
- General:
|
||||||
- usage/*
|
- usage/*
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ status: draft
|
|||||||
owners:
|
owners:
|
||||||
- "@yuanheng-zhao"
|
- "@yuanheng-zhao"
|
||||||
- "@Isotr0py"
|
- "@Isotr0py"
|
||||||
|
- "@lishunyang12"
|
||||||
primary_code_paths:
|
primary_code_paths:
|
||||||
- vllm_omni/diffusion/offloader/**
|
- vllm_omni/diffusion/offloader/**
|
||||||
related_code_paths:
|
related_code_paths:
|
||||||
|
|||||||
@@ -24,22 +24,15 @@ SERVING_MODE_TITLES = {
|
|||||||
"online_serving": "Online serving",
|
"online_serving": "Online serving",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Keep the Examples navigation focused on reusable modality/task entry points.
|
# Generated example pages keep their source-derived URLs even when their
|
||||||
# Model-specific scripts remain available under ``examples/`` and are surfaced
|
# navigation category changes. Quantization helpers are feature documentation,
|
||||||
# from these shared pages instead of getting one page per model.
|
# not user-serving examples, so keep them under the existing Features /
|
||||||
GENERAL_EXAMPLE_SLUGS = frozenset(
|
# Quantization section instead of creating a second top-level Quantization
|
||||||
{
|
# category under Examples.
|
||||||
"image_to_image",
|
EXAMPLE_NAV_TARGETS = {
|
||||||
"image_to_video",
|
"quantization": "quantization",
|
||||||
"speech_to_video",
|
}
|
||||||
"text_to_audio",
|
GENERATED_QUANTIZATION_EXAMPLES_TITLE = "Generated Examples"
|
||||||
"text_to_image",
|
|
||||||
"text_to_speech",
|
|
||||||
"text_to_video",
|
|
||||||
"x_to_text",
|
|
||||||
"x_to_video_audio",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def load_model_display_names() -> dict[str, str]:
|
def load_model_display_names() -> dict[str, str]:
|
||||||
@@ -63,13 +56,6 @@ def load_model_display_names() -> dict[str, str]:
|
|||||||
MODEL_DISPLAY_NAMES = load_model_display_names()
|
MODEL_DISPLAY_NAMES = load_model_display_names()
|
||||||
|
|
||||||
|
|
||||||
def is_general_example(example: "Example") -> bool:
|
|
||||||
"""Return whether an example should get a generated serving page."""
|
|
||||||
if example.category not in SERVING_MODE_TITLES:
|
|
||||||
return True
|
|
||||||
return example.path.stem in GENERAL_EXAMPLE_SLUGS
|
|
||||||
|
|
||||||
|
|
||||||
def fix_case(text: str) -> str:
|
def fix_case(text: str) -> str:
|
||||||
subs = {
|
subs = {
|
||||||
"api": "API",
|
"api": "API",
|
||||||
@@ -372,9 +358,12 @@ def update_nav_file(examples: list[Example]):
|
|||||||
items.append({example.nav_title: rel_path.as_posix()})
|
items.append({example.nav_title: rel_path.as_posix()})
|
||||||
return items
|
return items
|
||||||
|
|
||||||
# Build the new Examples section - start with preserved items.
|
# Build the new Examples section - start with preserved items. Categories
|
||||||
|
# not explicitly routed elsewhere retain the historical Examples behavior.
|
||||||
examples_section = preserved_items.copy()
|
examples_section = preserved_items.copy()
|
||||||
for category in sorted(examples_by_category.keys()):
|
for category in sorted(examples_by_category.keys()):
|
||||||
|
if EXAMPLE_NAV_TARGETS.get(category, "examples") != "examples":
|
||||||
|
continue
|
||||||
items = category_items(category)
|
items = category_items(category)
|
||||||
if items:
|
if items:
|
||||||
category_title = fix_case(category.replace("_", " ").title())
|
category_title = fix_case(category.replace("_", " ").title())
|
||||||
@@ -383,6 +372,36 @@ def update_nav_file(examples: list[Example]):
|
|||||||
# Update the nav structure
|
# Update the nav structure
|
||||||
nav_list[user_guide_idx]["User Guide"][examples_idx]["Examples"] = examples_section
|
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
|
# Write back to file
|
||||||
nav_data["nav"] = nav_list
|
nav_data["nav"] = nav_list
|
||||||
with open(NAV_FILE, "w", encoding="utf-8") as f:
|
with open(NAV_FILE, "w", encoding="utf-8") as f:
|
||||||
@@ -413,8 +432,6 @@ def on_startup(command: Literal["build", "gh-deploy", "serve"], dirty: bool):
|
|||||||
for path in category.glob("*/*.md"):
|
for path in category.glob("*/*.md"):
|
||||||
examples.append(Example(path.parent, category.stem))
|
examples.append(Example(path.parent, category.stem))
|
||||||
|
|
||||||
examples = [example for example in examples if is_general_example(example)]
|
|
||||||
|
|
||||||
# Generate the example documentation
|
# Generate the example documentation
|
||||||
for example in sorted(examples, key=lambda e: e.path.stem):
|
for example in sorted(examples, key=lambda e: e.path.stem):
|
||||||
example_name = f"{example.path.stem}.md"
|
example_name = f"{example.path.stem}.md"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from pathlib import Path
|
|||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import yaml
|
||||||
|
|
||||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||||
|
|
||||||
@@ -46,9 +47,111 @@ def test_model_display_names_require_string_mapping(tmp_path, monkeypatch):
|
|||||||
generate_examples.load_model_display_names()
|
generate_examples.load_model_display_names()
|
||||||
|
|
||||||
|
|
||||||
def test_only_general_serving_examples_get_generated_pages():
|
def test_quantization_examples_keep_source_urls_under_feature_navigation(tmp_path, monkeypatch):
|
||||||
general_example = SimpleNamespace(category="offline_inference", path=Path("text_to_image"))
|
nav_file = tmp_path / "docs" / ".nav.yml"
|
||||||
model_example = SimpleNamespace(category="offline_inference", path=Path("qwen3_omni"))
|
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",
|
||||||
|
)
|
||||||
|
|
||||||
assert generate_examples.is_general_example(general_example)
|
monkeypatch.setattr(generate_examples, "ROOT_DIR", tmp_path)
|
||||||
assert not generate_examples.is_general_example(model_example)
|
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
|
||||||
Reference in new issue
Block a user