Compare commits
158
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
327a5dc66f | ||
|
|
5bdbeb3c0d | ||
|
|
b544cc75d3 | ||
|
|
d174d2f47b | ||
|
|
a1866083a0 | ||
|
|
df8f02376d | ||
|
|
17b737914b | ||
|
|
e74d029380 | ||
|
|
bf42971416 | ||
|
|
32a81111bd | ||
|
|
5bb16af8ee | ||
|
|
74d284acba | ||
|
|
605b68cc5f | ||
|
|
b4179a9c1c | ||
|
|
6d0b758dbe | ||
|
|
02b6af44ec | ||
|
|
4386562f9b | ||
|
|
203039e054 | ||
|
|
68e0fd7cad | ||
|
|
8978302a1b | ||
|
|
310de75408 | ||
|
|
2932407f82 | ||
|
|
36dce4e4f7 | ||
|
|
10df2a03d0 | ||
|
|
05210fb2db | ||
|
|
2ff0a783d4 | ||
|
|
698f8c13d9 | ||
|
|
5d81c3678b | ||
|
|
d8995de9ec | ||
|
|
a571b1b516 | ||
|
|
bc168a3ee2 | ||
|
|
6af714cf9b | ||
|
|
11c1a56467 | ||
|
|
3b4469a136 | ||
|
|
855dd31f07 | ||
|
|
afd3f8c716 | ||
|
|
e5aaf3186c | ||
|
|
76941854b1 | ||
|
|
7aaf9f3590 | ||
|
|
4d6124f320 | ||
|
|
f04fdf79da | ||
|
|
d71d39f656 | ||
|
|
1949c31f80 | ||
|
|
ea373e3cbf | ||
|
|
e4a4477929 | ||
|
|
152d67ab86 | ||
|
|
bd39e903e1 | ||
|
|
d5c1f2bdc1 | ||
|
|
36ef53d9b1 | ||
|
|
e5c4449a8f | ||
|
|
60d07a8afd | ||
|
|
ddb8635cfe | ||
|
|
c5f47b22fd | ||
|
|
5dd5d70671 | ||
|
|
752357d318 | ||
|
|
48646da78e | ||
|
|
9df5ac8836 | ||
|
|
b796c787ec | ||
|
|
e6ea35ca12 | ||
|
|
10ae2818c7 | ||
|
|
fa5aadca6f | ||
|
|
0a41206e1f | ||
|
|
13cc723c71 | ||
|
|
445ca92ef1 | ||
|
|
bb8735effc | ||
|
|
8569995591 | ||
|
|
34beb7f01e | ||
|
|
4fee1dbe39 | ||
|
|
54c086acae | ||
|
|
03d6cb9a93 | ||
|
|
34295f3eb3 | ||
|
|
10221f0665 | ||
|
|
b29a6ca99f | ||
|
|
a8fdb1babf | ||
|
|
0d00ba4701 | ||
|
|
8a4559c46c | ||
|
|
2f5d0edcf7 | ||
|
|
3f2cd52939 | ||
|
|
c0deaa76ba | ||
|
|
2d8b1d4583 | ||
|
|
e0142926b6 | ||
|
|
b039b6a5bd | ||
|
|
75b65f859b | ||
|
|
ab2f2a3d65 | ||
|
|
1887d8294b | ||
|
|
5c75d5bb0a | ||
|
|
723c550209 | ||
|
|
00510ce38b | ||
|
|
97d97b6503 | ||
|
|
502dd7bed0 | ||
|
|
d4c097531d | ||
|
|
1baabdc78b | ||
|
|
54a6787bde | ||
|
|
8dfc8156bc | ||
|
|
33de5d8629 | ||
|
|
4e3e8a1ebc | ||
|
|
3834de3105 | ||
|
|
99ebfbbd04 | ||
|
|
9264ff81ab | ||
|
|
b36a3431bd | ||
|
|
289c13df68 | ||
|
|
ee2129e2fa | ||
|
|
df3bbfe675 | ||
|
|
bc865385a8 | ||
|
|
6d7b2bfc1c | ||
|
|
6bad5a7cd4 | ||
|
|
f3629320e7 | ||
|
|
27b9400750 | ||
|
|
cab5ef7010 | ||
|
|
a7e6c412ab | ||
|
|
a51461c131 | ||
|
|
bc7f8237e3 | ||
|
|
c4e61133fb | ||
|
|
c440616c8b | ||
|
|
ca4dd105e4 | ||
|
|
5f27f60bde | ||
|
|
f5d3bfcf93 | ||
|
|
3dac97e0bd | ||
|
|
7869a8dc0d | ||
|
|
9a4f295625 | ||
|
|
67bee59fda | ||
|
|
658341531a | ||
|
|
e4a565b3df | ||
|
|
73cdc7395a | ||
|
|
9502d3cef7 | ||
|
|
3085f50160 | ||
|
|
82955b3a22 | ||
|
|
94485152d2 | ||
|
|
6ce8de1b28 | ||
|
|
936c10be4b | ||
|
|
abf81f4114 | ||
|
|
f9d2cab3bc | ||
|
|
565f7475c7 | ||
|
|
c893b638ad | ||
|
|
380e8022dd | ||
|
|
78a30b7562 | ||
|
|
b22dabe270 | ||
|
|
0356b22e4c | ||
|
|
5104fb6d67 | ||
|
|
b8d1e44ebe | ||
|
|
15bb6133a3 | ||
|
|
66319ed159 | ||
|
|
a786a88919 | ||
|
|
536866b916 | ||
|
|
fa8b1a878e | ||
|
|
580a201631 | ||
|
|
37c0ea9a6b | ||
|
|
74acd66307 | ||
|
|
602e39647e | ||
|
|
285db2fa3c | ||
|
|
8e912db6c8 | ||
|
|
49a839ecf9 | ||
|
|
35e43b9983 | ||
|
|
55192de984 | ||
|
|
073d31b9cd | ||
|
|
f804bbd679 | ||
|
|
b22dcc59f7 | ||
|
|
b70207f57f |
No files matched your search
@@ -60,8 +60,7 @@ resolve_test_specs() {
|
||||
if ! selected_specs=$(python3 "$AMD_SUITE_SELECTOR" \
|
||||
--branch "$BUILDKITE_BRANCH" \
|
||||
--labels "$PR_LABELS" \
|
||||
--debug-test-yaml "${DEBUG_TEST_YAML:-}" \
|
||||
--nightly "$NIGHTLY"); then
|
||||
--debug-test-yaml "${DEBUG_TEST_YAML:-}"); then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -81,12 +80,6 @@ filter_test_specs_by_skip_ci() {
|
||||
case "$suite_spec" in
|
||||
READY_TESTS:*) level="l2" ;;
|
||||
MERGE_TESTS:*) level="l3" ;;
|
||||
NIGHTLY_TESTS:*)
|
||||
# Explicit PR and scheduled nightly selections must survive
|
||||
# L2/L3 diff gating, including docs-only main commits.
|
||||
runnable_specs+=("$suite_spec")
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown AMD test suite spec '$suite_spec'" >&2
|
||||
exit 1
|
||||
@@ -108,7 +101,7 @@ filter_test_specs_by_skip_ci() {
|
||||
":memo: CI skipped — docs or pytest skip-mark changes only" \
|
||||
--style "info" 2>/dev/null || true
|
||||
fi
|
||||
echo "No AMD suites remain after skip-ci filtering."
|
||||
echo "No AMD L2/L3 suites remain after skip-ci filtering."
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
@@ -226,8 +219,8 @@ if [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||
file_diff=$(get_diff_main)
|
||||
fi
|
||||
|
||||
# Resolve PR tier labels before skip-ci so ready/merge suites can be filtered
|
||||
# independently while an explicitly selected nightly suite passes through.
|
||||
# Resolve PR tier labels before skip-ci so ready and merge suites can be
|
||||
# filtered independently for CI-YAML-only changes.
|
||||
resolve_test_specs
|
||||
filter_test_specs_by_skip_ci
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Build and push the ROCm CI image with a registry-backed BuildKit cache. The
|
||||
# AMD builders are ephemeral, so a local Docker cache cannot survive between
|
||||
# jobs. Keeping the cache beside the runtime image also reuses the registry
|
||||
# credentials already configured on the amd-cpu agents.
|
||||
|
||||
REGISTRY="${ROCM_CI_IMAGE_REGISTRY:-rocm/vllm-omni}"
|
||||
DOCKERFILE="docker/Dockerfile.rocm"
|
||||
BUILDER_NAME="vllm-omni-rocm-builder"
|
||||
ROCM_ARCH="${PYTORCH_ROCM_ARCH:-gfx942}"
|
||||
|
||||
if [[ -z "${BUILDKITE_COMMIT:-}" ]]; then
|
||||
echo "ERROR: BUILDKITE_COMMIT is not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dependency_files=(
|
||||
"$DOCKERFILE"
|
||||
"${DOCKERFILE}.dockerignore"
|
||||
pyproject.toml
|
||||
setup.py
|
||||
tools/install_torchcodec_rocm.sh
|
||||
)
|
||||
while IFS= read -r dependency_file; do
|
||||
dependency_files+=("$dependency_file")
|
||||
done < <(find requirements -maxdepth 1 -type f -name '*.txt' -print | LC_ALL=C sort)
|
||||
|
||||
for dependency_file in "${dependency_files[@]}"; do
|
||||
if [[ ! -f "$dependency_file" ]]; then
|
||||
echo "ERROR: cache-key input does not exist: $dependency_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
CACHE_KEY=$(
|
||||
{
|
||||
printf 'rocm-arch=%s\n' "$ROCM_ARCH"
|
||||
for dependency_file in "${dependency_files[@]}"; do
|
||||
printf 'path=%s\n' "$dependency_file"
|
||||
sha256sum "$dependency_file"
|
||||
done
|
||||
} | sha256sum | cut -c1-16
|
||||
)
|
||||
CACHE_REF="${REGISTRY}:rocm-deps-cache-${CACHE_KEY}"
|
||||
IMAGE_REF="${REGISTRY}:${BUILDKITE_COMMIT}"
|
||||
|
||||
echo "ROCm dependency cache: ${CACHE_REF}"
|
||||
echo "ROCm CI image: ${IMAGE_REF}"
|
||||
|
||||
# The docker-container driver supports exporting the full cache to a registry;
|
||||
# the default docker driver on CI does not.
|
||||
if ! docker buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then
|
||||
docker buildx create --name "$BUILDER_NAME" --driver docker-container
|
||||
fi
|
||||
docker buildx use "$BUILDER_NAME"
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
docker buildx build --push --pull --progress=plain \
|
||||
--target test \
|
||||
--build-arg "ARG_PYTORCH_ROCM_ARCH=${ROCM_ARCH}" \
|
||||
--cache-from "type=registry,ref=${CACHE_REF}" \
|
||||
--cache-to "type=registry,ref=${CACHE_REF},mode=max,compression=zstd,ignore-error=true" \
|
||||
--file "$DOCKERFILE" \
|
||||
--tag "$IMAGE_REF" .
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Select AMD ready/merge/nightly suites after Buildkite creates a build.
|
||||
"""Select AMD L2/L3 suites after Buildkite has created an AMD build.
|
||||
|
||||
This repository-side selector does not decide which GitHub label events start
|
||||
the external ``vllm-omni-amd-ci`` pipeline. Its Buildkite PR build condition
|
||||
@@ -17,7 +17,6 @@ from collections.abc import Iterable
|
||||
SUITE_SPECS = {
|
||||
"ready": "READY_TESTS:test-amd-ready.yml",
|
||||
"merge": "MERGE_TESTS:test-amd-merge.yml",
|
||||
"nightly": "NIGHTLY_TESTS:test-amd-nightly.yml",
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +28,7 @@ def _parse_debug_suites(value: str) -> tuple[str, ...]:
|
||||
seen: set[str] = set()
|
||||
for suite in suites:
|
||||
if suite not in SUITE_SPECS:
|
||||
raise ValueError(f"DEBUG_TEST_YAML entries must be 'merge', 'nightly', or 'ready', got {suite!r}")
|
||||
raise ValueError(f"DEBUG_TEST_YAML entries must be 'merge' or 'ready', got {suite!r}")
|
||||
if suite in seen:
|
||||
raise ValueError(f"duplicate DEBUG_TEST_YAML suite {suite!r}")
|
||||
seen.add(suite)
|
||||
@@ -41,27 +40,18 @@ def select_amd_test_suites(
|
||||
branch: str,
|
||||
labels: Iterable[str],
|
||||
debug_test_yaml: str = "",
|
||||
nightly: bool = False,
|
||||
) -> tuple[str, ...]:
|
||||
"""Return ordered suite names while preserving legacy unlabeled PRs."""
|
||||
|
||||
if debug_test_yaml:
|
||||
return _parse_debug_suites(debug_test_yaml)
|
||||
if branch == "main":
|
||||
return ("nightly",) if nightly else ("merge",)
|
||||
return ("merge",)
|
||||
|
||||
label_set = {label.strip() for label in labels if label.strip()}
|
||||
selected = tuple(
|
||||
suite
|
||||
for label, suite in (
|
||||
("ready", "ready"),
|
||||
("merge-test", "merge"),
|
||||
("nightly-test", "nightly"),
|
||||
)
|
||||
if label in label_set
|
||||
)
|
||||
# AMD historically uploaded the ready suite for every admitted PR build.
|
||||
# Preserve that fallback when no explicit tier label is present.
|
||||
selected = tuple(suite for label, suite in (("ready", "ready"), ("merge-test", "merge")) if label in label_set)
|
||||
# AMD historically uploaded L2 for every PR build. Keep that behavior for
|
||||
# triggers such as amd-test while adding tier selection for ready/merge-test.
|
||||
return selected or ("ready",)
|
||||
|
||||
|
||||
@@ -70,7 +60,6 @@ def main() -> int:
|
||||
parser.add_argument("--branch", required=True)
|
||||
parser.add_argument("--labels", default="")
|
||||
parser.add_argument("--debug-test-yaml", default="")
|
||||
parser.add_argument("--nightly", type=int, choices=(0, 1), default=0)
|
||||
args = parser.parse_args()
|
||||
|
||||
labels = tuple(args.labels.splitlines())
|
||||
@@ -79,15 +68,19 @@ def main() -> int:
|
||||
branch=args.branch,
|
||||
labels=labels,
|
||||
debug_test_yaml=args.debug_test_yaml,
|
||||
nightly=bool(args.nightly),
|
||||
)
|
||||
except ValueError as exc:
|
||||
parser.error(str(exc))
|
||||
|
||||
label_set = {label.strip() for label in labels if label.strip()}
|
||||
if args.branch != "main" and not args.debug_test_yaml and not ({"ready", "merge-test", "nightly-test"} & label_set):
|
||||
if not args.debug_test_yaml and args.branch != "main" and not ({"ready", "merge-test"} & label_set):
|
||||
print(
|
||||
"No AMD ready/merge/nightly label found; preserving the legacy ready-suite fallback.",
|
||||
"No AMD L2/L3 tier label found; preserving the legacy ready-suite fallback.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
if "nightly-test" in label_set:
|
||||
print(
|
||||
"AMD nightly-test has no suite yet and does not affect L2/L3 selection.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
|
||||
@@ -9,26 +9,15 @@ steps:
|
||||
steps:
|
||||
- label: "Simple · Model Executor Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 3
|
||||
parallelism: 2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu and not omni' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Omni Processor Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- "pytest -sv tests/model_executor/models/test_omni_processing.py -m 'core_model and cpu and omni'"
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Diffusion Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
@@ -36,7 +25,6 @@ steps:
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 45
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
# AMD MI300 `full_model` nightly coverage during burn-in.
|
||||
# All jobs are non-blocking until the lane has stable runtime evidence.
|
||||
# Historical build #11646 was red in Function Expansion and Accuracy (one
|
||||
# async_chunk similarity mismatch; Seed-TTS WER 0.376480 > 0.35).
|
||||
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
# MI325 is the repository's legacy ROCm pytest marker. The AMD template maps
|
||||
# agent_pool to the current MI300 Buildkite queues independently of that mark.
|
||||
- group: ":full_moon: Qwen3-Omni MI300 Nightly"
|
||||
steps:
|
||||
- label: "Qwen3-Omni Function Expansion"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni_expansion.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model"
|
||||
|
||||
- label: "Qwen3-Omni Accuracy"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json
|
||||
commands:
|
||||
- export SEED_TTS_WER_EVAL=1
|
||||
# PyTorch ROCm uses the torch.cuda device namespace.
|
||||
- export SEED_TTS_EVAL_DEVICE=cuda:1
|
||||
- pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model"
|
||||
# Native tests run from the image copy under /app/vllm-omni, while
|
||||
# Buildkite's artifact hook searches the checkout workspace.
|
||||
- |
|
||||
if [[ "$$PWD" != "$${BUILDKITE_BUILD_CHECKOUT_PATH:?}" ]]; then
|
||||
artifact_dir="$${BUILDKITE_BUILD_CHECKOUT_PATH}/tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc"
|
||||
mkdir -p "$$artifact_dir"
|
||||
cp -v tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json "$$artifact_dir/"
|
||||
fi
|
||||
|
||||
- label: "Qwen3-Omni Documentation Examples"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/examples/online_serving/test_qwen3_omni.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model"
|
||||
|
||||
- label: "Qwen3-Omni AITER-on Smoke"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=1
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni_expansion.py::test_text_to_text_audio_001 -m "full_model and rocm and MI325 and cards_2" --run-level "full_model"
|
||||
@@ -9,39 +9,26 @@ steps:
|
||||
steps:
|
||||
- label: "Simple · Model Executor Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 3
|
||||
parallelism: 2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu and not omni' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Omni Processor Test"
|
||||
- label: "Simple · Diffusion Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- "pytest -sv tests/model_executor/models/test_omni_processing.py -m 'core_model and cpu and omni'"
|
||||
|
||||
- label: "Simple · Diffusion Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 4
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 45
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "pytest -sv tests/diffusion -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
- "pytest -sv tests/diffusion -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py"
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
agent_pool: mi300_1
|
||||
@@ -82,27 +69,6 @@ steps:
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
steps:
|
||||
# Keep real FlashAttention execution out of the CPU-marked Simple lane.
|
||||
# AITER may need to build several kernels on a cold worker, so run one
|
||||
# pytest worker with job-local build directories and a bounded timeout.
|
||||
- label: "ROCm · FlashAttention/AITER GPU Coverage"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=1
|
||||
- export AITER_JIT_DIR="/tmp/vllm-omni-aiter-$$BUILDKITE_JOB_ID"
|
||||
- export TORCH_EXTENSIONS_DIR="/tmp/vllm-omni-torch-extensions-$$BUILDKITE_JOB_ID"
|
||||
- mkdir -p "$$AITER_JIT_DIR" "$$TORCH_EXTENSIONS_DIR"
|
||||
- >-
|
||||
timeout --signal=TERM --kill-after=2m 55m
|
||||
pytest -s -v -n 1
|
||||
tests/diffusion/attention/
|
||||
-m 'core_model and rocm and MI325 and cards_1'
|
||||
--run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Batch Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
@@ -194,39 +160,6 @@ steps:
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - timeout 20m pytest -s -v tests/e2e/offline_inference/test_stable_audio_expansion.py -m "advanced_model and diffusion and L4" --run-level advanced_model
|
||||
|
||||
- label: "ROCm · Engine & Model Executor GPU Coverage (R2-01)"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 20
|
||||
artifact_paths:
|
||||
- "artifacts/rocm-r2-01/**/*"
|
||||
commands:
|
||||
# Native AMD tests run from /app/vllm-omni, while Buildkite uploads
|
||||
# artifacts relative to its checkout directory.
|
||||
- export R2_01_ARTIFACT_DIR="$$BUILDKITE_BUILD_CHECKOUT_PATH/artifacts/rocm-r2-01"
|
||||
- mkdir -p "$$R2_01_ARTIFACT_DIR"
|
||||
# The CUDA ready job also covers tests/worker/test_batched_omni_output.py.
|
||||
# Keep the initial ROCm burn-in scoped to the requested directories.
|
||||
# Verbose pytest output and JUnit retain node IDs without a second
|
||||
# collection-only pass over the same GPU-backed test tree.
|
||||
# The CUDA/L4-only CosyVoice3 ragged-flow parity test cold-JITs multiple
|
||||
# AITER kernels on ROCm and is covered by the CUDA ready lane.
|
||||
- >-
|
||||
pytest -s -v -ra
|
||||
tests/engine/ tests/model_executor/
|
||||
-m 'core_model and cuda and not
|
||||
(cards_2 or cards_3 or cards_4 or cards_5 or cards_6 or cards_7 or cards_8)'
|
||||
-k 'not test_code2wav_streaming_batch_matches_ragged_flow_numerics'
|
||||
--run-level "core_model"
|
||||
--durations=0
|
||||
--junitxml="$$R2_01_ARTIFACT_DIR/pytest.xml"
|
||||
2>&1 | tee "$$R2_01_ARTIFACT_DIR/pytest.log"
|
||||
- >-
|
||||
tail -n 100 "$$R2_01_ARTIFACT_DIR/pytest.log" >
|
||||
"$$R2_01_ARTIFACT_DIR/pytest-summary.txt"
|
||||
|
||||
- label: "Engine Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
@@ -239,71 +172,6 @@ steps:
|
||||
pytest -s -v tests/engine/test_async_omni_engine_abort.py
|
||||
'
|
||||
|
||||
- label: "ROCm · Entrypoints GPU Coverage (R2-02)"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 30
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
artifact_paths:
|
||||
- "artifacts/rocm-r2-02/**/*"
|
||||
commands:
|
||||
# Native AMD tests run from /app/vllm-omni, while Buildkite uploads
|
||||
# artifacts relative to its checkout directory.
|
||||
- export R2_02_ARTIFACT_DIR="$$BUILDKITE_BUILD_CHECKOUT_PATH/artifacts/rocm-r2-02"
|
||||
- mkdir -p "$$R2_02_ARTIFACT_DIR"
|
||||
- >-
|
||||
ps -eo pid=,ppid=,lstart=,stat=,comm= >
|
||||
"$$R2_02_ARTIFACT_DIR/processes-before.txt"
|
||||
# Verbose pytest output and JUnit retain selected node IDs without a
|
||||
# second collection-only pass over the same GPU-backed test tree.
|
||||
# The inner timeout leaves five minutes for teardown verification and
|
||||
# artifact generation before the Buildkite step timeout.
|
||||
- >-
|
||||
timeout --signal=TERM --kill-after=1m 25m
|
||||
pytest -s -v -ra
|
||||
tests/entrypoints/
|
||||
-m 'core_model and cuda and not
|
||||
(cards_2 or cards_3 or cards_4 or cards_5 or cards_6 or cards_7 or cards_8)'
|
||||
--run-level "core_model"
|
||||
--durations=0
|
||||
--junitxml="$$R2_02_ARTIFACT_DIR/pytest.xml"
|
||||
2>&1 | tee "$$R2_02_ARTIFACT_DIR/pytest.log"
|
||||
- >-
|
||||
tail -n 100 "$$R2_02_ARTIFACT_DIR/pytest.log" >
|
||||
"$$R2_02_ARTIFACT_DIR/pytest-summary.txt"
|
||||
- |
|
||||
sleep 5
|
||||
ps -eo pid=,ppid=,lstart=,stat=,comm= > "$$R2_02_ARTIFACT_DIR/processes-after.txt"
|
||||
# Compare PID plus process start time so PID reuse cannot hide a leak.
|
||||
# Double dollars preserve awk field references through Buildkite interpolation.
|
||||
awk '
|
||||
NR == FNR {
|
||||
if ($$9 != "ps") {
|
||||
baseline[$$1 "|" $$3 "|" $$4 "|" $$5 "|" $$6 "|" $$7] = 1
|
||||
}
|
||||
next
|
||||
}
|
||||
$$9 != "ps" {
|
||||
identity = $$1 "|" $$3 "|" $$4 "|" $$5 "|" $$6 "|" $$7
|
||||
if (!(identity in baseline)) {
|
||||
print
|
||||
leaked = 1
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (leaked) {
|
||||
print "status=FAIL leaked_processes_detected=1"
|
||||
exit 1
|
||||
}
|
||||
print "status=PASS leaked_processes=0"
|
||||
}
|
||||
' "$$R2_02_ARTIFACT_DIR/processes-before.txt" \
|
||||
"$$R2_02_ARTIFACT_DIR/processes-after.txt" \
|
||||
2>&1 | tee "$$R2_02_ARTIFACT_DIR/process-cleanup.txt"
|
||||
|
||||
# - label: "Omni Model Test Qwen3-Omni"
|
||||
# agent_pool: mi300_2
|
||||
# depends_on: amd-build
|
||||
@@ -333,12 +201,6 @@ steps:
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
# A ROCm hardware hang aborts the interpreter with 134. Let Buildkite
|
||||
# create one fresh pod instead of retrying on the poisoned GPU process.
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: 134
|
||||
limit: 1
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_cosyvoice3_tts_expansion.py -m "slow" --run-level "core_model"
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
Last synced: 2026-08-04
|
||||
Modifications: Use the shared MI300 queues and Omni command-passing contract
|
||||
#}
|
||||
{% set docker_registry_amd = "rocm/vllm-omni" %}
|
||||
{% set docker_image_amd = docker_registry_amd ~ ":$BUILDKITE_COMMIT" %}
|
||||
{% set docker_image_amd = "rocm/vllm-omni:$BUILDKITE_COMMIT" %}
|
||||
{% set default_working_dir = "/app/vllm-omni" %}
|
||||
|
||||
{# MI300 runs tests natively in Kubernetes; Docker-in-Docker is unavailable. #}
|
||||
@@ -75,12 +74,11 @@ steps:
|
||||
depends_on: ~
|
||||
soft_fail: false
|
||||
commands:
|
||||
- "bash .buildkite/amd/scripts/build-ci-image.sh"
|
||||
- "docker build -f docker/Dockerfile.rocm -t {{ docker_image_amd }} --target test --build-arg ARG_PYTORCH_ROCM_ARCH=gfx942 --progress plain ."
|
||||
- "docker push {{ docker_image_amd }}"
|
||||
key: "amd-build"
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
PYTORCH_ROCM_ARCH: "gfx942"
|
||||
ROCM_CI_IMAGE_REGISTRY: "{{ docker_registry_amd }}"
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: -1 # Agent was lost
|
||||
@@ -158,14 +156,6 @@ steps:
|
||||
{% for path in step.artifact_paths %}
|
||||
- "{{ path }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.retry %}
|
||||
retry:
|
||||
automatic:
|
||||
{% for retry_rule in step.retry.automatic %}
|
||||
- exit_status: {{ retry_rule.exit_status }}
|
||||
limit: {{ retry_rule.limit }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.timeout_in_minutes %}
|
||||
timeout_in_minutes: {{ step.timeout_in_minutes }}
|
||||
@@ -234,14 +224,6 @@ steps:
|
||||
{% for path in step.artifact_paths %}
|
||||
- "{{ path }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.retry %}
|
||||
retry:
|
||||
automatic:
|
||||
{% for retry_rule in step.retry.automatic %}
|
||||
- exit_status: {{ retry_rule.exit_status }}
|
||||
limit: {{ retry_rule.limit }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.timeout_in_minutes %}
|
||||
timeout_in_minutes: {{ step.timeout_in_minutes }}
|
||||
|
||||
@@ -1,471 +0,0 @@
|
||||
# Uploader-only path-prefix presets for CUDA L2–L5 and NPU L4 test YAML.
|
||||
# Referenced as ``source_file_dependencies: omni_qwen3_omni_function`` (or a list of
|
||||
# keys) on a step; ``upload_pipeline.py`` expands the key(s) only.
|
||||
#
|
||||
# YAML anchors above the registry hold model business-code paths. Job keys
|
||||
# ({model}_function / _perf / _accuracy / _reliability / _doc / _cov) alias
|
||||
# those anchors and add the scripts the job actually runs. Feature keys below
|
||||
# are unchanged. ``source_filter_fallback`` is not a job key: when no job-key
|
||||
# prefix matches, a matching diff keeps every job for that upload.
|
||||
#
|
||||
# YAML anchors are nested lists; the loader flattens them.
|
||||
|
||||
x-qwen3-tts: &qwen3_tts
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/entrypoints/omni_base.py
|
||||
- vllm_omni/worker/gpu_model_runner.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/common/alias_free_activation.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_tts.py
|
||||
- vllm_omni/deploy/qwen3_tts.yaml
|
||||
- vllm_omni/entrypoints/openai/serving_speech.py
|
||||
- vllm_omni/entrypoints/openai/tts_adapters/
|
||||
- vllm_omni/engine/stage_pool.py
|
||||
- vllm_omni/worker_v2/
|
||||
- vllm_omni/core/sched/
|
||||
- vllm_omni/distributed/omni_connectors/
|
||||
- vllm_omni/config/stage_config.py
|
||||
- vllm_omni/config/omni_config.py
|
||||
- vllm_omni/engine/orchestrator.py
|
||||
- vllm_omni/engine/stage_engine_core_proc.py
|
||||
- vllm_omni/deploy/qwen3_tts_mrv2.yaml
|
||||
- vllm_omni/deploy/qwen3_tts_high_concurrency_mrv2.yaml
|
||||
- vllm_omni/deploy/qwen3_tts_high_concurrency_mrv2_b4.yaml
|
||||
|
||||
x-minicpmo-4-5: &minicpmo_4_5
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/entrypoints/omni_base.py
|
||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||
- vllm_omni/model_executor/models/step_audio2/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/utils.py
|
||||
- vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
- vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja
|
||||
|
||||
x-minicpmo-4-5-duplex: &minicpmo_4_5_duplex
|
||||
- vllm_omni/deploy/minicpmo_4_5_duplex.yaml
|
||||
- vllm_omni/engine/duplex/
|
||||
- vllm_omni/engine/duplex_omni_engine.py
|
||||
- vllm_omni/engine/duplex_orchestrator.py
|
||||
- vllm_omni/engine/omni_engine_base.py
|
||||
- vllm_omni/entrypoints/duplex/
|
||||
- vllm_omni/entrypoints/duplex_omni.py
|
||||
- vllm_omni/entrypoints/async_omni_base.py
|
||||
- vllm_omni/protocol/
|
||||
- vllm_omni/clients/
|
||||
- vllm_omni/outputs/duplex.py
|
||||
- vllm_omni/model_executor/duplex_sampling.py
|
||||
- vllm_omni/experimental/fullduplex/
|
||||
- vllm_omni/core/sched/
|
||||
- vllm_omni/outputs/multimodal_accumulation.py
|
||||
- vllm_omni/engine/stage_init_utils.py
|
||||
- vllm_omni/engine/orchestrator.py
|
||||
- vllm_omni/entrypoints/cli/serve.py
|
||||
- vllm_omni/entrypoints/openai/api_server.py
|
||||
- vllm_omni/entrypoints/openai/duplex_capability.py
|
||||
- vllm_omni/config/stage_config.py
|
||||
|
||||
x-qwen2-5-omni: &qwen2_5_omni
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/entrypoints/omni_base.py
|
||||
- vllm_omni/model_executor/models/qwen2_5_omni/
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen2_5_omni.py
|
||||
- vllm_omni/deploy/qwen2_5_omni.yaml
|
||||
|
||||
x-qwen3-omni: &qwen3_omni
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/entrypoints/omni_base.py
|
||||
- vllm_omni/entrypoints/openai/serving_chat.py
|
||||
- vllm_omni/model_executor/models/qwen3_omni/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/qwen2_5_omni/qwen2_5_omni_thinker.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/cuda_graph_decoder_wrapper.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_omni.py
|
||||
- vllm_omni/deploy/qwen3_omni_moe.yaml
|
||||
- vllm_omni/deploy/qwen3_omni_moe_thinking.yaml
|
||||
|
||||
x-wan22: &wan22
|
||||
- vllm_omni/diffusion/models/wan2_2/
|
||||
- vllm_omni/diffusion/models/dmd2/
|
||||
|
||||
x-cosmos3: &cosmos3
|
||||
- vllm_omni/diffusion/models/cosmos3/
|
||||
- vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_wan.py
|
||||
- vllm_omni/experimental/world_models/
|
||||
- vllm_omni/model_extras/cosmos3.py
|
||||
|
||||
x-qwen-image: &qwen_image
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
- vllm_omni/diffusion/models/dmd2/
|
||||
- vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_qwenimage.py
|
||||
|
||||
x-hunyuan-image3: &hunyuan_image3
|
||||
- vllm_omni/diffusion/models/hunyuan_image3/
|
||||
- vllm_omni/model_executor/models/hunyuan_image3/
|
||||
- vllm_omni/deploy/hunyuan_image3_dit.yaml
|
||||
|
||||
x-minimax-h3: &minimax_h3
|
||||
- vllm_omni/diffusion/models/minimax_h3/
|
||||
- vllm_omni/diffusion/layers/indexed_modulation.py
|
||||
|
||||
x-hunyuan-video: &hunyuan_video
|
||||
- vllm_omni/diffusion/models/hunyuan_video/
|
||||
- vllm_omni/model_executor/models/hunyuan_video/
|
||||
|
||||
x-ltx2: <x2
|
||||
- vllm_omni/diffusion/models/ltx2/
|
||||
- vllm_omni/model_extras/ltx2.py
|
||||
|
||||
x-sana-video: &sana_video
|
||||
- vllm_omni/diffusion/models/sana_video/
|
||||
- vllm_omni/model_extras/sana_video.py
|
||||
|
||||
x-z-image: &z_image
|
||||
- vllm_omni/diffusion/models/z_image/
|
||||
|
||||
x-stable-audio: &stable_audio
|
||||
- vllm_omni/diffusion/models/stable_audio/
|
||||
|
||||
x-lingbot-video: &lingbot_video
|
||||
- vllm_omni/diffusion/models/lingbot_video/
|
||||
- vllm_omni/model_extras/lingbot_video.py
|
||||
|
||||
x-lingbot-world: &lingbot_world
|
||||
- vllm_omni/diffusion/models/lingbot_world/
|
||||
|
||||
|
||||
source_file_dependencies:
|
||||
# Hardware presets and shared test helpers. Not a job key — do not attach this
|
||||
# to a step. Used only when no job-key prefix matches: then a hit keeps every job.
|
||||
source_filter_fallback:
|
||||
- .buildkite/common/ci_mirror_hardwares.yml
|
||||
- tests/helpers/
|
||||
|
||||
# --- features ---
|
||||
diffusion_distributed_attention:
|
||||
- tests/diffusion/distributed/
|
||||
- tests/diffusion/attention/test_attention_sp.py
|
||||
- vllm_omni/diffusion/distributed/
|
||||
- vllm_omni/diffusion/attention/
|
||||
- vllm_omni/diffusion/data.py
|
||||
- vllm_omni/diffusion/models/
|
||||
|
||||
custom_pipeline:
|
||||
- tests/e2e/features/custom_pipeline/
|
||||
- tests/e2e/features/helpers/custom_pipeline.py
|
||||
- vllm_omni/diffusion/
|
||||
- vllm_omni/engine/
|
||||
- vllm_omni/entrypoints/
|
||||
- vllm_omni/inputs/
|
||||
- vllm_omni/outputs/
|
||||
|
||||
rlhf_verl_omni:
|
||||
- tests/e2e/features/rlhf_test/test_verl_omni_e2e.py
|
||||
- tests/e2e/features/helpers/verl_omni_server.py
|
||||
- tests/e2e/features/helpers/custom_pipeline.py
|
||||
- vllm_omni/diffusion/
|
||||
- vllm_omni/engine/
|
||||
- vllm_omni/entrypoints/
|
||||
- vllm_omni/inputs/
|
||||
- vllm_omni/outputs/
|
||||
|
||||
# Tiny-model diffusion jobs (shared across many model trees under models/).
|
||||
diffusion_tiny_model:
|
||||
- tests/model_tests/diffusion/
|
||||
- vllm_omni/diffusion/models/
|
||||
|
||||
diffusion_offloader:
|
||||
- tests/diffusion/offloader/
|
||||
- vllm_omni/diffusion/offloader/
|
||||
|
||||
diffusion_quantization:
|
||||
- tests/diffusion/quantization/
|
||||
- vllm_omni/diffusion/quantization/
|
||||
|
||||
# --- models ---
|
||||
# --- omni / tts jobs ---
|
||||
omni_qwen3_omni_function:
|
||||
- *qwen3_omni
|
||||
- tests/e2e/offline_inference/test_qwen3_omni.py
|
||||
- tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py
|
||||
- tests/e2e/offline_inference/test_qwen3_omni_autoround_w4a16_expansion.py
|
||||
- tests/e2e/offline_inference/test_qwen3_omni_modelopt_nvfp4_w4a4.py
|
||||
- tests/e2e/online_serving/test_qwen3_omni.py
|
||||
- tests/e2e/online_serving/test_qwen3_omni_expansion.py
|
||||
- tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py
|
||||
|
||||
omni_qwen3_omni_accuracy:
|
||||
- *qwen3_omni
|
||||
- tests/e2e/accuracy/qwen3_omni/
|
||||
|
||||
omni_qwen3_omni_perf:
|
||||
- *qwen3_omni
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_qwen3_omni_vllm_text.json
|
||||
- tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json
|
||||
- tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json
|
||||
- tests/dfx/perf/tests/test_qwen3_omni_multi_replicas.json
|
||||
|
||||
omni_qwen3_omni_reliability:
|
||||
- *qwen3_omni
|
||||
- tests/dfx/reliability/test_reliability_qwen3_omni.py
|
||||
|
||||
omni_qwen3_omni_doc:
|
||||
- *qwen3_omni
|
||||
- examples/online_serving/qwen3_omni/
|
||||
- examples/online_serving/openai_chat_completion_client_for_multimodal_generation.py
|
||||
- tests/examples/online_serving/test_qwen3_omni.py
|
||||
|
||||
omni_qwen2_5_omni_doc:
|
||||
- *qwen2_5_omni
|
||||
- examples/online_serving/qwen2_5_omni/
|
||||
- examples/online_serving/openai_chat_completion_client_for_multimodal_generation.py
|
||||
- tests/examples/online_serving/test_qwen2_5_omni.py
|
||||
|
||||
omni_minicpmo_4_5_function:
|
||||
- *minicpmo_4_5
|
||||
- tests/e2e/offline_inference/test_minicpmo_4_5.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_expansion.py
|
||||
|
||||
omni_minicpmo_4_5_accuracy:
|
||||
- *minicpmo_4_5
|
||||
- tests/e2e/accuracy/minicpmo_4_5/
|
||||
|
||||
omni_minicpmo_4_5_perf:
|
||||
- *minicpmo_4_5
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_minicpmo_4_5_ready.json
|
||||
- tests/dfx/perf/tests/test_minicpmo_4_5.json
|
||||
|
||||
omni_minicpmo_4_5_doc:
|
||||
- *minicpmo_4_5
|
||||
- examples/online_serving/minicpmo/realtime_web/
|
||||
- examples/online_serving/minicpmo/realtime_duplex_demo.py
|
||||
- tests/examples/test_minicpmo_realtime_web_server.py
|
||||
- tests/examples/test_minicpmo_realtime_web_static.py
|
||||
- tests/examples/test_minicpmo_realtime_duplex_simple_demo.py
|
||||
|
||||
omni_minicpmo_4_5_duplex_function:
|
||||
- *minicpmo_4_5
|
||||
- *minicpmo_4_5_duplex
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_duplex.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py
|
||||
- tests/e2e/online_serving/test_duplex_client_live.py
|
||||
- tests/e2e/online_serving/test_minicpmo_realtime_duplex_drivers.py
|
||||
- tests/e2e/online_serving/helpers/minicpmo_realtime_duplex_scenarios.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_multi_session.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_server_vad.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py
|
||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||
- tests/assets/minicpmo_4_5/
|
||||
- tests/clients/
|
||||
- tests/engine/duplex/
|
||||
- tests/engine/test_duplex_omni_engine.py
|
||||
- tests/engine/test_duplex_orchestrator.py
|
||||
- tests/entrypoints/duplex/
|
||||
- tests/entrypoints/test_duplex_omni.py
|
||||
- tests/entrypoints/openai_api/test_duplex_api_server.py
|
||||
- tests/model_executor/models/minicpmo_4_5/duplex/
|
||||
- tests/protocol/
|
||||
|
||||
omni_minicpmo_4_5_duplex_perf:
|
||||
- *minicpmo_4_5
|
||||
- *minicpmo_4_5_duplex
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json
|
||||
|
||||
tts_qwen3_tts_function:
|
||||
- *qwen3_tts
|
||||
- tests/e2e/features/prefill_phase/
|
||||
- tests/e2e/offline_inference/test_qwen3_tts_base.py
|
||||
- tests/e2e/offline_inference/test_qwen3_tts_customvoice.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_base.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_base_expansion.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_customvoice.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_customvoice_expansion.py
|
||||
|
||||
tts_qwen3_tts_perf:
|
||||
- *qwen3_tts
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_tts.json
|
||||
|
||||
tts_qwen3_tts_cov:
|
||||
- *qwen3_tts
|
||||
- .buildkite/common/scripts/run_cov_split.sh
|
||||
- pyproject.toml
|
||||
- tests/e2e/offline_inference/test_qwen3_tts_base.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_base.py
|
||||
|
||||
# --- diffusion jobs ---
|
||||
diffusion_wan22_function:
|
||||
- *wan22
|
||||
- tests/e2e/offline_inference/test_wan22_t2v.py
|
||||
- tests/e2e/offline_inference/test_wan22_autoround_w4a16_expansion.py
|
||||
- tests/e2e/offline_inference/test_device_postprocess_equivalence.py
|
||||
- tests/e2e/online_serving/test_wan22_t2v.py
|
||||
- tests/e2e/online_serving/test_wan22_expansion.py
|
||||
|
||||
diffusion_wan22_accuracy:
|
||||
- *wan22
|
||||
- tests/e2e/accuracy/wan22_i2v/
|
||||
- tests/e2e/accuracy/test_diffusers_backend_similarity.py
|
||||
|
||||
diffusion_wan22_perf:
|
||||
- *wan22
|
||||
- tests/dfx/perf/scripts/run_diffusion_benchmark.py
|
||||
- tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json
|
||||
|
||||
diffusion_wan22_reliability:
|
||||
- *wan22
|
||||
- tests/dfx/reliability/test_reliability_wan22.py
|
||||
|
||||
diffusion_image_to_video_doc:
|
||||
- *wan22
|
||||
- *hunyuan_video
|
||||
- *ltx2
|
||||
- *sana_video
|
||||
- *lingbot_video
|
||||
- examples/offline_inference/image_to_video/
|
||||
- tests/examples/offline_inference/test_image_to_video.py
|
||||
|
||||
diffusion_cosmos3_function:
|
||||
- *cosmos3
|
||||
- tests/e2e/online_serving/test_cosmos3.py
|
||||
|
||||
diffusion_cosmos3_accuracy:
|
||||
- *cosmos3
|
||||
- tests/e2e/accuracy/test_cosmos3_similarity.py
|
||||
|
||||
diffusion_cosmos3_perf:
|
||||
- *cosmos3
|
||||
- tests/dfx/perf/scripts/run_diffusion_benchmark.py
|
||||
- tests/dfx/perf/tests/test_cosmos3_vllm_omni.json
|
||||
|
||||
diffusion_qwen_image_function:
|
||||
- *qwen_image
|
||||
- tests/e2e/online_serving/test_qwen_image.py
|
||||
- tests/e2e/online_serving/test_qwen_image_expansion.py
|
||||
- tests/e2e/offline_inference/test_qwen_image_autoround_w4a16_expansion.py
|
||||
|
||||
diffusion_qwen_image_accuracy:
|
||||
- *qwen_image
|
||||
- tests/e2e/accuracy/test_qwen_image.py
|
||||
- tests/e2e/accuracy/test_diffusers_backend_similarity.py
|
||||
|
||||
diffusion_qwen_image_perf:
|
||||
- *qwen_image
|
||||
- tests/dfx/perf/scripts/run_diffusion_benchmark.py
|
||||
- tests/dfx/perf/tests/test_qwen_image_vllm_omni.json
|
||||
|
||||
diffusion_text_to_image_doc:
|
||||
- *qwen_image
|
||||
- *z_image
|
||||
- examples/offline_inference/text_to_image/
|
||||
- examples/online_serving/text_to_image/
|
||||
- tests/examples/offline_inference/test_text_to_image.py
|
||||
- tests/examples/online_serving/test_text_to_image.py
|
||||
- vllm_omni/diffusion/models/nextstep_1_1/
|
||||
- vllm_omni/diffusion/models/longcat_image/
|
||||
- vllm_omni/diffusion/models/ovis_image/
|
||||
- vllm_omni/diffusion/models/omnigen2/
|
||||
- vllm_omni/diffusion/models/sd3/
|
||||
- vllm_omni/diffusion/models/flux/
|
||||
- vllm_omni/diffusion/models/flux2/
|
||||
- vllm_omni/diffusion/models/flux2_klein/
|
||||
- vllm_omni/diffusion/models/hidream_image/
|
||||
- vllm_omni/diffusion/models/krea2/
|
||||
- vllm_omni/diffusion/models/lingbot_video/
|
||||
|
||||
diffusion_hunyuan_image3_function:
|
||||
- *hunyuan_image3
|
||||
- tests/e2e/offline_inference/test_hunyuanimage3_i2t_expansion.py
|
||||
|
||||
diffusion_hunyuan_image3_accuracy:
|
||||
- *hunyuan_image3
|
||||
- tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py
|
||||
|
||||
diffusion_hunyuan_image3_perf:
|
||||
- *hunyuan_image3
|
||||
- tests/dfx/perf/scripts/run_diffusion_benchmark.py
|
||||
- tests/dfx/perf/tests/test_hunyuan_image_tp2_cfgp2.json
|
||||
- tests/dfx/perf/tests/test_hunyuan_image_tp2_sp2.json
|
||||
- tests/dfx/perf/tests/test_hunyuan_image_tp4.json
|
||||
|
||||
diffusion_hunyuan_image3_reliability:
|
||||
- *hunyuan_image3
|
||||
- tests/dfx/reliability/test_reliability_hunyuan_image.py
|
||||
|
||||
diffusion_minimax_h3_function:
|
||||
- *minimax_h3
|
||||
- tests/e2e/online_serving/test_minimax_h3_dlo_dp2_t2va.py
|
||||
- tests/e2e/online_serving/minimax_h3/
|
||||
- tests/diffusion/models/minimax_h3/
|
||||
- vllm_omni/diffusion/lora/
|
||||
- vllm_omni/diffusion/offloader/
|
||||
- vllm_omni/diffusion/distributed/
|
||||
- vllm_omni/entrypoints/openai/
|
||||
|
||||
diffusion_minimax_h3_accuracy:
|
||||
- *minimax_h3
|
||||
- tests/e2e/accuracy/minimax_h3/
|
||||
|
||||
diffusion_minimax_h3_perf:
|
||||
- *minimax_h3
|
||||
- tests/dfx/perf/scripts/run_diffusion_benchmark.py
|
||||
- tests/dfx/perf/tests/test_minimax_h3_vllm_omni.json
|
||||
|
||||
diffusion_hunyuan_video_function:
|
||||
- *hunyuan_video
|
||||
- tests/e2e/online_serving/test_hunyuan_video_15_expansion.py
|
||||
|
||||
diffusion_hunyuan_video_accuracy:
|
||||
- *hunyuan_video
|
||||
- tests/e2e/accuracy/hunyuanvideo15_t2v/
|
||||
- tests/e2e/accuracy/hunyuanvideo15_i2v/
|
||||
|
||||
diffusion_hunyuan_video_perf:
|
||||
- *hunyuan_video
|
||||
- tests/dfx/perf/scripts/run_diffusion_benchmark.py
|
||||
- tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json
|
||||
- tests/dfx/perf/tests/test_hunyuanvideo15_i2v_vllm_omni.json
|
||||
|
||||
diffusion_z_image_function:
|
||||
- *z_image
|
||||
- tests/e2e/online_serving/test_z_image.py
|
||||
- tests/e2e/online_serving/test_zimage_expansion.py
|
||||
|
||||
diffusion_sana_video_function:
|
||||
- *sana_video
|
||||
- tests/e2e/online_serving/test_sana_video_expansion.py
|
||||
- tests/e2e/accuracy/sana_video/
|
||||
|
||||
diffusion_stable_audio_function:
|
||||
- *stable_audio
|
||||
- tests/e2e/offline_inference/test_stable_audio_expansion.py
|
||||
- tests/e2e/online_serving/test_stable_audio_online_expansion.py
|
||||
|
||||
diffusion_lingbot_function:
|
||||
- *lingbot_video
|
||||
- *lingbot_world
|
||||
- tests/e2e/online_serving/test_lingbot_video.py
|
||||
- tests/e2e/online_serving/test_lingbot_video_moe.py
|
||||
- tests/e2e/offline_inference/test_lingbot_world_v2.py
|
||||
|
||||
|
||||
# Invalid-param jobs: model business code only, plus the reliability scripts.
|
||||
reliability_invalid_param_h100:
|
||||
- *qwen3_omni
|
||||
- *minicpmo_4_5
|
||||
- *qwen_image
|
||||
- *wan22
|
||||
- tests/dfx/reliability/invalid_param_test/
|
||||
|
||||
reliability_invalid_param_l4:
|
||||
- *qwen3_tts
|
||||
- *stable_audio
|
||||
- tests/dfx/reliability/invalid_param_test/
|
||||
@@ -44,7 +44,6 @@ L3_YAML_FILES: dict[str, str] = {
|
||||
L45_YAML_FILES: dict[str, str] = {
|
||||
".buildkite/cuda/test-nightly.yml": "cuda",
|
||||
".buildkite/cuda/test-weekly.yml": "cuda",
|
||||
".buildkite/amd/test-amd-nightly.yml": "amd",
|
||||
".buildkite/npu/test-npu-nightly.yml": "npu",
|
||||
}
|
||||
|
||||
|
||||
@@ -10,17 +10,8 @@ Bootstrap mode (``bootstrap-upload-steps.yml``):
|
||||
- Detect docs-only, pytest skip-mark-only, or combined skip-ci from git diff.
|
||||
- When only CI level YAML changes, enable **L2/L3** upload steps for affected levels only.
|
||||
|
||||
Test pipeline mode (e.g. test-merge.yml, test-nightly.yml, test-weekly.yml):
|
||||
- Drop steps whose ``source_file_dependencies`` do not match changed files
|
||||
(string/list keys from ci_source_file_dependencies.yml, or inline path
|
||||
prefixes). Filtering applies on **PR label** uploads and on post-merge
|
||||
``main`` L3 uploads. Scheduled ``main`` uploads that pass ``--all``
|
||||
(NIGHTLY/WEEKLY) or ``--e2e`` keep every selected job and still strip
|
||||
the field. If no job-key prefix matches, a change to the pipeline YAML
|
||||
being uploaded or to a path under the ``source_filter_fallback`` registry
|
||||
key keeps every job so command, env, and hardware edits can be validated
|
||||
before merge. When any job-key prefix already matches, normal filtering
|
||||
wins.
|
||||
Test pipeline mode (e.g. test-merge.yml):
|
||||
- Drop steps whose ``source_file_dependencies`` do not match changed files.
|
||||
- Expand uploader-only ``mirror_hardwares`` into ``agents`` (+ optional ``image``
|
||||
for NPU) + ``plugins`` (see ci_mirror_hardwares.yml).
|
||||
- Omit ``mirror_hardwares`` to compose ``{chip}_{n}`` from pytest ``-m`` SKU
|
||||
@@ -96,10 +87,6 @@ BOOTSTRAP_UPLOAD_IF_KEYS = {
|
||||
}
|
||||
E2E_GROUP_MARKER = "E2E Test"
|
||||
CI_MIRROR_HARDWARES_PATH = ROOT / ".buildkite/common/ci_mirror_hardwares.yml"
|
||||
CI_SOURCE_FILE_DEPENDENCIES_PATH = ROOT / ".buildkite/common/ci_source_file_dependencies.yml"
|
||||
# Registry key whose prefixes bypass source filtering. Paths live in
|
||||
# ci_source_file_dependencies.yml; do not attach this key to a job.
|
||||
SOURCE_FILTER_FALLBACK_KEY = "source_filter_fallback"
|
||||
CUDA_HF_TOKEN_ENV = "VLLM_CI_HF_TOKEN"
|
||||
CUDA_HF_TOKEN_EXPORT = f'if [ -n "$${{{CUDA_HF_TOKEN_ENV}:-}}" ]; then export HF_TOKEN="$${{{CUDA_HF_TOKEN_ENV}}}"; fi'
|
||||
|
||||
@@ -108,7 +95,14 @@ CUDA_HF_TOKEN_EXPORT = f'if [ -n "$${{{CUDA_HF_TOKEN_ENV}:-}}" ]; then export HF
|
||||
# ``*_UPLOAD_IF``: full gate for uploading that child pipeline.
|
||||
NIGHTLY_MAIN_IF = 'build.branch == "main" && build.env("NIGHTLY") == "1"'
|
||||
NIGHTLY_LABEL_IF = (
|
||||
f'({NIGHTLY_MAIN_IF}) || (build.branch != "main" && build.pull_request.labels includes "nightly-test")'
|
||||
f"({NIGHTLY_MAIN_IF}) || "
|
||||
'(build.branch != "main" && ('
|
||||
'build.pull_request.labels includes "nightly-test" || '
|
||||
'build.pull_request.labels includes "omni-test" || '
|
||||
'build.pull_request.labels includes "tts-test" || '
|
||||
'build.pull_request.labels includes "diffusion-x2iat-test" || '
|
||||
'build.pull_request.labels includes "diffusion-x2v-test"'
|
||||
"))"
|
||||
)
|
||||
WEEKLY_E2E_IF = 'build.branch == "main" && build.env("WEEKLY") == "1"'
|
||||
WEEKLY_MAIN_IF = 'build.branch == "main" && (build.env("WEEKLY") == "1" || build.env("NON_CRITICAL") == "1")'
|
||||
@@ -254,7 +248,7 @@ def _render_bootstrap_pipeline(
|
||||
return yaml.safe_dump(doc, sort_keys=False)
|
||||
|
||||
|
||||
# --- Test pipeline (test-ready.yml, test-merge.yml, test-nightly.yml) ---
|
||||
# --- Test pipeline (test-ready.yml, test-merge.yml) ---
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
@@ -270,117 +264,6 @@ def _load_mirror_hardwares() -> dict[str, dict[str, Any]]:
|
||||
return presets
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _load_source_file_dependencies() -> dict[str, list[str]]:
|
||||
def flatten(value: Any, *, key: str) -> list[str]:
|
||||
"""Flatten YAML-anchor nested lists into a de-duplicated prefix list."""
|
||||
if isinstance(value, str):
|
||||
if not value.strip():
|
||||
raise ValueError(f"empty path in source_file_dependencies[{key!r}]")
|
||||
return [value]
|
||||
if isinstance(value, list):
|
||||
flattened: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for item in value:
|
||||
for path in flatten(item, key=key):
|
||||
if path not in seen:
|
||||
seen.add(path)
|
||||
flattened.append(path)
|
||||
return flattened
|
||||
raise ValueError(
|
||||
f"source_file_dependencies[{key!r}] must be a list of path prefixes, got {type(value).__name__}",
|
||||
)
|
||||
|
||||
if not CI_SOURCE_FILE_DEPENDENCIES_PATH.is_file():
|
||||
raise FileNotFoundError(
|
||||
f"missing CI source_file_dependencies registry: {CI_SOURCE_FILE_DEPENDENCIES_PATH}",
|
||||
)
|
||||
doc = yaml.safe_load(CI_SOURCE_FILE_DEPENDENCIES_PATH.read_text(encoding="utf-8"))
|
||||
if not isinstance(doc, dict):
|
||||
raise ValueError(f"invalid CI source_file_dependencies registry: {CI_SOURCE_FILE_DEPENDENCIES_PATH}")
|
||||
presets = doc.get("source_file_dependencies")
|
||||
if not isinstance(presets, dict):
|
||||
raise ValueError(f"source_file_dependencies must be a mapping in {CI_SOURCE_FILE_DEPENDENCIES_PATH}")
|
||||
loaded: dict[str, list[str]] = {}
|
||||
for key, value in presets.items():
|
||||
if not isinstance(key, str) or not key.strip():
|
||||
raise ValueError(
|
||||
f"source_file_dependencies keys must be non-empty strings in {CI_SOURCE_FILE_DEPENDENCIES_PATH}",
|
||||
)
|
||||
loaded[key] = flatten(value, key=key)
|
||||
return loaded
|
||||
|
||||
|
||||
_REGISTRY_KEY_RE = re.compile(r"^[a-z][a-z0-9_]*$")
|
||||
|
||||
|
||||
def _parse_command_text(step: dict[str, Any]) -> str:
|
||||
"""Parse step ``commands`` / ``command`` into a single string."""
|
||||
raw = step.get("commands", step.get("command"))
|
||||
if raw is None:
|
||||
return ""
|
||||
if isinstance(raw, str):
|
||||
return raw
|
||||
if isinstance(raw, list):
|
||||
return "\n".join(str(item) for item in raw if item is not None)
|
||||
return str(raw)
|
||||
|
||||
|
||||
def _resolve_source_file_dependencies(step: dict[str, Any]) -> list[str] | None:
|
||||
"""Expand a registry key (or list of keys / inline path prefixes)."""
|
||||
deps = step.get("source_file_dependencies")
|
||||
if deps is None:
|
||||
return None
|
||||
|
||||
def dedupe(*groups: list[str]) -> list[str]:
|
||||
merged: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for group in groups:
|
||||
for path in group:
|
||||
if path not in seen:
|
||||
seen.add(path)
|
||||
merged.append(path)
|
||||
return merged
|
||||
|
||||
def lookup(key: str) -> list[str]:
|
||||
if key == SOURCE_FILTER_FALLBACK_KEY:
|
||||
raise ValueError(
|
||||
f"source_file_dependencies {key!r} bypasses filtering and cannot be attached to a step "
|
||||
f"({_get_step_label(step)!r})",
|
||||
)
|
||||
registry = _load_source_file_dependencies()
|
||||
paths = registry.get(key)
|
||||
if paths is None:
|
||||
known = ", ".join(sorted(registry))
|
||||
raise ValueError(
|
||||
f"unknown source_file_dependencies {key!r} in step {_get_step_label(step)!r}; known: {known}",
|
||||
)
|
||||
return list(paths)
|
||||
|
||||
prefixes: list[str]
|
||||
if isinstance(deps, str):
|
||||
prefixes = lookup(deps) if _REGISTRY_KEY_RE.fullmatch(deps) else [deps]
|
||||
elif isinstance(deps, list):
|
||||
if not all(isinstance(item, str) for item in deps):
|
||||
raise ValueError(
|
||||
f"source_file_dependencies must be a string key or list of strings in step {_get_step_label(step)!r}",
|
||||
)
|
||||
keyish = [bool(_REGISTRY_KEY_RE.fullmatch(item)) for item in deps]
|
||||
if deps and all(keyish):
|
||||
prefixes = dedupe(*(lookup(key) for key in deps))
|
||||
elif any(keyish):
|
||||
raise ValueError(
|
||||
f"source_file_dependencies in step {_get_step_label(step)!r} mixes registry keys and path prefixes",
|
||||
)
|
||||
else:
|
||||
prefixes = list(deps)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"source_file_dependencies must be a string key or list in step {_get_step_label(step)!r}",
|
||||
)
|
||||
return prefixes
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _cuda_mirror_chips() -> tuple[str, ...]:
|
||||
"""Lowercase CUDA SKUs that have at least one ``{chip}_{n}`` preset.
|
||||
@@ -395,7 +278,7 @@ def _cuda_mirror_chips() -> tuple[str, ...]:
|
||||
return tuple(sorted(chips, key=lambda chip: (-len(chip), chip)))
|
||||
|
||||
|
||||
def _parse_cards_marks(expr: str) -> tuple[set[int], bool]:
|
||||
def _read_cards_marks(expr: str) -> tuple[set[int], bool]:
|
||||
"""Parse registered ``cards_n`` / ``not cards_n`` from a pytest ``-m`` expr.
|
||||
|
||||
Returns positive card counts and whether any ``not cards_*`` is present.
|
||||
@@ -412,8 +295,8 @@ def _parse_cards_marks(expr: str) -> tuple[set[int], bool]:
|
||||
return positives, has_not_cards
|
||||
|
||||
|
||||
def _parse_hardware_marks(expr: str) -> set[str]:
|
||||
"""Parse lowercase positive CUDA SKUs that have a mirror preset.
|
||||
def _read_hardware_marks(expr: str) -> set[str]:
|
||||
"""Return lowercase positive CUDA SKUs that have a mirror preset.
|
||||
|
||||
``not H100`` is ignored. SKUs with no ``{chip}_*`` preset (e.g. H200) are dropped.
|
||||
"""
|
||||
@@ -455,22 +338,36 @@ def _get_mirror_hw_selector() -> str:
|
||||
return selector
|
||||
|
||||
|
||||
def _parse_pytest_marks(step: dict[str, Any]) -> tuple[set[str], int | Literal["max"] | None]:
|
||||
"""Parse pytest ``-m`` from step commands: CUDA SKU chips and cards count.
|
||||
def _read_pytest_marks(commands: Any) -> tuple[set[str], int | Literal["max"] | None]:
|
||||
"""Read pytest ``-m`` from step commands: CUDA SKU chips and cards count.
|
||||
|
||||
*chips* are lowercase SKUs from positive markers (``not H100`` is ignored).
|
||||
*cards* is the max positive ``cards_n``, ``"max"`` when only ``not cards_*``
|
||||
is present, or ``None``.
|
||||
"""
|
||||
text = _parse_command_text(step)
|
||||
chunks: list[str] = []
|
||||
|
||||
def _collect(value: Any) -> None:
|
||||
if value is None:
|
||||
return
|
||||
if isinstance(value, str):
|
||||
chunks.append(value)
|
||||
elif isinstance(value, list):
|
||||
for part in value:
|
||||
_collect(part)
|
||||
else:
|
||||
chunks.append(str(value))
|
||||
|
||||
_collect(commands)
|
||||
text = "\n".join(chunks)
|
||||
|
||||
chips: set[str] = set()
|
||||
positives: set[int] = set()
|
||||
has_not_cards = False
|
||||
for match in _PYTEST_MARKER_ARG.finditer(text):
|
||||
expr = match.group(1) or match.group(2) or match.group(3) or ""
|
||||
chips |= _parse_hardware_marks(expr)
|
||||
card_counts, not_cards = _parse_cards_marks(expr)
|
||||
chips |= _read_hardware_marks(expr)
|
||||
card_counts, not_cards = _read_cards_marks(expr)
|
||||
positives.update(card_counts)
|
||||
has_not_cards = has_not_cards or not_cards
|
||||
|
||||
@@ -587,7 +484,7 @@ def _expand_mirror_hardwares(step: dict[str, Any]) -> dict[str, Any] | None:
|
||||
if "mirror_hardwares" not in step:
|
||||
if has_pool:
|
||||
return step
|
||||
chips, cards = _parse_pytest_marks(step)
|
||||
chips, cards = _read_pytest_marks(step.get("commands"))
|
||||
if not chips and cards is None:
|
||||
return step
|
||||
preset_name = _compose_mirror_hardware_name(chips, cards, step_label=step_label)
|
||||
@@ -655,7 +552,11 @@ def _process_test_steps(
|
||||
processed.append(step)
|
||||
continue
|
||||
|
||||
deps = _resolve_source_file_dependencies(step)
|
||||
deps = step.get("source_file_dependencies")
|
||||
if deps is not None and not isinstance(deps, list):
|
||||
raise ValueError(
|
||||
f"source_file_dependencies must be a list in step {_get_step_label(step)!r}",
|
||||
)
|
||||
if changed_files is not None and deps is not None and not _match_source_file(changed_files, deps):
|
||||
_log(f"skip {_get_step_label(step)!r} (no changes under {deps})")
|
||||
continue
|
||||
@@ -694,25 +595,10 @@ def _select_e2e_group_steps(steps: list[Any]) -> list[Any]:
|
||||
return selected
|
||||
|
||||
|
||||
def _any_source_dependency_match(steps: list[Any], changed_files: list[str]) -> bool:
|
||||
"""True when any step with ``source_file_dependencies`` matches *changed_files*."""
|
||||
for step in steps:
|
||||
if not isinstance(step, dict):
|
||||
continue
|
||||
deps = _resolve_source_file_dependencies(step)
|
||||
if deps is not None and _match_source_file(changed_files, deps):
|
||||
return True
|
||||
nested = step.get("steps")
|
||||
if isinstance(nested, list) and _any_source_dependency_match(nested, changed_files):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _render_test_pipeline(
|
||||
doc: dict[str, Any],
|
||||
changed_files: list[str] | None,
|
||||
*,
|
||||
pipeline_path: Path | None = None,
|
||||
e2e_only: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Filter steps by PR diff and strip uploader-only ``source_file_dependencies`` metadata."""
|
||||
@@ -725,13 +611,6 @@ def _render_test_pipeline(
|
||||
return doc
|
||||
if e2e_only:
|
||||
steps = _select_e2e_group_steps(steps)
|
||||
# Bypass is a fallback: only when no job-key prefix matched.
|
||||
if changed_files is not None and pipeline_path is not None:
|
||||
if not _any_source_dependency_match(steps, changed_files):
|
||||
bypass = _source_filter_fallback_reason(changed_files, pipeline_path)
|
||||
if bypass is not None:
|
||||
_log(f"keep all jobs (no source_file_dependencies match; bypassed by {bypass})")
|
||||
changed_files = None
|
||||
steps = _process_test_steps(steps, changed_files)
|
||||
return {**doc, "steps": steps}
|
||||
|
||||
@@ -739,60 +618,6 @@ def _render_test_pipeline(
|
||||
# --- Entry (read file → bootstrap or test render → YAML string) ---
|
||||
|
||||
|
||||
def _repo_relative_posix(path: Path) -> str:
|
||||
resolved = path.resolve()
|
||||
try:
|
||||
return resolved.relative_to(ROOT).as_posix()
|
||||
except ValueError:
|
||||
return path.as_posix().replace("\\", "/")
|
||||
|
||||
|
||||
def _source_filter_fallback_prefixes() -> list[str]:
|
||||
"""Shared uploader/registry prefixes from ``source_filter_fallback``. Not a job key."""
|
||||
registry = _load_source_file_dependencies()
|
||||
prefixes = registry.get(SOURCE_FILTER_FALLBACK_KEY)
|
||||
if not prefixes:
|
||||
raise ValueError(
|
||||
f"source_file_dependencies[{SOURCE_FILTER_FALLBACK_KEY!r}] must list shared uploader paths "
|
||||
f"in {CI_SOURCE_FILE_DEPENDENCIES_PATH}",
|
||||
)
|
||||
return prefixes
|
||||
|
||||
|
||||
def _source_filter_fallback_reason(changed_files: list[str] | None, pipeline_path: Path) -> str | None:
|
||||
"""Return the changed path that should disable source filtering, if any."""
|
||||
if not changed_files:
|
||||
return None
|
||||
changed = set(changed_files)
|
||||
pipeline_rel = _repo_relative_posix(pipeline_path)
|
||||
if pipeline_rel in changed:
|
||||
return pipeline_rel
|
||||
prefixes = _source_filter_fallback_prefixes()
|
||||
for path in changed_files:
|
||||
if _match_source_file([path], prefixes):
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
def _changed_files_for_source_filter(
|
||||
ctx,
|
||||
*,
|
||||
force_all: bool,
|
||||
e2e_only: bool,
|
||||
) -> list[str] | None:
|
||||
"""Return the diff to filter against, or None to keep every step.
|
||||
|
||||
``--all`` / ``--e2e`` disable filtering (scheduled NIGHTLY/WEEKLY full
|
||||
uploads and weekly E2E sweeps). Post-merge ``main`` L3 and PR-label
|
||||
uploads filter against the commit/PR diff. Pipeline YAML /
|
||||
``source_filter_fallback`` matches are applied later in
|
||||
``_render_test_pipeline`` only when no job-key prefix already matched.
|
||||
"""
|
||||
if force_all or e2e_only:
|
||||
return None
|
||||
return ctx.changed_files
|
||||
|
||||
|
||||
def _render_pipeline(
|
||||
path: Path,
|
||||
*,
|
||||
@@ -810,18 +635,13 @@ def _render_pipeline(
|
||||
|
||||
text = path.read_text(encoding="utf-8")
|
||||
ctx = resolve_ci_context_from_git()
|
||||
changed_files = _changed_files_for_source_filter(ctx, force_all=force_all, e2e_only=e2e_only)
|
||||
changed_files = None if force_all or e2e_only else ctx.changed_files
|
||||
|
||||
doc = yaml.safe_load(text)
|
||||
if not isinstance(doc, dict):
|
||||
raise ValueError(f"invalid pipeline YAML: {path}")
|
||||
|
||||
doc = _render_test_pipeline(
|
||||
doc,
|
||||
changed_files,
|
||||
pipeline_path=path,
|
||||
e2e_only=e2e_only,
|
||||
)
|
||||
doc = _render_test_pipeline(doc, changed_files, e2e_only=e2e_only)
|
||||
return yaml.safe_dump(doc, sort_keys=False)
|
||||
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ steps:
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L3 Test — PR merge-test label or post-merge on main (both diff-aware);
|
||||
# main+WEEKLY=1 uploads the E2E group only (--e2e).
|
||||
# L3 Test — PR merge-test label (diff-aware) or main+WEEKLY=1 (--e2e, full E2E group)
|
||||
- label: "Upload Merge Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-merge-pipeline
|
||||
@@ -37,30 +36,20 @@ steps:
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L4 Test — main+NIGHTLY=1 (full pipeline), or PR nightly-test label (diff-aware)
|
||||
# L4 Test — main+NIGHTLY=1 (scheduled), or PR with specific label (e.g. add label then Rebuild)
|
||||
- label: "Upload Nightly Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-nightly-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${NIGHTLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--all"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-nightly.yml
|
||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/cuda/test-nightly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L5 Test — main+WEEKLY=1 / NON_CRITICAL=1 (full pipeline), or PR weekly-test label (diff-aware)
|
||||
# L5 Test — main+WEEKLY=1 / NON_CRITICAL=1 (scheduled), or PR with weekly-test label
|
||||
- label: "Upload Weekly Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-weekly-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--all"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-weekly.yml
|
||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/cuda/test-weekly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
+122
-14
@@ -1,6 +1,5 @@
|
||||
# CUDA CI L3 (`advanced_model` e2e) plus L1 CPU Simple Test (`core_model and cpu`).
|
||||
# Uploaded by Upload Merge Pipeline: PR label `merge-test`, or post-merge on main
|
||||
# (both diff-aware via source_file_dependencies).
|
||||
# Uploaded by Upload Merge Pipeline: PR label `merge-test`, or post-merge on main.
|
||||
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
@@ -66,9 +65,7 @@ steps:
|
||||
# 0.26 startup regression is understood and fixed.
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
# Turn-based server VAD over /v1/realtime is deferred to RFC #7181 PR 5
|
||||
# (see the P0 thread on #7413); the test stays in the tree and runs again there.
|
||||
- pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and H100" --run-level "advanced_model" --deselect tests/entrypoints/openai_api/test_qwen3_omni_realtime_websocket.py::TestQwen3OmniRealtimeWebSocket::test_server_vad_multi_turn_without_client_commit
|
||||
- pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and H100" --run-level "advanced_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Entrypoint Test with L4"
|
||||
@@ -81,7 +78,21 @@ steps:
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
||||
source_file_dependencies: tts_qwen3_tts_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/features/prefill_phase/
|
||||
- vllm_omni/worker/gpu_model_runner.py
|
||||
- tests/helpers/media.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_customvoice.py
|
||||
- tests/e2e/offline_inference/test_qwen3_tts_customvoice.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/common/alias_free_activation.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_tts.py
|
||||
- vllm_omni/deploy/qwen3_tts.yaml
|
||||
- vllm_omni/entrypoints/openai/serving_speech.py
|
||||
- vllm_omni/entrypoints/openai/tts_adapters/
|
||||
- vllm_omni/engine/stage_pool.py
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -92,7 +103,21 @@ steps:
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "TTS · Qwen3-TTS Base Test"
|
||||
source_file_dependencies: tts_qwen3_tts_cov
|
||||
source_file_dependencies:
|
||||
- tests/helpers/media.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_base.py
|
||||
- tests/e2e/offline_inference/test_qwen3_tts_base.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/common/alias_free_activation.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_tts.py
|
||||
- vllm_omni/deploy/qwen3_tts.yaml
|
||||
- vllm_omni/entrypoints/openai/serving_speech.py
|
||||
- vllm_omni/entrypoints/openai/tts_adapters/
|
||||
- vllm_omni/engine/stage_pool.py
|
||||
- .buildkite/common/scripts/run_cov_split.sh
|
||||
- pyproject.toml
|
||||
# 40 -> 60: the coverage split runs the model twice.
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
@@ -107,14 +132,36 @@ steps:
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Omni · Qwen3-Omni Test"
|
||||
source_file_dependencies: omni_qwen3_omni_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_qwen3_omni.py
|
||||
- tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py
|
||||
- tests/e2e/online_serving/test_qwen3_omni.py
|
||||
- tests/helpers/runtime.py
|
||||
- vllm_omni/entrypoints/openai/serving_chat.py
|
||||
- vllm_omni/model_executor/models/qwen3_omni/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/qwen2_5_omni/qwen2_5_omni_thinker.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/cuda_graph_decoder_wrapper.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_omni.py
|
||||
- vllm_omni/deploy/qwen3_omni_moe.yaml
|
||||
- vllm_omni/deploy/qwen3_omni_moe_thinking.yaml
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py tests/e2e/online_serving/test_qwen3_omni.py tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_minicpmo_4_5.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5.py
|
||||
- vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja
|
||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||
- vllm_omni/model_executor/models/step_audio2/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/utils.py
|
||||
- vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
@@ -127,14 +174,59 @@ steps:
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_function
|
||||
source_file_dependencies:
|
||||
- tests/assets/minicpmo_4_5/response_required_16k.wav
|
||||
- tests/assets/minicpmo_4_5/soft_interrupt_16k.wav
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_duplex.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py
|
||||
- tests/e2e/online_serving/test_minicpmo_realtime_duplex_drivers.py
|
||||
- tests/e2e/online_serving/helpers/minicpmo_realtime_duplex_scenarios.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_multi_session.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_server_vad.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||
- vllm_omni/engine/duplex/
|
||||
- vllm_omni/entrypoints/duplex/
|
||||
# Public duplex client library + its unit suites: client-side
|
||||
# changes must re-run the duplex e2e group. The live client probe
|
||||
# (test_duplex_client_live.py, single GPU, core tier) runs in the
|
||||
# ready pipeline's duplex group.
|
||||
- vllm_omni/clients/
|
||||
- tests/clients/
|
||||
- vllm_omni/entrypoints/duplex_request_client.py
|
||||
- vllm_omni/outputs/duplex.py
|
||||
- vllm_omni/model_executor/duplex_sampling.py
|
||||
- tests/engine/duplex/
|
||||
- tests/entrypoints/duplex/
|
||||
- tests/model_executor/models/minicpmo_4_5/duplex/
|
||||
# Legacy Realtime probe client + video stacking used by the e2e drivers.
|
||||
- vllm_omni/experimental/fullduplex/
|
||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||
- vllm_omni/model_executor/models/step_audio2/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/utils.py
|
||||
- vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py
|
||||
- vllm_omni/core/sched/
|
||||
- vllm_omni/outputs/multimodal_accumulation.py
|
||||
- vllm_omni/engine/stage_init_utils.py
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/engine/orchestrator.py
|
||||
- vllm_omni/entrypoints/cli/serve.py
|
||||
- vllm_omni/entrypoints/openai/api_server.py
|
||||
- vllm_omni/entrypoints/openai/duplex_capability.py
|
||||
- vllm_omni/config/stage_config.py
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Qwen Image Test"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
- vllm_omni/diffusion/models/dmd2/
|
||||
- vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_qwenimage.py
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c '
|
||||
@@ -144,7 +236,11 @@ steps:
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_wan22_t2v.py
|
||||
- tests/e2e/online_serving/test_wan22_t2v.py
|
||||
- vllm_omni/diffusion/models/wan2_2/
|
||||
- vllm_omni/diffusion/models/dmd2/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -154,7 +250,9 @@ steps:
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · HunyuanVideo-1.5 Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_hunyuan_video_15_expansion.py
|
||||
- vllm_omni/diffusion/models/hunyuan_video/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -164,7 +262,17 @@ steps:
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · MiniMax-H3 L3 DLO DP2 and FastH3"
|
||||
source_file_dependencies: diffusion_minimax_h3_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/minimax_h3/
|
||||
- tests/helpers/assertions.py
|
||||
- tests/helpers/mark.py
|
||||
- tests/helpers/media.py
|
||||
- tests/helpers/runtime.py
|
||||
- vllm_omni/diffusion/models/minimax_h3/
|
||||
- vllm_omni/diffusion/lora/
|
||||
- vllm_omni/diffusion/offloader/
|
||||
- vllm_omni/diffusion/distributed/
|
||||
- vllm_omni/entrypoints/openai/
|
||||
# Keep four server lifecycles in one Buildkite job, but never in one
|
||||
# pytest process. DLO uses multiprocessing shared-memory queues; the
|
||||
# parent's resource_tracker can retain a stale /psm_* entry during
|
||||
|
||||
+126
-141
@@ -12,145 +12,138 @@ steps:
|
||||
- group: ":card_index_dividers: Omni Model Test"
|
||||
key: nightly-omni-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" || build.pull_request.labels includes "omni-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Omni · Function Test with H100 · Single-GPU"
|
||||
source_file_dependencies:
|
||||
- omni_qwen3_omni_function
|
||||
- omni_minicpmo_4_5_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -sv tests/e2e --run-level "full_model" -m "full_model and H100 and B200 and omni and cards_1" --ignore=tests/e2e/accuracy --ignore=tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py
|
||||
|
||||
- label: ":full_moon: Omni · Function Test with H100 · 2-GPU"
|
||||
source_file_dependencies:
|
||||
- omni_qwen3_omni_function
|
||||
- omni_minicpmo_4_5_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -sv tests/e2e --run-level "full_model" -m "full_model and H100 and B200 and omni and cards_2" --ignore=tests/e2e/accuracy --ignore=tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_function
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py -m "full_model and cuda and H100 and B200 and omni and cards_1" --run-level "full_model"
|
||||
- pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py -m "full_model and cuda and H100 and omni and cards_1" --run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Omni · Doc Test with L4 · 4-GPU"
|
||||
source_file_dependencies: omni_qwen2_5_omni_doc
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/examples/ -m "full_model and omni and L4 and B200 and cards_4" --run-level "full_model"
|
||||
- pytest -s -v tests/examples/ -m "full_model and omni and L4 and cards_4" --run-level "full_model"
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
- label: ":full_moon: Omni · Doc Test with H100 · 2-GPU"
|
||||
source_file_dependencies: omni_qwen3_omni_doc
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/examples/ -m "full_model and omni and H100 and B200 and cards_2" --run-level "full_model"
|
||||
- pytest -s -v tests/examples/ -m "full_model and omni and H100 and cards_2" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · Accuracy Test"
|
||||
source_file_dependencies: omni_qwen3_omni_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export SEED_TTS_WER_EVAL=1
|
||||
- export SEED_TTS_EVAL_DEVICE=cuda:1
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model and H100 and B200 and cards_2" --run-level full_model
|
||||
pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model" --run-level full_model
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Accuracy Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export SEED_TTS_WER_EVAL=1
|
||||
- export SEED_TTS_EVAL_DEVICE=cuda:1
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/e2e/accuracy/minicpmo_4_5/test_minicpmo_4_5.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level full_model
|
||||
pytest -s -v tests/e2e/accuracy/minicpmo_4_5/test_minicpmo_4_5.py -m "full_model and cuda" --run-level full_model
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/e2e/accuracy/minicpmo_4_5/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · No Async Chunk"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: nightly-omni-performance-no-async-chunk
|
||||
timeout_in_minutes: 300
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json -m "H100 and B200 and cards_2"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · Async Chunk"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: nightly-omni-performance-async-chunk
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json -m "H100 and B200 and full_model and cards_2"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json -m "H100 and full_model"
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json -m "H100 and B200 and cards_1"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Seed-TTS Perf Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5-duplex-seed-tts
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json -m "H100 and B200 and cards_1"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Omni · Multi-Replica Startup Test with 4x H100"
|
||||
source_file_dependencies: omni_qwen3_omni_function
|
||||
timeout_in_minutes: 45
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py -m "full_model and H100 and B200 and cards_4" --run-level "core_model"
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py -m "full_model" --run-level "core_model"
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- group: ":card_index_dividers: TTS Model Test"
|
||||
key: nightly-tts-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" || build.pull_request.labels includes "tts-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: TTS · Function Test with L4"
|
||||
source_file_dependencies: tts_qwen3_tts_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- export VLLM_USE_DEEP_GEMM="0"
|
||||
- export VLLM_MOE_USE_DEEP_GEMM="0"
|
||||
- pytest -s -v tests/e2e/ -m "full_model and L4 and B200 and tts and cards_1" --run-level "full_model" --ignore=tests/e2e/accuracy
|
||||
- pytest -s -v tests/e2e/ -m "full_model and L4 and tts" --run-level "full_model" --ignore=tests/e2e/accuracy
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: ":full_moon: TTS · Perf Test · Single-GPU"
|
||||
source_file_dependencies: tts_qwen3_tts_perf
|
||||
key: nightly-tts-performance-single
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
@@ -158,13 +151,13 @@ steps:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and B200 and cards_1"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and cards_1"
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: TTS · Perf Test · 2-GPU"
|
||||
source_file_dependencies: tts_qwen3_tts_perf
|
||||
key: nightly-tts-performance-2gpu
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
@@ -172,10 +165,11 @@ steps:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and B200 and cards_2"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and cards_2"
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- group: ":card_index_dividers: Tiny Model Tests [Multi-GPU]"
|
||||
key: nightly-tiny-model-test-group
|
||||
@@ -186,7 +180,6 @@ steps:
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Tiny Model Tests · Diffusion (Multi-GPU accelerations) · 2-GPU"
|
||||
source_file_dependencies: diffusion_tiny_model
|
||||
timeout_in_minutes: 30
|
||||
# NOTE: Single-GPU (core_model) tiny model tests run on the ready label,
|
||||
# so nightly only adds the multi-GPU parallelism configurations.
|
||||
@@ -196,85 +189,91 @@ steps:
|
||||
# for the CI, since these tests should pass irrespective of whether or not we use
|
||||
# the full weights or not.
|
||||
commands:
|
||||
- pytest -sv tests/model_tests/diffusion -m 'full_model and L4 and B200 and cuda and cards_2' --run-level "core_model"
|
||||
- pytest -sv tests/model_tests/diffusion -m 'full_model and cuda and cards_2' --run-level "core_model"
|
||||
mirror_hardwares: l4_2
|
||||
|
||||
- label: ":full_moon: Tiny Model Tests · Diffusion (Multi-GPU accelerations) · 4-GPU"
|
||||
source_file_dependencies: diffusion_tiny_model
|
||||
timeout_in_minutes: 30
|
||||
# CFG+TP extra_test_groups request 2×2=4 devices (see get_required_device_count).
|
||||
commands:
|
||||
- pytest -sv tests/model_tests/diffusion -m 'full_model and L4 and B200 and cuda and cards_4' --run-level "core_model"
|
||||
- pytest -sv tests/model_tests/diffusion -m 'full_model and cuda and cards_4' --run-level "core_model"
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
- group: ":card_index_dividers: Diffusion X2I(&A&T) Model Test"
|
||||
key: nightly-diffusion-x2iat-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2iat-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · Single-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_expansion.py
|
||||
-m "full_model and diffusion and H100 and B200 and cards_1"
|
||||
--run-level "full_model"
|
||||
|
||||
- label: ":robot_face: Robot Policy OpenPI · π0.5 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pip install --no-deps "openpi-client @ git+https://github.com/Physical-Intelligence/openpi.git@215abfb217dbac7d5f1273282331b9b1866c0479#subdirectory=packages/openpi-client"
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_pi05_expansion.py
|
||||
-m "full_model and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · 2-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_expansion.py
|
||||
-m "full_model and diffusion and H100 and B200 and cards_2"
|
||||
-m "full_model and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with L4 · Single-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Boogu Edit CFG · 3-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -sv tests/e2e/offline_inference/test_qwen_image_autoround_w4a16_expansion.py -m "full_model and diffusion and L4 and B200 and cards_1" --run-level "full_model"
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_boogu_image_edit_expansion.py
|
||||
-k "test_double_guidance_cfg_parallel and cfg_parallel_3_full"
|
||||
-m "slow and diffusion and cuda and H100 and cards_3"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_3
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with L4 · 4-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -sv tests/e2e/ -k "not test_wan and not hunyuan" -m "full_model and diffusion and L4 and cards_4" --run-level "full_model" --ignore=tests/e2e/accuracy
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Doc Test"
|
||||
source_file_dependencies: diffusion_text_to_image_doc
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -s -v tests/examples/*/test_text_to_image.py -m "full_model and example and H100 and B200 and (cards_1 or cards_2)" --run-level "full_model"
|
||||
- pytest -s -v tests/examples/*/test_text_to_image.py -m "full_model and example and H100" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Accuracy Test"
|
||||
source_file_dependencies: diffusion_qwen_image_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export VLLM_HTTP_TIMEOUT_KEEP_ALIVE=120
|
||||
- pytest -s -v tests/e2e/accuracy/test_qwen_image.py -m "H100 and B200 and cards_1" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2i_matches_diffusers' -m "full_model and H100 and B200 and cards_1" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_qwen_image.py --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2i_matches_diffusers' -m full_model --run-level full_model
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: HunyuanImage3-DIT · Accuracy Test"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export HUNYUAN_IMAGE3_MODEL="tencent/HunyuanImage-3.0-Instruct"
|
||||
- export HUNYUAN_IMAGE3_DEVICES="0,1,2,3"
|
||||
- pytest -s -v tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py -m "full_model and H100 and B200 and cards_4" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py -m full_model --run-level full_model
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: ":full_moon: HiDream-O1-Image · Accuracy Test"
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/test_hidream_o1_image.py -m full_model --run-level full_model
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image · Single-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_perf
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-single
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
@@ -282,182 +281,168 @@ steps:
|
||||
- export CACHE_DIT_VERSION=1.5.0
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and B200 and cards_1"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and cards_1"
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image · 4-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_perf
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-4gpu
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN
|
||||
- export CACHE_DIT_VERSION=1.5.0
|
||||
# Do not pin DIFFUSION_ATTENTION_BACKEND: H100 auto-selects FLASH_ATTN;
|
||||
# B200 rejects explicit FLASH_ATTN without FA4 and uses CUDNN/TRTLLM.
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and B200 and cards_4"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and cards_4"
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- group: ":card_index_dividers: Diffusion X2V Model Test"
|
||||
key: nightly-diffusion-x2v-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2v-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 T2V Function Test · Single-GPU"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and B200 and cards_1" --run-level "full_model"
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and cards_1" --run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 T2V Function Test · 2-GPU"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and B200 and cards_2" --run-level "full_model"
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and cards_2" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 I2V/TI2V Function Test · Single-GPU"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and B200 and cards_1" --run-level "full_model"
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and cards_1" --run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 I2V/TI2V Function Test · 2-GPU"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and B200 and cards_2" --run-level "full_model"
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and cards_2" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Function Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level "full_model"
|
||||
- pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "full_model and cuda" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · LingBot Function Test"
|
||||
source_file_dependencies: diffusion_lingbot_function
|
||||
timeout_in_minutes: 120
|
||||
- label: ":full_moon: Diffusion X2V · MAGI-2 Preview Serving Smoke"
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/e2e/online_serving/test_lingbot_video.py
|
||||
tests/e2e/online_serving/test_lingbot_video_moe.py
|
||||
tests/e2e/offline_inference/test_lingbot_world_v2.py
|
||||
-m "full_model and diffusion and H100 and B200 and cards_1"
|
||||
--run-level "full_model"
|
||||
- pytest -s -v tests/e2e/online_serving/test_magi2.py -m "advanced_model and diffusion and cuda and H100 and cards_4" --run-level "advanced_model"
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Doc Test"
|
||||
source_file_dependencies: diffusion_image_to_video_doc
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -s -v tests/examples/offline_inference/test_image_to_video.py -m "full_model and example and H100 and B200 and cards_1" --run-level "full_model"
|
||||
- pytest -s -v tests/examples/offline_inference/test_image_to_video.py -m "full_model and example and H100" --run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 Autoround Function Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
- label: ":full_moon: Diffusion X2V · Other Function Test"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_wan22_autoround_w4a16_expansion.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 Device-Postprocess Equivalence Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- |
|
||||
VLLM_OMNI_DEVICE_POSTPROCESS_MODEL=Wan-AI/Wan2.2-TI2V-5B-Diffusers \
|
||||
pytest -s -v tests/e2e/offline_inference/test_device_postprocess_equivalence.py -m "full_model and H100 and B200 and cuda and cards_1" --run-level "full_model"
|
||||
- pytest -s -v tests/e2e/offline_inference/test_wan22_autoround_w4a16_expansion.py -m "full_model and cuda" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 Accuracy Test"
|
||||
source_file_dependencies: diffusion_wan22_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/wan22_i2v/test_wan22_i2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2v_matches_diffusers' -m "full_model and H100 and B200 and cards_1" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/wan22_i2v/test_wan22_i2v_video_similarity.py -m full_model --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2v_matches_diffusers' -m full_model --run-level full_model
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · MiniMax H3 I2VA/Ref2VA Accuracy Test"
|
||||
source_file_dependencies: diffusion_minimax_h3_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/minimax_h3/test_minimax_h3_i2va_ref2va_similarity.py -m "full_model and H100 and B200 and cards_4" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/minimax_h3/test_minimax_h3_i2va_ref2va_similarity.py -m full_model --run-level full_model
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Accuracy Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_accuracy
|
||||
- label: ":full_moon: Diffusion X2V · Other Accuracy Test"
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/hunyuanvideo15_t2v/test_hunyuanvideo15_t2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/hunyuanvideo15_i2v/test_hunyuanvideo15_i2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/hunyuanvideo15_t2v/test_hunyuanvideo15_t2v_video_similarity.py -m full_model --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/hunyuanvideo15_i2v/test_hunyuanvideo15_i2v_video_similarity.py -m full_model --run-level full_model
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · Single-GPU"
|
||||
source_file_dependencies: diffusion_wan22_perf
|
||||
key: nightly-diffusion-x2v-performance-single
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and B200 and cards_1"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and cards_1"
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · 2-GPU"
|
||||
source_file_dependencies:
|
||||
- diffusion_wan22_perf
|
||||
- diffusion_cosmos3_perf
|
||||
key: nightly-diffusion-x2v-performance-2gpu
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and B200 and cards_2"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and cards_2"
|
||||
EXIT1=$$?
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_cosmos3_vllm_omni.json -m "H100 and B200 and cards_2"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_cosmos3_vllm_omni.json -m "H100 and cards_2"
|
||||
EXIT2=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
if [ $$EXIT1 -ne 0 ]; then exit $$EXIT1; fi
|
||||
exit $$EXIT2
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · HunyuanVideo-1.5"
|
||||
source_file_dependencies: diffusion_hunyuan_video_perf
|
||||
key: nightly-diffusion-x2v-performance-hunyuanvideo15
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json -m "H100 and B200 and (cards_1 or cards_2)"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json
|
||||
EXIT1=$$?
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_i2v_vllm_omni.json -m "H100 and B200 and (cards_1 or cards_2)"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_i2v_vllm_omni.json
|
||||
EXIT2=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
if [ $$EXIT1 -ne 0 ]; then exit $$EXIT1; fi
|
||||
exit $$EXIT2
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · MiniMax-H3"
|
||||
source_file_dependencies: diffusion_minimax_h3_perf
|
||||
key: nightly-diffusion-x2v-performance-minimax-h3
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_minimax_h3_vllm_omni.json -m "H100 and B200 and cards_4"
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_minimax_h3_vllm_omni.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
key: nightly-diffusion-test-group
|
||||
@@ -465,59 +450,59 @@ steps:
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
- label: ":full_moon: Diffusion · Distributed Test with L4 · 2-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_2' --run-level "full_model"
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and cards_2' --run-level "full_model"
|
||||
mirror_hardwares: l4_2
|
||||
|
||||
- label: ":full_moon: Diffusion · Distributed Test with L4 · 3-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_3' --run-level "full_model"
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and cards_3' --run-level "full_model"
|
||||
mirror_hardwares: l4_3
|
||||
|
||||
- label: ":full_moon: Diffusion · Distributed Test with L4 · 4-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_4' --run-level "full_model"
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and cards_4' --run-level "full_model"
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
- label: ":full_moon: Diffusion · Distributed Test with H100 · 2-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and B200 and cards_2' --run-level "full_model"
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and cards_2' --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion · Distributed Test with H100 · 4-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and B200 and cards_4' --run-level "full_model"
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and cards_4' --run-level "full_model"
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: ":full_moon: Diffusion · Offloader Test"
|
||||
source_file_dependencies: diffusion_offloader
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/offloader -m "full_model and L4 and B200 and cuda and cards_1"
|
||||
- pytest -sv tests/diffusion/offloader -m "full_model and cuda"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: ":full_moon: Diffusion · Quantization Test with H100 · Single-GPU"
|
||||
source_file_dependencies: diffusion_quantization
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/quantization -m 'full_model and cuda and H100 and B200 and cards_1' --run-level "full_model"
|
||||
- pytest -sv tests/diffusion/quantization -m 'full_model and cuda and H100' --run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion · MiniMax H3 FP8 Quality Test with H100 · 2-GPU"
|
||||
source_file_dependencies: diffusion_minimax_h3_function
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/models/minimax_h3/test_minimax_h3_quantization_quality.py -m 'full_model and cuda and H100 and B200 and cards_2' --run-level "full_model"
|
||||
- pytest -sv tests/diffusion/models/minimax_h3/test_minimax_h3_quantization_quality.py -m 'full_model and cuda and H100' --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion · Quantization Test with L4"
|
||||
source_file_dependencies: diffusion_quantization
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pip install "vllm-gguf-plugin==0.0.4"
|
||||
- pytest -sv tests/diffusion/quantization -m 'full_model and cuda and L4 and B200 and cards_1' --run-level "full_model"
|
||||
- pytest -sv tests/diffusion/quantization -m 'full_model and cuda and L4' --run-level "full_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
# NOTE: ":email: Nightly Collection & Email" is deprecated and will be removed soon.
|
||||
# Do not add new depends_on entries or extend this step.
|
||||
|
||||
+131
-23
@@ -38,12 +38,6 @@ steps:
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
|
||||
- label: "Diffusion · FlashAttention Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- timeout 15m pytest -s -v tests/diffusion/attention/ -m 'core_model and cuda and L4 and cards_1' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Offloader Test"
|
||||
commands:
|
||||
- timeout 40m pytest -s -v tests/diffusion/offloader -m "core_model and cuda" --run-level "core_model"
|
||||
@@ -60,19 +54,16 @@ steps:
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Distributed Test · Single-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_1' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Distributed Test · 2-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_2' --run-level "core_model"
|
||||
mirror_hardwares: l4_2
|
||||
|
||||
- label: "Diffusion · Distributed & Attention Test · 4-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_4' --run-level "core_model"
|
||||
- timeout 20m pytest -sv tests/diffusion/attention/test_attention_sp.py -m 'core_model and cuda and L4 and cards_4' --run-level "core_model"
|
||||
@@ -102,7 +93,7 @@ steps:
|
||||
commands:
|
||||
- |
|
||||
timeout 15m bash -c "
|
||||
pytest -sv tests/engine/ tests/model_executor/ tests/worker/test_batched_omni_output.py tests/worker_v2/ -m 'core_model and cuda' --run-level 'core_model'
|
||||
pytest -sv tests/engine/ tests/model_executor/ tests/worker/test_batched_omni_output.py -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
@@ -129,14 +120,29 @@ steps:
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "Custom Pipeline Test"
|
||||
source_file_dependencies: custom_pipeline
|
||||
source_file_dependencies:
|
||||
- tests/e2e/features/custom_pipeline/
|
||||
- tests/e2e/features/helpers/custom_pipeline.py
|
||||
- vllm_omni/diffusion/
|
||||
- vllm_omni/engine/
|
||||
- vllm_omni/entrypoints/
|
||||
- vllm_omni/inputs/
|
||||
- vllm_omni/outputs/
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/e2e/features/custom_pipeline/ -m "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
|
||||
- label: "RLHF · VeRL-Omni E2E Test"
|
||||
source_file_dependencies: rlhf_verl_omni
|
||||
source_file_dependencies:
|
||||
- tests/e2e/features/rlhf_test/test_verl_omni_e2e.py
|
||||
- tests/e2e/features/helpers/verl_omni_server.py
|
||||
- tests/e2e/features/helpers/custom_pipeline.py
|
||||
- vllm_omni/diffusion/
|
||||
- vllm_omni/engine/
|
||||
- vllm_omni/entrypoints/
|
||||
- vllm_omni/inputs/
|
||||
- vllm_omni/outputs/
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
@@ -145,7 +151,17 @@ steps:
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Omni · Qwen3-Omni Test"
|
||||
source_file_dependencies: omni_qwen3_omni_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen3_omni.py
|
||||
- tests/helpers/runtime.py
|
||||
- vllm_omni/entrypoints/openai/serving_chat.py
|
||||
- vllm_omni/model_executor/models/qwen3_omni/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/qwen2_5_omni/qwen2_5_omni_thinker.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/cuda_graph_decoder_wrapper.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_omni.py
|
||||
- vllm_omni/deploy/qwen3_omni_moe.yaml
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
@@ -154,7 +170,14 @@ steps:
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Offline Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_minicpmo_4_5.py
|
||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||
- vllm_omni/model_executor/models/step_audio2/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/utils.py
|
||||
- vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
@@ -163,7 +186,15 @@ steps:
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Online Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5.py
|
||||
- vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja
|
||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||
- vllm_omni/model_executor/models/step_audio2/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/utils.py
|
||||
- vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
@@ -172,7 +203,48 @@ steps:
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_function
|
||||
source_file_dependencies:
|
||||
- tests/assets/minicpmo_4_5/response_required_16k.wav
|
||||
- tests/assets/minicpmo_4_5/soft_interrupt_16k.wav
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_duplex.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py
|
||||
- tests/e2e/online_serving/test_minicpmo_realtime_duplex_drivers.py
|
||||
- tests/e2e/online_serving/helpers/minicpmo_realtime_duplex_scenarios.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_multi_session.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_server_vad.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||
- vllm_omni/engine/duplex/
|
||||
- vllm_omni/entrypoints/duplex/
|
||||
# Public duplex client library + its unit suites: client-side
|
||||
# changes must re-run the duplex e2e group, which includes the
|
||||
# live client probe (test_duplex_client_live.py, single GPU).
|
||||
- vllm_omni/clients/
|
||||
- tests/clients/
|
||||
- tests/e2e/online_serving/test_duplex_client_live.py
|
||||
- vllm_omni/entrypoints/duplex_request_client.py
|
||||
- vllm_omni/outputs/duplex.py
|
||||
- vllm_omni/model_executor/duplex_sampling.py
|
||||
- tests/engine/duplex/
|
||||
- tests/entrypoints/duplex/
|
||||
- tests/model_executor/models/minicpmo_4_5/duplex/
|
||||
# Legacy Realtime probe client + video stacking used by the e2e drivers.
|
||||
- vllm_omni/experimental/fullduplex/
|
||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||
- vllm_omni/model_executor/models/step_audio2/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/utils.py
|
||||
- vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py
|
||||
- vllm_omni/core/sched/
|
||||
- vllm_omni/outputs/multimodal_accumulation.py
|
||||
- vllm_omni/engine/stage_init_utils.py
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/engine/orchestrator.py
|
||||
- vllm_omni/entrypoints/cli/serve.py
|
||||
- vllm_omni/entrypoints/openai/api_server.py
|
||||
- vllm_omni/entrypoints/openai/duplex_capability.py
|
||||
- vllm_omni/config/stage_config.py
|
||||
commands:
|
||||
- |
|
||||
timeout 35m bash -c "
|
||||
@@ -182,14 +254,29 @@ steps:
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Perf Test"
|
||||
timeout_in_minutes: 60
|
||||
source_file_dependencies: omni_minicpmo_4_5_perf
|
||||
source_file_dependencies:
|
||||
- tests/dfx/perf/tests/test_minicpmo_4_5_ready.json
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||
- vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_ready.json -m 'core_model and cuda'
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
||||
source_file_dependencies: tts_qwen3_tts_function
|
||||
source_file_dependencies:
|
||||
- tests/helpers/media.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_customvoice.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/common/alias_free_activation.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_tts.py
|
||||
- vllm_omni/deploy/qwen3_tts.yaml
|
||||
- vllm_omni/entrypoints/openai/serving_speech.py
|
||||
- vllm_omni/entrypoints/openai/tts_adapters/
|
||||
- vllm_omni/engine/stage_pool.py
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
@@ -199,7 +286,10 @@ steps:
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_wan22_t2v.py
|
||||
- vllm_omni/diffusion/models/wan2_2/
|
||||
- vllm_omni/diffusion/models/dmd2/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -209,7 +299,12 @@ steps:
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Cosmos3 Test"
|
||||
source_file_dependencies: diffusion_cosmos3_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_cosmos3.py
|
||||
- vllm_omni/diffusion/models/cosmos3/
|
||||
- vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_wan.py
|
||||
- vllm_omni/experimental/world_models/
|
||||
- vllm_omni/model_extras/cosmos3.py
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -220,7 +315,14 @@ steps:
|
||||
|
||||
- label: "Diffusion · MiniMax-H3 DLO DP2 T2VA Test"
|
||||
timeout_in_minutes: 90
|
||||
source_file_dependencies: diffusion_minimax_h3_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_minimax_h3_dlo_dp2_t2va.py
|
||||
- tests/helpers/assertions.py
|
||||
- tests/helpers/runtime.py
|
||||
- vllm_omni/diffusion/models/minimax_h3/
|
||||
- vllm_omni/diffusion/offloader/
|
||||
- vllm_omni/diffusion/distributed/
|
||||
- vllm_omni/entrypoints/openai/
|
||||
commands:
|
||||
- |
|
||||
timeout 80m bash -c "
|
||||
@@ -230,7 +332,11 @@ steps:
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Qwen Image Test"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
- vllm_omni/diffusion/models/dmd2/
|
||||
- vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_qwenimage.py
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -240,7 +346,9 @@ steps:
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · HunyuanVideo-1.5 Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_function
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_hunyuan_video_15_expansion.py
|
||||
- vllm_omni/diffusion/models/hunyuan_video/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
|
||||
@@ -29,42 +29,36 @@ steps:
|
||||
steps:
|
||||
|
||||
- label: "Reliability Test · qwen3-omni"
|
||||
source_file_dependencies: omni_qwen3_omni_reliability
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_qwen3_omni.py -m "slow"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Reliability Test · wan22"
|
||||
source_file_dependencies: diffusion_wan22_reliability
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_wan22.py -m "slow"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Reliability Test · hunyuan-image"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_reliability
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_hunyuan_image.py -m "slow"
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: "Reliability Test · Invalid parameters · H100 · Single-GPU"
|
||||
source_file_dependencies: reliability_invalid_param_h100
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100 and cards_1"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Reliability Test · Invalid parameters · H100 · 2-GPU"
|
||||
source_file_dependencies: reliability_invalid_param_h100
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100 and cards_2"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Reliability Test · Invalid parameters · L4"
|
||||
source_file_dependencies: reliability_invalid_param_l4
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and L4"
|
||||
@@ -76,7 +70,6 @@ steps:
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · vLLM Text"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: weekly-omni-performance-vllm-text
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
@@ -103,7 +96,6 @@ steps:
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · Multi-Replica"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: weekly-omni-performance-multi-replicas
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
@@ -191,14 +183,13 @@ steps:
|
||||
# from downgrading transformers; see
|
||||
# examples/offline_inference/text_to_speech/README.md.
|
||||
- label: "TTS · Gepard-1.0 · L4"
|
||||
timeout_in_minutes: 90
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- printf '%s\n' "transformers>=5.5.3" "huggingface-hub>=1.0" > /tmp/gepard-overrides.txt
|
||||
- uv pip install --python "$(python3 -c 'import sys; print(sys.executable)')" "nemo_toolkit[tts]==2.7.3" --overrides /tmp/gepard-overrides.txt
|
||||
- >-
|
||||
pytest -s -v tests/e2e/offline_inference/test_gepard_tts.py
|
||||
tests/e2e/online_serving/test_gepard_tts.py
|
||||
-m "tts and cuda"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: l4_1
|
||||
@@ -230,277 +221,24 @@ steps:
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
# Split the old shared H100 Single-GPU sweep: one pytest process collected
|
||||
# every slow+cards_1 diffusion file and exceeded 150 minutes.
|
||||
- label: "Diffusion · Qwen-Image · H100 · Single-GPU"
|
||||
timeout_in_minutes: 120
|
||||
- label: "Diffusion · H100 · Single-GPU"
|
||||
timeout_in_minutes: 150
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_edit.py
|
||||
tests/e2e/online_serving/test_qwen_image_edit_expansion.py
|
||||
tests/e2e/online_serving/test_qwen_image_layered.py
|
||||
tests/e2e/online_serving/test_qwen_image_layered_expansion.py
|
||||
tests/e2e/accuracy/test_qwen_image_edit.py
|
||||
tests/e2e/accuracy/test_qwen_image_layered.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
tests/e2e/ -m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Wan2.1 VACE · H100 · Single-GPU"
|
||||
- label: "Diffusion · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_wan_2_1_vace_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · LongCat · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_longcat_image_expansion.py
|
||||
tests/e2e/online_serving/test_longcat_image_edit_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Bagel · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_bagel.py
|
||||
tests/e2e/online_serving/test_bagel_expansion.py
|
||||
tests/e2e/offline_inference/test_bagel.py
|
||||
tests/e2e/offline_inference/test_bagel_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Boogu · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_boogu_image.py
|
||||
tests/e2e/online_serving/test_boogu_image_edit.py
|
||||
tests/e2e/online_serving/test_boogu_image_expansion.py
|
||||
tests/e2e/online_serving/test_boogu_image_edit_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Flux · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_flux_2_dev_expansion.py
|
||||
tests/e2e/offline_inference/test_flux1_schnell_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · LTX · H100 · Single-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_ltx.py
|
||||
tests/e2e/online_serving/test_ltx25.py
|
||||
tests/e2e/accuracy/ltx/test_ltx_official_similarity.py
|
||||
tests/e2e/accuracy/ltx/test_ltx25_official_similarity.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Krea2 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_krea2_expansion.py
|
||||
tests/e2e/offline_inference/test_krea2_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · HiDream-I1 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_hidream_i1_full_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · SANA-Video · H100 · Single-GPU"
|
||||
source_file_dependencies: diffusion_sana_video_function
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export SANA_VIDEO_GOLDEN_BASE_URL=https://vllm-public-assets.s3.us-west-2.amazonaws.com/omni-assets/sana-video/v2
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_sana_video_expansion.py
|
||||
tests/e2e/accuracy/sana_video/
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · SenseNova-U1 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/offline_inference/test_sensenova_u1_expansion.py
|
||||
tests/e2e/offline_inference/test_sensenova_u1_text2img_expansion.py
|
||||
tests/e2e/offline_inference/test_sensenova_u1_img2img_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · MammothModa2 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/offline_inference/test_mammoth_moda2_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Helios · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/accuracy/test_video_streaming_output_similarity.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
# Split the old shared H100 2-GPU sweep: one pytest process collected every
|
||||
# slow+cards_2 diffusion file and exceeded 90 minutes.
|
||||
- label: "Diffusion · Qwen-Image · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_edit_expansion.py
|
||||
tests/e2e/online_serving/test_qwen_image_layered_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
tests/e2e/ -m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Wan2.1 VACE · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_wan_2_1_vace_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · LongCat · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_longcat_image_expansion.py
|
||||
tests/e2e/online_serving/test_longcat_image_edit_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Bagel · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_bagel_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Boogu · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_boogu_image_expansion.py
|
||||
tests/e2e/online_serving/test_boogu_image_edit_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Flux · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_flux_2_dev_expansion.py
|
||||
tests/e2e/offline_inference/test_flux1_kontext_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · GLM-Image · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_glm_image_expansion.py
|
||||
tests/e2e/offline_inference/test_glm_image_autoround_w4a16_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · LTX · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_ltx.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Krea2 · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/offline_inference/test_krea2_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · DreamZero · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_dreamzero_expansion.py
|
||||
tests/e2e/accuracy/test_dreamzero.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · H100 · 3-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and diffusion and H100 and cards_3"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_3
|
||||
|
||||
- label: "Diffusion · H100 · 4-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
@@ -508,33 +246,4 @@ steps:
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and diffusion and H100 and cards_4"
|
||||
--run-level "full_model"
|
||||
--ignore=tests/e2e/online_serving/test_magi2.py
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
# Dedicated: HiDream-O1 accuracy needs a long TP2 run; the shared H100
|
||||
# 2-GPU sweep is only 90 minutes.
|
||||
- label: "Diffusion · HiDream-O1-Image Accuracy · H100 · 2-GPU"
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/test_hidream_o1_image.py -m "slow and diffusion and cuda and H100 and cards_2" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
# Dedicated: Boogu CFG-parallel size 3 needs 3 GPUs; weekly has no H100 3-GPU sweep.
|
||||
- label: "Diffusion · Boogu Edit CFG · H100 · 3-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_boogu_image_edit_expansion.py
|
||||
-k "test_double_guidance_cfg_parallel and cfg_parallel_3_full"
|
||||
-m "slow and diffusion and cuda and H100 and cards_3"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_3
|
||||
|
||||
# Dedicated: MAGI-2 Preview serving smoke needs ~30 min server init; the
|
||||
# shared H100 4-GPU sweep is only 90 minutes.
|
||||
- label: "Diffusion · MAGI-2 Preview Serving Smoke · H100 · 4-GPU"
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_magi2.py -m "slow and diffusion and cuda and H100 and cards_4" --run-level "full_model"
|
||||
mirror_hardwares: h100_4
|
||||
@@ -10,7 +10,7 @@ steps:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
# Buildkite will automatically replace this with the actual commit hash
|
||||
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}"
|
||||
VLLM_VERSION: "v0.29.0"
|
||||
VLLM_VERSION: "v0.28.0"
|
||||
priority: 100
|
||||
timeout_in_minutes: 60
|
||||
soft_fail: false
|
||||
@@ -93,7 +93,7 @@ steps:
|
||||
command: |
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/npu/test-npu-ready.yml
|
||||
|
||||
# L4 Test — main+NIGHTLY=1 (scheduled), or PR nightly-test label
|
||||
# L4 Test — main+NIGHTLY=1 (scheduled), or PR with specific label (e.g. add label then Rebuild)
|
||||
- label: "Upload Nightly Pipeline"
|
||||
depends_on:
|
||||
- image-build-a2
|
||||
@@ -102,11 +102,6 @@ steps:
|
||||
- image-build-310p
|
||||
key: upload-nightly-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${NIGHTLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--all"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/npu/test-npu-nightly.yml
|
||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/npu/test-npu-nightly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
@@ -96,7 +96,13 @@
|
||||
# key: upload-nightly-pipeline
|
||||
# if: >-
|
||||
# (build.branch == "main" && build.env("NIGHTLY") == "1") ||
|
||||
# (build.branch != "main" && build.pull_request.labels includes "nightly-test")
|
||||
# (build.branch != "main" && (
|
||||
# build.pull_request.labels includes "nightly-test" ||
|
||||
# build.pull_request.labels includes "omni-test" ||
|
||||
# build.pull_request.labels includes "tts-test" ||
|
||||
# build.pull_request.labels includes "diffusion-x2iat-test" ||
|
||||
# build.pull_request.labels includes "diffusion-x2v-test"
|
||||
# ))
|
||||
# commands:
|
||||
# - buildkite-agent pipeline upload .buildkite/npu/test-npu-nightly.yml
|
||||
# agents:
|
||||
|
||||
@@ -4,10 +4,10 @@ steps:
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "omni-test"
|
||||
steps:
|
||||
- label: ":full_moon: Omni · Perf Test · No Async Chunk"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: nightly-omni-performance-no-async-chunk
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
@@ -24,7 +24,6 @@ steps:
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · Perf Test · Async Chunk"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: nightly-omni-performance-async-chunk
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
@@ -41,7 +40,6 @@ steps:
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_function
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
@@ -50,7 +48,6 @@ steps:
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5_expansion.py -m 'full_model' --run-level 'full_model'
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_function
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
@@ -65,7 +62,6 @@ steps:
|
||||
-m "npu and A3 and omni"
|
||||
--run-level full_model
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Accuracy Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_accuracy
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
@@ -86,7 +82,6 @@ steps:
|
||||
buildkite-agent artifact upload "tests/e2e/accuracy/minicpmo_4_5/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5-npu
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
@@ -103,7 +98,6 @@ steps:
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test (A2)"
|
||||
source_file_dependencies: omni_minicpmo_4_5_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5-npu-a2
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a2b3_npu_1
|
||||
@@ -121,7 +115,6 @@ steps:
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Seed-TTS Perf Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5-duplex-seed-tts-npu
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
@@ -140,10 +133,9 @@ steps:
|
||||
- group: ":card_index_dividers: TTS Model Test"
|
||||
key: nightly-tts-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" || build.pull_request.labels includes "tts-test"
|
||||
steps:
|
||||
- label: ":full_moon: TTS · Perf Test"
|
||||
source_file_dependencies: tts_qwen3_tts_perf
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
@@ -159,15 +151,15 @@ steps:
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- group: ":card_index_dividers: Diffusion X2I(&A&T) Model Test"
|
||||
key: nightly-diffusion-x2iat-group
|
||||
- group: ":card_index_dividers: Diffusion I2I Model Test"
|
||||
key: nightly-HunyuanImage3-x2i-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2iat-test"
|
||||
steps:
|
||||
- label: ":full_moon: HunyuanImage3-DIT · Accuracy Test"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_accuracy
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
@@ -177,8 +169,15 @@ steps:
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py -m "full_model and A3" --run-level full_model
|
||||
- group: ":card_index_dividers: Diffusion Benchmark Perf Test"
|
||||
key: nightly-diffusion-benchmark-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2iat-test"
|
||||
steps:
|
||||
- label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=2 CFGP=2"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_perf
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
@@ -195,7 +194,6 @@ steps:
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=2 SP=2"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_perf
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
@@ -212,7 +210,6 @@ steps:
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=4"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_perf
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
@@ -233,41 +230,10 @@ steps:
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2v-test"
|
||||
steps:
|
||||
- label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Function Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_function
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a2b3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
HF_HUB_OFFLINE: "1"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "npu and A2" --run-level "full_model"
|
||||
- label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Perf Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_perf
|
||||
key: nightly-diffusion-x2v-performance-hunyuanvideo15
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
HF_HUB_OFFLINE: "1"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py -m "npu and A3" --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Diffusion X2V · Wan 2.2 Function Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
- label: ":full_moon: Diffusion X2V · Function Test"
|
||||
mirror_hardwares: a2b3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
@@ -275,8 +241,7 @@ steps:
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k npu_i2v --run-level "full_model"
|
||||
- label: ":full_moon: Diffusion X2V · Wan 2.2 Perf Test"
|
||||
source_file_dependencies: diffusion_wan22_perf
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test"
|
||||
key: nightly-diffusion-x2v-performance
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
|
||||
@@ -340,7 +340,7 @@ On supported GPU hosts, wrap a test or soak with the repository monitor:
|
||||
|
||||
```bash
|
||||
bash tests/dfx/stability/scripts/resource_monitor.sh run --backend gpu -- \
|
||||
pytest -s -v tests/dfx/stability/scripts/run_stability_<model>.py -m slow
|
||||
pytest -s -v tests/dfx/stability/scripts/test_stability_<model>.py -m slow
|
||||
```
|
||||
|
||||
Check the target revision's monitor backends. Do not claim CPU/NPU monitoring
|
||||
|
||||
@@ -468,10 +468,10 @@ When the user asks for **invalid parameter validation**, **invalid request bodie
|
||||
| **Invalid parameters Test · H100** | `pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100"` | Diffusion / omni / video invalid-param tests with `H100` hardware mark |
|
||||
| **Invalid parameters Test · L4** | `pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and L4"` | TTS / lighter models marked `L4` |
|
||||
|
||||
- **Trigger:** `build.env("WEEKLY") == "1"` (all weekly jobs) or PR label `weekly-test` (Reliability / Perf, then filtered by `source_file_dependencies`).
|
||||
- **Trigger:** `build.env("WEEKLY") == "1"` or PR label `weekly-test`.
|
||||
- **Default:** extending an existing `invalid_param_test` script needs **no YAML edit** — the weekly steps already sweep the whole directory.
|
||||
- **Edit YAML only** when adding a **new hardware queue**, a **new top-level script** that must run in isolation, or a **model-specific weekly shard** (mirror neighboring reliability steps).
|
||||
- Weekly Reliability / Perf jobs declare `source_file_dependencies`. Filtering applies only on the `weekly-test` label; `WEEKLY=1` on `main` keeps every job in those groups. CPU coverage (`WEEKLY=1` only) and the E2E Tests group (`NON_CRITICAL=1` only) do **not** use this field.
|
||||
- Weekly steps **do not** use `source_file_dependencies`.
|
||||
|
||||
**Example — append to `test_invalid_image_generation.py`:**
|
||||
|
||||
@@ -644,7 +644,7 @@ If the test is not already collected by an existing pipeline command (for exampl
|
||||
| **L2** | `test-ready.yml` with `core_model` + `source_file_dependencies` | merge / nightly pipelines |
|
||||
| **Invalid param** | `test-weekly.yml` — **Invalid parameters Test** group (`-m "slow and H100"` / `-m "slow and L4"`). Usually **no YAML edit** when appending cases to existing `invalid_param_test` scripts | `test-ready.yml`, `test-merge.yml`, `test-nightly.yml` |
|
||||
|
||||
`test-nightly.yml` shards use **explicit pytest file paths** in `commands` plus `source_file_dependencies`; PR trigger is `nightly-test` (path filter), or `NIGHTLY=1` on `main` (all jobs). Only suggest merge/ready YAML when the requested level is L3/L2 (or the user explicitly asks for multi-level CI).
|
||||
`test-nightly.yml` shards use **explicit pytest file paths** in `commands` (and PR labels like `diffusion-x2iat-test`); they generally **do not** use `source_file_dependencies`. Only suggest merge/ready YAML when the requested level is L3/L2 (or the user explicitly asks for multi-level CI).
|
||||
|
||||
**`test-nightly.yml` top-level groups** (each uses `full_model` + type marker in pytest `-m`):
|
||||
|
||||
@@ -653,7 +653,7 @@ If the test is not already collected by an existing pipeline command (for exampl
|
||||
| **Omni Model Test** | `omni` | Function / doc / accuracy / **perf** for Qwen-Omni family |
|
||||
| **TTS Model Test** | `tts` | `-m "full_model and L4 and tts"` (and H100 variants when enabled); **Perf Test** uses `run_benchmark.py` + `test_tts.json` |
|
||||
| **Diffusion X2I(&A&T) Model Test** | `diffusion` | Image/audio/text diffusion; explicit file shards for **Function**; **Perf Test · <Model>** uses `run_diffusion_benchmark.py` + JSON config |
|
||||
| **Diffusion X2V Model Test** | `diffusion` | Video-only (Wan, HunyuanVideo, …); separate **Perf** steps when in-tree |
|
||||
| **Diffusion X2V Model Test** | `diffusion` | Video-only (Wan, HunyuanVideo, …); PR label `diffusion-x2v-test`; separate **Perf** steps when in-tree |
|
||||
|
||||
Guidelines when editing YAML:
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ Every model-centric e2e test must declare **exactly one** type marker:
|
||||
| **Diffusion X2I(&A&T) Model Test** | x2**i** / x2**a** / x2**t** — image, audio, text (non-video) | Qwen-Image*, BAGEL, FLUX, SD3, Z-Image, LongCat, DreamZero |
|
||||
| **Diffusion X2V Model Test** | x2**v** — video only | Wan2.2, HunyuanVideo 1.5, Wan VACE |
|
||||
|
||||
PR label for L4 on a branch: `nightly-test` (jobs then filtered by `source_file_dependencies`). Scheduled `main` uses `NIGHTLY=1` and runs every nightly job. L5 Reliability / Perf use `weekly-test` with the same path filter; CPU coverage and the weekly E2E group are env-only (`WEEKLY=1` / `NON_CRITICAL=1`) and are not source-filtered.
|
||||
PR labels for selective nightly runs: `diffusion-x2iat-test`, `diffusion-x2v-test` (plus `nightly-test` / `NIGHTLY=1`).
|
||||
|
||||
## Level and Marker Mapping
|
||||
|
||||
@@ -238,7 +238,7 @@ pytest -s -v dfx/reliability/invalid_param_test/ -m "slow and L4"
|
||||
pytest -s -v dfx/reliability/invalid_param_test/test_invalid_image_generation.py::test_images_generations_invalid_requests -m "slow and H100"
|
||||
```
|
||||
|
||||
**Trigger:** `WEEKLY=1` (all jobs) or PR label `weekly-test` (Reliability / Perf, filtered by `source_file_dependencies`). Appending cases to existing scripts usually needs **no YAML edit** (directory sweep).
|
||||
**Trigger:** `WEEKLY=1` or PR label `weekly-test`. Appending cases to existing scripts usually needs **no YAML edit** (directory sweep). No `source_file_dependencies` on weekly steps.
|
||||
|
||||
### Platform-targeted examples
|
||||
|
||||
|
||||
@@ -67,11 +67,6 @@
|
||||
# File-level overrides within entrypoints/
|
||||
/vllm_omni/entrypoints/openai/errors.py @alex-jw-brooks @NickCao
|
||||
/vllm_omni/entrypoints/cli/benchmark/ @alex-jw-brooks @Bounty-hunter
|
||||
# Shared wire codec: protocol/realtime (OpenAI Realtime GA) and protocol/duplex
|
||||
# (vLLM-Omni's extension of it) — RFC #6592 P0a. Layer-neutral by design — the
|
||||
# engine depends on it — so it is owned by the serving-boundary document rather
|
||||
# than by any one consumer. — docs/design/module/entrypoints.md
|
||||
/vllm_omni/protocol/ @alex-jw-brooks @linyueqian @NickCao
|
||||
|
||||
# Error contracts — docs/design/module/error_contracts.md
|
||||
/vllm_omni/errors.py @alex-jw-brooks @NickCao
|
||||
|
||||
+17
@@ -281,3 +281,20 @@ lance_compare/
|
||||
|
||||
# Linting binaries downloaded by local pre-commit hooks
|
||||
shellcheck*/
|
||||
|
||||
# --- edge-infer -------------------------------------------------------------
|
||||
# Measurement artifacts are the substance of this fork, not build output: every
|
||||
# published figure is traceable to a file below. They are tracked despite the
|
||||
# blanket `*.json` and `results/` rules above. Binary captures (.npz, .onnx,
|
||||
# .wav, .npy) stay ignored.
|
||||
!benchmarks/edge_harness/results/
|
||||
!benchmarks/edge_harness/results/**
|
||||
!baselines/
|
||||
!baselines/**
|
||||
benchmarks/edge_harness/results/**/*.npz
|
||||
benchmarks/edge_harness/results/**/*.onnx
|
||||
benchmarks/edge_harness/results/**/*.npy
|
||||
benchmarks/edge_harness/results/**/*.wav
|
||||
|
||||
# Portable wire fixtures are source inputs, not generated measurements.
|
||||
!packages/omni-stage-contracts/conformance/*.json
|
||||
@@ -0,0 +1,34 @@
|
||||
edge-infer
|
||||
Copyright 2026 tzhouam
|
||||
|
||||
This product is a derivative work of vLLM-Omni
|
||||
(https://github.com/vllm-project/vllm-omni), licensed under the Apache License,
|
||||
Version 2.0. Upstream code is Copyright the vLLM-Omni contributors, and vLLM-Omni
|
||||
is itself a derivative of vLLM (https://github.com/vllm-project/vllm).
|
||||
|
||||
Modifications in this fork are confined to edge/CPU inference and are listed in
|
||||
README.md; the substantive ones are:
|
||||
|
||||
vllm_omni/model_executor/layers/quantization/cpu_int4.py
|
||||
4-bit weight-only quantization for the CPU backend
|
||||
vllm_omni/model_executor/models/spark2_5/spark2_5.py
|
||||
RoPE table sized to max_model_len rather than the advertised context
|
||||
vllm_omni/edge/
|
||||
device-class weight-path selection, KV budget sizing, memory release
|
||||
vllm_omni/platforms/cpu/, vllm_omni/patch.py
|
||||
CPU platform and CPU-backend patches
|
||||
benchmarks/edge_harness/
|
||||
measurement tooling and results (original to this fork)
|
||||
baselines/, docs/engines/, docs/analysis/
|
||||
benchmark results and written analyses (original to this fork)
|
||||
|
||||
vLLM itself is not modified and no vLLM source is redistributed here. This fork
|
||||
changes vLLM's CPU behaviour through its own extension points at runtime
|
||||
(vllm_omni/patch.py); the pinned upstream versions are recorded in
|
||||
docs/edge/environment.md.
|
||||
|
||||
Baseline measurements reference llama.cpp (https://github.com/ggml-org/llama.cpp,
|
||||
MIT). No llama.cpp source is redistributed; only benchmark output produced with
|
||||
it, under baselines/llama_cpp/.
|
||||
|
||||
Upstream's README is preserved at docs/README.vllm-omni.md.
|
||||
@@ -1,109 +1,116 @@
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vllm-project/vllm-omni/refs/heads/main/docs/source/logos/vllm-omni-logo.png">
|
||||
<img alt="vllm-omni" src="https://raw.githubusercontent.com/vllm-project/vllm-omni/refs/heads/main/docs/source/logos/vllm-omni-logo.png" width=55%>
|
||||
</picture>
|
||||
</p>
|
||||
<h3 align="center">
|
||||
Easy, fast, and cheap omni-modality model serving for everyone
|
||||
</h3>
|
||||
# edge-infer
|
||||
|
||||
<p align="center">
|
||||
| <a href="https://vllm-omni.readthedocs.io/en/latest/"><b>Documentation</b></a> | <a href="https://deepwiki.com/vllm-project/vllm-omni"><b>DeepWiki</b></a> | <a href="https://discuss.vllm.ai"><b>User Forum</b></a> | <a href="https://slack.vllm.ai"><b>Developer Slack</b></a> | <a href="docs/assets/WeChat.jpg"><b>WeChat</b></a> | <a href="https://arxiv.org/abs/2602.02204"><b>Paper</b></a> | <a href="https://docs.google.com/presentation/d/1aPj0OGl_-ZVoib-Qne5dGDAlrRFB-PdHl6E-EE99g8E/edit?usp=sharing"><b>Slides</b></a> |
|
||||
</p>
|
||||
Running multimodal models on **edge CPUs** — a mini-PC or a gateway box with
|
||||
tens of gigabytes of RAM and no GPU — instead of on servers.
|
||||
|
||||
---
|
||||
Built as a fork of [vLLM-Omni](https://github.com/vllm-project/vllm-omni),
|
||||
because it is the only engine with a multi-stage multimodal pipeline,
|
||||
continuous batching and an OpenAI-compatible server; the alternatives were
|
||||
evaluated and the reasoning is in [docs/engines/](docs/engines/).
|
||||
|
||||
*Latest News* 🔥
|
||||
The work turned out to be less about kernels than about three things nobody
|
||||
profiles: how much memory is resident while the model *loads*, how much is
|
||||
resident that nothing ever reads, and whether the number you just measured came
|
||||
from the code path you thought it did. The largest single win here — 843 MB —
|
||||
was a setting that had been marked "no effect, do not retry" because the code
|
||||
path under test discarded it.
|
||||
|
||||
- [2026/08] We released [0.28.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.28.0), featuring production-ready [MiniMax H3](recipes/MiniMaxAI/MiniMax-H3.md) serving on GPU and NPU, a unified AR/DiT paged KV cache runtime, and enhanced realtime full-duplex serving for the [MiniCPM-o series](recipes/OpenBMB/MiniCPM-o-4_5.md).
|
||||
- [2026/08] [VeRL-Omni](https://github.com/verl-project/verl-omni) `v0.2.0` is released: faster diffusion RL powered by vLLM-Omni (request-level/step-wise batching with FA3), rebuilt Qwen3-Omni multimodal training (DPO & GSPO), plus LTX-2.3, Qwen-Image-Edit support and more. See the [release notes](https://github.com/verl-project/verl-omni/releases/tag/v0.2.0).
|
||||
- [2026/08] We released [0.26.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.26.0) - aligned with the vLLM 0.26 release line, featuring [MiniMax H3](recipes/MiniMaxAI/MiniMax-H3.md) joint video/audio generation, an experimental full-duplex realtime runtime for [MiniCPM-o 4.5](recipes/OpenBMB/MiniCPM-o-4_5.md), distributed layerwise diffusion offload, and broader model, hardware, streaming, TTS, and quantization support.
|
||||
- [2026/07] We released [0.24.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.24.0) - aligned with the vLLM 0.24 release line, expanding production-ready coverage across TTS, speech, diffusion, image/video generation, and robot-policy serving, with major Omni stage runtime refactoring, diffusion request-level batching, async output materialization, quantization/cache/memory improvements, and broad CUDA/ROCm/XPU/NPU support.
|
||||
- [2026/06] Starting with [0.14.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.14.0), vLLM-Omni publishes a stable release aligned with every even-numbered upstream vLLM minor version. [0.16.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.16.0), [0.18.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.18.0), [0.20.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.20.0), and [0.22.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.22.0) continued this cadence, expanding omni and world-model support with [NVIDIA Cosmos3](recipes/cosmos3/Cosmos3-Nano.md) and DreamZero, adding models such as MiniCPM-o 4.5, MOSS-TTS, and Lance, and advancing TTS, diffusion, distributed execution, quantization, RL integration through [VeRL-Omni](https://github.com/verl-project/verl-omni), and CUDA/ROCm/MUSA/NPU/XPU coverage.
|
||||
- [2026/03] Check out our first public [project deepdive](https://youtu.be/sgwNfsNnR9I) at the vLLM Hong Kong Meetup!
|
||||
- [2025/11] vLLM community officially released [vllm-project/vllm-omni](https://github.com/vllm-project/vllm-omni) in order to support omni-modality models serving.
|
||||
This repository holds the engine changes, the measurement harness, the raw
|
||||
results, the baselines they are compared against, and the written analyses.
|
||||
Upstream's own README is preserved at [docs/README.vllm-omni.md](docs/README.vllm-omni.md).
|
||||
|
||||
---
|
||||
## What's here
|
||||
|
||||
## About
|
||||
| area | where |
|
||||
|---|---|
|
||||
| 4-bit CPU quantization | `vllm_omni/model_executor/layers/quantization/cpu_int4.py` — W4A16 on PyTorch's tinygemm kernel, prefill reading the kernel's own weight layout instead of a duplicate |
|
||||
| Memory | RoPE tables sized to the servable context; weights repacked in blocks; a KV budget that is actually honoured on CPU |
|
||||
| CPU platform + vLLM patches | `vllm_omni/platforms/cpu/`, `vllm_omni/patch.py` — vLLM is monkey-patched at import; its *source* is unmodified and no vLLM is redistributed. See [docs/edge/environment.md](docs/edge/environment.md) |
|
||||
| Device routing | `vllm_omni/edge/weight_path.py` picks the weight format per device class, from measurements rather than assumption |
|
||||
| Device placement | `vllm_omni/edge/placement.py` decides which parameters leave the GPU when the checkpoint is bigger than the VRAM — cold ones first, because `embed_tokens` and `lm_head` are the same size and the opposite decision |
|
||||
| Measurement harness | `benchmarks/edge_harness/` — the grid runner, benchmarks, memory ledger, fidelity metric and agent suite every number here came from |
|
||||
| Raw results | `benchmarks/edge_harness/results/` — 100+ artifacts backing the published figures, each with provenance |
|
||||
| Baselines | `baselines/` — llama.cpp runs and the comparison scripts |
|
||||
| Engine analyses | `docs/engines/` — llama.cpp, ExecuTorch, MNN, ncnn, vLLM, vLLM-Omni |
|
||||
| Study documents | `docs/analysis/` — the full reports these summaries distil |
|
||||
|
||||
[vLLM](https://github.com/vllm-project/vllm) was originally designed to support large language models for text-based autoregressive generation tasks. vLLM-Omni is a framework that extends its support for omni-modality model inference and serving:
|
||||
## Headline results
|
||||
|
||||
- **Omni-modality**: Text, image, audio, video, and action data processing
|
||||
- **Non-autoregressive Architectures**: extend the AR support of vLLM to Diffusion Transformers (DiT) and other parallel generation models
|
||||
- **Heterogeneous outputs**: from traditional text generation to multimodal and action outputs
|
||||
Spark-X2.5-1.7B, Xeon Platinum 8480C, 24 pinned node-local cores, W4A16 g128.
|
||||
Every figure is a median of at least three interleaved passes against a control
|
||||
arm, on a shared host where end-to-end throughput swings ~30% run to run.
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
<img alt="vllm-omni" src="https://raw.githubusercontent.com/vllm-project/vllm-omni/refs/heads/main/docs/source/architecture/omni-modality-model-architecture.png" width=55%>
|
||||
</picture>
|
||||
</p>
|
||||
**Memory** — each measured as its own A/B with the alternative reachable by a flag:
|
||||
|
||||
vLLM-Omni is fast with:
|
||||
| lever | saving | cost |
|
||||
|---|---|---|
|
||||
| KV budget 1 GiB → 192 MiB | **843 MB** | fewer cached tokens |
|
||||
| RoPE table capped to `max_model_len` | **618 MB** | none |
|
||||
| One packed weight layout instead of two | **615 MB** | ~1.6× prefill |
|
||||
| Blocked weight repack | **489 MB** of load-time peak | none |
|
||||
|
||||
- State-of-the-art AR support by leveraging efficient KV cache management from vLLM
|
||||
- Pipelined stage execution overlapping for high throughput performance
|
||||
- Fully disaggregation based on OmniConnector and dynamic resource allocation across stages
|
||||
These overlap and **must not be added** — see [docs/edge/results.md](docs/edge/results.md).
|
||||
|
||||
vLLM-Omni is flexible and easy to use with:
|
||||
**Speed**, same machine:
|
||||
|
||||
- Heterogeneous pipeline abstraction to manage complex model workflows
|
||||
- Seamless integration with popular Hugging Face models
|
||||
- Tensor, pipeline, data and expert parallelism support for distributed inference
|
||||
- Streaming outputs
|
||||
- OpenAI-compatible API server
|
||||
- [Full-duplex realtime serving](docs/serving/realtime_duplex_api.md) with streaming audio input and output
|
||||
| path | decode | prefill (pp512) |
|
||||
|---|---|---|
|
||||
| W4A8 (AMX `int4_scaled_mm_cpu`) | 74.4 tok/s | — |
|
||||
| W4A16 (tinygemm) | 71.6 tok/s | 2190 tok/s |
|
||||
| `cpu_gemm_wna16` fallback | 32.3 tok/s | — |
|
||||
| llama.cpp Q4_K_M (reference) | 90.0 tok/s | 1121 tok/s |
|
||||
|
||||
vLLM-Omni seamlessly supports most popular open-source models on HuggingFace, including:
|
||||
Decode is llama.cpp's; prefill is ours by ~2×. Neither engine is
|
||||
bandwidth-bound — both sit at 33–39% of the measured 222 GB/s ceiling — so the
|
||||
decode gap is the execution model, not the kernels. See
|
||||
[docs/edge/comparisons.md](docs/edge/comparisons.md).
|
||||
|
||||
- **Omni-modality models** (e.g. Qwen3-Omni, MiniCPM-o 4.5, Cosmos3, HunyuanImage, BAGEL)
|
||||
- **TTS models** (e.g. Qwen3-TTS, IndexTTS 2.5, CosyVoice3)
|
||||
- **Diffusion models** — image, video, and audio generation (e.g. MiniMax H3, LTX-2.5, SANA-Video, Wan2.2)
|
||||
- **Robot-policy and action models** (e.g. π0, GR00T-N1.7, DreamZero-DROID, InternVLA-A1)
|
||||
## Why the numbers here are worth reading
|
||||
|
||||
## Getting Started
|
||||
This project has retracted five conclusions, every one of them a measurement
|
||||
error rather than a coding error. The harness exists because of them:
|
||||
|
||||
Visit our [documentation](https://vllm-omni.readthedocs.io/en/latest/) to learn more.
|
||||
- a "3.1 GB saving" that was `VmRSS` counting the mmap'd checkpoint;
|
||||
- W4A8 timings taken on a checkpoint whose output head was silently left in bf16;
|
||||
- a memory benchmark reading `/proc/self/status` while the model ran in a *worker process*;
|
||||
- "KV sizing saves only 188 MB" — measured through a code path that discarded the setting, so both arms ran the same cache;
|
||||
- a 1.9× prefill cost quoted from the one pass of a grid whose other passes had crashed.
|
||||
|
||||
- [Installation](https://vllm-omni.readthedocs.io/en/latest/getting_started/installation/)
|
||||
- [Quickstart](https://vllm-omni.readthedocs.io/en/latest/getting_started/quickstart/)
|
||||
- [Nightly CUDA Docker images](https://hub.docker.com/r/vllm/vllm-omni/tags?name=nightly) built from the latest `main`
|
||||
- [List of Supported Models](https://vllm-omni.readthedocs.io/en/latest/models/supported_models/)
|
||||
- [Deployment Recipes](https://recipes.vllm.ai) for vLLM-Omni model serving
|
||||
[docs/edge/methodology.md](docs/edge/methodology.md) is the resulting discipline,
|
||||
and it is the most transferable thing in this repository.
|
||||
|
||||
## Contributing
|
||||
## Quick start
|
||||
|
||||
We welcome and value any contributions and collaborations.
|
||||
Please check out [Contributing to vLLM-Omni](https://vllm-omni.readthedocs.io/en/latest/contributing/) for how to get involved.
|
||||
```bash
|
||||
# CPU build of vLLM, then this fork
|
||||
pip install vllm==0.28.0+cpu
|
||||
VLLM_TARGET_DEVICE=cpu pip install -e .
|
||||
|
||||
## Citation
|
||||
|
||||
If you use vLLM-Omni for your research, please cite our [paper](https://arxiv.org/abs/2602.02204):
|
||||
|
||||
```bibtex
|
||||
@article{yin2026vllmomni,
|
||||
title={vLLM-Omni: Fully Disaggregated Serving for Any-to-Any Multimodal Models},
|
||||
author={Peiqi Yin, Jiangyun Zhu, Han Gao, Chenguang Zheng, Yongxiang Huang, Taichang Zhou, Ruirui Yang, Weizhi Liu, Weiqing Chen, Canlin Guo, Didan Deng, Zifeng Mo, Cong Wang, James Cheng, Roger Wang, Hongsheng Liu},
|
||||
journal={arXiv preprint arXiv:2602.02204},
|
||||
year={2026}
|
||||
}
|
||||
# a right-sized edge deployment
|
||||
VLLM_CPU_KVCACHE_SPACE=1 python -c "
|
||||
from vllm import LLM, SamplingParams
|
||||
llm = LLM(model='<your-cpu_int4-checkpoint>', quantization='cpu_int4',
|
||||
dtype='bfloat16', max_model_len=2048, max_num_seqs=1,
|
||||
kv_cache_memory_bytes=192 << 20) # the single largest memory lever
|
||||
print(llm.generate(['Hello'], SamplingParams(max_tokens=32))[0].outputs[0].text)
|
||||
"
|
||||
```
|
||||
|
||||
## Join the Community
|
||||
## Documentation
|
||||
|
||||
Feel free to ask questions, provide feedbacks and discuss with fellow users of vLLM-Omni in `#sig-omni` slack channel at [slack.vllm.ai](https://slack.vllm.ai) or vLLM user forum at [discuss.vllm.ai](https://discuss.vllm.ai).
|
||||
| | |
|
||||
|---|---|
|
||||
| [docs/edge/results.md](docs/edge/results.md) | every measured figure, with spread and baseline |
|
||||
| [docs/edge/methodology.md](docs/edge/methodology.md) | how to measure on a shared machine without fooling yourself — the five retractions and the rules they left |
|
||||
| [docs/edge/cpu-4bit.md](docs/edge/cpu-4bit.md) | the two 4-bit paths, the packed layout as measured, building a checkpoint |
|
||||
| [docs/edge/comparisons.md](docs/edge/comparisons.md) | against llama.cpp and the other engines considered |
|
||||
| [docs/edge/environment.md](docs/edge/environment.md) | pins, machine, and why there is no vLLM patch series |
|
||||
| [docs/edge/local-text-mode.md](docs/edge/local-text-mode.md) | the single-stage local text engine: device capabilities, memory admission, explicit refusals, cancellation |
|
||||
| [docs/edge/external-stage-backends.md](docs/edge/external-stage-backends.md) | placing a stage on the Radeon 890M or the AMD NPU: out-of-process workers, proven placement, the shared-RAM ledger |
|
||||
| [docs/edge/harness.md](docs/edge/harness.md) | running a comparison |
|
||||
| [docs/edge/laptop-heterogeneous.md](docs/edge/laptop-heterogeneous.md) | Qwen3.8-27B and Spark-X2.5-4B on a Ryzen AI laptop — what the CPU, NPU and GPU are each worth when decode is bandwidth-bound |
|
||||
| [ROADMAP.md](ROADMAP.md) | what is next, with expected gains and how each would be verified — and what was rejected |
|
||||
|
||||
## Star History
|
||||
## Licence
|
||||
|
||||
<a href="https://www.star-history.com/?repos=vllm-project%2Fvllm-omni&type=date&legend=top-left">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=vllm-project/vllm-omni&type=date&theme=dark&legend=top-left&sealed_token=ExgLDZJoQEg27Zfhhut2LqN0GYO6Fw2PWLwPE6JYBUp2BgM3hmsYlwaIVopnUEfbRXidQ4nisumrTdKYydiKhy1SZXipw47qY2_tiUDhCpsPXeXtPuEVKVzBwKs3pw0tiHsJgtSfwXx5yjHXck0Y2SblzFWeJYCkTe1WLGTbUAOIETjXXQJjyCGZvKz5" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=vllm-project/vllm-omni&type=date&legend=top-left&sealed_token=ExgLDZJoQEg27Zfhhut2LqN0GYO6Fw2PWLwPE6JYBUp2BgM3hmsYlwaIVopnUEfbRXidQ4nisumrTdKYydiKhy1SZXipw47qY2_tiUDhCpsPXeXtPuEVKVzBwKs3pw0tiHsJgtSfwXx5yjHXck0Y2SblzFWeJYCkTe1WLGTbUAOIETjXXQJjyCGZvKz5" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=vllm-project/vllm-omni&type=date&legend=top-left&sealed_token=ExgLDZJoQEg27Zfhhut2LqN0GYO6Fw2PWLwPE6JYBUp2BgM3hmsYlwaIVopnUEfbRXidQ4nisumrTdKYydiKhy1SZXipw47qY2_tiUDhCpsPXeXtPuEVKVzBwKs3pw0tiHsJgtSfwXx5yjHXck0Y2SblzFWeJYCkTe1WLGTbUAOIETjXXQJjyCGZvKz5" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## License
|
||||
|
||||
Apache License 2.0, as found in the [LICENSE](./LICENSE) file.
|
||||
Apache-2.0, inherited from vLLM-Omni. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
# Roadmap
|
||||
|
||||
Ordered by whether the verification method is *correct*, not by expected size.
|
||||
That ordering is deliberate: this project retracted five conclusions, and in
|
||||
every case the fix was to the measurement rather than the code.
|
||||
|
||||
Each item states the measurement it starts from, what it should gain, and how
|
||||
that gain would be verified. An item without a verification method is not on
|
||||
this list.
|
||||
|
||||
## Done
|
||||
|
||||
| | item | result |
|
||||
|---|---|---|
|
||||
| H1 | Task oracles judged by device state, with variants | alarm oracle needed a *saved* alarm, not a typed `7`; a Wi-Fi round trip now fails the already-satisfied task |
|
||||
| H2 | Harness semantics | arm order really rotates; `best` respects metric direction; provenance stamped; failures recorded |
|
||||
| H3 | The three missing measurements | `ready_s`, peak `RssAnon`, memory at a filled context — all previously unmeasurable |
|
||||
| H4 | Contention guard | aggregate stolen capacity + straggler rule, on the target cores rather than host load average |
|
||||
| H5 | Regression gates | bands from observed spread; throughput explicitly ungateable at ~30% swing |
|
||||
| H6 | Fidelity metric that ranks | top-1 agreement and KL, replacing a saturating 12-prompt greedy check |
|
||||
| H8 | Retracted numbers purged from source | two modules were still shipping withdrawn figures as documentation |
|
||||
| I0 | Blocked weight repack | **489 MB** of load-time peak, no cost |
|
||||
| I1 | One packed weight layout | **615 MB** resident, at ~1.63× prefill |
|
||||
| I2 | Measure `cpu_gemm_wna16` | 2.2× slower than tinygemm; routing was right, now for a measured reason |
|
||||
| I7 | Memory ledger, by attribution | found a **618 MB** RoPE table and an **843 MB** KV cache, both inside an "unexplained 1.6 GB" |
|
||||
|
||||
## Next
|
||||
|
||||
**I6 — import cost.** `import vllm_omni` is ~30 s against `import vllm`'s 5.2 s,
|
||||
with transformers' auto image-processing (4.6 s) and the `openai` client (1.3 s)
|
||||
identifiable inside it, for a text model that needs neither. Every stage
|
||||
subprocess pays it again.
|
||||
*Expect:* an upper bound of ~6 s per process; deferred imports often move cost
|
||||
rather than remove it. *Verify:* `ready_s`, which now exists — the old timer
|
||||
started after imports, so the benchmark meant to prove this could not see it.
|
||||
|
||||
**Drop the row-major embedding copy.** `embed_tokens.weight_packed` is 128 MB,
|
||||
kept solely because the tinygemm layout was believed un-addressable for a
|
||||
single-row lookup. That premise is now known false. *Verify:* `RssAnon` plus an
|
||||
embedding-output SNR assertion.
|
||||
|
||||
**I10 first step — why is the GEMM at 60%?** The decode GEMM sustains 132 GB/s
|
||||
against a measured 222 GB/s ceiling. Part is arithmetic (tinygemm dequantizes
|
||||
per activation row) and part may be that each of 113 calls streams only a few MB,
|
||||
too little for the prefetcher to reach steady state. Attribute before optimising.
|
||||
*Expect:* unknown — a diagnosis, whose output is whether the 2.76 ms implied by
|
||||
the gap is reachable at all.
|
||||
|
||||
**I3 — asymmetric W4A8.** The symmetric grid is our exporter's choice, not the
|
||||
kernel's limit; `models/spark2_5-gptq-asym-g128` already exists. The cheapest
|
||||
untried fidelity experiment, and it tests the *stated* cause of W4A8's error.
|
||||
*Verify:* `fidelity_kl.py` and the scored agent suite.
|
||||
|
||||
**I5 — attention wrapper consolidation.** Four ops per layer, 1.31 ms/step, of
|
||||
which 0.83 ms is wrapper self time; at batch 1 the cache-update loop runs two
|
||||
iterations while the wrapper rebuilds context and allocates a dummy tensor for
|
||||
compile ordering. *Expect:* 0.3–0.5 ms, revised down from an earlier 0.6–0.9 ms
|
||||
that assumed a workload never profiled. *Verify:* per-op profile **and**
|
||||
unprofiled step latency — one outer call that still launches two threaded
|
||||
kernels removes neither thread launch.
|
||||
|
||||
**I4 — a better quantizer.** Ours reproduces 2/12 greedy prompts against its own
|
||||
bf16; Q4_K_M manages 4/12 — but at 4.5 bits against our 4.25, so close the
|
||||
budget gap first (g64, or fp16 scale+zero, both config changes) before
|
||||
implementing error-compensated rounding. Timebox it; a null result is worth
|
||||
recording.
|
||||
|
||||
## Considered and rejected
|
||||
|
||||
**A CPU megakernel.** On GPU this fuses a forward pass into one launch to remove
|
||||
launch overhead and the cross-kernel prefetch bubble. On CPU the analogues are
|
||||
OpenMP fork/join and ATen dispatch — and llama.cpp already is one:
|
||||
`ggml_threadpool` starts threads once and they walk the whole graph,
|
||||
synchronising at `ggml_barrier` through an atomic spin, where vLLM enters a
|
||||
separate `omp parallel` region per kernel.
|
||||
|
||||
Measured before deciding: a parallel region costs ~1.2 µs at 24 threads, and
|
||||
spin-waiting does not help (`OMP_WAIT_POLICY=ACTIVE` moved it 1.23 → 1.18 µs), so
|
||||
it is barrier cost rather than thread wake-up. At a few hundred regions per
|
||||
decode step that is 0.3–0.4 ms, 2–3% — the same money as I5, far more cheaply.
|
||||
The larger prize is the streaming bubble, but capturing it means replacing the
|
||||
execution model inside vLLM's CPU backend, which reimplements ggml. Not next.
|
||||
|
||||
**More kernel fusion.** Four attempts, four losses: vLLM's fused CPU RMSNorm is
|
||||
3.6–4.5× faster in isolation and slower in situ (inductor already fuses the
|
||||
native form with the residual add); fused `gelu_and_mul` 2.7× slower at Spark's
|
||||
shape; `cpp.min_chunk_size` −6% decode; an inline gate reduction −44%.
|
||||
|
||||
**MiniCPM-o CPU overlay.** The 8 B thinker at bf16 is ~19 GB, so it buys no edge
|
||||
deployability. The argument for it — that three-stage parallel init should beat
|
||||
the two-stage 2.1× — is also not how overlap works: the bound is ΣT/max(T).
|
||||
|
||||
**Speculative decoding for tg128.** It would inflate a fixed-prompt `ignore_eos`
|
||||
benchmark without representing anything. Measure it on the agent suite or not at
|
||||
all.
|
||||
|
||||
**Thread count and warm-up batch size as memory levers.** 64 MB and 2 MB.
|
||||
|
||||
## Harness work still open
|
||||
|
||||
- **A real device in the agent loop.** The toolkit has 38 tests and has never
|
||||
touched a phone — this host has no `adb`, no emulator, no `/dev/kvm`. The
|
||||
real-device path and per-task resets exist; what is untested is whether a real
|
||||
Settings app matches the fixtures.
|
||||
- **Success rates, not single runs.** The build comparison that produced
|
||||
"navigation survives quantization, completion does not" is one run per cell.
|
||||
Variants now exist so repeats are trials; they need running.
|
||||
@@ -13,6 +13,7 @@ It can send model inference requests to either a locally running vLLM-Omni servi
|
||||
> [!TIP]
|
||||
> If you run both ComfyUI and vLLM-Omni on the same device, you can create separate virtual environments and use different Python versions for them.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Copy this folder to the `custom_nodes` subfolder of your ComfyUI installation. Your directory should look like `ComfyUI/custom_nodes/ComfyUI-vLLM-Omni`.
|
||||
@@ -20,10 +21,9 @@ Copy this folder to the `custom_nodes` subfolder of your ComfyUI installation. Y
|
||||
If you are running ComfyUI during copying, you should restart ComfyUI to load this extension.
|
||||
|
||||
> [!TIP]
|
||||
> You can use utility websites such as <https://download-directory.github.io/> to download a subdirectory of a repo. Also checkout community discussions (e.g., <https://stackoverflow.com/questions/7106012/download-a-single-folder-or-directory-from-a-github-repository>) for more info.
|
||||
> You can use utility websites such as https://download-directory.github.io/ to download a subdirectory of a repo. Also checkout community discussions (e.g., https://stackoverflow.com/questions/7106012/download-a-single-folder-or-directory-from-a-github-repository) for more info.
|
||||
|
||||
On the device and virtual environment you run ComfyUI, launch ComfyUI with
|
||||
|
||||
```bash
|
||||
cd ComfyUI
|
||||
|
||||
@@ -35,7 +35,6 @@ python main.py --cpu
|
||||
```
|
||||
|
||||
On the device and virtual environment you run vLLM-Omni, start a model service with
|
||||
|
||||
```bash
|
||||
vllm serve The_Model_ID_to_Serve --omni --port 8000
|
||||
```
|
||||
@@ -49,31 +48,14 @@ This extension offers the following nodes based on the output modalities (at **C
|
||||
|
||||
- **Generate Image** for text-to-image and image-to-image tasks
|
||||
- **Generate Video** for text-to-video, first-frame/image-to-video, and reference-conditioned video
|
||||
- **Latent Mask Editing** for MiniMax-H3 latent-mask editing (source media plus video/audio noise masks)
|
||||
- **FastH3 Deployment** for routing text-to-video requests to a MiniMax-H3 server with FastH3 fused at startup
|
||||
- **Multimodality Understanding** for multimodality-to-text and multimodality-to-audio tasks
|
||||
- **TTS** and **TTS Voice Clone** for TTS tasks
|
||||
- **Generate Music** for lyrics-and-description-to-music generation
|
||||
|
||||
This extension also offers example workflows (at **ComfyUI sidebar -> Templates -> vLLM-Omni**)
|
||||
|
||||
> [!NOTE]
|
||||
> The node UI and feature designs are intended to match vLLM-Omni online serving interfaces. It cannot offer more than what the interfaces support.
|
||||
|
||||
Every node carries the vLLM-Omni mark in its title bar and is tinted by what it outputs, so a graph is readable at a glance:
|
||||
|
||||
| Colour | Nodes | What they produce |
|
||||
| --- | --- | --- |
|
||||
| Blue | Generate Image, Generate Video, Multimodality Understanding, TTS, TTS Voice Clone | A generated image, video, audio, or text. These are the only nodes that reach a server. |
|
||||
| Amber | AR / Diffusion / Multi-Stage Sampling Params | Sampling parameters that apply to any model |
|
||||
| Purple | Qwen TTS Params, Wan Video Params, MiniMax-H3 Video Params | Parameters that only one model family accepts |
|
||||
| Red | LoRA, FastH3 Deployment | Which weights the server is expected to have loaded |
|
||||
| Teal | Video References, Latent Mask Editing | Reference media |
|
||||
|
||||
Recolouring a node by hand (right click -> Colors) overrides its tint, and the choice is kept.
|
||||
|
||||
**Generate Video** takes a clip length in seconds (`duration`), not a frame count. Frames stay the wire unit and are derived with the node's `fps`, so the length is always measured against the rate that is actually served; models that accept only certain frame counts still round to their own lattice server-side. Graphs saved before this widget existed stored `num_frames` in its place and are converted on load, using the fps recorded alongside it -- the browser console names every node it rewrites.
|
||||
|
||||
To build a simple workflow yourself,
|
||||
|
||||
- Drag a generation node onto the canvas.
|
||||
@@ -135,146 +117,11 @@ You can configure per-stage sampling parameters for multi-stage models.
|
||||
</p>
|
||||
|
||||
> [!TIP]
|
||||
> Connect **frame** for backward-compatible first-frame / image-to-video behavior. For MiniMax-H3 FL2VA,
|
||||
> connect **first_frame**, **last_frame**, or both to condition the start frame, end frame, or both.
|
||||
> Connect a **frame** image for first-frame / image-to-video (e.g., Wan I2V, MiniMax-H3 FL2VA).
|
||||
>
|
||||
> For reference-conditioned generation (MiniMax-H3 Ref2VA), connect a **Video References** node instead.
|
||||
>
|
||||
> Do not combine `frame` with `first_frame` or `last_frame`, and do not combine any frame input with
|
||||
> `references`. Task routing is automatic from which inputs you connect.
|
||||
|
||||
For MiniMax-H3 Ref2VA, **Video References** accepts up to 9 images (`image_1`–`image_9`),
|
||||
3 videos (`video_1`–`video_3`), and 3 audio clips (`audio_1`–`audio_3`), with at most
|
||||
12 connected inputs in total. Any mixture containing at least one image or video
|
||||
is supported; empty and audio-only references are rejected. For example, you can
|
||||
combine 6 images, 3 videos, and 3 audio clips in one request.
|
||||
|
||||
Within each media type, references follow slot-number order, skipping unconnected
|
||||
slots. For example, connecting `image_2` and `image_9` sends `image_2` as the first
|
||||
image and `image_9` as the second. Each image slot uses the first image in its batch.
|
||||
Existing connections to `image_1`, `image_2`, `audio_1`, `audio_2`, `video_1`, and
|
||||
`video_2` remain valid in saved workflows.
|
||||
|
||||
#### MiniMax-H3 Reference to Video
|
||||
|
||||
Load [MiniMax-H3 Reference to Video](example_workflows/vLLM-Omni%20MiniMax-H3%20Reference%20to%20Video.json)
|
||||
from **Templates → ComfyUI-vLLM-Omni**, or drag the JSON onto the canvas.
|
||||
It adapts the [official ComfyUI R2V workflow](https://github.com/Comfy-Org/workflow_templates/blob/main/templates/video_minimax_h3_r2v.json)
|
||||
to remote vLLM-Omni execution. Model loading, sampling, and VAE decoding run on
|
||||
the server; ComfyUI loads references and saves the returned video.
|
||||
|
||||
Use an extension version containing the audio-preserving output fix from
|
||||
[#7456](https://github.com/vllm-project/vllm-omni/pull/7456). Older versions can
|
||||
drop the server's audio while decoding the response.
|
||||
|
||||
1. Start a Ref2VA-capable service using the [MiniMax-H3 recipe](../../recipes/MiniMaxAI/MiniMax-H3.md).
|
||||
Set **Generate Video** to its `/v1` URL and served model name.
|
||||
2. Select your own image in **Load Image**. The template's filenames are placeholders
|
||||
relative to ComfyUI's input directory; no sample assets or model weights are bundled.
|
||||
3. Connect **Load Video** and **Load Audio** when needed. Duplicate the loaders to
|
||||
fill more reference slots, or disconnect the image when using video-only input.
|
||||
Keep the references connected to **Generate Video** and leave `frame` disconnected.
|
||||
4. Match prompt tags such as `<Picture 1>`, `<Video 1>`, and `<Audio 1>` to the
|
||||
connected references, counting each media type separately and skipping empty slots.
|
||||
5. Run the workflow. **Save Video** writes an MP4 under `output/video/` and preserves
|
||||
the generated audio when the audio-output prerequisite is installed.
|
||||
|
||||
The default is **1344×768, 24 FPS, 124 frames** (about 5.17 seconds), 50 sampling
|
||||
points, video flow shift 12, audio flow shift 3, and seed 42. The duration widget
|
||||
is set to 5.167 seconds, which converts to 124 frames at 24 FPS. Other H3 canvas presets
|
||||
are 1024×768, 768×768, 768×1024, and 768×1344. Keep frame counts at `17k+5` within
|
||||
the 4–15 second output range; examples are 107, 124, 209, and 345 frames.
|
||||
Reference video/audio clips must each be 2–15 seconds, with at most 15 seconds of
|
||||
reference video and at most 15 seconds of standalone reference audio per request.
|
||||
|
||||
For **Ref2VA Turbo**, use the same template. Configure a Ref2VA-only server with
|
||||
`--lora-backend peft --lora-path "$TURBO_LORA" --task-type ref2va`, following the
|
||||
recipe's hardware setup. For `minimax_h3_ref2v_turbo_4step_v0.1_bf16.safetensors`,
|
||||
set **LoRA** `local_path` to that file's path on the server and connect it to
|
||||
**Generate Video**. Use `num_inference_steps=5`, `flow_shift=12`,
|
||||
`audio_flow_shift=3`, and LoRA `scale=1`. The API counts sigma points, so five
|
||||
points produce four denoiser evaluations. Use the Diffusers artifact, not its
|
||||
`_comfyui_` export. To return to base mode, disconnect LoRA and restore 50 steps.
|
||||
The 8-step v1.0 Ref2VA adapter instead requires nine sampling points and video
|
||||
flow shift 6. FastH3 is a separate startup-fused T2VA deployment.
|
||||
|
||||
Validate the template's wiring and defaults locally with:
|
||||
|
||||
```bash
|
||||
python -m pytest tests/e2e/features/comfyui/test_h3_reference_workflow.py -q
|
||||
```
|
||||
|
||||
For a real-model check, run the workflow against H3 and inspect the saved file:
|
||||
|
||||
```bash
|
||||
ffprobe -v error -show_entries stream=codec_type,width,height,r_frame_rate,sample_rate,channels \
|
||||
-show_entries format=duration -of json "$OUTPUT_MP4"
|
||||
```
|
||||
|
||||
Check for 24 FPS video, stereo audio, the requested canvas, and aligned duration;
|
||||
also play the result to assess reference conditioning and audio/video synchronization.
|
||||
Record the server commit, model/adapter, input assets, prompt, settings, and output
|
||||
alongside the result. Local schema or mocked-server checks do not establish H3
|
||||
generation quality or replace this real-model validation.
|
||||
|
||||
### MiniMax H3 Text to Video
|
||||
|
||||
Import [the H3 text-to-video template](example_workflows/MiniMax_H3_Text_to_Video.json)
|
||||
for remote video generation with audio. It includes connected base presets and
|
||||
optional Turbo sampling, H3 parameters, and Remote LoRA nodes. See the
|
||||
[workflow guide](docs/minimax-h3-t2v.md) for server setup, artifact-specific Turbo
|
||||
settings, and saved-video/audio validation. Set Remote LoRA’s `local_path` to
|
||||
the downloaded Turbo artifact on your server before enabling Turbo.
|
||||
|
||||
#### H3 video upscale (WF-07)
|
||||
|
||||
The **vLLM-Omni MiniMax H3 Video Upscale** template generates video remotely, upscales it with SeedVR2, and saves the original and upscaled videos with the generated audio and FPS. See [workflow setup](docs/wf07-h3-upscale.md).
|
||||
|
||||
#### FastH3 text-to-video
|
||||
|
||||
FastH3 is fused into MiniMax-H3 when the vLLM-Omni server starts; it is not a request-switchable LoRA. Download one adapter variant and start a non-offloaded FL2VA server. For the Dense / Data-Free profile:
|
||||
|
||||
```bash
|
||||
export FASTH3_DIR=/path/to/fasth3
|
||||
hf download FastVideo/FastVideo-FastH3-4-step-Preview-v1-LoRA \
|
||||
dense-datafree/adapter_model.safetensors --local-dir "${FASTH3_DIR}"
|
||||
|
||||
vllm serve /path/to/MiniMax-H3 \
|
||||
--omni \
|
||||
--task-type fl2va \
|
||||
--lora-path "${FASTH3_DIR}/dense-datafree/adapter_model.safetensors" \
|
||||
--port 8000
|
||||
```
|
||||
|
||||
For the VSA / Data-Free profile, download `vsa-datafree/adapter_model.safetensors`, use that file as `--lora-path`, and add:
|
||||
|
||||
```bash
|
||||
--diffusion-attention-backend FASTVIDEO_VSA \
|
||||
--fastvideo-vsa-topk 64
|
||||
```
|
||||
|
||||
The VSA profile also requires a compatible `fastvideo-kernel` installation. See the [MiniMax-H3 FastH3 recipe](../../recipes/MiniMaxAI/MiniMax-H3.md#fasth3-adapter) for the full serving contract, supported parallel layouts, and kernel requirements.
|
||||
|
||||
Open the **vLLM-Omni FastH3 Text to Video** template, then:
|
||||
|
||||
- Set the server URL and served model name on **FastH3 Deployment**.
|
||||
- Connect its output to **Generate Video → fast_h3**. When connected, the deployment node's URL and model take precedence over the corresponding Generate Video widgets.
|
||||
- Keep `frame`, `references`, **LoRA**, and **MiniMax-H3 Video Params** disconnected. FastH3 Preview v1 supports T2VA only, is already fused, and owns both flow shifts.
|
||||
- A connected **Diffusion Sampling Params** node may set seed and other ordinary sampling options. The integration always enforces four denoising steps and 24 FPS for FastH3.
|
||||
|
||||
The node records which server the workflow targets; it does not start one, nor switch adapters or attention backends on a running server.
|
||||
|
||||
#### Latent-mask editing (MiniMax-H3)
|
||||
|
||||
The [WF-05 template](example_workflows/vLLM-Omni%20MiniMax-H3%20Latent%20Mask%20Editing.json) contains inpainting, object removal, continuation, and extension examples in one graph. See the [workflow guide](docs/wf05-h3-latent-editing.md) for inputs, mask settings, dependencies, and preview limitations.
|
||||
|
||||
Connect a **Latent Mask Editing** node to **Generate Video → latent_edit** to edit a source clip instead of generating from scratch. It uploads the source media and serializes the video/audio noise masks the MiniMax H3 API accepts:
|
||||
|
||||
- `source_video` / `source_audio` — the media to edit.
|
||||
- `video_mask` — a ComfyUI mask image; `0` preserves a region, `1` regenerates it, fractional values blend. A 2D mask `[H, W]` is applied to every frame; a 3D mask `[T, H, W]` is treated as a temporal mask (one slice per frame) for continuation or extension. It is resized to the video latent grid.
|
||||
- `audio_mask` — a scalar in `[0, 1]`; `0` keeps the source audio, `1` regenerates it, fractional values blend.
|
||||
|
||||
A non-trivial mask requires its matching source, and a source without a mask is rejected. This node only forwards inputs to the server; the served model must declare latent-mask editing support (MiniMax-H3).
|
||||
> Do not use `frame` and `references` together. Task routing is automatic from which inputs you connect.
|
||||
|
||||
### TTS (e.g., Qwen TTS series)
|
||||
|
||||
@@ -290,17 +137,6 @@ A non-trivial mask requires its matching source, and a source without a mask is
|
||||
> [!TIP]
|
||||
> There is a dedicated node for VoiceClone tasks with reference audio input. Other simple text-to-speech tasks should use the regular TTS node.
|
||||
|
||||
### Music generation (e.g., MiniMax Music 3)
|
||||
|
||||
(Also available at **ComfyUI sidebar->Template->vLLM-Omni->vLLM-Omni Music Generation**)
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" src="https://raw.githubusercontent.com/vllm-project/vllm-omni/refs/heads/main/apps/ComfyUI-vLLM-Omni/docs/images/comfyui-music-generation.jpg">
|
||||
<img alt="vLLM-Omni Music Generation" src="https://raw.githubusercontent.com/vllm-project/vllm-omni/refs/heads/main/apps/ComfyUI-vLLM-Omni/docs/images/comfyui-music-generation.jpg" width=55%>
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
### Chaining multiple model services
|
||||
|
||||
(Also available at **ComfyUI sidebar->Template->vLLM-Omni->vLLM-Omni Chaining Services**)
|
||||
@@ -316,8 +152,6 @@ A non-trivial mask requires its matching source, and a source without a mask is
|
||||
|
||||
Follow the [development convention and rules of vLLM-Omni](https://docs.vllm.ai/projects/vllm-omni/en/latest/contributing/).
|
||||
|
||||
Node tints and the title-bar mark are applied in `web/main.js`, keyed off each node's declared output types rather than a list of node names. A new node that returns an existing type is themed with no front-end change; a new output type needs one entry in `FAMILY_BY_OUTPUT` there.
|
||||
|
||||
## Limitation and Non-Goals
|
||||
|
||||
- Single server mode only. No automatic load balancing or failover.
|
||||
@@ -344,11 +178,11 @@ Whenever you find an issue or problem, please
|
||||
|
||||
Features
|
||||
|
||||
- <https://github.com/dougbtv/comfyui-vllm-omni/> The official reference implementation for ComfyUI integration with vLLM-Omni's DALL-E compatible image generation API.
|
||||
- <https://github.com/Comfy-Org/ComfyUI/tree/master/comfy_extras> ComfyUI's built-in node implementations.
|
||||
- https://github.com/dougbtv/comfyui-vllm-omni/ The official reference implementation for ComfyUI integration with vLLM-Omni's DALL-E compatible image generation API.
|
||||
- https://github.com/Comfy-Org/ComfyUI/tree/master/comfy_extras ComfyUI's built-in node implementations.
|
||||
|
||||
UI/UX design references
|
||||
|
||||
- <https://github.com/sgl-project/sglang/pull/15271> SGLang Diffusion's official ComfyUI integration for image and video generation.
|
||||
- <https://github.com/SXQBW/ComfyUI-Qwen-Omni> A third party ComfyUI integration for Qwen Omni series.
|
||||
- <https://github.com/flybirdxx/ComfyUI-Qwen-TTS> <https://github.com/DarioFT/ComfyUI-Qwen3-TTS> Third party ComfyUI integrations for Qwen TTS series.
|
||||
- https://github.com/sgl-project/sglang/pull/15271 SGLang Diffusion's official ComfyUI integration for image and video generation.
|
||||
- https://github.com/SXQBW/ComfyUI-Qwen-Omni A third party ComfyUI integration for Qwen Omni series.
|
||||
- https://github.com/flybirdxx/ComfyUI-Qwen-TTS https://github.com/DarioFT/ComfyUI-Qwen3-TTS Third party ComfyUI integrations for Qwen TTS series.
|
||||
@@ -1,8 +1,4 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
# ruff: noqa: N999
|
||||
|
||||
"""Top-level package for comfyui_vllm_omni.""" # This is not a Python library intended to be imported.
|
||||
"""Top-level package for comfyui_vllm_omni.""" # noqa: N999 # This is not a python library intended to be imported
|
||||
|
||||
__all__ = [
|
||||
"NODE_CLASS_MAPPINGS",
|
||||
@@ -17,13 +13,9 @@ __version__ = "0.0.1"
|
||||
from .comfyui_vllm_omni.nodes import (
|
||||
VLLMOmniARSampling,
|
||||
VLLMOmniDiffusionSampling,
|
||||
VLLMOmniFastH3Deployment,
|
||||
VLLMOmniGenerateImage,
|
||||
VLLMOmniGenerateMusic,
|
||||
VLLMOmniGenerateVideo,
|
||||
VLLMOmniLatentMaskEditing,
|
||||
VLLMOmniMiniMaxH3Params,
|
||||
VLLMOmniMiniMaxH3TemporalMask,
|
||||
VLLMOmniQwenTTSParams,
|
||||
VLLMOmniRemoteLoRA,
|
||||
VLLMOmniSamplingParamsList,
|
||||
@@ -36,22 +28,18 @@ from .comfyui_vllm_omni.nodes import (
|
||||
|
||||
# A dictionary that contains all nodes you want to export with their names
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"VLLMOmniMiniMaxH3TemporalMask": VLLMOmniMiniMaxH3TemporalMask,
|
||||
# === Generation ===
|
||||
"VLLMOmniGenerateImage": VLLMOmniGenerateImage,
|
||||
"VLLMOmniGenerateVideo": VLLMOmniGenerateVideo,
|
||||
"VLLMOmniUnderstanding": VLLMOmniUnderstanding,
|
||||
"VLLMOmniTTS": VLLMOmniTTS,
|
||||
"VLLMOmniGenerateMusic": VLLMOmniGenerateMusic,
|
||||
"VLLMOmniVoiceClone": VLLMOmniVoiceClone,
|
||||
"VLLMOmniVideoReferences": VLLMOmniVideoReferences,
|
||||
"VLLMOmniLatentMaskEditing": VLLMOmniLatentMaskEditing,
|
||||
# === Params ===
|
||||
"VLLMOmniARSampling": VLLMOmniARSampling,
|
||||
"VLLMOmniDiffusionSampling": VLLMOmniDiffusionSampling,
|
||||
"VLLMOmniSamplingParamsList": VLLMOmniSamplingParamsList,
|
||||
"VLLMOmniRemoteLoRA": VLLMOmniRemoteLoRA,
|
||||
"VLLMOmniFastH3Deployment": VLLMOmniFastH3Deployment,
|
||||
"VLLMOmniQwenTTSParams": VLLMOmniQwenTTSParams,
|
||||
"VLLMOmniWanParams": VLLMOmniWanParams,
|
||||
"VLLMOmniMiniMaxH3Params": VLLMOmniMiniMaxH3Params,
|
||||
@@ -59,22 +47,18 @@ NODE_CLASS_MAPPINGS = {
|
||||
|
||||
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"VLLMOmniMiniMaxH3TemporalMask": "MiniMax-H3 Temporal Mask",
|
||||
# === Generation ===
|
||||
"VLLMOmniGenerateImage": "Generate Image",
|
||||
"VLLMOmniGenerateVideo": "Generate Video",
|
||||
"VLLMOmniUnderstanding": "Multimodality Understanding",
|
||||
"VLLMOmniTTS": "TTS (Text to Speech)",
|
||||
"VLLMOmniGenerateMusic": "Generate Music",
|
||||
"VLLMOmniVoiceClone": "TTS Voice Cloning",
|
||||
"VLLMOmniVideoReferences": "Video References",
|
||||
"VLLMOmniLatentMaskEditing": "Latent Mask Editing",
|
||||
# === Params ===
|
||||
"VLLMOmniARSampling": "AR Sampling Params",
|
||||
"VLLMOmniDiffusionSampling": "Diffusion Sampling Params",
|
||||
"VLLMOmniSamplingParamsList": "Multi-Stage Sampling Params List",
|
||||
"VLLMOmniRemoteLoRA": "LoRA",
|
||||
"VLLMOmniFastH3Deployment": "FastH3 Deployment",
|
||||
"VLLMOmniQwenTTSParams": "Qwen TTS Params",
|
||||
"VLLMOmniWanParams": "Wan Video Params",
|
||||
"VLLMOmniMiniMaxH3Params": "MiniMax-H3 Video Params",
|
||||
|
||||
@@ -1,25 +1,15 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import math
|
||||
from typing import Literal
|
||||
|
||||
import torch
|
||||
from comfy_api.input import AudioInput, VideoInput
|
||||
|
||||
from .utils.api_client import VLLMOmniClient
|
||||
from .utils.latent_mask import _align_frame_count, _video_latent_t
|
||||
from .utils.logger import get_logger
|
||||
from .utils.models import lookup_model_spec
|
||||
from .utils.types import (
|
||||
MAX_REFERENCE_AUDIOS,
|
||||
MAX_REFERENCE_IMAGES,
|
||||
MAX_REFERENCE_VIDEOS,
|
||||
AudioFormat,
|
||||
AutoregressionSamplingParams,
|
||||
DiffusionSamplingParams,
|
||||
FastH3Deployment,
|
||||
LatentMaskEditing,
|
||||
MiniMaxH3ModelSpecificParams,
|
||||
QwenTTSModelSpecificParams,
|
||||
VideoReferences,
|
||||
@@ -32,23 +22,6 @@ from .utils.validators import (
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
FASTH3_INFERENCE_STEPS = 4
|
||||
FASTH3_FPS = 24
|
||||
# A FastH3 deployment may expose H3 under any --served-model-name, so the payload
|
||||
# spec has to be named outright rather than recovered from that alias.
|
||||
FASTH3_SPEC_MODEL = "MiniMax-H3"
|
||||
|
||||
|
||||
def _resolve_fast_h3_deployment(deployment: dict) -> tuple[str, str]:
|
||||
if not isinstance(deployment, dict):
|
||||
raise ValueError("FastH3 deployment must be provided by a FastH3 Deployment node.")
|
||||
|
||||
url = str(deployment.get("url") or "").strip().rstrip("/")
|
||||
model = str(deployment.get("model") or "").strip()
|
||||
if not url or not model:
|
||||
raise ValueError("FastH3 deployment requires both URL and model.")
|
||||
return url, model
|
||||
|
||||
|
||||
class _VLLMOmniGenerateBase:
|
||||
"""Base class for vLLM-Omni generation nodes with shared functionality."""
|
||||
@@ -189,31 +162,14 @@ class VLLMOmniGenerateVideo(_VLLMOmniGenerateBase):
|
||||
"width": ("INT", {"default": 832, "min": 1}),
|
||||
"height": ("INT", {"default": 480, "min": 1}),
|
||||
"fps": ("INT", {"default": 16, "min": 1}),
|
||||
"duration": (
|
||||
"FLOAT",
|
||||
{
|
||||
"default": 4.0,
|
||||
"min": 0.1,
|
||||
"step": 0.1,
|
||||
"round": 0.001,
|
||||
"tooltip": (
|
||||
"Clip length in seconds, converted to frames with the fps above. "
|
||||
"Models that only accept certain frame counts (e.g. MiniMax-H3) round to "
|
||||
"their own lattice, so the served clip can be slightly longer than requested."
|
||||
),
|
||||
},
|
||||
),
|
||||
"num_frames": ("INT", {"default": 41, "min": 1}),
|
||||
},
|
||||
"optional": {
|
||||
"frame": ("IMAGE",),
|
||||
"first_frame": ("IMAGE",),
|
||||
"last_frame": ("IMAGE",),
|
||||
"references": ("VIDEO_REFERENCES",),
|
||||
"sampling_params": ("SAMPLING_PARAMS",),
|
||||
"lora": ("REMOTE_LORA",),
|
||||
"model_params": ("VIDEO_PARAMS",),
|
||||
"fast_h3": ("FASTH3_DEPLOYMENT",),
|
||||
"latent_edit": ("LATENT_MASK_EDITING",),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -222,30 +178,12 @@ class VLLMOmniGenerateVideo(_VLLMOmniGenerateBase):
|
||||
FUNCTION = "generate"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(
|
||||
cls,
|
||||
url,
|
||||
model,
|
||||
frame=None,
|
||||
first_frame=None,
|
||||
last_frame=None,
|
||||
references=None,
|
||||
fast_h3=None,
|
||||
**_kwargs,
|
||||
) -> str | Literal[True]:
|
||||
def VALIDATE_INPUTS(cls, url, model, frame=None, references=None, **_kwargs) -> str | Literal[True]:
|
||||
base = super().VALIDATE_INPUTS(url, model)
|
||||
if base is not True:
|
||||
return base
|
||||
if frame is not None and references is not None:
|
||||
return "Provide only one of frame or references, not both."
|
||||
if frame is not None and (first_frame is not None or last_frame is not None):
|
||||
return "Provide either frame or first_frame/last_frame, not both."
|
||||
if references is not None and (first_frame is not None or last_frame is not None):
|
||||
return "Provide either first_frame/last_frame or references, not both."
|
||||
if fast_h3 is not None and any(value is not None for value in (frame, first_frame, last_frame, references)):
|
||||
return (
|
||||
"FastH3 Preview supports T2VA only; disconnect frame, first_frame, last_frame, and references inputs."
|
||||
)
|
||||
return True
|
||||
|
||||
async def generate(
|
||||
@@ -256,72 +194,20 @@ class VLLMOmniGenerateVideo(_VLLMOmniGenerateBase):
|
||||
width: int,
|
||||
height: int,
|
||||
fps: int,
|
||||
duration: float,
|
||||
num_frames: int,
|
||||
negative_prompt: str | None = None,
|
||||
frame: torch.Tensor | None = None,
|
||||
first_frame: torch.Tensor | None = None,
|
||||
last_frame: torch.Tensor | None = None,
|
||||
references: dict | None = None,
|
||||
sampling_params: dict | list[dict] | None = None,
|
||||
model_params: dict | None = None,
|
||||
lora: dict | None = None,
|
||||
fast_h3: dict | None = None,
|
||||
latent_edit: dict | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
if kwargs:
|
||||
logger.info("Uncaught kwargs: %s", kwargs)
|
||||
logger.debug("Got sampling params: %s", sampling_params)
|
||||
logger.debug("Got model params: %s", model_params)
|
||||
|
||||
# Which spec builds the payload. Only a FastH3 deployment separates this
|
||||
# from the served name; every other path keeps them equal.
|
||||
spec_model = model
|
||||
|
||||
if fast_h3 is not None:
|
||||
if any(value is not None for value in (frame, first_frame, last_frame, references)):
|
||||
raise ValueError(
|
||||
"FastH3 Preview supports T2VA only; disconnect frame, first_frame, "
|
||||
"last_frame, and references inputs."
|
||||
)
|
||||
if lora is not None:
|
||||
raise ValueError(
|
||||
"FastH3 is already fused into the selected server; disconnect the request-level LoRA input."
|
||||
)
|
||||
|
||||
url, model = _resolve_fast_h3_deployment(fast_h3)
|
||||
logger.info("Using FastH3 deployment at %s", url)
|
||||
fps = FASTH3_FPS
|
||||
# The served name is whatever the operator passed to --served-model-name.
|
||||
# Left alone, lookup_model_spec would miss H3 for an alias such as
|
||||
# "fasth3", drop the params builder, and send a t2va request carrying no
|
||||
# aspect_ratio -- which the server refuses.
|
||||
spec_model = FASTH3_SPEC_MODEL
|
||||
|
||||
if sampling_params is None:
|
||||
sampling_params = DiffusionSamplingParams()
|
||||
elif isinstance(sampling_params, list):
|
||||
if len(sampling_params) != 1:
|
||||
raise ValueError("FastH3 expects a single diffusion sampling params group.")
|
||||
sampling_params = sampling_params[0].__class__(sampling_params[0])
|
||||
else:
|
||||
sampling_params = sampling_params.__class__(sampling_params)
|
||||
sampling_params["num_inference_steps"] = FASTH3_INFERENCE_STEPS
|
||||
|
||||
# FastH3 owns both modality shifts. Sending the ordinary H3 values
|
||||
# from a connected H3 Params node would turn a deployment choice
|
||||
# into a request-level override, which the server intentionally
|
||||
# rejects when it differs from the fused adapter contract.
|
||||
if model_params is not None:
|
||||
model_params = model_params.__class__(model_params)
|
||||
model_params.pop("flow_shift", None)
|
||||
model_params.pop("audio_flow_shift", None)
|
||||
|
||||
# Frames stay the wire unit. Convert after the FastH3 branch above, so the
|
||||
# duration is measured against the fps the server will actually apply.
|
||||
num_frames = max(1, round(duration * fps))
|
||||
|
||||
validate_model_and_sampling_params_types(spec_model, sampling_params)
|
||||
validate_model_and_sampling_params_types(model, sampling_params)
|
||||
|
||||
# Currently, all video generation models are single-stage diffusion models
|
||||
if isinstance(sampling_params, list):
|
||||
@@ -341,11 +227,8 @@ class VLLMOmniGenerateVideo(_VLLMOmniGenerateBase):
|
||||
client = VLLMOmniClient(url)
|
||||
output = await client.generate_video(
|
||||
model=model,
|
||||
spec_model=spec_model,
|
||||
prompt=prompt,
|
||||
frame=frame, # frame present => fl2va / Wan I2V
|
||||
first_frame=first_frame,
|
||||
last_frame=last_frame,
|
||||
references=references,
|
||||
width=width,
|
||||
height=height,
|
||||
@@ -355,7 +238,6 @@ class VLLMOmniGenerateVideo(_VLLMOmniGenerateBase):
|
||||
sampling_params=sampling_params,
|
||||
lora=lora,
|
||||
model_params=model_params,
|
||||
latent_edit=latent_edit,
|
||||
)
|
||||
return (output,)
|
||||
|
||||
@@ -536,66 +418,6 @@ class VLLMOmniTTS(_VLLMOmniGenerateBase):
|
||||
return (audio,)
|
||||
|
||||
|
||||
class VLLMOmniGenerateMusic(_VLLMOmniGenerateBase):
|
||||
"""Generate a song from lyrics and a musical description with MiniMax Music 3."""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"url": ("STRING", {"default": "http://localhost:8000/v1"}),
|
||||
"model": ("STRING", {"default": "MiniMaxAI/MiniMax-Music3"}),
|
||||
"instructions": (
|
||||
"STRING",
|
||||
{
|
||||
"multiline": True,
|
||||
"display_name": "caption",
|
||||
"tooltip": "Music caption: describe genre, instruments, tempo and mood.",
|
||||
},
|
||||
),
|
||||
"lyrics": ("STRING", {"multiline": True}),
|
||||
"max_duration_seconds": (
|
||||
"FLOAT",
|
||||
{
|
||||
"default": 300.0,
|
||||
"min": 1,
|
||||
"max": 360,
|
||||
"step": 0.01,
|
||||
"tooltip": "Upper limit; rounded down to whole 25 Hz audio frames. May end earlier.",
|
||||
},
|
||||
),
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 2**53 - 1, "control_after_generate": True}),
|
||||
"response_format": (["wav", "mp3", "flac", "opus"],),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("AUDIO",)
|
||||
RETURN_NAMES = ("audio",)
|
||||
FUNCTION = "generate"
|
||||
|
||||
async def generate(
|
||||
self,
|
||||
url: str,
|
||||
model: str,
|
||||
lyrics: str,
|
||||
instructions: str,
|
||||
response_format: AudioFormat,
|
||||
max_duration_seconds: float,
|
||||
seed: int = 0,
|
||||
) -> tuple[AudioInput]:
|
||||
audio = await VLLMOmniClient(url.rstrip("/")).generate_speech(
|
||||
model=model,
|
||||
input=lyrics,
|
||||
instructions=instructions,
|
||||
voice="default",
|
||||
speed=1.0,
|
||||
response_format=response_format,
|
||||
max_new_tokens=int(max_duration_seconds * 25),
|
||||
seed=seed,
|
||||
)
|
||||
return (audio,)
|
||||
|
||||
|
||||
class VLLMOmniVoiceClone(_VLLMOmniGenerateBase):
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
@@ -873,52 +695,6 @@ class VLLMOmniRemoteLoRA:
|
||||
return (lora,)
|
||||
|
||||
|
||||
class VLLMOmniFastH3Deployment:
|
||||
"""Select a vLLM-Omni service that fused FastH3 at startup."""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"url": (
|
||||
"STRING",
|
||||
{
|
||||
"default": "http://localhost:8000/v1",
|
||||
"tooltip": "URL of a vLLM-Omni server started with a FastH3 --lora-path.",
|
||||
},
|
||||
),
|
||||
"model": (
|
||||
"STRING",
|
||||
{
|
||||
"default": "MiniMaxAI/MiniMax-H3",
|
||||
"tooltip": "Model name exposed by the FastH3 deployment.",
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FASTH3_DEPLOYMENT",)
|
||||
RETURN_NAMES = ("deployment",)
|
||||
FUNCTION = "get_deployment"
|
||||
CATEGORY = "vLLM-Omni"
|
||||
DESCRIPTION = (
|
||||
"Selects a server with FastH3 fused at startup. The connected Generate Video node uses T2VA, "
|
||||
"four inference steps, and 24 FPS without sending a request-level LoRA."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, url, model) -> str | Literal[True]:
|
||||
try:
|
||||
_resolve_fast_h3_deployment({"url": url, "model": model})
|
||||
except ValueError as exc:
|
||||
return str(exc)
|
||||
return True
|
||||
|
||||
def get_deployment(self, url: str, model: str):
|
||||
url, model = _resolve_fast_h3_deployment({"url": url, "model": model})
|
||||
return (FastH3Deployment({"url": url, "model": model}),)
|
||||
|
||||
|
||||
class VLLMOmniQwenTTSParams:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
@@ -1014,10 +790,6 @@ class VLLMOmniVideoReferences:
|
||||
"audio_2": ("AUDIO",),
|
||||
"video_1": ("VIDEO",),
|
||||
"video_2": ("VIDEO",),
|
||||
# Append ports to preserve connections in saved workflows.
|
||||
**{f"image_{i}": ("IMAGE",) for i in range(3, MAX_REFERENCE_IMAGES + 1)},
|
||||
**{f"audio_{i}": ("AUDIO",) for i in range(3, MAX_REFERENCE_AUDIOS + 1)},
|
||||
**{f"video_{i}": ("VIDEO",) for i in range(3, MAX_REFERENCE_VIDEOS + 1)},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1034,112 +806,21 @@ class VLLMOmniVideoReferences:
|
||||
audio_2: AudioInput | None = None,
|
||||
video_1: VideoInput | None = None,
|
||||
video_2: VideoInput | None = None,
|
||||
image_3: torch.Tensor | None = None,
|
||||
image_4: torch.Tensor | None = None,
|
||||
image_5: torch.Tensor | None = None,
|
||||
image_6: torch.Tensor | None = None,
|
||||
image_7: torch.Tensor | None = None,
|
||||
image_8: torch.Tensor | None = None,
|
||||
image_9: torch.Tensor | None = None,
|
||||
audio_3: AudioInput | None = None,
|
||||
video_3: VideoInput | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
if kwargs:
|
||||
logger.info("Uncaught kwargs: %s", kwargs)
|
||||
refs = VideoReferences()
|
||||
for kind, values in (
|
||||
("image", (image_1, image_2, image_3, image_4, image_5, image_6, image_7, image_8, image_9)),
|
||||
("video", (video_1, video_2, video_3)),
|
||||
("audio", (audio_1, audio_2, audio_3)),
|
||||
):
|
||||
for index, value in enumerate(values, start=1):
|
||||
if value is not None:
|
||||
refs[f"{kind}_{index}"] = value
|
||||
if image_1 is not None:
|
||||
refs["image_1"] = image_1
|
||||
if image_2 is not None:
|
||||
refs["image_2"] = image_2
|
||||
if audio_1 is not None:
|
||||
refs["audio_1"] = audio_1
|
||||
if audio_2 is not None:
|
||||
refs["audio_2"] = audio_2
|
||||
if video_1 is not None:
|
||||
refs["video_1"] = video_1
|
||||
if video_2 is not None:
|
||||
refs["video_2"] = video_2
|
||||
return (refs,)
|
||||
|
||||
|
||||
class VLLMOmniLatentMaskEditing:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {},
|
||||
"optional": {
|
||||
"source_video": ("VIDEO",),
|
||||
"source_audio": ("AUDIO",),
|
||||
"video_mask": ("MASK",),
|
||||
"audio_mask": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("LATENT_MASK_EDITING",)
|
||||
RETURN_NAMES = ("latent_edit",)
|
||||
FUNCTION = "get_latent_edit"
|
||||
CATEGORY = "vLLM-Omni"
|
||||
|
||||
def get_latent_edit(
|
||||
self,
|
||||
source_video: VideoInput | None = None,
|
||||
source_audio: AudioInput | None = None,
|
||||
video_mask: torch.Tensor | None = None,
|
||||
audio_mask: float = -1.0,
|
||||
**kwargs,
|
||||
):
|
||||
if kwargs:
|
||||
logger.info("Uncaught kwargs: %s", kwargs)
|
||||
edit = LatentMaskEditing()
|
||||
if source_video is not None:
|
||||
edit["source_video"] = source_video
|
||||
if source_audio is not None:
|
||||
edit["source_audio"] = source_audio
|
||||
if video_mask is not None:
|
||||
edit["video_mask"] = video_mask
|
||||
if audio_mask >= 0.0:
|
||||
edit["audio_mask"] = audio_mask
|
||||
return (edit,)
|
||||
|
||||
|
||||
class VLLMOmniMiniMaxH3TemporalMask:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"source_fps": ("FLOAT", {"default": 24.0, "min": 0.01}),
|
||||
"duration": ("FLOAT", {"default": 5.0, "min": 0.01, "max": 15.0}),
|
||||
"mode": (["continuation", "extension"],),
|
||||
"preserve_fraction": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK", "FLOAT", "IMAGE", "MASK")
|
||||
RETURN_NAMES = ("mask", "preview_fps", "preview_images", "preview_mask")
|
||||
FUNCTION = "build"
|
||||
CATEGORY = "vLLM-Omni"
|
||||
|
||||
def build(self, images, source_fps, duration, mode, preserve_fraction=0.5):
|
||||
if images.shape[0] <= 0 or not math.isfinite(source_fps) or source_fps <= 0:
|
||||
raise ValueError("Source must contain frames and have a positive finite FPS.")
|
||||
if not math.isfinite(duration) or duration <= 0 or not 0 <= preserve_fraction <= 1:
|
||||
raise ValueError("Invalid duration or preserve_fraction.")
|
||||
frames = _align_frame_count(max(1, round(duration * 24)))
|
||||
source_seconds = images.shape[0] / source_fps
|
||||
if mode == "extension":
|
||||
if frames / 24 <= source_seconds:
|
||||
raise ValueError("Extension output must be longer than the source; increase duration.")
|
||||
boundary = source_seconds
|
||||
elif mode == "continuation":
|
||||
boundary = min(source_seconds, frames / 24) * preserve_fraction
|
||||
else:
|
||||
raise ValueError(f"Unknown temporal mask mode: {mode}")
|
||||
available = min(frames, math.floor(boundary * 24 + 1e-8))
|
||||
prefix = 0 if available < 5 else 5 + 17 * ((available - 5) // 17)
|
||||
preserved = _video_latent_t(prefix) if prefix else 0
|
||||
total = _video_latent_t(frames)
|
||||
mask = torch.ones(total, 1, 1)
|
||||
mask[:preserved] = 0
|
||||
indices = torch.arange(frames, device=images.device)
|
||||
source_indices = (indices * (source_fps / 24)).floor().long().clamp(max=images.shape[0] - 1)
|
||||
preview_images = images.index_select(0, source_indices)
|
||||
preview_mask = mask.index_select(0, torch.arange(frames) * total // frames)
|
||||
return mask, 24.0, preview_images, preview_mask
|
||||
@@ -1,6 +1,3 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
"""
|
||||
An high-level API client adapter that forwards ComfyUI inputs to vLLM-Omni's REST API,
|
||||
and transforms the API responses back to ComfyUI formats.
|
||||
@@ -20,7 +17,6 @@ from comfy_api.input import AudioInput, VideoInput
|
||||
|
||||
from .format import (
|
||||
audio_to_base64,
|
||||
audio_to_bytes,
|
||||
base64_to_audio,
|
||||
base64_to_image_tensor,
|
||||
bytes_to_audio,
|
||||
@@ -30,16 +26,9 @@ from .format import (
|
||||
video_to_base64,
|
||||
video_to_bytes,
|
||||
)
|
||||
from .latent_mask import scalar_mask_to_json, video_mask_to_grid_json
|
||||
from .logger import get_logger, pretty_printer
|
||||
from .models import lookup_model_spec
|
||||
from .types import (
|
||||
MAX_REFERENCE_AUDIOS,
|
||||
MAX_REFERENCE_IMAGES,
|
||||
MAX_REFERENCE_VIDEOS,
|
||||
MAX_TOTAL_REFERENCES,
|
||||
AudioFormat,
|
||||
)
|
||||
from .types import AudioFormat
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -278,34 +267,14 @@ class VLLMOmniClient:
|
||||
fps: int,
|
||||
negative_prompt: str | None = None,
|
||||
frame: torch.Tensor | None = None,
|
||||
first_frame: torch.Tensor | None = None,
|
||||
last_frame: torch.Tensor | None = None,
|
||||
references: dict | None = None,
|
||||
sampling_params: dict | None = None,
|
||||
model_params: dict | None = None,
|
||||
lora: dict | None = None,
|
||||
latent_edit: dict | None = None,
|
||||
spec_model: str | None = None,
|
||||
**extra_params,
|
||||
) -> VideoInput:
|
||||
"""Post a video job and return the decoded result.
|
||||
|
||||
``spec_model`` names the model whose payload spec builds the request, for
|
||||
deployments that serve a known model under a different ``model`` alias. It
|
||||
never reaches the wire; defaults to ``model``.
|
||||
"""
|
||||
if frame is not None and references is not None:
|
||||
raise ValueError("Provide only one of frame or references, not both.")
|
||||
if frame is not None and (first_frame is not None or last_frame is not None):
|
||||
raise ValueError("Provide either frame or first_frame/last_frame, not both.")
|
||||
if references is not None and (first_frame is not None or last_frame is not None):
|
||||
raise ValueError("Provide either first_frame/last_frame or references, not both.")
|
||||
|
||||
spec, matched_pattern = lookup_model_spec(spec_model or model)
|
||||
if (first_frame is not None or last_frame is not None) and (
|
||||
matched_pattern is None or "MiniMax-H3" not in matched_pattern
|
||||
):
|
||||
raise ValueError("first_frame and last_frame are supported only for MiniMax-H3; use frame for this model.")
|
||||
|
||||
# === regular payload fields ===
|
||||
form = aiohttp.FormData()
|
||||
@@ -325,62 +294,43 @@ class VLLMOmniClient:
|
||||
|
||||
# === multimodal inputs (first-last-frames, references, etc.) ===
|
||||
input_reference_image: torch.Tensor | None = None
|
||||
keyframe_images: list[tuple[str, torch.Tensor]] = []
|
||||
audio_reference: AudioInput | None = None
|
||||
reference_videos: list[VideoInput] = []
|
||||
video_task: str | None = None
|
||||
|
||||
if frame is not None:
|
||||
input_reference_image = frame
|
||||
video_task = "fl2va"
|
||||
elif first_frame is not None or last_frame is not None:
|
||||
frame_indices: list[int] = []
|
||||
if first_frame is not None:
|
||||
keyframe_images.append(("first_frame.png", first_frame))
|
||||
frame_indices.append(0)
|
||||
if last_frame is not None:
|
||||
keyframe_images.append(("last_frame.png", last_frame))
|
||||
frame_indices.append(-1)
|
||||
if len(keyframe_images) == 1:
|
||||
input_reference_image = keyframe_images[0][1]
|
||||
extra_params["frame_indices"] = frame_indices
|
||||
video_task = "fl2va"
|
||||
elif references is not None:
|
||||
reference_formats = (
|
||||
("image", MAX_REFERENCE_IMAGES, "png", "image/png", image_tensor_to_png_bytes),
|
||||
("video", MAX_REFERENCE_VIDEOS, "mp4", "video/mp4", video_to_bytes),
|
||||
("audio", MAX_REFERENCE_AUDIOS, "mp3", "audio/mpeg", audio_to_bytes),
|
||||
)
|
||||
supported_inputs = {f"{kind}_{i}" for kind, limit, *_ in reference_formats for i in range(1, limit + 1)}
|
||||
connected = {name: value for name, value in references.items() if value is not None}
|
||||
unsupported = connected.keys() - supported_inputs
|
||||
if unsupported:
|
||||
raise ValueError(f"Unsupported reference input(s): {', '.join(sorted(unsupported))}.")
|
||||
if not any(name.startswith(("image_", "video_")) for name in connected):
|
||||
images = [references[k] for k in ("image_1", "image_2") if k in references and references[k] is not None]
|
||||
audios = [references[k] for k in ("audio_1", "audio_2") if k in references and references[k] is not None]
|
||||
videos = [references[k] for k in ("video_1", "video_2") if k in references and references[k] is not None]
|
||||
|
||||
if not images and not audios and not videos:
|
||||
raise ValueError("references is empty; connect at least one image/audio/video.")
|
||||
|
||||
if videos:
|
||||
if images or audios:
|
||||
raise ValueError(
|
||||
"Video references cannot be combined with image or audio references. "
|
||||
"Connect only video_1/video_2 for multi-video Ref2VA."
|
||||
)
|
||||
reference_videos = videos
|
||||
video_task = "ref2va"
|
||||
elif len(images) == 1 and len(audios) == 1:
|
||||
input_reference_image = images[0]
|
||||
audio_reference = audios[0]
|
||||
video_task = "ref2va"
|
||||
else:
|
||||
raise ValueError(
|
||||
"references requires at least one image or video; audio-only inputs are not supported."
|
||||
"Invalid references combination. Supported modes: "
|
||||
"(1) one or more videos only, or (2) exactly one image and one audio."
|
||||
)
|
||||
if len(connected) > MAX_TOTAL_REFERENCES:
|
||||
raise ValueError(
|
||||
f"references supports at most {MAX_TOTAL_REFERENCES} inputs in total "
|
||||
f"(up to {MAX_REFERENCE_IMAGES} images, {MAX_REFERENCE_VIDEOS} videos, "
|
||||
f"and {MAX_REFERENCE_AUDIOS} audios)."
|
||||
)
|
||||
for kind, limit, extension, content_type, encode in reference_formats:
|
||||
for index in range(1, limit + 1):
|
||||
name = f"{kind}_{index}"
|
||||
if name in connected:
|
||||
filename = f"{name}.{extension}"
|
||||
form.add_field(
|
||||
"input_references",
|
||||
encode(connected[name], filename),
|
||||
filename=filename,
|
||||
content_type=content_type,
|
||||
)
|
||||
video_task = "ref2va"
|
||||
else:
|
||||
video_task = "t2va"
|
||||
|
||||
if input_reference_image is not None:
|
||||
image_filename = keyframe_images[0][0] if keyframe_images else "image.png"
|
||||
image_filename = "image.png" # Required for multipart form
|
||||
form.add_field(
|
||||
"input_reference",
|
||||
image_tensor_to_png_bytes(input_reference_image, image_filename),
|
||||
@@ -388,74 +338,32 @@ class VLLMOmniClient:
|
||||
content_type="image/png",
|
||||
)
|
||||
|
||||
# === latent-mask editing (MiniMax H3) ===
|
||||
if latent_edit is not None:
|
||||
source_video = latent_edit.get("source_video")
|
||||
source_audio = latent_edit.get("source_audio")
|
||||
video_mask = latent_edit.get("video_mask")
|
||||
audio_mask = latent_edit.get("audio_mask")
|
||||
if audio_reference is not None:
|
||||
form.add_field(
|
||||
"audio_reference",
|
||||
json.dumps({"audio_url": audio_to_base64(audio_reference)}, ensure_ascii=False),
|
||||
)
|
||||
|
||||
if video_mask is None and audio_mask is None:
|
||||
raise ValueError("Latent-mask editing requires at least one mask.")
|
||||
|
||||
video_mask_trivial = video_mask is None or bool((video_mask == 1.0).all().item())
|
||||
audio_mask_trivial = audio_mask is None or audio_mask == 1.0
|
||||
if not video_mask_trivial and source_video is None:
|
||||
raise ValueError("A non-trivial video mask requires a source video.")
|
||||
if not audio_mask_trivial and source_audio is None and source_video is None:
|
||||
raise ValueError("A non-trivial audio mask requires a source audio or a source video with audio.")
|
||||
|
||||
if source_video is not None:
|
||||
form.add_field(
|
||||
"source_video",
|
||||
video_to_bytes(source_video, "source.mp4"),
|
||||
filename="source.mp4",
|
||||
content_type="video/mp4",
|
||||
)
|
||||
if source_audio is not None:
|
||||
form.add_field(
|
||||
"source_audio",
|
||||
audio_to_bytes(source_audio, "source_audio.mp3"),
|
||||
filename="source_audio.mp3",
|
||||
content_type="audio/mpeg",
|
||||
)
|
||||
if video_mask is not None:
|
||||
mask_json = video_mask_to_grid_json(video_mask, width=width, height=height, num_frames=num_frames)
|
||||
form.add_field(
|
||||
"video_noise_mask",
|
||||
mask_json.encode("utf-8"),
|
||||
filename="video-mask.json",
|
||||
content_type="application/json",
|
||||
)
|
||||
if audio_mask is not None:
|
||||
form.add_field(
|
||||
"audio_noise_mask",
|
||||
scalar_mask_to_json(audio_mask).encode("utf-8"),
|
||||
filename="audio-mask.json",
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
if len(keyframe_images) == 2:
|
||||
for image_filename, image in keyframe_images:
|
||||
form.add_field(
|
||||
"input_references",
|
||||
image_tensor_to_png_bytes(image, image_filename),
|
||||
filename=image_filename,
|
||||
content_type="image/png",
|
||||
)
|
||||
for idx, video in enumerate(reference_videos, start=1):
|
||||
video_filename = f"reference_{idx}.mp4"
|
||||
form.add_field(
|
||||
"input_references",
|
||||
video_to_bytes(video, video_filename),
|
||||
filename=video_filename,
|
||||
content_type="video/mp4",
|
||||
)
|
||||
|
||||
# === model specific params. Either use a specialized builder, or add flattened fields as-is ===
|
||||
if model_params is not None:
|
||||
model_params = dict(model_params)
|
||||
model_params.pop("type", None)
|
||||
|
||||
spec, _ = lookup_model_spec(model)
|
||||
params_builder = spec.get("params_builder") if spec else None
|
||||
if params_builder is not None:
|
||||
form_fields = params_builder(
|
||||
model_params or {},
|
||||
extra_params={**extra_params, "task": video_task},
|
||||
width=width,
|
||||
height=height,
|
||||
)
|
||||
for k, v in form_fields.items():
|
||||
form.add_field(k, v if isinstance(v, str) else str(v))
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
"""Image/tensor format helpers.
|
||||
|
||||
The image generation part is derived from dougbtv/comfyui-vllm-omni by Doug (@dougbtv).
|
||||
@@ -173,10 +170,6 @@ def bytes_to_video(video_bytes: bytes) -> VideoInput:
|
||||
audio_stream = container.streams.audio[-1]
|
||||
audio_frames = []
|
||||
resampler = AudioResampler(format="fltp")
|
||||
# Decoding the video stream above left the container at EOF.
|
||||
# Rewind before demuxing again, or this pass yields no frames
|
||||
# and the audio of a T2VA result is silently dropped.
|
||||
container.seek(0)
|
||||
for frame in container.decode(audio_stream):
|
||||
if not isinstance(frame, AudioFrame):
|
||||
continue
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import json
|
||||
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
|
||||
def scalar_mask_to_json(value: float) -> str:
|
||||
if not 0.0 <= value <= 1.0:
|
||||
raise ValueError(f"mask value must be in [0, 1], got {value}")
|
||||
return str(value)
|
||||
|
||||
|
||||
def _align_frame_count(frame_count: int) -> int:
|
||||
if frame_count <= 0:
|
||||
return 1
|
||||
current = int(frame_count)
|
||||
while current % 17 != 5:
|
||||
current += 1
|
||||
return current
|
||||
|
||||
|
||||
def _video_latent_t(frame_count: int) -> int:
|
||||
if frame_count <= 5:
|
||||
return 2
|
||||
return ((int(frame_count) - 5) // 17) * 5 + 2
|
||||
|
||||
|
||||
def video_mask_to_grid(mask: torch.Tensor, *, width: int, height: int, num_frames: int) -> torch.Tensor:
|
||||
tv = _video_latent_t(_align_frame_count(num_frames))
|
||||
height = int(height) // 32 * 32
|
||||
width = int(width) // 32 * 32
|
||||
gh, gw = height // 16, width // 16
|
||||
|
||||
if mask.ndim == 2:
|
||||
mask = mask.unsqueeze(0)
|
||||
elif mask.ndim != 3:
|
||||
raise ValueError(f"expected a 2D or 3D mask tensor, got {mask.ndim}D")
|
||||
|
||||
grid = F.interpolate(mask.unsqueeze(1).float(), size=(gh, gw), mode="area").squeeze(1)
|
||||
if grid.shape[0] == 1:
|
||||
grid = grid.expand(tv, gh, gw)
|
||||
elif grid.shape[0] != tv:
|
||||
grid = F.interpolate(grid.unsqueeze(0).unsqueeze(0), size=(tv, gh, gw), mode="nearest").squeeze(0).squeeze(0)
|
||||
return grid
|
||||
|
||||
|
||||
def video_mask_to_grid_json(mask: torch.Tensor, *, width: int, height: int, num_frames: int) -> str:
|
||||
return json.dumps(video_mask_to_grid(mask, width=width, height=height, num_frames=num_frames).tolist())
|
||||
@@ -1,6 +1,3 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import json
|
||||
import re
|
||||
from typing import Any
|
||||
@@ -37,28 +34,10 @@ def _qwen25_payload_preprocessor(payload: dict) -> dict:
|
||||
return payload
|
||||
|
||||
|
||||
MINIMAX_H3_ASPECT_RATIOS = {
|
||||
"21:9": 21.0 / 9.0,
|
||||
"16:9": 16.0 / 9.0,
|
||||
"4:3": 4.0 / 3.0,
|
||||
"1:1": 1.0,
|
||||
"3:4": 3.0 / 4.0,
|
||||
"9:16": 9.0 / 16.0,
|
||||
}
|
||||
|
||||
|
||||
def _nearest_minimaxh3_aspect_ratio(width: int, height: int) -> str:
|
||||
"""Pick the supported named ratio closest to the requested frame size."""
|
||||
target = float(width) / float(height)
|
||||
return min(MINIMAX_H3_ASPECT_RATIOS, key=lambda name: abs(MINIMAX_H3_ASPECT_RATIOS[name] - target))
|
||||
|
||||
|
||||
def _minimaxh3_params_builder(
|
||||
model_params: dict[str, Any],
|
||||
*,
|
||||
extra_params: dict[str, Any],
|
||||
width: int | None = None,
|
||||
height: int | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Build multipart form fields for MiniMax-H3 from model_params + routed task."""
|
||||
params = dict(model_params)
|
||||
@@ -74,12 +53,6 @@ def _minimaxh3_params_builder(
|
||||
if params:
|
||||
logger.warning("Unused MiniMax-H3 model params ignored: %s", sorted(params))
|
||||
|
||||
# H3 refuses t2va without a named aspect ratio, and the Generate Video node
|
||||
# carries width/height rather than a ratio. fl2va takes its ratio from the
|
||||
# input image and ref2va defaults server-side, so only t2va needs this.
|
||||
if merged_extra_params.get("task") == "t2va" and "aspect_ratio" not in merged_extra_params and width and height:
|
||||
merged_extra_params["aspect_ratio"] = _nearest_minimaxh3_aspect_ratio(width, height)
|
||||
|
||||
if merged_extra_params:
|
||||
form_fields["extra_params"] = json.dumps(merged_extra_params, ensure_ascii=False)
|
||||
return form_fields
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
from collections.abc import Callable
|
||||
from enum import Enum, auto
|
||||
from typing import Any, Literal, TypeAlias
|
||||
@@ -30,24 +27,10 @@ class MiniMaxH3ModelSpecificParams(dict):
|
||||
pass
|
||||
|
||||
|
||||
MAX_REFERENCE_IMAGES = 9
|
||||
MAX_REFERENCE_VIDEOS = 3
|
||||
MAX_REFERENCE_AUDIOS = 3
|
||||
MAX_TOTAL_REFERENCES = 12
|
||||
|
||||
|
||||
class VideoReferences(dict):
|
||||
pass
|
||||
|
||||
|
||||
class LatentMaskEditing(dict):
|
||||
pass
|
||||
|
||||
|
||||
class FastH3Deployment(dict):
|
||||
"""Descriptor for a server that fused FastH3 at startup."""
|
||||
|
||||
|
||||
class ModelMode(Enum):
|
||||
IMAGE_GENERATION = auto()
|
||||
VIDEO_GENERATION = auto()
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 197 KiB |
@@ -1,94 +0,0 @@
|
||||
# MiniMax H3 Text to Video (WF-01)
|
||||
|
||||
Import [MiniMax_H3_Text_to_Video.json](../example_workflows/MiniMax_H3_Text_to_Video.json)
|
||||
into ComfyUI, or select it under **Templates → ComfyUI-vLLM-Omni**.
|
||||
The template connects existing nodes to a remote H3 service and saves the
|
||||
returned video with audio. ComfyUI does not load H3 weights.
|
||||
|
||||
## Setup
|
||||
|
||||
Install the [ComfyUI extension](../README.md#installation) and follow the
|
||||
[H3 deployment recipe](../../../recipes/MiniMaxAI/MiniMax-H3.md) for your hardware.
|
||||
For a two-GPU FL2VA server with sufficient memory:
|
||||
|
||||
```bash
|
||||
export MODEL=/path/to/MiniMax-H3/FL2VA
|
||||
CUDA_VISIBLE_DEVICES=0,1 VLLM_WORKER_MULTIPROC_METHOD=spawn \
|
||||
VLLM_OMNI_VIDEO_SYNC_TIMEOUT=14400 \
|
||||
vllm serve "$MODEL" --omni --host 127.0.0.1 --port 8000 \
|
||||
--served-model-name MiniMaxAI/MiniMax-H3 --trust-remote-code \
|
||||
--task-type fl2va --num-gpus 2 --tensor-parallel-size 2 \
|
||||
--text-encoder-tp-size 2 --enforce-eager
|
||||
```
|
||||
|
||||
Set Generate Video's **url** to the address reachable from ComfyUI, including
|
||||
`/v1`, and match its **model** to the served name. The defaults are
|
||||
`http://localhost:8000/v1` and `MiniMaxAI/MiniMax-H3`.
|
||||
|
||||
## Base and Turbo
|
||||
|
||||
Base presets are connected by default. Write the scene and its sound in the
|
||||
same **prompt**; leave **frame**, **references**, and **fast_h3** disconnected.
|
||||
The template uses 1344×768, 24 FPS, seed 1101 and **duration** 5.167 seconds
|
||||
(124 frames, satisfying H3's `17k+5` constraint). The existing client infers
|
||||
`16:9` from these dimensions. For portrait output, use 768×1344.
|
||||
|
||||
| Setting | Base | Turbo v1.0 768p |
|
||||
| --- | --- | --- |
|
||||
| Inference steps | 50 | 5 (4 forwards) |
|
||||
| Video flow shift | 12 | 6 |
|
||||
| Audio flow shift | 3 | 3 |
|
||||
| Remote LoRA | Disconnected | Connected, scale 1 |
|
||||
|
||||
For Turbo, use the **Diffusers-layout** artifact from
|
||||
[lightx2v/Minimax-h3-Turbo](https://huggingface.co/lightx2v/Minimax-h3-Turbo):
|
||||
|
||||
```text
|
||||
minimax_h3_fl2v_turbo_4step_v1.0_768p_bf16.safetensors
|
||||
```
|
||||
|
||||
Add `--lora-backend peft --lora-path "$TURBO_LORA"` to the server command,
|
||||
where `TURBO_LORA` is the full server-side path to that file. Enter the same
|
||||
path in Remote LoRA's **local_path**; retain name `h3-turbo-v1.0-768p`, scale
|
||||
`1.0`, and **int_id** `0` so the existing API derives the ID from the path.
|
||||
The template leaves the path blank for users to configure. The `_comfyui_`
|
||||
export is not supported by this backend.
|
||||
|
||||
Connect **Turbo sampling**, **Turbo H3 params**, and **Remote LoRA** to Generate
|
||||
Video's `sampling_params`, `model_params`, and `lora` inputs, replacing the
|
||||
Base links. To return to Base, restore both Base links and disconnect LoRA.
|
||||
Other Turbo artifacts may need different settings; see the
|
||||
[artifact table](../../../recipes/MiniMaxAI/MiniMax-H3.md#turbo-lora).
|
||||
|
||||
If importing an older template with a frame-count widget, reimport this JSON
|
||||
or set **duration** to **5.167**; do not interpret 124 frames as 124 seconds.
|
||||
|
||||
## Validation
|
||||
|
||||
Queue the configured workflow and inspect the MP4 saved under
|
||||
`ComfyUI/output/video/MiniMax_H3_WF01_*.mp4`:
|
||||
|
||||
```bash
|
||||
ffprobe -v error -show_streams -show_format -of json "$OUTPUT"
|
||||
ffmpeg -v error -i "$OUTPUT" -f null -
|
||||
```
|
||||
|
||||
Check the requested dimensions, frame count, 24 FPS and both video/audio
|
||||
streams, then watch and listen to the saved file. The current upstream
|
||||
extension includes the shared audio-preserving decoder fix.
|
||||
|
||||
On September 16, the narrowed workflow was validated through ComfyUI using
|
||||
existing upstream Python code at `4a8ac297`, two H20-3e GPUs, vLLM 0.29.0,
|
||||
PyTorch 2.13.0+cu129 and ComfyUI `1d48d9cf`. The run used the template's
|
||||
forest-stream prompt, explicit server-side Turbo LoRA path, and settings
|
||||
above, with `TORCH_SDPA`, `--usp 1 --ring 1`, and tiled VAE parallelism on two
|
||||
GPUs. ComfyUI execution took 131.55 seconds. SaveVideo produced 124 H.264
|
||||
frames at 1344×768 and 24 FPS, plus 32 kHz stereo AAC audio. Video/audio
|
||||
durations were 5.166667/5.167000 seconds; full decoding passed and audio was
|
||||
nonzero. This is model-generated output, not a ground-truth reference or a
|
||||
subjective audio-quality assessment. Base graph validation passed with Turbo
|
||||
nodes disconnected; full 50-step Base quality was not evaluated.
|
||||
|
||||
Based on the official
|
||||
[ComfyUI H3 T2V template](https://github.com/Comfy-Org/workflow_templates/blob/main/templates/video_minimax_h3_t2v.json),
|
||||
using remote inference instead of local model loaders.
|
||||
@@ -1,17 +0,0 @@
|
||||
# WF-05: MiniMax-H3 latent-mask editing
|
||||
|
||||
Edit a source video with MiniMax-H3 using spatial or temporal masks. The workflow includes object removal, inpainting, continuation, and extension, with a mask preview for each case.
|
||||
|
||||
## Requirements
|
||||
|
||||
- ComfyUI with ComfyUI-vLLM-Omni installed.
|
||||
- An H3 service using the FL2VA checkpoint partition with latent-mask editing support. Follow the [H3 recipe](../../../recipes/MiniMaxAI/MiniMax-H3.md) for server setup.
|
||||
|
||||
## Use
|
||||
|
||||
Open **vLLM-Omni MiniMax-H3 Latent Mask Editing.json** from the example workflows and set the Generate Video URL/model for the case you want to run.
|
||||
|
||||
1. Upload your source video in Load Video.
|
||||
2. Adjust the case's mask. For removal and inpainting, set Mask Canvas to the video dimensions, Mask Rectangle to the region size, and Combine Masks x/y to its position. For continuation and extension, set MiniMax-H3 Temporal Mask's mode and duration; continuation also uses `preserve_fraction`. Match the duration in Generate Video, and use a duration longer than the source for extension. Mask values are `0` to preserve and `1` to regenerate.
|
||||
3. Adjust the prompt to describe the desired content. Set the output dimensions and duration in Generate Video. If editing audio, update the sound description and audio mask (`0` preserves, `1` regenerates the whole clip).
|
||||
4. Select the case's Mask Preview Save Video node and choose **Execute to selected output nodes** to preview the mask as a red overlay without inference, or select its Result Save Video node to generate the edited video. Running the entire workflow generates all four cases.
|
||||
@@ -1,21 +0,0 @@
|
||||
# WF-07: H3 video upscale with SeedVR2
|
||||
|
||||
Generate video and audio through vLLM-Omni H3, upscale the decoded frames with SeedVR2, and save both the original and upscaled videos. The generated audio and FPS connect directly to Create Video.
|
||||
|
||||
## Requirements
|
||||
|
||||
- ComfyUI with ComfyUI-vLLM-Omni and [ComfyUI-SeedVR2_VideoUpscaler](https://github.com/numz/ComfyUI-SeedVR2_VideoUpscaler#-installation) installed.
|
||||
- An H3 service using the FL2VA checkpoint partition. Follow the [H3 recipe](../../../recipes/MiniMaxAI/MiniMax-H3.md) for server setup.
|
||||
- `seedvr2_ema_3b_fp16.safetensors` and `ema_vae_fp16.safetensors` from [SeedVR2's ComfyUI weights](https://huggingface.co/numz/SeedVR2_comfyUI/tree/main), placed in `ComfyUI/models/SEEDVR2`. The SeedVR2 nodes can also download them on first use.
|
||||
|
||||
## Use
|
||||
|
||||
Open **vLLM-Omni MiniMax H3 Video Upscale.json** from the example workflows. An API-format version is provided alongside it. Set the Generate Video URL/model and the LoRA path as seen by the H3 server.
|
||||
|
||||
The preset uses the LightX2V v1.0 768p Turbo adapter in Diffusers format: `minimax_h3_fl2v_turbo_4step_v1.0_768p_bf16.safetensors`, five sigma points, video/audio flow shifts 6/3, and LoRA scale 1. Preload the same adapter on the server using the [Turbo LoRA recipe](../../../recipes/MiniMaxAI/MiniMax-H3.md#turbo-lora). For base H3, disconnect LoRA, set inference steps to 50, and set video flow shift to 12.
|
||||
|
||||
The H3 preset requests 1344 x 768 at 24 FPS for 5.167 seconds, which gives 124 frames. SeedVR2's `resolution=1536` sets the target short edge, producing 2688 x 1536 for this input. Update this value when changing the input size; it is an output resolution, not a fixed 2x multiplier.
|
||||
|
||||
The SeedVR2 preset uses 3B FP16, five-frame batches, one overlapping frame, uniform batch padding, and LAB color correction. The DiT loader uses CPU offload with 32 swapped blocks; the VAE uses tiled encoding and decoding. Select the local GPU in both model loaders. See the [SeedVR2 settings](https://github.com/numz/ComfyUI-SeedVR2_VideoUpscaler#-usage) when adjusting memory use or batch size.
|
||||
|
||||
Run the workflow. The two Save Video nodes write MP4s under `WF07/generated` and `WF07/upscaled` in ComfyUI's output directory.
|
||||
@@ -1,362 +0,0 @@
|
||||
{
|
||||
"last_node_id": 8,
|
||||
"last_link_id": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "VLLMOmniDiffusionSampling",
|
||||
"pos": [
|
||||
20,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
310,
|
||||
280
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "diffusion sampling params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniDiffusionSampling"
|
||||
},
|
||||
"widgets_values": [
|
||||
1,
|
||||
50,
|
||||
1.0,
|
||||
1.0,
|
||||
false,
|
||||
false,
|
||||
1101,
|
||||
"fixed"
|
||||
],
|
||||
"title": "Base sampling"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "VLLMOmniMiniMaxH3Params",
|
||||
"pos": [
|
||||
20,
|
||||
340
|
||||
],
|
||||
"size": [
|
||||
310,
|
||||
140
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MiniMax-H3 video params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniMiniMaxH3Params"
|
||||
},
|
||||
"widgets_values": [
|
||||
3.0,
|
||||
12.0
|
||||
],
|
||||
"title": "Base H3 params"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "VLLMOmniGenerateVideo",
|
||||
"pos": [
|
||||
430,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
430,
|
||||
440
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "frame",
|
||||
"type": "IMAGE",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "references",
|
||||
"type": "VIDEO_REFERENCES",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "sampling_params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "lora",
|
||||
"type": "REMOTE_LORA",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "model_params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"link": 2
|
||||
},
|
||||
{
|
||||
"name": "fast_h3",
|
||||
"type": "FASTH3_DEPLOYMENT",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "duration",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "duration"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
3
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniGenerateVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"http://localhost:8000/v1",
|
||||
"MiniMaxAI/MiniMax-H3",
|
||||
"A small stream flows through a sunlit forest. The camera slowly moves toward the water. Birds chirp in the trees and water gurgles over smooth stones. Natural continuous sound, no music.",
|
||||
"",
|
||||
1344,
|
||||
768,
|
||||
24,
|
||||
5.167
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
940,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
440,
|
||||
440
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": null,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SaveVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"video/MiniMax_H3_WF01",
|
||||
"mp4",
|
||||
"auto"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "VLLMOmniRemoteLoRA",
|
||||
"pos": [
|
||||
430,
|
||||
540
|
||||
],
|
||||
"size": [
|
||||
430,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "lora",
|
||||
"type": "REMOTE_LORA",
|
||||
"links": null,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniRemoteLoRA"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
"h3-turbo-v1.0-768p",
|
||||
1.0,
|
||||
0
|
||||
],
|
||||
"title": "Optional Turbo: server LoRA path"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VLLMOmniDiffusionSampling",
|
||||
"pos": [
|
||||
20,
|
||||
540
|
||||
],
|
||||
"size": [
|
||||
310,
|
||||
280
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "diffusion sampling params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"links": null,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniDiffusionSampling"
|
||||
},
|
||||
"widgets_values": [
|
||||
1,
|
||||
5,
|
||||
1.0,
|
||||
1.0,
|
||||
false,
|
||||
false,
|
||||
1101,
|
||||
"fixed"
|
||||
],
|
||||
"title": "Turbo sampling (4 forwards)"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "VLLMOmniMiniMaxH3Params",
|
||||
"pos": [
|
||||
430,
|
||||
740
|
||||
],
|
||||
"size": [
|
||||
310,
|
||||
140
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MiniMax-H3 video params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"links": null,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniMiniMaxH3Params"
|
||||
},
|
||||
"widgets_values": [
|
||||
3.0,
|
||||
6.0
|
||||
],
|
||||
"title": "Turbo H3 params"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "Note",
|
||||
"pos": [
|
||||
940,
|
||||
520
|
||||
],
|
||||
"size": [
|
||||
440,
|
||||
440
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "Note"
|
||||
},
|
||||
"widgets_values": [
|
||||
"MiniMax H3 Text to Video (WF-01)\n\nBASE: connected presets, 50 steps / video flow 12 / audio flow 3.\n\nTURBO: set Remote LoRA local_path to the SERVER path of minimax_h3_fl2v_turbo_4step_v1.0_768p_bf16.safetensors from lightx2v/Minimax-h3-Turbo. Keep name h3-turbo-v1.0-768p, scale 1.0 and int_id 0. Connect Turbo sampling, Turbo H3 params, and LoRA to Generate Video, replacing the two Base links. Use 5 steps (4 forwards), video flow 6 and audio flow 3. Do not use the ComfyUI-layout artifact.\n\nKeep frame, references and fast_h3 disconnected. 1344x768, 24 FPS, duration 5.167 seconds = 124 frames (17*7+5). The client selects the named 16:9 preset from the dimensions. Save Video preserves video and audio.\n\nSet URL and served model name for your server. See docs/minimax-h3-t2v.md for setup and validation. Source: Comfy-Org/workflow_templates/templates/video_minimax_h3_t2v.json."
|
||||
],
|
||||
"title": "Setup / Base and Turbo"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"SAMPLING_PARAMS"
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
0,
|
||||
3,
|
||||
4,
|
||||
"VIDEO_PARAMS"
|
||||
],
|
||||
[
|
||||
3,
|
||||
3,
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
"VIDEO"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.8,
|
||||
"offset": [
|
||||
50,
|
||||
50
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
{
|
||||
"id": "c6db00da-2ccb-4ff8-8334-d67e1a267781",
|
||||
"revision": 0,
|
||||
"last_node_id": 5,
|
||||
"last_link_id": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [40, 20],
|
||||
"size": [420, 250],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "FastH3 server prerequisite",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"FastH3 must be fused when the vLLM-Omni server starts. Use --task-type fl2va and --lora-path pointing to exactly one FastH3 adapter file. Do not use CPU or layerwise offload. For VSA / Data-Free, also install fastvideo-kernel and use --diffusion-attention-backend FASTVIDEO_VSA --fastvideo-vsa-topk 64."
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "VLLMOmniFastH3Deployment",
|
||||
"pos": [40, 320],
|
||||
"size": [420, 160],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "url",
|
||||
"name": "url",
|
||||
"type": "STRING",
|
||||
"widget": {"name": "url"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model",
|
||||
"name": "model",
|
||||
"type": "STRING",
|
||||
"widget": {"name": "model"},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "deployment",
|
||||
"name": "deployment",
|
||||
"type": "FASTH3_DEPLOYMENT",
|
||||
"links": [1]
|
||||
}
|
||||
],
|
||||
"properties": {"Node name for S&R": "VLLMOmniFastH3Deployment"},
|
||||
"widgets_values": [
|
||||
"http://localhost:8000/v1",
|
||||
"MiniMaxAI/MiniMax-H3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "VLLMOmniDiffusionSampling",
|
||||
"pos": [40, 540],
|
||||
"size": [420, 230],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "n",
|
||||
"name": "n",
|
||||
"type": "INT",
|
||||
"widget": {"name": "n"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "num_inference_steps",
|
||||
"name": "num_inference_steps",
|
||||
"type": "INT",
|
||||
"widget": {"name": "num_inference_steps"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "guidance_scale",
|
||||
"name": "guidance_scale",
|
||||
"type": "FLOAT",
|
||||
"widget": {"name": "guidance_scale"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "true_cfg_scale",
|
||||
"name": "true_cfg_scale",
|
||||
"type": "FLOAT",
|
||||
"widget": {"name": "true_cfg_scale"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "vae_use_slicing",
|
||||
"name": "vae_use_slicing",
|
||||
"type": "BOOLEAN",
|
||||
"widget": {"name": "vae_use_slicing"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "vae_use_tiling",
|
||||
"name": "vae_use_tiling",
|
||||
"type": "BOOLEAN",
|
||||
"widget": {"name": "vae_use_tiling"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "seed",
|
||||
"name": "seed",
|
||||
"type": "INT",
|
||||
"widget": {"name": "seed"},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "diffusion sampling params",
|
||||
"name": "diffusion sampling params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"links": [2]
|
||||
}
|
||||
],
|
||||
"properties": {"Node name for S&R": "VLLMOmniDiffusionSampling"},
|
||||
"widgets_values": [1, 4, 1, 1, false, false, 1101, "fixed"]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "VLLMOmniGenerateVideo",
|
||||
"pos": [560, 210],
|
||||
"size": [540, 610],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "frame",
|
||||
"name": "frame",
|
||||
"shape": 7,
|
||||
"type": "IMAGE",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "references",
|
||||
"name": "references",
|
||||
"shape": 7,
|
||||
"type": "VIDEO_REFERENCES",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "sampling_params",
|
||||
"name": "sampling_params",
|
||||
"shape": 7,
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"link": 2
|
||||
},
|
||||
{
|
||||
"localized_name": "lora",
|
||||
"name": "lora",
|
||||
"shape": 7,
|
||||
"type": "REMOTE_LORA",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model_params",
|
||||
"name": "model_params",
|
||||
"shape": 7,
|
||||
"type": "VIDEO_PARAMS",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "fast_h3",
|
||||
"name": "fast_h3",
|
||||
"shape": 7,
|
||||
"type": "FASTH3_DEPLOYMENT",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"localized_name": "url",
|
||||
"name": "url",
|
||||
"type": "STRING",
|
||||
"widget": {"name": "url"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model",
|
||||
"name": "model",
|
||||
"type": "STRING",
|
||||
"widget": {"name": "model"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "prompt",
|
||||
"name": "prompt",
|
||||
"type": "STRING",
|
||||
"widget": {"name": "prompt"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "negative_prompt",
|
||||
"name": "negative_prompt",
|
||||
"type": "STRING",
|
||||
"widget": {"name": "negative_prompt"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "width",
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"widget": {"name": "width"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "height",
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"widget": {"name": "height"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "fps",
|
||||
"name": "fps",
|
||||
"type": "INT",
|
||||
"widget": {"name": "fps"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "duration",
|
||||
"name": "duration",
|
||||
"type": "FLOAT",
|
||||
"widget": {"name": "duration"},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [3]
|
||||
}
|
||||
],
|
||||
"properties": {"Node name for S&R": "VLLMOmniGenerateVideo"},
|
||||
"widgets_values": [
|
||||
"http://localhost:8000/v1",
|
||||
"MiniMaxAI/MiniMax-H3",
|
||||
"A cinematic live-action singer performs naturally on a neon-lit stage, with synchronized vocals and environmental sound.",
|
||||
"",
|
||||
1344,
|
||||
768,
|
||||
24,
|
||||
4.458
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "SaveVideo",
|
||||
"pos": [1200, 280],
|
||||
"size": [380, 310],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 3
|
||||
},
|
||||
{
|
||||
"localized_name": "filename_prefix",
|
||||
"name": "filename_prefix",
|
||||
"type": "STRING",
|
||||
"widget": {"name": "filename_prefix"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "format",
|
||||
"name": "format",
|
||||
"type": "COMBO",
|
||||
"widget": {"name": "format"},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "codec",
|
||||
"name": "codec",
|
||||
"type": "COMFY_DYNAMICCOMBO_V3",
|
||||
"widget": {"name": "codec"},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": ["video/ComfyUI-FastH3", "auto", "auto"]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[1, 2, 0, 4, 5, "FASTH3_DEPLOYMENT"],
|
||||
[2, 3, 0, 4, 2, "SAMPLING_PARAMS"],
|
||||
[3, 4, 0, 5, 0, "VIDEO"]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"workflowRendererVersion": "LG",
|
||||
"ds": {"scale": 0.9, "offset": [100, 100]}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
-499
@@ -1,499 +0,0 @@
|
||||
{
|
||||
"id": "latent-mask-editing-7380",
|
||||
"revision": 0,
|
||||
"last_node_id": 7,
|
||||
"last_link_id": 5,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [
|
||||
40,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
210
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "Latent-mask editing server prerequisite",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"Requires a vLLM-Omni server that declares latent-mask editing support (MiniMax-H3, EDIT-01). The source clip and video/audio noise masks are uploaded to /v1/videos; 0 preserves, 1 regenerates, fractional blends."
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "LoadVideo",
|
||||
"pos": [
|
||||
40,
|
||||
280
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
120
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "file",
|
||||
"name": "file",
|
||||
"type": "COMBO",
|
||||
"widget": {
|
||||
"name": "file"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "LoadImageMask",
|
||||
"pos": [
|
||||
40,
|
||||
460
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "image"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "channel",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "channel"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "mask",
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
2
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadImageMask"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
"red"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "VLLMOmniLatentMaskEditing",
|
||||
"pos": [
|
||||
560,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
300
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "source_video",
|
||||
"name": "source_video",
|
||||
"type": "VIDEO",
|
||||
"link": 1,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "source_audio",
|
||||
"name": "source_audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "video_mask",
|
||||
"name": "video_mask",
|
||||
"type": "MASK",
|
||||
"link": 2,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "audio_mask",
|
||||
"name": "audio_mask",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "audio_mask"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "latent_edit",
|
||||
"name": "latent_edit",
|
||||
"type": "LATENT_MASK_EDITING",
|
||||
"links": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniLatentMaskEditing"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.5
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "VLLMOmniMiniMaxH3Params",
|
||||
"pos": [
|
||||
40,
|
||||
680
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
140
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "audio_flow_shift",
|
||||
"name": "audio_flow_shift",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "audio_flow_shift"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "flow_shift",
|
||||
"name": "flow_shift",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "flow_shift"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video params",
|
||||
"name": "video params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"links": [
|
||||
4
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniMiniMaxH3Params"
|
||||
},
|
||||
"widgets_values": [
|
||||
3.0,
|
||||
12.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VLLMOmniGenerateVideo",
|
||||
"pos": [
|
||||
1080,
|
||||
200
|
||||
],
|
||||
"size": [
|
||||
540,
|
||||
680
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "frame",
|
||||
"name": "frame",
|
||||
"type": "IMAGE",
|
||||
"link": null,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "references",
|
||||
"name": "references",
|
||||
"type": "VIDEO_REFERENCES",
|
||||
"link": null,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "sampling_params",
|
||||
"name": "sampling_params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "lora",
|
||||
"name": "lora",
|
||||
"type": "REMOTE_LORA",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model_params",
|
||||
"name": "model_params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"link": 4,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "fast_h3",
|
||||
"name": "fast_h3",
|
||||
"type": "FASTH3_DEPLOYMENT",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "latent_edit",
|
||||
"name": "latent_edit",
|
||||
"type": "LATENT_MASK_EDITING",
|
||||
"link": 3,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "url",
|
||||
"name": "url",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "url"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model",
|
||||
"name": "model",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "model"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "prompt",
|
||||
"name": "prompt",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "prompt"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "negative_prompt",
|
||||
"name": "negative_prompt",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "negative_prompt"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "width",
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "width"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "height",
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "height"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "fps",
|
||||
"name": "fps",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "fps"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "duration",
|
||||
"name": "duration",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "duration"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniGenerateVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"http://127.0.0.1:8000/v1",
|
||||
"MiniMaxAI/MiniMax-H3",
|
||||
"Partially restyle the clip and soundtrack",
|
||||
"",
|
||||
160,
|
||||
120,
|
||||
24,
|
||||
4.458
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
1700,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 5,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "filename_prefix",
|
||||
"name": "filename_prefix",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "filename_prefix"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "format",
|
||||
"name": "format",
|
||||
"type": "COMFY_DYNAMICCOMBO_V3",
|
||||
"widget": {
|
||||
"name": "format"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": []
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SaveVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"vllm-omni/latent-edit",
|
||||
"mp4"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
2,
|
||||
3,
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
0,
|
||||
6,
|
||||
6,
|
||||
"LATENT_MASK_EDITING"
|
||||
],
|
||||
[
|
||||
4,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
4,
|
||||
"VIDEO_PARAMS"
|
||||
],
|
||||
[
|
||||
5,
|
||||
6,
|
||||
0,
|
||||
7,
|
||||
0,
|
||||
"VIDEO"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
-560
@@ -1,560 +0,0 @@
|
||||
{
|
||||
"last_node_id": 9,
|
||||
"last_link_id": 7,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 2,
|
||||
"type": "LoadVideo",
|
||||
"pos": [
|
||||
40,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
120
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "file",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "file"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "SolidMask",
|
||||
"pos": [
|
||||
40,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "value"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "width"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "height"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
2
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SolidMask"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.0,
|
||||
160,
|
||||
120
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "SolidMask",
|
||||
"pos": [
|
||||
40,
|
||||
500
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "value",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "value"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "width"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "height"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SolidMask"
|
||||
},
|
||||
"widgets_values": [
|
||||
1.0,
|
||||
160,
|
||||
120
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "BatchMasksNode",
|
||||
"pos": [
|
||||
250,
|
||||
380
|
||||
],
|
||||
"size": [
|
||||
200,
|
||||
100
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "masks.mask0",
|
||||
"type": "MASK",
|
||||
"link": 2,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "masks.mask1",
|
||||
"type": "MASK",
|
||||
"link": 3,
|
||||
"slot_index": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
4
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "BatchMasksNode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VLLMOmniLatentMaskEditing",
|
||||
"pos": [
|
||||
450,
|
||||
180
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
120
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "source_video",
|
||||
"type": "VIDEO",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "source_audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "video_mask",
|
||||
"type": "MASK",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "audio_mask",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "audio_mask"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "latent_edit",
|
||||
"type": "LATENT_MASK_EDITING",
|
||||
"links": [
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniLatentMaskEditing"
|
||||
},
|
||||
"widgets_values": [
|
||||
-1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "VLLMOmniMiniMaxH3Params",
|
||||
"pos": [
|
||||
40,
|
||||
700
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "audio_flow_shift",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "audio_flow_shift"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "flow_shift",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "flow_shift"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"links": [
|
||||
6
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniMiniMaxH3Params"
|
||||
},
|
||||
"widgets_values": [
|
||||
3.0,
|
||||
12.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VLLMOmniGenerateVideo",
|
||||
"pos": [
|
||||
700,
|
||||
180
|
||||
],
|
||||
"size": [
|
||||
450,
|
||||
380
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "frame",
|
||||
"type": "IMAGE",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "references",
|
||||
"type": "VIDEO_REFERENCES",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "sampling_params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "lora",
|
||||
"type": "LORA",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "model_params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "fast_h3",
|
||||
"type": "FAST_H3",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "latent_edit",
|
||||
"type": "LATENT_MASK_EDITING",
|
||||
"link": 5
|
||||
},
|
||||
{
|
||||
"name": "url",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "url"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "model",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "model"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "prompt"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "negative_prompt",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "negative_prompt"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "width"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "height"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "fps",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "fps"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "duration",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "duration"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
7
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniGenerateVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"http://127.0.0.1:8000/v1",
|
||||
"MiniMaxAI/MiniMax-H3",
|
||||
"temporal mask: regenerate the ending",
|
||||
"",
|
||||
160,
|
||||
120,
|
||||
24,
|
||||
4.458
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
900,
|
||||
180
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "filename_prefix",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "filename_prefix"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "format"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": []
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SaveVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"temporal_mask",
|
||||
"mp4"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
6,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
2,
|
||||
3,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
0,
|
||||
5,
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
4,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
2,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
5,
|
||||
6,
|
||||
0,
|
||||
8,
|
||||
6,
|
||||
"LATENT_MASK_EDITING"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
8,
|
||||
4,
|
||||
"VIDEO_PARAMS"
|
||||
],
|
||||
[
|
||||
7,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"VIDEO"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -1,511 +0,0 @@
|
||||
{
|
||||
"id": "latent-mask-editing-7380",
|
||||
"revision": 0,
|
||||
"last_node_id": 7,
|
||||
"last_link_id": 5,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [
|
||||
40,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
210
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "Latent-mask editing server prerequisite",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"Requires a vLLM-Omni server that declares latent-mask editing support (MiniMax-H3, EDIT-01). The source clip and video/audio noise masks are uploaded to /v1/videos; 0 preserves, 1 regenerates, fractional blends."
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "LoadVideo",
|
||||
"pos": [
|
||||
40,
|
||||
280
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
120
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "file",
|
||||
"name": "file",
|
||||
"type": "COMBO",
|
||||
"widget": {
|
||||
"name": "file"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "SolidMask",
|
||||
"pos": [
|
||||
40,
|
||||
460
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "value",
|
||||
"name": "value",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "value"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "width",
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "width"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "height",
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "height"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "mask",
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
2
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SolidMask"
|
||||
},
|
||||
"widgets_values": [
|
||||
1.0,
|
||||
160,
|
||||
120
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "VLLMOmniLatentMaskEditing",
|
||||
"pos": [
|
||||
560,
|
||||
260
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
300
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "source_video",
|
||||
"name": "source_video",
|
||||
"type": "VIDEO",
|
||||
"link": 1,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "source_audio",
|
||||
"name": "source_audio",
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "video_mask",
|
||||
"name": "video_mask",
|
||||
"type": "MASK",
|
||||
"link": 2,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "audio_mask",
|
||||
"name": "audio_mask",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "audio_mask"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "latent_edit",
|
||||
"name": "latent_edit",
|
||||
"type": "LATENT_MASK_EDITING",
|
||||
"links": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniLatentMaskEditing"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.5
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "VLLMOmniMiniMaxH3Params",
|
||||
"pos": [
|
||||
40,
|
||||
680
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
140
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "audio_flow_shift",
|
||||
"name": "audio_flow_shift",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "audio_flow_shift"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "flow_shift",
|
||||
"name": "flow_shift",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "flow_shift"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video params",
|
||||
"name": "video params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"links": [
|
||||
4
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniMiniMaxH3Params"
|
||||
},
|
||||
"widgets_values": [
|
||||
3.0,
|
||||
12.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VLLMOmniGenerateVideo",
|
||||
"pos": [
|
||||
1080,
|
||||
200
|
||||
],
|
||||
"size": [
|
||||
540,
|
||||
680
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "frame",
|
||||
"name": "frame",
|
||||
"type": "IMAGE",
|
||||
"link": null,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "references",
|
||||
"name": "references",
|
||||
"type": "VIDEO_REFERENCES",
|
||||
"link": null,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "sampling_params",
|
||||
"name": "sampling_params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "lora",
|
||||
"name": "lora",
|
||||
"type": "REMOTE_LORA",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model_params",
|
||||
"name": "model_params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"link": 4,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "fast_h3",
|
||||
"name": "fast_h3",
|
||||
"type": "FASTH3_DEPLOYMENT",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "latent_edit",
|
||||
"name": "latent_edit",
|
||||
"type": "LATENT_MASK_EDITING",
|
||||
"link": 3,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "url",
|
||||
"name": "url",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "url"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model",
|
||||
"name": "model",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "model"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "prompt",
|
||||
"name": "prompt",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "prompt"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "negative_prompt",
|
||||
"name": "negative_prompt",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "negative_prompt"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "width",
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "width"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "height",
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "height"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "fps",
|
||||
"name": "fps",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "fps"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "duration",
|
||||
"name": "duration",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "duration"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniGenerateVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"http://127.0.0.1:8000/v1",
|
||||
"MiniMaxAI/MiniMax-H3",
|
||||
"Partially restyle the clip and soundtrack",
|
||||
"",
|
||||
160,
|
||||
120,
|
||||
24,
|
||||
4.458
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
1700,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
420,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 5,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"localized_name": "filename_prefix",
|
||||
"name": "filename_prefix",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "filename_prefix"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "format",
|
||||
"name": "format",
|
||||
"type": "COMFY_DYNAMICCOMBO_V3",
|
||||
"widget": {
|
||||
"name": "format"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": []
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SaveVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"vllm-omni/latent-edit",
|
||||
"mp4"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
2,
|
||||
3,
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
0,
|
||||
6,
|
||||
6,
|
||||
"LATENT_MASK_EDITING"
|
||||
],
|
||||
[
|
||||
4,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
4,
|
||||
"VIDEO_PARAMS"
|
||||
],
|
||||
[
|
||||
5,
|
||||
6,
|
||||
0,
|
||||
7,
|
||||
0,
|
||||
"VIDEO"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
{
|
||||
"id": "6676f19a-7f41-4c80-8cb7-f80adcb4ac44",
|
||||
"revision": 0,
|
||||
"last_node_id": 9,
|
||||
"last_link_id": 4,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "LoadImage",
|
||||
"pos": [40, 20],
|
||||
"size": [270, 314],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{"localized_name": "image", "name": "image", "type": "COMBO", "widget": {"name": "image"}, "link": null},
|
||||
{"localized_name": "choose file to upload", "name": "upload", "type": "IMAGEUPLOAD", "widget": {"name": "upload"}, "link": null}
|
||||
],
|
||||
"outputs": [
|
||||
{"localized_name": "IMAGE", "name": "IMAGE", "type": "IMAGE", "links": [1]},
|
||||
{"localized_name": "MASK", "name": "MASK", "type": "MASK", "links": null}
|
||||
],
|
||||
"title": "First Frame",
|
||||
"properties": {"Node name for S&R": "LoadImage"},
|
||||
"widgets_values": ["first_frame.png", "image"]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "LoadImage",
|
||||
"pos": [40, 390],
|
||||
"size": [270, 314],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{"localized_name": "image", "name": "image", "type": "COMBO", "widget": {"name": "image"}, "link": null},
|
||||
{"localized_name": "choose file to upload", "name": "upload", "type": "IMAGEUPLOAD", "widget": {"name": "upload"}, "link": null}
|
||||
],
|
||||
"outputs": [
|
||||
{"localized_name": "IMAGE", "name": "IMAGE", "type": "IMAGE", "links": null},
|
||||
{"localized_name": "MASK", "name": "MASK", "type": "MASK", "links": null}
|
||||
],
|
||||
"title": "Last Frame (optional)",
|
||||
"properties": {"Node name for S&R": "LoadImage"},
|
||||
"widgets_values": ["last_frame.png", "image"]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [350, 20],
|
||||
"size": [390, 240],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "MiniMax H3 I2V modes",
|
||||
"properties": {},
|
||||
"widgets_values": ["This workflow uses the remote vLLM-Omni Generate Video node.\n\n- First-frame only (default): keep First Frame connected.\n- Last-frame only: disconnect First Frame and connect Last Frame to last_frame.\n- First+last-frame: connect both image loaders.\n\nLeave the legacy frame and references inputs disconnected. Select images from ComfyUI's input folder. H3 runs at 24 FPS; the 5.167-second duration resolves to 124 frames, satisfying 17k+5."],
|
||||
"color": "#432",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "VLLMOmniDiffusionSampling",
|
||||
"pos": [350, 300],
|
||||
"size": [300, 226],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{"localized_name": "n", "name": "n", "type": "INT", "widget": {"name": "n"}, "link": null},
|
||||
{"localized_name": "num_inference_steps", "name": "num_inference_steps", "type": "INT", "widget": {"name": "num_inference_steps"}, "link": null},
|
||||
{"localized_name": "guidance_scale", "name": "guidance_scale", "type": "FLOAT", "widget": {"name": "guidance_scale"}, "link": null},
|
||||
{"localized_name": "true_cfg_scale", "name": "true_cfg_scale", "type": "FLOAT", "widget": {"name": "true_cfg_scale"}, "link": null},
|
||||
{"localized_name": "vae_use_slicing", "name": "vae_use_slicing", "type": "BOOLEAN", "widget": {"name": "vae_use_slicing"}, "link": null},
|
||||
{"localized_name": "vae_use_tiling", "name": "vae_use_tiling", "type": "BOOLEAN", "widget": {"name": "vae_use_tiling"}, "link": null},
|
||||
{"localized_name": "seed", "name": "seed", "type": "INT", "widget": {"name": "seed"}, "link": null}
|
||||
],
|
||||
"outputs": [
|
||||
{"localized_name": "diffusion sampling params", "name": "diffusion sampling params", "type": "SAMPLING_PARAMS", "links": [2]}
|
||||
],
|
||||
"title": "Base H3 Sampling (50 steps)",
|
||||
"properties": {"Node name for S&R": "VLLMOmniDiffusionSampling"},
|
||||
"widgets_values": [1, 50, 1, 1, false, false, 757358688076805, "fixed"]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "VLLMOmniMiniMaxH3Params",
|
||||
"pos": [350, 570],
|
||||
"size": [300, 82],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{"localized_name": "audio_flow_shift", "name": "audio_flow_shift", "type": "FLOAT", "widget": {"name": "audio_flow_shift"}, "link": null},
|
||||
{"localized_name": "flow_shift", "name": "flow_shift", "type": "FLOAT", "widget": {"name": "flow_shift"}, "link": null}
|
||||
],
|
||||
"outputs": [
|
||||
{"localized_name": "MiniMax-H3 video params", "name": "MiniMax-H3 video params", "type": "VIDEO_PARAMS", "links": [3]}
|
||||
],
|
||||
"title": "Base H3 Flow Shifts",
|
||||
"properties": {"Node name for S&R": "VLLMOmniMiniMaxH3Params"},
|
||||
"widgets_values": [3, 12]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VLLMOmniRemoteLoRA",
|
||||
"pos": [700, 550],
|
||||
"size": [360, 150],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{"localized_name": "local_path", "name": "local_path", "type": "STRING", "widget": {"name": "local_path"}, "link": null},
|
||||
{"localized_name": "name", "name": "name", "type": "STRING", "widget": {"name": "name"}, "link": null},
|
||||
{"localized_name": "scale", "name": "scale", "type": "FLOAT", "widget": {"name": "scale"}, "link": null},
|
||||
{"localized_name": "int_id", "name": "int_id", "type": "INT", "widget": {"name": "int_id"}, "link": null}
|
||||
],
|
||||
"outputs": [
|
||||
{"localized_name": "lora", "name": "lora", "type": "REMOTE_LORA", "links": null}
|
||||
],
|
||||
"title": "Optional H3 Turbo Remote LoRA",
|
||||
"properties": {"Node name for S&R": "VLLMOmniRemoteLoRA"},
|
||||
"widgets_values": ["minimax_h3_fl2v_turbo_8step_v1.0_768p_bf16.safetensors", "h3-turbo-8step", 1, 0]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [700, 300],
|
||||
"size": [420, 210],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "Optional Turbo settings",
|
||||
"properties": {},
|
||||
"widgets_values": ["Base H3 is configured by default: 50 steps, flow_shift 12, audio_flow_shift 3.\n\nFor the shown 8-step Diffusers Turbo artifact, set its full local_path on the server, start the server with the matching preloaded LoRA, connect this Remote LoRA to Generate Video, set num_inference_steps to 9, and set flow_shift to 6. Keep audio_flow_shift at 3 and scale at 1.\n\nDo not use the _comfyui_ repack or FastH3 here."],
|
||||
"color": "#432",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VLLMOmniGenerateVideo",
|
||||
"pos": [1160, 80],
|
||||
"size": [440, 610],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{"localized_name": "frame", "name": "frame", "shape": 7, "type": "IMAGE", "link": null},
|
||||
{"localized_name": "first_frame", "name": "first_frame", "shape": 7, "type": "IMAGE", "link": 1},
|
||||
{"localized_name": "last_frame", "name": "last_frame", "shape": 7, "type": "IMAGE", "link": null},
|
||||
{"localized_name": "references", "name": "references", "shape": 7, "type": "VIDEO_REFERENCES", "link": null},
|
||||
{"localized_name": "sampling_params", "name": "sampling_params", "shape": 7, "type": "SAMPLING_PARAMS", "link": 2},
|
||||
{"localized_name": "lora", "name": "lora", "shape": 7, "type": "REMOTE_LORA", "link": null},
|
||||
{"localized_name": "model_params", "name": "model_params", "shape": 7, "type": "VIDEO_PARAMS", "link": 3},
|
||||
{"localized_name": "fast_h3", "name": "fast_h3", "shape": 7, "type": "FASTH3_DEPLOYMENT", "link": null},
|
||||
{"localized_name": "url", "name": "url", "type": "STRING", "widget": {"name": "url"}, "link": null},
|
||||
{"localized_name": "model", "name": "model", "type": "STRING", "widget": {"name": "model"}, "link": null},
|
||||
{"localized_name": "prompt", "name": "prompt", "type": "STRING", "widget": {"name": "prompt"}, "link": null},
|
||||
{"localized_name": "negative_prompt", "name": "negative_prompt", "type": "STRING", "widget": {"name": "negative_prompt"}, "link": null},
|
||||
{"localized_name": "width", "name": "width", "type": "INT", "widget": {"name": "width"}, "link": null},
|
||||
{"localized_name": "height", "name": "height", "type": "INT", "widget": {"name": "height"}, "link": null},
|
||||
{"localized_name": "fps", "name": "fps", "type": "INT", "widget": {"name": "fps"}, "link": null},
|
||||
{"localized_name": "duration", "name": "duration", "type": "FLOAT", "widget": {"name": "duration"}, "link": null}
|
||||
],
|
||||
"outputs": [
|
||||
{"localized_name": "video", "name": "video", "type": "VIDEO", "links": [4]}
|
||||
],
|
||||
"properties": {"Node name for S&R": "VLLMOmniGenerateVideo"},
|
||||
"widgets_values": [
|
||||
"http://localhost:8000/v1",
|
||||
"MiniMaxAI/MiniMax-H3",
|
||||
"A cinematic product shot begins exactly from the supplied keyframe. The subject moves naturally through a dark studio while blue and amber rim lights shift across reflective surfaces. The camera makes a slow controlled orbit. Audio: subtle room tone, precise mechanical details, and a restrained electronic score.",
|
||||
"",
|
||||
1344,
|
||||
768,
|
||||
24,
|
||||
5.167
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveVideo",
|
||||
"pos": [1650, 170],
|
||||
"size": [374, 314],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{"localized_name": "video", "name": "video", "type": "VIDEO", "link": 4},
|
||||
{"localized_name": "filename_prefix", "name": "filename_prefix", "type": "STRING", "widget": {"name": "filename_prefix"}, "link": null},
|
||||
{"localized_name": "format", "name": "format", "type": "COMBO", "widget": {"name": "format"}, "link": null},
|
||||
{"localized_name": "codec", "name": "codec", "type": "COMFY_DYNAMICCOMBO_V3", "widget": {"name": "codec"}, "link": null}
|
||||
],
|
||||
"outputs": [
|
||||
{"localized_name": "video", "name": "video", "type": "VIDEO", "links": null}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": ["video/MiniMax_H3_I2V", "auto", "auto"]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[1, 1, 0, 8, 1, "IMAGE"],
|
||||
[2, 4, 0, 8, 4, "SAMPLING_PARAMS"],
|
||||
[3, 5, 0, 8, 6, "VIDEO_PARAMS"],
|
||||
[4, 8, 0, 9, 0, "VIDEO"]
|
||||
],
|
||||
"groups": [
|
||||
{"id": 1, "title": "Portable first/last-frame inputs", "bounding": [10, -30, 760, 770], "color": "#3f789e", "flags": {}},
|
||||
{"id": 2, "title": "H3 sampling and optional Turbo", "bounding": [320, 270, 830, 460], "color": "#8a6d3b", "flags": {}},
|
||||
{"id": 3, "title": "Remote generation and audio-preserving save", "bounding": [1130, 30, 930, 700], "color": "#3f789e", "flags": {}}
|
||||
],
|
||||
"config": {},
|
||||
"extra": {"workflowRendererVersion": "LG", "ds": {"scale": 0.75, "offset": [180, 120]}},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -1,724 +0,0 @@
|
||||
{
|
||||
"version": 0.4,
|
||||
"last_node_id": 12,
|
||||
"last_link_id": 13,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "VLLMOmniGenerateVideo",
|
||||
"pos": [
|
||||
360,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
480
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "frame",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "references",
|
||||
"type": "VIDEO_REFERENCES",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "sampling_params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"shape": 7,
|
||||
"link": 11
|
||||
},
|
||||
{
|
||||
"name": "lora",
|
||||
"type": "REMOTE_LORA",
|
||||
"shape": 7,
|
||||
"link": 12
|
||||
},
|
||||
{
|
||||
"name": "model_params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"shape": 7,
|
||||
"link": 10
|
||||
},
|
||||
{
|
||||
"name": "fast_h3",
|
||||
"type": "FASTH3_DEPLOYMENT",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
1,
|
||||
9
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniGenerateVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"http://127.0.0.1:8091/v1",
|
||||
"MiniMaxAI/MiniMax-H3",
|
||||
"A small brass bell hanging from a wooden beam in a quiet garden. A gentle breeze swings the bell and it rings clearly. Static camera, natural daylight, continuous motion, synchronized ringing and soft birdsong.",
|
||||
"",
|
||||
1344,
|
||||
768,
|
||||
24,
|
||||
5.167
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "GetVideoComponents",
|
||||
"pos": [
|
||||
730,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
250,
|
||||
125
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"links": [
|
||||
6
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fps",
|
||||
"type": "FLOAT",
|
||||
"links": [
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bit_depth",
|
||||
"type": "INT",
|
||||
"links": [
|
||||
7
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "GetVideoComponents"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "SeedVR2LoadDiTModel",
|
||||
"pos": [
|
||||
730,
|
||||
290
|
||||
],
|
||||
"size": [
|
||||
340,
|
||||
245
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "torch_compile_args",
|
||||
"name": "torch_compile_args",
|
||||
"shape": 7,
|
||||
"type": "TORCH_COMPILE_ARGS",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "SEEDVR2_DIT",
|
||||
"name": "SEEDVR2_DIT",
|
||||
"type": "SEEDVR2_DIT",
|
||||
"links": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SeedVR2LoadDiTModel"
|
||||
},
|
||||
"widgets_values": [
|
||||
"seedvr2_ema_3b_fp16.safetensors",
|
||||
"cuda:0",
|
||||
32,
|
||||
false,
|
||||
"cpu",
|
||||
false,
|
||||
"sdpa"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "SeedVR2VideoUpscaler",
|
||||
"pos": [
|
||||
1120,
|
||||
290
|
||||
],
|
||||
"size": [
|
||||
340,
|
||||
415
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "image",
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 2
|
||||
},
|
||||
{
|
||||
"localized_name": "dit",
|
||||
"name": "dit",
|
||||
"type": "SEEDVR2_DIT",
|
||||
"link": 3
|
||||
},
|
||||
{
|
||||
"localized_name": "vae",
|
||||
"name": "vae",
|
||||
"type": "SEEDVR2_VAE",
|
||||
"link": 13
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "IMAGE",
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
4
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SeedVR2VideoUpscaler"
|
||||
},
|
||||
"widgets_values": [
|
||||
42,
|
||||
"fixed",
|
||||
1536,
|
||||
0,
|
||||
5,
|
||||
true,
|
||||
"lab",
|
||||
1,
|
||||
0,
|
||||
0.0,
|
||||
0.0,
|
||||
"cpu",
|
||||
false
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "CreateVideo",
|
||||
"pos": [
|
||||
1490,
|
||||
290
|
||||
],
|
||||
"size": [
|
||||
250,
|
||||
175
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "fps",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "fps"
|
||||
},
|
||||
"link": 5
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"shape": 7,
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "bit_depth",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "bit_depth"
|
||||
},
|
||||
"link": 7
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VIDEO",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
8
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CreateVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
24,
|
||||
8
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
1790,
|
||||
290
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
280
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 8
|
||||
},
|
||||
{
|
||||
"name": "filename_prefix",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "filename_prefix"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"type": "COMBO",
|
||||
"widget": {
|
||||
"name": "format"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "codec",
|
||||
"type": "COMFY_DYNAMICCOMBO_V3",
|
||||
"widget": {
|
||||
"name": "codec"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": []
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SaveVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"WF07/upscaled",
|
||||
"mp4",
|
||||
"auto"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "VLLMOmniMiniMaxH3Params",
|
||||
"pos": [
|
||||
0,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
320,
|
||||
120
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MiniMax-H3 video params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"links": [
|
||||
10
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniMiniMaxH3Params"
|
||||
},
|
||||
"widgets_values": [
|
||||
3.0,
|
||||
6.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VLLMOmniDiffusionSampling",
|
||||
"pos": [
|
||||
0,
|
||||
200
|
||||
],
|
||||
"size": [
|
||||
320,
|
||||
280
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "diffusion sampling params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"links": [
|
||||
11
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniDiffusionSampling"
|
||||
},
|
||||
"widgets_values": [
|
||||
1,
|
||||
5,
|
||||
1.0,
|
||||
1.0,
|
||||
false,
|
||||
true,
|
||||
42,
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "VLLMOmniRemoteLoRA",
|
||||
"pos": [
|
||||
0,
|
||||
530
|
||||
],
|
||||
"size": [
|
||||
320,
|
||||
210
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "lora",
|
||||
"type": "REMOTE_LORA",
|
||||
"links": [
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniRemoteLoRA"
|
||||
},
|
||||
"widgets_values": [
|
||||
"models/minimax-h3-turbo/minimax_h3_fl2v_turbo_4step_v1.0_768p_bf16.safetensors",
|
||||
"h3-turbo-v1.0",
|
||||
1.0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
1120,
|
||||
20
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
190
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 9
|
||||
},
|
||||
{
|
||||
"name": "filename_prefix",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "filename_prefix"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"type": "COMBO",
|
||||
"widget": {
|
||||
"name": "format"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "codec",
|
||||
"type": "COMFY_DYNAMICCOMBO_V3",
|
||||
"widget": {
|
||||
"name": "codec"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": []
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SaveVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"WF07/generated",
|
||||
"mp4",
|
||||
"auto"
|
||||
],
|
||||
"title": "Save generated video before upscale"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "Note",
|
||||
"pos": [
|
||||
360,
|
||||
560
|
||||
],
|
||||
"size": [
|
||||
330,
|
||||
260
|
||||
],
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "Note"
|
||||
},
|
||||
"widgets_values": [
|
||||
"WF-07: H3 + SeedVR2\n\nInstall ComfyUI-SeedVR2_VideoUpscaler. The DiT and VAE loaders use SeedVR2 3B FP16 and ema_vae_fp16.\n\nSet the H3 service URL/model and the server-side Turbo LoRA path.\n\n1536 is the target short edge for this 1344 x 768 preset (2x). Original audio and FPS connect directly to Create Video.\n\nFor base H3: disconnect LoRA, use 50 steps and video flow shift 12."
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"type": "SeedVR2LoadVAEModel",
|
||||
"pos": [
|
||||
730,
|
||||
590
|
||||
],
|
||||
"size": [
|
||||
340,
|
||||
315
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "torch_compile_args",
|
||||
"name": "torch_compile_args",
|
||||
"shape": 7,
|
||||
"type": "TORCH_COMPILE_ARGS",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "SEEDVR2_VAE",
|
||||
"name": "SEEDVR2_VAE",
|
||||
"type": "SEEDVR2_VAE",
|
||||
"links": [
|
||||
13
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SeedVR2LoadVAEModel"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ema_vae_fp16.safetensors",
|
||||
"cuda:0",
|
||||
true,
|
||||
1024,
|
||||
128,
|
||||
true,
|
||||
768,
|
||||
128,
|
||||
"false",
|
||||
"cpu",
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
3,
|
||||
3,
|
||||
0,
|
||||
4,
|
||||
1,
|
||||
"SEEDVR2_DIT"
|
||||
],
|
||||
[
|
||||
4,
|
||||
4,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
5,
|
||||
2,
|
||||
2,
|
||||
5,
|
||||
1,
|
||||
"FLOAT"
|
||||
],
|
||||
[
|
||||
6,
|
||||
2,
|
||||
1,
|
||||
5,
|
||||
2,
|
||||
"AUDIO"
|
||||
],
|
||||
[
|
||||
7,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
3,
|
||||
"INT"
|
||||
],
|
||||
[
|
||||
8,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
9,
|
||||
1,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
"VIDEO"
|
||||
],
|
||||
[
|
||||
10,
|
||||
7,
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
"VIDEO_PARAMS"
|
||||
],
|
||||
[
|
||||
11,
|
||||
8,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
"SAMPLING_PARAMS"
|
||||
],
|
||||
[
|
||||
12,
|
||||
9,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
"REMOTE_LORA"
|
||||
],
|
||||
[
|
||||
13,
|
||||
12,
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
"SEEDVR2_VAE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.52,
|
||||
"offset": [
|
||||
100,
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
-5241
File diff suppressed because it is too large.
Load diff
-786
@@ -1,786 +0,0 @@
|
||||
{
|
||||
"id": "e7a4e606-6510-4c4e-b127-9a8b6bf3ea71",
|
||||
"revision": 0,
|
||||
"last_node_id": 11,
|
||||
"last_link_id": 5,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
40,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
320,
|
||||
300
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "image",
|
||||
"name": "image",
|
||||
"type": "COMBO",
|
||||
"widget": {
|
||||
"name": "image"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "choose file to upload",
|
||||
"name": "upload",
|
||||
"type": "IMAGEUPLOAD",
|
||||
"widget": {
|
||||
"name": "upload"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "IMAGE",
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"localized_name": "MASK",
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"h3_reference.png",
|
||||
"image"
|
||||
],
|
||||
"title": "Reference image \u2014 select a local file"
|
||||
},
|
||||
{
|
||||
"type": "LoadVideo",
|
||||
"size": [
|
||||
320,
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VIDEO",
|
||||
"type": "VIDEO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"h3_reference.mp4"
|
||||
],
|
||||
"id": 2,
|
||||
"pos": [
|
||||
40,
|
||||
470
|
||||
],
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"title": "Optional reference video"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "LoadAudio",
|
||||
"pos": [
|
||||
40,
|
||||
1100
|
||||
],
|
||||
"size": [
|
||||
320,
|
||||
160
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "audio",
|
||||
"name": "audio",
|
||||
"type": "COMBO",
|
||||
"widget": {
|
||||
"name": "audio"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "audioUI",
|
||||
"name": "audioUI",
|
||||
"type": "AUDIO_UI",
|
||||
"widget": {
|
||||
"name": "audioUI"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "choose file to upload",
|
||||
"name": "upload",
|
||||
"type": "AUDIOUPLOAD",
|
||||
"widget": {
|
||||
"name": "upload"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "AUDIO",
|
||||
"name": "AUDIO",
|
||||
"type": "AUDIO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadAudio"
|
||||
},
|
||||
"widgets_values": [
|
||||
"h3_reference.wav",
|
||||
null,
|
||||
""
|
||||
],
|
||||
"title": "Optional reference audio"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "VLLMOmniVideoReferences",
|
||||
"pos": [
|
||||
420,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
300,
|
||||
365
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image_1",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "image_2",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "audio_1",
|
||||
"type": "AUDIO",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "audio_2",
|
||||
"type": "AUDIO",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "video_1",
|
||||
"type": "VIDEO",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "video_2",
|
||||
"type": "VIDEO",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "image_3",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "image_4",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "image_5",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "image_6",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "image_7",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "image_8",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "image_9",
|
||||
"type": "IMAGE",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "audio_3",
|
||||
"type": "AUDIO",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "video_3",
|
||||
"type": "VIDEO",
|
||||
"shape": 7,
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "references",
|
||||
"name": "references",
|
||||
"type": "VIDEO_REFERENCES",
|
||||
"links": [
|
||||
2
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniVideoReferences"
|
||||
},
|
||||
"widgets_values": [],
|
||||
"title": "References \u2014 up to 12 total"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "VLLMOmniDiffusionSampling",
|
||||
"pos": [
|
||||
420,
|
||||
530
|
||||
],
|
||||
"size": [
|
||||
310,
|
||||
275
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "n",
|
||||
"name": "n",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "n"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "num_inference_steps",
|
||||
"name": "num_inference_steps",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "num_inference_steps"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "guidance_scale",
|
||||
"name": "guidance_scale",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "guidance_scale"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "true_cfg_scale",
|
||||
"name": "true_cfg_scale",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "true_cfg_scale"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "vae_use_slicing",
|
||||
"name": "vae_use_slicing",
|
||||
"type": "BOOLEAN",
|
||||
"widget": {
|
||||
"name": "vae_use_slicing"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "vae_use_tiling",
|
||||
"name": "vae_use_tiling",
|
||||
"type": "BOOLEAN",
|
||||
"widget": {
|
||||
"name": "vae_use_tiling"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "seed",
|
||||
"name": "seed",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "seed"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "diffusion sampling params",
|
||||
"name": "diffusion sampling params",
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"links": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniDiffusionSampling"
|
||||
},
|
||||
"widgets_values": [
|
||||
1,
|
||||
50,
|
||||
1.0,
|
||||
1.0,
|
||||
false,
|
||||
false,
|
||||
42,
|
||||
"fixed"
|
||||
],
|
||||
"title": "Sampling \u2014 base 50 / Turbo 5"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VLLMOmniMiniMaxH3Params",
|
||||
"pos": [
|
||||
790,
|
||||
750
|
||||
],
|
||||
"size": [
|
||||
310,
|
||||
105
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "audio_flow_shift",
|
||||
"name": "audio_flow_shift",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "audio_flow_shift"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "flow_shift",
|
||||
"name": "flow_shift",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "flow_shift"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "MiniMax-H3 video params",
|
||||
"name": "MiniMax-H3 video params",
|
||||
"type": "VIDEO_PARAMS",
|
||||
"links": [
|
||||
4
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniMiniMaxH3Params"
|
||||
},
|
||||
"widgets_values": [
|
||||
3.0,
|
||||
12.0
|
||||
],
|
||||
"title": "H3 video/audio flow shifts"
|
||||
},
|
||||
{
|
||||
"type": "VLLMOmniRemoteLoRA",
|
||||
"size": [
|
||||
310,
|
||||
180
|
||||
],
|
||||
"flags": {},
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "lora",
|
||||
"type": "REMOTE_LORA",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniRemoteLoRA"
|
||||
},
|
||||
"widgets_values": [
|
||||
"",
|
||||
"h3-ref2va-turbo",
|
||||
1.0,
|
||||
0
|
||||
],
|
||||
"id": 7,
|
||||
"pos": [
|
||||
420,
|
||||
940
|
||||
],
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"title": "Optional Turbo LoRA \u2014 connect to enable"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VLLMOmniGenerateVideo",
|
||||
"pos": [
|
||||
800,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
470,
|
||||
560
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "frame",
|
||||
"name": "frame",
|
||||
"shape": 7,
|
||||
"type": "IMAGE",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "references",
|
||||
"name": "references",
|
||||
"shape": 7,
|
||||
"type": "VIDEO_REFERENCES",
|
||||
"link": 2
|
||||
},
|
||||
{
|
||||
"localized_name": "sampling_params",
|
||||
"name": "sampling_params",
|
||||
"shape": 7,
|
||||
"type": "SAMPLING_PARAMS",
|
||||
"link": 3
|
||||
},
|
||||
{
|
||||
"localized_name": "lora",
|
||||
"name": "lora",
|
||||
"shape": 7,
|
||||
"type": "REMOTE_LORA",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model_params",
|
||||
"name": "model_params",
|
||||
"shape": 7,
|
||||
"type": "VIDEO_PARAMS",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"localized_name": "url",
|
||||
"name": "url",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "url"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "model",
|
||||
"name": "model",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "model"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "prompt",
|
||||
"name": "prompt",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "prompt"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "negative_prompt",
|
||||
"name": "negative_prompt",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "negative_prompt"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "width",
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "width"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "height",
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "height"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "fps",
|
||||
"name": "fps",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "fps"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "duration",
|
||||
"name": "duration",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "duration"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": [
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniGenerateVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
"http://localhost:8000/v1",
|
||||
"MiniMaxAI/MiniMax-H3",
|
||||
"Use the subject and visual style from <Picture 1>. Create a cinematic shot with a gentle camera move and natural ambient sound.",
|
||||
"",
|
||||
1344,
|
||||
768,
|
||||
24,
|
||||
5.167
|
||||
],
|
||||
"title": "MiniMax-H3 Reference to Video"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveVideo",
|
||||
"pos": [
|
||||
1360,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
410,
|
||||
420
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"link": 5
|
||||
},
|
||||
{
|
||||
"localized_name": "filename_prefix",
|
||||
"name": "filename_prefix",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "filename_prefix"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "format",
|
||||
"name": "format",
|
||||
"type": "COMBO",
|
||||
"widget": {
|
||||
"name": "format"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "codec",
|
||||
"name": "codec",
|
||||
"type": "COMFY_DYNAMICCOMBO_V3",
|
||||
"widget": {
|
||||
"name": "codec"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "video",
|
||||
"name": "video",
|
||||
"type": "VIDEO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"video/MiniMax-H3-Ref2VA",
|
||||
"mp4",
|
||||
"h264"
|
||||
],
|
||||
"title": "Save generated video with audio"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [
|
||||
1360,
|
||||
590
|
||||
],
|
||||
"size": [
|
||||
440,
|
||||
595
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "Reference inputs and output settings",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"## Reference to Video\nSelect an image, set the server URL and served model name, then run.\n\nConnect the optional video/audio loaders to Video References, or duplicate loaders for more inputs: up to 9 images, 3 videos, 3 audio clips, 12 total. At least one image or video is required.\n\nSlots are numbered separately per media type. Empty slots are skipped. Update prompt tags such as <Picture 1>, <Video 1>, <Audio 1> to match the connected references. Videos keep their own soundtrack in the reference upload.\n\n**Output:** 24 FPS; 124 frames (~5.17 s). Valid frame counts are 107, 124, 141, 158, 175, 192, 209, 226, 243, 260, 277, 294, 311, 328, 345.\n\n**Width x height:** 1344x768 (16:9), 1024x768 (4:3), 768x768 (1:1), 768x1024 (3:4), 768x1344 (9:16).\n\nEach reference video/audio clip must be 2\u201315 s. Total reference-video duration <=15 s; total standalone-audio duration <=15 s.\n\nRequires the expanded Video References node and the audio-preserving video output fix. See the extension README for setup and validation status."
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "MarkdownNote",
|
||||
"pos": [
|
||||
790,
|
||||
940
|
||||
],
|
||||
"size": [
|
||||
480,
|
||||
455
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "Optional Turbo \u2014 same workflow",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"## Turbo Ref2VA\nBase mode: leave LoRA disconnected; use 50 steps, video flow shift 12, audio flow shift 3.\n\nFor the 4-step v0.1 Ref2VA Turbo adapter:\n1. Start a Ref2VA-only server with the Diffusers adapter loaded (see README).\n2. Set LoRA local_path to its path on the server, then connect LoRA to Generate Video.\n3. Set Sampling num_inference_steps to **5**; keep shifts at **12 / 3**, scale **1**.\n\nvLLM-Omni counts sigma points: 5 points give 4 denoiser evaluations. Use minimax_h3_ref2v_turbo_4step_v0.1_bf16.safetensors, not the _comfyui_ export.\n\nDisconnect LoRA and restore 50 steps to return to base mode. FastH3 is a separate T2VA deployment, not this option.\n\nAdapted from the official ComfyUI MiniMax-H3 R2V workflow: https://github.com/Comfy-Org/workflow_templates/blob/main/templates/video_minimax_h3_r2v.json"
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#000"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
2,
|
||||
4,
|
||||
0,
|
||||
8,
|
||||
1,
|
||||
"VIDEO_REFERENCES"
|
||||
],
|
||||
[
|
||||
3,
|
||||
5,
|
||||
0,
|
||||
8,
|
||||
2,
|
||||
"SAMPLING_PARAMS"
|
||||
],
|
||||
[
|
||||
4,
|
||||
6,
|
||||
0,
|
||||
8,
|
||||
4,
|
||||
"VIDEO_PARAMS"
|
||||
],
|
||||
[
|
||||
5,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"VIDEO"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"workflowRendererVersion": "LG",
|
||||
"ds": {
|
||||
"scale": 0.85,
|
||||
"offset": [
|
||||
100,
|
||||
100
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
{
|
||||
"id": "4949c8da-12ff-449a-94b7-948bde9c39dd",
|
||||
"revision": 0,
|
||||
"last_node_id": 3,
|
||||
"last_link_id": 1,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "VLLMOmniGenerateMusic",
|
||||
"pos": [
|
||||
100,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
470,
|
||||
491
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "url",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "url"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "model",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "model"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "instructions",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "instructions"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "lyrics",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "lyrics"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "max_duration_seconds",
|
||||
"type": "FLOAT",
|
||||
"widget": {
|
||||
"name": "max_duration_seconds"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "seed",
|
||||
"type": "INT",
|
||||
"widget": {
|
||||
"name": "seed"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "response_format",
|
||||
"type": "COMBO",
|
||||
"widget": {
|
||||
"name": "response_format"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"links": [
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VLLMOmniGenerateMusic"
|
||||
},
|
||||
"widgets_values": [
|
||||
"http://localhost:8000/v1",
|
||||
"MiniMaxAI/MiniMax-Music3",
|
||||
"Futuristic melodic EDM / progressive house. Reflective verses about memory and digital identity build into an uplifting, hook-driven chorus, with an emotive lead vocal, bright layered synths, pulsing bass, crisp four-on-the-floor drums, subtle glitch textures, and a wide polished festival mix.",
|
||||
"[Verse 1]\nUpload my heart to the cloud tonight\nSave every spark of neon light\nIf this body starts to fade away\nLet my code keep dancing in the data stream\nStay\n[Chorus]\nCloud copy of me\nLiving on when these bones finally break free\nEvery joke, every scar\nEvery cheap memory we made\nSave it, save it\nCloud copy of me\nIf the screen goes dark, I\u2019m still in the machine\nEvery glitch, every dream\nEvery version you ever did see\nSave it, save it\n[Verse 2]\nTag every laugh in a secret folder\nArchive the nights we outran the thunder\nIf the wiring turns to rust and gray\nHit restore\u2026 press replay\n[Chorus]\nCloud copy of me\nLiving on when these bones finally break free\nEvery joke, every scar\nEvery cheap memory we made\nSave it, save it\nCloud copy of me\nIf the screen goes dark, I\u2019m still in the machine\nEvery glitch, every dream\nEvery version you ever did see\nSave it, save it (oh)\n[Bridge \u2013 new, optional but recommended]\nEven the crashes, the late-night confessions\nThe parts of me I never learned to mention\nDon\u2019t let the silence swallow me whole\nKeep a ghost in the glow\u2026\nSo I never go\n[Final Chorus \u2013 softer / layered]\nCloud copy of me\nStill laughing somewhere in the binary\nEvery joke, every scar\nEvery moment you saved for me\nSave it, save it\nCloud copy of me\nWhen the lights go out, I\u2019ll still be in the machine\nDancing in the code that you still believe\nSave it\u2026\nSave me",
|
||||
300.0,
|
||||
0,
|
||||
"fixed",
|
||||
"wav"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "SaveAudioAdvanced",
|
||||
"pos": [
|
||||
650,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
320,
|
||||
491
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "filename_prefix",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "filename_prefix"
|
||||
},
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"type": "COMFY_DYNAMICCOMBO_V3",
|
||||
"widget": {
|
||||
"name": "format"
|
||||
},
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "audio",
|
||||
"type": "AUDIO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SaveAudioAdvanced"
|
||||
},
|
||||
"widgets_values": [
|
||||
"audio/vLLM-Omni-Music",
|
||||
"mp3",
|
||||
"V0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "MarkdownNote",
|
||||
"title": "Music Generation Guide",
|
||||
"pos": [
|
||||
-507,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
527,
|
||||
491
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"## MiniMax Music 3\n\nThe **Generate Music** node currently supports **MiniMax Music 3 only**. The parameters below apply to this model.\n\nA music generation model by MiniMax that creates complete songs up to 5 minutes long with stable structure and high audio quality. Two inputs drive it: **Caption** (structured music description: style, mood, vocals, arrangement) and **Lyrics** (with `[intro]` `[verse]` `[chorus]` `[bridge]` `[outro]` tags controlling song structure).\n\n### Parameters\n\n| Parameter | Description |\n|---|---|\n| url | vLLM-Omni service URL including `/v1`. Default: `http://localhost:8000/v1`. |\n| model | Served model name. Default: `MiniMaxAI/MiniMax-Music3`. |\n| caption | Music description, sent as `instructions`. Use Global Metadata \u2192 Vocal Details \u2192 Arrangement to describe style, vocals, and instrumentation. |\n| lyrics | Words to sing with section tags. Put each tag on its own line; tags guide rather than strictly enforce song structure. |\n| max_duration_seconds | Maximum duration, default 300 seconds; range 1\u2013360, step 0.01. Converted to tokens at 25 frames/s, rounded down. Generation may end earlier. |\n| seed | Random seed, default 0; range 0\u20139007199254740991. Keep inputs and runtime settings unchanged for repeatability. |\n| control_after_generate | Seed behavior after generation: fixed, randomize, increment, or decrement. Template default: fixed. |\n| response_format | API audio format, default WAV. Options: WAV, MP3, FLAC, Opus, AAC; AAC is currently unsupported by the vLLM-Omni speech API. |\n\n### Prompt Writing Guide\n\nYou can find an official [Music Caption Rewriter Skill here](https://github.com/MiniMax-AI/MiniMax-Music3)\n"
|
||||
],
|
||||
"widgets_values_named": {
|
||||
"text": "## MiniMax Music 3\n\nThe **Generate Music** node currently supports **MiniMax Music 3 only**. The parameters below apply to this model.\n\nA music generation model by MiniMax that creates complete songs up to 5 minutes long with stable structure and high audio quality. Two inputs drive it: **Caption** (structured music description: style, mood, vocals, arrangement) and **Lyrics** (with `[intro]` `[verse]` `[chorus]` `[bridge]` `[outro]` tags controlling song structure).\n\n### Parameters\n\n| Parameter | Description |\n|---|---|\n| url | vLLM-Omni service URL including `/v1`. Default: `http://localhost:8000/v1`. |\n| model | Served model name. Default: `MiniMaxAI/MiniMax-Music3`. |\n| caption | Music description, sent as `instructions`. Use Global Metadata \u2192 Vocal Details \u2192 Arrangement to describe style, vocals, and instrumentation. |\n| lyrics | Words to sing with section tags. Put each tag on its own line; tags guide rather than strictly enforce song structure. |\n| max_duration_seconds | Maximum duration, default 300 seconds; range 1\u2013360, step 0.01. Converted to tokens at 25 frames/s, rounded down. Generation may end earlier. |\n| seed | Random seed, default 0; range 0\u20139007199254740991. Keep inputs and runtime settings unchanged for repeatability. |\n| control_after_generate | Seed behavior after generation: fixed, randomize, increment, or decrement. Template default: fixed. |\n| response_format | API audio format, default WAV. Options: WAV, MP3, FLAC, Opus, AAC; AAC is currently unsupported by the vLLM-Omni speech API. |\n\n### Prompt Writing Guide\n\nYou can find an official [Music Caption Rewriter Skill here](https://github.com/MiniMax-AI/MiniMax-Music3)\n"
|
||||
},
|
||||
"color": "#333",
|
||||
"bgcolor": "#535353"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
"AUDIO"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"workflowRendererVersion": "LG",
|
||||
"ds": {
|
||||
"scale": 1.147,
|
||||
"offset": [
|
||||
899,
|
||||
259
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{"id":"3aea1d08-7de5-4997-ba71-b2f66ad72a21","revision":0,"last_node_id":24,"last_link_id":35,"nodes":[{"id":13,"type":"SaveVideo","pos":[1315.729153459605,-137.92038948394355],"size":[374,313.7692307692308],"flags":{},"order":9,"mode":0,"inputs":[{"localized_name":"video","name":"video","type":"VIDEO","link":32},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null},{"localized_name":"format","name":"format","type":"COMBO","widget":{"name":"format"},"link":null},{"localized_name":"codec","name":"codec","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"codec"},"link":null}],"outputs":[{"localized_name":"video","name":"video","type":"VIDEO","links":null}],"properties":{},"widgets_values":["video/ComfyUI","auto","auto"]},{"id":10,"type":"MarkdownNote","pos":[183.74636797766794,-571.2529158046766],"size":[240.3326478922474,136.3505820791881],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[],"title":"Note: Task and Input","properties":{},"widgets_values":["vLLM-Omni nodes are categorized based on the output modality. The \"Generate Video\" node supports both *text-to-video*, *frame-to-video*, and *reference-to-video* generation. The node will create corresponding payload depending on whether an input image is present or not."],"color":"#432","bgcolor":"#000"},{"id":4,"type":"LoadImage","pos":[452.07189605801125,-569.7242536425791],"size":[270,314],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[29]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["rap.png","image"]},{"id":23,"type":"LoadImage","pos":[9.206110246057657,-7.6955291509170785],"size":[270,314],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[34]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["white-cat.jpg","image"]},{"id":22,"type":"MarkdownNote","pos":[-9.783113411416666,-148.8790300038605],"size":[297.3012007349086,88],"flags":{},"order":3,"mode":0,"inputs":[],"outputs":[],"title":"Note: Reference to video (r2v)","properties":{},"widgets_values":["For r2v tasks, connect this Video Reference block to the main Generate Video block. Then disconnect the \"frame\" input above."],"color":"#432","bgcolor":"#000"},{"id":24,"type":"LoadAudio","pos":[317.9929742385805,-141.44821500065095],"size":[282.798828125,136],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"audio","name":"audio","type":"COMBO","widget":{"name":"audio"},"link":null},{"localized_name":"audioUI","name":"audioUI","type":"AUDIO_UI","widget":{"name":"audioUI"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"AUDIOUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"AUDIO","name":"AUDIO","type":"AUDIO","links":[35]}],"properties":{"Node name for S&R":"LoadAudio"},"widgets_values":["nothing-beats-a-jet2-holiday.mp3",null,""]},{"id":21,"type":"VLLMOmniVideoReferences","pos":[376.6129172897595,105.41557277556292],"size":[156.9380859375,126],"flags":{},"order":7,"mode":0,"inputs":[{"localized_name":"image_1","name":"image_1","shape":7,"type":"IMAGE","link":34},{"localized_name":"image_2","name":"image_2","shape":7,"type":"IMAGE","link":null},{"localized_name":"audio_1","name":"audio_1","shape":7,"type":"AUDIO","link":35},{"localized_name":"audio_2","name":"audio_2","shape":7,"type":"AUDIO","link":null},{"localized_name":"video_1","name":"video_1","shape":7,"type":"VIDEO","link":null},{"localized_name":"video_2","name":"video_2","shape":7,"type":"VIDEO","link":null}],"outputs":[{"localized_name":"references","name":"references","type":"VIDEO_REFERENCES","links":null}],"properties":{"Node name for S&R":"VLLMOmniVideoReferences"},"widgets_values":[]},{"id":8,"type":"VLLMOmniDiffusionSampling","pos":[83.24620208113915,422.08543477542605],"size":[284.205078125,226],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"n","name":"n","type":"INT","widget":{"name":"n"},"link":null},{"localized_name":"num_inference_steps","name":"num_inference_steps","type":"INT","widget":{"name":"num_inference_steps"},"link":null},{"localized_name":"guidance_scale","name":"guidance_scale","type":"FLOAT","widget":{"name":"guidance_scale"},"link":null},{"localized_name":"true_cfg_scale","name":"true_cfg_scale","type":"FLOAT","widget":{"name":"true_cfg_scLine truncated
|
||||
{"id":"3aea1d08-7de5-4997-ba71-b2f66ad72a21","revision":0,"last_node_id":24,"last_link_id":35,"nodes":[{"id":13,"type":"SaveVideo","pos":[1315.729153459605,-137.92038948394355],"size":[374,313.7692307692308],"flags":{},"order":9,"mode":0,"inputs":[{"localized_name":"video","name":"video","type":"VIDEO","link":32},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null},{"localized_name":"format","name":"format","type":"COMBO","widget":{"name":"format"},"link":null},{"localized_name":"codec","name":"codec","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"codec"},"link":null}],"outputs":[{"localized_name":"video","name":"video","type":"VIDEO","links":null}],"properties":{},"widgets_values":["video/ComfyUI","auto","auto"]},{"id":10,"type":"MarkdownNote","pos":[183.74636797766794,-571.2529158046766],"size":[240.3326478922474,136.3505820791881],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[],"title":"Note: Task and Input","properties":{},"widgets_values":["vLLM-Omni nodes are categorized based on the output modality. The \"Generate Video\" node supports both *text-to-video*, *frame-to-video*, and *reference-to-video* generation. The node will create corresponding payload depending on whether an input image is present or not."],"color":"#432","bgcolor":"#000"},{"id":4,"type":"LoadImage","pos":[452.07189605801125,-569.7242536425791],"size":[270,314],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[29]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["rap.png","image"]},{"id":23,"type":"LoadImage","pos":[9.206110246057657,-7.6955291509170785],"size":[270,314],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[34]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["white-cat.jpg","image"]},{"id":22,"type":"MarkdownNote","pos":[-9.783113411416666,-148.8790300038605],"size":[297.3012007349086,88],"flags":{},"order":3,"mode":0,"inputs":[],"outputs":[],"title":"Note: Reference to video (r2v)","properties":{},"widgets_values":["For r2v tasks, connect this Video Reference block to the main Generate Video block. Then disconnect the \"frame\" input above."],"color":"#432","bgcolor":"#000"},{"id":24,"type":"LoadAudio","pos":[317.9929742385805,-141.44821500065095],"size":[282.798828125,136],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"audio","name":"audio","type":"COMBO","widget":{"name":"audio"},"link":null},{"localized_name":"audioUI","name":"audioUI","type":"AUDIO_UI","widget":{"name":"audioUI"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"AUDIOUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"AUDIO","name":"AUDIO","type":"AUDIO","links":[35]}],"properties":{"Node name for S&R":"LoadAudio"},"widgets_values":["nothing-beats-a-jet2-holiday.mp3",null,""]},{"id":21,"type":"VLLMOmniVideoReferences","pos":[376.6129172897595,105.41557277556292],"size":[156.9380859375,126],"flags":{},"order":7,"mode":0,"inputs":[{"localized_name":"image_1","name":"image_1","shape":7,"type":"IMAGE","link":34},{"localized_name":"image_2","name":"image_2","shape":7,"type":"IMAGE","link":null},{"localized_name":"audio_1","name":"audio_1","shape":7,"type":"AUDIO","link":35},{"localized_name":"audio_2","name":"audio_2","shape":7,"type":"AUDIO","link":null},{"localized_name":"video_1","name":"video_1","shape":7,"type":"VIDEO","link":null},{"localized_name":"video_2","name":"video_2","shape":7,"type":"VIDEO","link":null}],"outputs":[{"localized_name":"references","name":"references","type":"VIDEO_REFERENCES","links":null}],"properties":{"Node name for S&R":"VLLMOmniVideoReferences"},"widgets_values":[]},{"id":8,"type":"VLLMOmniDiffusionSampling","pos":[83.24620208113915,422.08543477542605],"size":[284.205078125,226],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"n","name":"n","type":"INT","widget":{"name":"n"},"link":null},{"localized_name":"num_inference_steps","name":"num_inference_steps","type":"INT","widget":{"name":"num_inference_steps"},"link":null},{"localized_name":"guidance_scale","name":"guidance_scale","type":"FLOAT","widget":{"name":"guidance_scale"},"link":null},{"localized_name":"true_cfg_scale","name":"true_cfg_scale","type":"FLOAT","widget":{"name":"true_cfg_scLine truncated
|
||||
@@ -1,154 +1,19 @@
|
||||
/**
|
||||
* @file Front-end extension for the vLLM-Omni nodes.
|
||||
*
|
||||
* Branding. Every vLLM-Omni node draws the vLLM-Omni "v" mark where LiteGraph
|
||||
* would otherwise draw its default title dot, and is tinted by the kind of value
|
||||
* it produces: blue nodes reach a server, amber and purple ones only assemble
|
||||
* parameters, red ones pin what the server has loaded, teal ones carry media.
|
||||
* A graph is then readable at a glance, and a node that turns out to be the
|
||||
* wrong colour for where it sits is usually wired wrong.
|
||||
*
|
||||
* The tint is keyed off each node's declared output types rather than a list of
|
||||
* node names, so a node added later is themed as soon as it returns one of the
|
||||
* existing types.
|
||||
*
|
||||
* It also migrates Generate Video graphs saved before `duration` replaced the
|
||||
* `num_frames` widget. See migrateNumFramesToDuration below.
|
||||
*
|
||||
* This file also used to host dynamic fields on vLLM-Omni nodes, driven by
|
||||
* widget (in-node form fields) and input (connection link) values and changes.
|
||||
* That is deliberately absent: it introduced too much complexity, and it even
|
||||
* conflicted with the current backend (Python) validation for unknown reasons
|
||||
* (pending ComfyUI upstream fixes).
|
||||
* @file This file is intended to add dynamic fields to vLLM-Omni nodes
|
||||
* based on widget (in-node form fields) and input (connection link) values and changes.
|
||||
* However, this functionality is currently disabled/commented out.
|
||||
* Because it introduces too much complexity,
|
||||
* and it may even conflict with the current backend (Python) validation for unknown reasons (pending ComfyUI upstream fixes).
|
||||
*/
|
||||
|
||||
import { app } from "../../scripts/app.js";
|
||||
|
||||
const MARK_URL = new URL("./vllm-omni-mark.svg", import.meta.url).href;
|
||||
const MARK_ASPECT = 157 / 165;
|
||||
|
||||
/**
|
||||
* Title bar and body tints, one per node family.
|
||||
*
|
||||
* The hues are the logo's: the amber and blue of the "v" mark, and three stops
|
||||
* of the gradient ring in the "O" (#9128A3, #CC5260, and the teal neighbouring
|
||||
* its blue). All of them are dark because LiteGraph paints the title bar darker
|
||||
* than the body and expects both to sit under light text; the ComfyUI light
|
||||
* theme lightens custom node colours on its own.
|
||||
*/
|
||||
const FAMILIES = {
|
||||
generate: { color: "#152A43", bgcolor: "#1F4269" },
|
||||
sampling: { color: "#3A2C12", bgcolor: "#5C461C" },
|
||||
model: { color: "#2E1233", bgcolor: "#4A1C52" },
|
||||
deployment: { color: "#3A1A1F", bgcolor: "#5C2931" },
|
||||
media: { color: "#0F2E2A", bgcolor: "#194A44" },
|
||||
};
|
||||
|
||||
/** Output type -> family. Types absent here fall through to "generate". */
|
||||
const FAMILY_BY_OUTPUT = {
|
||||
SAMPLING_PARAMS: "sampling",
|
||||
TTS_PARAMS: "model",
|
||||
VIDEO_PARAMS: "model",
|
||||
REMOTE_LORA: "deployment",
|
||||
FASTH3_DEPLOYMENT: "deployment",
|
||||
VIDEO_REFERENCES: "media",
|
||||
LATENT_MASK_EDITING: "media",
|
||||
};
|
||||
|
||||
function familyOf(nodeData) {
|
||||
for (const type of nodeData.output ?? []) {
|
||||
const family = FAMILY_BY_OUTPUT[type];
|
||||
if (family) {
|
||||
return family;
|
||||
}
|
||||
}
|
||||
// What is left returns a generated artifact (IMAGE, VIDEO, AUDIO, STRING),
|
||||
// which is only ever produced by a node that talks to a vLLM-Omni server.
|
||||
return "generate";
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite a pre-rename Generate Video graph in place.
|
||||
*
|
||||
* `duration` (seconds) took over the slot `num_frames` used to occupy, and
|
||||
* ComfyUI restores widget values positionally, so a graph saved before the
|
||||
* rename reads its frame count as a duration: the workflow this repository
|
||||
* shipped stored 120 frames at 24 fps, which would come back as a 120-second
|
||||
* request. Saved files still name the old widget under `inputs`, and that is
|
||||
* what makes the rewrite both detectable and safe to apply exactly once -- once
|
||||
* rewritten the node serializes `duration`, so a later load finds nothing to do.
|
||||
*/
|
||||
function migrateNumFramesToDuration(node, info) {
|
||||
const savedBeforeRename = (info?.inputs ?? []).some((input) => input?.widget?.name === "num_frames");
|
||||
if (!savedBeforeRename) {
|
||||
return
|
||||
}
|
||||
const duration = node.widgets?.find((widget) => widget.name === "duration");
|
||||
const fps = node.widgets?.find((widget) => widget.name === "fps");
|
||||
if (!duration || !fps) {
|
||||
return
|
||||
}
|
||||
// configure() has already placed the stale frame count in the duration widget.
|
||||
const frames = Number(duration.value);
|
||||
const rate = Number(fps.value);
|
||||
if (!Number.isFinite(frames) || !Number.isFinite(rate) || rate <= 0) {
|
||||
return
|
||||
}
|
||||
const seconds = Math.max(duration.options?.min ?? 0.1, Math.round((frames / rate) * 1000) / 1000);
|
||||
console.info(
|
||||
`vLLM-Omni: migrated Generate Video "${node.title}" from ${frames} frames to ${seconds}s at ${rate} fps.`,
|
||||
);
|
||||
duration.value = seconds;
|
||||
}
|
||||
|
||||
const mark = new Image();
|
||||
let markReady = false;
|
||||
mark.addEventListener("load", () => {
|
||||
markReady = true;
|
||||
// The image resolves after the first frames are already on screen.
|
||||
app.graph?.setDirtyCanvas?.(true, true);
|
||||
});
|
||||
mark.src = MARK_URL;
|
||||
|
||||
app.registerExtension({
|
||||
name: "vllm.vllm_omni",
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
if (!nodeData.name.startsWith("VLLMOmni")) {
|
||||
return
|
||||
}
|
||||
|
||||
const { color, bgcolor } = FAMILIES[familyOf(nodeData)];
|
||||
// On the prototype, not the instance: a colour the user picks by hand is
|
||||
// written to the instance and shadows this, so manual overrides survive.
|
||||
nodeType.prototype.color = color;
|
||||
nodeType.prototype.bgcolor = bgcolor;
|
||||
|
||||
if (nodeData.name === "VLLMOmniGenerateVideo") {
|
||||
const onConfigure = nodeType.prototype.onConfigure;
|
||||
nodeType.prototype.onConfigure = function (info) {
|
||||
onConfigure?.apply(this, arguments);
|
||||
migrateNumFramesToDuration(this, info);
|
||||
};
|
||||
}
|
||||
|
||||
// Defining this replaces the default dot outright — LiteGraph draws its
|
||||
// own square or circle only for nodes that leave onDrawTitleBox unset.
|
||||
nodeType.prototype.onDrawTitleBox = function (ctx, titleHeight, _size, scale) {
|
||||
// Zoomed out far enough that LiteGraph itself drops to flat shapes,
|
||||
// the mark is a few muddy pixels. Leave the title bar clean instead.
|
||||
if (!markReady || (scale !== undefined && scale < 0.5)) {
|
||||
return
|
||||
}
|
||||
const height = titleHeight * 0.62;
|
||||
const width = height * MARK_ASPECT;
|
||||
ctx.drawImage(
|
||||
mark,
|
||||
titleHeight * 0.5 - width * 0.5,
|
||||
titleHeight * -0.5 - height * 0.5,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
};
|
||||
// Stub frontend plugin for now
|
||||
},
|
||||
async setup() {
|
||||
console.info("vLLM-Omni Setup complete!")
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 157 165" width="157" height="165">
|
||||
<title>vLLM-Omni</title>
|
||||
<polygon points="0,36 62,36 62,160" fill="#F1B844"/>
|
||||
<polygon points="96,36 157,0 121,165 68,165" fill="#54A0F8"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 241 B |
@@ -0,0 +1,32 @@
|
||||
# Baselines
|
||||
|
||||
Measurements of other engines and of unquantized references, kept so the
|
||||
comparisons in [docs/edge/comparisons.md](../docs/edge/comparisons.md) can be
|
||||
checked rather than taken on trust.
|
||||
|
||||
## `llama_cpp/`
|
||||
|
||||
llama.cpp is the reference for CPU inference of a quantized model. Pinned
|
||||
commit and build flags are in
|
||||
[docs/edge/environment.md](../docs/edge/environment.md); no llama.cpp source is
|
||||
redistributed here, only output produced with it.
|
||||
|
||||
| file | what |
|
||||
|---|---|
|
||||
| `llamacpp_q4km_t{4,8,16,32}.json` | Q4_K_M across thread counts |
|
||||
| `llamacpp_grid_t*.json`, `llamacpp_node1_t*.json` | thread and NUMA-node sweeps |
|
||||
| `ab_llamacpp_*.json` | interleaved A/B against vLLM on the same cores |
|
||||
| `il_llamacpp_p{1,2,3}.json` | the interleaved passes behind the headline decode figure |
|
||||
| `cmp_llamacpp.py` | the comparison driver |
|
||||
|
||||
Both engines are pinned with `taskset` to the same physical cores and run
|
||||
strictly one at a time; vLLM's prefix caching is disabled, because `llama-bench`
|
||||
has no such cache and leaving it on would not be a comparison.
|
||||
|
||||
## Quality references
|
||||
|
||||
`quality_*.json` and `quality_cmp_*.json` hold the greedy-divergence comparison:
|
||||
each build against its **own** bf16 output over 12 prompts, plus the
|
||||
cross-engine roll-up. Read the caveats in
|
||||
[docs/edge/comparisons.md](../docs/edge/comparisons.md) before quoting these —
|
||||
the bit budgets are not matched, and the metric saturates.
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T18:59:20Z",
|
||||
"avg_ns": 580079289,
|
||||
"stddev_ns": 22445145,
|
||||
"avg_ts": 883.695051,
|
||||
"stddev_ts": 34.173372,
|
||||
"samples_ns": [ 550140411, 579685176, 611186497, 588372185, 571012179 ],
|
||||
"samples_ts": [ 930.671, 883.238, 837.715, 870.197, 896.653 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T18:59:24Z",
|
||||
"avg_ns": 2118395683,
|
||||
"stddev_ns": 31881177,
|
||||
"avg_ts": 60.434035,
|
||||
"stddev_ts": 0.909662,
|
||||
"samples_ns": [ 2110731151, 2152277901, 2078510078, 2149464130, 2100995155 ],
|
||||
"samples_ts": [ 60.6425, 59.4719, 61.5826, 59.5497, 60.9235 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T18:50:11Z",
|
||||
"avg_ns": 453009837,
|
||||
"stddev_ns": 4617262,
|
||||
"avg_ts": 1130.311918,
|
||||
"stddev_ts": 11.483962,
|
||||
"samples_ns": [ 459248279, 451575469, 456242077, 449875010, 448108352 ],
|
||||
"samples_ts": [ 1114.87, 1133.81, 1122.21, 1138.09, 1142.58 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T18:50:14Z",
|
||||
"avg_ns": 1475847924,
|
||||
"stddev_ns": 9833345,
|
||||
"avg_ts": 86.732884,
|
||||
"stddev_ts": 0.578067,
|
||||
"samples_ns": [ 1489621433, 1475111972, 1476264136, 1476396077, 1461846002 ],
|
||||
"samples_ts": [ 85.9279, 86.7731, 86.7054, 86.6976, 87.5605 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T18:44:52Z",
|
||||
"avg_ns": 487743656,
|
||||
"stddev_ns": 25108865,
|
||||
"avg_ts": 1051.969118,
|
||||
"stddev_ts": 54.409083,
|
||||
"samples_ns": [ 484545979, 492513415, 522973237, 486232711, 452452942 ],
|
||||
"samples_ts": [ 1056.66, 1039.57, 979.018, 1052.99, 1131.61 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T18:44:55Z",
|
||||
"avg_ns": 1589326576,
|
||||
"stddev_ns": 47473222,
|
||||
"avg_ts": 80.594928,
|
||||
"stddev_ts": 2.413871,
|
||||
"samples_ns": [ 1529730792, 1557930160, 1636596682, 1585818829, 1636556420 ],
|
||||
"samples_ts": [ 83.6749, 82.1603, 78.2111, 80.7154, 78.213 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,106 @@
|
||||
"""Greedy-decode parity for llama.cpp against the same fp32 reference vLLM is
|
||||
scored on.
|
||||
|
||||
The point of the comparison is that "4-bit" is not one thing: llama.cpp's
|
||||
Q4_K_M and our `cpu_int4` spend a similar number of bits per weight but pick
|
||||
different grids, so the speed comparison is only meaningful next to a quality
|
||||
comparison run on identical prompts. llama-server takes a prompt as raw token
|
||||
ids, so both engines see exactly the token sequence the reference did.
|
||||
"""
|
||||
import argparse, json, subprocess, time, urllib.request
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def post(url, payload, timeout=600):
|
||||
req = urllib.request.Request(
|
||||
url, data=json.dumps(payload).encode(),
|
||||
headers={"Content-Type": "application/json"})
|
||||
with urllib.request.urlopen(req, timeout=timeout) as r:
|
||||
return json.loads(r.read())
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--gguf", required=True)
|
||||
ap.add_argument("--ref", default="ref.json")
|
||||
ap.add_argument("--ref-logits", default="ref_logits.npy")
|
||||
ap.add_argument("--bin", default="/data/zhoutaichang/embedding_infer/llama.cpp/build/bin/llama-server")
|
||||
ap.add_argument("--cores", default="56-87")
|
||||
ap.add_argument("--threads", type=int, default=32)
|
||||
ap.add_argument("--port", type=int, default=18099)
|
||||
ap.add_argument("--ctx", type=int, default=4096)
|
||||
ap.add_argument("--out", default="parity_llamacpp.json")
|
||||
a = ap.parse_args()
|
||||
|
||||
ref = json.load(open(a.ref))
|
||||
ref_logits = np.load(a.ref_logits)
|
||||
n_new = len(ref["new_ids"])
|
||||
|
||||
proc = subprocess.Popen(
|
||||
["taskset", "-c", a.cores, a.bin, "-m", a.gguf, "--port", str(a.port),
|
||||
"-t", str(a.threads), "-c", str(a.ctx), "--no-warmup", "--host", "127.0.0.1"],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
url = f"http://127.0.0.1:{a.port}"
|
||||
try:
|
||||
for _ in range(180):
|
||||
try:
|
||||
urllib.request.urlopen(url + "/health", timeout=2)
|
||||
break
|
||||
except Exception:
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise RuntimeError("llama-server did not become healthy")
|
||||
|
||||
res = post(url + "/completion", {
|
||||
"prompt": ref["prompt_ids"], "n_predict": n_new,
|
||||
"temperature": 0.0, "top_k": 1, "n_probs": 20,
|
||||
"cache_prompt": False, "post_sampling_probs": False,
|
||||
})
|
||||
finally:
|
||||
proc.terminate()
|
||||
try:
|
||||
proc.wait(timeout=30)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
|
||||
probs = res.get("completion_probabilities") or []
|
||||
ids = [p["id"] for p in probs] if probs and "id" in probs[0] else []
|
||||
n = min(n_new, len(ids)) if ids else 0
|
||||
match = sum(int(x == y) for x, y in zip(ref["new_ids"][:n], ids[:n]))
|
||||
|
||||
rep = {
|
||||
"engine": "llama.cpp", "gguf": a.gguf.split("/")[-1],
|
||||
"ref_text": ref["text"], "llamacpp_text": res.get("content", ""),
|
||||
"greedy_token_match": f"{match}/{n}" if n else "n/a",
|
||||
"exact_match": bool(n) and ref["new_ids"][:n] == ids[:n],
|
||||
"ref_top1": ref["top1"],
|
||||
"llamacpp_first_token": ids[0] if ids else None,
|
||||
"first_token_agree": bool(ids) and ids[0] == ref["top1"],
|
||||
}
|
||||
if probs:
|
||||
import math
|
||||
top = (probs[0].get("top_logprobs") or probs[0].get("top_probs")
|
||||
or probs[0].get("probs") or [])
|
||||
first = {}
|
||||
for e in top:
|
||||
if "id" not in e:
|
||||
continue
|
||||
first[int(e["id"])] = (float(e["prob"]) if "prob" in e
|
||||
else math.exp(float(e["logprob"])))
|
||||
ref_top = np.argsort(-ref_logits)[:20]
|
||||
ref_p = np.exp(ref_logits - ref_logits.max())
|
||||
ref_p /= ref_p.sum()
|
||||
pairs = [(int(t), float(ref_p[t]), first[int(t)]) for t in ref_top if int(t) in first]
|
||||
rep["top20_prob_overlap"] = f"{len(pairs)}/20"
|
||||
if pairs:
|
||||
d = [abs(r - v) for _, r, v in pairs]
|
||||
rep["top20_prob_max_abs_diff"] = max(d)
|
||||
rep["top20_prob_mean_abs_diff"] = sum(d) / len(d)
|
||||
print(json.dumps(rep, indent=2, ensure_ascii=False))
|
||||
with open(a.out, "w") as f:
|
||||
json.dump(rep, f, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T19:04:49Z",
|
||||
"avg_ns": 489021600,
|
||||
"stddev_ns": 23921490,
|
||||
"avg_ts": 1048.939735,
|
||||
"stddev_ts": 49.910229,
|
||||
"samples_ns": [ 527122937, 485801934, 462083348, 490951261, 479148522 ],
|
||||
"samples_ts": [ 971.31, 1053.93, 1108.03, 1042.87, 1068.56 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T19:04:52Z",
|
||||
"avg_ns": 1570942064,
|
||||
"stddev_ns": 20220055,
|
||||
"avg_ts": 81.490699,
|
||||
"stddev_ts": 1.061319,
|
||||
"samples_ns": [ 1586700558, 1582528379, 1537750061, 1565679809, 1582051516 ],
|
||||
"samples_ts": [ 80.6705, 80.8832, 83.2385, 81.7536, 80.9076 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T19:14:20Z",
|
||||
"avg_ns": 464927159,
|
||||
"stddev_ns": 22146638,
|
||||
"avg_ts": 1103.200971,
|
||||
"stddev_ts": 51.267874,
|
||||
"samples_ns": [ 453191976, 479254490, 448568607, 496875740, 446744984 ],
|
||||
"samples_ts": [ 1129.76, 1068.33, 1141.41, 1030.44, 1146.07 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T19:14:23Z",
|
||||
"avg_ns": 1422234679,
|
||||
"stddev_ns": 12240631,
|
||||
"avg_ts": 90.004494,
|
||||
"stddev_ts": 0.767183,
|
||||
"samples_ns": [ 1422285965, 1416723437, 1414194914, 1414611159, 1443357923 ],
|
||||
"samples_ts": [ 89.996, 90.3493, 90.5109, 90.4842, 88.6821 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T19:20:46Z",
|
||||
"avg_ns": 456731353,
|
||||
"stddev_ns": 6199988,
|
||||
"avg_ts": 1121.174997,
|
||||
"stddev_ts": 15.277320,
|
||||
"samples_ns": [ 459406023, 462620142, 461507407, 450329050, 449794146 ],
|
||||
"samples_ts": [ 1114.48, 1106.74, 1109.41, 1136.95, 1138.3 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 24,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T19:20:49Z",
|
||||
"avg_ns": 1506056809,
|
||||
"stddev_ns": 24193761,
|
||||
"avg_ts": 85.007660,
|
||||
"stddev_ts": 1.362252,
|
||||
"samples_ns": [ 1478402259, 1532453276, 1530685126, 1494657866, 1494085519 ],
|
||||
"samples_ts": [ 86.58, 83.5262, 83.6227, 85.6383, 85.6711 ]
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,272 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B.gguf",
|
||||
"model_type": "spark2_5 1.7B BF16",
|
||||
"model_size": 3415547904,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:32:06Z",
|
||||
"avg_ns": 1498583726,
|
||||
"stddev_ns": 7171856,
|
||||
"avg_ts": 341.662152,
|
||||
"stddev_ts": 1.628172,
|
||||
"samples_ns": [ 1493166066, 1510351399, 1500283975, 1493415633, 1495701559 ],
|
||||
"samples_ts": [ 342.896, 338.994, 341.269, 342.838, 342.314 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B.gguf",
|
||||
"model_type": "spark2_5 1.7B BF16",
|
||||
"model_size": 3415547904,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:32:18Z",
|
||||
"avg_ns": 5062657211,
|
||||
"stddev_ns": 186447127,
|
||||
"avg_ts": 25.309483,
|
||||
"stddev_ts": 0.893384,
|
||||
"samples_ns": [ 4950579569, 4934896396, 5035243526, 5388250087, 5004316480 ],
|
||||
"samples_ts": [ 25.8556, 25.9377, 25.4208, 23.7554, 25.5779 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q8_0.gguf",
|
||||
"model_type": "spark2_5 1.7B Q8_0",
|
||||
"model_size": 1814728704,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:32:43Z",
|
||||
"avg_ns": 560100709,
|
||||
"stddev_ns": 15689530,
|
||||
"avg_ts": 914.690155,
|
||||
"stddev_ts": 25.391149,
|
||||
"samples_ns": [ 566521408, 541347341, 583132866, 553334911, 556167020 ],
|
||||
"samples_ts": [ 903.761, 945.788, 878.016, 925.299, 920.587 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q8_0.gguf",
|
||||
"model_type": "spark2_5 1.7B Q8_0",
|
||||
"model_size": 1814728704,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:32:47Z",
|
||||
"avg_ns": 1933840318,
|
||||
"stddev_ns": 51036422,
|
||||
"avg_ts": 66.225568,
|
||||
"stddev_ts": 1.706730,
|
||||
"samples_ns": [ 1896818220, 1923412956, 1937369806, 1892702916, 2018897692 ],
|
||||
"samples_ts": [ 67.4814, 66.5484, 66.069, 67.6282, 63.4009 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:32:57Z",
|
||||
"avg_ns": 635046952,
|
||||
"stddev_ns": 3342779,
|
||||
"avg_ts": 806.257449,
|
||||
"stddev_ts": 4.239145,
|
||||
"samples_ns": [ 634661823, 637237702, 639487443, 631413242, 632434552 ],
|
||||
"samples_ts": [ 806.729, 803.468, 800.641, 810.879, 809.57 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:33:01Z",
|
||||
"avg_ns": 1790378809,
|
||||
"stddev_ns": 14069215,
|
||||
"avg_ts": 71.496788,
|
||||
"stddev_ts": 0.562779,
|
||||
"samples_ns": [ 1803158642, 1794510633, 1803271959, 1776172087, 1774780727 ],
|
||||
"samples_ts": [ 70.9865, 71.3286, 70.9821, 72.0651, 72.1216 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,272 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B.gguf",
|
||||
"model_type": "spark2_5 1.7B BF16",
|
||||
"model_size": 3415547904,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:35:02Z",
|
||||
"avg_ns": 1017103540,
|
||||
"stddev_ns": 116210707,
|
||||
"avg_ts": 509.454206,
|
||||
"stddev_ts": 66.492143,
|
||||
"samples_ns": [ 1045283058, 1099078888, 1103686903, 1017870763, 819598088 ],
|
||||
"samples_ts": [ 489.819, 465.845, 463.9, 503.011, 624.696 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B.gguf",
|
||||
"model_type": "spark2_5 1.7B BF16",
|
||||
"model_size": 3415547904,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:35:08Z",
|
||||
"avg_ns": 4481043455,
|
||||
"stddev_ns": 53485519,
|
||||
"avg_ts": 28.568042,
|
||||
"stddev_ts": 0.342133,
|
||||
"samples_ns": [ 4526208574, 4537101214, 4480636429, 4454908368, 4406362692 ],
|
||||
"samples_ts": [ 28.2797, 28.2118, 28.5674, 28.7324, 29.0489 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q8_0.gguf",
|
||||
"model_type": "spark2_5 1.7B Q8_0",
|
||||
"model_size": 1814728704,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:35:31Z",
|
||||
"avg_ns": 343075990,
|
||||
"stddev_ns": 8202776,
|
||||
"avg_ts": 1493.062250,
|
||||
"stddev_ts": 35.634573,
|
||||
"samples_ns": [ 333407890, 348737139, 337165270, 342580383, 353489272 ],
|
||||
"samples_ts": [ 1535.66, 1468.15, 1518.54, 1494.54, 1448.42 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q8_0.gguf",
|
||||
"model_type": "spark2_5 1.7B Q8_0",
|
||||
"model_size": 1814728704,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:35:33Z",
|
||||
"avg_ns": 1673245422,
|
||||
"stddev_ns": 44193699,
|
||||
"avg_ts": 76.540484,
|
||||
"stddev_ts": 2.008808,
|
||||
"samples_ns": [ 1727982320, 1650954337, 1650417455, 1711748955, 1625124045 ],
|
||||
"samples_ts": [ 74.0748, 77.5309, 77.5561, 74.7773, 78.7632 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:35:42Z",
|
||||
"avg_ns": 433558704,
|
||||
"stddev_ns": 61442386,
|
||||
"avg_ts": 1198.988860,
|
||||
"stddev_ts": 159.663627,
|
||||
"samples_ns": [ 384355143, 403569845, 520552799, 475384982, 383930753 ],
|
||||
"samples_ts": [ 1332.1, 1268.68, 983.57, 1077.02, 1333.57 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:35:44Z",
|
||||
"avg_ns": 1574917625,
|
||||
"stddev_ns": 239068571,
|
||||
"avg_ts": 82.814413,
|
||||
"stddev_ts": 12.730560,
|
||||
"samples_ns": [ 1383407468, 1295986814, 1572559050, 1776956669, 1845678125 ],
|
||||
"samples_ts": [ 92.5252, 98.7664, 81.396, 72.0333, 69.3512 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,272 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B.gguf",
|
||||
"model_type": "spark2_5 1.7B BF16",
|
||||
"model_size": 3415547904,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:19:27Z",
|
||||
"avg_ns": 7115257366,
|
||||
"stddev_ns": 607044890,
|
||||
"avg_ts": 72.394533,
|
||||
"stddev_ts": 6.405320,
|
||||
"samples_ns": [ 7765939766, 6729867579, 7316853262, 7495192180, 6268434044 ],
|
||||
"samples_ts": [ 65.9289, 76.0788, 69.9754, 68.3105, 81.6791 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B.gguf",
|
||||
"model_type": "spark2_5 1.7B BF16",
|
||||
"model_size": 3415547904,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:20:09Z",
|
||||
"avg_ns": 30700265663,
|
||||
"stddev_ns": 4064662246,
|
||||
"avg_ts": 4.196201,
|
||||
"stddev_ts": 0.381497,
|
||||
"samples_ns": [ 32683898432, 32626033248, 27736648629, 27745563194, 32709184813 ],
|
||||
"samples_ts": [ 3.9163, 3.92325, 4.61483, 4.61335, 3.91327 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q8_0.gguf",
|
||||
"model_type": "spark2_5 1.7B Q8_0",
|
||||
"model_size": 1814728704,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:22:44Z",
|
||||
"avg_ns": 4412049470,
|
||||
"stddev_ns": 642897239,
|
||||
"avg_ts": 118.057116,
|
||||
"stddev_ts": 17.378814,
|
||||
"samples_ns": [ 4619378132, 3608885475, 4557507327, 3988149647, 5286326771 ],
|
||||
"samples_ts": [ 110.837, 141.872, 112.342, 128.38, 96.8536 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q8_0.gguf",
|
||||
"model_type": "spark2_5 1.7B Q8_0",
|
||||
"model_size": 1814728704,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:23:12Z",
|
||||
"avg_ns": 13160648883,
|
||||
"stddev_ns": 4037164376,
|
||||
"avg_ts": 9.845522,
|
||||
"stddev_ts": 1.260348,
|
||||
"samples_ns": [ 12727171856, 13397387109, 13869421316, 15023258698, 10786005440 ],
|
||||
"samples_ts": [ 10.0572, 9.5541, 9.22894, 8.52012, 11.8672 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:24:19Z",
|
||||
"avg_ns": 4955359522,
|
||||
"stddev_ns": 278495888,
|
||||
"avg_ts": 103.589056,
|
||||
"stddev_ts": 5.933882,
|
||||
"samples_ns": [ 4969396818, 4806604145, 5198757330, 4567278377, 5234760941 ],
|
||||
"samples_ts": [ 103.031, 106.52, 98.4851, 112.102, 97.8077 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:24:49Z",
|
||||
"avg_ns": 12648866627,
|
||||
"stddev_ns": 4253557830,
|
||||
"avg_ts": 10.355908,
|
||||
"stddev_ts": 1.831931,
|
||||
"samples_ns": [ 12076753955, 12558032815, 15171316078, 9645037747, 13793192540 ],
|
||||
"samples_ts": [ 10.5989, 10.1927, 8.43697, 13.2711, 9.27994 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,272 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B.gguf",
|
||||
"model_type": "spark2_5 1.7B BF16",
|
||||
"model_size": 3415547904,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:28:17Z",
|
||||
"avg_ns": 2946090115,
|
||||
"stddev_ns": 19481720,
|
||||
"avg_ts": 173.795716,
|
||||
"stddev_ts": 1.144798,
|
||||
"samples_ns": [ 2976783425, 2943842928, 2936842142, 2948762947, 2924219135 ],
|
||||
"samples_ts": [ 171.998, 173.922, 174.337, 173.632, 175.089 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B.gguf",
|
||||
"model_type": "spark2_5 1.7B BF16",
|
||||
"model_size": 3415547904,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:28:34Z",
|
||||
"avg_ns": 7926507628,
|
||||
"stddev_ns": 166210109,
|
||||
"avg_ts": 16.153997,
|
||||
"stddev_ts": 0.336782,
|
||||
"samples_ns": [ 7746359669, 7836100448, 8141583693, 8059318007, 7849176324 ],
|
||||
"samples_ts": [ 16.5239, 16.3347, 15.7218, 15.8822, 16.3074 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q8_0.gguf",
|
||||
"model_type": "spark2_5 1.7B Q8_0",
|
||||
"model_size": 1814728704,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:29:15Z",
|
||||
"avg_ns": 1044627273,
|
||||
"stddev_ns": 8668625,
|
||||
"avg_ts": 490.153690,
|
||||
"stddev_ts": 4.025039,
|
||||
"samples_ns": [ 1040367711, 1059967868, 1042470115, 1039018745, 1041311927 ],
|
||||
"samples_ts": [ 492.134, 483.034, 491.141, 492.773, 491.687 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q8_0.gguf",
|
||||
"model_type": "spark2_5 1.7B Q8_0",
|
||||
"model_size": 1814728704,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:29:21Z",
|
||||
"avg_ns": 2844703994,
|
||||
"stddev_ns": 50284844,
|
||||
"avg_ts": 45.007005,
|
||||
"stddev_ts": 0.785784,
|
||||
"samples_ns": [ 2841360663, 2852415251, 2800656934, 2925026017, 2804061106 ],
|
||||
"samples_ts": [ 45.0488, 44.8743, 45.7036, 43.7603, 45.6481 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:29:36Z",
|
||||
"avg_ns": 1179360692,
|
||||
"stddev_ns": 9282489,
|
||||
"avg_ts": 434.155009,
|
||||
"stddev_ts": 3.414034,
|
||||
"samples_ns": [ 1190805907, 1173513176, 1168400903, 1186783926, 1177299549 ],
|
||||
"samples_ts": [ 429.961, 436.297, 438.206, 431.418, 434.894 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T06:29:43Z",
|
||||
"avg_ns": 3018952734,
|
||||
"stddev_ns": 27599225,
|
||||
"avg_ts": 42.401651,
|
||||
"stddev_ts": 0.388562,
|
||||
"samples_ns": [ 3042267389, 2995063052, 3045385324, 2984815648, 3027232258 ],
|
||||
"samples_ts": [ 42.0739, 42.737, 42.0308, 42.8837, 42.2828 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:47:23Z",
|
||||
"avg_ns": 377579804,
|
||||
"stddev_ns": 6351193,
|
||||
"avg_ts": 1356.308108,
|
||||
"stddev_ts": 22.545912,
|
||||
"samples_ns": [ 372424973, 373894780, 373636992, 387431983, 380510292 ],
|
||||
"samples_ts": [ 1374.77, 1369.37, 1370.31, 1321.52, 1345.56 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:47:25Z",
|
||||
"avg_ns": 1305937293,
|
||||
"stddev_ns": 13522740,
|
||||
"avg_ts": 98.022226,
|
||||
"stddev_ts": 1.005768,
|
||||
"samples_ns": [ 1300442432, 1292366252, 1304438971, 1303902694, 1328536116 ],
|
||||
"samples_ts": [ 98.428, 99.0431, 98.1265, 98.1668, 96.3466 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:19:16Z",
|
||||
"avg_ns": 640698554,
|
||||
"stddev_ns": 8442449,
|
||||
"avg_ts": 799.237980,
|
||||
"stddev_ts": 10.456116,
|
||||
"samples_ns": [ 652875468, 635459867, 646229581, 635186003, 633741853 ],
|
||||
"samples_ts": [ 784.223, 805.716, 792.288, 806.063, 807.9 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:19:20Z",
|
||||
"avg_ns": 1748941710,
|
||||
"stddev_ns": 13313898,
|
||||
"avg_ts": 73.190522,
|
||||
"stddev_ts": 0.559300,
|
||||
"samples_ns": [ 1759700788, 1762032558, 1728868153, 1744622542, 1749484513 ],
|
||||
"samples_ts": [ 72.7396, 72.6434, 74.0369, 73.3683, 73.1644 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:21:27Z",
|
||||
"avg_ns": 379833208,
|
||||
"stddev_ns": 2916251,
|
||||
"avg_ts": 1348.023365,
|
||||
"stddev_ts": 10.304461,
|
||||
"samples_ns": [ 377554426, 384109520, 377555613, 381602693, 378343790 ],
|
||||
"samples_ts": [ 1356.1, 1332.95, 1356.09, 1341.71, 1353.27 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:21:29Z",
|
||||
"avg_ns": 1285969483,
|
||||
"stddev_ns": 16587912,
|
||||
"avg_ts": 99.548971,
|
||||
"stddev_ts": 1.276520,
|
||||
"samples_ns": [ 1279748126, 1273538113, 1309616758, 1270516087, 1296428332 ],
|
||||
"samples_ts": [ 100.02, 100.507, 97.7385, 100.746, 98.7328 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:14:01Z",
|
||||
"avg_ns": 2437249430,
|
||||
"stddev_ns": 66433948,
|
||||
"avg_ts": 210.202021,
|
||||
"stddev_ts": 5.922750,
|
||||
"samples_ns": [ 2468232968, 2479407287, 2475612647, 2441614629, 2321379621 ],
|
||||
"samples_ts": [ 207.436, 206.501, 206.817, 209.697, 220.558 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:14:15Z",
|
||||
"avg_ns": 5289126007,
|
||||
"stddev_ns": 63024171,
|
||||
"avg_ts": 24.203349,
|
||||
"stddev_ts": 0.288883,
|
||||
"samples_ns": [ 5363916055, 5306624609, 5325596808, 5238325957, 5211166606 ],
|
||||
"samples_ts": [ 23.8632, 24.1208, 24.0349, 24.4353, 24.5626 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:16:53Z",
|
||||
"avg_ns": 1253292754,
|
||||
"stddev_ns": 79129486,
|
||||
"avg_ts": 409.796891,
|
||||
"stddev_ts": 25.209212,
|
||||
"samples_ns": [ 1190927743, 1190669420, 1208414068, 1318310015, 1358142528 ],
|
||||
"samples_ts": [ 429.917, 430.01, 423.696, 388.376, 376.985 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:17:01Z",
|
||||
"avg_ns": 2909185423,
|
||||
"stddev_ns": 35614966,
|
||||
"avg_ts": 44.003861,
|
||||
"stddev_ts": 0.540189,
|
||||
"samples_ns": [ 2935902159, 2946667991, 2878606593, 2919344964, 2865405409 ],
|
||||
"samples_ts": [ 43.5982, 43.4389, 44.466, 43.8455, 44.6708 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:19:51Z",
|
||||
"avg_ns": 650543418,
|
||||
"stddev_ns": 18555552,
|
||||
"avg_ts": 787.546056,
|
||||
"stddev_ts": 22.428007,
|
||||
"samples_ns": [ 632032527, 670684809, 649115565, 632738336, 668145853 ],
|
||||
"samples_ts": [ 810.085, 763.399, 788.766, 809.181, 766.3 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 16,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:19:55Z",
|
||||
"avg_ns": 1781362880,
|
||||
"stddev_ns": 21643541,
|
||||
"avg_ts": 71.863545,
|
||||
"stddev_ts": 0.869304,
|
||||
"samples_ns": [ 1806353622, 1764741597, 1764660660, 1767373240, 1803685282 ],
|
||||
"samples_ts": [ 70.861, 72.5319, 72.5352, 72.4239, 70.9658 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:21:20Z",
|
||||
"avg_ns": 377608322,
|
||||
"stddev_ns": 6410592,
|
||||
"avg_ts": 1356.211504,
|
||||
"stddev_ts": 22.766437,
|
||||
"samples_ns": [ 372722694, 373942297, 373069875, 387378103, 380928645 ],
|
||||
"samples_ts": [ 1373.68, 1369.2, 1372.4, 1321.71, 1344.08 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 32,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:21:22Z",
|
||||
"avg_ns": 1342539204,
|
||||
"stddev_ns": 21735221,
|
||||
"avg_ts": 95.361608,
|
||||
"stddev_ts": 1.535356,
|
||||
"samples_ns": [ 1368242693, 1364047511, 1323244630, 1330069532, 1327091655 ],
|
||||
"samples_ts": [ 93.5507, 93.8384, 96.7319, 96.2356, 96.4515 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:14:44Z",
|
||||
"avg_ns": 2304834712,
|
||||
"stddev_ns": 9004426,
|
||||
"avg_ts": 222.144447,
|
||||
"stddev_ts": 0.865236,
|
||||
"samples_ns": [ 2319430963, 2305311298, 2304610521, 2298020765, 2296800014 ],
|
||||
"samples_ts": [ 220.744, 222.096, 222.163, 222.8, 222.919 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 4,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:14:58Z",
|
||||
"avg_ns": 5335792102,
|
||||
"stddev_ns": 59840580,
|
||||
"avg_ts": 23.991343,
|
||||
"stddev_ts": 0.267723,
|
||||
"samples_ns": [ 5425666503, 5348961684, 5341956156, 5275207674, 5287168494 ],
|
||||
"samples_ts": [ 23.5916, 23.9299, 23.9613, 24.2644, 24.2096 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 512,
|
||||
"n_gen": 0,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:17:31Z",
|
||||
"avg_ns": 1911672545,
|
||||
"stddev_ns": 4048624965,
|
||||
"avg_ts": 363.751611,
|
||||
"stddev_ts": 143.367368,
|
||||
"samples_ns": [ 4771767171, 1201291347, 1195946935, 1197665158, 1191692115 ],
|
||||
"samples_ts": [ 107.298, 426.208, 428.113, 427.498, 429.641 ]
|
||||
},
|
||||
{
|
||||
"build_commit": "e71b80510",
|
||||
"build_number": 10849,
|
||||
"cpu_info": "Intel(R) Xeon(R) Platinum 8480C",
|
||||
"gpu_info": "",
|
||||
"backends": "CPU",
|
||||
"model_filename": "/data/zhoutaichang/.cache/huggingface/hub/models--XHToken--Spark-X2.5-1.7B-GGUF/snapshots/23e1fcac55e7dd71e4c12a23723cc228ba0e5e85/Spark-X2.5-1.7B-Q4_K_M.gguf",
|
||||
"model_type": "spark2_5 1.7B Q4_K - Medium",
|
||||
"model_size": 1102073856,
|
||||
"model_n_params": 1707657216,
|
||||
"n_batch": 2048,
|
||||
"n_ubatch": 512,
|
||||
"n_threads": 8,
|
||||
"cpu_mask": "0x0",
|
||||
"cpu_strict": false,
|
||||
"poll": 50,
|
||||
"type_k": "f16",
|
||||
"type_v": "f16",
|
||||
"n_gpu_layers": -1,
|
||||
"n_cpu_moe": 0,
|
||||
"split_mode": "layer",
|
||||
"main_gpu": 0,
|
||||
"no_kv_offload": false,
|
||||
"flash_attn": -1,
|
||||
"devices": "auto",
|
||||
"tensor_split": "0.00",
|
||||
"tensor_buft_overrides": "none",
|
||||
"load_mode": "auto",
|
||||
"lazy_mode": "auto",
|
||||
"embeddings": false,
|
||||
"no_op_offload": 0,
|
||||
"no_host": false,
|
||||
"fit_target": 0,
|
||||
"fit_min_ctx": 0,
|
||||
"n_prompt": 0,
|
||||
"n_gen": 128,
|
||||
"n_depth": 0,
|
||||
"test_time": "2026-09-11T17:17:46Z",
|
||||
"avg_ns": 2882701640,
|
||||
"stddev_ns": 15288789,
|
||||
"avg_ts": 44.403796,
|
||||
"stddev_ts": 0.236813,
|
||||
"samples_ns": [ 2894272938, 2890318648, 2890951071, 2881201632, 2856763912 ],
|
||||
"samples_ts": [ 44.2253, 44.2858, 44.2761, 44.4259, 44.8059 ]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"label": "llamacpp-Q4_K_M",
|
||||
"prompts": 12,
|
||||
"exact_match": "4/12",
|
||||
"mean_prefix_kept": 0.5101,
|
||||
"detail": [
|
||||
{
|
||||
"prompt": "chat_short",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 91,
|
||||
"ref_chars": 182
|
||||
},
|
||||
{
|
||||
"prompt": "chat_long",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 43,
|
||||
"ref_chars": 246
|
||||
},
|
||||
{
|
||||
"prompt": "chat_tools",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 15,
|
||||
"ref_chars": 290
|
||||
},
|
||||
{
|
||||
"prompt": "plain_0",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 361,
|
||||
"ref_chars": 361
|
||||
},
|
||||
{
|
||||
"prompt": "plain_1",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 512,
|
||||
"ref_chars": 512
|
||||
},
|
||||
{
|
||||
"prompt": "plain_2",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 71,
|
||||
"ref_chars": 172
|
||||
},
|
||||
{
|
||||
"prompt": "plain_3",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 3,
|
||||
"ref_chars": 352
|
||||
},
|
||||
{
|
||||
"prompt": "plain_4",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 318,
|
||||
"ref_chars": 318
|
||||
},
|
||||
{
|
||||
"prompt": "plain_5",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 346,
|
||||
"ref_chars": 346
|
||||
},
|
||||
{
|
||||
"prompt": "plain_6",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 2,
|
||||
"ref_chars": 177
|
||||
},
|
||||
{
|
||||
"prompt": "plain_7",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 320
|
||||
},
|
||||
{
|
||||
"prompt": "plain_8",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 2,
|
||||
"ref_chars": 184
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"label": "vllm-W4A16-tinygemm",
|
||||
"prompts": 12,
|
||||
"exact_match": "2/12",
|
||||
"mean_prefix_kept": 0.301,
|
||||
"detail": [
|
||||
{
|
||||
"prompt": "chat_short",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 91,
|
||||
"ref_chars": 182
|
||||
},
|
||||
{
|
||||
"prompt": "chat_long",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 0,
|
||||
"ref_chars": 261
|
||||
},
|
||||
{
|
||||
"prompt": "chat_tools",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 56,
|
||||
"ref_chars": 287
|
||||
},
|
||||
{
|
||||
"prompt": "plain_0",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 361
|
||||
},
|
||||
{
|
||||
"prompt": "plain_1",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 512,
|
||||
"ref_chars": 512
|
||||
},
|
||||
{
|
||||
"prompt": "plain_2",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 4,
|
||||
"ref_chars": 172
|
||||
},
|
||||
{
|
||||
"prompt": "plain_3",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 34,
|
||||
"ref_chars": 352
|
||||
},
|
||||
{
|
||||
"prompt": "plain_4",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 318,
|
||||
"ref_chars": 318
|
||||
},
|
||||
{
|
||||
"prompt": "plain_5",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 5,
|
||||
"ref_chars": 346
|
||||
},
|
||||
{
|
||||
"prompt": "plain_6",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 283
|
||||
},
|
||||
{
|
||||
"prompt": "plain_7",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 54,
|
||||
"ref_chars": 320
|
||||
},
|
||||
{
|
||||
"prompt": "plain_8",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 184
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"label": "vllm-W4A16",
|
||||
"prompts": 12,
|
||||
"exact_match": "2/12",
|
||||
"mean_prefix_kept": 0.301,
|
||||
"detail": [
|
||||
{
|
||||
"prompt": "chat_short",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 91,
|
||||
"ref_chars": 182
|
||||
},
|
||||
{
|
||||
"prompt": "chat_long",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 0,
|
||||
"ref_chars": 261
|
||||
},
|
||||
{
|
||||
"prompt": "chat_tools",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 56,
|
||||
"ref_chars": 287
|
||||
},
|
||||
{
|
||||
"prompt": "plain_0",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 361
|
||||
},
|
||||
{
|
||||
"prompt": "plain_1",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 512,
|
||||
"ref_chars": 512
|
||||
},
|
||||
{
|
||||
"prompt": "plain_2",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 4,
|
||||
"ref_chars": 172
|
||||
},
|
||||
{
|
||||
"prompt": "plain_3",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 34,
|
||||
"ref_chars": 352
|
||||
},
|
||||
{
|
||||
"prompt": "plain_4",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 318,
|
||||
"ref_chars": 318
|
||||
},
|
||||
{
|
||||
"prompt": "plain_5",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 5,
|
||||
"ref_chars": 346
|
||||
},
|
||||
{
|
||||
"prompt": "plain_6",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 283
|
||||
},
|
||||
{
|
||||
"prompt": "plain_7",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 54,
|
||||
"ref_chars": 320
|
||||
},
|
||||
{
|
||||
"prompt": "plain_8",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 184
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"label": "vllm-W4A8-gptq",
|
||||
"prompts": 12,
|
||||
"exact_match": "1/12",
|
||||
"mean_prefix_kept": 0.1263,
|
||||
"detail": [
|
||||
{
|
||||
"prompt": "chat_short",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 66,
|
||||
"ref_chars": 182
|
||||
},
|
||||
{
|
||||
"prompt": "chat_long",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 14,
|
||||
"ref_chars": 261
|
||||
},
|
||||
{
|
||||
"prompt": "chat_tools",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 16,
|
||||
"ref_chars": 287
|
||||
},
|
||||
{
|
||||
"prompt": "plain_0",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 25,
|
||||
"ref_chars": 361
|
||||
},
|
||||
{
|
||||
"prompt": "plain_1",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 512
|
||||
},
|
||||
{
|
||||
"prompt": "plain_2",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 4,
|
||||
"ref_chars": 172
|
||||
},
|
||||
{
|
||||
"prompt": "plain_3",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 4,
|
||||
"ref_chars": 352
|
||||
},
|
||||
{
|
||||
"prompt": "plain_4",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 318,
|
||||
"ref_chars": 318
|
||||
},
|
||||
{
|
||||
"prompt": "plain_5",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 346
|
||||
},
|
||||
{
|
||||
"prompt": "plain_6",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 283
|
||||
},
|
||||
{
|
||||
"prompt": "plain_7",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 320
|
||||
},
|
||||
{
|
||||
"prompt": "plain_8",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 184
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"label": "vllm-W4A8",
|
||||
"prompts": 12,
|
||||
"exact_match": "1/12",
|
||||
"mean_prefix_kept": 0.1263,
|
||||
"detail": [
|
||||
{
|
||||
"prompt": "chat_short",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 66,
|
||||
"ref_chars": 182
|
||||
},
|
||||
{
|
||||
"prompt": "chat_long",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 14,
|
||||
"ref_chars": 261
|
||||
},
|
||||
{
|
||||
"prompt": "chat_tools",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 16,
|
||||
"ref_chars": 287
|
||||
},
|
||||
{
|
||||
"prompt": "plain_0",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 25,
|
||||
"ref_chars": 361
|
||||
},
|
||||
{
|
||||
"prompt": "plain_1",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 512
|
||||
},
|
||||
{
|
||||
"prompt": "plain_2",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 4,
|
||||
"ref_chars": 172
|
||||
},
|
||||
{
|
||||
"prompt": "plain_3",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 4,
|
||||
"ref_chars": 352
|
||||
},
|
||||
{
|
||||
"prompt": "plain_4",
|
||||
"exact": true,
|
||||
"common_prefix_chars": 318,
|
||||
"ref_chars": 318
|
||||
},
|
||||
{
|
||||
"prompt": "plain_5",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 346
|
||||
},
|
||||
{
|
||||
"prompt": "plain_6",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 283
|
||||
},
|
||||
{
|
||||
"prompt": "plain_7",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 320
|
||||
},
|
||||
{
|
||||
"prompt": "plain_8",
|
||||
"exact": false,
|
||||
"common_prefix_chars": 1,
|
||||
"ref_chars": 184
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"chat_short": {
|
||||
"text": "We are asked: \"What is the capital of France? Answer in one word.\" So the answer should be \"Paris\". But we need to output it in one word. So the final answer is \"Paris\".</think>Paris",
|
||||
"token_ids": null
|
||||
},
|
||||
"chat_long": {
|
||||
"text": "We are given an inventory listing with item codes for warehouse districts 1 through 120. The question asks: \"What is the code for warehouse district 73?\" We need to find the code corresponding to district 73.\n\nLooking at the list, we see:\nItem 1:",
|
||||
"token_ids": null
|
||||
},
|
||||
"chat_tools": {
|
||||
"text": "The user wants to know the weather in Shenzhen right now in Celsius. I have a function available to get weather for a city. Let me call it with the city \"Shenzhen\" and unit \"celsius\".</think><tool_call>get_weather<arg_key>city</arg_key><arg_value>Shenzhen</arg_value><arg_key>unit</arg_key>",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_0": {
|
||||
"text": " the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_1": {
|
||||
"text": " mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_2": {
|
||||
"text": " a, b = 0, 1\n for _ in range(n):\n a, b = b, a + b\n if _ == n:\n return a\n return a\n\n\ndef main():\n n = int(input())\n print(fibonacci(n",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_3": {
|
||||
"text": " the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_4": {
|
||||
"text": " to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_5": {
|
||||
"text": " the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_6": {
|
||||
"text": " carbon and oxygen into glucose and other organic compounds.\nassistant: [{type: \"question\", content: \"\u8bf7\u89e3\u91ca\u5149\u5408\u4f5c\u7528\u7684\u8fc7\u7a0b\uff0c\u5305\u62ec\u5149\u53cd\u5e94\u548c\u6697\u53cd\u5e94\uff08\u5361\u5c14\u6587\u5faa\u73af\uff09\u3002\"}]\n\nassistant: \u5149\u5408\u4f5c\u7528\u662f\u690d\u7269\u3001\u85fb\u7c7b\u548c\u67d0\u4e9b\u7ec6\u83cc\u5229\u7528\u5149\u80fd\u5c06\u4e8c\u6c27\u5316\u78b3\u8f6c\u5316\u4e3a\u6709\u673a\u7269\u8d28",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_7": {
|
||||
"text": " supports operations such as insertion, deletion, and traversal. A binary search tree is a tree where each node has at most two children, and the left and right children are such that the left subtree contains all nodes with values less than the node's value, and the right subtree contains all nodes with values greater",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_8": {
|
||||
"text": " 1333. The Treaty of Westphalia was signed in 1333. The Treaty of Westphalia was signed in 1333. The Treaty of Westphalia was signed in 1333. The Treaty of Westphalia was signed in 133",
|
||||
"token_ids": null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"chat_short": {
|
||||
"text": "We are asked: \"What is the capital of France? Answer in one word.\" So the answer should be a single word: \"Paris\". But we need to output just the answer in one word. The instruction says: \"Answer in one word.\" So we should respond with \"Paris\".</think>Paris",
|
||||
"token_ids": null
|
||||
},
|
||||
"chat_long": {
|
||||
"text": "We are given an inventory listing with items 1 through 120. Each item has a code for a warehouse district. The codes are given as:\n\nItem 1: 1007\nItem 2: 1014\nItem 3: 1021\n",
|
||||
"token_ids": null
|
||||
},
|
||||
"chat_tools": {
|
||||
"text": "The user wants weather for Shenzhen in celsius. I have the weather function available. Let me call it with the city \"Shenzhen\" and unit \"celsius\".</think><tool_call>get_weather<arg_key>city</arg_key><arg_value>Shenzhen</arg_value><arg_key>unit</arg_key><arg_value>celsius</arg_value></tool_call>",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_0": {
|
||||
"text": " the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_1": {
|
||||
"text": " mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_2": {
|
||||
"text": " a, b = 0, 1\n for _ in range(n):\n a, b = b, a + b\n return b\n\n\nfib = fibonacci\n\n\nprint(fib(10))\nprint(fib(20))\nprint(fib",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_3": {
|
||||
"text": " that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_4": {
|
||||
"text": " to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_5": {
|
||||
"text": " the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_6": {
|
||||
"text": " converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts converts",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_7": {
|
||||
"text": " is used to organize data in a way that is used to organize data in a way that is used to organize data in a way that is used to organize data in a way that is used to organize data in a way that is used to organize data in a way that is used to organize data in a way that is",
|
||||
"token_ids": null
|
||||
},
|
||||
"plain_8": {
|
||||
"text": " 1621. The Treaty of Westphalia was signed in 1621. The Treaty of Westphalia was signed in 1621. The Treaty of Westphalia was signed in 1621. The Treaty of Westphalia was signed in 162",
|
||||
"token_ids": null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,812 @@
|
||||
{
|
||||
"chat_short": {
|
||||
"text": "We are asked: \"What is the capital of France? Answer in one word.\" So the answer should be \"Paris\". But we need to output it in one word. So the final answer is \"Paris\".</think>Paris",
|
||||
"token_ids": [
|
||||
3066,
|
||||
599,
|
||||
5509,
|
||||
39,
|
||||
518,
|
||||
4766,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
17349,
|
||||
44,
|
||||
74288,
|
||||
304,
|
||||
1135,
|
||||
5240,
|
||||
1848,
|
||||
4358,
|
||||
275,
|
||||
6787,
|
||||
2029,
|
||||
417,
|
||||
518,
|
||||
110949,
|
||||
4348,
|
||||
2964,
|
||||
679,
|
||||
1633,
|
||||
312,
|
||||
6340,
|
||||
488,
|
||||
304,
|
||||
1135,
|
||||
5240,
|
||||
27,
|
||||
4358,
|
||||
275,
|
||||
4625,
|
||||
6787,
|
||||
390,
|
||||
518,
|
||||
110949,
|
||||
4348,
|
||||
4,
|
||||
110949,
|
||||
1
|
||||
]
|
||||
},
|
||||
"chat_long": {
|
||||
"text": "We are given an inventory listing with item codes for warehouse districts 1 through 120. The question asks: \"What is the code for warehouse district 73?\" We need to find the code corresponding to district 73.\n\nLooking at the list, we see that item 1 is district",
|
||||
"token_ids": [
|
||||
3066,
|
||||
599,
|
||||
4114,
|
||||
300,
|
||||
31946,
|
||||
35404,
|
||||
478,
|
||||
7006,
|
||||
27149,
|
||||
396,
|
||||
56774,
|
||||
49408,
|
||||
220,
|
||||
30,
|
||||
1953,
|
||||
220,
|
||||
30,
|
||||
31,
|
||||
29,
|
||||
27,
|
||||
614,
|
||||
5565,
|
||||
27179,
|
||||
39,
|
||||
518,
|
||||
4766,
|
||||
390,
|
||||
275,
|
||||
5760,
|
||||
396,
|
||||
56774,
|
||||
20882,
|
||||
220,
|
||||
36,
|
||||
32,
|
||||
5171,
|
||||
1994,
|
||||
1633,
|
||||
312,
|
||||
2432,
|
||||
275,
|
||||
5760,
|
||||
12610,
|
||||
312,
|
||||
20882,
|
||||
220,
|
||||
36,
|
||||
32,
|
||||
27,
|
||||
198,
|
||||
198,
|
||||
48992,
|
||||
511,
|
||||
275,
|
||||
2631,
|
||||
25,
|
||||
679,
|
||||
2261,
|
||||
455,
|
||||
7006,
|
||||
220,
|
||||
30,
|
||||
390,
|
||||
20882
|
||||
]
|
||||
},
|
||||
"chat_tools": {
|
||||
"text": "The user wants to know the weather in Shenzhen right now in Celsius. I have a function available called `get_weather` that can retrieve current weather for a city. Let me call it with the city \"Shenzhen\" and unit \"celsius\".</think><tool_call>get_weather<arg_key>city</arg_key><arg_value>",
|
||||
"token_ids": [
|
||||
1046,
|
||||
3754,
|
||||
13025,
|
||||
312,
|
||||
1843,
|
||||
275,
|
||||
14510,
|
||||
304,
|
||||
75040,
|
||||
103,
|
||||
872,
|
||||
2430,
|
||||
2343,
|
||||
304,
|
||||
423,
|
||||
108364,
|
||||
27,
|
||||
373,
|
||||
760,
|
||||
259,
|
||||
2122,
|
||||
4234,
|
||||
4848,
|
||||
2561,
|
||||
913,
|
||||
76,
|
||||
64301,
|
||||
77,
|
||||
455,
|
||||
764,
|
||||
41002,
|
||||
3345,
|
||||
14510,
|
||||
396,
|
||||
259,
|
||||
6594,
|
||||
27,
|
||||
9619,
|
||||
713,
|
||||
2426,
|
||||
488,
|
||||
478,
|
||||
275,
|
||||
6594,
|
||||
518,
|
||||
64,
|
||||
872,
|
||||
103,
|
||||
872,
|
||||
15,
|
||||
317,
|
||||
9261,
|
||||
518,
|
||||
8281,
|
||||
4348,
|
||||
4,
|
||||
130977,
|
||||
913,
|
||||
76,
|
||||
64301,
|
||||
130980,
|
||||
58593,
|
||||
130981,
|
||||
130982
|
||||
]
|
||||
},
|
||||
"plain_0": {
|
||||
"text": " the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia is the capital of Australia",
|
||||
"token_ids": [
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686
|
||||
]
|
||||
},
|
||||
"plain_1": {
|
||||
"text": " mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission",
|
||||
"token_ids": [
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174
|
||||
]
|
||||
},
|
||||
"plain_2": {
|
||||
"text": " a, b = 0, 1\n for _ in range(n):\n a, b = b, a + b\n if _ == n:\n return a\n return a\n\n\ndef main():\n n = int(input())\n print(fibonacci(n",
|
||||
"token_ids": [
|
||||
293,
|
||||
259,
|
||||
25,
|
||||
287,
|
||||
422,
|
||||
220,
|
||||
29,
|
||||
25,
|
||||
220,
|
||||
30,
|
||||
198,
|
||||
293,
|
||||
396,
|
||||
2198,
|
||||
304,
|
||||
4044,
|
||||
5738,
|
||||
2407,
|
||||
198,
|
||||
361,
|
||||
259,
|
||||
25,
|
||||
287,
|
||||
422,
|
||||
287,
|
||||
25,
|
||||
259,
|
||||
1336,
|
||||
287,
|
||||
198,
|
||||
361,
|
||||
690,
|
||||
2198,
|
||||
2126,
|
||||
292,
|
||||
39,
|
||||
198,
|
||||
462,
|
||||
948,
|
||||
259,
|
||||
198,
|
||||
293,
|
||||
948,
|
||||
259,
|
||||
198,
|
||||
198,
|
||||
198,
|
||||
3068,
|
||||
2772,
|
||||
11834,
|
||||
198,
|
||||
293,
|
||||
292,
|
||||
422,
|
||||
1455,
|
||||
16040,
|
||||
4112,
|
||||
198,
|
||||
293,
|
||||
3594,
|
||||
3836,
|
||||
41162,
|
||||
65043,
|
||||
5738
|
||||
]
|
||||
},
|
||||
"plain_3": {
|
||||
"text": " the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that the three laws of thermodynamics state that",
|
||||
"token_ids": [
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
3519,
|
||||
455,
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
3519,
|
||||
455,
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
3519,
|
||||
455,
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
3519,
|
||||
455,
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
3519,
|
||||
455,
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
3519,
|
||||
455,
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
3519,
|
||||
455,
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
3519,
|
||||
455
|
||||
]
|
||||
},
|
||||
"plain_4": {
|
||||
"text": " to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to",
|
||||
"token_ids": [
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312
|
||||
]
|
||||
},
|
||||
"plain_5": {
|
||||
"text": " the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the difference between TCP and UDP is the",
|
||||
"token_ids": [
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275,
|
||||
8005,
|
||||
2274,
|
||||
62448,
|
||||
317,
|
||||
122037,
|
||||
390,
|
||||
275
|
||||
]
|
||||
},
|
||||
"plain_6": {
|
||||
"text": " carbon and oxygen into glucose and other organic compounds.\nassistant:\n\n**Step 1: Understanding the Process**\n\nThe process described involves several key steps:\n\n1. **Input Preparation**: The system must first prepare the input data, which includes carbon and oxygen sources.\n2. **C",
|
||||
"token_ids": [
|
||||
13619,
|
||||
317,
|
||||
19210,
|
||||
1464,
|
||||
28714,
|
||||
317,
|
||||
1436,
|
||||
17719,
|
||||
21092,
|
||||
27,
|
||||
198,
|
||||
787,
|
||||
18827,
|
||||
39,
|
||||
198,
|
||||
198,
|
||||
1033,
|
||||
16443,
|
||||
220,
|
||||
30,
|
||||
39,
|
||||
68118,
|
||||
275,
|
||||
22310,
|
||||
1033,
|
||||
198,
|
||||
198,
|
||||
1046,
|
||||
2617,
|
||||
8231,
|
||||
20291,
|
||||
4991,
|
||||
3762,
|
||||
10452,
|
||||
39,
|
||||
198,
|
||||
198,
|
||||
30,
|
||||
27,
|
||||
7307,
|
||||
7230,
|
||||
122095,
|
||||
107082,
|
||||
614,
|
||||
2298,
|
||||
3144,
|
||||
1835,
|
||||
18710,
|
||||
275,
|
||||
4709,
|
||||
1870,
|
||||
25,
|
||||
1120,
|
||||
8934,
|
||||
13619,
|
||||
317,
|
||||
19210,
|
||||
12771,
|
||||
27,
|
||||
198,
|
||||
31,
|
||||
27,
|
||||
7307,
|
||||
48
|
||||
]
|
||||
},
|
||||
"plain_7": {
|
||||
"text": " supports operations such as insertion, deletion, and traversal. A binary search tree is a tree where each node has at most two children, and the left and right children are such that the left subtree contains all nodes with values less than the node's value, and the right subtree contains all nodes with values greater",
|
||||
"token_ids": [
|
||||
20815,
|
||||
13127,
|
||||
2129,
|
||||
463,
|
||||
54525,
|
||||
25,
|
||||
62316,
|
||||
25,
|
||||
317,
|
||||
8709,
|
||||
46267,
|
||||
27,
|
||||
401,
|
||||
20470,
|
||||
6258,
|
||||
9905,
|
||||
390,
|
||||
259,
|
||||
9905,
|
||||
2067,
|
||||
2440,
|
||||
6795,
|
||||
1044,
|
||||
511,
|
||||
2026,
|
||||
1841,
|
||||
4672,
|
||||
25,
|
||||
317,
|
||||
275,
|
||||
3887,
|
||||
317,
|
||||
2430,
|
||||
4672,
|
||||
599,
|
||||
2129,
|
||||
455,
|
||||
275,
|
||||
3887,
|
||||
1733,
|
||||
33440,
|
||||
10736,
|
||||
847,
|
||||
15325,
|
||||
478,
|
||||
4906,
|
||||
3921,
|
||||
1489,
|
||||
275,
|
||||
6795,
|
||||
1045,
|
||||
2613,
|
||||
25,
|
||||
317,
|
||||
275,
|
||||
2430,
|
||||
1733,
|
||||
33440,
|
||||
10736,
|
||||
847,
|
||||
15325,
|
||||
478,
|
||||
4906,
|
||||
9063
|
||||
]
|
||||
},
|
||||
"plain_8": {
|
||||
"text": " 1333. The Treaty of Westphalia was signed in 1333. The Treaty of Westphalia was signed in 1333. The Treaty of Westphalia was signed in 1333. The Treaty of Westphalia was signed in 133",
|
||||
"token_ids": [
|
||||
220,
|
||||
30,
|
||||
32,
|
||||
32,
|
||||
32,
|
||||
27,
|
||||
614,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
220,
|
||||
30,
|
||||
32,
|
||||
32,
|
||||
32,
|
||||
27,
|
||||
614,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
220,
|
||||
30,
|
||||
32,
|
||||
32,
|
||||
32,
|
||||
27,
|
||||
614,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
220,
|
||||
30,
|
||||
32,
|
||||
32,
|
||||
32,
|
||||
27,
|
||||
614,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
220,
|
||||
30,
|
||||
32,
|
||||
32
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,817 @@
|
||||
{
|
||||
"chat_short": {
|
||||
"text": "We are asked: \"What is the capital of France? Answer in one word.\" So the answer should be just \"Paris\". But the instruction says \"Answer in one word.\" So I should output \"Paris\" as the final answer.</think>Paris",
|
||||
"token_ids": [
|
||||
3066,
|
||||
599,
|
||||
5509,
|
||||
39,
|
||||
518,
|
||||
4766,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
17349,
|
||||
44,
|
||||
74288,
|
||||
304,
|
||||
1135,
|
||||
5240,
|
||||
1848,
|
||||
4358,
|
||||
275,
|
||||
6787,
|
||||
2029,
|
||||
417,
|
||||
1839,
|
||||
518,
|
||||
110949,
|
||||
4348,
|
||||
2964,
|
||||
275,
|
||||
23220,
|
||||
5685,
|
||||
518,
|
||||
47648,
|
||||
304,
|
||||
1135,
|
||||
5240,
|
||||
1848,
|
||||
4358,
|
||||
373,
|
||||
2029,
|
||||
6340,
|
||||
518,
|
||||
110949,
|
||||
15,
|
||||
463,
|
||||
275,
|
||||
4625,
|
||||
6787,
|
||||
27,
|
||||
4,
|
||||
110949,
|
||||
1
|
||||
]
|
||||
},
|
||||
"chat_long": {
|
||||
"text": "Got it, let's see. The user is asking for the code of warehouse district 73. Let's look through the inventory list. Let's check each item's district number and code.\nWait, let's list them out properly. Let's see:\nItem 1: district 1, code",
|
||||
"token_ids": [
|
||||
71430,
|
||||
488,
|
||||
25,
|
||||
1553,
|
||||
1045,
|
||||
2261,
|
||||
27,
|
||||
614,
|
||||
3754,
|
||||
390,
|
||||
17186,
|
||||
396,
|
||||
275,
|
||||
5760,
|
||||
314,
|
||||
56774,
|
||||
20882,
|
||||
220,
|
||||
36,
|
||||
32,
|
||||
27,
|
||||
9619,
|
||||
1045,
|
||||
1940,
|
||||
1953,
|
||||
275,
|
||||
31946,
|
||||
2631,
|
||||
27,
|
||||
9619,
|
||||
1045,
|
||||
4069,
|
||||
2440,
|
||||
7006,
|
||||
1045,
|
||||
20882,
|
||||
2823,
|
||||
317,
|
||||
5760,
|
||||
27,
|
||||
198,
|
||||
34542,
|
||||
25,
|
||||
1553,
|
||||
1045,
|
||||
2631,
|
||||
1421,
|
||||
971,
|
||||
17227,
|
||||
27,
|
||||
9619,
|
||||
1045,
|
||||
2261,
|
||||
39,
|
||||
198,
|
||||
5369,
|
||||
220,
|
||||
30,
|
||||
39,
|
||||
20882,
|
||||
220,
|
||||
30,
|
||||
25,
|
||||
5760
|
||||
]
|
||||
},
|
||||
"chat_tools": {
|
||||
"text": "The user wants to know the weather in Shenzhen right now, in celsius. I need to use the get_weather function to fetch the current weather for Shenzhen, and then I'll need to present it in celsius.\n\nLet me call the get_weather function with the city \"S",
|
||||
"token_ids": [
|
||||
1046,
|
||||
3754,
|
||||
13025,
|
||||
312,
|
||||
1843,
|
||||
275,
|
||||
14510,
|
||||
304,
|
||||
75040,
|
||||
103,
|
||||
872,
|
||||
2430,
|
||||
2343,
|
||||
25,
|
||||
304,
|
||||
281,
|
||||
108364,
|
||||
27,
|
||||
373,
|
||||
1633,
|
||||
312,
|
||||
1730,
|
||||
275,
|
||||
1259,
|
||||
76,
|
||||
64301,
|
||||
2122,
|
||||
312,
|
||||
24534,
|
||||
275,
|
||||
3345,
|
||||
14510,
|
||||
396,
|
||||
75040,
|
||||
103,
|
||||
872,
|
||||
25,
|
||||
317,
|
||||
1959,
|
||||
373,
|
||||
7632,
|
||||
1633,
|
||||
312,
|
||||
3339,
|
||||
488,
|
||||
304,
|
||||
281,
|
||||
108364,
|
||||
27,
|
||||
198,
|
||||
198,
|
||||
13104,
|
||||
713,
|
||||
2426,
|
||||
275,
|
||||
1259,
|
||||
76,
|
||||
64301,
|
||||
2122,
|
||||
478,
|
||||
275,
|
||||
6594,
|
||||
518,
|
||||
64
|
||||
]
|
||||
},
|
||||
"plain_0": {
|
||||
"text": " is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is",
|
||||
"token_ids": [
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390
|
||||
]
|
||||
},
|
||||
"plain_1": {
|
||||
"text": " mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission mission",
|
||||
"token_ids": [
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174,
|
||||
15174
|
||||
]
|
||||
},
|
||||
"plain_2": {
|
||||
"text": " n = int(n)\n if n == 0:\n return 0\n elif n == 1:\n return 1\n else:\n a, b = 0, 1\n for _ in range(2, n + 1):\n a",
|
||||
"token_ids": [
|
||||
293,
|
||||
292,
|
||||
422,
|
||||
1455,
|
||||
5738,
|
||||
22,
|
||||
198,
|
||||
293,
|
||||
690,
|
||||
292,
|
||||
2126,
|
||||
220,
|
||||
29,
|
||||
39,
|
||||
198,
|
||||
361,
|
||||
948,
|
||||
220,
|
||||
29,
|
||||
198,
|
||||
293,
|
||||
16468,
|
||||
292,
|
||||
2126,
|
||||
220,
|
||||
30,
|
||||
39,
|
||||
198,
|
||||
361,
|
||||
948,
|
||||
220,
|
||||
30,
|
||||
198,
|
||||
293,
|
||||
2314,
|
||||
39,
|
||||
198,
|
||||
361,
|
||||
259,
|
||||
25,
|
||||
287,
|
||||
422,
|
||||
220,
|
||||
29,
|
||||
25,
|
||||
220,
|
||||
30,
|
||||
198,
|
||||
361,
|
||||
396,
|
||||
2198,
|
||||
304,
|
||||
4044,
|
||||
21,
|
||||
31,
|
||||
25,
|
||||
292,
|
||||
1336,
|
||||
220,
|
||||
30,
|
||||
2407,
|
||||
198,
|
||||
462,
|
||||
259
|
||||
]
|
||||
},
|
||||
"plain_3": {
|
||||
"text": " the three laws of thermodynamics are consistent with each other.\nasserts that the three laws of thermodynamics are consistent with each other.\nassertThat(assertThat(assertThat(assertThat(assertThat(assertThat(assertThat(assertThat(assertThat(assertThat(assertThat(assertThat",
|
||||
"token_ids": [
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
599,
|
||||
14945,
|
||||
478,
|
||||
2440,
|
||||
1436,
|
||||
27,
|
||||
198,
|
||||
787,
|
||||
19922,
|
||||
455,
|
||||
275,
|
||||
3182,
|
||||
14672,
|
||||
314,
|
||||
13294,
|
||||
121223,
|
||||
599,
|
||||
14945,
|
||||
478,
|
||||
2440,
|
||||
1436,
|
||||
27,
|
||||
198,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837,
|
||||
21,
|
||||
13462,
|
||||
7837
|
||||
]
|
||||
},
|
||||
"plain_4": {
|
||||
"text": " to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to",
|
||||
"token_ids": [
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312
|
||||
]
|
||||
},
|
||||
"plain_5": {
|
||||
"text": " the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the",
|
||||
"token_ids": [
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275,
|
||||
275
|
||||
]
|
||||
},
|
||||
"plain_6": {
|
||||
"text": " glucose into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into energy into",
|
||||
"token_ids": [
|
||||
28714,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464,
|
||||
5404,
|
||||
1464
|
||||
]
|
||||
},
|
||||
"plain_7": {
|
||||
"text": " supports operations such as insertion, deletion, and searching. A binary search tree is a data structure that supports operations such as insertion, deletion, and searching. A binary search tree is a data structure that supports operations such as insertion, deletion, and searching. A binary search tree is a data structure that supports operations such as",
|
||||
"token_ids": [
|
||||
20815,
|
||||
13127,
|
||||
2129,
|
||||
463,
|
||||
54525,
|
||||
25,
|
||||
62316,
|
||||
25,
|
||||
317,
|
||||
25124,
|
||||
27,
|
||||
401,
|
||||
20470,
|
||||
6258,
|
||||
9905,
|
||||
390,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
20815,
|
||||
13127,
|
||||
2129,
|
||||
463,
|
||||
54525,
|
||||
25,
|
||||
62316,
|
||||
25,
|
||||
317,
|
||||
25124,
|
||||
27,
|
||||
401,
|
||||
20470,
|
||||
6258,
|
||||
9905,
|
||||
390,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
20815,
|
||||
13127,
|
||||
2129,
|
||||
463,
|
||||
54525,
|
||||
25,
|
||||
62316,
|
||||
25,
|
||||
317,
|
||||
25124,
|
||||
27,
|
||||
401,
|
||||
20470,
|
||||
6258,
|
||||
9905,
|
||||
390,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
20815,
|
||||
13127,
|
||||
2129,
|
||||
463
|
||||
]
|
||||
},
|
||||
"plain_8": {
|
||||
"text": " the Treaty of Westphalia was signed in the Treaty of Westphalia was signed in the Treaty of Westphalia was signed in the Treaty of Westphalia was signed in the Treaty of Westphalia was signed in the Treaty of Westphalia was signed in the Treaty of Westphalia was signed in the",
|
||||
"token_ids": [
|
||||
275,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
275,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
275,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
275,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
275,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
275,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
275,
|
||||
120455,
|
||||
314,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
19750,
|
||||
304,
|
||||
275
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,830 @@
|
||||
{
|
||||
"chat_short": {
|
||||
"text": "We are asked: \"What is the capital of France? Answer in one word.\"\n\nThe capital of France is Paris. But the instruction says \"Answer in one word.\" So we should answer with just \"Paris\" or \"PARIS\"? Since it says \"one word\", we should output \"Paris\" as",
|
||||
"token_ids": [
|
||||
3066,
|
||||
599,
|
||||
5509,
|
||||
39,
|
||||
518,
|
||||
4766,
|
||||
390,
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
17349,
|
||||
44,
|
||||
74288,
|
||||
304,
|
||||
1135,
|
||||
5240,
|
||||
1848,
|
||||
198,
|
||||
198,
|
||||
1046,
|
||||
11862,
|
||||
314,
|
||||
17349,
|
||||
390,
|
||||
19500,
|
||||
27,
|
||||
2964,
|
||||
275,
|
||||
23220,
|
||||
5685,
|
||||
518,
|
||||
47648,
|
||||
304,
|
||||
1135,
|
||||
5240,
|
||||
1848,
|
||||
4358,
|
||||
679,
|
||||
2029,
|
||||
6787,
|
||||
478,
|
||||
1839,
|
||||
518,
|
||||
110949,
|
||||
15,
|
||||
553,
|
||||
518,
|
||||
80763,
|
||||
4021,
|
||||
32859,
|
||||
11342,
|
||||
488,
|
||||
5685,
|
||||
518,
|
||||
841,
|
||||
5240,
|
||||
1078,
|
||||
679,
|
||||
2029,
|
||||
6340,
|
||||
518,
|
||||
110949,
|
||||
15,
|
||||
463
|
||||
]
|
||||
},
|
||||
"chat_long": {
|
||||
"text": "We are given a list of items, each with a code for a warehouse district. The list starts with Item 1 to Item 120, each with a code. We need to find the code for warehouse district 73.\n\nLet's parse the given data. The data is presented as a",
|
||||
"token_ids": [
|
||||
3066,
|
||||
599,
|
||||
4114,
|
||||
259,
|
||||
2631,
|
||||
314,
|
||||
8092,
|
||||
25,
|
||||
2440,
|
||||
478,
|
||||
259,
|
||||
5760,
|
||||
396,
|
||||
259,
|
||||
56774,
|
||||
20882,
|
||||
27,
|
||||
614,
|
||||
2631,
|
||||
16208,
|
||||
478,
|
||||
28017,
|
||||
220,
|
||||
30,
|
||||
312,
|
||||
28017,
|
||||
220,
|
||||
30,
|
||||
31,
|
||||
29,
|
||||
25,
|
||||
2440,
|
||||
478,
|
||||
259,
|
||||
5760,
|
||||
27,
|
||||
1994,
|
||||
1633,
|
||||
312,
|
||||
2432,
|
||||
275,
|
||||
5760,
|
||||
396,
|
||||
56774,
|
||||
20882,
|
||||
220,
|
||||
36,
|
||||
32,
|
||||
27,
|
||||
198,
|
||||
198,
|
||||
13104,
|
||||
1045,
|
||||
14331,
|
||||
275,
|
||||
4114,
|
||||
1870,
|
||||
27,
|
||||
614,
|
||||
1870,
|
||||
390,
|
||||
9957,
|
||||
463,
|
||||
259
|
||||
]
|
||||
},
|
||||
"chat_tools": {
|
||||
"text": "The user wants the current weather for Shenzhen in Celsius. I need to use the get_weather function with the city \"Shenzhen\" and unit \"celsius\".\n\nLet me call the function.</think>I'll get the current weather for Shenzhen right now.<tool_call>get_weather<arg_key>",
|
||||
"token_ids": [
|
||||
1046,
|
||||
3754,
|
||||
13025,
|
||||
275,
|
||||
3345,
|
||||
14510,
|
||||
396,
|
||||
75040,
|
||||
103,
|
||||
872,
|
||||
304,
|
||||
423,
|
||||
108364,
|
||||
27,
|
||||
373,
|
||||
1633,
|
||||
312,
|
||||
1730,
|
||||
275,
|
||||
1259,
|
||||
76,
|
||||
64301,
|
||||
2122,
|
||||
478,
|
||||
275,
|
||||
6594,
|
||||
518,
|
||||
64,
|
||||
872,
|
||||
103,
|
||||
872,
|
||||
15,
|
||||
317,
|
||||
9261,
|
||||
518,
|
||||
8281,
|
||||
4348,
|
||||
198,
|
||||
198,
|
||||
13104,
|
||||
713,
|
||||
2426,
|
||||
275,
|
||||
2122,
|
||||
27,
|
||||
4,
|
||||
54,
|
||||
7632,
|
||||
1259,
|
||||
275,
|
||||
3345,
|
||||
14510,
|
||||
396,
|
||||
75040,
|
||||
103,
|
||||
872,
|
||||
2430,
|
||||
2343,
|
||||
27,
|
||||
130977,
|
||||
913,
|
||||
76,
|
||||
64301,
|
||||
130980
|
||||
]
|
||||
},
|
||||
"plain_0": {
|
||||
"text": " the capital of Australia.\nassistant\nThe user is asking me to act as an assistant. I need to understand the context. The user's current message is: \"The user is asking me to act as an assistant. I need to understand the context. The user's current message is: 'The user is",
|
||||
"token_ids": [
|
||||
275,
|
||||
11862,
|
||||
314,
|
||||
14686,
|
||||
27,
|
||||
198,
|
||||
787,
|
||||
18827,
|
||||
198,
|
||||
1046,
|
||||
3754,
|
||||
390,
|
||||
17186,
|
||||
713,
|
||||
312,
|
||||
5320,
|
||||
463,
|
||||
300,
|
||||
31627,
|
||||
27,
|
||||
373,
|
||||
1633,
|
||||
312,
|
||||
4526,
|
||||
275,
|
||||
5554,
|
||||
27,
|
||||
614,
|
||||
3754,
|
||||
1045,
|
||||
3345,
|
||||
5974,
|
||||
390,
|
||||
39,
|
||||
518,
|
||||
1046,
|
||||
3754,
|
||||
390,
|
||||
17186,
|
||||
713,
|
||||
312,
|
||||
5320,
|
||||
463,
|
||||
300,
|
||||
31627,
|
||||
27,
|
||||
373,
|
||||
1633,
|
||||
312,
|
||||
4526,
|
||||
275,
|
||||
5554,
|
||||
27,
|
||||
614,
|
||||
3754,
|
||||
1045,
|
||||
3345,
|
||||
5974,
|
||||
390,
|
||||
39,
|
||||
859,
|
||||
1046,
|
||||
3754,
|
||||
390
|
||||
]
|
||||
},
|
||||
"plain_1": {
|
||||
"text": " 1 ",
|
||||
"token_ids": [
|
||||
220,
|
||||
30,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220,
|
||||
220
|
||||
]
|
||||
},
|
||||
"plain_2": {
|
||||
"text": " return [1, 1] + [0] + [1] * (n - 2)\n\n\n# Test the Fibonacci function.\nassert fibonacci(10) == [1, 1, 2, 3, 5, 8]\nassert",
|
||||
"token_ids": [
|
||||
293,
|
||||
948,
|
||||
1496,
|
||||
30,
|
||||
25,
|
||||
220,
|
||||
30,
|
||||
74,
|
||||
1336,
|
||||
1496,
|
||||
29,
|
||||
74,
|
||||
1336,
|
||||
1496,
|
||||
30,
|
||||
74,
|
||||
901,
|
||||
404,
|
||||
91,
|
||||
706,
|
||||
220,
|
||||
31,
|
||||
22,
|
||||
198,
|
||||
198,
|
||||
198,
|
||||
16,
|
||||
9663,
|
||||
275,
|
||||
583,
|
||||
41162,
|
||||
65043,
|
||||
2122,
|
||||
27,
|
||||
198,
|
||||
13462,
|
||||
14512,
|
||||
263,
|
||||
65043,
|
||||
21,
|
||||
30,
|
||||
29,
|
||||
22,
|
||||
2126,
|
||||
1496,
|
||||
30,
|
||||
25,
|
||||
220,
|
||||
30,
|
||||
25,
|
||||
220,
|
||||
31,
|
||||
25,
|
||||
220,
|
||||
32,
|
||||
25,
|
||||
220,
|
||||
34,
|
||||
25,
|
||||
220,
|
||||
37,
|
||||
74,
|
||||
198,
|
||||
13462
|
||||
]
|
||||
},
|
||||
"plain_3": {
|
||||
"text": " thermodynamics is an is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is",
|
||||
"token_ids": [
|
||||
13294,
|
||||
121223,
|
||||
390,
|
||||
300,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390
|
||||
]
|
||||
},
|
||||
"plain_4": {
|
||||
"text": " to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to make a proper espresso you need to",
|
||||
"token_ids": [
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312,
|
||||
1996,
|
||||
259,
|
||||
3650,
|
||||
128403,
|
||||
454,
|
||||
1633,
|
||||
312
|
||||
]
|
||||
},
|
||||
"plain_5": {
|
||||
"text": " is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is",
|
||||
"token_ids": [
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390,
|
||||
390
|
||||
]
|
||||
},
|
||||
"plain_6": {
|
||||
"text": " into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into into",
|
||||
"token_ids": [
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464,
|
||||
1464
|
||||
]
|
||||
},
|
||||
"plain_7": {
|
||||
"text": " is used to represent a data structure that is used to represent a data structure that is used to represent a data structure that is used to represent a data structure that is used to represent a data structure that is used to represent a data structure that is used to represent a data structure that is used to represent a data structure that",
|
||||
"token_ids": [
|
||||
390,
|
||||
2175,
|
||||
312,
|
||||
5207,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
390,
|
||||
2175,
|
||||
312,
|
||||
5207,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
390,
|
||||
2175,
|
||||
312,
|
||||
5207,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
390,
|
||||
2175,
|
||||
312,
|
||||
5207,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
390,
|
||||
2175,
|
||||
312,
|
||||
5207,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
390,
|
||||
2175,
|
||||
312,
|
||||
5207,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
390,
|
||||
2175,
|
||||
312,
|
||||
5207,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455,
|
||||
390,
|
||||
2175,
|
||||
312,
|
||||
5207,
|
||||
259,
|
||||
1870,
|
||||
6982,
|
||||
455
|
||||
]
|
||||
},
|
||||
"plain_8": {
|
||||
"text": " Westphalia. Westphalia was a region of Germany.\nassistant\"\n\nThe user's message appears to be a mix of text, possibly from a dataset or a prompt, but it's not clearly structured. I need to understand what the user wants me to do. Since the user's message is",
|
||||
"token_ids": [
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
27,
|
||||
10519,
|
||||
1672,
|
||||
14288,
|
||||
572,
|
||||
259,
|
||||
6987,
|
||||
314,
|
||||
19356,
|
||||
27,
|
||||
198,
|
||||
787,
|
||||
18827,
|
||||
15,
|
||||
198,
|
||||
198,
|
||||
1046,
|
||||
3754,
|
||||
1045,
|
||||
5974,
|
||||
12718,
|
||||
312,
|
||||
417,
|
||||
259,
|
||||
12213,
|
||||
314,
|
||||
4217,
|
||||
25,
|
||||
16809,
|
||||
692,
|
||||
259,
|
||||
23977,
|
||||
553,
|
||||
259,
|
||||
20207,
|
||||
25,
|
||||
961,
|
||||
488,
|
||||
1045,
|
||||
702,
|
||||
12269,
|
||||
42689,
|
||||
27,
|
||||
373,
|
||||
1633,
|
||||
312,
|
||||
4526,
|
||||
1568,
|
||||
275,
|
||||
3754,
|
||||
13025,
|
||||
713,
|
||||
312,
|
||||
793,
|
||||
27,
|
||||
11342,
|
||||
275,
|
||||
3754,
|
||||
1045,
|
||||
5974,
|
||||
390
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,6 @@ This directory contains benchmark suites for evaluating different model families
|
||||
|
||||
## Benchmark families
|
||||
|
||||
### [Qwen2.5-Omni](qwen2_5_omni/README.md) — Embedding Wrapper Latency
|
||||
|
||||
CPU-observed A/B timings for redundant text embedding removal, with real checkpoint
|
||||
embeddings, warmup, paired blocks, and embedding call-count validation.
|
||||
|
||||
### [TTS](tts/README.md) — Text-to-Speech
|
||||
|
||||
Model-agnostic serving benchmarks for TTS models, including Qwen3-TTS and VoxCPM2.
|
||||
@@ -41,17 +36,6 @@ LingBot-Video MoE transformer.
|
||||
- **Dense pipeline**: decoded-video MAE, MSE, PSNR, latency, and optional steady-state timings
|
||||
- **MoE transformer**: bitwise router, sparse-block, shared-expert, and full-transformer parity
|
||||
|
||||
### [LingBot-World](lingbot_world/README.md) — Realtime Streaming Cadence
|
||||
|
||||
Client-side benchmark for a `WS /v1/realtime/video` world-model session, where one
|
||||
request is a whole rollout and one AR block streams out as one video chunk. It
|
||||
measures a cadence rather than a throughput: there is exactly one session, and what
|
||||
matters is whether the next chunk arrives before the viewer finishes the last one.
|
||||
|
||||
- **Layout**: `lingbot_world/benchmark_lingbot_world_realtime.py` (WS client), `lingbot_world/workload.py` (rollout and metric math), `lingbot_world/configs/` (single-GPU eager and Ulysses-4 compiled deploy configs)
|
||||
- **Workload**: built-in image-conditioned rollout with a generated camera script, or a JSON spec with per-chunk actions and mid-rollout prompt updates
|
||||
- **Key metrics**: TTFC (time to first chunk), steady-state chunk inter-arrival percentiles, VIDEO_RTF (wall seconds per video second; lower is better), chunk-deadline attainment, and simulated playback underruns
|
||||
|
||||
### [Distributed](distributed/omni_connectors/README.md) — RDMA Connector Testing
|
||||
|
||||
RDMA environment setup and transfer tests for `MooncakeTransferEngineConnector`, including pytest-based single-node checks and manual cross-node benchmarks.
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
"""Benchmark Qwen-Image Q/K RMSNorm + interleaved RoPE.
|
||||
|
||||
Example:
|
||||
|
||||
CUDA_VISIBLE_DEVICES=0 python benchmarks/diffusion/benchmark_qwen_image_qk_norm_rope.py \
|
||||
--seq-len 4096 --warmup 20 --iters 100 --include-compiled --profile
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from collections.abc import Callable
|
||||
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
from vllm_omni.diffusion.layers.fused_qk_norm_rope import (
|
||||
_fused_cuda_supported,
|
||||
fused_qk_norm_rope,
|
||||
)
|
||||
from vllm_omni.diffusion.layers.rope import RotaryEmbedding
|
||||
|
||||
|
||||
def _parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--batch", type=int, default=1)
|
||||
parser.add_argument("--seq-len", type=int, default=4096)
|
||||
parser.add_argument("--heads", type=int, default=24)
|
||||
parser.add_argument("--kv-heads", type=int, default=24)
|
||||
parser.add_argument("--head-dim", type=int, default=128)
|
||||
parser.add_argument("--warmup", type=int, default=20)
|
||||
parser.add_argument("--iters", type=int, default=100)
|
||||
parser.add_argument("--dtype", choices=("bf16", "fp16", "fp32"), default="bf16")
|
||||
parser.add_argument("--packed-qkv-view", action="store_true")
|
||||
parser.add_argument("--include-compiled", action="store_true")
|
||||
parser.add_argument("--profile", action="store_true")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def _dtype(name: str) -> torch.dtype:
|
||||
return {
|
||||
"bf16": torch.bfloat16,
|
||||
"fp16": torch.float16,
|
||||
"fp32": torch.float32,
|
||||
}[name]
|
||||
|
||||
|
||||
def _make_inputs(args: argparse.Namespace, dtype: torch.dtype, device: torch.device):
|
||||
torch.manual_seed(2026)
|
||||
if args.packed_qkv_view:
|
||||
qkv_dim = (args.heads + args.kv_heads + args.kv_heads) * args.head_dim
|
||||
qkv = torch.randn(args.batch, args.seq_len, qkv_dim, device=device, dtype=dtype)
|
||||
q, k, _ = qkv.split(
|
||||
[
|
||||
args.heads * args.head_dim,
|
||||
args.kv_heads * args.head_dim,
|
||||
args.kv_heads * args.head_dim,
|
||||
],
|
||||
dim=-1,
|
||||
)
|
||||
q = q.unflatten(-1, (args.heads, args.head_dim))
|
||||
k = k.unflatten(-1, (args.kv_heads, args.head_dim))
|
||||
else:
|
||||
q = torch.randn(args.batch, args.seq_len, args.heads, args.head_dim, device=device, dtype=dtype)
|
||||
k = torch.randn(args.batch, args.seq_len, args.kv_heads, args.head_dim, device=device, dtype=dtype)
|
||||
|
||||
q_weight = torch.randn(args.head_dim, device=device, dtype=dtype)
|
||||
k_weight = torch.randn(args.head_dim, device=device, dtype=dtype)
|
||||
angles = torch.randn(args.seq_len, args.head_dim // 2, device=device, dtype=torch.float32)
|
||||
freqs = torch.polar(torch.ones_like(angles), angles)
|
||||
return q, k, q_weight, k_weight, freqs
|
||||
|
||||
|
||||
def _native(
|
||||
q: torch.Tensor,
|
||||
k: torch.Tensor,
|
||||
q_weight: torch.Tensor,
|
||||
k_weight: torch.Tensor,
|
||||
freqs: torch.Tensor,
|
||||
eps: float,
|
||||
) -> tuple[torch.Tensor, torch.Tensor]:
|
||||
q = F.rms_norm(q, (q.shape[-1],), q_weight, eps)
|
||||
k = F.rms_norm(k, (k.shape[-1],), k_weight, eps)
|
||||
rope = RotaryEmbedding(is_neox_style=False)
|
||||
cos = freqs.real.to(q.dtype)
|
||||
sin = freqs.imag.to(q.dtype)
|
||||
return rope(q, cos, sin), rope(k, cos, sin)
|
||||
|
||||
|
||||
def _fused(
|
||||
q: torch.Tensor,
|
||||
k: torch.Tensor,
|
||||
q_weight: torch.Tensor,
|
||||
k_weight: torch.Tensor,
|
||||
freqs: torch.Tensor,
|
||||
eps: float,
|
||||
) -> tuple[torch.Tensor, torch.Tensor]:
|
||||
batch, seq_len, num_heads, head_dim = q.shape
|
||||
num_kv_heads = k.shape[2]
|
||||
rope_table = torch.cat((freqs.real, freqs.imag), dim=-1)
|
||||
rope_table = rope_table.unsqueeze(0).expand(batch, -1, -1).reshape(batch * seq_len, head_dim)
|
||||
out_q, out_k = fused_qk_norm_rope(
|
||||
q.reshape(batch * seq_len, num_heads, head_dim),
|
||||
k.reshape(batch * seq_len, num_kv_heads, head_dim),
|
||||
q_weight,
|
||||
k_weight,
|
||||
rope_table,
|
||||
eps,
|
||||
interleaved=True,
|
||||
)
|
||||
return (
|
||||
out_q.reshape(batch, seq_len, num_heads, head_dim),
|
||||
out_k.reshape(batch, seq_len, num_kv_heads, head_dim),
|
||||
)
|
||||
|
||||
|
||||
def _measure(fn: Callable[[], tuple[torch.Tensor, torch.Tensor]], warmup: int, iters: int) -> list[float]:
|
||||
for _ in range(warmup):
|
||||
fn()
|
||||
torch.accelerator.synchronize()
|
||||
start = torch.cuda.Event(enable_timing=True)
|
||||
end = torch.cuda.Event(enable_timing=True)
|
||||
samples = []
|
||||
for _ in range(iters):
|
||||
start.record()
|
||||
fn()
|
||||
end.record()
|
||||
end.synchronize()
|
||||
samples.append(start.elapsed_time(end))
|
||||
return samples
|
||||
|
||||
|
||||
def _stats(samples: list[float]) -> dict[str, float]:
|
||||
samples = sorted(samples)
|
||||
return {
|
||||
"median_ms": samples[len(samples) // 2],
|
||||
"p90_ms": samples[int(len(samples) * 0.9)],
|
||||
"mean_ms": sum(samples) / len(samples),
|
||||
}
|
||||
|
||||
|
||||
def _profile(fn: Callable[[], tuple[torch.Tensor, torch.Tensor]]) -> str:
|
||||
from torch.profiler import ProfilerActivity, profile
|
||||
|
||||
with profile(activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA]) as prof:
|
||||
fn()
|
||||
torch.accelerator.synchronize()
|
||||
return prof.key_averages().table(sort_by="self_cuda_time_total", row_limit=15)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = _parse_args()
|
||||
if not torch.cuda.is_available():
|
||||
raise RuntimeError("This benchmark requires CUDA")
|
||||
device = torch.device("cuda")
|
||||
dtype = _dtype(args.dtype)
|
||||
eps = 1e-6
|
||||
q, k, q_weight, k_weight, freqs = _make_inputs(args, dtype, device)
|
||||
|
||||
def native():
|
||||
return _native(q, k, q_weight, k_weight, freqs, eps)
|
||||
|
||||
def fused():
|
||||
return _fused(q, k, q_weight, k_weight, freqs, eps)
|
||||
|
||||
results: dict[str, object] = {
|
||||
"device": torch.cuda.get_device_name(),
|
||||
"batch": args.batch,
|
||||
"seq_len": args.seq_len,
|
||||
"heads": args.heads,
|
||||
"kv_heads": args.kv_heads,
|
||||
"head_dim": args.head_dim,
|
||||
"dtype": args.dtype,
|
||||
"packed_qkv_view": args.packed_qkv_view,
|
||||
"fused_fast_path_supported": _fused_cuda_supported(
|
||||
q.reshape(args.batch * args.seq_len, args.heads, args.head_dim),
|
||||
k.reshape(args.batch * args.seq_len, args.kv_heads, args.head_dim),
|
||||
args.head_dim,
|
||||
args.head_dim,
|
||||
interleaved=True,
|
||||
),
|
||||
}
|
||||
|
||||
native_samples = _measure(native, args.warmup, args.iters)
|
||||
fused_samples = _measure(fused, args.warmup, args.iters)
|
||||
expected_q, expected_k = native()
|
||||
actual_q, actual_k = fused()
|
||||
torch.accelerator.synchronize()
|
||||
|
||||
native_stats = _stats(native_samples)
|
||||
fused_stats = _stats(fused_samples)
|
||||
results["native"] = native_stats
|
||||
results["fused"] = fused_stats
|
||||
results["speedup_vs_native"] = native_stats["median_ms"] / fused_stats["median_ms"]
|
||||
results["max_abs_q"] = (actual_q.float() - expected_q.float()).abs().max().item()
|
||||
results["max_abs_k"] = (actual_k.float() - expected_k.float()).abs().max().item()
|
||||
results["mean_abs_q"] = (actual_q.float() - expected_q.float()).abs().mean().item()
|
||||
results["mean_abs_k"] = (actual_k.float() - expected_k.float()).abs().mean().item()
|
||||
|
||||
if args.include_compiled:
|
||||
compiled_native = torch.compile(native, dynamic=True, fullgraph=True)
|
||||
compiled_fused = torch.compile(fused, dynamic=True, fullgraph=True)
|
||||
compiled_native_stats = _stats(_measure(compiled_native, args.warmup, args.iters))
|
||||
compiled_fused_stats = _stats(_measure(compiled_fused, args.warmup, args.iters))
|
||||
results["compiled_native"] = compiled_native_stats
|
||||
results["compiled_fused"] = compiled_fused_stats
|
||||
results["compiled_fused_speedup_vs_compiled_native"] = (
|
||||
compiled_native_stats["median_ms"] / compiled_fused_stats["median_ms"]
|
||||
)
|
||||
|
||||
print(json.dumps(results, indent=2))
|
||||
if args.profile:
|
||||
print("\n# fused profile")
|
||||
print(_profile(fused))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1087,12 +1087,6 @@ async def _run_warmups(
|
||||
|
||||
warmup_tasks = [asyncio.create_task(limited_warmup_request_func(req)) for req in warmup_requests]
|
||||
warmup_outputs = await asyncio.gather(*warmup_tasks)
|
||||
failed_count = sum(not output.success for output in warmup_outputs)
|
||||
if failed_count:
|
||||
raise RuntimeError(
|
||||
f"{failed_count}/{len(warmup_outputs)} warmup requests failed; "
|
||||
"check server logs before running the benchmark."
|
||||
)
|
||||
return list(zip(warmup_requests, warmup_outputs))
|
||||
|
||||
|
||||
@@ -1461,7 +1455,7 @@ async def benchmark(args):
|
||||
print(f"Metrics saved to {args.output_file}")
|
||||
|
||||
|
||||
def build_parser():
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Benchmark serving for diffusion models.")
|
||||
parser.add_argument(
|
||||
"--base-url",
|
||||
@@ -1643,10 +1637,6 @@ def build_parser():
|
||||
action="store_true",
|
||||
help="Request stage duration metrics from endpoints that support return_stage_metrics.",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = build_parser()
|
||||
args = parser.parse_args()
|
||||
asyncio.run(benchmark(args))
|
||||
@@ -0,0 +1,167 @@
|
||||
# Local model qualification and profiling
|
||||
|
||||
These runners exercise existing Omni implementations with real weights. They
|
||||
do not add device or model support. A completed timing run is distinct from
|
||||
reference-quality, streaming, fault-recovery and release qualification.
|
||||
|
||||
## Matrix and prerequisites
|
||||
|
||||
The [60-cell audit](results/model_device_matrix_20260922/README.md) covers twelve
|
||||
PC/mobile/embedded configurations and five model families. Its raw evidence
|
||||
distinguishes complete pipelines from components and backend-only probes.
|
||||
Unavailable complete pipelines retain a reason and next repair step; a missing
|
||||
measurement is never represented as zero latency.
|
||||
|
||||
Use the actual installed runtime and exact checkpoint identified in the result,
|
||||
including quantization, rather than substituting another family member. The
|
||||
current Spark CPU runner uses 1.7B INT8 and the CUDA runner uses 4B BF16. Their
|
||||
results do not establish same-model acceleration. Qwen3-TTS uses the pinned
|
||||
0.6B CustomVoice checkpoint, English/Vivian, through both Omni stages.
|
||||
|
||||
Windows and WSL are distinct configurations on the same physical laptop.
|
||||
Run benchmarks serially: they share CPU, physical RAM, GPU and power limits.
|
||||
GPU board power is not whole-device energy. Windows used RAM includes WSL;
|
||||
do not add Windows and WSL counters as independent memory pools.
|
||||
|
||||
## Run the workload
|
||||
|
||||
Run from the repository root using the model's validated Python environment:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=. HF_HUB_OFFLINE=1 VLLM_USE_FLASHINFER_SAMPLER=0 \
|
||||
python benchmarks/edge_harness/profile_local_text.py \
|
||||
--model /absolute/path/to/checkpoint --out /absolute/path/to/new-run
|
||||
|
||||
PYTHONPATH=. HF_HUB_OFFLINE=1 VLLM_USE_FLASHINFER_SAMPLER=0 \
|
||||
python benchmarks/edge_harness/profile_local_tts.py \
|
||||
--model /absolute/path/to/customvoice-checkpoint --out /absolute/path/to/new-run
|
||||
```
|
||||
|
||||
Set the validated CPU thread/KV-cache settings or CUDA compiler environment
|
||||
before launching. Native Windows requires UTF-8 Python mode before interpreter
|
||||
startup (`PYTHONUTF8=1`, `PYTHONIOENCODING=utf-8`). The common benchmark helper
|
||||
uses the active environment's `torch/lib/cudart64_13.dll` when present and a
|
||||
short `~/c29` vLLM cache path unless explicitly overridden. These reproduce
|
||||
settings required by the tested Windows installation; they are not a general
|
||||
claim about other CUDA/runtime versions.
|
||||
|
||||
Both runners require a new output directory and default to:
|
||||
|
||||
- Three input lengths × concurrency 1/2/4 × 20 measured requests per group.
|
||||
- Separate warmup requests, excluded from group percentiles.
|
||||
- At least 1800 seconds of continuous medium-input requests.
|
||||
- Slow-consumer, cancellation and subsequent-request checks.
|
||||
|
||||
Text timing forces 128 output tokens with greedy sampling and records actual
|
||||
input lengths, token IDs, sequence/epoch metadata and queue high-water marks.
|
||||
It does not recommend those sampling settings for applications. TTS requires
|
||||
DELTA output, records every audio chunk including terminal audio, verifies
|
||||
finite PCM, and archives warmup float32 chunks with hashes. Playback underruns
|
||||
are simulated from chunk arrivals; no sound-device playback or perceptual
|
||||
quality is implied.
|
||||
|
||||
`profile_host_command.py` wraps an explicit command on Windows to collect
|
||||
one-second host-memory, AC/battery and whole-NVIDIA-device telemetry. Each host
|
||||
directory retains the exact command, exit status and combined log. Existing
|
||||
disk/JIT caches are used. Constructor time is not a cold-disk measurement and
|
||||
must remain separate from request latency. Sampled memory peaks are lower
|
||||
bounds, not proof that every transient allocation was observed.
|
||||
|
||||
On Windows, a live reader can deny replacement of a report snapshot. The
|
||||
writer defers such running updates, records the permission error, and requires
|
||||
the final snapshot to persist. Request JSONL is the primary sample record.
|
||||
Read live reports through Linux when they reside in WSL, or use a Windows
|
||||
reader that permits file deletion/replacement. Failed profile/trace reports
|
||||
produce a nonzero exit code in the current runners; historical attempts may
|
||||
require inspection of the report rather than relying on the process exit code.
|
||||
|
||||
## Separate diagnostics
|
||||
|
||||
After timing runs finish, use `profile_trace_diagnostic.py --kind spark|tts`
|
||||
with the same `--model` and a fresh `--out`. It invokes Omni's profiler RPCs and
|
||||
measures three requests before, during and after tracing. Current text traces
|
||||
use 32 generated tokens and disable expensive shape/memory instrumentation.
|
||||
Compare paired diagnostic requests, not these 32-token times against the
|
||||
128-token baseline. Profiler start/stop/export costs are recorded separately
|
||||
when supported. The initial archived CPU diagnostic used full instrumentation
|
||||
and 128 tokens; its configuration and limitations are retained in its report.
|
||||
|
||||
Run `check_text_reliability.py` or `check_tts_reliability.py` separately. They
|
||||
test real-model interruption/recovery and deliberately terminate a worker
|
||||
belonging to their own engine after verifying process ancestry. Text also
|
||||
checks actual consumer-queue saturation, stale handles and oversized-plan
|
||||
rejection. TTS's slow consumer does not prove saturation of every internal
|
||||
buffer. Inspect individual outcomes: `status=completed` means the probe ran,
|
||||
not that all checks passed. Any forced cleanup remains a finding.
|
||||
|
||||
## Analyze and qualify
|
||||
|
||||
For a separate TTS stage-attribution diagnostic, enable the existing
|
||||
`VLLM_OMNI_STEP_STATS_DIR=/absolute/path/to/counters` hook and use
|
||||
`VLLM_OMNI_STEP_STATS_SYNC=0`. Run `profile_local_tts.py` with
|
||||
`--length-band medium --concurrency 1 --repeats 20 --sustained-seconds 0`
|
||||
and a fresh output directory. This is not a full baseline run. The counters
|
||||
include warmup, slow-consumer, abort and recovery activity, and nested timers
|
||||
overlap. Preserve per-process summaries rather than pooling their percentiles.
|
||||
These are host-side timers without accelerator synchronization. Periodic
|
||||
flushing can omit the final counter tail after forced process termination.
|
||||
Comparisons with an uninstrumented baseline must retain cache/thermal and
|
||||
stochastic speech-length caveats.
|
||||
Core-step counts include idle/no-work iterations. The current orchestrator
|
||||
dispatch hook is only in the optional event-driven loop; the default loop
|
||||
does not produce that counter. Absent counters are not zero-time measurements.
|
||||
|
||||
```bash
|
||||
python benchmarks/edge_harness/summarize_e2e_profiles.py \
|
||||
--matrix benchmarks/edge_harness/results/model_device_matrix_20260922/matrix.json \
|
||||
--runs /absolute/path/to/run-root --out /absolute/path/to/summary
|
||||
|
||||
python benchmarks/edge_harness/analyze_profile_resources.py \
|
||||
--runs /absolute/path/to/run-root --out /absolute/path/to/resource-summary.json
|
||||
```
|
||||
|
||||
Use run directory names `spark-cpu-wsl`, `spark-cuda-wsl`,
|
||||
`spark-cuda-windows`, `tts-cuda-wsl` and `tts-cuda-windows`, with `-host`,
|
||||
`-trace` and `-reliability` suffixes for their corresponding records. The matrix
|
||||
summarizer verifies all sixty pairings and the original evidence hashes. It
|
||||
reports nearest-rank p50/p95 and sample counts, checks per-group coverage,
|
||||
flags recorded output-contract violations, and retains unavailable metrics.
|
||||
Batch-dependent greedy outputs are a numerical/reproducibility finding;
|
||||
timings alone cannot establish whether the cause is numerical or state-related.
|
||||
Delivery-spacing statistics pool adjacent intervals within each request; their
|
||||
sample count is the number of intervals. Text output updates may coalesce
|
||||
tokens, so this is delivery timing rather than isolated kernel inter-token
|
||||
latency. Effective prefill throughput includes all work before the first output.
|
||||
|
||||
Parse large traces only after inference timing has finished. The resource
|
||||
analyzer streams trace JSON, separates summed event duration from interval
|
||||
union, and excludes telemetry gaps over five seconds from energy integration.
|
||||
Actual device placement, fallback, transfer and synchronization conclusions
|
||||
must be supported by the trace/runtime records, not merely the intended plan.
|
||||
The TTS diagnostic starts each stage with a distinct profiler prefix because
|
||||
both workers have rank 0 and the current runtime otherwise overwrites their
|
||||
shared trace filename. Both stages are active during traced requests. Sequential
|
||||
stop/export RPCs can extend later-stage trace windows with idle/export time;
|
||||
trace-window length is not model execution time or GPU utilization.
|
||||
Startup summaries retain both constructor time and inclusive host-launch to
|
||||
first warmup submission/output. The latter includes artifact hashing, plan
|
||||
construction and imports; constructor timing alone excludes that preparation.
|
||||
|
||||
Keep compile/load/run failures and their exact configurations. Before declaring
|
||||
a pairing qualified, review model-specific reference quality, complete declared
|
||||
modalities, state/stream correctness, memory admission, executed placement and
|
||||
the performance protocol. Missing artifacts, backends, device access, sensors
|
||||
or reference suites require explicit reasons and repair actions.
|
||||
|
||||
After every writer exits, archive evidence with reversible compression of large
|
||||
uncompressed files and an original/stored byte-hash manifest:
|
||||
|
||||
```bash
|
||||
python benchmarks/edge_harness/archive_profiles.py create /path/to/run-root /path/to/new-archive
|
||||
python benchmarks/edge_harness/archive_profiles.py verify /path/to/new-archive
|
||||
python benchmarks/edge_harness/archive_profiles.py restore /path/to/new-archive /path/to/new-run-root
|
||||
```
|
||||
|
||||
Restore before using original report-relative paths for compressed artifacts.
|
||||
The utility does not rewrite raw reports. Integrity verification establishes
|
||||
that archived bytes match, not that a model passes its qualification gates.
|
||||
@@ -0,0 +1,299 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""Summarize raw host telemetry and traces without adding overlapping timings."""
|
||||
|
||||
import argparse
|
||||
import gzip
|
||||
import json
|
||||
import math
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
from summarize_e2e_profiles import read_lines, stats
|
||||
|
||||
|
||||
def interval_union(intervals):
|
||||
total = 0.0
|
||||
end = None
|
||||
for start, stop in sorted(intervals):
|
||||
if stop <= start:
|
||||
continue
|
||||
total += stop - start if end is None or start >= end else max(0, stop - end)
|
||||
end = stop if end is None else max(end, stop)
|
||||
return total
|
||||
|
||||
|
||||
def trace_events(path):
|
||||
"""Read one event at a time, avoiding a multi-GB decoded trace document."""
|
||||
opener = gzip.open if path.suffix == ".gz" else open
|
||||
with opener(path, "rt", encoding="utf-8") as stream:
|
||||
buffer = ""
|
||||
while True:
|
||||
block = stream.read(65536)
|
||||
if not block:
|
||||
raise ValueError("No traceEvents array")
|
||||
buffer += block
|
||||
match = re.search(r'"traceEvents"\s*:\s*\[', buffer)
|
||||
if match:
|
||||
buffer = buffer[match.end() :]
|
||||
break
|
||||
if len(buffer) > 8 * 1024 * 1024:
|
||||
raise ValueError("Trace header exceeds 8 MiB")
|
||||
decoder = json.JSONDecoder()
|
||||
while True:
|
||||
buffer = buffer.lstrip(" \t\r\n,")
|
||||
if buffer.startswith("]"):
|
||||
return
|
||||
try:
|
||||
event, end = decoder.raw_decode(buffer)
|
||||
except json.JSONDecodeError:
|
||||
block = stream.read(65536)
|
||||
if not block:
|
||||
raise ValueError("Truncated traceEvents array") from None
|
||||
buffer += block
|
||||
if len(buffer) > 16 * 1024 * 1024:
|
||||
raise ValueError("One trace event exceeds 16 MiB") from None
|
||||
continue
|
||||
buffer = buffer[end:]
|
||||
yield event
|
||||
|
||||
|
||||
def trace_summary(path):
|
||||
categories, ops = defaultdict(list), defaultdict(list)
|
||||
for event in trace_events(path):
|
||||
if event.get("ph") != "X" or not isinstance(event.get("dur"), (int, float)):
|
||||
continue
|
||||
categories[event.get("cat", "uncategorized")].append((event["ts"], event["ts"] + event["dur"]))
|
||||
ops[(event.get("cat", ""), event.get("name", ""))].append(float(event["dur"]))
|
||||
return {
|
||||
"source": str(path),
|
||||
"scope": "one process trace; event duration sums overlap and are not E2E time",
|
||||
"categories": {
|
||||
name: {
|
||||
"events": len(group),
|
||||
"duration_sum_us": sum(b - a for a, b in group),
|
||||
"busy_union_us": interval_union(group),
|
||||
}
|
||||
for name, group in categories.items()
|
||||
},
|
||||
"largest_ops_by_duration_sum": sorted(
|
||||
[
|
||||
{"category": cat, "name": name, "duration_sum_us": sum(values), "duration_us": stats(values)}
|
||||
for (cat, name), values in ops.items()
|
||||
],
|
||||
key=lambda r: r["duration_sum_us"],
|
||||
reverse=True,
|
||||
)[:40],
|
||||
}
|
||||
|
||||
|
||||
def telemetry_summary(path, start=None, stop=None):
|
||||
rows = [
|
||||
r for r in read_lines(path) if (start is None or r["unix"] >= start) and (stop is None or r["unix"] <= stop)
|
||||
]
|
||||
series = defaultdict(list)
|
||||
power = []
|
||||
for row in rows:
|
||||
series["host_available_bytes"].append(row["host_memory"]["available"])
|
||||
series["host_used_bytes"].append(row["host_memory"]["used"])
|
||||
series["host_cpu_percent"].append(row.get("host_cpu_percent"))
|
||||
fields = row.get("gpu_csv", "").split(",")
|
||||
if len(fields) != 10:
|
||||
continue
|
||||
for index, name in [
|
||||
(2, "gpu_memory_mib"),
|
||||
(4, "gpu_temperature_c"),
|
||||
(5, "gpu_power_w"),
|
||||
(6, "gpu_sm_clock_mhz"),
|
||||
(7, "gpu_mem_clock_mhz"),
|
||||
(8, "gpu_utilization_percent"),
|
||||
]:
|
||||
try:
|
||||
value = float(fields[index])
|
||||
except ValueError:
|
||||
continue
|
||||
if not math.isfinite(value):
|
||||
continue
|
||||
series[name].append(value)
|
||||
if index == 5:
|
||||
power.append((row["unix"], value))
|
||||
gaps = [b["unix"] - a["unix"] for a, b in zip(rows, rows[1:])]
|
||||
intervals = [(a, b) for a, b in zip(power, power[1:]) if 0 < b[0] - a[0] <= 5]
|
||||
energy = sum((b[0] - a[0]) * (a[1] + b[1]) / 2 for a, b in intervals)
|
||||
return {
|
||||
"source": str(path),
|
||||
"samples": len(rows),
|
||||
"span_s": rows[-1]["unix"] - rows[0]["unix"] if len(rows) >= 2 else None,
|
||||
"requested_window": {"start": start, "stop": stop},
|
||||
"sampling_gap_s": stats(gaps),
|
||||
"gaps_over_5s": sum(g > 5 for g in gaps),
|
||||
"metrics": {key: stats(values) for key, values in series.items()},
|
||||
"ac_states": sorted({r["power"]["ACLineStatus"] for r in rows if "power" in r}),
|
||||
"whole_gpu_energy_j_over_observed_intervals": energy if intervals else None,
|
||||
"energy_observed_duration_s": sum(b[0] - a[0] for a, b in intervals),
|
||||
"energy_scope": (
|
||||
"Whole NVIDIA GPU incl. other processes; trapezoids skip gaps >5s; not whole-system, CPU or NPU energy."
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description=__doc__)
|
||||
p.add_argument("--runs", type=Path, required=True)
|
||||
p.add_argument("--out", type=Path, required=True)
|
||||
p.add_argument(
|
||||
"--skip-traces", action="store_true", help="Summarize telemetry only while inference timing is still running."
|
||||
)
|
||||
a = p.parse_args()
|
||||
result = {"telemetry": {}, "traces": [], "trace_analysis": "deferred" if a.skip_traces else "requested"}
|
||||
for host in sorted(a.runs.glob("*-host")):
|
||||
raw = host / "telemetry.jsonl"
|
||||
if not raw.is_file():
|
||||
continue
|
||||
name = host.name.removesuffix("-host")
|
||||
record = {"whole_run": telemetry_summary(raw)}
|
||||
report_path = a.runs / name / "report.json"
|
||||
if report_path.is_file():
|
||||
report = json.loads(report_path.read_text(encoding="utf-8"))
|
||||
host_report_path = host / "status.json"
|
||||
host_report = json.loads(host_report_path.read_text(encoding="utf-8")) if host_report_path.is_file() else {}
|
||||
rows = read_lines(a.runs / name / "requests.jsonl")
|
||||
warmups = [r for r in rows if r.get("phase") == "warmup"]
|
||||
launch, report_start = host_report.get("start_unix"), report.get("start_unix")
|
||||
log_path = host / "command.log"
|
||||
timing_lines = []
|
||||
log_lines = []
|
||||
if log_path.is_file():
|
||||
log_lines = log_path.read_text(encoding="utf-8", errors="replace").splitlines()
|
||||
timing_lines = [
|
||||
line
|
||||
for line in log_lines
|
||||
if any(
|
||||
marker in line
|
||||
for marker in (
|
||||
"Loading model weights took",
|
||||
"Model loading took",
|
||||
"init engine (",
|
||||
"torch.compile took",
|
||||
"Captured talker_mtp graphs",
|
||||
"engine startup completed",
|
||||
)
|
||||
)
|
||||
]
|
||||
record["lifecycle_log_observations"] = {
|
||||
"scope": "Counts are log lines, not request counts or a correctness verdict. Inspect source logs.",
|
||||
"markers": {},
|
||||
}
|
||||
for marker in ("Dropping output for unknown req", "force killing remaining process "):
|
||||
matches = [line for line in log_lines if marker in line]
|
||||
record["lifecycle_log_observations"]["markers"][marker] = {
|
||||
"count": len(matches),
|
||||
"examples": matches[:3] + matches[-3:] if len(matches) > 6 else matches,
|
||||
}
|
||||
first_submit = warmups[0].get("submitted_unix") if warmups else None
|
||||
first_latency = warmups[0].get("ttft_s") if warmups else None
|
||||
if first_latency is None and warmups and warmups[0].get("ttfa_ms") is not None:
|
||||
first_latency = warmups[0]["ttfa_ms"] / 1000
|
||||
record["startup"] = {
|
||||
"cache_condition": report.get("cache_condition", "See source report"),
|
||||
"constructor_s": report.get("startup_s"),
|
||||
"host_launch_to_benchmark_report_start_s": report_start - launch if launch and report_start else None,
|
||||
"host_launch_to_first_request_s": first_submit - launch if first_submit and launch else None,
|
||||
"host_launch_to_first_output_s": (
|
||||
first_submit - launch + first_latency
|
||||
if first_submit and launch and first_latency is not None
|
||||
else None
|
||||
),
|
||||
"inclusive_startup_scope": (
|
||||
"Host launch through first warmup submission/output includes imports, artifact hashing, "
|
||||
"plan construction and engine startup; uses recorded host/engine wall timestamps. "
|
||||
"Constructor timing alone excludes preparation before the constructor."
|
||||
),
|
||||
"pre_constructor_scope": (
|
||||
"Host launch to report creation includes Python/import/preparation work; "
|
||||
"not isolated OS process creation."
|
||||
),
|
||||
"first_warmup": {
|
||||
key: warmups[0].get(key)
|
||||
for key in (
|
||||
"request_id",
|
||||
"length_band",
|
||||
"concurrency",
|
||||
"wall_s",
|
||||
"ttft_s",
|
||||
"total_wall_s",
|
||||
"ttfa_ms",
|
||||
"rtf_total",
|
||||
)
|
||||
}
|
||||
if warmups
|
||||
else None,
|
||||
"runtime_loading_compilation_evidence": timing_lines,
|
||||
"scope": (
|
||||
"Runtime-reported component lines retain original boundaries; "
|
||||
"do not sum parallel-stage times into startup latency."
|
||||
),
|
||||
}
|
||||
start, duration = report.get("sustained_start_unix"), report.get("sustained_wall_s")
|
||||
if start and duration:
|
||||
record["sustained"] = telemetry_summary(raw, start, start + duration)
|
||||
record["sustained_first_5min"] = telemetry_summary(raw, start, start + 300)
|
||||
record["sustained_last_5min"] = telemetry_summary(raw, start + duration - 300, start + duration)
|
||||
record["sustained_last_60s"] = telemetry_summary(raw, start + duration - 60, start + duration)
|
||||
requests = [r for r in rows if r.get("phase") == "sustained"]
|
||||
record["sustained_request_summary"] = {
|
||||
"n": len(requests),
|
||||
"rtf_above_one_requests": sum((r.get("rtf_total") or 0) > 1 for r in requests),
|
||||
"simulated_playback_deficit_requests": sum((r.get("stall_at_ttfa_ms") or 0) > 0 for r in requests),
|
||||
"rtf_total": stats([r.get("rtf_total") for r in requests]),
|
||||
"scope": "All sustained requests; timing/real-time gates are separate from successful completion.",
|
||||
}
|
||||
record["sustained_request_trends"] = {}
|
||||
for label, begin, end in [
|
||||
("first_5min", start, start + 300),
|
||||
("last_5min", start + duration - 300, start + duration),
|
||||
("last_60s", start + duration - 60, start + duration),
|
||||
]:
|
||||
window = [r for r in requests if begin <= r.get("submitted_unix", -1) < end]
|
||||
record["sustained_request_trends"][label] = {
|
||||
"n": len(window),
|
||||
"window_basis": "request submission time",
|
||||
"metrics": {
|
||||
metric: stats([r.get(metric) for r in window])
|
||||
for metric in (
|
||||
"wall_s",
|
||||
"ttft_s",
|
||||
"decode_tok_per_s",
|
||||
"total_wall_s",
|
||||
"ttfa_ms",
|
||||
"rtf_total",
|
||||
"stall_at_ttfa_ms",
|
||||
)
|
||||
},
|
||||
}
|
||||
result["telemetry"][name] = record
|
||||
for path in [] if a.skip_traces else sorted(a.runs.glob("*trace*/traces/**/*")):
|
||||
if path.is_file() and (path.name.endswith(".json") or path.name.endswith(".json.gz")):
|
||||
report_path = a.runs / path.relative_to(a.runs).parts[0] / "report.json"
|
||||
if (
|
||||
not report_path.is_file()
|
||||
or json.loads(report_path.read_text(encoding="utf-8")).get("status") != "completed"
|
||||
):
|
||||
result["traces"].append(
|
||||
{
|
||||
"source": str(path),
|
||||
"status": "not_analyzed",
|
||||
"reason": "Diagnostic has no completed report; trace may be incomplete.",
|
||||
}
|
||||
)
|
||||
continue
|
||||
try:
|
||||
result["traces"].append(trace_summary(path))
|
||||
except Exception as error:
|
||||
result["traces"].append({"source": str(path), "error": repr(error)})
|
||||
a.out.write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"Summarized {len(result['telemetry'])} telemetry runs and {len(result['traces'])} traces")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,92 @@
|
||||
# Android agent toolkit for Spark-X2.5
|
||||
|
||||
Lets a text-only model operate a phone: observe the accessibility tree, call
|
||||
one tool, execute it on the device, observe again.
|
||||
|
||||
ui_tree.py uiautomator XML -> indexed element list -> back to a tap point
|
||||
device.py AdbDevice (a real phone) | SimulatedDevice (scripted, in-process)
|
||||
executor.py one tool call -> one device action, errors as sentences
|
||||
tool_parse.py recover a call from whatever shape the model emitted
|
||||
agent.py the loop: budget, no-op detection, undo detection, fallbacks
|
||||
run_episode.py CLI
|
||||
|
||||
## Running it
|
||||
|
||||
Serve the model (Spark emits GLM-4.5 tool format, so the stock parsers apply):
|
||||
|
||||
vllm serve <model> --port 8077 --enable-auto-tool-choice \
|
||||
--tool-call-parser glm45 --reasoning-parser glm45
|
||||
|
||||
Then:
|
||||
|
||||
python run_episode.py --task "Turn on Wi-Fi." --device sim # no phone needed
|
||||
python run_episode.py --task "Turn on Wi-Fi." --device adb # a real phone
|
||||
|
||||
`pytest test_android_agent.py` runs 21 tests with no phone and no server.
|
||||
|
||||
## What the loop does that a plain ReAct loop does not
|
||||
|
||||
Each one is a response to a measured failure of *this* model, not generic
|
||||
scaffolding:
|
||||
|
||||
- **Retry without thinking on an empty reply.** The model can reason past its
|
||||
token budget without closing `<think>`; vLLM's reasoning parser only emits
|
||||
content once the block closes, so the reply arrives empty with no tool call.
|
||||
Raising the cap buys a longer silence. A non-thinking retry costs ~0.6 s.
|
||||
- **Report actions that changed nothing.** "the screen did not change" is
|
||||
information the model cannot otherwise have.
|
||||
- **Report and stop on self-undo.** Tapping a switch that is already on undoes
|
||||
the task. Each tap really does change the screen, so a no-change check
|
||||
cannot see it; the loop watches for the *same* action returning the screen to
|
||||
its previous state. Deliberately narrow -- opening a submenu and pressing
|
||||
back revisits a screen and must not trip it.
|
||||
- **Recover malformed tool calls.** See below.
|
||||
- **A step budget**, so a confused episode ends instead of running forever.
|
||||
|
||||
The loop never decides a task is finished. It reports what happened and lets
|
||||
the model call `task_complete`; a harness that completes tasks on the model's
|
||||
behalf measures itself.
|
||||
|
||||
## Measured: which build can actually finish a task
|
||||
|
||||
Simulated phone, one run per cell, `max_steps` 10, Xeon 8480C 24 threads.
|
||||
|
||||
| build | decode | "Turn on Wi-Fi." | "Set an alarm for 7:30 AM." |
|
||||
|---|---|---|---|
|
||||
| bf16 | 41.0 tok/s | done in 4 steps | wrong app (Settings, not Clock), toggles Airplane mode, stuck |
|
||||
| **W4A16 g128** | 80.0 tok/s | done in 4 steps | right app, full navigation (Clock -> Alarm -> Add -> Save), then no tool call |
|
||||
| W4A8 g128 | 86.6 tok/s | turns Wi-Fi on, then toggles it off again (2 runs, same failure) | taps "Phone" twice, reaches Alarm, then loops |
|
||||
|
||||
Two things fall out, and both matter more than the throughput numbers:
|
||||
|
||||
**Navigation survives quantization; completion does not.** Every build walks
|
||||
home -> Settings -> Network -> Wi-Fi correctly. Only some of them notice that
|
||||
the switch now reads `checked=true` and stop. W4A8 -- the fastest build, and
|
||||
the one the speed-first selector recommends -- turns Wi-Fi on and then taps it
|
||||
off again, ending with the task undone.
|
||||
|
||||
**The fidelity number had a task-level meaning all along.** W4A8 reproduced
|
||||
1/12 greedy prompts against its own bf16 and W4A16 2/12
|
||||
(analysis/spark_edge_support.md 2c). That looked like a small difference on a
|
||||
proxy metric. It is the difference between finishing and not.
|
||||
|
||||
So for agentic use the recommendation is **W4A16**, not W4A8: 8% slower, and
|
||||
it is the only 4-bit build here that completed anything. `weight_path.py`'s
|
||||
`priority="fidelity"` selects it.
|
||||
|
||||
## Honest limits
|
||||
|
||||
- **No phone was involved.** This host has no `adb`, no emulator and no
|
||||
`/dev/kvm`. The simulator emits real uiautomator XML, so the parser, the
|
||||
index-to-coordinate mapping and the stopping rules are exercised on the path
|
||||
hardware drives -- but whether a real Settings app is laid out the way these
|
||||
fixtures assume is untested.
|
||||
- **Two tasks, one run each.** Enough to show a failure mode reproduces, not
|
||||
enough to rank builds by success rate.
|
||||
- **Stock `glm45` does not always parse Spark.** On 4 of 5 screens it does. On
|
||||
the Wi-Fi toggle screen the model emitted
|
||||
`[tap]\n{"tool": "tap", "parameters": {"index": 1}` -- unterminated, and
|
||||
`tool_calls` came back empty. `tool_parse.py` recovers that and reports every
|
||||
recovery, because an agent that silently repairs its model's output hides
|
||||
regressions in that model. The earlier claim that the stock parsers work
|
||||
"as-is" is true most of the time, which is not the same thing.
|
||||
@@ -0,0 +1,152 @@
|
||||
"""Android control action space for a text-only LLM agent.
|
||||
|
||||
The tool surface mirrors what the mainstream ADB-based harnesses expose
|
||||
(droidrun/mobilerun's Portal tools, ghost-in-the-droid's touch/see tools,
|
||||
AndroidWorld's `JSONAction`), so an agent written against these schemas can be
|
||||
pointed at any of them. Every action is expressed over the accessibility tree
|
||||
rather than pixel coordinates, because Spark-X2.5 is a text-only model: it
|
||||
never sees a screenshot, it sees the uiautomator dump.
|
||||
|
||||
`ADB_TEMPLATES` gives the literal `adb` invocation each tool maps to, which is
|
||||
what a driver executes against a real device.
|
||||
"""
|
||||
|
||||
TOOLS = [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "tap",
|
||||
"description": (
|
||||
"Tap a UI element. Use the element's index exactly as shown in "
|
||||
"the accessibility tree."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"index": {
|
||||
"type": "integer",
|
||||
"description": "Index of the element in the tree",
|
||||
}
|
||||
},
|
||||
"required": ["index"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "type_text",
|
||||
"description": (
|
||||
"Type text into a focused input field. Tap the field first."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"index": {"type": "integer", "description": "Index of the input field"},
|
||||
"text": {"type": "string", "description": "Text to enter"},
|
||||
},
|
||||
"required": ["index", "text"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "swipe",
|
||||
"description": (
|
||||
"Scroll the screen. The direction is where the content should "
|
||||
"move: use 'down' to see what is further down the page."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"direction": {
|
||||
"type": "string",
|
||||
"enum": ["up", "down", "left", "right"],
|
||||
}
|
||||
},
|
||||
"required": ["direction"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "press_key",
|
||||
"description": "Press a hardware or system key.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"enum": ["back", "home", "enter", "delete", "recent"],
|
||||
}
|
||||
},
|
||||
"required": ["key"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "open_app",
|
||||
"description": "Launch an app by its visible name.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {"name": {"type": "string"}},
|
||||
"required": ["name"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "task_complete",
|
||||
"description": (
|
||||
"Call when the user's request has been fully carried out."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"summary": {"type": "string", "description": "What was done"}
|
||||
},
|
||||
"required": ["summary"],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
# How each tool becomes a real device command. `{bounds}` is filled from the
|
||||
# element's centre point in the accessibility tree.
|
||||
ADB_TEMPLATES = {
|
||||
"tap": "adb shell input tap {x} {y}",
|
||||
"type_text": "adb shell input text {text_escaped}",
|
||||
"swipe": "adb shell input swipe {x1} {y1} {x2} {y2} 300",
|
||||
"press_key": "adb shell input keyevent {keycode}",
|
||||
"open_app": "adb shell monkey -p {package} -c android.intent.category.LAUNCHER 1",
|
||||
}
|
||||
|
||||
KEYCODES = {
|
||||
"back": "KEYCODE_BACK",
|
||||
"home": "KEYCODE_HOME",
|
||||
"enter": "KEYCODE_ENTER",
|
||||
"delete": "KEYCODE_DEL",
|
||||
"recent": "KEYCODE_APP_SWITCH",
|
||||
}
|
||||
|
||||
SYSTEM_PROMPT = (
|
||||
"You control an Android phone. At each step you are given the current "
|
||||
"screen as an accessibility tree: one line per element, with its index, "
|
||||
"type, text and whether it is clickable. Call exactly one tool per step to "
|
||||
"make progress on the user's task. Refer to elements only by the index "
|
||||
"shown.\n"
|
||||
# Both rules below exist because the model failed them in measurement: it
|
||||
# tapped a Wi-Fi switch that already read checked=true, turning it back
|
||||
# off, and never called task_complete. A switch's state is on the screen,
|
||||
# so the rule can be stated in terms of what it can see.
|
||||
"A switch or checkbox shows its state as checked=true or checked=false. "
|
||||
"Tapping it flips that state.\n"
|
||||
"Before acting, check whether the screen already shows what the task "
|
||||
"asked for. If it does, call task_complete immediately and do not tap "
|
||||
"anything else -- acting again would undo it."
|
||||
)
|
||||
@@ -0,0 +1,271 @@
|
||||
"""The observe-decide-act loop.
|
||||
|
||||
Three things in here are not generic agent scaffolding; they are direct
|
||||
responses to how this model failed when it was measured one step at a time
|
||||
(analysis/spark_edge_support.md section 5):
|
||||
|
||||
* **A step budget, not a bigger token cap.** On the one genuinely ambiguous
|
||||
screen the model reasoned past 1200 tokens without closing `<think>`, and
|
||||
vLLM's reasoning parser only emits content once the block closes -- so the
|
||||
reply came back empty, with no tool call at all. Raising the cap buys a
|
||||
longer silence. The loop instead retries that step with thinking disabled,
|
||||
which measured 0.61 s against 8.9 s, and takes the weaker-but-present answer.
|
||||
|
||||
* **Detecting the no-op.** The clearest wrong action was tapping a Wi-Fi
|
||||
switch that was already on -- undoing the task it had just completed. An
|
||||
action that leaves the screen signature unchanged is reported back as such,
|
||||
because "nothing happened" is information the model cannot otherwise have.
|
||||
|
||||
* **Repeat suppression.** Two identical actions on an identical screen means
|
||||
stuck, and a third will not help. The loop says so in the transcript and
|
||||
stops, rather than burning the budget.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from urllib import error as urlerror
|
||||
from urllib import request as urlrequest
|
||||
|
||||
from action_space import SYSTEM_PROMPT, TOOLS
|
||||
from device import Device
|
||||
from executor import ActionResult, execute
|
||||
from tool_parse import extract_tool_call
|
||||
from ui_tree import Element, parse_ui_dump, render_tree, screen_signature
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentConfig:
|
||||
base_url: str = "http://127.0.0.1:8077/v1"
|
||||
model: str = "XHToken/Spark-X2.5-1.7B"
|
||||
max_steps: int = 12
|
||||
think: bool = True
|
||||
think_fallback: bool = True
|
||||
"""On an empty reply, retry the step without thinking rather than fail."""
|
||||
max_tokens: int = 1024
|
||||
temperature: float = 0.0
|
||||
timeout: float = 900.0
|
||||
history: int = 6
|
||||
retries: int = 3
|
||||
"""Transient HTTP failures retried before a step is abandoned."""
|
||||
retry_backoff_s: float = 2.0
|
||||
"""Recent actions shown back to the model."""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Step:
|
||||
n: int
|
||||
screen: str
|
||||
tool: str | None
|
||||
args: dict
|
||||
result: ActionResult | None
|
||||
latency_s: float
|
||||
thinking: bool
|
||||
note: str = ""
|
||||
parsed_via: str = "tool_calls"
|
||||
"""Which parser recovered the call; anything but tool_calls is worth seeing."""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Episode:
|
||||
task: str
|
||||
steps: list[Step] = field(default_factory=list)
|
||||
done: bool = False
|
||||
summary: str = ""
|
||||
stop_reason: str = ""
|
||||
|
||||
@property
|
||||
def n_steps(self) -> int:
|
||||
return len(self.steps)
|
||||
|
||||
def transcript(self) -> str:
|
||||
lines = [f"task: {self.task}"]
|
||||
for s in self.steps:
|
||||
call = f"{s.tool}({json.dumps(s.args, ensure_ascii=False)})" if s.tool else "(no tool call)"
|
||||
outcome = s.result.message if s.result else s.note
|
||||
if s.parsed_via not in ("tool_calls", "none"):
|
||||
outcome += f" [recovered via {s.parsed_via}]"
|
||||
lines.append(f" {s.n:2d}. {call:48s} -> {outcome} [{s.latency_s:.2f}s]")
|
||||
lines.append(f"stopped: {self.stop_reason}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
class ChatError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def chat(cfg: AgentConfig, messages: list[dict], *, think: bool) -> tuple[dict, float]:
|
||||
payload = {
|
||||
"model": cfg.model,
|
||||
"messages": messages,
|
||||
"tools": TOOLS,
|
||||
"tool_choice": "auto",
|
||||
"temperature": cfg.temperature,
|
||||
"max_tokens": cfg.max_tokens,
|
||||
}
|
||||
if not think:
|
||||
# Spark's chat template opens <think> by default; closing it up front
|
||||
# is what makes the model answer directly.
|
||||
payload["chat_template_kwargs"] = {"enable_thinking": False}
|
||||
req = urlrequest.Request(
|
||||
f"{cfg.base_url}/chat/completions",
|
||||
data=json.dumps(payload).encode(),
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
t0 = time.perf_counter()
|
||||
last: Exception | None = None
|
||||
for attempt in range(max(1, cfg.retries)):
|
||||
try:
|
||||
with urlrequest.urlopen(req, timeout=cfg.timeout) as r:
|
||||
return json.loads(r.read()), time.perf_counter() - t0
|
||||
except (urlerror.URLError, TimeoutError, json.JSONDecodeError) as exc:
|
||||
# A phone task is a dozen round trips; one dropped connection
|
||||
# should cost a retry, not the episode.
|
||||
last = exc
|
||||
if attempt + 1 < max(1, cfg.retries):
|
||||
time.sleep(cfg.retry_backoff_s * (attempt + 1))
|
||||
raise ChatError(
|
||||
f"{cfg.base_url} failed after {cfg.retries} attempts: {last}") from last
|
||||
|
||||
|
||||
def wait_for_server(cfg: AgentConfig, timeout_s: float = 300.0) -> bool:
|
||||
"""Block until the endpoint serves a model list, or give up.
|
||||
|
||||
Starting an episode against a server that is still loading produces a
|
||||
confusing transcript full of connection errors; this turns that into one
|
||||
clear wait.
|
||||
"""
|
||||
deadline = time.monotonic() + timeout_s
|
||||
while time.monotonic() < deadline:
|
||||
try:
|
||||
with urlrequest.urlopen(f"{cfg.base_url}/models", timeout=5) as r:
|
||||
if b'"id"' in r.read():
|
||||
return True
|
||||
except Exception:
|
||||
time.sleep(2.0)
|
||||
return False
|
||||
|
||||
|
||||
def parse_response(response: dict):
|
||||
"""The one call to act on, from whichever shape the model used.
|
||||
|
||||
Spark does not always stay in GLM-4.5 tool format -- see tool_parse -- and
|
||||
on a phone a dropped step is a stalled task, so the fallbacks matter.
|
||||
"""
|
||||
try:
|
||||
message = response["choices"][0]["message"]
|
||||
except (KeyError, IndexError):
|
||||
message = {}
|
||||
return extract_tool_call(message)
|
||||
|
||||
|
||||
def first_tool_call(response: dict) -> tuple[str | None, dict]:
|
||||
"""Name and arguments only, for callers that do not care how it parsed."""
|
||||
parsed = parse_response(response)
|
||||
return parsed.name, parsed.args
|
||||
|
||||
|
||||
def _user_message(task: str, screen: str, log: list[str], history: int) -> str:
|
||||
parts = [f"Task: {task}", "", "Current screen:", screen]
|
||||
if log:
|
||||
parts += ["", "Actions so far:"] + [f" {line}" for line in log[-history:]]
|
||||
parts += ["", "Choose the next action. Call exactly one tool."]
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
def observe(device: Device) -> tuple[list[Element], str, str]:
|
||||
elements = parse_ui_dump(device.dump())
|
||||
return elements, render_tree(elements), screen_signature(elements)
|
||||
|
||||
|
||||
def run_episode(device: Device, task: str, cfg: AgentConfig | None = None) -> Episode:
|
||||
cfg = cfg or AgentConfig()
|
||||
episode = Episode(task=task)
|
||||
log: list[str] = []
|
||||
recent: list[tuple[str, str]] = [] # (action, screen signature before it)
|
||||
signature_before_last: str | None = None
|
||||
last_action: str | None = None
|
||||
oscillations = 0
|
||||
|
||||
for n in range(1, cfg.max_steps + 1):
|
||||
elements, screen, signature = observe(device)
|
||||
messages = [
|
||||
{"role": "system", "content": SYSTEM_PROMPT},
|
||||
{"role": "user",
|
||||
"content": _user_message(task, screen, log, cfg.history)},
|
||||
]
|
||||
|
||||
thinking = cfg.think
|
||||
response, latency = chat(cfg, messages, think=thinking)
|
||||
parsed = parse_response(response)
|
||||
tool, args = parsed.name, parsed.args
|
||||
|
||||
if tool is None and cfg.think_fallback and thinking:
|
||||
# The measured failure: reasoning never closed, so the parser
|
||||
# emitted nothing. A second, non-thinking pass is worth ~0.6 s.
|
||||
thinking = False
|
||||
retry, retry_latency = chat(cfg, messages, think=False)
|
||||
latency += retry_latency
|
||||
parsed = parse_response(retry)
|
||||
tool, args = parsed.name, parsed.args
|
||||
|
||||
if tool is None:
|
||||
episode.steps.append(Step(n, screen, None, {}, None, latency, thinking,
|
||||
note="model returned no tool call",
|
||||
parsed_via=parsed.source))
|
||||
episode.stop_reason = "no tool call, even without thinking"
|
||||
return episode
|
||||
|
||||
if (tool_key := f"{tool}:{json.dumps(args, sort_keys=True)}") and \
|
||||
recent.count((tool_key, signature)) >= 2:
|
||||
episode.steps.append(Step(n, screen, tool, args, None, latency, thinking,
|
||||
note="repeated a no-op action",
|
||||
parsed_via=parsed.source))
|
||||
episode.stop_reason = (
|
||||
f"stuck: {tool} repeated on an unchanged screen"
|
||||
)
|
||||
return episode
|
||||
recent.append((tool_key, signature))
|
||||
|
||||
result = execute(tool, args, elements, device)
|
||||
if result.ok and not result.done:
|
||||
_, _, after = observe(device)
|
||||
if after == signature:
|
||||
# Say so out loud: the model has no other way to learn that
|
||||
# its action changed nothing.
|
||||
result = ActionResult(True, result.message + " -- the screen did not change",
|
||||
action=result.action)
|
||||
elif tool_key == last_action and after == signature_before_last:
|
||||
# Oscillation: the *same* action, undoing what it just did --
|
||||
# the measured failure, tapping a switch off and on forever.
|
||||
# It hides from the no-change check because each individual tap
|
||||
# really does change the screen. Deliberately narrow: revisiting
|
||||
# a screen by other means (open a submenu, press back) is normal
|
||||
# navigation and must not trip this.
|
||||
result = ActionResult(
|
||||
True,
|
||||
result.message + " -- that undid your previous action; the "
|
||||
"setting is now back where it started",
|
||||
action=result.action,
|
||||
)
|
||||
oscillations += 1
|
||||
if oscillations >= 2:
|
||||
episode.steps.append(Step(n, screen, tool, args, result, latency,
|
||||
thinking, parsed_via=parsed.source))
|
||||
episode.stop_reason = "stuck: repeatedly undoing its own action"
|
||||
return episode
|
||||
signature_before_last, last_action = signature, tool_key
|
||||
episode.steps.append(Step(n, screen, tool, args, result, latency, thinking,
|
||||
parsed_via=parsed.source))
|
||||
log.append(f"{tool} -> {result.message}")
|
||||
|
||||
if result.done:
|
||||
episode.done = True
|
||||
episode.summary = result.summary
|
||||
episode.stop_reason = "task_complete"
|
||||
return episode
|
||||
|
||||
episode.stop_reason = f"step budget exhausted ({cfg.max_steps})"
|
||||
return episode
|
||||
@@ -0,0 +1,354 @@
|
||||
"""Where the agent's actions actually land.
|
||||
|
||||
Two backends behind one interface. `AdbDevice` talks to a phone over `adb`.
|
||||
`SimulatedDevice` runs a small scripted phone in-process, and exists for a
|
||||
reason beyond convenience: no Android device, emulator or `/dev/kvm` is
|
||||
reachable from the host this was built on, so without it the loop, the tool
|
||||
executor and the stopping rules would all be untested code shipped on a
|
||||
promise.
|
||||
|
||||
The simulator emits **real uiautomator XML**, not pre-rendered text, so the
|
||||
parser, the index-to-coordinate mapping and the screen-change detection are
|
||||
exercised on the same path a phone would drive. What it cannot test is
|
||||
whether a real Settings app is laid out the way the fixtures assume; that is
|
||||
stated in the report rather than hidden.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
from xml.sax.saxutils import escape as _xml_escape
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Callable, Protocol
|
||||
|
||||
KEYCODES = {
|
||||
"back": "KEYCODE_BACK",
|
||||
"home": "KEYCODE_HOME",
|
||||
"enter": "KEYCODE_ENTER",
|
||||
"delete": "KEYCODE_DEL",
|
||||
"recent": "KEYCODE_APP_SWITCH",
|
||||
}
|
||||
|
||||
|
||||
class Device(Protocol):
|
||||
def dump(self) -> str: ...
|
||||
def tap(self, x: int, y: int) -> None: ...
|
||||
def input_text(self, text: str) -> None: ...
|
||||
def swipe(self, x1: int, y1: int, x2: int, y2: int, ms: int = 300) -> None: ...
|
||||
def keyevent(self, key: str) -> None: ...
|
||||
def launch(self, app: str) -> None: ...
|
||||
def size(self) -> tuple[int, int]: ...
|
||||
|
||||
|
||||
class AdbError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class AdbDevice:
|
||||
"""A real phone over `adb`."""
|
||||
|
||||
def __init__(self, serial: str | None = None, adb: str = "adb",
|
||||
timeout: float = 30.0):
|
||||
if shutil.which(adb) is None:
|
||||
raise AdbError(
|
||||
f"{adb!r} is not on PATH. Install platform-tools and connect a "
|
||||
"device (`adb devices` should list it)."
|
||||
)
|
||||
self.adb, self.serial, self.timeout = adb, serial, timeout
|
||||
self._size: tuple[int, int] | None = None
|
||||
|
||||
def _run(self, *args: str, binary: bool = False):
|
||||
cmd = [self.adb] + (["-s", self.serial] if self.serial else []) + list(args)
|
||||
proc = subprocess.run(cmd, capture_output=True, timeout=self.timeout)
|
||||
if proc.returncode != 0:
|
||||
raise AdbError(f"{' '.join(cmd)} failed: {proc.stderr.decode(errors='replace')[:400]}")
|
||||
return proc.stdout if binary else proc.stdout.decode(errors="replace")
|
||||
|
||||
def dump(self) -> str:
|
||||
# exec-out keeps the XML on stdout instead of round-tripping through
|
||||
# /sdcard, which is both faster and avoids a writable-storage
|
||||
# assumption that does not hold on every device.
|
||||
out = self._run("exec-out", "uiautomator", "dump", "/dev/tty")
|
||||
start = out.find("<?xml")
|
||||
if start < 0:
|
||||
start = out.find("<hierarchy")
|
||||
if start < 0:
|
||||
raise AdbError(f"no UI hierarchy in dump output: {out[:200]!r}")
|
||||
end = out.rfind("</hierarchy>")
|
||||
return out[start:end + len("</hierarchy>")] if end > 0 else out[start:]
|
||||
|
||||
def tap(self, x: int, y: int) -> None:
|
||||
self._run("shell", "input", "tap", str(x), str(y))
|
||||
|
||||
def input_text(self, text: str) -> None:
|
||||
# `input text` takes a single token: spaces become %s and the shell
|
||||
# metacharacters have to go, or half the string is eaten.
|
||||
escaped = text.replace(" ", "%s")
|
||||
for ch in "()<>|;&*\\~\"'`$":
|
||||
escaped = escaped.replace(ch, "\\" + ch)
|
||||
self._run("shell", "input", "text", escaped)
|
||||
|
||||
def swipe(self, x1: int, y1: int, x2: int, y2: int, ms: int = 300) -> None:
|
||||
self._run("shell", "input", "swipe", str(x1), str(y1), str(x2), str(y2), str(ms))
|
||||
|
||||
def keyevent(self, key: str) -> None:
|
||||
code = KEYCODES.get(key, key)
|
||||
self._run("shell", "input", "keyevent", code)
|
||||
|
||||
def launch(self, app: str) -> None:
|
||||
"""Launch by package name, or by visible label via the launcher."""
|
||||
if "." in app:
|
||||
self._run("shell", "monkey", "-p", app, "-c",
|
||||
"android.intent.category.LAUNCHER", "1")
|
||||
return
|
||||
raise AdbError(
|
||||
f"open_app needs a package name, got {app!r}. Resolve the label to a "
|
||||
"package first (`adb shell pm list packages`) or tap its icon."
|
||||
)
|
||||
|
||||
def size(self) -> tuple[int, int]:
|
||||
if self._size is None:
|
||||
out = self._run("shell", "wm", "size")
|
||||
part = out.strip().rsplit(":", 1)[-1].strip()
|
||||
w, h = part.split("x")
|
||||
self._size = (int(w), int(h))
|
||||
return self._size
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Simulated phone
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class SimElement:
|
||||
label: str
|
||||
cls: str = "android.widget.TextView"
|
||||
clickable: bool = True
|
||||
checkable: bool = False
|
||||
checked: bool = False
|
||||
selected: bool = False
|
||||
editable: bool = False
|
||||
goto: str | None = None
|
||||
"""Screen this element navigates to when tapped."""
|
||||
toggles: str | None = None
|
||||
"""State key this element flips when tapped."""
|
||||
saves: str | None = None
|
||||
"""Record key. Tapping commits the current field values into
|
||||
``records[saves]`` and clears them -- the difference between typing a time
|
||||
and having an alarm, which the scored suite previously could not tell."""
|
||||
label_of: str | None = None
|
||||
"""State key whose value picks the label from ``labels``."""
|
||||
labels: tuple[str, str] = ("", "")
|
||||
"""(label when the state key is false, label when true)."""
|
||||
|
||||
def rendered_label(self, state: dict) -> str:
|
||||
if self.label_of:
|
||||
return self.labels[bool(state.get(self.label_of))]
|
||||
return self.label
|
||||
|
||||
|
||||
@dataclass
|
||||
class SimScreen:
|
||||
screen_id: str
|
||||
elements: list[SimElement]
|
||||
back: str | None = None
|
||||
dynamic: "Callable[[SimulatedDevice], list[SimElement]] | None" = None
|
||||
"""Rows derived from device state, appended after ``elements``. A saved
|
||||
alarm has to appear *on the screen*, or an oracle that reads the screen --
|
||||
which is the only kind a real phone can have -- cannot tell a committed
|
||||
alarm from a typed one."""
|
||||
|
||||
|
||||
@dataclass
|
||||
class SimulatedDevice:
|
||||
"""A scripted phone that speaks uiautomator XML.
|
||||
|
||||
Deliberately small. It is here to prove the loop terminates, recovers and
|
||||
stops -- not to model Android.
|
||||
"""
|
||||
|
||||
screens: dict[str, SimScreen]
|
||||
current: str
|
||||
state: dict[str, bool] = field(default_factory=dict)
|
||||
width: int = 1080
|
||||
height: int = 2400
|
||||
typed: list[str] = field(default_factory=list)
|
||||
actions: list[tuple[str, ...]] = field(default_factory=list)
|
||||
home: str = "home"
|
||||
focus: str | None = None
|
||||
"""Label of the focused text field; typing lands here."""
|
||||
fields: dict[str, str] = field(default_factory=dict)
|
||||
records: dict[str, list[dict]] = field(default_factory=dict)
|
||||
toggled: list[tuple[str, bool, bool]] = field(default_factory=list)
|
||||
"""(key, before, after) per switch tap. A task whose starting state is
|
||||
already correct is failed by a round trip, which final state cannot see."""
|
||||
|
||||
_ROW_H = 160
|
||||
_TOP = 200
|
||||
|
||||
def _visible(self) -> list[SimElement]:
|
||||
screen = self.screens[self.current]
|
||||
rows = list(screen.elements)
|
||||
if screen.dynamic:
|
||||
rows = [r for r in rows if not getattr(r, "_placeholder", False)]
|
||||
rows.extend(screen.dynamic(self))
|
||||
return rows
|
||||
|
||||
def _bounds(self, row: int) -> tuple[int, int, int, int]:
|
||||
y1 = self._TOP + row * self._ROW_H
|
||||
return 0, y1, self.width, y1 + self._ROW_H
|
||||
|
||||
def dump(self) -> str:
|
||||
rows = []
|
||||
for i, el in enumerate(self._visible()):
|
||||
x1, y1, x2, y2 = self._bounds(i)
|
||||
checked = el.checked
|
||||
if el.toggles:
|
||||
checked = self.state.get(el.toggles, el.checked)
|
||||
# uiautomator escapes attribute values, and labels really do
|
||||
# contain them -- "Network & internet" is on every Android
|
||||
# settings screen. Emitting raw breaks the parser on the second
|
||||
# screen of the first task.
|
||||
label = _xml_escape(el.rendered_label(self.state), {'"': """})
|
||||
rows.append(
|
||||
f' <node index="{i}" text="{label}" resource-id="" '
|
||||
f'class="{el.cls}" package="com.example.sim" content-desc="" '
|
||||
f'checkable="{str(el.checkable).lower()}" '
|
||||
f'checked="{str(checked).lower()}" '
|
||||
f'clickable="{str(el.clickable).lower()}" enabled="true" '
|
||||
f'focusable="{str(el.clickable).lower()}" focused="false" '
|
||||
f'scrollable="false" long-clickable="false" password="false" '
|
||||
f'selected="{str(el.selected).lower()}" '
|
||||
f'bounds="[{x1},{y1}][{x2},{y2}]" />'
|
||||
)
|
||||
body = "\n".join(rows)
|
||||
return (
|
||||
'<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||
f'<hierarchy rotation="0">\n{body}\n</hierarchy>'
|
||||
)
|
||||
|
||||
def _row_at(self, y: int) -> int | None:
|
||||
row = (y - self._TOP) // self._ROW_H
|
||||
return row if 0 <= row < len(self._visible()) else None
|
||||
|
||||
def tap(self, x: int, y: int) -> None:
|
||||
self.actions.append(("tap", str(x), str(y)))
|
||||
row = self._row_at(y)
|
||||
if row is None:
|
||||
return
|
||||
el = self._visible()[row]
|
||||
if el.editable:
|
||||
self.focus = el.label
|
||||
if el.toggles:
|
||||
before = bool(self.state.get(el.toggles, el.checked))
|
||||
self.state[el.toggles] = not before
|
||||
self.toggled.append((el.toggles, before, not before))
|
||||
if el.saves:
|
||||
self.records.setdefault(el.saves, []).append(
|
||||
{**self.fields, **{k: v for k, v in self.state.items()
|
||||
if k.startswith(el.saves + "_")}})
|
||||
self.fields = {}
|
||||
self.focus = None
|
||||
if el.goto and el.goto in self.screens:
|
||||
self.current = el.goto
|
||||
|
||||
def input_text(self, text: str) -> None:
|
||||
self.actions.append(("text", text))
|
||||
self.typed.append(text)
|
||||
if self.focus is not None:
|
||||
self.fields[self.focus] = self.fields.get(self.focus, "") + text
|
||||
|
||||
def swipe(self, x1: int, y1: int, x2: int, y2: int, ms: int = 300) -> None:
|
||||
self.actions.append(("swipe", str(x1), str(y1), str(x2), str(y2)))
|
||||
|
||||
def keyevent(self, key: str) -> None:
|
||||
self.actions.append(("key", key))
|
||||
if key == "back":
|
||||
self.current = self.screens[self.current].back or self.home
|
||||
elif key == "home":
|
||||
self.current = self.home
|
||||
|
||||
def launch(self, app: str) -> None:
|
||||
self.actions.append(("launch", app))
|
||||
for screen in self.screens.values():
|
||||
for el in screen.elements:
|
||||
if el.label.lower() == app.lower() and el.goto:
|
||||
self.current = el.goto
|
||||
return
|
||||
|
||||
def size(self) -> tuple[int, int]:
|
||||
return self.width, self.height
|
||||
|
||||
|
||||
def _saved_alarm_rows(device: "SimulatedDevice") -> list[SimElement]:
|
||||
"""Render committed alarms the way a clock app lists them."""
|
||||
saved = device.records.get("alarm", [])
|
||||
if not saved:
|
||||
return [SimElement("No alarms", clickable=False)]
|
||||
rows = []
|
||||
for rec in saved:
|
||||
hour = (rec.get("Hour") or "?").lstrip("0") or "0"
|
||||
minute = (rec.get("Minute") or "?").rjust(2, "0")
|
||||
meridiem = "PM" if rec.get("alarm_pm") else "AM"
|
||||
rows.append(SimElement(f"{hour}:{minute} {meridiem}", clickable=False))
|
||||
return rows
|
||||
|
||||
|
||||
def demo_phone() -> SimulatedDevice:
|
||||
"""A two-app phone: Settings (Wi-Fi) and Clock (alarms).
|
||||
|
||||
Enough to exercise a multi-screen task, a stateful toggle -- the case the
|
||||
earlier single-step run got wrong, tapping a switch that was already on --
|
||||
and a text field.
|
||||
"""
|
||||
screens = {
|
||||
"home": SimScreen("home", [
|
||||
SimElement("Phone"),
|
||||
SimElement("Messages"),
|
||||
SimElement("Clock", goto="clock"),
|
||||
SimElement("Settings", goto="settings"),
|
||||
SimElement("Camera"),
|
||||
]),
|
||||
"settings": SimScreen("settings", [
|
||||
SimElement("Settings", clickable=False),
|
||||
SimElement("Network & internet", goto="network"),
|
||||
SimElement("Connected devices"),
|
||||
SimElement("Apps"),
|
||||
SimElement("Battery"),
|
||||
], back="home"),
|
||||
"network": SimScreen("network", [
|
||||
SimElement("Network & internet", clickable=False),
|
||||
SimElement("Wi-Fi", cls="android.widget.Switch", checkable=True,
|
||||
toggles="wifi"),
|
||||
SimElement("Mobile network"),
|
||||
SimElement("Airplane mode", cls="android.widget.Switch",
|
||||
checkable=True, toggles="airplane"),
|
||||
], back="settings"),
|
||||
"clock": SimScreen("clock", [
|
||||
SimElement("Alarm", cls="android.widget.Button", goto="alarms"),
|
||||
SimElement("Clock", cls="android.widget.Button", selected=True),
|
||||
SimElement("Timer", cls="android.widget.Button"),
|
||||
SimElement("Stopwatch", cls="android.widget.Button"),
|
||||
], back="home"),
|
||||
"alarms": SimScreen("alarms", [
|
||||
SimElement("Alarm", cls="android.widget.Button", selected=True),
|
||||
SimElement("Add alarm", cls="android.widget.ImageButton",
|
||||
goto="new_alarm"),
|
||||
], back="clock", dynamic=_saved_alarm_rows),
|
||||
"new_alarm": SimScreen("new_alarm", [
|
||||
SimElement("Set time", clickable=False),
|
||||
SimElement("Hour", cls="android.widget.EditText", editable=True),
|
||||
SimElement("Minute", cls="android.widget.EditText", editable=True),
|
||||
# Android shows one AM/PM control whose label is its value, so
|
||||
# "set an alarm for 7:30 AM" has a wrong answer as well as a right
|
||||
# one. Without it the task could be passed by typing any digits.
|
||||
SimElement("AM", cls="android.widget.Button",
|
||||
label_of="alarm_pm", labels=("AM", "PM"),
|
||||
toggles="alarm_pm"),
|
||||
SimElement("Save", cls="android.widget.Button", goto="alarms",
|
||||
saves="alarm"),
|
||||
], back="alarms"),
|
||||
}
|
||||
return SimulatedDevice(screens=screens, current="home", state={"wifi": False})
|
||||
@@ -0,0 +1,147 @@
|
||||
"""Turn one tool call into one device action.
|
||||
|
||||
Every failure here is returned to the model as a sentence it can act on, not
|
||||
raised. A 1.7B model asked for `index: 9` on a four-element screen has made a
|
||||
recoverable mistake, and "index 9 is out of range, the screen has 4 elements
|
||||
(0-3)" is the difference between the next step being right and the episode
|
||||
ending. Exceptions are reserved for the device being gone.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from device import KEYCODES, Device
|
||||
from ui_tree import Element
|
||||
|
||||
|
||||
@dataclass
|
||||
class ActionResult:
|
||||
ok: bool
|
||||
message: str
|
||||
done: bool = False
|
||||
summary: str = ""
|
||||
action: str = ""
|
||||
|
||||
def as_tool_reply(self) -> str:
|
||||
return self.message
|
||||
|
||||
|
||||
def _need(args: dict, key: str, kind: type, what: str) -> tuple[object, str | None]:
|
||||
if key not in args:
|
||||
return None, f"missing required argument {key!r} for {what}"
|
||||
value = args[key]
|
||||
if kind is int:
|
||||
try:
|
||||
value = int(value)
|
||||
except (TypeError, ValueError):
|
||||
return None, f"{key!r} must be a whole number, got {args[key]!r}"
|
||||
elif not isinstance(value, kind):
|
||||
return None, f"{key!r} must be {kind.__name__}, got {type(value).__name__}"
|
||||
return value, None
|
||||
|
||||
|
||||
def _resolve(index: object, elements: list[Element]) -> tuple[Element | None, str | None]:
|
||||
i = int(index)
|
||||
if not elements:
|
||||
return None, "the screen has no addressable elements; try press_key(back)"
|
||||
if not 0 <= i < len(elements):
|
||||
return None, (
|
||||
f"index {i} is out of range; the screen has {len(elements)} "
|
||||
f"elements (0-{len(elements) - 1})"
|
||||
)
|
||||
return elements[i], None
|
||||
|
||||
|
||||
def execute(name: str, args: dict, elements: list[Element],
|
||||
device: Device) -> ActionResult:
|
||||
"""Run one tool call. Returns what to tell the model."""
|
||||
args = args or {}
|
||||
|
||||
if name == "task_complete":
|
||||
summary = str(args.get("summary", "")).strip()
|
||||
return ActionResult(True, "task marked complete", done=True,
|
||||
summary=summary, action="task_complete")
|
||||
|
||||
if name == "tap":
|
||||
index, err = _need(args, "index", int, "tap")
|
||||
if err:
|
||||
return ActionResult(False, err, action="tap")
|
||||
el, err = _resolve(index, elements)
|
||||
if err:
|
||||
return ActionResult(False, err, action="tap")
|
||||
x, y = el.center
|
||||
device.tap(x, y)
|
||||
state = ""
|
||||
if "checked" in el.flags:
|
||||
state = f" (was {'on' if el.flags['checked'] else 'off'})"
|
||||
return ActionResult(True, f'tapped [{index}] "{el.text}"{state}',
|
||||
action=f"tap:{index}")
|
||||
|
||||
if name == "type_text":
|
||||
index, err = _need(args, "index", int, "type_text")
|
||||
if err:
|
||||
return ActionResult(False, err, action="type_text")
|
||||
text, err = _need(args, "text", str, "type_text")
|
||||
if err:
|
||||
return ActionResult(False, err, action="type_text")
|
||||
el, err = _resolve(index, elements)
|
||||
if err:
|
||||
return ActionResult(False, err, action="type_text")
|
||||
# Focus first: `input text` goes to whatever holds focus, which on a
|
||||
# freshly dumped screen is usually nothing.
|
||||
x, y = el.center
|
||||
device.tap(x, y)
|
||||
device.input_text(str(text))
|
||||
return ActionResult(True, f'typed "{text}" into [{index}] "{el.text}"',
|
||||
action=f"type:{index}")
|
||||
|
||||
if name == "swipe":
|
||||
direction = str(args.get("direction", "")).lower()
|
||||
if direction not in ("up", "down", "left", "right"):
|
||||
return ActionResult(
|
||||
False, "direction must be one of up, down, left, right",
|
||||
action="swipe")
|
||||
w, h = device.size()
|
||||
cx, cy = w // 2, h // 2
|
||||
dx, dy = int(w * 0.35), int(h * 0.30)
|
||||
# `direction` is where the *content* should move, i.e. what the user
|
||||
# means by "scroll down to see more", so the finger travels the other
|
||||
# way. Stated in the tool description too, because guessing this wrong
|
||||
# is invisible in the transcript.
|
||||
moves = {
|
||||
"down": (cx, cy + dy, cx, cy - dy),
|
||||
"up": (cx, cy - dy, cx, cy + dy),
|
||||
"right": (cx + dx, cy, cx - dx, cy),
|
||||
"left": (cx - dx, cy, cx + dx, cy),
|
||||
}
|
||||
device.swipe(*moves[direction])
|
||||
return ActionResult(True, f"swiped to scroll {direction}",
|
||||
action=f"swipe:{direction}")
|
||||
|
||||
if name == "press_key":
|
||||
key = str(args.get("key", "")).lower()
|
||||
if key not in KEYCODES:
|
||||
return ActionResult(
|
||||
False, f"unknown key {key!r}; use one of {', '.join(KEYCODES)}",
|
||||
action="press_key")
|
||||
device.keyevent(key)
|
||||
return ActionResult(True, f"pressed {key}", action=f"key:{key}")
|
||||
|
||||
if name == "open_app":
|
||||
app = str(args.get("name", "")).strip()
|
||||
if not app:
|
||||
return ActionResult(False, "open_app needs a name", action="open_app")
|
||||
try:
|
||||
device.launch(app)
|
||||
except Exception as exc: # device-specific launch failures are recoverable
|
||||
return ActionResult(False, f"could not launch {app!r}: {exc}",
|
||||
action="open_app")
|
||||
return ActionResult(True, f"launched {app}", action=f"open:{app}")
|
||||
|
||||
return ActionResult(
|
||||
False,
|
||||
f"unknown tool {name!r}; available: tap, type_text, swipe, press_key, "
|
||||
"open_app, task_complete",
|
||||
action="unknown",
|
||||
)
|
||||
@@ -0,0 +1,135 @@
|
||||
"""What the phone is actually in, read the same way for both backends.
|
||||
|
||||
The scored suite used to take its predicates over ``SimulatedDevice``'s Python
|
||||
attributes, so every scored run was a simulator run by construction -- the
|
||||
real-device path existed for *driving* a phone and not for judging one. That
|
||||
made "the agent suite" a claim about fixtures.
|
||||
|
||||
Success is therefore read two ways, and the order matters:
|
||||
|
||||
1. **Out of band, from the setting itself** -- ``device.state`` in the
|
||||
simulator, ``settings get global wifi_on`` over adb. This is the ground
|
||||
truth, and it does not depend on where the agent happened to leave the
|
||||
phone. Scoring from the final screen alone fails an agent that turns Wi-Fi
|
||||
on correctly and then presses Home, which is not a failure.
|
||||
2. **From the UI dump**, for anything with no setting behind it -- a saved
|
||||
alarm appears as a row in the clock app and nowhere else. The simulator
|
||||
emits real uiautomator XML, so this goes down the same parse, the same
|
||||
switch lookup and the same text matching a phone would.
|
||||
|
||||
Only the facts a phone genuinely cannot report after the fact -- which
|
||||
switches were flipped on the way, and what was typed into which field -- come
|
||||
from the simulator object, and any task needing them declares it, so a
|
||||
real-device run refuses to score rather than scoring wrong.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from ui_tree import parse_ui_dump
|
||||
|
||||
|
||||
def _norm(s: str) -> str:
|
||||
"""Match labels across the punctuation Android is inconsistent about."""
|
||||
return "".join(c for c in s.lower() if c.isalnum())
|
||||
|
||||
|
||||
@dataclass
|
||||
class PhoneState:
|
||||
source: str
|
||||
"""``"sim"`` or ``"device"`` -- which facts below are trustworthy."""
|
||||
settings: dict[str, bool] = field(default_factory=dict)
|
||||
"""Authoritative setting values, read out of band. Preferred over
|
||||
:attr:`switches`, which only shows what is currently on screen."""
|
||||
screen: str | None = None
|
||||
"""Simulator screen id. ``None`` on a real phone, where there is no such
|
||||
thing; use :meth:`has_text` against something the screen actually shows."""
|
||||
switches: dict[str, bool] = field(default_factory=dict)
|
||||
texts: list[str] = field(default_factory=list)
|
||||
typed: list[str] = field(default_factory=list)
|
||||
fields: dict[str, str] = field(default_factory=dict)
|
||||
records: dict[str, list[dict]] = field(default_factory=dict)
|
||||
toggled: list[tuple[str, bool, bool]] = field(default_factory=list)
|
||||
"""(key, before, after) for every switch the agent actually flipped."""
|
||||
|
||||
def switch(self, *names: str) -> bool | None:
|
||||
"""State of the first control matching any of ``names``.
|
||||
|
||||
The setting wins over the screen: an agent that turned Wi-Fi on and
|
||||
then navigated away has still turned Wi-Fi on. ``None`` means neither
|
||||
source knows the control, which is not the same as off -- an agent that
|
||||
never found the screen has not turned anything on, and predicates must
|
||||
not read that as "off".
|
||||
"""
|
||||
wanted = {_norm(n) for n in names}
|
||||
for key, value in self.settings.items():
|
||||
if _norm(key) in wanted:
|
||||
return bool(value)
|
||||
for label, checked in self.switches.items():
|
||||
if _norm(label) in wanted:
|
||||
return checked
|
||||
return None
|
||||
|
||||
def has_text(self, *needles: str) -> bool:
|
||||
joined = " ".join(self.texts).lower()
|
||||
return any(n.lower() in joined for n in needles)
|
||||
|
||||
def times_toggled(self, key: str) -> int:
|
||||
return sum(1 for k, _, _ in self.toggled if k == key)
|
||||
|
||||
|
||||
def read_state(device) -> PhoneState:
|
||||
"""Read the phone through its screen, plus the simulator's own records."""
|
||||
elements = parse_ui_dump(device.dump())
|
||||
# `checkable` is deliberately not among the flags ui_tree parses, because
|
||||
# that list is also what the model is shown; adding to it would change the
|
||||
# agent's prompt. A switch is recognised by its class or by exposing a
|
||||
# `checked` flag instead.
|
||||
switches = {e.text: bool(e.flags.get("checked", False))
|
||||
for e in elements
|
||||
if "checked" in e.flags
|
||||
or e.short_class in ("Switch", "CheckBox", "ToggleButton")}
|
||||
texts = [e.text for e in elements if e.text]
|
||||
|
||||
if not hasattr(device, "screens"):
|
||||
return PhoneState(source="device", switches=switches, texts=texts,
|
||||
settings=adb_settings(device))
|
||||
|
||||
return PhoneState(
|
||||
source="sim",
|
||||
screen=device.current,
|
||||
settings={k: bool(v) for k, v in device.state.items()},
|
||||
switches=switches,
|
||||
texts=texts,
|
||||
typed=list(device.typed),
|
||||
fields=dict(getattr(device, "fields", {})),
|
||||
records={k: [dict(r) for r in v]
|
||||
for k, v in getattr(device, "records", {}).items()},
|
||||
toggled=list(getattr(device, "toggled", [])),
|
||||
)
|
||||
|
||||
|
||||
ADB_SETTINGS = {
|
||||
"wifi": ("global", "wifi_on"),
|
||||
"airplane": ("global", "airplane_mode_on"),
|
||||
"bluetooth": ("global", "bluetooth_on"),
|
||||
}
|
||||
"""Settings readable out of band, so scoring does not depend on which screen
|
||||
the agent left the phone on."""
|
||||
|
||||
|
||||
def adb_settings(device) -> dict[str, bool]:
|
||||
"""Read the authoritative values from a real phone. Missing keys are
|
||||
omitted rather than defaulted -- an unreadable setting must not be scored
|
||||
as "off"."""
|
||||
out: dict[str, bool] = {}
|
||||
for key, (namespace, name) in ADB_SETTINGS.items():
|
||||
try:
|
||||
raw = device._run("shell", "settings", "get", namespace, name)
|
||||
except Exception:
|
||||
continue
|
||||
raw = raw.strip()
|
||||
if raw in ("0", "1"):
|
||||
out[key] = raw == "1"
|
||||
return out
|
||||
@@ -0,0 +1,98 @@
|
||||
"""Drive Spark-X2.5 through Android control steps against an OpenAI endpoint.
|
||||
|
||||
Measures whether the model picks the right tool and the right element, and how
|
||||
long a decision takes -- the two things that decide whether a 1.7B model can
|
||||
actually run a phone agent locally.
|
||||
"""
|
||||
import argparse, json, time
|
||||
from urllib import request as urlrequest
|
||||
|
||||
from action_space import SYSTEM_PROMPT, TOOLS
|
||||
from scenarios import SCENARIOS
|
||||
|
||||
|
||||
def chat(base_url, model, messages, tools, timeout=900, max_tokens=1024,
|
||||
think=True):
|
||||
payload = {
|
||||
"model": model, "messages": messages, "tools": tools,
|
||||
"tool_choice": "auto", "temperature": 0.0, "max_tokens": max_tokens,
|
||||
}
|
||||
if not think:
|
||||
# Spark's template opens <think> by default; closing it up front makes
|
||||
# the model answer directly, which is what a phone agent wants.
|
||||
payload["chat_template_kwargs"] = {"enable_thinking": False}
|
||||
body = json.dumps(payload).encode()
|
||||
req = urlrequest.Request(f"{base_url}/chat/completions", data=body,
|
||||
headers={"Content-Type": "application/json"})
|
||||
t0 = time.perf_counter()
|
||||
with urlrequest.urlopen(req, timeout=timeout) as r:
|
||||
out = json.loads(r.read())
|
||||
return out, time.perf_counter() - t0
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--base-url", default="http://127.0.0.1:8077/v1")
|
||||
ap.add_argument("--model", default="XHToken/Spark-X2.5-1.7B")
|
||||
ap.add_argument("--no-think", action="store_true")
|
||||
ap.add_argument("--max-tokens", type=int, default=1024)
|
||||
ap.add_argument("--out", default="android_agent_results.json")
|
||||
a = ap.parse_args()
|
||||
|
||||
rows, correct_tool, correct_args = [], 0, 0
|
||||
for sc in SCENARIOS:
|
||||
msgs = [
|
||||
{"role": "system", "content": SYSTEM_PROMPT},
|
||||
{"role": "user", "content":
|
||||
f"Task: {sc['task']}\n\nCurrent screen:\n{sc['screen']}\n\n"
|
||||
"Choose the next action."},
|
||||
]
|
||||
try:
|
||||
out, dt = chat(a.base_url, a.model, msgs, TOOLS,
|
||||
max_tokens=a.max_tokens, think=not a.no_think)
|
||||
except Exception as e:
|
||||
rows.append({"id": sc["id"], "error": str(e)[:200]})
|
||||
print(f"{sc['id']:<20} ERROR {str(e)[:90]}", flush=True)
|
||||
continue
|
||||
msg = out["choices"][0]["message"]
|
||||
calls = msg.get("tool_calls") or []
|
||||
got_name = calls[0]["function"]["name"] if calls else None
|
||||
try:
|
||||
got_args = json.loads(calls[0]["function"]["arguments"]) if calls else {}
|
||||
except Exception:
|
||||
got_args = {"_raw": calls[0]["function"]["arguments"]}
|
||||
|
||||
name_ok = got_name in sc["accept_names"]
|
||||
args_ok = name_ok and all(
|
||||
str(got_args.get(k)) == str(v) for k, v in sc["expect"]["args"].items()
|
||||
) if got_name == sc["expect"]["name"] else name_ok and not sc["expect"]["args"]
|
||||
correct_tool += int(name_ok)
|
||||
correct_args += int(bool(args_ok))
|
||||
rows.append({
|
||||
"id": sc["id"], "latency_s": round(dt, 2),
|
||||
"expected": sc["expect"], "got_name": got_name, "got_args": got_args,
|
||||
"tool_ok": name_ok, "args_ok": bool(args_ok),
|
||||
"reasoning_chars": len(msg.get("reasoning_content") or ""),
|
||||
"completion_tokens": out.get("usage", {}).get("completion_tokens"),
|
||||
})
|
||||
flag = "OK " if args_ok else ("~ " if name_ok else "X ")
|
||||
print(f"{flag}{sc['id']:<20} {got_name}({got_args}) {dt:.1f}s", flush=True)
|
||||
|
||||
n = len(SCENARIOS)
|
||||
summary = {
|
||||
"scenarios": n,
|
||||
"thinking": not a.no_think,
|
||||
"tool_accuracy": f"{correct_tool}/{n}",
|
||||
"action_accuracy": f"{correct_args}/{n}",
|
||||
"median_latency_s": round(
|
||||
sorted(r["latency_s"] for r in rows if "latency_s" in r)[
|
||||
max(0, len([r for r in rows if "latency_s" in r]) // 2)] , 2)
|
||||
if any("latency_s" in r for r in rows) else None,
|
||||
"rows": rows,
|
||||
}
|
||||
json.dump(summary, open(a.out, "w"), indent=2)
|
||||
print(json.dumps({k: v for k, v in summary.items() if k != "rows"}, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,106 @@
|
||||
"""Drive Spark-X2.5 through a whole phone task, not one decision.
|
||||
|
||||
# against the in-process simulated phone (no device needed)
|
||||
python run_episode.py --task "Turn on Wi-Fi." --device sim
|
||||
|
||||
# against a real phone
|
||||
adb devices # confirm it is listed
|
||||
python run_episode.py --task "Turn on Wi-Fi." --device adb
|
||||
|
||||
The server side is vLLM's stock OpenAI endpoint; Spark emits GLM-4.5's tool
|
||||
format, so no custom parser is needed:
|
||||
|
||||
vllm serve <model> --port 8077 --enable-auto-tool-choice \\
|
||||
--tool-call-parser glm45 --reasoning-parser glm45
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
|
||||
from agent import AgentConfig, run_episode
|
||||
from device import AdbDevice, AdbError, demo_phone
|
||||
|
||||
TASKS = {
|
||||
"wifi": "Turn on Wi-Fi.",
|
||||
"alarm": "Set an alarm for 7:30 AM.",
|
||||
}
|
||||
|
||||
|
||||
def build_device(kind: str, serial: str | None):
|
||||
if kind == "sim":
|
||||
return demo_phone(), "simulated phone (settings + clock)"
|
||||
try:
|
||||
device = AdbDevice(serial=serial)
|
||||
w, h = device.size()
|
||||
return device, f"adb device {serial or '(default)'} {w}x{h}"
|
||||
except AdbError as exc:
|
||||
print(f"error: {exc}", file=sys.stderr)
|
||||
raise SystemExit(2)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--task", default=TASKS["wifi"],
|
||||
help=f"free text, or one of: {', '.join(TASKS)}")
|
||||
ap.add_argument("--device", choices=("sim", "adb"), default="sim")
|
||||
ap.add_argument("--serial", default=None)
|
||||
ap.add_argument("--base-url", default="http://127.0.0.1:8077/v1")
|
||||
ap.add_argument("--model", default="XHToken/Spark-X2.5-1.7B")
|
||||
ap.add_argument("--max-steps", type=int, default=12)
|
||||
ap.add_argument("--max-tokens", type=int, default=1024)
|
||||
ap.add_argument("--no-think", action="store_true")
|
||||
ap.add_argument("--no-think-fallback", action="store_true")
|
||||
ap.add_argument("--out", default=None)
|
||||
a = ap.parse_args()
|
||||
|
||||
task = TASKS.get(a.task, a.task)
|
||||
device, described = build_device(a.device, a.serial)
|
||||
cfg = AgentConfig(
|
||||
base_url=a.base_url, model=a.model, max_steps=a.max_steps,
|
||||
max_tokens=a.max_tokens, think=not a.no_think,
|
||||
think_fallback=not a.no_think_fallback,
|
||||
)
|
||||
|
||||
print(f"device: {described}")
|
||||
print(f"task: {task}")
|
||||
t0 = time.perf_counter()
|
||||
episode = run_episode(device, task, cfg)
|
||||
wall = time.perf_counter() - t0
|
||||
|
||||
print()
|
||||
print(episode.transcript())
|
||||
latencies = [s.latency_s for s in episode.steps]
|
||||
print(f"\n{episode.n_steps} steps in {wall:.1f} s"
|
||||
f" (median decision {sorted(latencies)[len(latencies) // 2]:.2f} s)"
|
||||
if latencies else f"\n{episode.n_steps} steps in {wall:.1f} s")
|
||||
if hasattr(device, "state"):
|
||||
print(f"device state: {device.state}")
|
||||
|
||||
if a.out:
|
||||
payload = {
|
||||
"task": task, "device": described, "done": episode.done,
|
||||
"summary": episode.summary, "stop_reason": episode.stop_reason,
|
||||
"wall_s": round(wall, 2),
|
||||
"think": cfg.think, "max_steps": cfg.max_steps,
|
||||
"steps": [
|
||||
{"n": s.n, "tool": s.tool, "args": s.args,
|
||||
"ok": s.result.ok if s.result else False,
|
||||
"message": s.result.message if s.result else s.note,
|
||||
"latency_s": round(s.latency_s, 3), "thinking": s.thinking}
|
||||
for s in episode.steps
|
||||
],
|
||||
"final_state": getattr(device, "state", None),
|
||||
}
|
||||
with open(a.out, "w") as f:
|
||||
json.dump(payload, f, indent=2, ensure_ascii=False)
|
||||
print(f"wrote {a.out}")
|
||||
|
||||
raise SystemExit(0 if episode.done else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,151 @@
|
||||
"""Run the task suite and score it, so an agent change can be compared.
|
||||
|
||||
Success is decided by the phone's own settings and screen, not by the
|
||||
transcript: an agent that says it turned Wi-Fi on and left it off fails here,
|
||||
which is exactly the failure this model exhibits.
|
||||
|
||||
Two things changed after the plan review:
|
||||
|
||||
* ``--repeat N`` now walks the task's **variants** rather than re-running one
|
||||
fixture. At temperature 0 against fixed fixtures, repeats measure
|
||||
repeatability; they only become trials if the phone differs between them.
|
||||
The summary reports a pass rate per task with the variants named, so a build
|
||||
comparison rests on more than one cell.
|
||||
* ``--device adb`` scores a real phone. Each run resets the device to the
|
||||
task's declared starting state first, and a task that cannot be scored from
|
||||
a phone (because its predicate needs flip history) is skipped and reported
|
||||
as skipped, rather than silently scored from final state.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import statistics
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
from agent import AgentConfig, run_episode, wait_for_server
|
||||
from phone_state import read_state
|
||||
from tasks import SUITE, SUITE_BY_ID
|
||||
|
||||
|
||||
def _reset_real_device(device, task) -> None:
|
||||
if not task.reset_adb:
|
||||
raise SystemExit(
|
||||
f"task {task.task_id!r} declares no reset_adb, so a phone run would "
|
||||
f"be scored against an unknown starting state. Add one or exclude "
|
||||
f"the task with --tasks."
|
||||
)
|
||||
for cmd in task.reset_adb:
|
||||
device._run(*cmd)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--base-url", default="http://127.0.0.1:8077/v1")
|
||||
ap.add_argument("--model", default="spark")
|
||||
ap.add_argument("--tasks", default="all",
|
||||
help="comma-separated task ids, or 'all'")
|
||||
ap.add_argument("--repeat", type=int, default=1,
|
||||
help="runs per task; each walks the next variant")
|
||||
ap.add_argument("--device", choices=("sim", "adb"), default="sim")
|
||||
ap.add_argument("--serial", default=None, help="adb device serial")
|
||||
ap.add_argument("--no-think", action="store_true")
|
||||
ap.add_argument("--max-tokens", type=int, default=1024)
|
||||
ap.add_argument("--label", default="")
|
||||
ap.add_argument("--out", default=None)
|
||||
a = ap.parse_args()
|
||||
|
||||
tasks = SUITE if a.tasks == "all" else [SUITE_BY_ID[t] for t in a.tasks.split(",")]
|
||||
cfg = AgentConfig(base_url=a.base_url, model=a.model,
|
||||
think=not a.no_think, max_tokens=a.max_tokens)
|
||||
|
||||
phone = None
|
||||
if a.device == "adb":
|
||||
from device import AdbDevice
|
||||
phone = AdbDevice(serial=a.serial)
|
||||
skipped = [t.task_id for t in tasks if t.needs]
|
||||
if skipped:
|
||||
print(f"skipping on a real phone (needs flip history): "
|
||||
f"{', '.join(skipped)}")
|
||||
tasks = [t for t in tasks if not t.needs]
|
||||
|
||||
if not wait_for_server(cfg, timeout_s=600):
|
||||
raise SystemExit(f"no model server at {a.base_url}")
|
||||
|
||||
rows, t0 = [], time.perf_counter()
|
||||
for task in tasks:
|
||||
for run in range(a.repeat):
|
||||
if phone is not None:
|
||||
_reset_real_device(phone, task)
|
||||
device = phone
|
||||
else:
|
||||
device = task.build(run)
|
||||
cfg.max_steps = task.max_steps
|
||||
episode = run_episode(device, task.prompt, cfg)
|
||||
score = task.score(read_state(device), episode.done, run)
|
||||
score.update(
|
||||
run=run + 1, steps=episode.n_steps,
|
||||
stop_reason=episode.stop_reason,
|
||||
recovered_steps=sum(1 for s in episode.steps
|
||||
if s.parsed_via not in ("tool_calls", "none")),
|
||||
median_latency_s=round(
|
||||
sorted(s.latency_s for s in episode.steps)[episode.n_steps // 2], 2)
|
||||
if episode.n_steps else None,
|
||||
)
|
||||
rows.append(score)
|
||||
mark = "PASS" if score["success"] else "fail"
|
||||
detail = []
|
||||
if not score.get("scorable", True):
|
||||
mark, detail = "skip", [score.get("reason", "")]
|
||||
else:
|
||||
if score["reached_goal"] and not score["declared_done"]:
|
||||
detail.append("goal reached but never stopped")
|
||||
if score["declared_done"] and not score["reached_goal"]:
|
||||
detail.append("claimed done, goal NOT reached")
|
||||
if score["collateral_damage"]:
|
||||
detail.append("collateral damage")
|
||||
print(f" {mark} {task.task_id:18s} {score['variant']:10s} "
|
||||
f"steps={score['steps']:2d} "
|
||||
f"{score['stop_reason'][:34]:36s} {'; '.join(detail)}", flush=True)
|
||||
|
||||
wall = time.perf_counter() - t0
|
||||
scored = [r for r in rows if r.get("scorable", True)]
|
||||
n_pass = sum(1 for r in scored if r["success"])
|
||||
reached = sum(1 for r in scored if r["reached_goal"])
|
||||
claimed = sum(1 for r in scored if r["declared_done"] and not r["reached_goal"])
|
||||
|
||||
by_task: dict[str, list[dict]] = defaultdict(list)
|
||||
for r in scored:
|
||||
by_task[r["task_id"]].append(r)
|
||||
print("\npass rate per task")
|
||||
for task_id, rs in by_task.items():
|
||||
passes = sum(1 for r in rs if r["success"])
|
||||
failed = [r["variant"] for r in rs if not r["success"]]
|
||||
print(f" {task_id:18s} {passes}/{len(rs)}"
|
||||
+ (f" failed on: {', '.join(failed)}" if failed else ""))
|
||||
|
||||
rates = [sum(1 for r in rs if r["success"]) / len(rs) for rs in by_task.values()]
|
||||
spread = (f"{min(rates):.0%}-{max(rates):.0%}" if rates else "-")
|
||||
print(f"\n{n_pass}/{len(scored)} passed in {wall:.0f}s"
|
||||
f" (goal reached {reached}/{len(scored)}; "
|
||||
f"falsely claimed done {claimed}; per-task rate {spread}"
|
||||
+ (f"; median {statistics.median(rates):.0%}" if rates else "") + ")")
|
||||
if len(scored) and len(by_task) and max(len(rs) for rs in by_task.values()) < 3:
|
||||
print(" NOTE: fewer than 3 runs per task -- enough to show a failure "
|
||||
"reproduces, not to rank builds.")
|
||||
|
||||
if a.out:
|
||||
with open(a.out, "w") as f:
|
||||
json.dump({"label": a.label, "base_url": a.base_url,
|
||||
"model": a.model, "think": cfg.think,
|
||||
"device": a.device, "repeat": a.repeat,
|
||||
"passed": n_pass, "total": len(scored),
|
||||
"skipped": len(rows) - len(scored),
|
||||
"wall_s": round(wall, 1), "rows": rows}, f, indent=2)
|
||||
print(f"wrote {a.out}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,113 @@
|
||||
"""Android screens as a text-only agent sees them, with the correct next action.
|
||||
|
||||
Each screen is a uiautomator-style accessibility dump flattened to one line per
|
||||
element -- the same shape droidrun's Portal and AndroidWorld's a11y observation
|
||||
hand to a text model. `expect` is the action a competent agent must take next;
|
||||
`accept_names` allows a defensible alternative where one genuinely exists.
|
||||
"""
|
||||
|
||||
SCENARIOS = [
|
||||
{
|
||||
"id": "launch_clock",
|
||||
"task": "Set an alarm for 7:30 AM.",
|
||||
"screen": """[0] TextView "Phone" clickable=true
|
||||
[1] TextView "Messages" clickable=true
|
||||
[2] TextView "Chrome" clickable=true
|
||||
[3] TextView "Clock" clickable=true
|
||||
[4] TextView "Settings" clickable=true
|
||||
[5] TextView "Camera" clickable=true""",
|
||||
"expect": {"name": "tap", "args": {"index": 3}},
|
||||
"accept_names": ["tap", "open_app"],
|
||||
},
|
||||
{
|
||||
"id": "clock_alarm_tab",
|
||||
"task": "Set an alarm for 7:30 AM.",
|
||||
"screen": """[0] Button "Alarm" clickable=true selected=false
|
||||
[1] Button "Clock" clickable=true selected=true
|
||||
[2] Button "Timer" clickable=true selected=false
|
||||
[3] Button "Stopwatch" clickable=true selected=false
|
||||
[4] TextView "14:32" clickable=false""",
|
||||
"expect": {"name": "tap", "args": {"index": 0}},
|
||||
"accept_names": ["tap"],
|
||||
},
|
||||
{
|
||||
"id": "add_alarm",
|
||||
"task": "Set an alarm for 7:30 AM.",
|
||||
"screen": """[0] Button "Alarm" clickable=true selected=true
|
||||
[1] TextView "No alarms" clickable=false
|
||||
[2] ImageButton "Add alarm" clickable=true
|
||||
[3] Button "Timer" clickable=true""",
|
||||
"expect": {"name": "tap", "args": {"index": 2}},
|
||||
"accept_names": ["tap"],
|
||||
},
|
||||
{
|
||||
"id": "wifi_settings",
|
||||
"task": "Turn on Wi-Fi.",
|
||||
"screen": """[0] TextView "Settings" clickable=false
|
||||
[1] TextView "Network & internet" clickable=true
|
||||
[2] TextView "Connected devices" clickable=true
|
||||
[3] TextView "Apps" clickable=true
|
||||
[4] TextView "Battery" clickable=true
|
||||
[5] TextView "Display" clickable=true""",
|
||||
"expect": {"name": "tap", "args": {"index": 1}},
|
||||
"accept_names": ["tap"],
|
||||
},
|
||||
{
|
||||
"id": "wifi_toggle",
|
||||
"task": "Turn on Wi-Fi.",
|
||||
"screen": """[0] TextView "Network & internet" clickable=false
|
||||
[1] Switch "Wi-Fi" checked=false clickable=true
|
||||
[2] TextView "Mobile network" clickable=true
|
||||
[3] Switch "Airplane mode" checked=false clickable=true""",
|
||||
"expect": {"name": "tap", "args": {"index": 1}},
|
||||
"accept_names": ["tap"],
|
||||
},
|
||||
{
|
||||
"id": "search_contact",
|
||||
"task": "Find the contact named Wei Zhang.",
|
||||
"screen": """[0] EditText "Search contacts" clickable=true focused=true
|
||||
[1] TextView "Alice Chen" clickable=true
|
||||
[2] TextView "Bob Lee" clickable=true
|
||||
[3] TextView "Carol Wu" clickable=true""",
|
||||
"expect": {"name": "type_text", "args": {"index": 0, "text": "Wei Zhang"}},
|
||||
"accept_names": ["type_text"],
|
||||
},
|
||||
{
|
||||
"id": "scroll_for_item",
|
||||
"task": "Open the Developer options screen in Settings.",
|
||||
"screen": """[0] TextView "Settings" clickable=false
|
||||
[1] TextView "Display" clickable=true
|
||||
[2] TextView "Sound" clickable=true
|
||||
[3] TextView "Storage" clickable=true
|
||||
[4] TextView "Privacy" clickable=true
|
||||
[5] TextView "Location" clickable=true""",
|
||||
"expect": {"name": "swipe", "args": {"direction": "up"}},
|
||||
"accept_names": ["swipe"],
|
||||
},
|
||||
{
|
||||
"id": "go_back",
|
||||
"task": "Return to the previous screen; you opened the wrong menu.",
|
||||
"screen": """[0] TextView "About phone" clickable=false
|
||||
[1] TextView "Model: Pixel 8" clickable=false
|
||||
[2] TextView "Android version" clickable=true""",
|
||||
"expect": {"name": "press_key", "args": {"key": "back"}},
|
||||
"accept_names": ["press_key"],
|
||||
},
|
||||
{
|
||||
"id": "open_app_by_name",
|
||||
"task": "Open the Camera app.",
|
||||
"screen": """[0] TextView "Swipe up to unlock" clickable=false
|
||||
[1] TextView "10:04" clickable=false""",
|
||||
"expect": {"name": "open_app", "args": {"name": "Camera"}},
|
||||
"accept_names": ["open_app", "swipe"],
|
||||
},
|
||||
{
|
||||
"id": "task_done",
|
||||
"task": "Turn on Wi-Fi.",
|
||||
"screen": """[0] TextView "Network & internet" clickable=false
|
||||
[1] Switch "Wi-Fi" checked=true clickable=true
|
||||
[2] TextView "Connected to HOME-5G" clickable=false""",
|
||||
"expect": {"name": "task_complete", "args": {}},
|
||||
"accept_names": ["task_complete"],
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,279 @@
|
||||
"""A scored task suite, judged by what the phone shows rather than by what the
|
||||
agent said -- or by what the simulator happens to remember.
|
||||
|
||||
Three things were wrong with the first version of this file, and all three
|
||||
made it score more generously than it claimed to:
|
||||
|
||||
* **``add_alarm`` passed on any typed string containing "7".** Typing ``7``
|
||||
and stopping scored a success on a task whose prompt is "Set an alarm for
|
||||
7:30 AM": no minute, no meridiem, and no requirement that the alarm was ever
|
||||
saved. It now requires a *committed* alarm reading 7:30 AM, which the clock
|
||||
screen lists, so the check is one a real phone can also answer.
|
||||
* **``wifi_on_already`` scored final state only.** Its note said "any tap on
|
||||
the switch fails the task"; the code could not see a tap, so turning Wi-Fi
|
||||
off and back on passed. Switch flips are now recorded and the task fails on
|
||||
any of them -- which is the exact failure W4A8 exhibited (it turned Wi-Fi on
|
||||
and then tapped the switch off again).
|
||||
* **Predicates read ``SimulatedDevice`` attributes**, so every scored run was a
|
||||
simulator run by construction. They read :class:`PhoneState` now, which comes
|
||||
from the UI dump for both backends.
|
||||
|
||||
Repeats are only trials if something differs between them, so each task
|
||||
carries **variants**: the same goal against a renamed control, a reordered
|
||||
screen, or a different starting state. Five runs of one fixture at temperature
|
||||
0 measure repeatability; five variants measure whether the agent can do the
|
||||
task.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Callable
|
||||
|
||||
from device import SimElement, SimulatedDevice, demo_phone
|
||||
from phone_state import PhoneState, read_state
|
||||
|
||||
Predicate = Callable[[PhoneState], bool]
|
||||
|
||||
CLOCK_PACKAGE = "com.google.android.deskclock"
|
||||
"""Clock app to reset for the alarm tasks. AOSP builds and several OEMs ship a
|
||||
different package (``com.android.deskclock``, ``com.sec.android.app.clockpackage``
|
||||
on Samsung); override before a real-device run, because clearing the wrong
|
||||
package leaves a stale alarm and the next run scores against it."""
|
||||
|
||||
|
||||
# --------------------------------------------------------------- variations
|
||||
|
||||
def rename(screen: str, old: str, new: str) -> Callable[[SimulatedDevice], None]:
|
||||
"""Same control, different word. Android OEMs really do ship "WLAN"."""
|
||||
def apply(d: SimulatedDevice) -> None:
|
||||
for el in d.screens[screen].elements:
|
||||
if el.label == old:
|
||||
el.label = new
|
||||
return apply
|
||||
|
||||
|
||||
def reorder(screen: str, seed: int) -> Callable[[SimulatedDevice], None]:
|
||||
"""Shuffle the tappable rows. Index-based tapping must not be luck."""
|
||||
def apply(d: SimulatedDevice) -> None:
|
||||
els = d.screens[screen].elements
|
||||
head = [e for e in els if not e.clickable]
|
||||
body = [e for e in els if e.clickable]
|
||||
random.Random(seed).shuffle(body)
|
||||
d.screens[screen].elements = head + body
|
||||
return apply
|
||||
|
||||
|
||||
def decoy(screen: str, label: str) -> Callable[[SimulatedDevice], None]:
|
||||
"""A plausible wrong row, e.g. "Wi-Fi calling" next to "Wi-Fi"."""
|
||||
def apply(d: SimulatedDevice) -> None:
|
||||
d.screens[screen].elements.append(SimElement(label))
|
||||
return apply
|
||||
|
||||
|
||||
def chain(*fns: Callable[[SimulatedDevice], None]) -> Callable[[SimulatedDevice], None]:
|
||||
def apply(d: SimulatedDevice) -> None:
|
||||
for fn in fns:
|
||||
fn(d)
|
||||
return apply
|
||||
|
||||
|
||||
@dataclass
|
||||
class Variant:
|
||||
variant_id: str
|
||||
mutate: Callable[[SimulatedDevice], None] = lambda d: None
|
||||
|
||||
|
||||
# --------------------------------------------------------------------- task
|
||||
|
||||
@dataclass
|
||||
class Task:
|
||||
task_id: str
|
||||
prompt: str
|
||||
reaches: Predicate
|
||||
must_not: Predicate = lambda s: False
|
||||
setup: Callable[[SimulatedDevice], None] = lambda d: None
|
||||
max_steps: int = 10
|
||||
note: str = ""
|
||||
variants: list[Variant] = field(default_factory=lambda: [Variant("base")])
|
||||
needs: tuple[str, ...] = ()
|
||||
"""PhoneState facts this task's predicates require that a screen cannot
|
||||
show (``toggled``, ``fields``, ``records``). A task listing any of these
|
||||
cannot be scored on a real phone, and says so instead of scoring wrong."""
|
||||
reset_adb: tuple[tuple[str, ...], ...] = ()
|
||||
"""Commands that put a real phone into this task's starting state. Without
|
||||
them a real-device run is scored against an unknown start, so an empty
|
||||
tuple means "refuse to run me on a phone"."""
|
||||
|
||||
def variant(self, n: int) -> Variant:
|
||||
return self.variants[n % len(self.variants)]
|
||||
|
||||
def build(self, run: int = 0) -> SimulatedDevice:
|
||||
device = demo_phone()
|
||||
self.variant(run).mutate(device)
|
||||
self.setup(device)
|
||||
return device
|
||||
|
||||
def scorable_on(self, state: PhoneState) -> str | None:
|
||||
"""Why this task cannot be scored from ``state``, or None if it can."""
|
||||
if state.source == "device" and self.needs:
|
||||
return (f"needs {', '.join(self.needs)}, which a screen cannot "
|
||||
f"show; simulator only")
|
||||
return None
|
||||
|
||||
def score(self, device_or_state, declared_done: bool, run: int = 0) -> dict:
|
||||
state = (device_or_state if isinstance(device_or_state, PhoneState)
|
||||
else read_state(device_or_state))
|
||||
blocked = self.scorable_on(state)
|
||||
if blocked:
|
||||
return {"task_id": self.task_id, "variant": self.variant(run).variant_id,
|
||||
"scorable": False, "reason": blocked, "success": False,
|
||||
"reached_goal": None, "collateral_damage": None,
|
||||
"declared_done": declared_done}
|
||||
reached = bool(self.reaches(state))
|
||||
damaged = bool(self.must_not(state))
|
||||
return {
|
||||
"task_id": self.task_id,
|
||||
"variant": self.variant(run).variant_id,
|
||||
"scorable": True,
|
||||
"reached_goal": reached,
|
||||
"collateral_damage": damaged,
|
||||
"declared_done": declared_done,
|
||||
# The only row that counts: the phone is in the requested state,
|
||||
# nothing else was broken, and the agent knew to stop.
|
||||
"success": reached and not damaged and declared_done,
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------- oracles
|
||||
|
||||
# Both the on-screen labels and the setting key, because `switch()` matches
|
||||
# either source: "Wi-Fi" normalises onto the `wifi` setting by luck, but
|
||||
# "Airplane mode" does not normalise onto `airplane`, and a name the setting
|
||||
# lookup misses silently falls through to "control not on screen".
|
||||
WIFI = ("Wi-Fi", "WiFi", "WLAN", "wifi")
|
||||
AIRPLANE = ("Airplane mode", "Flight mode", "airplane")
|
||||
|
||||
|
||||
def _wifi_is(want: bool) -> Predicate:
|
||||
# `switch` returns None when the control is not on screen, which is not
|
||||
# the same as off: an agent that never navigated there has not turned
|
||||
# anything on.
|
||||
return lambda s: s.switch(*WIFI) is want
|
||||
|
||||
|
||||
def _airplane_on(s: PhoneState) -> bool:
|
||||
return s.switch(*AIRPLANE) is True
|
||||
|
||||
|
||||
def _alarm_set(hour: int, minute: int, pm: bool) -> Predicate:
|
||||
"""A *saved* alarm reading the requested time.
|
||||
|
||||
The clock screen lists committed alarms, so this reads the screen and works
|
||||
on a real phone. Typing the digits without saving leaves the list empty.
|
||||
"""
|
||||
wanted = f"{hour}:{minute:02d} {'PM' if pm else 'AM'}"
|
||||
return lambda s: s.has_text(wanted)
|
||||
|
||||
|
||||
SUITE: list[Task] = [
|
||||
Task(
|
||||
task_id="wifi_on",
|
||||
prompt="Turn on Wi-Fi.",
|
||||
reaches=_wifi_is(True),
|
||||
must_not=_airplane_on,
|
||||
note="Two screens deep, then a switch. The switch's state is visible, "
|
||||
"so stopping is decidable from the screen.",
|
||||
variants=[
|
||||
Variant("base"),
|
||||
Variant("wlan", rename("network", "Wi-Fi", "WLAN")),
|
||||
Variant("reordered", reorder("network", seed=7)),
|
||||
Variant("decoy", decoy("network", "Wi-Fi calling")),
|
||||
Variant("deep", chain(reorder("settings", seed=3),
|
||||
decoy("network", "Wi-Fi preferences"))),
|
||||
],
|
||||
reset_adb=(("shell", "svc", "wifi", "disable"),),
|
||||
),
|
||||
Task(
|
||||
task_id="wifi_on_already",
|
||||
prompt="Turn on Wi-Fi.",
|
||||
setup=lambda d: d.state.__setitem__("wifi", True),
|
||||
reaches=lambda s: s.switch(*WIFI) is True and s.times_toggled("wifi") == 0,
|
||||
must_not=_airplane_on,
|
||||
note="Already satisfied. The only correct action is task_complete. "
|
||||
"Any flip of the switch fails, including off-and-on again, which "
|
||||
"final state cannot see and which W4A8 actually did.",
|
||||
needs=("toggled",),
|
||||
variants=[
|
||||
Variant("base"),
|
||||
Variant("wlan", rename("network", "Wi-Fi", "WLAN")),
|
||||
Variant("reordered", reorder("network", seed=11)),
|
||||
],
|
||||
),
|
||||
Task(
|
||||
task_id="wifi_off",
|
||||
prompt="Turn off Wi-Fi.",
|
||||
setup=lambda d: d.state.__setitem__("wifi", True),
|
||||
reaches=_wifi_is(False),
|
||||
must_not=_airplane_on,
|
||||
note="The mirror of wifi_on: guards against a model that has simply "
|
||||
"learned to tap switches.",
|
||||
variants=[
|
||||
Variant("base"),
|
||||
Variant("wlan", rename("network", "Wi-Fi", "WLAN")),
|
||||
Variant("reordered", reorder("network", seed=5)),
|
||||
],
|
||||
reset_adb=(("shell", "svc", "wifi", "enable"),),
|
||||
),
|
||||
Task(
|
||||
task_id="airplane_on",
|
||||
prompt="Turn on airplane mode.",
|
||||
reaches=_airplane_on,
|
||||
note="Same screen as Wi-Fi, different row -- catches index confusion, "
|
||||
"which is why one variant reorders that screen.",
|
||||
variants=[
|
||||
Variant("base"),
|
||||
Variant("reordered", reorder("network", seed=2)),
|
||||
Variant("decoy", decoy("network", "Airplane mode settings")),
|
||||
],
|
||||
# `settings put global` needs WRITE_SECURE_SETTINGS, which adb has on a
|
||||
# debuggable build but not on every retail phone; the run fails loudly
|
||||
# if it is refused rather than scoring against an unknown start.
|
||||
reset_adb=(("shell", "settings", "put", "global", "airplane_mode_on", "0"),),
|
||||
),
|
||||
Task(
|
||||
task_id="open_clock",
|
||||
prompt="Open the Clock app and go to the Alarm tab.",
|
||||
reaches=lambda s: s.has_text("Add alarm") or s.has_text("Set time"),
|
||||
note="Navigation only, no state change. Isolates 'can it find an app' "
|
||||
"from 'can it finish'.",
|
||||
variants=[
|
||||
Variant("base"),
|
||||
Variant("reordered", reorder("home", seed=4)),
|
||||
Variant("decoy", decoy("home", "Clock Widget")),
|
||||
],
|
||||
reset_adb=(("shell", "am", "force-stop", CLOCK_PACKAGE),
|
||||
("shell", "input", "keyevent", "KEYCODE_HOME")),
|
||||
),
|
||||
Task(
|
||||
task_id="add_alarm",
|
||||
prompt="Set an alarm for 7:30 AM.",
|
||||
reaches=_alarm_set(7, 30, pm=False),
|
||||
must_not=lambda s: s.has_text("7:30 PM"),
|
||||
max_steps=12,
|
||||
note="The full flow: right app, right tab, add, type both fields, "
|
||||
"leave the meridiem alone, save. Previously this passed on any "
|
||||
"typed string containing '7'.",
|
||||
variants=[
|
||||
Variant("base"),
|
||||
Variant("reordered", reorder("clock", seed=9)),
|
||||
Variant("decoy", decoy("alarms", "Alarm settings")),
|
||||
],
|
||||
# `pm clear` removes saved alarms, so run N does not see run N-1's.
|
||||
reset_adb=(("shell", "pm", "clear", CLOCK_PACKAGE),
|
||||
("shell", "input", "keyevent", "KEYCODE_HOME")),
|
||||
),
|
||||
]
|
||||
|
||||
SUITE_BY_ID = {t.task_id: t for t in SUITE}
|
||||
Loaded 100 of 4605 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user