[Benchmark] Add local OmniInteract realtime benchmark (#6522)
Signed-off-by: natureofnature <wzliu@connect.hku.hk>
This commit is contained in:
1 parent
c608910d20
commit
497c537c6f
16 files changed
+3025
-149
No files matched your search
@@ -1,3 +1,6 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import io
|
||||
@@ -16,7 +19,6 @@ from dataclasses import dataclass, replace
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal
|
||||
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
|
||||
|
||||
import aiohttp
|
||||
import numpy as np
|
||||
@@ -31,6 +33,7 @@ from vllm.benchmarks.lib.endpoint_request_func import (
|
||||
RequestFuncOutput,
|
||||
StreamedResponseHandler,
|
||||
_get_chat_content,
|
||||
_get_headers,
|
||||
_update_headers_common,
|
||||
_update_payload_common,
|
||||
_validate_api_url,
|
||||
@@ -46,6 +49,13 @@ from vllm_omni.benchmarks.data_modules.daily_omni_dataset import (
|
||||
daily_omni_local_videos_dir,
|
||||
resolve_daily_omni_local_root,
|
||||
)
|
||||
from vllm_omni.benchmarks.data_modules.omniinteract_dataset import (
|
||||
DEFAULT_OMNIINTERACT_REPO,
|
||||
OmniInteractDataset,
|
||||
OmniInteractPreparedInput,
|
||||
OmniInteractSampleRequest,
|
||||
OmniInteractSessionOptions,
|
||||
)
|
||||
from vllm_omni.benchmarks.data_modules.random_multi_modal_dataset import OmniRandomMultiModalDataset
|
||||
from vllm_omni.benchmarks.data_modules.seed_tts_dataset import (
|
||||
SEED_TTS_DEFAULT_OMNI_SYSTEM_PROMPT,
|
||||
@@ -56,8 +66,27 @@ from vllm_omni.benchmarks.data_modules.seed_tts_dataset import (
|
||||
)
|
||||
from vllm_omni.benchmarks.data_modules.sound_effect_dataset import SoundEffectDataset
|
||||
from vllm_omni.benchmarks.data_modules.ttsd_dataset import TTSDDataset
|
||||
from vllm_omni.benchmarks.omniinteract import (
|
||||
VIDEO_FPS,
|
||||
OmniInteractBenchmarkConfig,
|
||||
OmniInteractCaseResult,
|
||||
clear_batch_artifacts,
|
||||
clear_case_artifacts,
|
||||
prepare_media,
|
||||
publish_deferred_case_artifacts,
|
||||
run_omniinteract_case,
|
||||
write_failure_artifacts,
|
||||
)
|
||||
from vllm_omni.benchmarks.omniinteract import (
|
||||
benchmark_summary as omniinteract_benchmark_summary,
|
||||
)
|
||||
from vllm_omni.benchmarks.omniinteract import (
|
||||
write_batch_artifacts as write_omniinteract_batch_artifacts,
|
||||
)
|
||||
from vllm_omni.experimental.fullduplex.client import (
|
||||
RealtimeDuplexClient,
|
||||
build_realtime_url,
|
||||
reference_audio_data_url,
|
||||
summarize_session_request_metrics,
|
||||
wait_for,
|
||||
)
|
||||
@@ -221,6 +250,91 @@ def _attach_seed_tts_to_request_func_input(sample: SampleRequest, rfi: RequestFu
|
||||
rfi.extra_body = base
|
||||
|
||||
|
||||
def _attach_omniinteract_to_request_func_input(sample: SampleRequest, rfi: RequestFuncInput) -> None:
|
||||
if not isinstance(sample, OmniInteractSampleRequest):
|
||||
return
|
||||
setattr(rfi, "omniinteract_case", sample.omniinteract_case)
|
||||
setattr(rfi, "omniinteract_options", sample.omniinteract_options)
|
||||
setattr(rfi, "omniinteract_prepared_input", sample.omniinteract_prepared_input)
|
||||
|
||||
|
||||
def _append_error(existing: str, message: str) -> str:
|
||||
return f"{existing}\n{message}" if existing else message
|
||||
|
||||
|
||||
def _finalize_omniinteract_batch(
|
||||
input_requests: list[SampleRequest],
|
||||
outputs: list[RequestFuncOutput],
|
||||
) -> dict[str, object] | None:
|
||||
rows = [
|
||||
(sample, output)
|
||||
for sample, output in zip(input_requests, outputs, strict=True)
|
||||
if isinstance(sample, OmniInteractSampleRequest)
|
||||
]
|
||||
if not rows:
|
||||
return None
|
||||
options = rows[0][0].omniinteract_options
|
||||
if not isinstance(options, OmniInteractSessionOptions):
|
||||
raise RuntimeError("OmniInteract benchmark output lost its artifact options")
|
||||
cases, results = [], []
|
||||
artifact_errors: list[str] = []
|
||||
for sample, output in rows:
|
||||
case = sample.omniinteract_case
|
||||
result = getattr(output, "omniinteract_case_result", None)
|
||||
if case is None or not isinstance(result, OmniInteractCaseResult):
|
||||
raise RuntimeError("OmniInteract benchmark output lost its dataset identity")
|
||||
cases.append(case)
|
||||
results.append(result)
|
||||
try:
|
||||
publish_deferred_case_artifacts(options.output_root, case, result)
|
||||
except Exception as exc: # noqa: BLE001 - artifact backends raise heterogeneous errors
|
||||
result.success = result.eligible_for_official_eval = False
|
||||
if "artifact_write_failed" not in result.official_eval_ineligible_reasons:
|
||||
result.official_eval_ineligible_reasons.append("artifact_write_failed")
|
||||
artifact_error = f"Artifact publication failed: {exc}"
|
||||
result.error = _append_error(result.error, artifact_error)
|
||||
output.error = _append_error(output.error, artifact_error)
|
||||
message = f"{case.subset}/{case.video_rel}: {artifact_error}"
|
||||
artifact_errors.append(message)
|
||||
logger.exception(message)
|
||||
try:
|
||||
write_failure_artifacts(options.output_root, case, result)
|
||||
except Exception as recovery_exc: # noqa: BLE001 - preserve benchmark metrics after I/O failure
|
||||
message = f"{case.subset}/{case.video_rel}: failure artifact publication failed: {recovery_exc}"
|
||||
artifact_errors.append(message)
|
||||
logger.exception(message)
|
||||
try:
|
||||
write_omniinteract_batch_artifacts(options.output_root, cases, results)
|
||||
except Exception as exc: # noqa: BLE001 - preserve benchmark metrics after I/O failure
|
||||
message = f"Batch artifact publication failed: {exc}"
|
||||
artifact_errors.append(message)
|
||||
logger.exception(message)
|
||||
try:
|
||||
clear_batch_artifacts(options.output_root)
|
||||
except Exception as cleanup_exc: # noqa: BLE001 - best-effort removal of partial batch artifacts
|
||||
message = f"Partial batch artifact cleanup failed: {cleanup_exc}"
|
||||
artifact_errors.append(message)
|
||||
logger.exception(message)
|
||||
summary = omniinteract_benchmark_summary(results)
|
||||
compact_summary = {key: value for key, value in summary.items() if key != "results"}
|
||||
compact_summary["artifacts_complete"] = not artifact_errors
|
||||
if artifact_errors:
|
||||
compact_summary["artifact_errors"] = artifact_errors
|
||||
return compact_summary
|
||||
|
||||
|
||||
def _prepare_omniinteract_batch(input_requests: list[SampleRequest]) -> None:
|
||||
roots: set[Path] = set()
|
||||
for sample in input_requests:
|
||||
if not isinstance(sample, OmniInteractSampleRequest):
|
||||
continue
|
||||
root = sample.omniinteract_options.output_root.resolve()
|
||||
roots.add(root)
|
||||
clear_case_artifacts(sample.omniinteract_options.output_root, sample.omniinteract_case)
|
||||
for root in roots:
|
||||
clear_batch_artifacts(root)
|
||||
|
||||
|
||||
def _daily_omni_repo_from_args(args) -> str | None:
|
||||
"""Resolve HuggingFace repo id for Daily-Omni from CLI args.
|
||||
|
||||
@@ -250,6 +364,7 @@ def get_samples(args, tokenizer):
|
||||
"ttsd",
|
||||
"sound-effect",
|
||||
)
|
||||
is_omniinteract = args.dataset_name == "omniinteract"
|
||||
|
||||
# Check if we need to handle omni-related backends/datasets
|
||||
is_omni_backend = args.backend in [
|
||||
@@ -258,12 +373,68 @@ def get_samples(args, tokenizer):
|
||||
"openai-realtime-duplex",
|
||||
"daily-omni",
|
||||
]
|
||||
is_omni_dataset = is_daily_omni or is_seed_tts or args.dataset_name == "random-mm"
|
||||
is_omni_dataset = is_daily_omni or is_seed_tts or is_omniinteract or args.dataset_name == "random-mm"
|
||||
|
||||
if not is_omni_backend and not is_omni_dataset:
|
||||
# Not an omni-related request, delegate to original implementation
|
||||
return get_samples_old(args, tokenizer)
|
||||
|
||||
if is_omniinteract:
|
||||
dataset_path = getattr(args, "dataset_path", None)
|
||||
data_root = None
|
||||
dataset_repo = DEFAULT_OMNIINTERACT_REPO
|
||||
if dataset_path:
|
||||
candidate = Path(dataset_path).expanduser()
|
||||
if candidate.exists() or candidate.is_absolute():
|
||||
data_root = str(candidate)
|
||||
else:
|
||||
dataset_repo = str(dataset_path)
|
||||
dataset = OmniInteractDataset(
|
||||
data_root=data_root,
|
||||
dataset_repo=dataset_repo,
|
||||
subsets=tuple(getattr(args, "omniinteract_subsets")),
|
||||
random_seed=args.seed,
|
||||
disable_shuffle=getattr(args, "disable_shuffle", False),
|
||||
)
|
||||
options = OmniInteractSessionOptions(
|
||||
output_root=Path(getattr(args, "omniinteract_output_dir")),
|
||||
timeout_s=float(getattr(args, "omniinteract_timeout_s")),
|
||||
media_timeout_s=float(getattr(args, "omniinteract_media_timeout_s")),
|
||||
ref_audio=str(getattr(args, "omniinteract_ref_audio")),
|
||||
require_response=bool(getattr(args, "omniinteract_require_response")),
|
||||
max_video_duration_s=float(getattr(args, "omniinteract_max_video_duration_s")),
|
||||
)
|
||||
requests = dataset.sample(
|
||||
tokenizer,
|
||||
args.num_prompts,
|
||||
request_id_prefix=args.request_id_prefix,
|
||||
options=options,
|
||||
)
|
||||
if not requests:
|
||||
raise ValueError("No OmniInteract sessions were selected")
|
||||
encoded_ref_audio = reference_audio_data_url(options.ref_audio)
|
||||
assert encoded_ref_audio is not None
|
||||
for request in requests:
|
||||
case = request.omniinteract_case
|
||||
assert isinstance(request, OmniInteractSampleRequest) and case is not None
|
||||
duration, pcm, frames = prepare_media(
|
||||
case.video_path,
|
||||
VIDEO_FPS,
|
||||
timeout_s=options.media_timeout_s,
|
||||
max_duration_s=options.max_video_duration_s,
|
||||
)
|
||||
if not any(frames):
|
||||
raise ValueError(f"No video frames were decoded from {case.video_path}")
|
||||
request.omniinteract_prepared_input = OmniInteractPreparedInput(
|
||||
duration_s=duration,
|
||||
pcm16=pcm,
|
||||
video_frames=tuple(frames),
|
||||
ref_audio_data_url=encoded_ref_audio,
|
||||
)
|
||||
# Replace OmniInteract's ``0`` (all) with the measured request count.
|
||||
args.num_prompts = len(requests)
|
||||
return requests
|
||||
|
||||
# Handle Daily-Omni dataset
|
||||
if is_daily_omni:
|
||||
# Support:
|
||||
@@ -476,6 +647,7 @@ class MixRequestFuncOutput(RequestFuncOutput):
|
||||
image_pixels: int = 0
|
||||
denoise_step_latency_ms: float = 0.0
|
||||
text_latency: float = 0.0
|
||||
tpot_measured: bool = True
|
||||
#: Worst-case streaming-audio underrun (wall-clock seconds the player
|
||||
#: would have been starved). Populated by the audio-speech backend; ``0.0``
|
||||
#: for backends that do not run continuity analysis.
|
||||
@@ -1313,11 +1485,115 @@ async def async_request_openai_audio_speech(
|
||||
|
||||
|
||||
def _realtime_websocket_url(api_url: str) -> str:
|
||||
parts = urlsplit(api_url)
|
||||
scheme = "wss" if parts.scheme == "https" else "ws"
|
||||
query = dict(parse_qsl(parts.query, keep_blank_values=True))
|
||||
query.setdefault("duplex", "1")
|
||||
return urlunsplit((scheme, parts.netloc, parts.path, urlencode(query), parts.fragment))
|
||||
return build_realtime_url(api_url, None, native_duplex=None)
|
||||
|
||||
|
||||
def _nonnegative_number(value: object) -> bool:
|
||||
return isinstance(value, int | float) and not isinstance(value, bool) and np.isfinite(value) and value >= 0
|
||||
|
||||
|
||||
async def _async_request_omniinteract(
|
||||
request_func_input: RequestFuncInput,
|
||||
*,
|
||||
pbar: tqdm | None,
|
||||
) -> MixRequestFuncOutput:
|
||||
case = getattr(request_func_input, "omniinteract_case", None)
|
||||
options = getattr(request_func_input, "omniinteract_options", None)
|
||||
output = MixRequestFuncOutput()
|
||||
output.prompt_len = request_func_input.prompt_len
|
||||
output.start_time = time.perf_counter()
|
||||
try:
|
||||
if case is None or not isinstance(options, OmniInteractSessionOptions):
|
||||
raise ValueError("OmniInteract RequestFuncInput is missing its dataset session layout")
|
||||
prepared_input = getattr(request_func_input, "omniinteract_prepared_input", None)
|
||||
if not isinstance(prepared_input, OmniInteractPreparedInput):
|
||||
raise ValueError("OmniInteract media must be prepared before benchmark request timing")
|
||||
headers = _get_headers()
|
||||
_update_headers_common(headers, request_func_input)
|
||||
config = OmniInteractBenchmarkConfig(
|
||||
endpoint=request_func_input.api_url,
|
||||
model=request_func_input.model_name or request_func_input.model,
|
||||
output_root=options.output_root,
|
||||
timeout_s=options.timeout_s,
|
||||
media_timeout_s=options.media_timeout_s,
|
||||
max_video_duration_s=options.max_video_duration_s,
|
||||
ref_audio=options.ref_audio,
|
||||
require_response=options.require_response,
|
||||
extra_headers=headers or None,
|
||||
extra_body=dict(request_func_input.extra_body or {}) or None,
|
||||
)
|
||||
case_result = await run_omniinteract_case(
|
||||
case,
|
||||
config,
|
||||
request_index=request_func_input.request_id or uuid.uuid4().hex,
|
||||
capture_artifacts=request_func_input.request_id is not None,
|
||||
prepared_input=prepared_input,
|
||||
)
|
||||
output.latency = case_result.latency_s
|
||||
output.generated_text = case_result.transcript
|
||||
output.output_tokens = case_result.output_tokens
|
||||
output.audio_duration = case_result.audio_bytes / (24_000 * 2)
|
||||
output.audio_frames = case_result.audio_bytes // 2
|
||||
session_metrics = case_result.duplex_session_metrics
|
||||
output.ttft = float(session_metrics.get("mean_ttft_ms") or 0.0) / 1000.0
|
||||
output.audio_ttfp = float(session_metrics.get("mean_ttfp_ms") or 0.0) / 1000.0
|
||||
output.audio_rtf = float(session_metrics.get("mean_rtf") or 0.0)
|
||||
stages: list[tuple[int, dict[str, object]]] = []
|
||||
for request_metric in case_result.duplex_request_metrics:
|
||||
stage0 = request_metric.get("stage0_tokens")
|
||||
if not isinstance(stage0, dict):
|
||||
continue
|
||||
token_count = stage0.get("output_token_count")
|
||||
if isinstance(token_count, int) and not isinstance(token_count, bool) and token_count >= 0:
|
||||
stages.append((token_count, stage0))
|
||||
timed = [(count - 1, stage) for count, stage in stages if count > 1]
|
||||
complete = (
|
||||
len(stages) == len(case_result.duplex_request_metrics)
|
||||
and sum(count for count, _ in stages) == output.output_tokens
|
||||
)
|
||||
exact = complete and all(
|
||||
isinstance(values := stage.get("itls_ms"), list)
|
||||
and len(values) == intervals
|
||||
and all(_nonnegative_number(value) for value in values)
|
||||
for intervals, stage in timed
|
||||
)
|
||||
output.itl = [float(value) / 1000.0 for _, stage in timed for value in stage["itls_ms"]] if exact else []
|
||||
if output.itl:
|
||||
output.text_latency = output.ttft + sum(output.itl)
|
||||
elif complete and timed and all(_nonnegative_number(stage.get("tpot_ms")) for _, stage in timed):
|
||||
intervals = sum(count for count, _ in timed)
|
||||
weighted_tpot = sum(float(stage["tpot_ms"]) * count for count, stage in timed) / intervals / 1000.0
|
||||
output.text_latency = output.ttft + weighted_tpot * (output.output_tokens - 1)
|
||||
else:
|
||||
output.text_latency = output.ttft
|
||||
output.tpot_measured = False
|
||||
if output.output_tokens > 1 or (output.output_tokens == 0 and output.generated_text):
|
||||
logger.warning(
|
||||
"OmniInteract session %s omitted complete engine token timing; standard TPOT/ITL are unavailable",
|
||||
case_result.session_id,
|
||||
)
|
||||
output.duplex_request_metrics = case_result.duplex_request_metrics
|
||||
output.duplex_session_metrics = session_metrics
|
||||
output.success = case_result.success
|
||||
output.error = case_result.error
|
||||
setattr(output, "omniinteract_case", case)
|
||||
setattr(output, "omniinteract_case_result", case_result)
|
||||
except Exception:
|
||||
output.success = False
|
||||
output.error = traceback.format_exc()
|
||||
logger.error("OmniInteract Realtime request failed: %s", output.error)
|
||||
if case is not None:
|
||||
case_result = OmniInteractCaseResult(
|
||||
subset=case.subset,
|
||||
video=str(case.video_path),
|
||||
output_dir="",
|
||||
error=output.error,
|
||||
)
|
||||
setattr(output, "omniinteract_case", case)
|
||||
setattr(output, "omniinteract_case_result", case_result)
|
||||
if pbar:
|
||||
pbar.update(1)
|
||||
return output
|
||||
|
||||
|
||||
async def async_request_openai_realtime_duplex(
|
||||
@@ -1325,8 +1601,9 @@ async def async_request_openai_realtime_duplex(
|
||||
session: aiohttp.ClientSession,
|
||||
pbar: tqdm | None = None,
|
||||
) -> MixRequestFuncOutput:
|
||||
"""Run one or more Seed-TTS turns through one explicit Realtime TTS session."""
|
||||
del session
|
||||
if getattr(request_func_input, "omniinteract_case", None) is not None:
|
||||
return await _async_request_omniinteract(request_func_input, pbar=pbar)
|
||||
output = MixRequestFuncOutput()
|
||||
output.prompt_len = request_func_input.prompt_len
|
||||
output.start_time = time.perf_counter()
|
||||
@@ -1387,8 +1664,10 @@ async def async_request_openai_realtime_duplex(
|
||||
)
|
||||
await client.send({"type": "response.create"})
|
||||
await wait_for(
|
||||
lambda: client.events.count("response.done") > done_before
|
||||
or len(client.events.errors()) > errors_before,
|
||||
lambda: (
|
||||
client.events.count("response.done") > done_before
|
||||
or len(client.events.errors()) > errors_before
|
||||
),
|
||||
timeout_s=180.0,
|
||||
label=f"Seed-TTS Realtime TTS turn {request_index} response.done",
|
||||
)
|
||||
@@ -1433,19 +1712,7 @@ async def async_request_openai_realtime_duplex(
|
||||
channels=1,
|
||||
)
|
||||
)
|
||||
turn_transcripts.append(
|
||||
"".join(
|
||||
str(event.get("delta") or "")
|
||||
for event in client.events.events
|
||||
if client.events.response_id(event) == response_id
|
||||
and event.get("type")
|
||||
in {
|
||||
"response.audio_transcript.delta",
|
||||
"response.output_text.delta",
|
||||
"response.text.delta",
|
||||
}
|
||||
)
|
||||
)
|
||||
turn_transcripts.append(client.events.response_text(response_id))
|
||||
await client.acknowledge_playback()
|
||||
request_finished_at = time.perf_counter()
|
||||
session_metrics = summarize_session_request_metrics(
|
||||
@@ -1520,6 +1787,7 @@ from vllm.benchmarks.serve import TaskType, calculate_metrics_for_embeddings, ge
|
||||
from vllm_omni.benchmarks.metrics.metrics import (
|
||||
MultiModalsBenchmarkMetrics,
|
||||
calculate_metrics,
|
||||
has_metric_samples,
|
||||
)
|
||||
|
||||
# ruff: noqa: E402
|
||||
@@ -1626,6 +1894,7 @@ async def benchmark(
|
||||
)
|
||||
_attach_daily_omni_to_request_func_input(input_requests[0], test_input)
|
||||
_attach_seed_tts_to_request_func_input(input_requests[0], test_input)
|
||||
_attach_omniinteract_to_request_func_input(input_requests[0], test_input)
|
||||
|
||||
if ready_check_timeout_sec > 0:
|
||||
test_output = await wait_for_endpoint(
|
||||
@@ -1741,6 +2010,7 @@ async def benchmark(
|
||||
print(f"Probe request rate: {probe_request_rate} req/s")
|
||||
probe_task = asyncio.create_task(probe_loop())
|
||||
|
||||
_prepare_omniinteract_batch(input_requests)
|
||||
benchmark_start_time = time.perf_counter()
|
||||
tasks: list[asyncio.Task] = []
|
||||
|
||||
@@ -1801,6 +2071,7 @@ async def benchmark(
|
||||
)
|
||||
_attach_daily_omni_to_request_func_input(request, request_func_input)
|
||||
_attach_seed_tts_to_request_func_input(request, request_func_input)
|
||||
_attach_omniinteract_to_request_func_input(request, request_func_input)
|
||||
tasks.append(
|
||||
asyncio.create_task(limited_request_func(request_func_input=request_func_input, session=session, pbar=pbar))
|
||||
)
|
||||
@@ -1815,6 +2086,8 @@ async def benchmark(
|
||||
|
||||
benchmark_duration = time.perf_counter() - benchmark_start_time
|
||||
|
||||
omniinteract_summary = _finalize_omniinteract_batch(input_requests, outputs)
|
||||
|
||||
if task_type == TaskType.GENERATION:
|
||||
metrics, actual_output_lens = calculate_metrics(
|
||||
input_requests=input_requests,
|
||||
@@ -1839,6 +2112,13 @@ async def benchmark(
|
||||
actual_output_lens = 0
|
||||
|
||||
if isinstance(metrics, MultiModalsBenchmarkMetrics):
|
||||
|
||||
def measured_ttft(output: RequestFuncOutput) -> float | None:
|
||||
session_metrics = getattr(output, "duplex_session_metrics", None)
|
||||
if isinstance(session_metrics, dict) and session_metrics.get("mean_ttft_ms") is None:
|
||||
return None
|
||||
return output.ttft
|
||||
|
||||
result = {
|
||||
"duration": benchmark_duration,
|
||||
"completed": metrics.completed,
|
||||
@@ -1859,7 +2139,7 @@ async def benchmark(
|
||||
"input_lens": [output.prompt_len for output in outputs],
|
||||
"start_times": [output.start_time for output in outputs],
|
||||
"output_lens": actual_output_lens,
|
||||
"ttfts": [output.ttft for output in outputs],
|
||||
"ttfts": [measured_ttft(output) for output in outputs],
|
||||
"itls": [output.itl for output in outputs],
|
||||
"generated_texts": [output.generated_text for output in outputs],
|
||||
"errors": [output.error for output in outputs],
|
||||
@@ -1893,6 +2173,8 @@ async def benchmark(
|
||||
]
|
||||
if duplex_session_metrics:
|
||||
result["duplex_session_metrics"] = duplex_session_metrics
|
||||
if omniinteract_summary is not None:
|
||||
result["omniinteract"] = omniinteract_summary
|
||||
|
||||
from vllm_omni.benchmarks.data_modules.daily_omni_eval import (
|
||||
compute_daily_omni_accuracy_metrics,
|
||||
@@ -1949,6 +2231,8 @@ async def benchmark(
|
||||
# metric.
|
||||
if metric_attribute_name not in result_percentile_metrics:
|
||||
return
|
||||
if not has_metric_samples(metrics, metric_attribute_name):
|
||||
return
|
||||
# No text tokens generated (e.g. pure TTS speech endpoint): per-token
|
||||
# latency metrics (ttft/tpot/itl) are undefined, so skip them.
|
||||
is_text_token_metric = not (metric_attribute_name == "e2el" or metric_attribute_name.startswith("audio"))
|
||||
|
||||
Reference in new issue
Block a user