Files changed (4) hide show
  1. app.py +122 -20
  2. data/p-video-2-leaderboard.csv +19 -0
  3. model_display.py +43 -0
  4. ui.py +40 -24
app.py CHANGED
@@ -2345,6 +2345,34 @@ def load_qwen_combined_dataframe(path):
2345
  return df.reset_index(drop=True)
2346
 
2347
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2348
  def load_video_editing_dataframe(path):
2349
  """Load the video-to-video editing leaderboard."""
2350
  df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
@@ -2378,27 +2406,62 @@ def load_video_editing_dataframe(path):
2378
  "Price / Second of Video (USD)",
2379
  ],
2380
  )
2381
- end_to_end = df.get("Time / Output Video Second (s)")
2382
- execution = df.get("Execution Time / Output Video Second (s)")
2383
- if end_to_end is not None:
2384
- if "model_id" in df.columns:
2385
- is_ours = df["model_id"].astype(str).str.lower().str.startswith(
2386
- "p_video_edit"
2387
- )
2388
- else:
2389
- is_ours = df["Model"].astype(str).str.casefold().str.startswith(
2390
- "p-video-edit"
2391
- )
2392
- if execution is None:
2393
- pareto_time = end_to_end
2394
- else:
2395
- ours_time = execution.where(execution.notna(), end_to_end)
2396
- pareto_time = end_to_end.where(~is_ours, ours_time)
2397
- df["Pareto Time / Output Video Second (s)"] = pareto_time
2398
  df = df.drop(columns=["model_id"], errors="ignore")
2399
  return df.reset_index(drop=True)
2400
 
2401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2402
  df = load_oneig_dataframe(oneig_path)
2403
 
2404
  oneig_metric_columns = [
@@ -2466,11 +2529,16 @@ video_path = _resolve_data_path(
2466
  data_dir / "video-editing-leaderboard.csv",
2467
  space_root.parent / "video-editing-leaderboard.csv",
2468
  )
 
 
 
 
2469
 
2470
  qwen_df = load_qwen_combined_dataframe(qwen_path)
2471
  aa_df = load_artificial_analysis_dataframe(aa_path)
2472
  arena_df = load_arena_ai_dataframe(arena_path)
2473
  video_df = load_video_editing_dataframe(video_path)
 
2474
  qwen_display_columns = [
2475
  col
2476
  for col in [
@@ -2514,6 +2582,19 @@ video_display_columns = [
2514
  ]
2515
  if col in video_df.columns
2516
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
2517
 
2518
  oneig_samples = load_sample_comparison_data(oneig_combined_dir)
2519
  qwen_samples = load_sample_comparison_data(qwen_combined_dir)
@@ -2577,8 +2658,26 @@ arena_metric_ids = _metric_ids_for(
2577
  ],
2578
  )
2579
  video_metric_ids = _metric_ids_for(video_df, ["datapoint_elo"])
 
 
 
2580
 
2581
  datasets = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2582
  {
2583
  "id": "video_editing",
2584
  "name": "Pruna Internal Video-Edit Benchmark",
@@ -2640,10 +2739,13 @@ datasets = [
2640
  datasets = [dataset for dataset in datasets if dataset["metric_ids"]]
2641
 
2642
  DEFAULT_DATASET_ID = next(
2643
- (dataset["id"] for dataset in datasets if dataset["id"] == "video_editing"),
2644
  next(
2645
- (dataset["id"] for dataset in datasets if dataset["id"] == "qwen"),
2646
- datasets[0]["id"] if datasets else None,
 
 
 
2647
  ),
2648
  )
2649
  DEFAULT_METRIC_ID = None
 
2345
  return df.reset_index(drop=True)
2346
 
2347
 
2348
+ def _is_pruna_video_model(series):
2349
+ models = series.astype(str).str.casefold()
2350
+ return models.str.startswith("p_video") | models.str.startswith("p-video")
2351
+
2352
+
2353
+ def _apply_video_timings(df, *, replace_displayed_time=False):
2354
+ """Mix Fal wall time with Pruna model execution time."""
2355
+ fal = df.get("Time / Output Video Second (s)")
2356
+ execution = df.get("Execution Time / Output Video Second (s)")
2357
+ if fal is None:
2358
+ return df
2359
+
2360
+ if "model_id" in df.columns:
2361
+ is_ours = _is_pruna_video_model(df["model_id"])
2362
+ else:
2363
+ is_ours = _is_pruna_video_model(df["Model"])
2364
+
2365
+ if execution is None:
2366
+ mixed = fal
2367
+ else:
2368
+ ours_time = execution.where(execution.notna(), fal)
2369
+ mixed = fal.where(~is_ours, ours_time)
2370
+ if replace_displayed_time:
2371
+ df["Time / Output Video Second (s)"] = mixed
2372
+ df["Pareto Time / Output Video Second (s)"] = mixed
2373
+ return df
2374
+
2375
+
2376
  def load_video_editing_dataframe(path):
2377
  """Load the video-to-video editing leaderboard."""
2378
  df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
 
2406
  "Price / Second of Video (USD)",
2407
  ],
2408
  )
2409
+ df = _apply_video_timings(df)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2410
  df = df.drop(columns=["model_id"], errors="ignore")
2411
  return df.reset_index(drop=True)
2412
 
2413
 
2414
+ def load_text_to_video_dataframe(path):
2415
+ """Load the text-to-video leaderboard (P-Video-2 and Fal models)."""
2416
+ df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
2417
+ model_column = "model_id" if "model_id" in df.columns else "Model"
2418
+ df = df[~df[model_column].astype(str).str.casefold().str.startswith("agnes")].copy()
2419
+ df = df.rename(
2420
+ columns={
2421
+ "model_id": "Model",
2422
+ "datapoint_elo": "Datapoint Elo",
2423
+ "rapidata_elo": "Rapidata Elo",
2424
+ "min_generation_s": "Min Generation Time (s)",
2425
+ "median_generation_s": "Median Generation Time (s)",
2426
+ "p20_generation_s": "P20 Generation Time (s)",
2427
+ "generation_s_per_output_video_s": "Time / Output Video Second (s)",
2428
+ "model_execution_s_per_output_video_s": (
2429
+ "Execution Time / Output Video Second (s)"
2430
+ ),
2431
+ "price_usd_per_second": "Price / Second of Video (USD)",
2432
+ }
2433
+ )
2434
+ df = df.drop(columns=["wandb_run_ids", "n_generations"], errors="ignore")
2435
+ df["Model"] = df["Model"].astype(str).str.strip()
2436
+ df = _as_numeric(
2437
+ df,
2438
+ [
2439
+ "Datapoint Elo",
2440
+ "Rapidata Elo",
2441
+ "Min Generation Time (s)",
2442
+ "Median Generation Time (s)",
2443
+ "P20 Generation Time (s)",
2444
+ "Time / Output Video Second (s)",
2445
+ "Execution Time / Output Video Second (s)",
2446
+ "Price / Second of Video (USD)",
2447
+ ],
2448
+ )
2449
+ # Pruna rows use model execution time; Fal rows keep Fal wall time.
2450
+ df = _apply_video_timings(df, replace_displayed_time=True)
2451
+ df = df.drop(
2452
+ columns=["Execution Time / Output Video Second (s)"],
2453
+ errors="ignore",
2454
+ )
2455
+ elo_columns = [
2456
+ column
2457
+ for column in ("Datapoint Elo", "Rapidata Elo")
2458
+ if column in df.columns
2459
+ ]
2460
+ if elo_columns:
2461
+ df = df.dropna(subset=elo_columns, how="all")
2462
+ return df.reset_index(drop=True)
2463
+
2464
+
2465
  df = load_oneig_dataframe(oneig_path)
2466
 
2467
  oneig_metric_columns = [
 
2529
  data_dir / "video-editing-leaderboard.csv",
2530
  space_root.parent / "video-editing-leaderboard.csv",
2531
  )
2532
+ text_to_video_path = _resolve_data_path(
2533
+ data_dir / "p-video-2-leaderboard.csv",
2534
+ space_root.parent / "p-video-2-leaderboard.csv",
2535
+ )
2536
 
2537
  qwen_df = load_qwen_combined_dataframe(qwen_path)
2538
  aa_df = load_artificial_analysis_dataframe(aa_path)
2539
  arena_df = load_arena_ai_dataframe(arena_path)
2540
  video_df = load_video_editing_dataframe(video_path)
2541
+ text_to_video_df = load_text_to_video_dataframe(text_to_video_path)
2542
  qwen_display_columns = [
2543
  col
2544
  for col in [
 
2582
  ]
2583
  if col in video_df.columns
2584
  ]
2585
+ text_to_video_display_columns = [
2586
+ col
2587
+ for col in [
2588
+ "Model",
2589
+ "Datapoint Elo",
2590
+ "Rapidata Elo",
2591
+ "Time / Output Video Second (s)",
2592
+ "Median Generation Time (s)",
2593
+ "Min Generation Time (s)",
2594
+ "Price / Second of Video (USD)",
2595
+ ]
2596
+ if col in text_to_video_df.columns
2597
+ ]
2598
 
2599
  oneig_samples = load_sample_comparison_data(oneig_combined_dir)
2600
  qwen_samples = load_sample_comparison_data(qwen_combined_dir)
 
2658
  ],
2659
  )
2660
  video_metric_ids = _metric_ids_for(video_df, ["datapoint_elo"])
2661
+ text_to_video_metric_ids = _metric_ids_for(
2662
+ text_to_video_df, ["datapoint_elo", "rapidata_elo"]
2663
+ )
2664
 
2665
  datasets = [
2666
+ {
2667
+ "id": "text_to_video",
2668
+ "name": "VBench-2.0 Dataset",
2669
+ "modality": "text_to_video",
2670
+ "data": text_to_video_df,
2671
+ "columns": text_to_video_display_columns,
2672
+ "metric_ids": text_to_video_metric_ids,
2673
+ "note": (
2674
+ "Datapoint Elo and Rapidata Elo from pairwise text-to-video "
2675
+ "preference. Price is USD per second of output video. Time per "
2676
+ "second of video is Fal wall time, except Pruna models which use "
2677
+ "model execution time."
2678
+ ),
2679
+ "samples": None,
2680
+ },
2681
  {
2682
  "id": "video_editing",
2683
  "name": "Pruna Internal Video-Edit Benchmark",
 
2739
  datasets = [dataset for dataset in datasets if dataset["metric_ids"]]
2740
 
2741
  DEFAULT_DATASET_ID = next(
2742
+ (dataset["id"] for dataset in datasets if dataset["id"] == "text_to_video"),
2743
  next(
2744
+ (dataset["id"] for dataset in datasets if dataset["id"] == "video_editing"),
2745
+ next(
2746
+ (dataset["id"] for dataset in datasets if dataset["id"] == "qwen"),
2747
+ datasets[0]["id"] if datasets else None,
2748
+ ),
2749
  ),
2750
  )
2751
  DEFAULT_METRIC_ID = None
data/p-video-2-leaderboard.csv ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ model_id,wandb_run_ids,n_generations,min_generation_s,median_generation_s,p20_generation_s,generation_s_per_output_video_s,model_execution_s_per_output_video_s,datapoint_elo,rapidata_elo,price_usd_per_second
2
+ gemini_omni_1_1_flash,mfajagum,89,26.276599962002365,31.884095050001633,29.0771403791965,6.399738597206617,,1037,1197,0.100
3
+ grok_imagine_video,q39r8v9e,90,68.9776645039965,99.17614604350092,78.69151808420138,16.13514411181308,,958,994,0.050
4
+ grok_imagine_video_v1_5,z2fp7hd7,90,38.42492011199647,52.268091876499966,46.47850653079659,11.452002471104521,,959,1016,0.140
5
+ ltx_2_5_fast,h6se1hfi,90,21.695961473000352,26.684429597007693,24.118977216200438,5.270079915707363,,1002,1035,0.090
6
+ ltx_2_5_pro,kjbgxbab,90,23.997383733993047,27.897931821993552,25.263995286799037,4.936325968288616,,1007,978,0.120
7
+ minimax_h3,xpcv2m58,89,97.61419671699696,117.51345164199665,106.57570995900024,24.968780374361877,,1026,1108,0.100
8
+ minimax_h3_max,0d2lkmp6,90,4.173863318999793,4.49869444649994,4.4671880990012145,1.3807388451000264,0.644,1031,1197,0.080
9
+ minimax_h3_max_turbo__prompt_expansion_mode_balanced,kxuwq31c,90,2.891819470001792,3.487746603501364,3.134695611400821,1.35231252479333,0.61,1040,1214,0.040
10
+ p_video_2__draft_false__prompt_upsampling_false__resolution_1080p,9hgkhujw,90,13.33159556199098,16.702878594005597,14.793676785795833,4.033411242884629,2.151682222222222,,,0.050
11
+ p_video_2__draft_false__prompt_upsampling_false__resolution_720p,m2jf4z7h,89,5.859760620005545,8.162274362999597,7.147269867203431,2.1525601170473116,0.9053123595505614,,,0.025
12
+ p_video_2__draft_false__prompt_upsampling_true__resolution_1080p,uoqpv10b,90,14.615217412007041,18.316011337505188,16.441080821005745,4.5638632221758275,2.152566666666667,979,991,0.050
13
+ p_video_2__draft_false__prompt_upsampling_true__resolution_720p,2q5jydr8,90,7.227749306999613,9.880705762494472,9.154919161600992,2.4789854674801206,0.9079755555555558,985,1039,0.025
14
+ p_video_2__draft_true__prompt_upsampling_false__resolution_1080p,qbt0atz4,89,6.250065040003392,9.528199804000906,7.504525098402519,2.431133616615736,0.7517640449438197,,,0.030
15
+ p_video_2__draft_true__prompt_upsampling_false__resolution_720p,9ur57h54,88,3.379928643000312,5.454214365498046,4.208131522199255,1.4960965825225272,0.40954545454545455,,,0.015
16
+ p_video_2__draft_true__prompt_upsampling_true__resolution_1080p,gcbyy4wn,90,8.047415203996934,11.128662197996164,9.22702455239487,2.8557857865532665,0.7514066666666668,,,0.030
17
+ p_video_2__draft_true__prompt_upsampling_true__resolution_720p,6hi994vk,90,4.985804016003385,7.4922584965024726,6.472871531004785,2.4024102996157146,0.40678444444444434,982,1048,0.015
18
+ seedance_2_5_turbo,l9zjnv7n,90,168.997338743,252.07832621250054,211.93920676639829,67.60899374696221,,1037,1080,0.200
19
+ veo_3_1_lite,jjbobes4,90,33.894167409991496,37.83729844300251,37.009501291197374,6.745116482181308,,968,986,0.050
model_display.py CHANGED
@@ -95,6 +95,17 @@ MODEL_DISPLAY_NAMES = {
95
  "P-Video Edit Final (draft)": "P-Video-Edit Draft",
96
  "p_video_edit_preview__replicate_final": "P-Video-Edit",
97
  "p_video_edit_preview__replicate_final__draft": "P-Video-Edit Draft",
 
 
 
 
 
 
 
 
 
 
 
98
  # Video-to-video leaderboard
99
  "gemini_omni_flash_edit__fal": "Gemini Omni Flash Edit",
100
  "grok_imagine_video__replicate": "Grok Imagine Video",
@@ -201,6 +212,35 @@ MODEL_DISPLAY_NAMES = {
201
  }
202
 
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  def _prettify_snake_case(model_id: str) -> str:
205
  parts = [part for part in str(model_id).split("_") if part]
206
  pretty = []
@@ -225,6 +265,9 @@ def display_model_name(model_id) -> str:
225
  return ""
226
  if raw in MODEL_DISPLAY_NAMES:
227
  return MODEL_DISPLAY_NAMES[raw]
 
 
 
228
  # Already a human label (spaces / punctuation) — keep as-is.
229
  if re.search(r"[\s.\[\]()-]", raw):
230
  return raw
 
95
  "P-Video Edit Final (draft)": "P-Video-Edit Draft",
96
  "p_video_edit_preview__replicate_final": "P-Video-Edit",
97
  "p_video_edit_preview__replicate_final__draft": "P-Video-Edit Draft",
98
+ # Text-to-video leaderboard
99
+ "gemini_omni_1_1_flash": "Gemini Omni 1.1 Flash",
100
+ "grok_imagine_video": "Grok Imagine Video",
101
+ "grok_imagine_video_v1_5": "Grok Imagine Video 1.5",
102
+ "ltx_2_5_fast": "LTX 2.5 Fast",
103
+ "ltx_2_5_pro": "LTX 2.5 Pro",
104
+ "minimax_h3": "MiniMax H3",
105
+ "minimax_h3_max": "MiniMax H3 Max",
106
+ "minimax_h3_max_turbo__prompt_expansion_mode_balanced": "MiniMax H3 Max Turbo",
107
+ "seedance_2_5_turbo": "Seedance 2.5 Turbo",
108
+ "veo_3_1_lite": "Veo 3.1 Lite",
109
  # Video-to-video leaderboard
110
  "gemini_omni_flash_edit__fal": "Gemini Omni Flash Edit",
111
  "grok_imagine_video__replicate": "Grok Imagine Video",
 
212
  }
213
 
214
 
215
+ def _p_video_2_display_name(model_id: str):
216
+ """Turn p_video_2 variant ids into P-Video-2 Draft 720p labels."""
217
+ raw = str(model_id).strip()
218
+ if raw != "p_video_2" and not raw.startswith("p_video_2__"):
219
+ return None
220
+ if raw == "p_video_2":
221
+ return "P-Video-2"
222
+
223
+ draft = False
224
+ upsample = None
225
+ resolution = None
226
+ for part in raw.split("__")[1:]:
227
+ if part.startswith("draft_"):
228
+ draft = part.endswith("true")
229
+ elif part.startswith("prompt_upsampling_"):
230
+ upsample = part.endswith("true")
231
+ elif part.startswith("resolution_"):
232
+ resolution = part[len("resolution_") :]
233
+
234
+ label = "P-Video-2"
235
+ if draft:
236
+ label += " Draft"
237
+ if resolution:
238
+ label += f" {resolution}"
239
+ if upsample is False:
240
+ label += " (no prompt upsampling)"
241
+ return label
242
+
243
+
244
  def _prettify_snake_case(model_id: str) -> str:
245
  parts = [part for part in str(model_id).split("_") if part]
246
  pretty = []
 
265
  return ""
266
  if raw in MODEL_DISPLAY_NAMES:
267
  return MODEL_DISPLAY_NAMES[raw]
268
+ p_video_2 = _p_video_2_display_name(raw)
269
+ if p_video_2:
270
+ return p_video_2
271
  # Already a human label (spaces / punctuation) — keep as-is.
272
  if re.search(r"[\s.\[\]()-]", raw):
273
  return raw
ui.py CHANGED
@@ -53,9 +53,11 @@ TAB_PARETO = "pareto"
53
  TAB_SAMPLES = "samples"
54
  TAB_ABOUT = "about"
55
 
 
56
  MODALITY_VIDEO_TO_VIDEO = "video_to_video"
57
  MODALITY_TEXT_TO_IMAGE = "text_to_image"
58
  MODALITY_CHOICES = [
 
59
  ("Video to Video", MODALITY_VIDEO_TO_VIDEO),
60
  ("Text to Image", MODALITY_TEXT_TO_IMAGE),
61
  ]
@@ -71,15 +73,15 @@ _VIEW_EVENTS = {
71
  ABOUT_OVERVIEW_CONTENT = """
72
  # About P-Bench
73
 
74
- P-Bench compares **text-to-image** and **video-to-video** models, including
75
- optimized or accelerated endpoints, on **quality, speed, and price**. Each
76
- view is a **dataset** scored with a **metric**, written as `Dataset | Metric`.
77
- There is no single score across P-Bench.
78
 
79
  ## How to read it
80
 
81
- 1. Pick a **type** (Video to Video or Text to Image), then a **dataset**
82
- and a **metric**.
83
  2. **Leaderboards**: ranked by that metric. Price and generation time sit in
84
  the same table when the source publishes them.
85
  3. **Pareto plots**: mark models that are not beaten on both higher score
@@ -87,7 +89,7 @@ There is no single score across P-Bench.
87
  can open this tab (not Arena AI).
88
  4. **Samples**: the same prompts, side by side. Only for datasets we
89
  generated (Qwen Image Dataset, OneIG Alignment Dataset, and the
90
- Pruna Internal Video-Edit Benchmark). Video samples show the source
91
  clip first, then each model's edit.
92
 
93
  ## How a score is made
@@ -107,6 +109,13 @@ prompt suites, so samples are not shown.
107
 
108
  ## Current datasets
109
 
 
 
 
 
 
 
 
110
  ### Pruna Internal Video-Edit Benchmark
111
  Pruna's internal video-to-video editing benchmark, collected by our
112
  research engineers. It combines prompts from public video-editing
@@ -162,12 +171,15 @@ ABOUT_DETAILS_CONTENT = """
162
  text rendering).
163
  - **Generation time**: median and minimum generation time in seconds for
164
  images, as reported in the evaluation table. For video, generation time
165
- per second of output video is the more informative figure (end-to-end
166
- wall time). This is not a p95, and we do not state warm vs cold or
167
- concurrent load. Not available for Arena AI.
 
 
168
  - **Price**: USD per image for text-to-image, or USD per second of output
169
- video for video-to-video. We do not state list price vs amount paid, or
170
- whether failed generations are included. Not available for Arena AI.
 
171
 
172
  Scores from different datasets or metrics are **not interchangeable**. A high
173
  OneIG alignment score is not the same quantity as a Datapoint Elo. Compare
@@ -181,16 +193,19 @@ models *within* a Dataset | Metric view.
181
  - **Prompt counts:** OneIG Alignment uses 100 anime, 100 human, and 99 object
182
  prompts (299 total). Qwen Image Dataset uses 100 prompts sampled from the
183
  1,000-prompt pool for roughly even coverage of its fine-grained (L3)
184
- categories. The Pruna Internal Video-Edit Benchmark uses 78 prompts
185
- across advertising, e-commerce, real estate, camera, lighting, text, and
186
- related categories. Artificial Analysis and Arena AI use their own
187
- private prompt sets.
 
188
  - **Generation (Qwen and OneIG):** one image per prompt per endpoint when
189
  the run exists. Default resolution is 1024×1024. Exceptions: FLUX 1.1 Pro
190
  Ultra at 2K, FLUX 2 Flex at 1008×1008, and any endpoint labeled 2K. The
191
  seed is derived from the prompt, so every model gets the same seed for the
192
  same prompt. Steps, CFG, prompt rewrite, and safety filters follow each
193
  endpoint's default. This does not describe Artificial Analysis or Arena AI.
 
 
194
  - **Generation (Video-Edit):** one edited clip per prompt per endpoint when
195
  the run exists. Every model sees the same source video for a prompt.
196
  - **Datapoint (Qwen and OneIG):** every model pair is compared on every
@@ -1370,11 +1385,11 @@ def _filter_row(datasets, metrics, default_dataset_id, default_metric_id=None):
1370
  modality_dd = gr.Dropdown(
1371
  choices=_modality_choices(datasets),
1372
  value=default_modality,
1373
- label="Type",
1374
  type="value",
1375
  filterable=False,
1376
  scale=1,
1377
- min_width=150,
1378
  )
1379
  dataset_dd = gr.Dropdown(
1380
  choices=_dataset_choices(datasets, modality=default_modality),
@@ -1424,12 +1439,13 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1424
  with gr.Column(elem_classes="workspace-filters") as filters_host:
1425
  gr.Markdown(
1426
  "<p class='filter-help'>"
1427
- "Start with Type to switch between Video to Video and Text "
1428
- "to Image. The rest of the filters follow you across "
1429
- "Leaderboards, Pareto plots, and Samples. Samples only "
1430
- "lists datasets and models we have generations for; Pareto "
1431
- "plots only lists datasets with price or generation time. "
1432
- "Search in Models, or leave it empty to include every model."
 
1433
  "</p>",
1434
  elem_classes="filter-help-host",
1435
  )
 
53
  TAB_SAMPLES = "samples"
54
  TAB_ABOUT = "about"
55
 
56
+ MODALITY_TEXT_TO_VIDEO = "text_to_video"
57
  MODALITY_VIDEO_TO_VIDEO = "video_to_video"
58
  MODALITY_TEXT_TO_IMAGE = "text_to_image"
59
  MODALITY_CHOICES = [
60
+ ("Text to Video", MODALITY_TEXT_TO_VIDEO),
61
  ("Video to Video", MODALITY_VIDEO_TO_VIDEO),
62
  ("Text to Image", MODALITY_TEXT_TO_IMAGE),
63
  ]
 
73
  ABOUT_OVERVIEW_CONTENT = """
74
  # About P-Bench
75
 
76
+ P-Bench compares **text-to-video**, **video-to-video**, and **text-to-image**
77
+ models, including optimized or accelerated endpoints, on **quality, speed,
78
+ and price**. Each view is a **dataset** scored with a **metric**, written as
79
+ `Dataset | Metric`. There is no single score across P-Bench.
80
 
81
  ## How to read it
82
 
83
+ 1. Pick a **model type** (Text to Video, Video to Video, or Text to Image),
84
+ then a **dataset** and a **metric**.
85
  2. **Leaderboards**: ranked by that metric. Price and generation time sit in
86
  the same table when the source publishes them.
87
  3. **Pareto plots**: mark models that are not beaten on both higher score
 
89
  can open this tab (not Arena AI).
90
  4. **Samples**: the same prompts, side by side. Only for datasets we
91
  generated (Qwen Image Dataset, OneIG Alignment Dataset, and the
92
+ Pruna Internal Video-Edit Benchmark). Video-edit samples show the source
93
  clip first, then each model's edit.
94
 
95
  ## How a score is made
 
109
 
110
  ## Current datasets
111
 
112
+ ### VBench-2.0 Dataset
113
+ VBench-2.0 prompts, comparing P-Video-2 variants with Fal-hosted models.
114
+ Quality is Datapoint Elo and Rapidata Elo from pairwise preference. Price
115
+ is USD per second of output video. Time per second of video is Fal wall
116
+ time, except Pruna models which use model execution time. Samples are not
117
+ shown for this dataset.
118
+
119
  ### Pruna Internal Video-Edit Benchmark
120
  Pruna's internal video-to-video editing benchmark, collected by our
121
  research engineers. It combines prompts from public video-editing
 
171
  text rendering).
172
  - **Generation time**: median and minimum generation time in seconds for
173
  images, as reported in the evaluation table. For video, generation time
174
+ per second of output video is the more informative figure. On the
175
+ text-to-video benchmark this is Fal wall time, except Pruna models which
176
+ use model execution time. On video-edit it is end-to-end wall time. This
177
+ is not a p95, and we do not state warm vs cold or concurrent load. Not
178
+ available for Arena AI.
179
  - **Price**: USD per image for text-to-image, or USD per second of output
180
+ video for text-to-video and video-to-video. We do not state list price vs
181
+ amount paid, or whether failed generations are included. Not available
182
+ for Arena AI.
183
 
184
  Scores from different datasets or metrics are **not interchangeable**. A high
185
  OneIG alignment score is not the same quantity as a Datapoint Elo. Compare
 
193
  - **Prompt counts:** OneIG Alignment uses 100 anime, 100 human, and 99 object
194
  prompts (299 total). Qwen Image Dataset uses 100 prompts sampled from the
195
  1,000-prompt pool for roughly even coverage of its fine-grained (L3)
196
+ categories. The VBench-2.0 Dataset uses about 90
197
+ generations per model. The Pruna Internal Video-Edit Benchmark uses 78
198
+ prompts across advertising, e-commerce, real estate, camera, lighting,
199
+ text, and related categories. Artificial Analysis and Arena AI use their
200
+ own private prompt sets.
201
  - **Generation (Qwen and OneIG):** one image per prompt per endpoint when
202
  the run exists. Default resolution is 1024×1024. Exceptions: FLUX 1.1 Pro
203
  Ultra at 2K, FLUX 2 Flex at 1008×1008, and any endpoint labeled 2K. The
204
  seed is derived from the prompt, so every model gets the same seed for the
205
  same prompt. Steps, CFG, prompt rewrite, and safety filters follow each
206
  endpoint's default. This does not describe Artificial Analysis or Arena AI.
207
+ - **Generation (Text-to-Video):** one clip per prompt per endpoint when the
208
+ run exists. About 90 generations per model.
209
  - **Generation (Video-Edit):** one edited clip per prompt per endpoint when
210
  the run exists. Every model sees the same source video for a prompt.
211
  - **Datapoint (Qwen and OneIG):** every model pair is compared on every
 
1385
  modality_dd = gr.Dropdown(
1386
  choices=_modality_choices(datasets),
1387
  value=default_modality,
1388
+ label="Model Type",
1389
  type="value",
1390
  filterable=False,
1391
  scale=1,
1392
+ min_width=170,
1393
  )
1394
  dataset_dd = gr.Dropdown(
1395
  choices=_dataset_choices(datasets, modality=default_modality),
 
1439
  with gr.Column(elem_classes="workspace-filters") as filters_host:
1440
  gr.Markdown(
1441
  "<p class='filter-help'>"
1442
+ "Start with Model Type to switch modalities. The rest of "
1443
+ "the filters follow you across Leaderboards, Pareto plots, "
1444
+ "and Samples. "
1445
+ "Samples only lists datasets and models we have generations "
1446
+ "for; Pareto plots only lists datasets with price or "
1447
+ "generation time. Search in Models, or leave it empty to "
1448
+ "include every model."
1449
  "</p>",
1450
  elem_classes="filter-help-host",
1451
  )