.gitignore CHANGED
@@ -176,8 +176,4 @@ cython_debug/
176
  evaluation_results/
177
  images/
178
  hf_cache/
179
- *.lock
180
-
181
- # macOS
182
- .DS_Store
183
-
 
176
  evaluation_results/
177
  images/
178
  hf_cache/
179
+ *.lock
 
 
 
 
README.md CHANGED
@@ -14,22 +14,11 @@ tags:
14
 
15
  # P-Bench
16
 
17
- Compare text-to-image, text-to-video, image-to-video, and video-to-video
18
- models on quality, speed, and price. This repo is the
19
  Gradio dashboard: leaderboards, Pareto plots, and side-by-side samples.
20
 
21
  The live Space is [PrunaAI/P-Bench](https://huggingface.co/spaces/PrunaAI/P-Bench).
22
 
23
- The current P-Video-2 Pro evaluation snapshots are
24
- `data/t2v-pro.csv` (text-to-video) and
25
- `data/i2v-pro.csv` (image-to-video). Both feed the leaderboards and
26
- price/time Pareto plots with Datapoint and Rapidata Elo. All
27
- models appear in the video-generation leaderboards, including variants with
28
- missing scores. Missing scores and ranks display as dashes; Pareto plots
29
- include only models with the required score and price or timing. Image-to-video
30
- sample media is not included in these exports.
31
- Rapidata Elo comes directly from these exports.
32
-
33
  ## Run locally
34
 
35
  From the repo root:
@@ -41,6 +30,8 @@ pip install "gradio==5.19.0" pandas -r requirements.txt
41
  python app.py
42
  ```
43
 
 
 
44
  `requirements.txt` lists Plotly. Gradio and pandas are required locally;
45
  Hugging Face Spaces installs Gradio from the YAML `sdk_version` above.
46
 
 
14
 
15
  # P-Bench
16
 
17
+ Compare text-to-image models on quality, speed, and price. This repo is the
 
18
  Gradio dashboard: leaderboards, Pareto plots, and side-by-side samples.
19
 
20
  The live Space is [PrunaAI/P-Bench](https://huggingface.co/spaces/PrunaAI/P-Bench).
21
 
 
 
 
 
 
 
 
 
 
 
22
  ## Run locally
23
 
24
  From the repo root:
 
30
  python app.py
31
  ```
32
 
33
+ The app is served at `http://127.0.0.1:7860`.
34
+
35
  `requirements.txt` lists Plotly. Gradio and pandas are required locally;
36
  Hugging Face Spaces installs Gradio from the YAML `sdk_version` above.
37
 
app.py CHANGED
@@ -62,9 +62,6 @@ custom_css = """
62
  --pruna-accordion-bg: rgba(255, 255, 255, 0.02);
63
  --pruna-accordion-border: rgba(216, 180, 254, 0.15);
64
  --pruna-dropdown-hover: #2a1844;
65
- --pruna-toggle-track: var(--pruna-bg-header);
66
- --pruna-toggle-thumb: var(--pruna-bg-elevated);
67
- --pruna-toggle-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.45), inset 0 1px rgba(255, 255, 255, 0.06);
68
  color-scheme: dark;
69
  }
70
 
@@ -108,27 +105,13 @@ custom_css = """
108
  --pruna-accordion-bg: var(--pruna-bg-card);
109
  --pruna-accordion-border: var(--pruna-border);
110
  --pruna-dropdown-hover: #f3e8ff;
111
- --pruna-toggle-track: var(--pruna-bg-header);
112
- --pruna-toggle-thumb: var(--pruna-bg-card);
113
- --pruna-toggle-thumb-shadow: 0 1px 2px rgba(88, 28, 135, 0.12);
114
  color-scheme: light;
115
  }
116
 
117
- html {
118
  width: 100% !important;
119
  max-width: 100% !important;
120
- min-width: 0 !important;
121
- overflow-x: hidden;
122
- overflow-y: auto;
123
- -webkit-text-size-adjust: 100%;
124
- text-size-adjust: 100%;
125
- -webkit-tap-highlight-color: transparent;
126
- }
127
- body, gradio-app {
128
- width: 100% !important;
129
- max-width: 100% !important;
130
- min-width: 0 !important;
131
- overflow: visible;
132
  -webkit-tap-highlight-color: transparent;
133
  }
134
  html, body, .gradio-container, .main {
@@ -151,25 +134,18 @@ button, a, label, input, select, textarea,
151
  /* Subtle depth — not a marketing-site hero glow */
152
  body, .gradio-container {
153
  background-image: var(--pruna-glow) !important;
154
- background-repeat: no-repeat !important;
155
- background-attachment: scroll !important;
156
- }
157
- @media (min-width: 701px) and (hover: hover) and (pointer: fine) {
158
- body, .gradio-container {
159
- background-attachment: fixed !important;
160
- }
161
  }
162
 
163
  .gradio-container {
164
  width: 100% !important;
165
  max-width: 1200px !important;
166
- min-width: 0 !important;
167
  margin: 0 auto !important;
168
  padding-top: 0 !important;
169
  padding-left: 20px !important;
170
  padding-right: 20px !important;
171
  box-sizing: border-box !important;
172
- overflow-x: hidden;
173
  }
174
  .gradio-container .main,
175
  .gradio-container .wrap,
@@ -190,7 +166,6 @@ body, .gradio-container {
190
  .workspace-filters,
191
  .view-filters {
192
  max-width: 100% !important;
193
- min-width: 0 !important;
194
  }
195
 
196
  /* —— App header (P-Bench only) —— */
@@ -325,9 +300,6 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
325
  background: transparent !important;
326
  box-shadow: none !important;
327
  }
328
- /* Flatten tabs so the bar sits above shared filters. display:contents is
329
- the fallback; Safari can drop or mis-order those children, so browsers
330
- with subgrid use the grid layout below instead. */
331
  .workspace-shell > .tabs,
332
  .workspace-shell > .main-tabs,
333
  .workspace-shell > .block:not(.workspace-filters),
@@ -351,49 +323,12 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
351
  margin: 0 0 16px !important;
352
  justify-content: center !important;
353
  width: 100% !important;
354
- overflow: visible !important;
355
- }
356
- @supports (grid-template-rows: subgrid) {
357
- .workspace-shell,
358
- .workspace-shell.block,
359
- .workspace-shell.column,
360
- .workspace-shell.gap {
361
- display: grid !important;
362
- grid-template-columns: minmax(0, 1fr) !important;
363
- grid-template-rows: auto auto auto !important;
364
- align-content: start !important;
365
- }
366
- .workspace-shell > .tabs,
367
- .workspace-shell > .main-tabs,
368
- .workspace-shell .tabs.main-tabs {
369
- display: grid !important;
370
- grid-template-columns: minmax(0, 1fr) !important;
371
- grid-template-rows: subgrid !important;
372
- grid-column: 1 !important;
373
- grid-row: 1 / 4 !important;
374
- position: static !important;
375
- }
376
- .main-tabs > .tab-wrapper {
377
- grid-row: 1 !important;
378
- order: 0 !important;
379
- }
380
- .workspace-filters {
381
- grid-column: 1 !important;
382
- grid-row: 2 !important;
383
- order: 0 !important;
384
- }
385
- .main-tabs .tabitem {
386
- grid-row: 3 !important;
387
- order: 0 !important;
388
- min-width: 0 !important;
389
- }
390
  }
391
  .main-tabs .tab-container {
392
  height: auto !important;
393
- min-height: 0 !important;
394
  justify-content: center !important;
395
  flex-wrap: wrap !important;
396
- overflow: visible !important;
397
  max-width: 100% !important;
398
  gap: 2px;
399
  }
@@ -510,8 +445,6 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
510
  .app-header-brand h1,
511
  .gradio-container .app-header-brand h1 {
512
  font-size: 1.55rem !important;
513
- width: auto !important;
514
- max-width: 100% !important;
515
  }
516
  .app-header-tagline {
517
  font-size: 0.88rem !important;
@@ -581,43 +514,24 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
581
  .prose .ranking-table td {
582
  padding: 8px 10px !important;
583
  }
584
- .ranking-table,
585
- .prose .ranking-table {
586
- --rank-col-width: 3.25rem;
587
- }
588
  .ranking-table .rank,
589
  .prose .ranking-table .rank,
590
  .ranking-table th.rank {
591
  position: sticky !important;
592
  left: 0 !important;
593
- width: var(--rank-col-width);
594
- min-width: var(--rank-col-width);
595
- max-width: var(--rank-col-width);
596
- box-shadow: none;
597
  }
598
  .ranking-table .model-cell,
599
- .prose .ranking-table .model-cell {
600
- position: static !important;
601
- left: auto !important;
602
- z-index: auto;
603
- min-width: 140px;
604
- max-width: none;
605
- background: transparent !important;
606
- box-shadow: none !important;
607
- }
608
- .ranking-table th.model-cell,
609
- .prose .ranking-table th.model-cell {
610
  position: sticky !important;
611
- top: 0 !important;
612
- left: auto !important;
613
- z-index: 3;
614
- min-width: 140px;
615
- max-width: none;
616
- background: var(--pruna-bg-header) !important;
617
- box-shadow: 0 1px 0 var(--pruna-hairline) !important;
618
  }
619
- .ranking-table tbody tr:hover .model-cell {
620
- background: var(--pruna-table-hover) !important;
621
  }
622
  .compare-controls,
623
  .compare-controls.row,
@@ -690,7 +604,7 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
690
  .view-filters {
691
  display: flex !important;
692
  flex-wrap: wrap !important;
693
- align-items: flex-end !important;
694
  gap: 12px !important;
695
  margin: 0;
696
  overflow: visible !important;
@@ -698,7 +612,7 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
698
  .view-filters > div,
699
  .view-filters > .block,
700
  .view-filters > .form {
701
- flex: 1 1 0% !important;
702
  min-width: 0 !important;
703
  }
704
  .view-filters > .block,
@@ -850,10 +764,6 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
850
  line-height: 1.45 !important;
851
  font-weight: 400 !important;
852
  }
853
- .view-help + .view-help,
854
- .prose .view-help + .view-help {
855
- margin-top: 0.45rem !important;
856
- }
857
  .view-filters span[data-testid="block-info"],
858
  .view-filters .info,
859
  .view-filters .block-info {
@@ -991,7 +901,7 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
991
  .leaderboard-controls {
992
  display: flex !important;
993
  flex-wrap: wrap !important;
994
- align-items: flex-end !important;
995
  gap: 10px !important;
996
  margin-bottom: 12px;
997
  overflow: visible !important;
@@ -1114,11 +1024,11 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1114
  max-height: min(70vh, 720px);
1115
  overflow-x: auto;
1116
  overflow-y: auto;
1117
- overscroll-behavior: none;
 
1118
  }
1119
  .ranking-table,
1120
  .prose .ranking-table {
1121
- --rank-col-width: 4.25rem;
1122
  width: 100%;
1123
  margin: 0 !important;
1124
  overflow: visible;
@@ -1194,14 +1104,10 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1194
  .prose .ranking-table .rank {
1195
  position: sticky;
1196
  left: 0;
1197
- z-index: 2;
1198
  box-sizing: border-box;
1199
- width: var(--rank-col-width);
1200
- min-width: var(--rank-col-width);
1201
- max-width: var(--rank-col-width);
1202
- padding-left: 0.5rem !important;
1203
- padding-right: 0.5rem !important;
1204
- overflow: hidden;
1205
  color: var(--pruna-lavender) !important;
1206
  font-weight: 700 !important;
1207
  text-align: center;
@@ -1218,21 +1124,18 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1218
  .ranking-table .model-cell,
1219
  .prose .ranking-table .model-cell {
1220
  position: sticky;
1221
- left: var(--rank-col-width);
1222
- z-index: 2;
1223
- box-sizing: border-box;
1224
  min-width: 180px;
1225
  max-width: 260px;
1226
  background: var(--pruna-table-sticky) !important;
1227
- box-shadow: 8px 0 10px -8px rgba(0, 0, 0, 0.35) !important;
1228
  }
1229
  .ranking-table th.model-cell,
1230
  .prose .ranking-table th.model-cell {
1231
  top: 0;
1232
- left: var(--rank-col-width);
1233
  z-index: 5;
1234
  background: var(--pruna-bg-header) !important;
1235
- box-shadow: 0 1px 0 var(--pruna-hairline), 8px 0 10px -8px rgba(0, 0, 0, 0.35) !important;
1236
  }
1237
  .ranking-table tbody tr:hover .rank,
1238
  .ranking-table tbody tr:hover .model-cell {
@@ -1252,23 +1155,6 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1252
  color: var(--pruna-text-muted) !important;
1253
  font-size: 12px;
1254
  }
1255
- .model-name-tooltip {
1256
- position: fixed;
1257
- z-index: 10000;
1258
- max-width: min(440px, calc(100vw - 24px));
1259
- box-sizing: border-box;
1260
- padding: 10px 14px;
1261
- border: 1px solid var(--pruna-border);
1262
- border-radius: 8px;
1263
- background: var(--pruna-bg-elevated);
1264
- color: var(--pruna-text-primary);
1265
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
1266
- font: 13px/1.5 var(--pruna-font);
1267
- white-space: normal;
1268
- overflow-wrap: anywhere;
1269
- pointer-events: none;
1270
- }
1271
- .model-name-tooltip[hidden] { display: none !important; }
1272
  .ranking-table .text-cell,
1273
  .prose .ranking-table .text-cell {
1274
  color: var(--pruna-text-muted) !important;
@@ -1431,9 +1317,7 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1431
  box-shadow: none !important;
1432
  }
1433
  .compare-controls .compare-prompt-count .head {
1434
- display: block !important;
1435
- grid-column: 1 / -1;
1436
- grid-row: 1;
1437
  margin: 0 !important;
1438
  }
1439
  .compare-controls .compare-prompt-count .head label {
@@ -1607,182 +1491,7 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1607
  margin: 0 !important;
1608
  }
1609
  .compare-row { display: grid; gap: 12px; min-width: 0; width: 100%; }
1610
- .compare-prompt-text { overflow-wrap: anywhere; word-break: break-word; }
1611
- .pareto-heading-row,
1612
- .pareto-heading-row.row,
1613
- .pareto-heading-row .form {
1614
- display: flex !important;
1615
- flex-wrap: wrap !important;
1616
- align-items: center !important;
1617
- gap: 8px 12px !important;
1618
- width: 100% !important;
1619
- margin-bottom: 0.4rem !important;
1620
- }
1621
- .pareto-heading-row .pareto-subhead,
1622
- .pareto-heading-row > div:first-child,
1623
- .pareto-heading-row .form > div:first-child {
1624
- flex: 1 1 240px !important;
1625
- min-width: 0 !important;
1626
- margin: 0 !important;
1627
- }
1628
- .pareto-heading-row .pareto-scale-control {
1629
- display: flex !important;
1630
- flex-direction: row !important;
1631
- align-items: center !important;
1632
- justify-content: flex-end !important;
1633
- flex: 0 0 auto !important;
1634
- gap: 0 !important;
1635
- margin-left: auto !important;
1636
- max-width: 168px !important;
1637
- padding: 0 !important;
1638
- }
1639
- .pareto-scale-all-row,
1640
- .pareto-scale-all-row.row,
1641
- .pareto-scale-all-row .form {
1642
- display: flex !important;
1643
- flex-direction: row !important;
1644
- flex-wrap: wrap !important;
1645
- align-items: center !important;
1646
- justify-content: flex-start !important;
1647
- gap: 8px 12px !important;
1648
- width: 100% !important;
1649
- margin: 2px 0 14px !important;
1650
- }
1651
- .pareto-scale-all-row .html-container,
1652
- .pareto-scale-all-row .block {
1653
- border: none !important;
1654
- background: transparent !important;
1655
- box-shadow: none !important;
1656
- padding: 0 !important;
1657
- margin: 0 !important;
1658
- width: auto !important;
1659
- flex: 0 0 auto !important;
1660
- }
1661
- .pareto-scale-all-row .html-container {
1662
- flex: 1 1 auto !important;
1663
- min-width: 0 !important;
1664
- }
1665
- .pareto-scale-all-label {
1666
- color: var(--pruna-text-muted);
1667
- font-size: 0.8rem;
1668
- font-weight: 500;
1669
- white-space: nowrap;
1670
- }
1671
- .pareto-scale-all-row .pareto-scale-toggle {
1672
- margin-left: auto !important;
1673
- }
1674
- .pareto-scale-toggle,
1675
- .pareto-scale-toggle.block {
1676
- min-width: 0 !important;
1677
- width: auto !important;
1678
- border: none !important;
1679
- background: transparent !important;
1680
- box-shadow: none !important;
1681
- padding: 0 !important;
1682
- margin: 0 !important;
1683
- }
1684
- .pareto-scale-toggle .wrap,
1685
- .pareto-scale-toggle .form {
1686
- display: block !important;
1687
- width: auto !important;
1688
- margin: 0 !important;
1689
- padding: 0 !important;
1690
- border: none !important;
1691
- background: transparent !important;
1692
- box-shadow: none !important;
1693
- }
1694
- .pareto-scale-toggle legend {
1695
- display: none !important;
1696
- }
1697
- .pareto-scale-toggle fieldset,
1698
- .pareto-scale-toggle .wrap:has(> label),
1699
- .pareto-scale-toggle .form:has(> label) {
1700
- position: relative !important;
1701
- display: grid !important;
1702
- grid-template-columns: 1fr 1fr !important;
1703
- align-items: stretch !important;
1704
- isolation: isolate;
1705
- box-sizing: border-box !important;
1706
- width: max-content !important;
1707
- min-width: 0 !important;
1708
- padding: 4px !important;
1709
- gap: 4px !important;
1710
- border: 1px solid var(--pruna-input-border) !important;
1711
- border-radius: 10px !important;
1712
- background: var(--pruna-toggle-track) !important;
1713
- box-shadow: none !important;
1714
- }
1715
- .pareto-scale-toggle fieldset::before,
1716
- .pareto-scale-toggle .wrap:has(> label)::before,
1717
- .pareto-scale-toggle .form:has(> label)::before {
1718
- content: none !important;
1719
- }
1720
- .pareto-scale-toggle label {
1721
- position: relative !important;
1722
- z-index: 1 !important;
1723
- display: flex !important;
1724
- flex: 1 1 auto !important;
1725
- align-items: center !important;
1726
- justify-content: center !important;
1727
- gap: 0 !important;
1728
- box-sizing: border-box !important;
1729
- min-width: 58px !important;
1730
- min-height: 26px !important;
1731
- margin: 0 !important;
1732
- padding: 5px 12px !important;
1733
- border: none !important;
1734
- border-radius: 6px !important;
1735
- background: transparent !important;
1736
- box-shadow: none !important;
1737
- color: var(--pruna-text-body) !important;
1738
- font-size: 0.72rem !important;
1739
- font-weight: 600 !important;
1740
- line-height: 1.2 !important;
1741
- letter-spacing: 0.01em;
1742
- white-space: nowrap;
1743
- cursor: pointer !important;
1744
- }
1745
- .pareto-scale-toggle-all label {
1746
- min-width: 68px !important;
1747
- min-height: 30px !important;
1748
- padding: 6px 14px !important;
1749
- font-size: 0.85rem !important;
1750
- }
1751
- .pareto-scale-toggle label span {
1752
- margin: 0 !important;
1753
- padding: 0 !important;
1754
- color: inherit !important;
1755
- opacity: 1 !important;
1756
- }
1757
- .pareto-scale-toggle label > * + * {
1758
- margin-left: 0 !important;
1759
- }
1760
- .pareto-scale-toggle label + label::before,
1761
- .pareto-scale-toggle label + label {
1762
- content: none !important;
1763
- border-left: none !important;
1764
- }
1765
- .pareto-scale-toggle input[type="radio"] {
1766
- position: absolute !important;
1767
- appearance: none !important;
1768
- opacity: 0 !important;
1769
- width: 0 !important;
1770
- height: 0 !important;
1771
- margin: 0 !important;
1772
- pointer-events: none !important;
1773
- }
1774
- .pareto-scale-toggle label:hover {
1775
- background: transparent !important;
1776
- color: var(--pruna-text-primary) !important;
1777
- }
1778
- .pareto-scale-toggle label.selected,
1779
- .pareto-scale-toggle label:has(input:checked) {
1780
- background: var(--pruna-toggle-thumb) !important;
1781
- color: var(--pruna-lavender) !important;
1782
- font-weight: 700 !important;
1783
- border-color: transparent !important;
1784
- box-shadow: var(--pruna-toggle-thumb-shadow) !important;
1785
- }
1786
  .pareto-layout,
1787
  .pareto-layout.row,
1788
  .pareto-layout .form {
@@ -1800,9 +1509,6 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1800
  max-width: 100% !important;
1801
  }
1802
  .compare-cell { min-width: 0; }
1803
- .compare-cell.compare-source .compare-model-label {
1804
- color: var(--pruna-text-muted);
1805
- }
1806
  .compare-model-label {
1807
  margin-bottom: 6px;
1808
  color: var(--pruna-lavender);
@@ -1810,23 +1516,15 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1810
  font-weight: 700;
1811
  word-break: break-word;
1812
  }
1813
- .compare-cell img,
1814
- .compare-cell video {
1815
  display: block;
1816
  width: 100%;
 
 
1817
  border-radius: 12px;
1818
  border: 1px solid var(--pruna-border);
1819
  background: var(--pruna-bg-elevated);
1820
  }
1821
- .compare-cell img {
1822
- aspect-ratio: 1 / 1;
1823
- object-fit: cover;
1824
- }
1825
- .compare-cell video {
1826
- aspect-ratio: 16 / 9;
1827
- max-height: 360px;
1828
- object-fit: contain;
1829
- }
1830
  .compare-empty,
1831
  .pareto-note-copy {
1832
  margin: 0;
@@ -1851,7 +1549,7 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
1851
  .app-header .app-header-brand h1 {
1852
  display: block !important;
1853
  width: max-content !important;
1854
- max-width: 100% !important;
1855
  flex: 0 0 auto !important;
1856
  margin: 0 !important;
1857
  padding: 0 !important;
@@ -2185,20 +1883,14 @@ def load_sample_comparison_data(folder):
2185
  return None
2186
 
2187
  prompts = {}
2188
- source_videos = {}
2189
  with prompts_path.open() as handle:
2190
  for line in handle:
2191
  if not line.strip():
2192
  continue
2193
  row = json.loads(line)
2194
- prompt_id = row["prompt_id"]
2195
- prompts[prompt_id] = row.get("text", "")
2196
- source_video = row.get("source_video")
2197
- if source_video:
2198
- source_videos[prompt_id] = source_video
2199
 
2200
  images = defaultdict(dict)
2201
- kinds = set()
2202
  with generations_path.open() as handle:
2203
  for line in handle:
2204
  if not line.strip():
@@ -2206,33 +1898,20 @@ def load_sample_comparison_data(folder):
2206
  row = json.loads(line)
2207
  model_id = row["model_id"]
2208
  prompt_id = row["prompt_id"]
2209
- media_url = row.get("image") or row.get("video")
2210
- if row.get("video"):
2211
- kinds.add("video")
2212
- elif row.get("image"):
2213
- kinds.add("image")
2214
- if model_id and prompt_id and media_url:
2215
- images[model_id][prompt_id] = media_url
2216
- if prompt_id and prompt_id not in source_videos:
2217
- params = row.get("params") or {}
2218
- input_video = params.get("input_video") or row.get("input_video")
2219
- if input_video:
2220
- source_videos[prompt_id] = input_video
2221
 
2222
  models = sorted(images)
2223
  if not models or not prompts:
2224
  return None
2225
 
2226
- loaded = {
2227
  "prompts": prompts,
2228
  "images": {model: dict(prompt_map) for model, prompt_map in images.items()},
2229
  "models": models,
2230
  "prompt_ids": sorted(prompts),
2231
- "kind": "video" if "video" in kinds else "image",
2232
  }
2233
- if source_videos:
2234
- loaded["source_videos"] = source_videos
2235
- return loaded
2236
 
2237
 
2238
  def _as_numeric(df, columns):
@@ -2347,7 +2026,7 @@ def load_qwen_combined_dataframe(path):
2347
  df = df[~df["Model"].astype(str).str.startswith("#")].copy()
2348
  df["Model"] = df["Model"].astype(str).str.strip()
2349
 
2350
- df = _as_numeric(
2351
  df,
2352
  [
2353
  "Price / Image (USD)",
@@ -2357,121 +2036,7 @@ def load_qwen_combined_dataframe(path):
2357
  "Rapidata Elo",
2358
  "Datapoint Elo",
2359
  ],
2360
- )
2361
- df = df.drop(columns=["Raw Win Rate"], errors="ignore")
2362
- return df.reset_index(drop=True)
2363
-
2364
-
2365
- def _is_pruna_video_model(series):
2366
- models = series.astype(str).str.casefold()
2367
- return models.str.startswith("p_video") | models.str.startswith("p-video")
2368
-
2369
-
2370
- def _apply_video_timings(df, *, replace_displayed_time=False):
2371
- """Mix provider wall time with Pruna model execution time."""
2372
- fal = df.get("Time / Output Video Second (s)")
2373
- execution = df.get("Execution Time / Output Video Second (s)")
2374
- if fal is None:
2375
- return df
2376
-
2377
- if "model_id" in df.columns:
2378
- is_ours = _is_pruna_video_model(df["model_id"])
2379
- else:
2380
- is_ours = _is_pruna_video_model(df["Model"])
2381
-
2382
- if execution is None:
2383
- mixed = fal
2384
- else:
2385
- ours_time = execution.where(execution.notna(), fal)
2386
- mixed = fal.where(~is_ours, ours_time)
2387
- if replace_displayed_time:
2388
- df["Time / Output Video Second (s)"] = mixed
2389
- df["Pareto Time / Output Video Second (s)"] = mixed
2390
- return df
2391
-
2392
-
2393
- def load_video_editing_dataframe(path):
2394
- """Load the video-to-video editing leaderboard."""
2395
- df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
2396
- df = df.rename(
2397
- columns={
2398
- "display_name": "Model",
2399
- "elo": "Datapoint Elo",
2400
- "min_generation_s": "Min Generation Time (s)",
2401
- "median_generation_s": "Median Generation Time (s)",
2402
- "p20_generation_s": "P20 Generation Time (s)",
2403
- "generation_s_per_output_video_s": "Time / Output Video Second (s)",
2404
- "predict_time_s_per_output_video_s": "Predict Time / Output Video Second (s)",
2405
- "model_execution_time_s_per_output_video_s": (
2406
- "Execution Time / Output Video Second (s)"
2407
- ),
2408
- "price": "Price / Second of Video (USD)",
2409
- }
2410
- )
2411
- df = df.drop(columns=["wandb_run_ids", "n_generations"], errors="ignore")
2412
- df["Model"] = df["Model"].astype(str).str.strip()
2413
- df = _as_numeric(
2414
- df,
2415
- [
2416
- "Datapoint Elo",
2417
- "Min Generation Time (s)",
2418
- "Median Generation Time (s)",
2419
- "P20 Generation Time (s)",
2420
- "Time / Output Video Second (s)",
2421
- "Predict Time / Output Video Second (s)",
2422
- "Execution Time / Output Video Second (s)",
2423
- "Price / Second of Video (USD)",
2424
- ],
2425
- )
2426
- df = _apply_video_timings(df)
2427
- df = df.drop(columns=["model_id"], errors="ignore")
2428
- return df.reset_index(drop=True)
2429
-
2430
-
2431
- def load_video_generation_dataframe(path):
2432
- """Load a text-to-video or image-to-video evaluation snapshot."""
2433
- df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
2434
- df = df.rename(
2435
- columns={
2436
- "model_id": "Model",
2437
- "datapoint_elo": "Datapoint Elo",
2438
- "rapidata_elo": "Rapidata Elo",
2439
- "min_generation_s": "Min Generation Time (s)",
2440
- "median_generation_s": "Median Generation Time (s)",
2441
- "p20_generation_s": "P20 Generation Time (s)",
2442
- "generation_s_per_output_video_s": "Time / Output Video Second (s)",
2443
- "model_execution_s_per_output_video_s": (
2444
- "Execution Time / Output Video Second (s)"
2445
- ),
2446
- "price_usd_per_second": "Price / Second of Video (USD)",
2447
- }
2448
- )
2449
- df = df.drop(columns=["wandb_run_ids", "n_generations"], errors="ignore")
2450
- df["Model"] = df["Model"].astype(str).str.strip()
2451
- df = _as_numeric(
2452
- df,
2453
- [
2454
- "Datapoint Elo",
2455
- "Rapidata Elo",
2456
- "Min Generation Time (s)",
2457
- "Median Generation Time (s)",
2458
- "P20 Generation Time (s)",
2459
- "Time / Output Video Second (s)",
2460
- "Execution Time / Output Video Second (s)",
2461
- "Price / Second of Video (USD)",
2462
- ],
2463
- )
2464
- # Pruna rows use model execution time; other rows keep provider wall time.
2465
- df = _apply_video_timings(df, replace_displayed_time=True)
2466
- df = df.drop(
2467
- columns=["Execution Time / Output Video Second (s)"],
2468
- errors="ignore",
2469
- )
2470
- return df.reset_index(drop=True)
2471
-
2472
-
2473
- def load_text_to_video_dataframe(path):
2474
- return load_video_generation_dataframe(path)
2475
 
2476
 
2477
  df = load_oneig_dataframe(oneig_path)
@@ -2521,17 +2086,9 @@ qwen_combined_dir = _resolve_data_path(
2521
  data_dir / "qwen_image_bench_combined",
2522
  space_root.parent / "qwen_image_bench_combined",
2523
  )
2524
- video_combined_dir = _resolve_data_path(
2525
- data_dir / "video_editing_combined",
2526
- space_root.parent / "video_editing_combined",
2527
- )
2528
- text_to_video_combined_dir = _resolve_data_path(
2529
- data_dir / "video_generation_combined",
2530
- space_root.parent / "video_generation_combined",
2531
- )
2532
  qwen_path = _resolve_data_path(
2533
- data_dir / "qwen_image_bench_model_price_and_median_generation_time_10_august.csv",
2534
- space_root.parent / "qwen_image_bench_model_price_and_median_generation_time_10_august.csv",
2535
  )
2536
  aa_path = _resolve_data_path(
2537
  data_dir / "artificial_analysis_text_to_image_leaderboard.csv",
@@ -2541,25 +2098,10 @@ arena_path = _resolve_data_path(
2541
  data_dir / "arena_ai_text_to_image_leaderboard.csv",
2542
  space_root.parent / "arena_ai_text_to_image_leaderboard.csv",
2543
  )
2544
- video_path = _resolve_data_path(
2545
- data_dir / "video-editing-leaderboard.csv",
2546
- space_root.parent / "video-editing-leaderboard.csv",
2547
- )
2548
- text_to_video_path = _resolve_data_path(
2549
- data_dir / "t2v-pro.csv",
2550
- space_root.parent / "t2v-pro.csv",
2551
- )
2552
- image_to_video_path = _resolve_data_path(
2553
- data_dir / "i2v-pro.csv",
2554
- space_root.parent / "i2v-pro.csv",
2555
- )
2556
 
2557
  qwen_df = load_qwen_combined_dataframe(qwen_path)
2558
  aa_df = load_artificial_analysis_dataframe(aa_path)
2559
  arena_df = load_arena_ai_dataframe(arena_path)
2560
- video_df = load_video_editing_dataframe(video_path)
2561
- text_to_video_df = load_text_to_video_dataframe(text_to_video_path)
2562
- image_to_video_df = load_video_generation_dataframe(image_to_video_path)
2563
  qwen_display_columns = [
2564
  col
2565
  for col in [
@@ -2567,6 +2109,7 @@ qwen_display_columns = [
2567
  "Datapoint Elo",
2568
  "Rapidata Elo",
2569
  "P-Judge Overall",
 
2570
  "Median Generation Time (s)",
2571
  "Min Generation Time (s)",
2572
  "Price / Image (USD)",
@@ -2591,36 +2134,9 @@ arena_display_columns = [
2591
  ]
2592
  if col in arena_df.columns
2593
  ]
2594
- video_display_columns = [
2595
- col
2596
- for col in [
2597
- "Model",
2598
- "Datapoint Elo",
2599
- "Time / Output Video Second (s)",
2600
- "Median Generation Time (s)",
2601
- "Min Generation Time (s)",
2602
- "Price / Second of Video (USD)",
2603
- ]
2604
- if col in video_df.columns
2605
- ]
2606
- text_to_video_display_columns = [
2607
- col
2608
- for col in [
2609
- "Model",
2610
- "Datapoint Elo",
2611
- "Rapidata Elo",
2612
- "Time / Output Video Second (s)",
2613
- "Median Generation Time (s)",
2614
- "Min Generation Time (s)",
2615
- "Price / Second of Video (USD)",
2616
- ]
2617
- if col in text_to_video_df.columns
2618
- ]
2619
 
2620
  oneig_samples = load_sample_comparison_data(oneig_combined_dir)
2621
  qwen_samples = load_sample_comparison_data(qwen_combined_dir)
2622
- video_samples = load_sample_comparison_data(video_combined_dir)
2623
- text_to_video_samples = load_sample_comparison_data(text_to_video_combined_dir)
2624
 
2625
  metrics = [
2626
  {"id": "datapoint_elo", "column": "Datapoint Elo"},
@@ -2679,64 +2195,11 @@ arena_metric_ids = _metric_ids_for(
2679
  "arena_text",
2680
  ],
2681
  )
2682
- video_metric_ids = _metric_ids_for(video_df, ["datapoint_elo"])
2683
- text_to_video_metric_ids = _metric_ids_for(
2684
- text_to_video_df, ["datapoint_elo", "rapidata_elo"]
2685
- )
2686
- image_to_video_metric_ids = _metric_ids_for(
2687
- image_to_video_df, ["datapoint_elo", "rapidata_elo"]
2688
- )
2689
 
2690
  datasets = [
2691
- {
2692
- "id": "text_to_video",
2693
- "name": "VBench-2.0 Dataset",
2694
- "modality": "text_to_video",
2695
- "data": text_to_video_df,
2696
- "columns": text_to_video_display_columns,
2697
- "metric_ids": text_to_video_metric_ids,
2698
- "note": (
2699
- "Datapoint Elo and Rapidata Elo from pairwise text-to-video "
2700
- "preference. Price is USD per second of output video. Time per "
2701
- "second of video is provider wall time, except Pruna models which use "
2702
- "model execution time."
2703
- ),
2704
- "samples": text_to_video_samples,
2705
- },
2706
- {
2707
- "id": "image_to_video",
2708
- "name": "Vbench-i2V",
2709
- "modality": "image_to_video",
2710
- "data": image_to_video_df,
2711
- "columns": text_to_video_display_columns,
2712
- "metric_ids": image_to_video_metric_ids,
2713
- "note": (
2714
- "Datapoint Elo and Rapidata Elo from pairwise image-to-video "
2715
- "preference, comparing P-Video-2 Pro variants with other models. "
2716
- "Price is USD per second of output video. Time per second of "
2717
- "video is provider wall time, except Pruna models which use "
2718
- "model execution time."
2719
- ),
2720
- "samples": None,
2721
- },
2722
- {
2723
- "id": "video_editing",
2724
- "name": "Pruna Internal Video-Edit Benchmark",
2725
- "modality": "video_to_video",
2726
- "data": video_df,
2727
- "columns": video_display_columns,
2728
- "metric_ids": video_metric_ids,
2729
- "note": (
2730
- "Datapoint Elo from pairwise video-edit preference. Price is USD "
2731
- "per second of output video. Generation time per second of video "
2732
- "is end-to-end wall time to produce one second of output."
2733
- ),
2734
- "samples": video_samples,
2735
- },
2736
  {
2737
  "id": "qwen",
2738
  "name": "Qwen Image Dataset",
2739
- "modality": "text_to_image",
2740
  "data": qwen_df,
2741
  "columns": qwen_display_columns,
2742
  "metric_ids": qwen_metric_ids,
@@ -2746,7 +2209,6 @@ datasets = [
2746
  {
2747
  "id": "oneig",
2748
  "name": "OneIG Alignment Dataset",
2749
- "modality": "text_to_image",
2750
  "data": oneig_df,
2751
  "columns": oneig_display_columns,
2752
  "metric_ids": oneig_metric_ids,
@@ -2759,7 +2221,6 @@ datasets = [
2759
  {
2760
  "id": "artificial_analysis",
2761
  "name": "Artificial Analysis Dataset",
2762
- "modality": "text_to_image",
2763
  "data": aa_df,
2764
  "columns": aa_display_columns,
2765
  "metric_ids": aa_metric_ids,
@@ -2769,7 +2230,6 @@ datasets = [
2769
  {
2770
  "id": "arena_ai",
2771
  "name": "Arena AI Dataset",
2772
- "modality": "text_to_image",
2773
  "data": arena_df,
2774
  "columns": arena_display_columns,
2775
  "metric_ids": arena_metric_ids,
@@ -2780,14 +2240,8 @@ datasets = [
2780
  datasets = [dataset for dataset in datasets if dataset["metric_ids"]]
2781
 
2782
  DEFAULT_DATASET_ID = next(
2783
- (dataset["id"] for dataset in datasets if dataset["id"] == "text_to_video"),
2784
- next(
2785
- (dataset["id"] for dataset in datasets if dataset["id"] == "video_editing"),
2786
- next(
2787
- (dataset["id"] for dataset in datasets if dataset["id"] == "qwen"),
2788
- datasets[0]["id"] if datasets else None,
2789
- ),
2790
- ),
2791
  )
2792
  DEFAULT_METRIC_ID = None
2793
 
@@ -2863,23 +2317,11 @@ custom_head = """
2863
  return found;
2864
  };
2865
 
2866
- const applyPlotTheme = (gd, mode) => {
2867
- const layout = PLOT_LAYOUT[mode];
2868
- if (!layout || typeof Plotly === "undefined" || !gd) return;
2869
- if (gd.layout && gd.layout.paper_bgcolor === layout.paper_bgcolor) return;
2870
- try { Plotly.relayout(gd, layout); } catch (e) {}
2871
- };
2872
-
2873
- const watchPlotTheme = (gd) => {
2874
- if (!gd || gd.__inferbenchThemeBound) return;
2875
- gd.__inferbenchThemeBound = true;
2876
- gd.addEventListener("plotly_afterplot", () => applyPlotTheme(gd, currentMode()));
2877
- };
2878
-
2879
  const restylePlots = (mode) => {
 
 
2880
  queryAll(".js-plotly-plot").forEach((gd) => {
2881
- watchPlotTheme(gd);
2882
- applyPlotTheme(gd, mode);
2883
  });
2884
  };
2885
 
@@ -3017,63 +2459,6 @@ custom_head = """
3017
  })();
3018
  </script>
3019
  <script>
3020
- (() => {
3021
- if (window.__inferbenchModelTooltipBound) return;
3022
- window.__inferbenchModelTooltipBound = true;
3023
- let tooltip;
3024
- let active;
3025
- let previousDescription;
3026
-
3027
- const hide = () => {
3028
- if (tooltip) tooltip.hidden = true;
3029
- if (active) {
3030
- if (previousDescription === null) active.removeAttribute("aria-describedby");
3031
- else active.setAttribute("aria-describedby", previousDescription);
3032
- }
3033
- active = null;
3034
- };
3035
- const show = (event) => {
3036
- const target = event.target.closest?.(
3037
- ".ranking-table tbody .model-cell, .view-filters .filter-chips .token span"
3038
- );
3039
- if (!target || target === active) return;
3040
- hide();
3041
- const text = target.querySelector("strong") || target;
3042
- if (text.scrollWidth <= text.clientWidth) return;
3043
- if (!tooltip) {
3044
- tooltip = document.createElement("div");
3045
- tooltip.id = "model-name-tooltip";
3046
- tooltip.className = "model-name-tooltip";
3047
- tooltip.setAttribute("role", "tooltip");
3048
- document.body.appendChild(tooltip);
3049
- }
3050
- tooltip.textContent = target.dataset.modelName || text.textContent.trim();
3051
- tooltip.hidden = false;
3052
- active = target;
3053
- previousDescription = target.getAttribute("aria-describedby");
3054
- target.setAttribute("aria-describedby", [previousDescription, tooltip.id].filter(Boolean).join(" "));
3055
- const rect = target.getBoundingClientRect();
3056
- const width = tooltip.offsetWidth;
3057
- const height = tooltip.offsetHeight;
3058
- tooltip.style.left = Math.max(12, Math.min(rect.left, window.innerWidth - width - 12)) + "px";
3059
- const top = rect.top >= height + 12 ? rect.top - height - 8 : rect.bottom + 8;
3060
- tooltip.style.top = Math.max(12, Math.min(top, window.innerHeight - height - 12)) + "px";
3061
- };
3062
- document.addEventListener("pointerover", show);
3063
- document.addEventListener("focusin", show);
3064
- for (const eventName of ["pointerout", "focusout"]) {
3065
- document.addEventListener(eventName, (event) => {
3066
- if (active && active.contains(event.target) && !active.contains(event.relatedTarget)) hide();
3067
- });
3068
- }
3069
- document.addEventListener("scroll", hide, true);
3070
- window.addEventListener("resize", hide);
3071
- document.addEventListener("keydown", (event) => {
3072
- if (event.key === "Escape") hide();
3073
- });
3074
- })();
3075
- </script>
3076
- <script>
3077
  (() => {
3078
  if (window.__inferbenchChipScrollBound) return;
3079
  window.__inferbenchChipScrollBound = true;
 
62
  --pruna-accordion-bg: rgba(255, 255, 255, 0.02);
63
  --pruna-accordion-border: rgba(216, 180, 254, 0.15);
64
  --pruna-dropdown-hover: #2a1844;
 
 
 
65
  color-scheme: dark;
66
  }
67
 
 
105
  --pruna-accordion-bg: var(--pruna-bg-card);
106
  --pruna-accordion-border: var(--pruna-border);
107
  --pruna-dropdown-hover: #f3e8ff;
 
 
 
108
  color-scheme: light;
109
  }
110
 
111
+ html, body {
112
  width: 100% !important;
113
  max-width: 100% !important;
114
+ overflow-x: clip;
 
 
 
 
 
 
 
 
 
 
 
115
  -webkit-tap-highlight-color: transparent;
116
  }
117
  html, body, .gradio-container, .main {
 
134
  /* Subtle depth — not a marketing-site hero glow */
135
  body, .gradio-container {
136
  background-image: var(--pruna-glow) !important;
137
+ background-attachment: fixed !important;
 
 
 
 
 
 
138
  }
139
 
140
  .gradio-container {
141
  width: 100% !important;
142
  max-width: 1200px !important;
 
143
  margin: 0 auto !important;
144
  padding-top: 0 !important;
145
  padding-left: 20px !important;
146
  padding-right: 20px !important;
147
  box-sizing: border-box !important;
148
+ overflow-x: clip;
149
  }
150
  .gradio-container .main,
151
  .gradio-container .wrap,
 
166
  .workspace-filters,
167
  .view-filters {
168
  max-width: 100% !important;
 
169
  }
170
 
171
  /* —— App header (P-Bench only) —— */
 
300
  background: transparent !important;
301
  box-shadow: none !important;
302
  }
 
 
 
303
  .workspace-shell > .tabs,
304
  .workspace-shell > .main-tabs,
305
  .workspace-shell > .block:not(.workspace-filters),
 
323
  margin: 0 0 16px !important;
324
  justify-content: center !important;
325
  width: 100% !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
  }
327
  .main-tabs .tab-container {
328
  height: auto !important;
 
329
  justify-content: center !important;
330
  flex-wrap: wrap !important;
331
+ overflow: hidden !important;
332
  max-width: 100% !important;
333
  gap: 2px;
334
  }
 
445
  .app-header-brand h1,
446
  .gradio-container .app-header-brand h1 {
447
  font-size: 1.55rem !important;
 
 
448
  }
449
  .app-header-tagline {
450
  font-size: 0.88rem !important;
 
514
  .prose .ranking-table td {
515
  padding: 8px 10px !important;
516
  }
 
 
 
 
517
  .ranking-table .rank,
518
  .prose .ranking-table .rank,
519
  .ranking-table th.rank {
520
  position: sticky !important;
521
  left: 0 !important;
522
+ width: 2.4rem;
523
+ min-width: 2.4rem;
 
 
524
  }
525
  .ranking-table .model-cell,
526
+ .prose .ranking-table .model-cell,
527
+ .ranking-table th.model-cell {
 
 
 
 
 
 
 
 
 
528
  position: sticky !important;
529
+ left: 2.4rem !important;
530
+ min-width: 108px;
531
+ max-width: 36vw;
 
 
 
 
532
  }
533
+ .ranking-table .model-cell strong {
534
+ white-space: nowrap;
535
  }
536
  .compare-controls,
537
  .compare-controls.row,
 
604
  .view-filters {
605
  display: flex !important;
606
  flex-wrap: wrap !important;
607
+ align-items: end !important;
608
  gap: 12px !important;
609
  margin: 0;
610
  overflow: visible !important;
 
612
  .view-filters > div,
613
  .view-filters > .block,
614
  .view-filters > .form {
615
+ flex: 1 1 0 !important;
616
  min-width: 0 !important;
617
  }
618
  .view-filters > .block,
 
764
  line-height: 1.45 !important;
765
  font-weight: 400 !important;
766
  }
 
 
 
 
767
  .view-filters span[data-testid="block-info"],
768
  .view-filters .info,
769
  .view-filters .block-info {
 
901
  .leaderboard-controls {
902
  display: flex !important;
903
  flex-wrap: wrap !important;
904
+ align-items: end !important;
905
  gap: 10px !important;
906
  margin-bottom: 12px;
907
  overflow: visible !important;
 
1024
  max-height: min(70vh, 720px);
1025
  overflow-x: auto;
1026
  overflow-y: auto;
1027
+ -webkit-overflow-scrolling: touch;
1028
+ overscroll-behavior-x: contain;
1029
  }
1030
  .ranking-table,
1031
  .prose .ranking-table {
 
1032
  width: 100%;
1033
  margin: 0 !important;
1034
  overflow: visible;
 
1104
  .prose .ranking-table .rank {
1105
  position: sticky;
1106
  left: 0;
1107
+ z-index: 1;
1108
  box-sizing: border-box;
1109
+ width: 3.25rem;
1110
+ min-width: 3.25rem;
 
 
 
 
1111
  color: var(--pruna-lavender) !important;
1112
  font-weight: 700 !important;
1113
  text-align: center;
 
1124
  .ranking-table .model-cell,
1125
  .prose .ranking-table .model-cell {
1126
  position: sticky;
1127
+ left: 3.25rem;
1128
+ z-index: 1;
 
1129
  min-width: 180px;
1130
  max-width: 260px;
1131
  background: var(--pruna-table-sticky) !important;
 
1132
  }
1133
  .ranking-table th.model-cell,
1134
  .prose .ranking-table th.model-cell {
1135
  top: 0;
1136
+ left: 3.25rem;
1137
  z-index: 5;
1138
  background: var(--pruna-bg-header) !important;
 
1139
  }
1140
  .ranking-table tbody tr:hover .rank,
1141
  .ranking-table tbody tr:hover .model-cell {
 
1155
  color: var(--pruna-text-muted) !important;
1156
  font-size: 12px;
1157
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1158
  .ranking-table .text-cell,
1159
  .prose .ranking-table .text-cell {
1160
  color: var(--pruna-text-muted) !important;
 
1317
  box-shadow: none !important;
1318
  }
1319
  .compare-controls .compare-prompt-count .head {
1320
+ display: contents;
 
 
1321
  margin: 0 !important;
1322
  }
1323
  .compare-controls .compare-prompt-count .head label {
 
1491
  margin: 0 !important;
1492
  }
1493
  .compare-row { display: grid; gap: 12px; min-width: 0; width: 100%; }
1494
+ .compare-prompt-text { overflow-wrap: anywhere; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1495
  .pareto-layout,
1496
  .pareto-layout.row,
1497
  .pareto-layout .form {
 
1509
  max-width: 100% !important;
1510
  }
1511
  .compare-cell { min-width: 0; }
 
 
 
1512
  .compare-model-label {
1513
  margin-bottom: 6px;
1514
  color: var(--pruna-lavender);
 
1516
  font-weight: 700;
1517
  word-break: break-word;
1518
  }
1519
+ .compare-cell img {
 
1520
  display: block;
1521
  width: 100%;
1522
+ aspect-ratio: 1 / 1;
1523
+ object-fit: cover;
1524
  border-radius: 12px;
1525
  border: 1px solid var(--pruna-border);
1526
  background: var(--pruna-bg-elevated);
1527
  }
 
 
 
 
 
 
 
 
 
1528
  .compare-empty,
1529
  .pareto-note-copy {
1530
  margin: 0;
 
1549
  .app-header .app-header-brand h1 {
1550
  display: block !important;
1551
  width: max-content !important;
1552
+ max-width: none !important;
1553
  flex: 0 0 auto !important;
1554
  margin: 0 !important;
1555
  padding: 0 !important;
 
1883
  return None
1884
 
1885
  prompts = {}
 
1886
  with prompts_path.open() as handle:
1887
  for line in handle:
1888
  if not line.strip():
1889
  continue
1890
  row = json.loads(line)
1891
+ prompts[row["prompt_id"]] = row.get("text", "")
 
 
 
 
1892
 
1893
  images = defaultdict(dict)
 
1894
  with generations_path.open() as handle:
1895
  for line in handle:
1896
  if not line.strip():
 
1898
  row = json.loads(line)
1899
  model_id = row["model_id"]
1900
  prompt_id = row["prompt_id"]
1901
+ image_url = row.get("image")
1902
+ if model_id and prompt_id and image_url:
1903
+ images[model_id][prompt_id] = image_url
 
 
 
 
 
 
 
 
 
1904
 
1905
  models = sorted(images)
1906
  if not models or not prompts:
1907
  return None
1908
 
1909
+ return {
1910
  "prompts": prompts,
1911
  "images": {model: dict(prompt_map) for model, prompt_map in images.items()},
1912
  "models": models,
1913
  "prompt_ids": sorted(prompts),
 
1914
  }
 
 
 
1915
 
1916
 
1917
  def _as_numeric(df, columns):
 
2026
  df = df[~df["Model"].astype(str).str.startswith("#")].copy()
2027
  df["Model"] = df["Model"].astype(str).str.strip()
2028
 
2029
+ return _as_numeric(
2030
  df,
2031
  [
2032
  "Price / Image (USD)",
 
2036
  "Rapidata Elo",
2037
  "Datapoint Elo",
2038
  ],
2039
+ ).reset_index(drop=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2040
 
2041
 
2042
  df = load_oneig_dataframe(oneig_path)
 
2086
  data_dir / "qwen_image_bench_combined",
2087
  space_root.parent / "qwen_image_bench_combined",
2088
  )
 
 
 
 
 
 
 
 
2089
  qwen_path = _resolve_data_path(
2090
+ data_dir / "qwen_image_bench_model_price_and_median_generation_time.csv",
2091
+ space_root.parent / "qwen_image_bench_model_price_and_median_generation_time.csv",
2092
  )
2093
  aa_path = _resolve_data_path(
2094
  data_dir / "artificial_analysis_text_to_image_leaderboard.csv",
 
2098
  data_dir / "arena_ai_text_to_image_leaderboard.csv",
2099
  space_root.parent / "arena_ai_text_to_image_leaderboard.csv",
2100
  )
 
 
 
 
 
 
 
 
 
 
 
 
2101
 
2102
  qwen_df = load_qwen_combined_dataframe(qwen_path)
2103
  aa_df = load_artificial_analysis_dataframe(aa_path)
2104
  arena_df = load_arena_ai_dataframe(arena_path)
 
 
 
2105
  qwen_display_columns = [
2106
  col
2107
  for col in [
 
2109
  "Datapoint Elo",
2110
  "Rapidata Elo",
2111
  "P-Judge Overall",
2112
+ "Raw Win Rate",
2113
  "Median Generation Time (s)",
2114
  "Min Generation Time (s)",
2115
  "Price / Image (USD)",
 
2134
  ]
2135
  if col in arena_df.columns
2136
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2137
 
2138
  oneig_samples = load_sample_comparison_data(oneig_combined_dir)
2139
  qwen_samples = load_sample_comparison_data(qwen_combined_dir)
 
 
2140
 
2141
  metrics = [
2142
  {"id": "datapoint_elo", "column": "Datapoint Elo"},
 
2195
  "arena_text",
2196
  ],
2197
  )
 
 
 
 
 
 
 
2198
 
2199
  datasets = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2200
  {
2201
  "id": "qwen",
2202
  "name": "Qwen Image Dataset",
 
2203
  "data": qwen_df,
2204
  "columns": qwen_display_columns,
2205
  "metric_ids": qwen_metric_ids,
 
2209
  {
2210
  "id": "oneig",
2211
  "name": "OneIG Alignment Dataset",
 
2212
  "data": oneig_df,
2213
  "columns": oneig_display_columns,
2214
  "metric_ids": oneig_metric_ids,
 
2221
  {
2222
  "id": "artificial_analysis",
2223
  "name": "Artificial Analysis Dataset",
 
2224
  "data": aa_df,
2225
  "columns": aa_display_columns,
2226
  "metric_ids": aa_metric_ids,
 
2230
  {
2231
  "id": "arena_ai",
2232
  "name": "Arena AI Dataset",
 
2233
  "data": arena_df,
2234
  "columns": arena_display_columns,
2235
  "metric_ids": arena_metric_ids,
 
2240
  datasets = [dataset for dataset in datasets if dataset["metric_ids"]]
2241
 
2242
  DEFAULT_DATASET_ID = next(
2243
+ (dataset["id"] for dataset in datasets if dataset["id"] == "qwen"),
2244
+ datasets[0]["id"] if datasets else None,
 
 
 
 
 
 
2245
  )
2246
  DEFAULT_METRIC_ID = None
2247
 
 
2317
  return found;
2318
  };
2319
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2320
  const restylePlots = (mode) => {
2321
+ const layout = PLOT_LAYOUT[mode];
2322
+ if (!layout || typeof Plotly === "undefined") return;
2323
  queryAll(".js-plotly-plot").forEach((gd) => {
2324
+ try { Plotly.relayout(gd, layout); } catch (e) {}
 
2325
  });
2326
  };
2327
 
 
2459
  })();
2460
  </script>
2461
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2462
  (() => {
2463
  if (window.__inferbenchChipScrollBound) return;
2464
  window.__inferbenchChipScrollBound = true;
data/i2v-pro.csv DELETED
@@ -1,21 +0,0 @@
1
- task,model_id,display_name,wandb_run_ids,wandb_project,provider,endpoint,resolution,output_duration_s,n_generations,min_generation_s,p20_generation_s,median_generation_s,mean_generation_s,generation_s_per_output_video_s,median_generation_s_per_output_video_s,model_execution_s_per_output_video_s,model_execution_source,predict_s_per_output_video_s,list_price_usd_per_second,yaml_price_usd_per_second,currently_billed_usd_per_second,flat_price_usd_per_request,price_usd_per_second,price_usd_per_clip,price_usd_per_5s,price_config,price_note,disabled_expansion_model_execution_s_per_output_video_s,disabled_expansion_timing_source,datapoint_elo,rapidata_elo
2
- i2v,p_video_2_pro__mode_cost__prompt_upsampler_off__resolution_480p,"P-Video 2 Pro (cost mode, 480p)",lqcey8fm,p-video-i2v,replicate,prunaai/p-video-2-pro,480p,5.0,10,9.646036516000096,11.469126884000797,14.284900057999948,13.203384606500368,2.6406769213000736,2.8569800115999895,0.95356,replicate model_execution_time_s,2.8225635115,0.01,0.01,0.01,0.0,0.01,0.05,0.05,model/remote/text+image_video/p_video_2_pro/replicate_480p_cost_off.yaml,,,,961.0,984.0
3
- i2v,p_video_2_pro__mode_speed__prompt_upsampler_turbo__resolution_480p,"P-Video 2 Pro (speed, upsampler turbo, 480p)",uflwzoyr,p-video-i2v,replicate,prunaai/p-video-2-pro,480p,5.0,100,7.607446426998649,10.114996741200594,12.339616352997837,12.90726687451992,2.5814533749039836,2.4679232705995675,0.307928,replicate model_execution_time_s,2.4315828523,0.02,0.02,0.02,0.0,0.02,0.1,0.1,model/remote/text+image_video/p_video_2_pro/replicate_480p_speed_turbo.yaml,,,,961.0,984.0
4
- i2v,minimax_h3_max_turbo__prompt_expansion_mode_balanced__resolution_480p,"MiniMax H3 Max Turbo (expansion balanced, 480p)",rynohmot,p-video-i2v,fal,minimax/h3-max-turbo/image-to-video,480p,5.0,85,2.0626198340032715,2.676248207790195,3.3828403819934465,3.5529157923407824,0.7105831584681565,0.6765680763986893,0.6701127952941176,fal request duration,,0.025,0.0125,0.0125,0.0,0.025,0.125,0.125,model/remote/text+image_video/minimax_h3_max_turbo/fal_480p_balanced.yaml,fal list; fal still bills 50% promo $0.0125/s (page says promo ended 2026-09-30),0.53,estimated,978.0,938.0
5
- i2v,p_video_2_pro__mode_cost__prompt_upsampler_off__resolution_768p,"P-Video 2 Pro (cost mode, 768p)",rn66usgo,p-video-i2v,replicate,prunaai/p-video-2-pro,768p,5.0,10,18.36896738299947,20.285163481000563,21.051096533999953,28.224230830200213,5.644846166040042,4.210219306799991,2.15268,replicate model_execution_time_s,4.0450694081,0.025,0.025,0.025,0.0,0.025,0.125,0.125,model/remote/text+image_video/p_video_2_pro/replicate_768p_cost_off.yaml,,,,994.0,995.0
6
- i2v,agnes_video_2_5,Agnes Video 2.5 (720p),9mk5by2e,p-video-i2v,agnes,agnes-video-2.5,720p,5.0,85,48.16999681999732,72.84911508619844,73.43243030199665,86.38921110764632,17.277842221529266,14.686486060399329,,,,0.025,0.025,0.025,0.0,0.025,0.125,0.125,model/remote/text+image_video/agnes_video_2_5/agnes.yaml,,,,994.0,1009.0
7
- i2v,p_video_2_pro__mode_speed__prompt_upsampler_turbo__resolution_768p,"P-Video 2 Pro (speed, upsampler turbo, 768p)",tpm41r5n,p-video-i2v,replicate,prunaai/p-video-2-pro,768p,5.0,100,9.887984333006898,12.503273962804816,13.168237036006758,16.083959509319683,3.2167919018639366,2.6336474072013516,0.600798,replicate model_execution_time_s,2.5795859222999997,0.035,0.035,0.035,0.0,0.035,0.17500000000000002,0.17500000000000002,model/remote/text+image_video/p_video_2_pro/replicate_768p_speed_turbo.yaml,,,,994.0,995.0
8
- i2v,minimax_h3_max_turbo__prompt_expansion_mode_disabled__resolution_768p,"MiniMax H3 Max Turbo (expansion disabled, 768p)",pjwfymx5,p-video-i2v,fal,minimax/h3-max-turbo/image-to-video,768p,5.0,85,2.6675288240003283,3.140221786400434,3.638195310999436,3.8602934768940673,0.7720586953788134,0.7276390621998872,0.7294826282352943,fal request duration,,0.04,0.04,0.02,0.0,0.04,0.2,0.2,model/remote/text+image_video/minimax_h3_max_turbo/fal.yaml,fal list; fal still bills 50% promo $0.02/s (page says promo ended 2026-09-30),0.7294826282352943,"measured (fal duration, run pjwfymx5)",,
9
- i2v,minimax_h3_max_turbo__prompt_expansion_mode_balanced__resolution_768p,"MiniMax H3 Max Turbo (expansion balanced, 768p)",8nqtrs6k,p-video-i2v,fal,minimax/h3-max-turbo/image-to-video,768p,5.0,85,3.360883756977273,3.894791807589354,4.465880261996063,4.664087176540702,0.9328174353081404,0.8931760523992127,0.8866546423529411,fal request duration,,0.04,0.04,0.02,0.0,0.04,0.2,0.2,model/remote/text+image_video/minimax_h3_max_turbo/fal_768p_balanced.yaml,fal list; fal still bills 50% promo $0.02/s (page says promo ended 2026-09-30),0.7294826282352943,"measured (fal duration, run pjwfymx5)",993.0,1028.0
10
- i2v,minimax_h3_max__prompt_expansion_mode_balanced__resolution_480p,"MiniMax H3 Max (expansion balanced, 480p)",zd77gnta,p-video-i2v,fal,minimax/h3-max/image-to-video,480p,5.0,85,2.4688335089995235,2.904314552000142,3.387883318999229,3.737727538835273,0.7475455077670545,0.6775766637998457,0.7043849176470587,fal request duration,,0.05,0.025,0.025,0.0,0.05,0.25,0.25,model/remote/text+image_video/minimax_h3_max/fal_480p_balanced.yaml,fal list; fal still bills 50% promo $0.025/s (page says promo ended 2026-09-30),0.56,estimated,989.0,922.0
11
- i2v,veo_3_1_lite,Veo 3.1 Lite (720p),py4m5xd9,p-video-i2v,wavespeed,google/veo3.1-lite/image-to-video,720p,6.0,98,41.81875224500254,49.431026957599535,56.17033411549892,58.89651842808168,9.816086404680279,9.361722352583154,,,,0.05,0.05,0.05,0.0,0.05000000000000001,0.30000000000000004,0.25,model/remote/text+image_video/veo_3_1_lite/wavespeed.yaml,,,,1016.0,1029.0
12
- i2v,grok_imagine_video,Grok Imagine Video (720p),1pj3o83x,p-video-i2v,wavespeed,x-ai/grok-imagine-video/image-to-video,720p,6.0,100,62.43508535699948,69.995984365201,81.70177976000014,85.91732073955012,14.319553456591688,13.616963293333356,,,,0.05,0.05,0.05,0.0,0.05000000000000001,0.30000000000000004,0.25,model/remote/text+image_video/grok_imagine_video/wavespeed.yaml,,,,998.0,993.0
13
- i2v,p_video_2_pro__mode_quality__prompt_upsampler_max__resolution_768p,"P-Video 2 Pro (quality, upsampler max, 768p)",92gnt2qk,p-video-i2v,replicate,prunaai/p-video-2-pro,768p,5.0,100,54.11051772299106,68.09604510500503,82.57195331449475,102.8043552905605,20.5608710581121,16.514390662898947,1.8536400000000002,replicate model_execution_time_s,16.2845354215,0.075,0.075,0.075,0.0,0.075,0.375,0.375,model/remote/text+image_video/p_video_2_pro/replicate_768p_quality_max.yaml,,,,1013.0,1049.0
14
- i2v,minimax_h3_max__prompt_expansion_mode_disabled__resolution_768p,"MiniMax H3 Max (expansion disabled, 768p)",3m1dlqdk,p-video-i2v,fal,minimax/h3-max/image-to-video,768p,5.0,85,4.174281786999927,4.483852291799485,5.105214381999758,5.227787268011718,1.0455574536023435,1.0210428763999517,0.9978179623529411,fal request duration,,0.08,0.08,0.04,0.0,0.08,0.4,0.4,model/remote/text+image_video/minimax_h3_max/fal.yaml,fal list; fal still bills 50% promo $0.04/s (page says promo ended 2026-09-30),0.9978179623529411,"measured (fal duration, run 3m1dlqdk)",,
15
- i2v,minimax_h3_max__prompt_expansion_mode_balanced__resolution_768p,"MiniMax H3 Max (expansion balanced, 768p)",6l5e62xs,p-video-i2v,fal,minimax/h3-max/image-to-video,768p,5.0,85,4.774919076007791,5.433260408189381,5.80711786300526,6.162871519518975,1.232574303903795,1.161423572601052,1.1812099717647058,fal request duration,,0.08,0.08,0.04,0.0,0.08,0.4,0.4,model/remote/text+image_video/minimax_h3_max/fal_768p_balanced.yaml,fal list; fal still bills 50% promo $0.04/s (page says promo ended 2026-09-30),0.9978179623529411,"measured (fal duration, run 3m1dlqdk)",999.0,993.0
16
- i2v,ltx_2_5_fast,LTX 2.5 Fast (720p),mdwwaui9,p-video-i2v,fal,lightricks/ltx-2.5/image-to-video/fast,720p,6.0,100,19.59916955500012,25.333775025999785,30.807174913999916,30.09333773863007,5.015556289771679,5.13452915233332,,,,0.09,0.09,0.09,0.0,0.09000000000000001,0.54,0.44999999999999996,model/remote/text+image_video/ltx_2_5_fast/fal.yaml,,,,1006.0,943.0
17
- i2v,gemini_omni_1_1_flash,Gemini Omni 1.1 Flash (720p),rgls30vm,p-video-i2v,wavespeed,google/gemini-omni-1.1-flash/image-to-video,720p,5.0,96,33.23962910800037,40.41112426700056,47.169307519498034,76.65512052288535,15.331024104577072,9.433861503899607,,,,0.1,0.1,0.1,0.0,0.1,0.5,0.5,model/remote/text+image_video/gemini_omni_1_1_flash/wavespeed.yaml,,,,1018.0,993.0
18
- i2v,minimax_h3,MiniMax H3 (768p),4i8707tj,p-video-i2v,wavespeed,minimax/h3/image-to-video,768p,5.0,98,122.5933248429974,146.0719200146006,155.3556124200004,163.95953334504068,32.791906669008135,31.071122484000078,,,,0.1,0.1,0.1,0.0,0.1,0.5,0.5,model/remote/text+image_video/minimax_h3/wavespeed.yaml,,,,1019.0,1023.0
19
- i2v,ltx_2_5_pro,LTX 2.5 Pro (720p),oq5adzi8,p-video-i2v,fal,lightricks/ltx-2.5/image-to-video/pro,720p,6.0,100,23.96283850599866,30.78141485860033,32.351289345499936,32.846369120970046,5.474394853495008,5.391881557583323,,,,0.12,0.12,0.12,0.0,0.12,0.72,0.6,model/remote/text+image_video/ltx_2_5_pro/fal.yaml,,,,1009.0,1016.0
20
- i2v,grok_imagine_video_v1_5,Grok Imagine Video v1.5 (720p),c6iao0m8,p-video-i2v,wavespeed,x-ai/grok-imagine-video-v1.5/image-to-video,720p,5.0,100,37.19857703399976,44.88756618759872,55.24653504449998,59.73615804140987,11.947231608281975,11.049307008899996,,,,0.14,0.14,0.14,0.01,0.14200000000000002,0.7100000000000001,0.7100000000000001,model/remote/text+image_video/grok_imagine_video_v1_5/wavespeed.yaml,,,,1000.0,1023.0
21
- i2v,seedance_2_5_turbo,Seedance 2.5 Turbo (720p),9pr8w9xy,p-video-i2v,wavespeed,bytedance/seedance-2.5/image-to-video-turbo,720p,5.0,100,151.128106406999,203.1471570823989,253.8349715054992,280.7854034020103,56.15708068040205,50.76699430109984,,,,0.2,0.2,0.2,0.0,0.2,1.0,1.0,model/remote/text+image_video/seedance_2_5_turbo/wavespeed.yaml,,,,975.0,935.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/qwen_image_bench_model_price_and_median_generation_time.csv ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Model,Price / Image (USD),Median Generation Time (s),Min Generation Time (s),P-Judge Overall,Raw Win Rate,Rapidata Elo,Datapoint Elo,Benchmark.ai Elo
2
+ reve_2_1,N/A,N/A,28.3,,,,,1173.2
3
+ ideogram_4_0_quality,N/A,N/A,66.6,,,,,1131.0
4
+ gpt_image_2,0.21,77.8,77.8,59.02083099999998,,1172.58,1116,1124.5
5
+ nano_banana_2_0,N/A,N/A,N/A,56.362956,59.4%,1071.79,1067,1056.3
6
+ gpt_image_1_5,0.135,38.0,38.0,57.864434999999986,64.5%,1102.09,1064,910.3
7
+ hidream_i1_dev,0.0086,2.823569217998738,2.06,49.17682099999999,51.7%,999.17,984,
8
+ gpt_image_1,0.167,38.8,38.8,54.975741000000006,,1095.39,987,
9
+ imagen_4_0_ultra,0.06,11.4,11.4,53.385603999999965,59.7%,1075.22,1023,
10
+ flux_2_flex,0.06,10.856533817990567,8.07,53.9245676767677,57.8%,1054.34,1018,921.3
11
+ qwen_image,0.025,4.8,4.8,51.561746,51.5%,1073.72,1005,975.6
12
+ seedream_5_0,N/A,N/A,N/A,55.715153,,1070.35,1012,
13
+ nano_banana_pro,0.134,17.2,17.2,56.452189898989914,58.0%,1029.51,1045,1102.4
14
+ hidream_i1_fast,0.0051,9.920469530501578,1.40,48.89298600000002,50.1%,1024.67,984,
15
+ imagen_4_fast,0.02,3.7531301500021073,2.71,50.155055208333344,,972.6,981,
16
+ seedream_4_5,0.04,16.6,16.6,55.66328800000001,,1048.96,1035,964.2
17
+ seedream_4_0,0.03,12.2,12.2,55.241443999999994,,1050.41,1035,
18
+ p_image_2_ideogram_low_1k,0.0075,2.59,1.55,54.827397,53.2%,1000.07,1009,1103.9
19
+ #p_image_2_ideogram_low_2k,0.016,5.17,4.25,53.971723,48.4%,1074.91,1003,
20
+ qwen_image_2_0_pro,0.035,35.5,35.5,56.181776,,1033.25,1017,959.9
21
+ juggernaut_base_flux,0.035,4.115834823496698,3.84,49.474676,46.4%,1038.22,972,
22
+ flux_2_pro,N/A,N/A,N/A,54.43423900000002,,993.54,1019,1011.6
23
+ z_image,0.005,1.5122045120006078,1.22,49.946227999999984,48.1%,1028.1,1001,
24
+ p_image_2_ideogram_high_1k,0.015,4.28,3.07,55.754507999999994,52.1%,972.92,1022,1104.0
25
+ #p_image_2_ideogram_high_2k,0.03,8.69,7.12,54.757842000000004,49.4%,1074.91,1007,
26
+ qwen_image_2512,0.02,19.1,19.1,51.677326,,1029.6,1009,
27
+ flux_2_max,0.07,26.4,26.4,54.047976,60.9%,955.19,1028,1001.6
28
+ flux_1_1_pro_ultra,0.06,9.026992494000297,6.20,50.358445,52.0%,979.56,995,
29
+ juggernaut_pro_flux,0.055,3.699636150500737,3.36,49.741183,46.4%,972.14,964,
30
+ flux_dev,0.025,1.6931055715031107,1.49,48.241479,42.1%,925.04,940,
31
+ p_image_2_ideogram_very_low_1k,0.003,2.56,1.49,53.51894200000001,48.1%,959.86,995,1071.7
32
+ #p_image_2_ideogram_very_low_2k,0.006,3.94,3.05,53.68248699999998,47.2%,962.38,980,
33
+ #p_image_2_ideogram_very_low_1k_no_upsampling,0.005,0.82,,46.33,,,,1071.7
34
+ #p_image_2_ideogram_very_low_2k_no_upsampling,0.005,2.18,,46.39,,,,1071.7
35
+ #p_image_2_ideogram_low_1k_no_upsampling,0.01,3.33,,45.32,,,,1103.9
36
+ #p_image_2_ideogram_low_2k_no_upsampling,0.01,3.34,,46.25,,,,1103.9
37
+ #p_image_2_ideogram_medium_1k_no_upsampling,0.015,2.13,,46.88,,,,1115.1
38
+ #p_image_2_ideogram_medium_2k_no_upsampling,0.015,5.55,,47.11,,,,1115.1
39
+ #p_image_2_ideogram_high_1k_no_upsampling,0.03,3.11,,46.88,,,,1104.0
40
+ #p_image_2_ideogram_high_2k_no_upsampling,0.03,5.55,,47.06,,,,1104.0
41
+ hidream_i1_full,0.014,6.008430051002506,5.69,46.82559300000002,36.9%,955.46,944,
42
+ flux_2_dev,0.025,4.310278721997747,4.03,52.71644489795918,53.1%,1007.6,1021,942.0
43
+ imagen_4_0,0.04,14.1,14.1,52.08996199999999,53.5%,979.62,1005,
44
+ wan_2_2_image,0.02,3.005390542501118,2.96,48.19959399999999,,944.87,960,
45
+ flux_krea,0.025,1.7150160090022837,1.7150160090022837,50.35734,50.0%,919.73,975,
46
+ p_image_2_ideogram_medium_1k,0.01,3.06,2.05,54.719193000000004,51.7%,941.46,1002,1115.1
47
+ #p_image_2_ideogram_medium_2k,0.02,7.44,6.47,54.23124444444446,48.1%,949.35,1000,
48
+ glm_image,0.05,188.2,188.2,51.42623399999999,,923.35,953,
49
+ p_image,0.005,1.0640762715011078,0.95,48.75217099999999,44.8%,924.37,961,1098.7
50
+ hunyuanimage_3_0,0.09,41.0,41.0,52.32440099999998,52.4%,1009.61,979,765.3
51
+ juggernaut_lightning_flux,0.006,1.1787893719956628,0.93,48.30471699999998,40.5%,916.68,929,
52
+ flux_1_1_pro,0.04,3.0104645500032348,2.34,49.92882700000001,50.6%,925.04,984,
53
+ flux_schnell,0.003,0.8411653029907029,0.80,46.685981818181816,34.8%,892.32,915,
54
+ kling_v2_1,N/A,N/A,N/A,51.044512,,870.04,981,
55
+ #p_image_2_ideogram_very_high_high_1k,0.075,9.34,7.25,58.45,,,1025,
56
+ #p_image_2_ideogram_very_high_low_1k,0.0375,26.17,10.44,57.59,,,1024,
57
+ #p_image_2_ideogram_very_high_medium_1k,0.05,9.28,5.96,57.88,,,1020,
58
+ #p_image_2_ideogram_very_high_very_low_1k,0.015,26.52,10.60,56.92,,,1002,
59
+ #p_image_2_ideogram_final_1k,0.0375,11.17,5.55,58.28,,,,
60
+ #p_image_2_ideogram_final_2k,0.075,14.34,9.96,57.68,,,,
data/qwen_image_bench_model_price_and_median_generation_time_10_august.csv DELETED
@@ -1,64 +0,0 @@
1
- Rapidata Model,Price / Image (USD),Median Generation Time (s),Min Generation Time (s),P-Judge Overall,Raw Win Rate,Rapidata Elo,Datapoint Elo,Benchmark.ai Elo
2
- reve_2_1,N/A,N/A,28.3,,,,,1173.2
3
- ideogram_4_0_quality,N/A,N/A,66.6,,,,,1131.0
4
- gpt_image_2,0.21,77.8,77.8,59.02083099999998,65.6%,1172.58,1110,1124.5
5
- nano_banana_2_0,N/A,N/A,N/A,56.362956,59.2%,1071.79,1063,1056.3
6
- gpt_image_1_5,0.135,38.0,38.0,57.864434999999986,58.9%,1102.09,1060,910.3
7
- hidream_i1_dev,0.0086,2.823569217998738,2.06,49.17682099999999,47.7%,999.17,983,
8
- gpt_image_1,0.167,38.8,38.8,54.975741000000006,47.4%,1095.39,984,
9
- imagen_4_0_ultra,0.06,11.4,11.4,53.385603999999965,52.9%,1075.22,1019,
10
- flux_2_flex,0.06,10.856533817990567,8.07,53.9245676767677,52.4%,1054.34,1014,921.3
11
- #flux_2_turbo,0.008,2.14,1.81,53.02,,,1003,
12
- #flux_2_flash,0.005,1.43,1.03,52.03,,,1001,
13
- qwen_image,0.025,4.8,4.8,51.561746,50.3%,1073.72,1002,975.6
14
- seedream_5_0,N/A,N/A,N/A,55.715153,51.6%,1070.35,1010,
15
- nano_banana_pro,0.134,17.2,17.2,56.452189898989914,56.4%,1029.51,1041,1102.4
16
- hidream_i1_fast,0.0051,9.920469530501578,1.40,48.89298600000002,47.2%,1024.67,980,
17
- imagen_4_fast,0.02,3.7531301500021073,2.71,50.155055208333344,47.2%,972.6,980,
18
- seedream_4_5,0.04,16.6,16.6,55.66328800000001,54.7%,1048.96,1032,964.2
19
- seedream_4_0,0.03,12.2,12.2,55.241443999999994,54.9%,1050.41,1032,
20
- p_image_2_ideogram_low_1k,0.0075,2.59,1.55,54.827397,50.8%,1000.07,1006,1103.9
21
- #p_image_2_ideogram_low_2k,0.016,5.17,4.25,53.971723,50.0%,1074.91,1000,1103.9
22
- qwen_image_2_0_pro,0.035,35.5,35.5,56.181776,52.2%,1033.25,1014,959.9
23
- juggernaut_base_flux,0.035,4.115834823496698,3.84,49.474676,46.1%,1038.22,971,
24
- flux_2_pro,N/A,N/A,N/A,54.43423900000002,52.2%,993.54,1014,1011.6
25
- z_image,0.005,1.5122045120006078,1.22,49.946227999999984,49.9%,1028.1,999,
26
- p_image_2_ideogram_high_1k,0.015,4.28,3.07,55.754507999999994,52.5%,972.92,1017,1104.0
27
- #p_image_2_ideogram_high_2k,0.06,8.69,7.12,54.757842000000004,50.7%,1074.91,1006,1104.0
28
- qwen_image_2512,0.02,19.1,19.1,51.677326,50.9%,1029.6,1005,
29
- flux_2_max,0.07,26.4,26.4,54.047976,53.9%,955.19,1026,1001.6
30
- flux_1_1_pro_ultra,0.06,9.026992494000297,6.20,50.358445,48.6%,979.56,990,
31
- juggernaut_pro_flux,0.055,3.699636150500737,3.36,49.741183,44.7%,972.14,963,
32
- flux_dev,0.025,1.6931055715031107,1.49,48.241479,41.5%,925.04,941,
33
- p_image_2_ideogram_very_low_1k,0.003,2.56,1.49,53.51894200000001,49.1%,959.86,994,1071.7
34
- #p_image_2_ideogram_very_low_2k,0.006,3.94,3.05,53.68248699999998,46.3%,962.38,976,1071.7
35
- #p_image_2_ideogram_very_low_1k_no_upsampling,0.005,0.82,,46.33,,,,1071.7
36
- #p_image_2_ideogram_very_low_2k_no_upsampling,0.005,2.18,,46.39,,,,1071.7
37
- #p_image_2_ideogram_low_1k_no_upsampling,0.01,3.33,,45.32,,,,1103.9
38
- #p_image_2_ideogram_low_2k_no_upsampling,0.01,3.34,,46.25,,,,1103.9
39
- #p_image_2_ideogram_medium_1k_no_upsampling,0.015,2.13,,46.88,,,,1115.1
40
- #p_image_2_ideogram_medium_2k_no_upsampling,0.015,5.55,,47.11,,,,1115.1
41
- #p_image_2_ideogram_high_1k_no_upsampling,0.03,3.11,,46.88,,,,1104.0
42
- #p_image_2_ideogram_high_2k_no_upsampling,0.03,5.55,,47.06,,,,1104.0
43
- hidream_i1_full,0.014,6.008430051002506,5.69,46.82559300000002,41.4%,955.46,941,
44
- flux_2_dev,0.025,4.310278721997747,4.03,52.71644489795918,52.5%,1007.6,1016,942.0
45
- imagen_4_0,0.04,14.1,14.1,52.08996199999999,50.4%,979.62,1002,
46
- wan_2_2_image,0.02,3.005390542501118,2.96,48.19959399999999,44.1%,944.87,958,
47
- flux_krea,0.025,1.7150160090022837,1.7150160090022837,50.35734,46.2%,919.73,973,
48
- p_image_2_ideogram_medium_1k,0.01,3.06,2.05,54.719193000000004,49.8%,941.46,999,1115.1
49
- #p_image_2_ideogram_medium_2k,0.02,7.44,6.47,54.23124444444446,49.3%,949.35,996,1115.1
50
- glm_image,0.05,188.2,188.2,51.42623399999999,42.9%,923.35,950,
51
- p_image,0.005,1.0640762715011078,0.95,48.75217099999999,44.3%,924.37,960,1098.7
52
- hunyuanimage_3_0,0.09,41.0,41.0,52.32440099999998,46.6%,1009.61,977,765.3
53
- juggernaut_lightning_flux,0.006,1.1787893719956628,0.93,48.30471699999998,40.0%,916.68,930,
54
- flux_1_1_pro,0.04,3.0104645500032348,2.34,49.92882700000001,47.7%,925.04,984,
55
- flux_schnell,0.003,0.8411653029907029,0.80,46.685981818181816,37.6%,892.32,914,
56
- kling_v2_1,N/A,N/A,N/A,51.044512,47.2%,870.04,980,
57
- #p_image_2_ideogram_very_high_high_1k,0.075,9.34,7.25,58.45,52.9%,,1024,
58
- #p_image_2_ideogram_very_high_low_1k,0.0375,26.17,10.44,57.59,52.9%,,1023,
59
- #p_image_2_ideogram_very_high_medium_1k,0.05,9.28,5.96,57.88,52.3%,,1019,
60
- #p_image_2_ideogram_very_high_very_low_1k,0.015,26.52,10.60,56.92,49.4%,,1001,
61
- p_image_2_ideogram_very_high_1k,0.033,11.17,5.55,58.28,55.5%,,1034,
62
- #p_image_2_ideogram_very_high_2k,0.066,14.34,9.96,57.68,53.4%,,1020,
63
- #p_image_2_ideogram_very_high_john_1k,,8.53,6.43,58.19,,,1015,
64
- #p_image_2_ideogram_very_high_john_2k,,13.86,10.64,57.75,,,1002,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/t2v-pro.csv DELETED
@@ -1,29 +0,0 @@
1
- task,model_id,display_name,wandb_run_ids,wandb_project,provider,endpoint,resolution,output_duration_s,n_generations,min_generation_s,p20_generation_s,median_generation_s,mean_generation_s,generation_s_per_output_video_s,median_generation_s_per_output_video_s,model_execution_s_per_output_video_s,model_execution_source,predict_s_per_output_video_s,list_price_usd_per_second,yaml_price_usd_per_second,currently_billed_usd_per_second,flat_price_usd_per_request,price_usd_per_second,price_usd_per_clip,price_usd_per_5s,price_config,price_note,disabled_expansion_model_execution_s_per_output_video_s,disabled_expansion_timing_source,datapoint_elo,rapidata_elo
2
- t2v,p_video_2_pro__mode_cost__prompt_upsampler_off__resolution_480p,"P-Video 2 Pro (cost mode, 480p)",jycb3yyj,p-video-2-pro,replicate,prunaai/p-video-2-pro,480p,5.0,10,9.408479179999633,9.510774168599891,9.72883671299951,10.391401128699908,2.0782802257399817,1.9457673425999018,0.9005,replicate model_execution_time_s,1.8816932411,0.01,0.01,0.01,0.0,0.01,0.05,0.05,model/remote/text_video/p_video_2_pro/replicate_480p_cost_off.yaml,,,,961.0,905.0
3
- t2v,p_video_2__draft_true__prompt_upsampling_false__resolution_720p,"P-Video 2 (draft, no upsampling, 720p)",9ur57h54,p-video-2-0,replicate,prunaai/p-video-2.0,720p,5.0,88,3.379928643000312,4.208131522199255,5.454214365498046,7.4804829126126355,1.4960965825225272,1.0908428730996094,0.40954545454545455,replicate model_execution_time_s,1.0549488494,0.015,0.015,0.015,0.0,0.015,0.075,0.075,model/remote/text_video/p_video_2/replicate_720p_draft.yaml,,,,,
4
- t2v,p_video_2__draft_true__prompt_upsampling_true__resolution_720p,"P-Video 2 (draft, upsampling, 720p)",6hi994vk,p-video-2-0,replicate,prunaai/p-video-2.0,720p,5.0,90,4.985804016003385,6.472871531004785,7.4922584965024726,12.012051498078574,2.4024102996157146,1.4984516993004944,0.40678444444444445,replicate model_execution_time_s,1.4668891899999998,0.015,0.015,0.015,0.0,0.015,0.075,0.075,model/remote/text_video/p_video_2/replicate_720p_draft_upsample.yaml,,,,984.0,1044.0
5
- t2v,p_video_2_pro__mode_cost__prompt_upsampler_off__resolution_768p,"P-Video 2 Pro (cost mode, 768p)",zeio3rpy,p-video-2-pro,replicate,prunaai/p-video-2-pro,768p,5.0,10,15.82823935200031,16.06025371800024,18.991634191500452,18.809975293400203,3.7619950586800406,3.7983268383000905,2.0337,replicate model_execution_time_s,3.7674125726,0.025,0.025,0.025,0.0,0.025,0.125,0.125,model/remote/text_video/p_video_2_pro/replicate_768p_cost_off.yaml,,,,1011.0,1129.0
6
- t2v,agnes_video_2_5,Agnes Video 2.5 (720p),krnwtzyy,p-video-2-0,agnes,agnes-video-2.5,720p,5.0,90,39.94301277900013,48.21273472360044,56.4691387010007,62.43517924498891,12.487035848997783,11.29382774020014,,,,0.025,0.025,0.025,0.0,0.025,0.125,0.125,model/remote/text_video/agnes_video_2_5/agnes.yaml,,,,990.0,1009.0
7
- t2v,p_video_2__draft_false__prompt_upsampling_false__resolution_720p,"P-Video 2 (full, no upsampling, 720p)",m2jf4z7h,p-video-2-0,replicate,prunaai/p-video-2.0,720p,5.0,89,5.859760620005545,7.147269867203431,8.162274362999597,10.762800585236556,2.1525601170473116,1.6324548725999193,0.9053123595505618,replicate model_execution_time_s,1.5813138966,0.03,0.025,0.03,0.0,0.03,0.15,0.15,model/remote/text_video/p_video_2/replicate_720p.yaml,Replicate prunaai/p-video-2 list; YAML had $0.025/s,,,,
8
- t2v,p_video_2__draft_true__prompt_upsampling_false__resolution_1080p,"P-Video 2 (draft, no upsampling, 1080p)",qbt0atz4,p-video-2-0,replicate,prunaai/p-video-2.0,1080p,5.0,89,6.250065040003392,7.504525098402519,9.528199804000906,12.155668083078679,2.431133616615736,1.905639960800181,0.7517640449438201,replicate model_execution_time_s,1.7764584898,0.03,0.03,0.03,0.0,0.03,0.15,0.15,model/remote/text_video/p_video_2/replicate_1080p_draft.yaml,,,,,
9
- t2v,p_video_2__draft_false__prompt_upsampling_true__resolution_720p,"P-Video 2 (full, upsampling, 720p)",2q5jydr8,p-video-2-0,replicate,prunaai/p-video-2.0,720p,5.0,90,7.227749306999613,9.154919161600994,9.880705762494472,12.394927337400603,2.4789854674801206,1.9761411524988943,0.9079755555555554,replicate model_execution_time_s,1.8864087514999999,0.03,0.025,0.03,0.0,0.03,0.15,0.15,model/remote/text_video/p_video_2/replicate_720p_upsample.yaml,Replicate prunaai/p-video-2 list; YAML had $0.025/s,,,987.0,1032.0
10
- t2v,p_video_2__draft_true__prompt_upsampling_true__resolution_1080p,"P-Video 2 (draft, upsampling, 1080p)",gcbyy4wn,p-video-2-0,replicate,prunaai/p-video-2.0,1080p,5.0,90,8.047415203996934,9.22702455239487,11.128662197996164,14.278928932766332,2.8557857865532665,2.225732439599233,0.7514066666666667,replicate model_execution_time_s,2.178066129,0.03,0.03,0.03,0.0,0.03,0.15,0.15,model/remote/text_video/p_video_2/replicate_1080p_draft_upsample.yaml,,,,,
11
- t2v,p_video_2_pro__mode_speed__prompt_upsampler_turbo__resolution_768p,"P-Video 2 Pro (speed, upsampler turbo, 768p)",syngi7ri,p-video-2-pro,replicate,prunaai/p-video-2-pro,768p,5.0,100,7.353956573002506,9.24571067720244,11.115983718002099,11.52855639862959,2.305711279725918,2.2231967436004196,0.807034,replicate model_execution_time_s,2.1527908192,0.035,0.035,0.035,0.0,0.035,0.17500000000000002,0.17500000000000002,model/remote/text_video/p_video_2_pro/replicate_768p_speed_turbo.yaml,,,,1011.0,1129.0
12
- t2v,p_video_2_pro__mode_speed__prompt_upsampler_off__resolution_768p,"P-Video 2 Pro (speed, upsampler off, 768p)",jgyitbf0,p-video-2-pro,replicate,prunaai/p-video-2-pro,768p,5.0,99,4.8043301480065566,7.719320420798613,10.179680373999872,11.869338264453667,2.373867652890733,2.0359360747999746,0.8455151515151514,replicate model_execution_time_s,1.7538052489999998,0.035,0.035,0.035,0.0,0.035,0.17500000000000002,0.17500000000000002,model/remote/text_video/p_video_2_pro/replicate_768p_speed_off.yaml,,,,,
13
- t2v,p_video_2_pro__mode_speed__prompt_upsampler_max__resolution_768p,"P-Video 2 Pro (speed, upsampler max, 768p)",94ledtdd,p-video-2-pro,replicate,prunaai/p-video-2-pro,768p,5.0,100,11.908190361995366,16.36631814179418,21.841233791004925,32.62473624780017,6.524947249560035,4.368246758200986,0.7760619999999999,replicate model_execution_time_s,4.344442295,0.035,0.035,0.035,0.0,0.035,0.17500000000000002,0.17500000000000002,model/remote/text_video/p_video_2_pro/replicate_768p_speed_max.yaml,,,,,
14
- t2v,minimax_h3_max_turbo__prompt_expansion_mode_disabled,"MiniMax H3 Max Turbo (expansion disabled, 768p)",3ddm84m0,p-video-2-0,fal,minimax/h3-max-turbo/text-to-video,768p,5.0,90,2.062721883998165,2.2604693188011877,2.277240929495747,3.0311573386223043,0.6062314677244609,0.45544818589914937,0.5372808644444445,fal request duration,,0.04,0.04,0.02,0.0,0.04,0.2,0.2,model/remote/text_video/minimax_h3_max_turbo/fal.yaml,fal list; fal still bills 50% promo $0.02/s (page says promo ended 2026-09-30),0.5372808644444445,"measured (fal duration, run 3ddm84m0)",,
15
- t2v,minimax_h3_max_turbo__prompt_expansion_mode_balanced,"MiniMax H3 Max Turbo (expansion balanced, 768p)",kxuwq31c,p-video-2-0,fal,minimax/h3-max-turbo/text-to-video,768p,5.0,90,2.891819470001792,3.134695611400821,3.487746603501364,6.76156262396665,1.35231252479333,0.6975493207002728,1.3032290133333335,fal request duration,,0.04,0.04,0.02,0.0,0.04,0.2,0.2,model/remote/text_video/minimax_h3_max_turbo/fal.yaml,fal list; fal still bills 50% promo $0.02/s (page says promo ended 2026-09-30),0.5372808644444445,"measured (fal duration, run 3ddm84m0)",1039.0,1208.0
16
- t2v,veo_3_1_lite,Veo 3.1 Lite (720p),jjbobes4,p-video-2-0,wavespeed,google/veo3.1-lite/text-to-video,720p,6.0,90,33.894167409991496,37.009501291197374,37.83729844300251,40.47069889308784,6.745116482181308,6.306216407167086,,,,0.05,0.05,0.05,0.0,0.05000000000000001,0.30000000000000004,0.25,model/remote/text_video/veo_3_1_lite/wavespeed.yaml,,,,969.0,976.0
17
- t2v,grok_imagine_video,Grok Imagine Video (720p),q39r8v9e,p-video-2-0,wavespeed,x-ai/grok-imagine-video/text-to-video,720p,6.0,90,68.9776645039965,78.69151808420138,99.17614604350092,96.81086467087847,16.13514411181308,16.52935767391682,,,,0.05,0.05,0.05,0.0,0.05000000000000001,0.30000000000000004,0.25,model/remote/text_video/grok_imagine_video/wavespeed.yaml,,,,957.0,987.0
18
- t2v,p_video_2__draft_false__prompt_upsampling_false__resolution_1080p,"P-Video 2 (full, no upsampling, 1080p)",9hgkhujw,p-video-2-0,replicate,prunaai/p-video-2.0,1080p,5.0,90,13.33159556199098,14.793676785795833,16.702878594005597,20.167056214423145,4.033411242884629,3.3405757188011194,2.151682222222222,replicate model_execution_time_s,3.2819483332,0.06,0.05,0.06,0.0,0.06,0.3,0.3,model/remote/text_video/p_video_2/replicate_1080p.yaml,Replicate prunaai/p-video-2 list; YAML had $0.05/s,,,,
19
- t2v,p_video_2__draft_false__prompt_upsampling_true__resolution_1080p,"P-Video 2 (full, upsampling, 1080p)",uoqpv10b,p-video-2-0,replicate,prunaai/p-video-2.0,1080p,5.0,90,14.61521741200704,16.441080821005745,18.316011337505188,22.819316110879136,4.5638632221758275,3.6632022675010374,2.1525666666666665,replicate model_execution_time_s,3.6489784669,0.06,0.05,0.06,0.0,0.06,0.3,0.3,model/remote/text_video/p_video_2/replicate_1080p_upsample.yaml,Replicate prunaai/p-video-2 list; YAML had $0.05/s,,,981.0,985.0
20
- t2v,p_video_2_pro__mode_quality__prompt_upsampler_off__resolution_768p,"P-Video 2 Pro (quality, upsampler off, 768p)",xhk419ab,p-video-2-pro,replicate,prunaai/p-video-2-pro,768p,5.0,100,9.819089652010009,11.889321832402493,14.033189198496984,14.014546667209652,2.80290933344193,2.8066378396993965,1.6132959999999998,replicate model_execution_time_s,2.799488201,0.075,0.075,0.075,0.0,0.075,0.375,0.375,model/remote/text_video/p_video_2_pro/replicate_768p_quality_off.yaml,,,,,
21
- t2v,p_video_2_pro__mode_quality__prompt_upsampler_turbo__resolution_768p,"P-Video 2 Pro (quality, upsampler turbo, 768p)",12cddspr,p-video-2-pro,replicate,prunaai/p-video-2-pro,768p,5.0,99,11.383456109993858,12.709244234193466,14.387750708992826,17.637302765524254,3.5274605531048504,2.877550141798565,1.6795858585858587,replicate model_execution_time_s,2.8335850258,0.075,0.075,0.075,0.0,0.075,0.375,0.375,model/remote/text_video/p_video_2_pro/replicate_768p_quality_turbo.yaml,,,,,
22
- t2v,p_video_2_pro__mode_quality__prompt_upsampler_max__resolution_768p,"P-Video 2 Pro (quality, upsampler max, 768p)",w7xnkv2n,p-video-2-pro,replicate,prunaai/p-video-2-pro,768p,5.0,100,16.86041410799953,19.295531428194955,27.29956308000692,30.495400724648935,6.099080144929787,5.459912616001384,1.6686840000000005,replicate model_execution_time_s,5.1314450994000005,0.075,0.075,0.075,0.0,0.075,0.375,0.375,model/remote/text_video/p_video_2_pro/replicate_768p_quality_max.yaml,,,,1022.0,1087.0
23
- t2v,minimax_h3_max,"MiniMax H3 Max (expansion balanced, 768p)",0d2lkmp6,p-video-2-0,fal,minimax/h3-max/text-to-video,768p,5.0,90,4.173863318999793,4.4671880990012145,4.49869444649994,6.903694225500132,1.3807388451000264,0.899738889299988,1.3319782333333334,fal request duration,,0.08,0.08,0.04,0.0,0.08,0.4,0.4,model/remote/text_video/minimax_h3_max/fal.yaml,fal list; fal still bills 50% promo $0.04/s (page says promo ended 2026-09-30),0.74,estimated,1032.0,1191.0
24
- t2v,ltx_2_5_fast,LTX 2.5 Fast (720p),h6se1hfi,p-video-2-0,fal,lightricks/ltx-2.5/text-to-video/fast,720p,6.0,90,21.695961473000352,24.118977216200438,26.684429597007693,31.620479494244176,5.270079915707363,4.4474049328346155,,,,0.09,0.09,0.09,0.0,0.09000000000000001,0.54,0.44999999999999996,model/remote/text_video/ltx_2_5_fast/fal.yaml,,,,1003.0,1029.0
25
- t2v,gemini_omni_1_1_flash,Gemini Omni 1.1 Flash (720p),mfajagum,p-video-2-0,wavespeed,google/gemini-omni-1.1-flash/text-to-video,720p,5.0,89,26.276599962002365,29.0771403791965,31.884095050001637,31.99869298603308,6.399738597206617,6.376819010000327,,,,0.1,0.1,0.1,0.0,0.1,0.5,0.5,model/remote/text_video/gemini_omni_1_1_flash/wavespeed.yaml,,,,1039.0,1189.0
26
- t2v,minimax_h3,MiniMax H3 (768p),xpcv2m58,p-video-2-0,wavespeed,minimax/h3/text-to-video,768p,5.0,89,97.61419671699696,106.57570995900022,117.51345164199664,124.8439018718094,24.968780374361877,23.50269032839933,,,,0.1,0.1,0.1,0.0,0.1,0.5,0.5,model/remote/text_video/minimax_h3/wavespeed.yaml,,,,1025.0,1103.0
27
- t2v,ltx_2_5_pro,LTX 2.5 Pro (720p),kjbgxbab,p-video-2-0,fal,lightricks/ltx-2.5/text-to-video/pro,720p,6.0,90,23.997383733993047,25.263995286799037,27.897931821993552,29.617955809731697,4.936325968288616,4.649655303665591,,,,0.12,0.12,0.12,0.0,0.12,0.72,0.6,model/remote/text_video/ltx_2_5_pro/fal.yaml,,,,1007.0,975.0
28
- t2v,grok_imagine_video_v1_5,Grok Imagine Video v1.5 (720p),z2fp7hd7,p-video-2-0,wavespeed,x-ai/grok-imagine-video-v1.5/text-to-video,720p,5.0,90,38.42492011199647,46.47850653079659,52.268091876499966,57.260012355522605,11.452002471104521,10.453618375299992,,,,0.14,0.14,0.14,0.0,0.14,0.7000000000000001,0.7000000000000001,model/remote/text_video/grok_imagine_video_v1_5/wavespeed.yaml,,,,961.0,1009.0
29
- t2v,seedance_2_5_turbo,Seedance 2.5 Turbo (720p),l9zjnv7n,p-video-2-0,wavespeed,bytedance/seedance-2.5/text-to-video-turbo,720p,5.0,90,168.997338743,211.93920676639829,252.07832621250054,338.04496873481105,67.60899374696221,50.41566524250011,,,,0.2,0.2,0.2,0.0,0.2,1.0,1.0,model/remote/text_video/seedance_2_5_turbo/wavespeed.yaml,,,,1038.0,1071.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/video-editing-leaderboard.csv DELETED
@@ -1,11 +0,0 @@
1
- model_id,display_name,elo,wandb_run_ids,n_generations,min_generation_s,median_generation_s,p20_generation_s,generation_s_per_output_video_s,predict_time_s_per_output_video_s,model_execution_time_s_per_output_video_s,price
2
- gemini_omni_flash_edit__fal,Gemini Omni Flash Edit,1054,3iuctwj9,56,32.574746752001374,58.2327566820004,50.44402900500063,13.78,,,0.13
3
- grok_imagine_video__replicate,Grok Imagine Video,974,q0ogvekx,59,31.640928319000523,43.75649321700257,32.88782280539963,11.04,,,0.05
4
- happyhorse_1_0__wavespeed,HappyHorse 1.0,1048,k4zj5wqk,71,106.5824136010051,201.2431439649954,141.46595527700265,46.73,,,0.14
5
- lucy_edit_pro__fal,Lucy Edit Pro,879,na6bz9xx,72,118.3459930579993,136.44442766549764,124.13885582720104,27.18,,,0.15
6
- minimax_h3_reference_to_video__fal,MiniMax H3 Reference-to-Video,1060,639xmakz,63,180.8385945170012,308.29198316100155,248.2394383729996,58.31,,,0.06
7
- p_video_edit_preview__replicate_final,P-Video-Edit,1000,m8irpsa6,73,31.41135125700021,86.86665409700072,57.21095684959946,23.18,17.99,12.06,0.045
8
- p_video_edit_preview__replicate_final__draft,P-Video-Edit Draft,994,6f88e6mx,73,23.04809326099712,42.9797806409988,33.19193872759861,11.48,11.28,4.46,0.025
9
- seedance_2_5_video_edit_turbo__wavespeed,Seedance 2.5 Video Edit Turbo,1063,2nr274vp,68,142.49452170499717,293.7401115540015,223.11569286320045,59.93,,,0.24
10
- wan_2_7_video_edit__wavespeed,Wan 2.7 Video Edit,1055,9lq803be,66,134.3744560209998,313.957433804002,219.2491260079987,68.04,,,0.2
11
-
 
 
 
 
 
 
 
 
 
 
 
 
data/video_editing_combined/generations.jsonl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:fb97166ea143a220c9395706627259755d0656534b3162712ecc619020b995db
3
- size 674713
 
 
 
 
data/video_editing_combined/prompts.jsonl DELETED
@@ -1,78 +0,0 @@
1
- {"prompt_id": "video_edit_internal__advertising__p0000", "text": "Replace the white bottle with an orange sunscreen bottle.", "dataset": "video_edit_internal", "category": "advertising", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/advertising/4620329ad65820ce.mp4"}
2
- {"prompt_id": "video_edit_internal__advertising__p0001", "text": "Replace the woman with an asian woman riding on a donkey through a chinese small town.", "dataset": "video_edit_internal", "category": "advertising", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/advertising/44db5689846be901.mp4"}
3
- {"prompt_id": "video_edit_internal__advertising__p0002", "text": "Place the couple on a snowy mountain next to a mountain hut.", "dataset": "video_edit_internal", "category": "advertising", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/advertising/481db4a047688bbe.mp4"}
4
- {"prompt_id": "video_edit_internal__advertising__p0003", "text": "Turn this into a scene in the summer with birds flying in the sky and butterflies in the foreground.", "dataset": "video_edit_internal", "category": "advertising", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/advertising/32b9f56763c56482.mp4"}
5
- {"prompt_id": "video_edit_internal__advertising__p0004", "text": "Replace the robot arm with a dancing hamster on a small table.", "dataset": "video_edit_internal", "category": "advertising", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/advertising/22d02ae2df7f9045.mp4"}
6
- {"prompt_id": "video_edit_internal__anonymization__p0000", "text": "Anonymize the womans face", "dataset": "video_edit_internal", "category": "anonymization", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/anonymization/7c410085f2fd939d.mp4"}
7
- {"prompt_id": "video_edit_internal__anonymization__p0001", "text": "Anonymize the mans face", "dataset": "video_edit_internal", "category": "anonymization", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/anonymization/7b495805c0c270ea.mp4"}
8
- {"prompt_id": "video_edit_internal__anonymization__p0002", "text": "Anonymize the mans face", "dataset": "video_edit_internal", "category": "anonymization", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/anonymization/736b6fb504bd32be.mp4"}
9
- {"prompt_id": "video_edit_internal__anonymization__p0003", "text": "Anonymize the girls face", "dataset": "video_edit_internal", "category": "anonymization", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/anonymization/2c82413d39579cd5.mp4"}
10
- {"prompt_id": "video_edit_internal__artificial_analysis__p0000", "text": "Change the rainforest setting to a neon-lit urban alley at night with steam from vents and wet reflective asphalt, and move into an ariel shot of the character after the initial camera movement to focus on the character", "dataset": "video_edit_internal", "category": "artificial_analysis", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/artificial_analysis/e2f6121269a206d3.mp4"}
11
- {"prompt_id": "video_edit_internal__artificial_analysis__p0001", "text": "Replace the magenta hover-car with a chrome-blue car, keeping the drift and neon light trails.", "dataset": "video_edit_internal", "category": "artificial_analysis", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/artificial_analysis/55d1baa7f3f71b26.mp4"}
12
- {"prompt_id": "video_edit_internal__artificial_analysis__p0002", "text": "Make the footage look like it was shot on a 1970s film camera, with grainy film texture, faded warm colors, slight softness, and slightly darker corners around the edges.", "dataset": "video_edit_internal", "category": "artificial_analysis", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/artificial_analysis/fd1ab436de020152.mp4"}
13
- {"prompt_id": "video_edit_internal__artificial_analysis__p0003", "text": "A person appears at the top of the waterfall, leaps into the lake below, and disappears into the misty water beneath the falls.", "dataset": "video_edit_internal", "category": "artificial_analysis", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/artificial_analysis/7ee1623303a8da68.mp4"}
14
- {"prompt_id": "video_edit_internal__artificial_analysis__p0004", "text": "A fluffy orange cat leaps gracefully from the floor onto the couch, paws sinking into the soft cushions. It circles once in place, tail swaying gently, before curling up tightly on one of the cushions and settling in comfortably.", "dataset": "video_edit_internal", "category": "artificial_analysis", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/artificial_analysis/9a73c608b343bbbe.mp4"}
15
- {"prompt_id": "video_edit_internal__camera_editing__p0000", "text": "Zoom in on the man's face to show his focused expression", "dataset": "video_edit_internal", "category": "camera_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/camera_editing/0336e64b0594bd7a.mp4"}
16
- {"prompt_id": "video_edit_internal__camera_editing__p0001", "text": "Perform an arc shot around the tram as it arrives at the station", "dataset": "video_edit_internal", "category": "camera_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/camera_editing/204aa93703da117b.mp4"}
17
- {"prompt_id": "video_edit_internal__camera_editing__p0002", "text": "Change the view to a high angle.", "dataset": "video_edit_internal", "category": "camera_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/camera_editing/c2ccb5351be5c718.mp4"}
18
- {"prompt_id": "video_edit_internal__camera_editing__p0003", "text": "Change the view to a high angle.", "dataset": "video_edit_internal", "category": "camera_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/camera_editing/b725aaded02d65e9.mp4"}
19
- {"prompt_id": "video_edit_internal__camera_editing__p0004", "text": "Gradually move the camera away from the doctor", "dataset": "video_edit_internal", "category": "camera_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/camera_editing/33f24f4d083df743.mp4"}
20
- {"prompt_id": "video_edit_internal__design_arena__p0000", "text": "Create a transition of the video of the product whihc is the jeans on the lady model with an atitiude that goes into a zoom out camera that she is in a party .Focus on the vibes", "dataset": "video_edit_internal", "category": "design_arena", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/design_arena/b0b4642272a481b1.mp4"}
21
- {"prompt_id": "video_edit_internal__design_arena__p0001", "text": "add ethnic urban women dancing at the bottem and at the bar wearing DMI Tshirts", "dataset": "video_edit_internal", "category": "design_arena", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/design_arena/0f730f98f3c51356.mp4"}
22
- {"prompt_id": "video_edit_internal__design_arena__p0002", "text": "Generate a commercial of this dog drinking beer at an electronic music party in a world where dogs and humans are mixed together.", "dataset": "video_edit_internal", "category": "design_arena", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/design_arena/575fc4b9b6d7b3ab.mp4"}
23
- {"prompt_id": "video_edit_internal__design_arena__p0003", "text": "everything is the same excpet the winter season, snowing", "dataset": "video_edit_internal", "category": "design_arena", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/design_arena/8674fd022867a736.mp4"}
24
- {"prompt_id": "video_edit_internal__design_arena__p0004", "text": "A cinematic character introduction of Jason, framed in a medium close-up with subtle camera movement, confident body language, and expressive facial detail. Moody, high-contrast lighting with a cool-toned color palette, shallow depth of field, and a slow dramatic reveal that builds intrigue over a few seconds. I want a video in a 9:16 aspect ratio for tiktok. remove all text and have him in a mid day campus setting", "dataset": "video_edit_internal", "category": "design_arena", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/design_arena/91873bbafe4173da.mp4"}
25
- {"prompt_id": "video_edit_internal__e_commerce__p0000", "text": "Remove the black blazer.", "dataset": "video_edit_internal", "category": "e_commerce", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/e_commerce/b89faaa5080c31db.mp4"}
26
- {"prompt_id": "video_edit_internal__e_commerce__p0001", "text": "Replace her skirt with a jeans skirt.", "dataset": "video_edit_internal", "category": "e_commerce", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/e_commerce/c34a33d07e843804.mp4"}
27
- {"prompt_id": "video_edit_internal__e_commerce__p0002", "text": "Replace the black leggings and the black shirt with a white dress.", "dataset": "video_edit_internal", "category": "e_commerce", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/e_commerce/489d2439cbaeed79.mp4"}
28
- {"prompt_id": "video_edit_internal__e_commerce__p0003", "text": "Replace the white woman with a lebanese-looking woman.", "dataset": "video_edit_internal", "category": "e_commerce", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/e_commerce/0ad8fb773f303a11.mp4"}
29
- {"prompt_id": "video_edit_internal__e_commerce__p0004", "text": "Remove all items on the table and place an eyeshadow pallete on the table next to the woman.", "dataset": "video_edit_internal", "category": "e_commerce", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/e_commerce/f28f3aa12b1ec220.mp4"}
30
- {"prompt_id": "video_edit_internal__lighting__p0000", "text": "After the sun sets behind the mountains, the scene transitions into nighttime.", "dataset": "video_edit_internal", "category": "lighting", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/lighting/229c165e0ac97daf.mp4"}
31
- {"prompt_id": "video_edit_internal__lighting__p0001", "text": "Change the weather to a dazzling starry night.", "dataset": "video_edit_internal", "category": "lighting", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/lighting/f42c41ab2f3adc26.mp4"}
32
- {"prompt_id": "video_edit_internal__lighting__p0002", "text": "Change the weather to a thunderstorm with heavy rain.", "dataset": "video_edit_internal", "category": "lighting", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/lighting/daa36567634ca6be.mp4"}
33
- {"prompt_id": "video_edit_internal__lighting__p0003", "text": "Change the weather to a torrential downpour.", "dataset": "video_edit_internal", "category": "lighting", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/lighting/6817a4142b69d602.mp4"}
34
- {"prompt_id": "video_edit_internal__lighting__p0004", "text": "Change the weather to a torrential downpour.", "dataset": "video_edit_internal", "category": "lighting", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/lighting/ac01488a685a1096.mp4"}
35
- {"prompt_id": "video_edit_internal__long__p0000", "text": "Change the weather to a dazzling starry night.", "dataset": "video_edit_internal", "category": "long", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/long/e9af2a7039e43f16.mp4"}
36
- {"prompt_id": "video_edit_internal__long__p0001", "text": "Adjust the color of book to blue", "dataset": "video_edit_internal", "category": "long", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/long/eab696d1555be316.mp4"}
37
- {"prompt_id": "video_edit_internal__long__p0002", "text": "Make the young woman turn into sand and blow away.", "dataset": "video_edit_internal", "category": "long", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/long/d18378f1d7e4ca0e.mp4"}
38
- {"prompt_id": "video_edit_internal__long__p0003", "text": "Make the bird flap its wings", "dataset": "video_edit_internal", "category": "long", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/long/3835b37b43f5e5bf.mp4"}
39
- {"prompt_id": "video_edit_internal__long__p0004", "text": "Transform the video into a ukiyo-e style", "dataset": "video_edit_internal", "category": "long", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/long/09fe5bb4b5304b66.mp4"}
40
- {"prompt_id": "video_edit_internal__movie_concept_art__p0000", "text": "Add more blood and wounds to the mans face.", "dataset": "video_edit_internal", "category": "movie_concept_art", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/movie_concept_art/1d1a99167475720b.mp4"}
41
- {"prompt_id": "video_edit_internal__movie_concept_art__p0001", "text": "Make the scene less dark.", "dataset": "video_edit_internal", "category": "movie_concept_art", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/movie_concept_art/10cb44d8c0bf4116.mp4"}
42
- {"prompt_id": "video_edit_internal__movie_concept_art__p0002", "text": "Replace the female warrior with a male warrior with ginger hair.", "dataset": "video_edit_internal", "category": "movie_concept_art", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/movie_concept_art/9e45454390c20b8a.mp4"}
43
- {"prompt_id": "video_edit_internal__movie_concept_art__p0003", "text": "Turn the man's hand into a robotic hand.", "dataset": "video_edit_internal", "category": "movie_concept_art", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/movie_concept_art/99977e7a91a950b4.mp4"}
44
- {"prompt_id": "video_edit_internal__real_estate__p0000", "text": "Replace the interior with a gold-black interior heavy luxury style.", "dataset": "video_edit_internal", "category": "real_estate", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/real_estate/869064ab06bb5daa.mp4"}
45
- {"prompt_id": "video_edit_internal__real_estate__p0001", "text": "Replace the grey wallpaper with a beige painted wall and turn the grey curtains a dark brown.", "dataset": "video_edit_internal", "category": "real_estate", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/real_estate/1c2f358bfe9b8299.mp4"}
46
- {"prompt_id": "video_edit_internal__real_estate__p0002", "text": "Remove all decoration from the walls and keep only the furniture.", "dataset": "video_edit_internal", "category": "real_estate", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/real_estate/2058bcf38389f8fe.mp4"}
47
- {"prompt_id": "video_edit_internal__real_estate__p0003", "text": "Exchange the wooden floor for a marble floor.", "dataset": "video_edit_internal", "category": "real_estate", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/real_estate/6a4c09a23dda57d9.mp4"}
48
- {"prompt_id": "video_edit_internal__real_estate__p0004", "text": "Replace the bedframe with a modern wooden bed.", "dataset": "video_edit_internal", "category": "real_estate", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/real_estate/3e0f6dc5df891001.mp4"}
49
- {"prompt_id": "video_edit_internal__style_transfer__p0000", "text": "Transform the video into a cyberpunk style", "dataset": "video_edit_internal", "category": "style_transfer", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/style_transfer/2253f6ed3674f006.mp4"}
50
- {"prompt_id": "video_edit_internal__style_transfer__p0001", "text": "Convert to different shades of orange", "dataset": "video_edit_internal", "category": "style_transfer", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/style_transfer/edb6a105be03bae0.mp4"}
51
- {"prompt_id": "video_edit_internal__style_transfer__p0002", "text": "Convert to black and white", "dataset": "video_edit_internal", "category": "style_transfer", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/style_transfer/c3dc058b3be26cbd.mp4"}
52
- {"prompt_id": "video_edit_internal__style_transfer__p0003", "text": "Apply Ghibli-style editing to the video", "dataset": "video_edit_internal", "category": "style_transfer", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/style_transfer/83a638223a20911c.mp4"}
53
- {"prompt_id": "video_edit_internal__style_transfer__p0004", "text": "Relight the scene as if it were shot during golden hour, with warm low-angle sunlight, soft shadows, and natural highlights on faces and surfaces.", "dataset": "video_edit_internal", "category": "style_transfer", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/style_transfer/daa36567634ca6be.mp4"}
54
- {"prompt_id": "video_edit_internal__subject_editing__p0000", "text": "Replace the rainbow colors of the logo with different shades of purple", "dataset": "video_edit_internal", "category": "subject_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_editing/6358f26b46baadf5.mp4"}
55
- {"prompt_id": "video_edit_internal__subject_editing__p0001", "text": "Add a small dog running beside the scooter", "dataset": "video_edit_internal", "category": "subject_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_editing/052c0bfd7b68fea7.mp4"}
56
- {"prompt_id": "video_edit_internal__subject_editing__p0002", "text": "Replace the splashing waves with a calm water surface", "dataset": "video_edit_internal", "category": "subject_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_editing/c3f79578a39f415d.mp4"}
57
- {"prompt_id": "video_edit_internal__subject_editing__p0003", "text": "Add a violinist in the background", "dataset": "video_edit_internal", "category": "subject_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_editing/a0eebf32a076e2fc.mp4"}
58
- {"prompt_id": "video_edit_internal__subject_editing__p0004", "text": "Add a group of people walking on the pathway", "dataset": "video_edit_internal", "category": "subject_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_editing/3c2b7e3a5b284e1d.mp4"}
59
- {"prompt_id": "video_edit_internal__subject_motion_editing__p0000", "text": "Make the bird hop around instead of walking and foraging", "dataset": "video_edit_internal", "category": "subject_motion_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_motion_editing/ac38b2a97d1a5c3a.mp4"}
60
- {"prompt_id": "video_edit_internal__subject_motion_editing__p0001", "text": "The male colleague is walking around to observe.", "dataset": "video_edit_internal", "category": "subject_motion_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_motion_editing/8aaab7d304c5ad99.mp4"}
61
- {"prompt_id": "video_edit_internal__subject_motion_editing__p0002", "text": "Make the static spider-man in the mural dynamic and make him swing faster", "dataset": "video_edit_internal", "category": "subject_motion_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_motion_editing/3412b39686fd5879.mp4"}
62
- {"prompt_id": "video_edit_internal__subject_motion_editing__p0003", "text": "Change the woman's jogging to taking off.", "dataset": "video_edit_internal", "category": "subject_motion_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_motion_editing/17c4dc0514772321.mp4"}
63
- {"prompt_id": "video_edit_internal__subject_motion_editing__p0004", "text": "Make the knight lunging forward and the creature swiping at the knight", "dataset": "video_edit_internal", "category": "subject_motion_editing", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/subject_motion_editing/980354550011911b.mp4"}
64
- {"prompt_id": "video_edit_internal__synthetic_data__p0000", "text": "Turn the scene into nighttime.", "dataset": "video_edit_internal", "category": "synthetic_data", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/synthetic_data/e3b1e603bfaa1aec.mp4"}
65
- {"prompt_id": "video_edit_internal__synthetic_data__p0001", "text": "Remove the crosswalk.", "dataset": "video_edit_internal", "category": "synthetic_data", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/synthetic_data/30df5fd5fe28af65.mp4"}
66
- {"prompt_id": "video_edit_internal__synthetic_data__p0002", "text": "Add a bicycle riding in front of the car.", "dataset": "video_edit_internal", "category": "synthetic_data", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/synthetic_data/d093491e25682b3a.mp4"}
67
- {"prompt_id": "video_edit_internal__synthetic_data__p0003", "text": "Turn the scene into a snowstorm scene.", "dataset": "video_edit_internal", "category": "synthetic_data", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/synthetic_data/1da5913f13362f8d.mp4"}
68
- {"prompt_id": "video_edit_internal__synthetic_data__p0004", "text": "Make it rain in the scene.", "dataset": "video_edit_internal", "category": "synthetic_data", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/synthetic_data/936bdb89558f5a7f.mp4"}
69
- {"prompt_id": "video_edit_internal__text__p0000", "text": "Add the text \"True Love\" in the foreground in pink romantic font.", "dataset": "video_edit_internal", "category": "text", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/text/c763407793ca9b0e.mp4"}
70
- {"prompt_id": "video_edit_internal__text__p0001", "text": "Replace any mention of \"Fanta\" with the branding \"Cola\".", "dataset": "video_edit_internal", "category": "text", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/text/7b878ea6d99834b2.mp4"}
71
- {"prompt_id": "video_edit_internal__text__p0002", "text": "Remove all text from the video.", "dataset": "video_edit_internal", "category": "text", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/text/76763c31b2609109.mp4"}
72
- {"prompt_id": "video_edit_internal__text__p0003", "text": "Replace the branding \"Royalty\" with the phrasing \"Princess\".", "dataset": "video_edit_internal", "category": "text", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/text/d221d299c9e49064.mp4"}
73
- {"prompt_id": "video_edit_internal__text__p0004", "text": "Remove all text from the video.", "dataset": "video_edit_internal", "category": "text", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/text/5c169901af8e4ed6.mp4"}
74
- {"prompt_id": "video_edit_internal__transitions__p0000", "text": "After a black screen transition, the road transforms into lush grass.", "dataset": "video_edit_internal", "category": "transitions", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/transitions/964c35b19ee1fc1f.mp4"}
75
- {"prompt_id": "video_edit_internal__transitions__p0001", "text": "After a wave-foam transition, the small fishing boat is eaten by a giant whale.", "dataset": "video_edit_internal", "category": "transitions", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/transitions/b8b88f43316363f3.mp4"}
76
- {"prompt_id": "video_edit_internal__transitions__p0002", "text": "Add a cut transition, then show a bowl of ramen topped with parsley.", "dataset": "video_edit_internal", "category": "transitions", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/transitions/c823d6c77bdc87f4.mp4"}
77
- {"prompt_id": "video_edit_internal__transitions__p0003", "text": "Add a smoke transition, then show the circuit board burning.", "dataset": "video_edit_internal", "category": "transitions", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/transitions/edb9927ff06c1175.mp4"}
78
- {"prompt_id": "video_edit_internal__transitions__p0004", "text": "After a smoke transition, the Basilica of the Sacred Heart of Paris catches fire.", "dataset": "video_edit_internal", "category": "transitions", "source_video": "https://d2j1a65dna040x.cloudfront.net/benchmark_inputs/video_edit_internal/transitions/77bb900383d4f370.mp4"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/video_generation_combined/generations.jsonl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:149714ae8c73bf2832fd8b9ac2fbdde069971b9f5cf90e8ac2725f051d805b59
3
- size 970689
 
 
 
 
data/video_generation_combined/prompts.jsonl DELETED
@@ -1,90 +0,0 @@
1
- {"prompt_id": "v-bench2__all__p0000", "text": "Garden, zoom in.", "dataset": "v-bench2", "category": "all"}
2
- {"prompt_id": "v-bench2__all__p0001", "text": "Garden, zoom out.", "dataset": "v-bench2", "category": "all"}
3
- {"prompt_id": "v-bench2__all__p0002", "text": "Garden, tilt up.", "dataset": "v-bench2", "category": "all"}
4
- {"prompt_id": "v-bench2__all__p0003", "text": "The camera starts at the top of the forest, where thick morning mist drifts between the treetops, with sunlight filtering through the leaves and casting dappled spots of light, the air fresh and moist. As the camera slowly moves downward, dewdrops glisten on the leaves, a gentle breeze rustling the leaves, making a soft, soothing sound. The camera moves along a woodland path, occasionally capturing a squirrel leaping between trees, its agile figure darting across the branches. The shot continues, eventually arriving at a tranquil lake. The surface of the water is like a mirror, reflecting the towering trees and distant mountains. In the distance, a heron takes off from the lakeshore, breaking the stillness of the water, ripples forming as the bird skims the surface. The camera follows its flight and gradually pulls back, showing the entire serene beauty of the lake.", "dataset": "v-bench2", "category": "all"}
5
- {"prompt_id": "v-bench2__all__p0004", "text": "The scene opens in the vast desert, with the camera angled low over the sand, fine grains drifting in the gentle breeze, the undulating dunes in the distance bathed in a faint orange glow. As the camera moves forward, the outlines of the dunes become clearer, and the early morning sky begins to glow with warm hues, transitioning the desert from deep brown to golden yellow. The scene cuts to the top of a dune, where the camera follows a caravan of camels making their way across the endless desert, their bells jingling softly in the wind. The first rays of the sun break through the gaps between the dunes, casting golden light on the sand, as the desert comes to life, glowing in the morning's embrace. Finally, the camera pulls back, revealing the vast expanse of the desert merging with the horizon, the sun climbing higher, illuminating the entire landscape in a mystical, warm glow.", "dataset": "v-bench2", "category": "all"}
6
- {"prompt_id": "v-bench2__all__p0005", "text": "The camera begins in a vast grassland, where the lush green grass sways gently in the breeze, the air fresh, and the soft rustling of the leaves fills the space. As the camera moves forward, the grass turns from a vibrant green to golden hues, sunlight pouring over the land, the textures of the grass becoming more pronounced in the play of light and shadow. In the distance, a herd of cattle grazes peacefully. Their figures become clearer as the camera moves closer, occasionally lifting their heads and gazing into the distance. The scene shifts to a lakeshore, where the lake reflects the sky, grasslands, and distant mountains, the water clear and calm, with gentle ripples created by the breeze. Finally, the camera pulls back, following the herd as they move off into the distance, the vastness of the grassland merging with the expansive sky, creating a feeling of peaceful openness.", "dataset": "v-bench2", "category": "all"}
7
- {"prompt_id": "v-bench2__all__p0006", "text": "The camera starts at a tranquil coastline, where the waves gently crash against the rocks, the salty sea breeze fills the air, and the atmosphere feels fresh and alive. As the camera moves forward, the surface of the water glistens with golden light from the setting sun, the sound of the waves becoming more distinct as the tide retreats, revealing a moist sandy shore. The scene shifts to the beach, where a few seagulls peck at the sand, occasionally flying up and breaking the stillness of the sky. The sun slowly sinks below the horizon, painting the sky in vibrant shades of orange and red, as the golden light on the water fades, and the waves begin to intensify. Finally, the camera pulls back, and the entire coastline fades into twilight, with the sea and sky blending together in a serene, solitary embrace.", "dataset": "v-bench2", "category": "all"}
8
- {"prompt_id": "v-bench2__all__p0007", "text": "The race began, and the first runner quickly took off, leading the other teams. Everyone was focused on his performance. During the baton handoff of the first runner, Team A made a slight mistake, and the baton nearly fell. Despite this, the runner quickly passed it to the second runner. The second runner showed great determination and chased hard, finally overtaking Team B on the bend. However, due to the earlier mistake, Team A's lead was not significant. During the third runner's handoff, the runner from Team A nervously accelerated and managed to maintain the lead, but Team C quickly caught up thanks to their excellent pace control. During the fourth runner's handoff, the final sprint became crucial. The Team A runner started to accelerate in the second-to-last turn and, with a burst of strength, successfully widened the gap, steadily running toward the finish line and winning the race.", "dataset": "v-bench2", "category": "all"}
9
- {"prompt_id": "v-bench2__all__p0008", "text": "The match began, and Team A quickly organized an attack, breaking through Team B's defense with fast passes. The forward accurately kicked the ball into the goal, taking a 1-0 lead. Team B did not panic; they used a long pass to quickly counterattack. The forward calmly shot past the goalkeeper, and the ball went straight into the net, making it 1-1. At this point, the game entered a stalemate. Both teams' defenses were solid, and the match became a fierce battle. In the second half, Team A had a corner kick. The high ball delivered by the player was headed in by the center-back who jumped high, putting Team A in the lead at 2-1. In the final moments of the game, Team B got a penalty kick. The forward took the shot without hesitation, sending the ball into the net to make it 2-2. Finally, in the last moments of extra time, Team A used a quick counterattack and a long-range shot from outside the box flew straight into the corner, securing the win with a 3-2 score.", "dataset": "v-bench2", "category": "all"}
10
- {"prompt_id": "v-bench2__all__p0009", "text": "The race began, and all the runners sprinted quickly. The runner from Team A quickly took the lead. After a period of steady running, the runners from Team A and Team B gradually created a gap, almost running shoulder to shoulder. However, at the 25 km mark, the runner from Team A suddenly began to feel unwell, slowing down noticeably. The runner from Team B seized the opportunity and caught up, eventually overtaking Team A to take the lead at the 30 km mark. As the race entered the second half, the Team A runner gave it their all, regained their rhythm, and caught up with Team B at the 35 km mark. The two were neck and neck in the final sprint, and with only 200 meters remaining, the Team A runner pushed through with determination and accelerated to cross the finish line first by a narrow margin, winning the tough race.", "dataset": "v-bench2", "category": "all"}
11
- {"prompt_id": "v-bench2__all__p0010", "text": "The race began, and the runners quickly started. The Team A runner took the lead initially due to a powerful start. However, the Team B runner did not rush to chase but instead steadily adjusted their pace, ensuring they had more energy for the latter part of the race. By the third lap, the Team A runner began to tire, and the Team B runner gradually reduced the gap, eventually overtaking Team A in the fourth lap. The Team C runner, meanwhile, began to accelerate, and in the last two laps, with strong willpower, they overtook Team B and moved into the lead. In the final sprint, the Team A runner gritted their teeth and tried to close the gap, but with only 50 meters left, the Team C runner exploded with speed, crossing the finish line with a clear lead and winning the race.", "dataset": "v-bench2", "category": "all"}
12
- {"prompt_id": "v-bench2__all__p0011", "text": "The match began, and Team A quickly found their rhythm. A series of fast attacks put pressure on Team B’s defense. Team A's forward made two three-pointers, quickly increasing the lead. After the first quarter, Team B adjusted their tactics, strengthened their defense, and gradually started to counterattack, narrowing the gap. In the third quarter, Team A’s key player was injured and forced to leave the game. Team B took advantage of this by speeding up their attacks, overtaking the score. In the fourth quarter, Team A's bench players caught up with a series of fast breaks, and in the final moments, a player from Team A calmly made a game-winning three-pointer from beyond the arc, securing a narrow 1-point victory.", "dataset": "v-bench2", "category": "all"}
13
- {"prompt_id": "v-bench2__all__p0012", "text": "The match began, and Team A quickly gained the upper hand with several precise kills, taking a 11-6 lead. The Team B player stayed calm and gradually adjusted, finding ways to respond. In the second set, Team B improved their serving quality, scoring several powerful smashes to win a set, leveling the score at 1-1. In the deciding set, the Team A player showed signs of fatigue, but with precise net control and quick reflexes, they pulled ahead. In the crucial final point, a lightning-fast smash left Team B with no chance to return, and Team A won the match 21-19.", "dataset": "v-bench2", "category": "all"}
14
- {"prompt_id": "v-bench2__all__p0013", "text": "A lion with the wings of an eagle, soaring through the sky with majestic ease.", "dataset": "v-bench2", "category": "all"}
15
- {"prompt_id": "v-bench2__all__p0014", "text": "A giraffe with the scales of a fish, able to glide smoothly through the water.", "dataset": "v-bench2", "category": "all"}
16
- {"prompt_id": "v-bench2__all__p0015", "text": "A wolf with the body of a horse, galloping across a vast plains with wild abandon.", "dataset": "v-bench2", "category": "all"}
17
- {"prompt_id": "v-bench2__all__p0016", "text": "A bear with the antlers of a deer, roaming the forest with a regal presence.", "dataset": "v-bench2", "category": "all"}
18
- {"prompt_id": "v-bench2__all__p0017", "text": "A cheetah with the shell of a tortoise, moving quickly but with a protective outer layer.", "dataset": "v-bench2", "category": "all"}
19
- {"prompt_id": "v-bench2__all__p0018", "text": "A wooden toy is placed gently on the surface of a small bowl of water.", "dataset": "v-bench2", "category": "all"}
20
- {"prompt_id": "v-bench2__all__p0019", "text": "A river changes from blue to brown.", "dataset": "v-bench2", "category": "all"}
21
- {"prompt_id": "v-bench2__all__p0020", "text": "The leaves gradually change from red to green.", "dataset": "v-bench2", "category": "all"}
22
- {"prompt_id": "v-bench2__all__p0021", "text": "A river changes from brown to blue.", "dataset": "v-bench2", "category": "all"}
23
- {"prompt_id": "v-bench2__all__p0022", "text": "A car changes from white to red.", "dataset": "v-bench2", "category": "all"}
24
- {"prompt_id": "v-bench2__all__p0023", "text": "A car changes from red to white.", "dataset": "v-bench2", "category": "all"}
25
- {"prompt_id": "v-bench2__all__p0024", "text": "A dog is on the left of a table, then the dog runs to the front of the table.", "dataset": "v-bench2", "category": "all"}
26
- {"prompt_id": "v-bench2__all__p0025", "text": "A dog is on the left of a sofa, then the dog runs to the front of the sofa.", "dataset": "v-bench2", "category": "all"}
27
- {"prompt_id": "v-bench2__all__p0026", "text": "A dog is on the right of a table, then the dog runs to the left of the table.", "dataset": "v-bench2", "category": "all"}
28
- {"prompt_id": "v-bench2__all__p0027", "text": "A dog is on the right of a sofa, then the dog runs to the front of the sofa.", "dataset": "v-bench2", "category": "all"}
29
- {"prompt_id": "v-bench2__all__p0028", "text": "A dog is on the right of a rock, then the dog runs to the left of the rock.", "dataset": "v-bench2", "category": "all"}
30
- {"prompt_id": "v-bench2__all__p0029", "text": "A dog is behind a chair, then the dog runs to the right of the chair.", "dataset": "v-bench2", "category": "all"}
31
- {"prompt_id": "v-bench2__all__p0030", "text": "A man is doing yoga.", "dataset": "v-bench2", "category": "all"}
32
- {"prompt_id": "v-bench2__all__p0031", "text": "A woman is doing yoga.", "dataset": "v-bench2", "category": "all"}
33
- {"prompt_id": "v-bench2__all__p0032", "text": "people are doing yoga.", "dataset": "v-bench2", "category": "all"}
34
- {"prompt_id": "v-bench2__all__p0033", "text": "A man is running.", "dataset": "v-bench2", "category": "all"}
35
- {"prompt_id": "v-bench2__all__p0034", "text": "A woman is running.", "dataset": "v-bench2", "category": "all"}
36
- {"prompt_id": "v-bench2__all__p0035", "text": "people are running.", "dataset": "v-bench2", "category": "all"}
37
- {"prompt_id": "v-bench2__all__p0036", "text": "A man is walking.", "dataset": "v-bench2", "category": "all"}
38
- {"prompt_id": "v-bench2__all__p0037", "text": "A woman is walking.", "dataset": "v-bench2", "category": "all"}
39
- {"prompt_id": "v-bench2__all__p0038", "text": "people are walking.", "dataset": "v-bench2", "category": "all"}
40
- {"prompt_id": "v-bench2__all__p0039", "text": "A man is dancing.", "dataset": "v-bench2", "category": "all"}
41
- {"prompt_id": "v-bench2__all__p0040", "text": "A woman is dancing.", "dataset": "v-bench2", "category": "all"}
42
- {"prompt_id": "v-bench2__all__p0041", "text": "A man is playing basketball.", "dataset": "v-bench2", "category": "all"}
43
- {"prompt_id": "v-bench2__all__p0042", "text": "A woman is playing basketball.", "dataset": "v-bench2", "category": "all"}
44
- {"prompt_id": "v-bench2__all__p0043", "text": "One person hands a cup of water to another.", "dataset": "v-bench2", "category": "all"}
45
- {"prompt_id": "v-bench2__all__p0044", "text": "One person passes a ball to another.", "dataset": "v-bench2", "category": "all"}
46
- {"prompt_id": "v-bench2__all__p0045", "text": "Two people shake hands.", "dataset": "v-bench2", "category": "all"}
47
- {"prompt_id": "v-bench2__all__p0046", "text": "One person ties the shoelaces of another person.", "dataset": "v-bench2", "category": "all"}
48
- {"prompt_id": "v-bench2__all__p0047", "text": "One person opens the door for another person.", "dataset": "v-bench2", "category": "all"}
49
- {"prompt_id": "v-bench2__all__p0048", "text": "Two people exchange a book.", "dataset": "v-bench2", "category": "all"}
50
- {"prompt_id": "v-bench2__all__p0049", "text": "One person puts a coat on another person.", "dataset": "v-bench2", "category": "all"}
51
- {"prompt_id": "v-bench2__all__p0050", "text": "One person places a chair for another to sit in.", "dataset": "v-bench2", "category": "all"}
52
- {"prompt_id": "v-bench2__all__p0051", "text": "An orange dog is running.", "dataset": "v-bench2", "category": "all"}
53
- {"prompt_id": "v-bench2__all__p0052", "text": "Two orange dogs are running.", "dataset": "v-bench2", "category": "all"}
54
- {"prompt_id": "v-bench2__all__p0053", "text": "A brown dog is on the left of an apple, then the dog moves to the right of the apple.", "dataset": "v-bench2", "category": "all"}
55
- {"prompt_id": "v-bench2__all__p0054", "text": "An orange cat is running.", "dataset": "v-bench2", "category": "all"}
56
- {"prompt_id": "v-bench2__all__p0055", "text": "Equal amounts of yellow and blue paint are rapidly combined, with the mixture being vigorously stirred until fully blended.", "dataset": "v-bench2", "category": "all"}
57
- {"prompt_id": "v-bench2__all__p0056", "text": "Equal amounts of black and white paint are rapidly combined, with the mixture being vigorously stirred until fully blended.", "dataset": "v-bench2", "category": "all"}
58
- {"prompt_id": "v-bench2__all__p0057", "text": "Equal amounts of white and black paint are rapidly combined, with the mixture being vigorously stirred until fully blended.", "dataset": "v-bench2", "category": "all"}
59
- {"prompt_id": "v-bench2__all__p0058", "text": "Equal amounts of red and purple paint are rapidly combined, with the mixture being vigorously stirred until fully blended.", "dataset": "v-bench2", "category": "all"}
60
- {"prompt_id": "v-bench2__all__p0059", "text": "A bowl of soup is tilted in the space station, with the liquid slowly spreading in all directions.", "dataset": "v-bench2", "category": "all"}
61
- {"prompt_id": "v-bench2__all__p0060", "text": "A jar of peanut butter is opened in the space station, with the viscous liquid slowly dispersing.", "dataset": "v-bench2", "category": "all"}
62
- {"prompt_id": "v-bench2__all__p0061", "text": "A container of cream is opened in the space station, with the liquid slowly dispersing into the air.", "dataset": "v-bench2", "category": "all"}
63
- {"prompt_id": "v-bench2__all__p0062", "text": "A cup of tea is carefully tilted in the space station, and the liquid floats in various directions.", "dataset": "v-bench2", "category": "all"}
64
- {"prompt_id": "v-bench2__all__p0063", "text": "A bottle of ketchup is gently squeezed in the space station, with the thick liquid spreading into the environment.", "dataset": "v-bench2", "category": "all"}
65
- {"prompt_id": "v-bench2__all__p0064", "text": "A bottle of water is opened in the space station, and the water starts to float out in irregular shapes.", "dataset": "v-bench2", "category": "all"}
66
- {"prompt_id": "v-bench2__all__p0065", "text": "A person is sitting on the couch, then suddenly they get up and start sweeping the floor.", "dataset": "v-bench2", "category": "all"}
67
- {"prompt_id": "v-bench2__all__p0066", "text": "A dog is playing with a ball, then it suddenly starts lying down on the carpet.", "dataset": "v-bench2", "category": "all"}
68
- {"prompt_id": "v-bench2__all__p0067", "text": "A person is cooking dinner, then they suddenly start organizing the pantry.", "dataset": "v-bench2", "category": "all"}
69
- {"prompt_id": "v-bench2__all__p0068", "text": "A cat is watching birds through the window, then it suddenly starts grooming itself.", "dataset": "v-bench2", "category": "all"}
70
- {"prompt_id": "v-bench2__all__p0069", "text": "A person is typing on a keyboard, then they suddenly get up and start making the bed.", "dataset": "v-bench2", "category": "all"}
71
- {"prompt_id": "v-bench2__all__p0070", "text": "A horse is trotting in the field, then it suddenly starts drinking from a stream.", "dataset": "v-bench2", "category": "all"}
72
- {"prompt_id": "v-bench2__all__p0071", "text": "A person is drinking a glass of water, then they suddenly start cleaning the windows.", "dataset": "v-bench2", "category": "all"}
73
- {"prompt_id": "v-bench2__all__p0072", "text": "A dog is sitting in the yard, then it suddenly starts running in circles.", "dataset": "v-bench2", "category": "all"}
74
- {"prompt_id": "v-bench2__all__p0073", "text": "A person is slurping noodles from a steaming bowl.", "dataset": "v-bench2", "category": "all"}
75
- {"prompt_id": "v-bench2__all__p0074", "text": "A person is eating hamburger.", "dataset": "v-bench2", "category": "all"}
76
- {"prompt_id": "v-bench2__all__p0075", "text": "A person is eating ice cream.", "dataset": "v-bench2", "category": "all"}
77
- {"prompt_id": "v-bench2__all__p0076", "text": "A person is drinking coffee from a cup.", "dataset": "v-bench2", "category": "all"}
78
- {"prompt_id": "v-bench2__all__p0077", "text": "A person is spreading butter on toast.", "dataset": "v-bench2", "category": "all"}
79
- {"prompt_id": "v-bench2__all__p0078", "text": "A person is eating spaghetti with a fork.", "dataset": "v-bench2", "category": "all"}
80
- {"prompt_id": "v-bench2__all__p0079", "text": "A person is biting into an apple.", "dataset": "v-bench2", "category": "all"}
81
- {"prompt_id": "v-bench2__all__p0080", "text": "A person is peeling a banana.", "dataset": "v-bench2", "category": "all"}
82
- {"prompt_id": "v-bench2__all__p0081", "text": "The camera orbits around. Castle, the camera circles around.", "dataset": "v-bench2", "category": "all"}
83
- {"prompt_id": "v-bench2__all__p0082", "text": "The camera orbits around. Volcano, the camera circles around.", "dataset": "v-bench2", "category": "all"}
84
- {"prompt_id": "v-bench2__all__p0083", "text": "The camera orbits around. Statue, the camera circles around.", "dataset": "v-bench2", "category": "all"}
85
- {"prompt_id": "v-bench2__all__p0084", "text": "The camera orbits around. Clock Tower, the camera circles around.", "dataset": "v-bench2", "category": "all"}
86
- {"prompt_id": "v-bench2__all__p0085", "text": "The camera orbits around. Playground, the camera circles around.", "dataset": "v-bench2", "category": "all"}
87
- {"prompt_id": "v-bench2__all__p0086", "text": "A timelapse captures the transformation of water in an untextured bottle as the temperature significantly drops below 0°C.", "dataset": "v-bench2", "category": "all"}
88
- {"prompt_id": "v-bench2__all__p0087", "text": "A timelapse captures the transformation of a river as the temperature significantly drops below 0°C.", "dataset": "v-bench2", "category": "all"}
89
- {"prompt_id": "v-bench2__all__p0088", "text": "A timelapse captures the transformation of juice in an untextured bottle as the temperature significantly drops below 0°C.", "dataset": "v-bench2", "category": "all"}
90
- {"prompt_id": "v-bench2__all__p0089", "text": "A timelapse captures the transformation of milk in an untextured bottle as the temperature significantly drops below 0°C.", "dataset": "v-bench2", "category": "all"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model_display.py CHANGED
@@ -87,34 +87,6 @@ MODEL_DISPLAY_NAMES = {
87
  "p_image_2_ideogram_high_1k": "P-Image-Ideogram High 1K",
88
  "p_image_2_ideogram_high_2k": "P-Image-Ideogram High 2K",
89
  "P-Image-Ideogram (High)": "P-Image-Ideogram High",
90
- "p_image_2_ideogram_very_high_1k": "P-Image-Ideogram Very High 1K",
91
- # P-Video-Edit
92
- "P-Video-Edit": "P-Video-Edit",
93
- "P-Video-Edit Draft": "P-Video-Edit Draft",
94
- "P-Video Edit Final": "P-Video-Edit",
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
- "ltx_2_5_fast": "LTX 2.5 Fast",
100
- "ltx_2_5_pro": "LTX 2.5 Pro",
101
- "gemini_omni_1_1_flash": "Gemini Omni 1.1 Flash",
102
- "grok_imagine_video": "Grok Imagine Video",
103
- "grok_imagine_video_v1_5": "Grok Imagine Video 1.5",
104
- "minimax_h3": "MiniMax H3",
105
- "minimax_h3_max": "MiniMax H3 Max",
106
- "minimax_h3_max_turbo": "MiniMax H3 Max Turbo",
107
- "minimax_h3_max_turbo__prompt_expansion_mode_balanced": "MiniMax H3 Max Turbo",
108
- "seedance_2_5_turbo": "Seedance 2.5 Turbo",
109
- "veo_3_1_lite": "Veo 3.1 Lite",
110
- # Video-to-video leaderboard
111
- "gemini_omni_flash_edit__fal": "Gemini Omni Flash Edit",
112
- "grok_imagine_video__replicate": "Grok Imagine Video",
113
- "happyhorse_1_0__wavespeed": "HappyHorse 1.0",
114
- "lucy_edit_pro__fal": "Lucy Edit Pro",
115
- "minimax_h3_reference_to_video__fal": "MiniMax H3 Reference-to-Video",
116
- "seedance_2_5_video_edit_turbo__wavespeed": "Seedance 2.5 Video Edit Turbo",
117
- "wan_2_7_video_edit__wavespeed": "Wan 2.7 Video Edit",
118
  # Others overlapping P-Bench
119
  "z_image": "Z-Image",
120
  "glm_image": "GLM-Image",
@@ -212,60 +184,6 @@ MODEL_DISPLAY_NAMES = {
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 _video_variant_display_name(model_id: str):
245
- """Keep Pro settings and resolution-specific comparison models distinct."""
246
- parts = model_id.split("__")
247
- base = parts[0]
248
- if base in {"p_video_2_pro", "p-video-2-pro"}:
249
- label = "P-Video-2 Pro"
250
- elif base.startswith("minimax_") and any(
251
- part.startswith("resolution_") for part in parts[1:]
252
- ):
253
- label = display_model_name(base)
254
- else:
255
- return None
256
-
257
- for part in parts[1:]:
258
- if part.startswith("mode_"):
259
- label += " " + part[len("mode_") :].capitalize()
260
- elif part.startswith("prompt_upsampler_"):
261
- label += " (upsampler " + part[len("prompt_upsampler_") :] + ")"
262
- elif part.startswith("prompt_expansion_mode_"):
263
- label += " (expansion " + part[len("prompt_expansion_mode_") :] + ")"
264
- elif part.startswith("resolution_"):
265
- label += " " + part[len("resolution_") :]
266
- return label
267
-
268
-
269
  def _prettify_snake_case(model_id: str) -> str:
270
  parts = [part for part in str(model_id).split("_") if part]
271
  pretty = []
@@ -290,13 +208,7 @@ def display_model_name(model_id) -> str:
290
  return ""
291
  if raw in MODEL_DISPLAY_NAMES:
292
  return MODEL_DISPLAY_NAMES[raw]
293
- video_variant = _video_variant_display_name(raw)
294
- if video_variant:
295
- return video_variant
296
- p_video_2 = _p_video_2_display_name(raw)
297
- if p_video_2:
298
- return p_video_2
299
  # Already a human label (spaces / punctuation) — keep as-is.
300
- if re.search(r"[\s.\[\]()-]", raw):
301
  return raw
302
  return _prettify_snake_case(raw)
 
87
  "p_image_2_ideogram_high_1k": "P-Image-Ideogram High 1K",
88
  "p_image_2_ideogram_high_2k": "P-Image-Ideogram High 2K",
89
  "P-Image-Ideogram (High)": "P-Image-Ideogram High",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  # Others overlapping P-Bench
91
  "z_image": "Z-Image",
92
  "glm_image": "GLM-Image",
 
184
  }
185
 
186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  def _prettify_snake_case(model_id: str) -> str:
188
  parts = [part for part in str(model_id).split("_") if part]
189
  pretty = []
 
208
  return ""
209
  if raw in MODEL_DISPLAY_NAMES:
210
  return MODEL_DISPLAY_NAMES[raw]
 
 
 
 
 
 
211
  # Already a human label (spaces / punctuation) — keep as-is.
212
+ if re.search(r"[\s.\[\]()]", raw):
213
  return raw
214
  return _prettify_snake_case(raw)
ui.py CHANGED
@@ -1,5 +1,4 @@
1
  from html import escape
2
- from math import ceil, floor, log10
3
  from pathlib import Path
4
  import base64
5
  import random
@@ -25,45 +24,13 @@ MAX_COMPARE_PROMPTS = 8
25
  MAX_PARETO_METRICS = 8
26
  _PARETO_SLOT_COUNT = 1 + MAX_PARETO_METRICS * 8
27
  _PARETO_PRICE_COLUMN = "Price / Image (USD)"
28
- _PARETO_VIDEO_PRICE_COLUMN = "Price / Second of Video (USD)"
29
- _PARETO_PRICE_COLUMNS = (_PARETO_PRICE_COLUMN, _PARETO_VIDEO_PRICE_COLUMN)
30
  _PARETO_TIME_COLUMN = "Min Generation Time (s)"
31
- _PARETO_VIDEO_TIME_COLUMN = "Pareto Time / Output Video Second (s)"
32
- _PARETO_TIME_COLUMNS = (_PARETO_VIDEO_TIME_COLUMN, _PARETO_TIME_COLUMN)
33
- _PARETO_PRICE_TITLES = {
34
- _PARETO_PRICE_COLUMN: "Price per image (USD)",
35
- _PARETO_VIDEO_PRICE_COLUMN: "Price per second of video (USD)",
36
- }
37
- _PARETO_TIME_TITLES = {
38
- _PARETO_TIME_COLUMN: "Min generation time (s)",
39
- _PARETO_VIDEO_TIME_COLUMN: "Generation time per second of video",
40
- }
41
- _PARETO_SCALE_CHOICES = [
42
- ("Log", "Logarithmic"),
43
- ("Linear", "Linear"),
44
- ]
45
- _PARETO_SCALE_VALUES = {value for _, value in _PARETO_SCALE_CHOICES}
46
- _PARETO_SCALE_DEFAULT = "Logarithmic"
47
- _PARETO_PRUNA_COLOR = "#c084fc"
48
- _PARETO_OTHER_COLOR = "#9aa3b5"
49
- _PARETO_FRONTIER_OUTLINE = "#3fa87e"
50
 
51
  TAB_LEADERBOARDS = "leaderboards"
52
  TAB_PARETO = "pareto"
53
  TAB_SAMPLES = "samples"
54
  TAB_ABOUT = "about"
55
 
56
- MODALITY_TEXT_TO_VIDEO = "text_to_video"
57
- MODALITY_IMAGE_TO_VIDEO = "image_to_video"
58
- MODALITY_VIDEO_TO_VIDEO = "video_to_video"
59
- MODALITY_TEXT_TO_IMAGE = "text_to_image"
60
- MODALITY_CHOICES = [
61
- ("Text to Video", MODALITY_TEXT_TO_VIDEO),
62
- ("Image to Video", MODALITY_IMAGE_TO_VIDEO),
63
- ("Video to Video", MODALITY_VIDEO_TO_VIDEO),
64
- ("Text to Image", MODALITY_TEXT_TO_IMAGE),
65
- ]
66
-
67
  _MODEL_CHOICES_CACHE = {}
68
  _VIEW_EVENTS = {
69
  "show_progress": "hidden",
@@ -75,24 +42,21 @@ _VIEW_EVENTS = {
75
  ABOUT_OVERVIEW_CONTENT = """
76
  # About P-Bench
77
 
78
- P-Bench compares **text-to-video**, **image-to-video**, **video-to-video**, and **text-to-image**
79
- models, including optimized or accelerated endpoints, on **quality, speed,
80
- and price**. Each view is a **dataset** scored with a **metric**, written as
81
- `Dataset | Metric`. There is no single score across P-Bench.
82
 
83
  ## How to read it
84
 
85
- 1. Pick a **model type** (Text to Video, Image to Video, Video to Video, or Text to Image),
86
- then a **dataset** and a **metric**.
87
  2. **Leaderboards**: ranked by that metric. Price and generation time sit in
88
  the same table when the source publishes them.
89
  3. **Pareto plots**: mark models that are not beaten on both higher score
90
  and lower price (or time). Only datasets with price or generation time
91
  can open this tab (not Arena AI).
92
  4. **Samples**: the same prompts, side by side. Only for datasets we
93
- generated (VBench-2.0 Dataset, Qwen Image Dataset, OneIG Alignment
94
- Dataset, and the Pruna Internal Video-Edit Benchmark). Video-edit
95
- samples show the source clip first, then each model's edit.
96
 
97
  ## How a score is made
98
 
@@ -111,35 +75,6 @@ prompt suites, so samples are not shown.
111
 
112
  ## Current datasets
113
 
114
- ### VBench-2.0 Dataset
115
- 100 samples from VBench-2.0, comparing P-Video-2 and P-Video-2 Pro variants
116
- with other models. Categories are sampled in proportion to their prompt
117
- counts in the original dataset.
118
- Quality is Datapoint Elo and Rapidata Elo from pairwise preference. Price
119
- is USD per second of output video. Time per second of video is provider wall
120
- time, except Pruna models which use model execution time. Samples are
121
- available.
122
-
123
- ### Vbench-i2V
124
- 100 image-to-video samples, comparing P-Video-2 Pro cost, speed, and quality
125
- modes with other models, including 480p and 768p variants. Sampling uses the
126
- images' `subject` attribute, with each subject represented in proportion
127
- to its frequency in the original dataset. Quality is Datapoint
128
- Elo and Rapidata Elo from pairwise preference. Price is USD per second of
129
- output video. Time per second of video is provider wall time, except Pruna
130
- models which use model execution time. Sample media is not yet available.
131
-
132
- ### Pruna Internal Video-Edit Benchmark
133
- Pruna's internal video-to-video editing benchmark, collected by our
134
- research engineers. It combines prompts from public video-editing
135
- benchmarks with use-case examples we gathered for advertisement,
136
- e-commerce, real estate, concept art, and similar work. The suite also
137
- covers camera-angle and movement changes, lighting, and text in video
138
- (altering, adding, or removing it). Quality is Datapoint Elo from
139
- pairwise preference. Price is USD per second of output video;
140
- generation time is wall time per second of output video. Samples show
141
- the source clip beside each model's edit.
142
-
143
  ### Qwen Image Dataset
144
  100 prompts from the 1,000-prompt Qwen Image Bench set, sampled for coverage
145
  across its fine-grained (L3) categories. Metrics include Datapoint Elo,
@@ -182,17 +117,12 @@ ABOUT_DETAILS_CONTENT = """
182
  - **Arena Elo**: Elo published by Arena AI on their own dataset, plus
183
  category Elos (branding, 3D, cartoon/anime, photorealistic, art, portraits,
184
  text rendering).
185
- - **Generation time**: median and minimum generation time in seconds for
186
- images, as reported in the evaluation table. For video, generation time
187
- per second of output video is the more informative figure. On the
188
- text-to-video and image-to-video benchmarks this is provider wall time, except Pruna models which
189
- use model execution time. On video-edit it is end-to-end wall time. This
190
- is not a p95, and we do not state warm vs cold or concurrent load. Not
191
  available for Arena AI.
192
- - **Price**: USD per image for text-to-image, or USD per second of output
193
- video for text-to-video, image-to-video, and video-to-video. We do not state list price vs
194
- amount paid, or whether failed generations are included. Not available
195
- for Arena AI.
196
 
197
  Scores from different datasets or metrics are **not interchangeable**. A high
198
  OneIG alignment score is not the same quantity as a Datapoint Elo. Compare
@@ -200,30 +130,20 @@ models *within* a Dataset | Metric view.
200
 
201
  ## Setup
202
 
203
- - **Evaluation snapshots:** the current video-generation exports include
204
- P-Video-2 Pro. Other benchmark tables retain their existing snapshots.
205
  - **Update policy:** numbers come from evaluation snapshots in the tables,
206
  not a live API poll.
207
  - **Prompt counts:** OneIG Alignment uses 100 anime, 100 human, and 99 object
208
  prompts (299 total). Qwen Image Dataset uses 100 prompts sampled from the
209
  1,000-prompt pool for roughly even coverage of its fine-grained (L3)
210
- categories. VBench-2.0 Dataset and Vbench-i2V each use 100 samples.
211
- The Pruna Internal Video-Edit Benchmark uses 78
212
- prompts across advertising, e-commerce, real estate, camera, lighting,
213
- text, and related categories. Artificial Analysis and Arena AI use their
214
- own private prompt sets.
215
  - **Generation (Qwen and OneIG):** one image per prompt per endpoint when
216
  the run exists. Default resolution is 1024×1024. Exceptions: FLUX 1.1 Pro
217
  Ultra at 2K, FLUX 2 Flex at 1008×1008, and any endpoint labeled 2K. The
218
  seed is derived from the prompt, so every model gets the same seed for the
219
  same prompt. Steps, CFG, prompt rewrite, and safety filters follow each
220
  endpoint's default. This does not describe Artificial Analysis or Arena AI.
221
- - **Generation (Text-to-Video):** 100 samples, with a five-second video
222
- generated for each sample.
223
- - **Generation (Image-to-Video):** 100 samples, with a five-second video
224
- generated for each sample.
225
- - **Generation (Video-Edit):** one edited clip per prompt per endpoint when
226
- the run exists. Every model sees the same source video for a prompt.
227
  - **Datapoint (Qwen and OneIG):** every model pair is compared on every
228
  prompt, with 10 votes per battle.
229
  - **Rapidata (Qwen and OneIG):** prompts longer than 400 characters are
@@ -295,7 +215,7 @@ def render_header():
295
  </svg>
296
  </button>
297
  </div>
298
- <p class="app-header-tagline">Compare models on quality, speed, and price</p>
299
  </header>
300
  """,
301
  padding=False,
@@ -310,42 +230,10 @@ def _item(items, item_id):
310
  return items[0] if items else None
311
 
312
 
313
- def _dataset_modality(dataset):
314
- return (dataset or {}).get("modality") or MODALITY_TEXT_TO_IMAGE
315
-
316
-
317
- def _datasets_for_modality(datasets, modality):
318
- if not modality:
319
- return list(datasets)
320
- scoped = [
321
- dataset
322
- for dataset in datasets
323
- if _dataset_modality(dataset) == modality
324
- ]
325
- return scoped or list(datasets)
326
-
327
-
328
- def _modality_choices(datasets):
329
- present = {_dataset_modality(dataset) for dataset in datasets}
330
- return [
331
- (label, value) for label, value in MODALITY_CHOICES if value in present
332
- ]
333
-
334
-
335
- def _default_dataset_id(datasets, modality, preferred=None):
336
- scoped = _datasets_for_modality(datasets, modality)
337
- if preferred and any(dataset["id"] == preferred for dataset in scoped):
338
- return preferred
339
- return scoped[0]["id"] if scoped else None
340
-
341
-
342
- def _dataset_choices(
343
- datasets, *, modality=None, require_samples=False, require_pareto=False
344
- ):
345
- scoped = _datasets_for_modality(datasets, modality)
346
  return [
347
  (dataset["name"], dataset["id"])
348
- for dataset in scoped
349
  if (not require_samples or dataset.get("samples"))
350
  and (not require_pareto or _dataset_has_pareto(datasets, dataset["id"]))
351
  ]
@@ -356,77 +244,17 @@ def _dataset_has_samples(datasets, dataset_id):
356
  return bool(dataset and dataset.get("samples"))
357
 
358
 
359
- def _sample_model_ids(datasets, dataset_id):
360
- dataset = _item(datasets, dataset_id)
361
- samples = dataset.get("samples") if dataset else None
362
- if not samples:
363
- return set()
364
- models = set(samples.get("models") or [])
365
- return models | {display_model_name(model) for model in models}
366
-
367
-
368
- def _sample_media_map(samples):
369
- return (samples or {}).get("images") or {}
370
-
371
-
372
- def _resolve_sample_model(samples, model):
373
- media = _sample_media_map(samples)
374
- if model in media:
375
- return model
376
- wanted = {str(model or "").strip(), display_model_name(model)}
377
- wanted.discard("")
378
- for key in media:
379
- if key in wanted or display_model_name(key) in wanted:
380
- return key
381
- return None
382
-
383
-
384
- def _default_sample_models(samples):
385
- models = list((samples or {}).get("models") or [])
386
- preferred = [model for model in models if _is_pruna_model(model)]
387
- preferred.sort(
388
- key=lambda model: (
389
- "draft" in str(model).casefold()
390
- or "draft" in display_model_name(model).casefold(),
391
- display_model_name(model).casefold(),
392
- )
393
- )
394
- return (preferred or models)[:2]
395
-
396
-
397
- def _pareto_price_column(data):
398
- columns = getattr(data, "columns", []) if data is not None else []
399
- for column in _PARETO_PRICE_COLUMNS:
400
- if column in columns:
401
- return column
402
- return None
403
-
404
-
405
- def _pareto_time_column(data):
406
- columns = getattr(data, "columns", []) if data is not None else []
407
- for column in _PARETO_TIME_COLUMNS:
408
- if column in columns:
409
- return column
410
- return None
411
-
412
-
413
  def _dataset_has_pareto(datasets, dataset_id):
414
  dataset = _item(datasets, dataset_id)
415
- data = dataset.get("data") if dataset else None
416
- return (
417
- _pareto_price_column(data) is not None
418
- or _pareto_time_column(data) is not None
419
- )
420
 
421
 
422
- def _dataset_dropdown_update(datasets, tab, dataset_id, modality=None):
423
  """Limit the dataset list to what the current tab can show."""
424
- if modality is None:
425
- modality = _dataset_modality(_item(datasets, dataset_id))
426
  return gr.update(
427
  choices=_dataset_choices(
428
  datasets,
429
- modality=modality,
430
  require_samples=tab == TAB_SAMPLES
431
  and _dataset_has_samples(datasets, dataset_id),
432
  require_pareto=tab == TAB_PARETO
@@ -486,25 +314,23 @@ def _metric_dropdown_value(metric_id):
486
  ]
487
 
488
 
489
- def _model_choices(datasets, dataset_id, *, require_samples=False):
490
  cached = _MODEL_CHOICES_CACHE.get(dataset_id)
491
- if cached is None:
492
- dataset = _item(datasets, dataset_id)
493
- data = dataset.get("data") if dataset else None
494
- if data is None or "Model" not in getattr(data, "columns", []):
495
- cached = []
496
- else:
497
- models = data["Model"].dropna().astype(str).unique().tolist()
498
- # (label, value) so the UI shows the shared name but filters on the raw id.
499
- cached = sorted(
500
- ((display_model_name(model), model) for model in models),
501
- key=lambda item: item[0].casefold(),
502
- )
503
- _MODEL_CHOICES_CACHE[dataset_id] = cached
504
- if not require_samples:
505
  return cached
506
- allowed = _sample_model_ids(datasets, dataset_id)
507
- return [choice for choice in cached if choice[1] in allowed]
 
 
 
 
 
 
 
 
 
 
 
508
 
509
 
510
  def _model_choice_values(choices):
@@ -532,11 +358,9 @@ _LEADERBOARD_IDENTITY_COLUMNS = [
532
  "Optimized",
533
  ]
534
  _LEADERBOARD_META_COLUMNS = [
535
- "Time / Output Video Second (s)",
536
  "Median Generation Time (s)",
537
  "Min Generation Time (s)",
538
  "Price / Image (USD)",
539
- "Price / Second of Video (USD)",
540
  "Evaluation Date (UTC)",
541
  "Date",
542
  ]
@@ -652,10 +476,7 @@ def _assign_leaderboard_ranks(data, overall_column):
652
  overall_column, ascending=False, na_position="last"
653
  )
654
  ranked = ranked.reset_index(drop=True)
655
- ranks = pd.Series(ranked.index + 1, index=ranked.index, dtype="Int64")
656
- if overall_column and overall_column in ranked.columns:
657
- ranks = ranks.where(ranked[overall_column].notna())
658
- ranked.insert(0, "Rank", ranks)
659
  return ranked
660
 
661
 
@@ -684,11 +505,9 @@ def _leaderboard_html(data, columns):
684
  css = _leaderboard_cell_class(column)
685
  sort_value = escape(_leaderboard_sort_value(column, row[column]), quote=True)
686
  if column == "Model":
687
- model_name = _format_leaderboard_cell(column, row[column])
688
  cells.append(
689
- f'<td class="{css}" data-sort-value="{sort_value}" '
690
- f'data-model-name="{model_name}" tabindex="0">'
691
- f"<strong>{model_name}</strong></td>"
692
  )
693
  else:
694
  cells.append(
@@ -766,11 +585,10 @@ def _display_label(column):
766
  "Arena Art Elo": "Art",
767
  "Arena Portraits Elo": "Portraits",
768
  "Arena Text Rendering Elo": "Text Rendering",
 
769
  "Median Generation Time (s)": "Median generation time",
770
  "Min Generation Time (s)": "Min generation time",
771
- "Time / Output Video Second (s)": "Generation time per second of video",
772
  "Price / Image (USD)": "Price per image",
773
- "Price / Second of Video (USD)": "Price per second of video",
774
  "Evaluation Date (UTC)": "Date",
775
  "Date": "Date",
776
  }
@@ -845,23 +663,6 @@ def _applied_key(view_state):
845
  )
846
 
847
 
848
- def _is_pruna_model(model_id) -> bool:
849
- raw = str(model_id or "").casefold()
850
- label = display_model_name(model_id).casefold()
851
- return any(
852
- value.startswith(prefix)
853
- for value in (raw, label)
854
- for prefix in ("p-image", "p_image", "p-video", "p_video")
855
- )
856
-
857
-
858
- def _pareto_fill_colors(models):
859
- return [
860
- _PARETO_PRUNA_COLOR if _is_pruna_model(model) else _PARETO_OTHER_COLOR
861
- for model in models
862
- ]
863
-
864
-
865
  def _build_pareto_figure(
866
  data,
867
  score_column,
@@ -869,7 +670,6 @@ def _build_pareto_figure(
869
  x_title,
870
  x_hover_prefix="",
871
  x_hover_suffix="",
872
- x_axis_type="linear",
873
  ):
874
  scatter = (
875
  data[["Model", score_column, x_column]]
@@ -886,8 +686,6 @@ def _build_pareto_figure(
886
 
887
  dominated = scatter.loc[[not flag for flag in on_frontier]].copy()
888
  frontier = scatter.loc[on_frontier].sort_values(x_column).copy()
889
- dominated_colors = _pareto_fill_colors(dominated["Model"]) if not dominated.empty else []
890
- frontier_colors = _pareto_fill_colors(frontier["Model"]) if not frontier.empty else []
891
  if not dominated.empty:
892
  dominated["Model"] = dominated["Model"].map(display_model_name)
893
  if not frontier.empty:
@@ -908,11 +706,10 @@ def _build_pareto_figure(
908
  name="Below frontier",
909
  text=dominated["Model"],
910
  hovertemplate=hover,
911
- showlegend=False,
912
  marker={
913
  "size": 9,
914
- "color": dominated_colors,
915
- "opacity": 0.85,
916
  "line": {"width": 0},
917
  },
918
  )
@@ -926,51 +723,14 @@ def _build_pareto_figure(
926
  name="On frontier",
927
  text=frontier["Model"],
928
  hovertemplate=hover,
929
- showlegend=False,
930
- line={"color": _PARETO_FRONTIER_OUTLINE, "width": 2.5},
931
  marker={
932
  "size": 12,
933
- "color": frontier_colors,
934
- "line": {"width": 2.5, "color": _PARETO_FRONTIER_OUTLINE},
935
  },
936
  )
937
  )
938
- for name, marker in (
939
- (
940
- "Pruna",
941
- {
942
- "size": 10,
943
- "color": _PARETO_PRUNA_COLOR,
944
- "line": {"width": 0},
945
- },
946
- ),
947
- (
948
- "Other models",
949
- {
950
- "size": 10,
951
- "color": _PARETO_OTHER_COLOR,
952
- "line": {"width": 0},
953
- },
954
- ),
955
- (
956
- "On frontier",
957
- {
958
- "size": 12,
959
- "color": "rgba(0,0,0,0)",
960
- "line": {"width": 2.5, "color": _PARETO_FRONTIER_OUTLINE},
961
- },
962
- ),
963
- ):
964
- fig.add_trace(
965
- go.Scatter(
966
- x=[None],
967
- y=[None],
968
- mode="markers",
969
- name=name,
970
- marker=marker,
971
- hoverinfo="skip",
972
- )
973
- )
974
 
975
  score_label = _display_label(score_column)
976
  fig.update_layout(
@@ -995,29 +755,7 @@ def _build_pareto_figure(
995
  )
996
  axis_font = {"color": "#fafafa", "size": 13}
997
  tick_font = {"color": "#a3a3a3", "size": 12}
998
- x_axis_ticks = {}
999
- if x_axis_type == "log":
1000
- positive_x = scatter.loc[scatter[x_column] > 0, x_column].astype(float)
1001
- if not positive_x.empty:
1002
- minimum = positive_x.min()
1003
- maximum = positive_x.max()
1004
- tick_values = [
1005
- factor * (10**exponent)
1006
- for exponent in range(
1007
- floor(log10(minimum)),
1008
- ceil(log10(maximum)) + 1,
1009
- )
1010
- for factor in (1, 2, 5)
1011
- if minimum * 0.8 <= factor * (10**exponent) <= maximum * 1.2
1012
- ]
1013
- x_axis_ticks = {
1014
- "tickmode": "array",
1015
- "tickvals": tick_values,
1016
- "ticktext": [f"{value:g}" for value in tick_values],
1017
- }
1018
  fig.update_xaxes(
1019
- type=x_axis_type,
1020
- **x_axis_ticks,
1021
  showgrid=True,
1022
  gridcolor="rgba(74, 57, 98, 0.55)",
1023
  zeroline=False,
@@ -1036,55 +774,6 @@ def _build_pareto_figure(
1036
  return fig
1037
 
1038
 
1039
- def _is_log_scale(scale):
1040
- return scale == "Logarithmic"
1041
-
1042
-
1043
- def _pareto_axis_type(scale):
1044
- return "log" if _is_log_scale(scale) else "linear"
1045
-
1046
-
1047
- def _pareto_scale_radio(*extra_classes):
1048
- return gr.Radio(
1049
- choices=_PARETO_SCALE_CHOICES,
1050
- value=_PARETO_SCALE_DEFAULT,
1051
- show_label=False,
1052
- container=False,
1053
- elem_classes=["pareto-scale-toggle", *extra_classes],
1054
- )
1055
-
1056
-
1057
- def _pareto_plot_heading(title):
1058
- with gr.Row(equal_height=False, elem_classes="pareto-heading-row"):
1059
- gr.Markdown(f"#### {title}", elem_classes="pareto-subhead")
1060
- with gr.Column(min_width=140, elem_classes="pareto-scale-control"):
1061
- return _pareto_scale_radio()
1062
-
1063
-
1064
- def _default_pareto_scales():
1065
- return [_PARETO_SCALE_DEFAULT] * MAX_PARETO_METRICS
1066
-
1067
-
1068
- def _normalize_pareto_scales(scales):
1069
- values = list(scales or [])
1070
- if len(values) < MAX_PARETO_METRICS:
1071
- values.extend(
1072
- [_PARETO_SCALE_DEFAULT] * (MAX_PARETO_METRICS - len(values))
1073
- )
1074
- return values[:MAX_PARETO_METRICS]
1075
-
1076
-
1077
- def _uniform_pareto_scales(scale):
1078
- return [scale] * MAX_PARETO_METRICS
1079
-
1080
-
1081
- def _pareto_master_scale_update(price_scales, time_scales):
1082
- values = list(price_scales) + list(time_scales)
1083
- if values and all(value == values[0] for value in values):
1084
- return gr.update(value=values[0])
1085
- return gr.update(value=None)
1086
-
1087
-
1088
  def _pareto_axis(data, score_column, x_column, x_title, missing_message, empty_message, **hover):
1089
  if x_column not in data.columns:
1090
  return None, missing_message
@@ -1100,83 +789,56 @@ def _pareto_axis(data, score_column, x_column, x_title, missing_message, empty_m
1100
  return fig, None
1101
 
1102
 
1103
- def _pareto_pair(
1104
- data,
1105
- score_column,
1106
- latency_scale=_PARETO_SCALE_DEFAULT,
1107
- price_scale=_PARETO_SCALE_DEFAULT,
1108
- ):
1109
  score_missing = "No score data is available for this metric."
1110
  if data is None or not score_column or score_column not in data.columns:
1111
  return None, score_missing, None, score_missing
1112
 
1113
- price_column = _pareto_price_column(data) or _PARETO_PRICE_COLUMN
1114
- price_title = _PARETO_PRICE_TITLES.get(price_column, "Price (USD)")
1115
- price_missing = (
1116
- "Price per second of video isn't available for this dataset."
1117
- if price_column == _PARETO_VIDEO_PRICE_COLUMN
1118
- else "Price per image isn't available for this dataset."
1119
- )
1120
  price_fig, price_message = _pareto_axis(
1121
  data,
1122
  score_column,
1123
- price_column,
1124
- price_title,
1125
- price_missing,
1126
  "No models have both a score and a price for this metric.",
1127
  x_hover_prefix="$",
1128
- x_axis_type=_pareto_axis_type(price_scale),
1129
- )
1130
- time_column = _pareto_time_column(data) or _PARETO_TIME_COLUMN
1131
- time_title = _PARETO_TIME_TITLES.get(time_column, "Generation time (s)")
1132
- time_missing = (
1133
- "Generation time per second of video isn't available for this dataset."
1134
- if time_column == _PARETO_VIDEO_TIME_COLUMN
1135
- else "Min generation time isn't available for this dataset."
1136
- )
1137
- time_empty = (
1138
- "No models have both a score and generation time per second of "
1139
- "video for this metric."
1140
- if time_column == _PARETO_VIDEO_TIME_COLUMN
1141
- else "No models have both a score and a min generation time for this metric."
1142
  )
1143
  time_fig, time_message = _pareto_axis(
1144
  data,
1145
  score_column,
1146
- time_column,
1147
- time_title,
1148
- time_missing,
1149
- time_empty,
1150
  x_hover_suffix="s",
1151
- x_axis_type=_pareto_axis_type(latency_scale),
1152
  )
1153
  return price_fig, price_message, time_fig, time_message
1154
 
1155
 
1156
  def _pareto_dataset_message(data):
1157
- has_price = _pareto_price_column(data) is not None
1158
- has_time = _pareto_time_column(data) is not None
1159
  if has_price or has_time:
1160
  return None
1161
  return (
1162
- "Price and generation time aren't available for "
1163
  "this dataset, so these plots can't be drawn."
1164
  )
1165
 
1166
 
1167
  def _pareto_slot_note(price_fig, price_message, time_fig, time_message, data):
1168
- has_price = _pareto_price_column(data) is not None
1169
- has_time = _pareto_time_column(data) is not None
1170
  notes = []
1171
  if has_price and not has_time:
1172
  notes.append(
1173
- "Generation time isn't available for this dataset, so only "
1174
  "price vs score is shown."
1175
  )
1176
  elif has_time and not has_price:
1177
  notes.append(
1178
- "Price isn't available for this dataset, so only "
1179
- "time vs score is shown."
1180
  )
1181
  if price_fig is None and has_price:
1182
  notes.append(price_message)
@@ -1187,18 +849,11 @@ def _pareto_slot_note(price_fig, price_message, time_fig, time_message, data):
1187
  return " ".join(notes)
1188
 
1189
 
1190
- def _pareto_slot_updates(
1191
- data,
1192
- score_columns,
1193
- price_scales=None,
1194
- time_scales=None,
1195
- ):
1196
  """Updates for a fixed bank of Gradio Plot slots (visible/hidden)."""
1197
  score_columns = [column for column in (score_columns or []) if column]
1198
- price_scales = _normalize_pareto_scales(price_scales)
1199
- time_scales = _normalize_pareto_scales(time_scales)
1200
- has_price = _pareto_price_column(data) is not None
1201
- has_time = _pareto_time_column(data) is not None
1202
  dataset_note = _pareto_dataset_message(data)
1203
  updates = [_pareto_note_update(dataset_note)]
1204
  hide_all_slots = not has_price and not has_time
@@ -1218,10 +873,7 @@ def _pareto_slot_updates(
1218
  continue
1219
  score_column = score_columns[index]
1220
  price_fig, price_message, time_fig, time_message = _pareto_pair(
1221
- data,
1222
- score_column,
1223
- latency_scale=time_scales[index],
1224
- price_scale=price_scales[index],
1225
  )
1226
  show_price = price_fig is not None
1227
  show_time = time_fig is not None
@@ -1248,77 +900,20 @@ def _pareto_slot_updates(
1248
  return updates
1249
 
1250
 
1251
- def _pareto_all_scale_updates(data, score_columns, scale):
1252
- """Apply one scale to every Pareto plot and radio."""
1253
- score_columns = [column for column in (score_columns or []) if column]
1254
- price_updates = []
1255
- time_updates = []
1256
- for index in range(MAX_PARETO_METRICS):
1257
- if index >= len(score_columns):
1258
- price_updates.append(gr.skip())
1259
- time_updates.append(gr.skip())
1260
- continue
1261
- price_fig, _, time_fig, _ = _pareto_pair(
1262
- data,
1263
- score_columns[index],
1264
- latency_scale=scale,
1265
- price_scale=scale,
1266
- )
1267
- price_updates.append(_pareto_plot_update(price_fig))
1268
- time_updates.append(_pareto_plot_update(time_fig))
1269
- radio_updates = [
1270
- gr.update(value=scale) for _ in range(MAX_PARETO_METRICS * 2)
1271
- ]
1272
- return price_updates + time_updates + radio_updates
1273
-
1274
-
1275
  def _samples_html(samples, selected_models, num_prompts, seed=0):
1276
  if not samples:
1277
  return _pareto_unavailable_html(
1278
  "Samples aren't available for this dataset."
1279
  )
1280
- models = [
1281
- resolved
1282
- for model in (selected_models or [])
1283
- if (resolved := _resolve_sample_model(samples, model))
1284
- ]
1285
  if not models:
1286
- models = _default_sample_models(samples)
1287
  return _build_compare_samples_html(samples, models, num_prompts, seed)
1288
 
1289
 
1290
- def _compare_media_html(url, label, *, kind):
1291
- safe_url = escape(url, quote=True)
1292
- safe_label = escape(label)
1293
- if kind == "video":
1294
- return (
1295
- f'<video src="{safe_url}" controls preload="metadata" '
1296
- f'playsinline></video>'
1297
- )
1298
- return (
1299
- f'<a href="{safe_url}" target="_blank" rel="noopener noreferrer">'
1300
- f'<img src="{safe_url}" alt="{safe_label} sample" loading="lazy" />'
1301
- f"</a>"
1302
- )
1303
-
1304
-
1305
- def _compare_cell_html(label, url, *, kind, extra_class=""):
1306
- classes = "compare-cell"
1307
- if extra_class:
1308
- classes = f"{classes} {extra_class}"
1309
- return f"""
1310
- <div class="{classes}">
1311
- <div class="compare-model-label">{escape(label)}</div>
1312
- {_compare_media_html(url, label, kind=kind)}
1313
- </div>
1314
- """
1315
-
1316
-
1317
  def _build_compare_samples_html(samples, selected_models, num_prompts, seed=0):
1318
  selected_models = list(selected_models or [])[:MAX_COMPARE_MODELS]
1319
- media = _sample_media_map(samples)
1320
- kind = (samples or {}).get("kind") or "image"
1321
- source_videos = (samples or {}).get("source_videos") or {}
1322
 
1323
  if not selected_models:
1324
  return (
@@ -1329,7 +924,7 @@ def _build_compare_samples_html(samples, selected_models, num_prompts, seed=0):
1329
 
1330
  shared_prompt_ids = None
1331
  for model in selected_models:
1332
- model_prompt_ids = set(media.get(model) or [])
1333
  shared_prompt_ids = (
1334
  model_prompt_ids
1335
  if shared_prompt_ids is None
@@ -1349,31 +944,29 @@ def _build_compare_samples_html(samples, selected_models, num_prompts, seed=0):
1349
  rng.shuffle(prompt_pool)
1350
  chosen = prompt_pool[: max(1, min(int(num_prompts), len(prompt_pool)))]
1351
 
 
1352
  blocks = []
1353
  for index, prompt_id in enumerate(chosen, start=1):
1354
  prompt_text = escape(samples["prompts"].get(prompt_id, ""))
1355
  cells = []
1356
- source_url = source_videos.get(prompt_id)
1357
- if source_url:
1358
- cells.append(
1359
- _compare_cell_html(
1360
- "Source", source_url, kind="video", extra_class="compare-source"
1361
- )
1362
- )
1363
  for model in selected_models:
 
1364
  cells.append(
1365
- _compare_cell_html(
1366
- display_model_name(model),
1367
- media[model][prompt_id],
1368
- kind=kind,
1369
- )
 
 
 
1370
  )
1371
- columns = len(cells)
1372
  blocks.append(
1373
  f"""
1374
  <div class="compare-prompt-block">
1375
  <div class="compare-prompt-meta">
1376
  <span>Prompt {index}</span>
 
1377
  </div>
1378
  <p class="compare-prompt-text">{prompt_text}</p>
1379
  <div class="compare-row" style="grid-template-columns: repeat({columns}, minmax(0, 1fr));">
@@ -1401,19 +994,9 @@ def _filter_row(datasets, metrics, default_dataset_id, default_metric_id=None):
1401
  metric_id = _coerce_metric(
1402
  datasets, metrics, default_dataset_id, default_metric_id
1403
  )
1404
- default_modality = _dataset_modality(_item(datasets, default_dataset_id))
1405
  with gr.Row(elem_classes="view-filters"):
1406
- modality_dd = gr.Dropdown(
1407
- choices=_modality_choices(datasets),
1408
- value=default_modality,
1409
- label="Model Type",
1410
- type="value",
1411
- filterable=False,
1412
- scale=1,
1413
- min_width=170,
1414
- )
1415
  dataset_dd = gr.Dropdown(
1416
- choices=_dataset_choices(datasets, modality=default_modality),
1417
  value=default_dataset_id,
1418
  label="Dataset",
1419
  type="value",
@@ -1445,7 +1028,7 @@ def _filter_row(datasets, metrics, default_dataset_id, default_metric_id=None):
1445
  min_width=180,
1446
  elem_classes="filter-chips",
1447
  )
1448
- return modality_dd, dataset_dd, metric_dd, models_dd
1449
 
1450
 
1451
  def render_image_workspace(datasets, metrics, default_dataset_id, default_metric_id):
@@ -1460,17 +1043,15 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1460
  with gr.Column(elem_classes="workspace-filters") as filters_host:
1461
  gr.Markdown(
1462
  "<p class='filter-help'>"
1463
- "Start with Model Type to switch modalities. The rest of "
1464
- "the filters follow you across Leaderboards, Pareto plots, "
1465
- "and Samples. "
1466
- "Samples only lists datasets and models we have generations "
1467
- "for; Pareto plots only lists datasets with price or "
1468
- "generation time. Search in Models, or leave it empty to "
1469
- "include every model."
1470
  "</p>",
1471
  elem_classes="filter-help-host",
1472
  )
1473
- modality_dd, dataset_dd, metric_dd, models_dd = _filter_row(
1474
  datasets, metrics, default_dataset_id, None
1475
  )
1476
  with gr.Tabs(elem_classes="main-tabs") as main_tabs:
@@ -1536,27 +1117,12 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1536
  ) as pp_tab:
1537
  gr.Markdown(
1538
  "<p class='view-help'>"
1539
- "Score against price and generation time. Green points are on "
1540
- "the frontier; lavender points sit below it. Hover a point to "
1541
- "see which model it is."
1542
- "</p>"
1543
- "<p class='view-help'>"
1544
- "Plots use a logarithmic scale by default. You can switch "
1545
- "to linear for all plots, or individually for each plot."
1546
  "</p>",
1547
  elem_classes="view-help-host",
1548
  )
1549
- with gr.Row(
1550
- equal_height=False,
1551
- elem_classes="pareto-scale-all-row",
1552
- ):
1553
- gr.HTML(
1554
- "<span class='pareto-scale-all-label'>All plots</span>",
1555
- padding=False,
1556
- )
1557
- pareto_all_scale = _pareto_scale_radio(
1558
- "pareto-scale-toggle-all",
1559
- )
1560
  pareto_dataset_note = gr.HTML(
1561
  "",
1562
  padding=False,
@@ -1582,8 +1148,9 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1582
  min_width=320,
1583
  elem_classes="pareto-col",
1584
  ) as slot_price_col:
1585
- slot_price_scale = _pareto_plot_heading(
1586
- "Price vs score"
 
1587
  )
1588
  slot_price = gr.Plot(
1589
  value=None,
@@ -1595,8 +1162,9 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1595
  min_width=320,
1596
  elem_classes="pareto-col",
1597
  ) as slot_time_col:
1598
- slot_time_scale = _pareto_plot_heading(
1599
- "Time vs score"
 
1600
  )
1601
  slot_time = gr.Plot(
1602
  value=None,
@@ -1617,10 +1185,8 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1617
  slot_layout,
1618
  slot_price_col,
1619
  slot_price,
1620
- slot_price_scale,
1621
  slot_time_col,
1622
  slot_time,
1623
- slot_time_scale,
1624
  )
1625
  )
1626
 
@@ -1632,8 +1198,7 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1632
  with gr.Column(visible=bool(initial_samples)) as samples_panel:
1633
  gr.Markdown(
1634
  f"<p class='view-help'>"
1635
- f"The same prompts, side by side. Video edits show the "
1636
- f"source clip first. Select up to "
1637
  f"<strong>{MAX_COMPARE_MODELS}</strong> models above, or leave "
1638
  f"Models empty for two defaults."
1639
  f"</p>",
@@ -1670,16 +1235,12 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1670
  with gr.TabItem("About", id=TAB_ABOUT) as about_tab:
1671
  render_about()
1672
 
1673
- def _synced_filters(
1674
- dataset_id, metric_id, models, *, clear_metric=False, require_samples=False
1675
- ):
1676
  if clear_metric:
1677
  metric_id = []
1678
  else:
1679
  metric_id = _coerce_metric(datasets, metrics, dataset_id, metric_id)
1680
- model_choices = _model_choices(
1681
- datasets, dataset_id, require_samples=require_samples
1682
- )
1683
  model_values = set(_model_choice_values(model_choices))
1684
  models = [model for model in (models or []) if model in model_values]
1685
  metric_choices = _metric_dropdown_choices(datasets, metrics, dataset_id)
@@ -1751,14 +1312,8 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1751
  ):
1752
  prev = dict(view_state or {})
1753
  extras = extras or {}
1754
- modality = _dataset_modality(_item(datasets, dataset_id))
1755
- last_by_modality = dict(prev.get("dataset_by_modality") or {})
1756
- if dataset_id:
1757
- last_by_modality[modality] = dataset_id
1758
  return {
1759
  "dataset_id": dataset_id,
1760
- "modality": modality,
1761
- "dataset_by_modality": last_by_modality,
1762
  "metric_id": metric_id,
1763
  "models": list(models or []),
1764
  "current_tab": tab,
@@ -1769,8 +1324,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1769
  "optimized": list(
1770
  extras.get("optimized", prev.get("optimized") or [])
1771
  ),
1772
- "price_scales": _normalize_pareto_scales(prev.get("price_scales")),
1773
- "time_scales": _normalize_pareto_scales(prev.get("time_scales")),
1774
  "stale": {
1775
  TAB_LEADERBOARDS: not flags["include_leaderboard"],
1776
  TAB_PARETO: not flags["include_pareto"],
@@ -1830,8 +1383,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1830
  include_leaderboard=True,
1831
  include_pareto=False,
1832
  include_samples=False,
1833
- price_scales=None,
1834
- time_scales=None,
1835
  ):
1836
  view = resolve_view(datasets, metrics, dataset_id, metric_id)
1837
  data = view["data"]
@@ -1852,12 +1403,7 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1852
  ranking_html = gr.skip()
1853
  if include_pareto:
1854
  pareto_data = _filter_leaderboard(data, [], [], [], models=models)
1855
- pareto_updates = _pareto_slot_updates(
1856
- pareto_data,
1857
- view["score_columns"],
1858
- price_scales=price_scales,
1859
- time_scales=time_scales,
1860
- )
1861
  else:
1862
  pareto_updates = _pareto_skip_updates()
1863
  if include_samples:
@@ -1896,24 +1442,13 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1896
  tab = view_state.get("current_tab") or TAB_LEADERBOARDS
1897
  selected_raw = _normalize_metric_ids(metric_id)
1898
  incoming_models = list(models or [])
1899
- filter_changed = source in {"dataset", "modality"}
1900
- dataset_changed = filter_changed and dataset_id != view_state.get(
1901
  "dataset_id"
1902
  )
1903
- can_pareto = _dataset_has_pareto(datasets, dataset_id)
1904
- can_samples = _dataset_has_samples(datasets, dataset_id)
1905
- selected_tab = tab
1906
- if filter_changed:
1907
- if tab == TAB_SAMPLES and not can_samples:
1908
- selected_tab = TAB_LEADERBOARDS
1909
- elif tab == TAB_PARETO and not can_pareto:
1910
- selected_tab = TAB_LEADERBOARDS
1911
  synced = _synced_filters(
1912
- dataset_id,
1913
- metric_id,
1914
- models,
1915
- clear_metric=source == "modality" or dataset_changed,
1916
- require_samples=selected_tab == TAB_SAMPLES,
1917
  )
1918
  dataset_id, metric_id, models = synced[:3]
1919
  metric_update, models_update = synced[3], synced[4]
@@ -1951,13 +1486,20 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1951
  ):
1952
  return None
1953
 
 
1954
  extras = (
1955
  list(platform_value or []),
1956
  list(owner_value or []),
1957
  list(optimized_value or []),
1958
  )
1959
  extra_updates = None
1960
- if filter_changed:
 
 
 
 
 
 
1961
  view = resolve_view(datasets, metrics, dataset_id, metric_id)
1962
  extra_updates = _leaderboard_extras(
1963
  view["data"] if view else None,
@@ -1995,8 +1537,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
1995
  extras[2],
1996
  num_prompts,
1997
  seed,
1998
- price_scales=view_state.get("price_scales"),
1999
- time_scales=view_state.get("time_scales"),
2000
  **flags,
2001
  ),
2002
  "state": _commit_state(
@@ -2010,67 +1550,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2010
  ),
2011
  }
2012
 
2013
- def on_modality(
2014
- modality,
2015
- dataset_id,
2016
- metric_id,
2017
- models,
2018
- platform_value,
2019
- owner_value,
2020
- optimized_value,
2021
- num_prompts,
2022
- seed,
2023
- view_state,
2024
- ):
2025
- view_state = dict(view_state or {})
2026
- last_by_modality = dict(view_state.get("dataset_by_modality") or {})
2027
- current_modality = view_state.get("modality") or _dataset_modality(
2028
- _item(datasets, dataset_id)
2029
- )
2030
- if dataset_id:
2031
- last_by_modality[current_modality] = dataset_id
2032
- dataset_id = _default_dataset_id(
2033
- datasets, modality, last_by_modality.get(modality)
2034
- )
2035
- view_state["modality"] = modality
2036
- view_state["dataset_by_modality"] = last_by_modality
2037
- result = _apply_filter_change(
2038
- "modality",
2039
- dataset_id,
2040
- metric_id,
2041
- models,
2042
- platform_value,
2043
- owner_value,
2044
- optimized_value,
2045
- num_prompts,
2046
- seed,
2047
- view_state,
2048
- )
2049
- if result is None:
2050
- return _skip_all(len(dataset_outputs))
2051
- extras = result["extra_updates"]
2052
- return (
2053
- _dataset_dropdown_update(
2054
- datasets,
2055
- result["selected_tab"],
2056
- result["dataset_id"],
2057
- modality=modality,
2058
- ),
2059
- result["metric_update"],
2060
- result["models_update"],
2061
- extras[6],
2062
- extras[0],
2063
- extras[1],
2064
- extras[2],
2065
- *result["views"],
2066
- gr.update(interactive=result["can_pareto"]),
2067
- gr.update(interactive=result["can_samples"]),
2068
- gr.update(selected=result["selected_tab"])
2069
- if result["selected_tab"] != result["tab"]
2070
- else gr.skip(),
2071
- result["state"],
2072
- )
2073
-
2074
  def on_dataset(
2075
  dataset_id,
2076
  metric_id,
@@ -2198,17 +1677,7 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2198
  )
2199
  dataset_update = _dataset_dropdown_update(datasets, tab, dataset_id)
2200
  metric_id = _coerce_metric(datasets, metrics, dataset_id, metric_id)
2201
- require_samples = tab == TAB_SAMPLES
2202
- model_choices = _model_choices(
2203
- datasets, dataset_id, require_samples=require_samples
2204
- )
2205
- allowed_models = set(_model_choice_values(model_choices))
2206
- models = [model for model in (models or []) if model in allowed_models]
2207
- models_update = (
2208
- gr.update(choices=model_choices, value=models)
2209
- if (prev_tab == TAB_SAMPLES) != require_samples
2210
- else gr.skip()
2211
- )
2212
  view_state["current_tab"] = tab
2213
  view_state["dataset_id"] = dataset_id
2214
  view_state["metric_id"] = metric_id
@@ -2245,7 +1714,7 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2245
  filters_vis,
2246
  dataset_update,
2247
  metric_vis,
2248
- models_update,
2249
  *lb_filters,
2250
  )
2251
  tab_select = (
@@ -2270,8 +1739,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2270
  optimized_value,
2271
  num_prompts,
2272
  seed,
2273
- price_scales=view_state.get("price_scales"),
2274
- time_scales=view_state.get("time_scales"),
2275
  **flags,
2276
  )
2277
  stale[tab] = False
@@ -2328,70 +1795,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2328
  next_seed,
2329
  )
2330
 
2331
- def _on_pareto_plot_scale(slot_index, axis):
2332
- def handler(dataset_id, metric_id, models, scale, view_state):
2333
- view_state = dict(view_state or {})
2334
- price_scales = _normalize_pareto_scales(
2335
- view_state.get("price_scales")
2336
- )
2337
- time_scales = _normalize_pareto_scales(
2338
- view_state.get("time_scales")
2339
- )
2340
- if axis == "price":
2341
- if price_scales[slot_index] == scale:
2342
- return gr.skip(), gr.skip(), gr.skip()
2343
- price_scales[slot_index] = scale
2344
- else:
2345
- if time_scales[slot_index] == scale:
2346
- return gr.skip(), gr.skip(), gr.skip()
2347
- time_scales[slot_index] = scale
2348
- view_state["price_scales"] = price_scales
2349
- view_state["time_scales"] = time_scales
2350
- master_scale = _pareto_master_scale_update(
2351
- price_scales, time_scales
2352
- )
2353
- view = resolve_view(datasets, metrics, dataset_id, metric_id)
2354
- score_columns = [
2355
- column for column in (view["score_columns"] or []) if column
2356
- ]
2357
- if slot_index >= len(score_columns):
2358
- return gr.skip(), master_scale, view_state
2359
- data = _filter_leaderboard(
2360
- view["data"], [], [], [], models=list(models or [])
2361
- )
2362
- price_fig, _, time_fig, _ = _pareto_pair(
2363
- data,
2364
- score_columns[slot_index],
2365
- latency_scale=time_scales[slot_index],
2366
- price_scale=price_scales[slot_index],
2367
- )
2368
- fig = price_fig if axis == "price" else time_fig
2369
- return _pareto_plot_update(fig), master_scale, view_state
2370
-
2371
- handler.__name__ = f"on_pareto_{axis}_scale_{slot_index}"
2372
- return handler
2373
-
2374
- def on_pareto_all_scale(dataset_id, metric_id, models, scale, view_state):
2375
- if scale not in _PARETO_SCALE_VALUES:
2376
- return (*_skip_all(MAX_PARETO_METRICS * 4), gr.skip())
2377
- view_state = dict(view_state or {})
2378
- scales = _uniform_pareto_scales(scale)
2379
- if (
2380
- _normalize_pareto_scales(view_state.get("price_scales")) == scales
2381
- and _normalize_pareto_scales(view_state.get("time_scales")) == scales
2382
- ):
2383
- return (*_skip_all(MAX_PARETO_METRICS * 4), gr.skip())
2384
- view_state["price_scales"] = scales
2385
- view_state["time_scales"] = scales
2386
- view = resolve_view(datasets, metrics, dataset_id, metric_id)
2387
- data = _filter_leaderboard(
2388
- view["data"], [], [], [], models=list(models or [])
2389
- )
2390
- return (
2391
- *_pareto_all_scale_updates(data, view["score_columns"], scale),
2392
- view_state,
2393
- )
2394
-
2395
  def _on_tab(tab):
2396
  def handler(
2397
  dataset_id,
@@ -2420,20 +1823,15 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2420
  handler.__name__ = f"on_tab_{tab}"
2421
  return handler
2422
 
2423
- default_modality = _dataset_modality(_item(datasets, default_dataset_id))
2424
  view_state = gr.State(
2425
  {
2426
  "dataset_id": default_dataset_id,
2427
- "modality": default_modality,
2428
- "dataset_by_modality": {default_modality: default_dataset_id},
2429
  "metric_id": None,
2430
  "models": [],
2431
  "current_tab": TAB_LEADERBOARDS,
2432
  "platform": [],
2433
  "owner": [],
2434
  "optimized": [],
2435
- "price_scales": _default_pareto_scales(),
2436
- "time_scales": _default_pareto_scales(),
2437
  "stale": {
2438
  TAB_LEADERBOARDS: False,
2439
  TAB_PARETO: True,
@@ -2445,7 +1843,7 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2445
  pareto_dataset_note,
2446
  *[
2447
  component
2448
- for slot_group, slot_title, slot_note, slot_layout, slot_price_col, slot_price, slot_price_scale, slot_time_col, slot_time, slot_time_scale in pareto_slots
2449
  for component in (
2450
  slot_group,
2451
  slot_title,
@@ -2458,24 +1856,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2458
  )
2459
  ],
2460
  ]
2461
- pareto_all_scale_outputs = [
2462
- *[
2463
- slot_price
2464
- for _, _, _, _, _, slot_price, _, _, _, _ in pareto_slots
2465
- ],
2466
- *[
2467
- slot_time
2468
- for _, _, _, _, _, _, _, _, slot_time, _ in pareto_slots
2469
- ],
2470
- *[
2471
- slot_price_scale
2472
- for _, _, _, _, _, _, slot_price_scale, _, _, _ in pareto_slots
2473
- ],
2474
- *[
2475
- slot_time_scale
2476
- for _, _, _, _, _, _, _, _, _, slot_time_scale in pareto_slots
2477
- ],
2478
- ]
2479
  view_inputs = [
2480
  platform,
2481
  owner,
@@ -2507,12 +1887,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2507
  main_tabs,
2508
  view_state,
2509
  ]
2510
- modality_dd.change(
2511
- on_modality,
2512
- inputs=[modality_dd, *filter_inputs],
2513
- outputs=dataset_outputs,
2514
- **_VIEW_EVENTS,
2515
- )
2516
  dataset_dd.change(
2517
  on_dataset,
2518
  inputs=filter_inputs,
@@ -2586,56 +1960,6 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
2586
  show_progress="hidden",
2587
  )
2588
 
2589
- pareto_all_scale.change(
2590
- on_pareto_all_scale,
2591
- inputs=[
2592
- dataset_dd,
2593
- metric_dd,
2594
- models_dd,
2595
- pareto_all_scale,
2596
- view_state,
2597
- ],
2598
- outputs=[*pareto_all_scale_outputs, view_state],
2599
- **_VIEW_EVENTS,
2600
- )
2601
-
2602
- for slot_index, (
2603
- _,
2604
- _,
2605
- _,
2606
- _,
2607
- _,
2608
- slot_price,
2609
- slot_price_scale,
2610
- _,
2611
- slot_time,
2612
- slot_time_scale,
2613
- ) in enumerate(pareto_slots):
2614
- slot_price_scale.change(
2615
- _on_pareto_plot_scale(slot_index, "price"),
2616
- inputs=[
2617
- dataset_dd,
2618
- metric_dd,
2619
- models_dd,
2620
- slot_price_scale,
2621
- view_state,
2622
- ],
2623
- outputs=[slot_price, pareto_all_scale, view_state],
2624
- **_VIEW_EVENTS,
2625
- )
2626
- slot_time_scale.change(
2627
- _on_pareto_plot_scale(slot_index, "time"),
2628
- inputs=[
2629
- dataset_dd,
2630
- metric_dd,
2631
- models_dd,
2632
- slot_time_scale,
2633
- view_state,
2634
- ],
2635
- outputs=[slot_time, pareto_all_scale, view_state],
2636
- **_VIEW_EVENTS,
2637
- )
2638
-
2639
  prompt_count.change(
2640
  on_samples_controls,
2641
  inputs=[dataset_dd, models_dd, prompt_count, seed_state],
 
1
  from html import escape
 
2
  from pathlib import Path
3
  import base64
4
  import random
 
24
  MAX_PARETO_METRICS = 8
25
  _PARETO_SLOT_COUNT = 1 + MAX_PARETO_METRICS * 8
26
  _PARETO_PRICE_COLUMN = "Price / Image (USD)"
 
 
27
  _PARETO_TIME_COLUMN = "Min Generation Time (s)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  TAB_LEADERBOARDS = "leaderboards"
30
  TAB_PARETO = "pareto"
31
  TAB_SAMPLES = "samples"
32
  TAB_ABOUT = "about"
33
 
 
 
 
 
 
 
 
 
 
 
 
34
  _MODEL_CHOICES_CACHE = {}
35
  _VIEW_EVENTS = {
36
  "show_progress": "hidden",
 
42
  ABOUT_OVERVIEW_CONTENT = """
43
  # About P-Bench
44
 
45
+ P-Bench compares **text-to-image models**, including optimized or accelerated
46
+ endpoints, on **quality, speed, and price**. Each view is a **dataset** scored
47
+ with a **metric**, written as `Dataset | Metric`. There is no single score
48
+ across P-Bench.
49
 
50
  ## How to read it
51
 
52
+ 1. Pick a **dataset** and a **metric**.
 
53
  2. **Leaderboards**: ranked by that metric. Price and generation time sit in
54
  the same table when the source publishes them.
55
  3. **Pareto plots**: mark models that are not beaten on both higher score
56
  and lower price (or time). Only datasets with price or generation time
57
  can open this tab (not Arena AI).
58
  4. **Samples**: the same prompts, side by side. Only for datasets we
59
+ generated (Qwen Image Dataset and OneIG Alignment Dataset).
 
 
60
 
61
  ## How a score is made
62
 
 
75
 
76
  ## Current datasets
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  ### Qwen Image Dataset
79
  100 prompts from the 1,000-prompt Qwen Image Bench set, sampled for coverage
80
  across its fine-grained (L3) categories. Metrics include Datapoint Elo,
 
117
  - **Arena Elo**: Elo published by Arena AI on their own dataset, plus
118
  category Elos (branding, 3D, cartoon/anime, photorealistic, art, portraits,
119
  text rendering).
120
+ - **Generation time**: median and minimum generation time in seconds, as
121
+ reported in the evaluation table. This is not a p95, and we do not state
122
+ warm vs cold or concurrent load. Not available for Arena AI.
123
+ - **Price**: USD per image in the evaluation table. We do not state list
124
+ price vs amount paid, or whether failed generations are included. Not
 
125
  available for Arena AI.
 
 
 
 
126
 
127
  Scores from different datasets or metrics are **not interchangeable**. A high
128
  OneIG alignment score is not the same quantity as a Datapoint Elo. Compare
 
130
 
131
  ## Setup
132
 
133
+ - **Evaluation window:** July–August 2026.
 
134
  - **Update policy:** numbers come from evaluation snapshots in the tables,
135
  not a live API poll.
136
  - **Prompt counts:** OneIG Alignment uses 100 anime, 100 human, and 99 object
137
  prompts (299 total). Qwen Image Dataset uses 100 prompts sampled from the
138
  1,000-prompt pool for roughly even coverage of its fine-grained (L3)
139
+ categories. Artificial Analysis and Arena AI use their own private prompt
140
+ sets.
 
 
 
141
  - **Generation (Qwen and OneIG):** one image per prompt per endpoint when
142
  the run exists. Default resolution is 1024×1024. Exceptions: FLUX 1.1 Pro
143
  Ultra at 2K, FLUX 2 Flex at 1008×1008, and any endpoint labeled 2K. The
144
  seed is derived from the prompt, so every model gets the same seed for the
145
  same prompt. Steps, CFG, prompt rewrite, and safety filters follow each
146
  endpoint's default. This does not describe Artificial Analysis or Arena AI.
 
 
 
 
 
 
147
  - **Datapoint (Qwen and OneIG):** every model pair is compared on every
148
  prompt, with 10 votes per battle.
149
  - **Rapidata (Qwen and OneIG):** prompts longer than 400 characters are
 
215
  </svg>
216
  </button>
217
  </div>
218
+ <p class="app-header-tagline">Compare text-to-image models on quality, speed, and price</p>
219
  </header>
220
  """,
221
  padding=False,
 
230
  return items[0] if items else None
231
 
232
 
233
+ def _dataset_choices(datasets, *, require_samples=False, require_pareto=False):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  return [
235
  (dataset["name"], dataset["id"])
236
+ for dataset in datasets
237
  if (not require_samples or dataset.get("samples"))
238
  and (not require_pareto or _dataset_has_pareto(datasets, dataset["id"]))
239
  ]
 
244
  return bool(dataset and dataset.get("samples"))
245
 
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  def _dataset_has_pareto(datasets, dataset_id):
248
  dataset = _item(datasets, dataset_id)
249
+ columns = getattr(dataset.get("data") if dataset else None, "columns", [])
250
+ return _PARETO_PRICE_COLUMN in columns or _PARETO_TIME_COLUMN in columns
 
 
 
251
 
252
 
253
+ def _dataset_dropdown_update(datasets, tab, dataset_id):
254
  """Limit the dataset list to what the current tab can show."""
 
 
255
  return gr.update(
256
  choices=_dataset_choices(
257
  datasets,
 
258
  require_samples=tab == TAB_SAMPLES
259
  and _dataset_has_samples(datasets, dataset_id),
260
  require_pareto=tab == TAB_PARETO
 
314
  ]
315
 
316
 
317
+ def _model_choices(datasets, dataset_id):
318
  cached = _MODEL_CHOICES_CACHE.get(dataset_id)
319
+ if cached is not None:
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  return cached
321
+ dataset = _item(datasets, dataset_id)
322
+ data = dataset.get("data") if dataset else None
323
+ if data is None or "Model" not in getattr(data, "columns", []):
324
+ _MODEL_CHOICES_CACHE[dataset_id] = []
325
+ return []
326
+ models = data["Model"].dropna().astype(str).unique().tolist()
327
+ # (label, value) so the UI shows the shared name but filters on the raw id.
328
+ choices = sorted(
329
+ ((display_model_name(model), model) for model in models),
330
+ key=lambda item: item[0].casefold(),
331
+ )
332
+ _MODEL_CHOICES_CACHE[dataset_id] = choices
333
+ return choices
334
 
335
 
336
  def _model_choice_values(choices):
 
358
  "Optimized",
359
  ]
360
  _LEADERBOARD_META_COLUMNS = [
 
361
  "Median Generation Time (s)",
362
  "Min Generation Time (s)",
363
  "Price / Image (USD)",
 
364
  "Evaluation Date (UTC)",
365
  "Date",
366
  ]
 
476
  overall_column, ascending=False, na_position="last"
477
  )
478
  ranked = ranked.reset_index(drop=True)
479
+ ranked.insert(0, "Rank", ranked.index + 1)
 
 
 
480
  return ranked
481
 
482
 
 
505
  css = _leaderboard_cell_class(column)
506
  sort_value = escape(_leaderboard_sort_value(column, row[column]), quote=True)
507
  if column == "Model":
 
508
  cells.append(
509
+ f'<td class="{css}" data-sort-value="{sort_value}">'
510
+ f"<strong>{_format_leaderboard_cell(column, row[column])}</strong></td>"
 
511
  )
512
  else:
513
  cells.append(
 
585
  "Arena Art Elo": "Art",
586
  "Arena Portraits Elo": "Portraits",
587
  "Arena Text Rendering Elo": "Text Rendering",
588
+ "Raw Win Rate": "Raw win rate",
589
  "Median Generation Time (s)": "Median generation time",
590
  "Min Generation Time (s)": "Min generation time",
 
591
  "Price / Image (USD)": "Price per image",
 
592
  "Evaluation Date (UTC)": "Date",
593
  "Date": "Date",
594
  }
 
663
  )
664
 
665
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
  def _build_pareto_figure(
667
  data,
668
  score_column,
 
670
  x_title,
671
  x_hover_prefix="",
672
  x_hover_suffix="",
 
673
  ):
674
  scatter = (
675
  data[["Model", score_column, x_column]]
 
686
 
687
  dominated = scatter.loc[[not flag for flag in on_frontier]].copy()
688
  frontier = scatter.loc[on_frontier].sort_values(x_column).copy()
 
 
689
  if not dominated.empty:
690
  dominated["Model"] = dominated["Model"].map(display_model_name)
691
  if not frontier.empty:
 
706
  name="Below frontier",
707
  text=dominated["Model"],
708
  hovertemplate=hover,
 
709
  marker={
710
  "size": 9,
711
+ "color": "#d8b4fe",
712
+ "opacity": 0.8,
713
  "line": {"width": 0},
714
  },
715
  )
 
723
  name="On frontier",
724
  text=frontier["Model"],
725
  hovertemplate=hover,
726
+ line={"color": "#69a45c", "width": 2.5},
 
727
  marker={
728
  "size": 12,
729
+ "color": "#69a45c",
730
+ "line": {"width": 1.5, "color": "#86c077"},
731
  },
732
  )
733
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
734
 
735
  score_label = _display_label(score_column)
736
  fig.update_layout(
 
755
  )
756
  axis_font = {"color": "#fafafa", "size": 13}
757
  tick_font = {"color": "#a3a3a3", "size": 12}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
758
  fig.update_xaxes(
 
 
759
  showgrid=True,
760
  gridcolor="rgba(74, 57, 98, 0.55)",
761
  zeroline=False,
 
774
  return fig
775
 
776
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
777
  def _pareto_axis(data, score_column, x_column, x_title, missing_message, empty_message, **hover):
778
  if x_column not in data.columns:
779
  return None, missing_message
 
789
  return fig, None
790
 
791
 
792
+ def _pareto_pair(data, score_column):
 
 
 
 
 
793
  score_missing = "No score data is available for this metric."
794
  if data is None or not score_column or score_column not in data.columns:
795
  return None, score_missing, None, score_missing
796
 
 
 
 
 
 
 
 
797
  price_fig, price_message = _pareto_axis(
798
  data,
799
  score_column,
800
+ _PARETO_PRICE_COLUMN,
801
+ "Price per image (USD)",
802
+ "Price per image isn't available for this dataset.",
803
  "No models have both a score and a price for this metric.",
804
  x_hover_prefix="$",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
805
  )
806
  time_fig, time_message = _pareto_axis(
807
  data,
808
  score_column,
809
+ _PARETO_TIME_COLUMN,
810
+ "Min generation time (s)",
811
+ "Min generation time isn't available for this dataset.",
812
+ "No models have both a score and a min generation time for this metric.",
813
  x_hover_suffix="s",
 
814
  )
815
  return price_fig, price_message, time_fig, time_message
816
 
817
 
818
  def _pareto_dataset_message(data):
819
+ has_price = data is not None and _PARETO_PRICE_COLUMN in data.columns
820
+ has_time = data is not None and _PARETO_TIME_COLUMN in data.columns
821
  if has_price or has_time:
822
  return None
823
  return (
824
+ "Price per image and min generation time aren't available for "
825
  "this dataset, so these plots can't be drawn."
826
  )
827
 
828
 
829
  def _pareto_slot_note(price_fig, price_message, time_fig, time_message, data):
830
+ has_price = data is not None and _PARETO_PRICE_COLUMN in data.columns
831
+ has_time = data is not None and _PARETO_TIME_COLUMN in data.columns
832
  notes = []
833
  if has_price and not has_time:
834
  notes.append(
835
+ "Min generation time isn't available for this dataset, so only "
836
  "price vs score is shown."
837
  )
838
  elif has_time and not has_price:
839
  notes.append(
840
+ "Price per image isn't available for this dataset, so only min "
841
+ "generation time vs score is shown."
842
  )
843
  if price_fig is None and has_price:
844
  notes.append(price_message)
 
849
  return " ".join(notes)
850
 
851
 
852
+ def _pareto_slot_updates(data, score_columns):
 
 
 
 
 
853
  """Updates for a fixed bank of Gradio Plot slots (visible/hidden)."""
854
  score_columns = [column for column in (score_columns or []) if column]
855
+ has_price = data is not None and _PARETO_PRICE_COLUMN in data.columns
856
+ has_time = data is not None and _PARETO_TIME_COLUMN in data.columns
 
 
857
  dataset_note = _pareto_dataset_message(data)
858
  updates = [_pareto_note_update(dataset_note)]
859
  hide_all_slots = not has_price and not has_time
 
873
  continue
874
  score_column = score_columns[index]
875
  price_fig, price_message, time_fig, time_message = _pareto_pair(
876
+ data, score_column
 
 
 
877
  )
878
  show_price = price_fig is not None
879
  show_time = time_fig is not None
 
900
  return updates
901
 
902
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
903
  def _samples_html(samples, selected_models, num_prompts, seed=0):
904
  if not samples:
905
  return _pareto_unavailable_html(
906
  "Samples aren't available for this dataset."
907
  )
908
+ images = samples.get("images", {})
909
+ models = [model for model in (selected_models or []) if model in images]
 
 
 
910
  if not models:
911
+ models = (samples.get("models") or [])[:2]
912
  return _build_compare_samples_html(samples, models, num_prompts, seed)
913
 
914
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
915
  def _build_compare_samples_html(samples, selected_models, num_prompts, seed=0):
916
  selected_models = list(selected_models or [])[:MAX_COMPARE_MODELS]
 
 
 
917
 
918
  if not selected_models:
919
  return (
 
924
 
925
  shared_prompt_ids = None
926
  for model in selected_models:
927
+ model_prompt_ids = set(samples["images"][model])
928
  shared_prompt_ids = (
929
  model_prompt_ids
930
  if shared_prompt_ids is None
 
944
  rng.shuffle(prompt_pool)
945
  chosen = prompt_pool[: max(1, min(int(num_prompts), len(prompt_pool)))]
946
 
947
+ columns = len(selected_models)
948
  blocks = []
949
  for index, prompt_id in enumerate(chosen, start=1):
950
  prompt_text = escape(samples["prompts"].get(prompt_id, ""))
951
  cells = []
 
 
 
 
 
 
 
952
  for model in selected_models:
953
+ image_url = escape(samples["images"][model][prompt_id], quote=True)
954
  cells.append(
955
+ f"""
956
+ <div class="compare-cell">
957
+ <div class="compare-model-label">{escape(display_model_name(model))}</div>
958
+ <a href="{image_url}" target="_blank" rel="noopener noreferrer">
959
+ <img src="{image_url}" alt="{escape(display_model_name(model))} sample" loading="lazy" />
960
+ </a>
961
+ </div>
962
+ """
963
  )
 
964
  blocks.append(
965
  f"""
966
  <div class="compare-prompt-block">
967
  <div class="compare-prompt-meta">
968
  <span>Prompt {index}</span>
969
+ <span>{escape(prompt_id)}</span>
970
  </div>
971
  <p class="compare-prompt-text">{prompt_text}</p>
972
  <div class="compare-row" style="grid-template-columns: repeat({columns}, minmax(0, 1fr));">
 
994
  metric_id = _coerce_metric(
995
  datasets, metrics, default_dataset_id, default_metric_id
996
  )
 
997
  with gr.Row(elem_classes="view-filters"):
 
 
 
 
 
 
 
 
 
998
  dataset_dd = gr.Dropdown(
999
+ choices=_dataset_choices(datasets),
1000
  value=default_dataset_id,
1001
  label="Dataset",
1002
  type="value",
 
1028
  min_width=180,
1029
  elem_classes="filter-chips",
1030
  )
1031
+ return dataset_dd, metric_dd, models_dd
1032
 
1033
 
1034
  def render_image_workspace(datasets, metrics, default_dataset_id, default_metric_id):
 
1043
  with gr.Column(elem_classes="workspace-filters") as filters_host:
1044
  gr.Markdown(
1045
  "<p class='filter-help'>"
1046
+ "These filters apply to Leaderboards, Pareto plots, and Samples. "
1047
+ "On Samples, only datasets we have generations for are listed. "
1048
+ "On Pareto plots, only datasets with price or generation time "
1049
+ "are listed. Search in Models, or leave it empty to include "
1050
+ "every model."
 
 
1051
  "</p>",
1052
  elem_classes="filter-help-host",
1053
  )
1054
+ dataset_dd, metric_dd, models_dd = _filter_row(
1055
  datasets, metrics, default_dataset_id, None
1056
  )
1057
  with gr.Tabs(elem_classes="main-tabs") as main_tabs:
 
1117
  ) as pp_tab:
1118
  gr.Markdown(
1119
  "<p class='view-help'>"
1120
+ "Score against price and generation time. Green points are on the "
1121
+ "frontier; lavender points sit below it. Hover a point to see "
1122
+ "which model it is."
 
 
 
 
1123
  "</p>",
1124
  elem_classes="view-help-host",
1125
  )
 
 
 
 
 
 
 
 
 
 
 
1126
  pareto_dataset_note = gr.HTML(
1127
  "",
1128
  padding=False,
 
1148
  min_width=320,
1149
  elem_classes="pareto-col",
1150
  ) as slot_price_col:
1151
+ gr.Markdown(
1152
+ "#### Price vs score",
1153
+ elem_classes="pareto-subhead",
1154
  )
1155
  slot_price = gr.Plot(
1156
  value=None,
 
1162
  min_width=320,
1163
  elem_classes="pareto-col",
1164
  ) as slot_time_col:
1165
+ gr.Markdown(
1166
+ "#### Min generation time vs score",
1167
+ elem_classes="pareto-subhead",
1168
  )
1169
  slot_time = gr.Plot(
1170
  value=None,
 
1185
  slot_layout,
1186
  slot_price_col,
1187
  slot_price,
 
1188
  slot_time_col,
1189
  slot_time,
 
1190
  )
1191
  )
1192
 
 
1198
  with gr.Column(visible=bool(initial_samples)) as samples_panel:
1199
  gr.Markdown(
1200
  f"<p class='view-help'>"
1201
+ f"The same prompts, side by side. Select up to "
 
1202
  f"<strong>{MAX_COMPARE_MODELS}</strong> models above, or leave "
1203
  f"Models empty for two defaults."
1204
  f"</p>",
 
1235
  with gr.TabItem("About", id=TAB_ABOUT) as about_tab:
1236
  render_about()
1237
 
1238
+ def _synced_filters(dataset_id, metric_id, models, *, clear_metric=False):
 
 
1239
  if clear_metric:
1240
  metric_id = []
1241
  else:
1242
  metric_id = _coerce_metric(datasets, metrics, dataset_id, metric_id)
1243
+ model_choices = _model_choices(datasets, dataset_id)
 
 
1244
  model_values = set(_model_choice_values(model_choices))
1245
  models = [model for model in (models or []) if model in model_values]
1246
  metric_choices = _metric_dropdown_choices(datasets, metrics, dataset_id)
 
1312
  ):
1313
  prev = dict(view_state or {})
1314
  extras = extras or {}
 
 
 
 
1315
  return {
1316
  "dataset_id": dataset_id,
 
 
1317
  "metric_id": metric_id,
1318
  "models": list(models or []),
1319
  "current_tab": tab,
 
1324
  "optimized": list(
1325
  extras.get("optimized", prev.get("optimized") or [])
1326
  ),
 
 
1327
  "stale": {
1328
  TAB_LEADERBOARDS: not flags["include_leaderboard"],
1329
  TAB_PARETO: not flags["include_pareto"],
 
1383
  include_leaderboard=True,
1384
  include_pareto=False,
1385
  include_samples=False,
 
 
1386
  ):
1387
  view = resolve_view(datasets, metrics, dataset_id, metric_id)
1388
  data = view["data"]
 
1403
  ranking_html = gr.skip()
1404
  if include_pareto:
1405
  pareto_data = _filter_leaderboard(data, [], [], [], models=models)
1406
+ pareto_updates = _pareto_slot_updates(pareto_data, view["score_columns"])
 
 
 
 
 
1407
  else:
1408
  pareto_updates = _pareto_skip_updates()
1409
  if include_samples:
 
1442
  tab = view_state.get("current_tab") or TAB_LEADERBOARDS
1443
  selected_raw = _normalize_metric_ids(metric_id)
1444
  incoming_models = list(models or [])
1445
+ dataset_changed = source == "dataset" and dataset_id != view_state.get(
 
1446
  "dataset_id"
1447
  )
1448
+
1449
+ if source == "dataset":
 
 
 
 
 
 
1450
  synced = _synced_filters(
1451
+ dataset_id, metric_id, models, clear_metric=dataset_changed
 
 
 
 
1452
  )
1453
  dataset_id, metric_id, models = synced[:3]
1454
  metric_update, models_update = synced[3], synced[4]
 
1486
  ):
1487
  return None
1488
 
1489
+ selected_tab = tab
1490
  extras = (
1491
  list(platform_value or []),
1492
  list(owner_value or []),
1493
  list(optimized_value or []),
1494
  )
1495
  extra_updates = None
1496
+ can_pareto = _dataset_has_pareto(datasets, dataset_id)
1497
+ can_samples = _dataset_has_samples(datasets, dataset_id)
1498
+ if source == "dataset":
1499
+ if tab == TAB_SAMPLES and not can_samples:
1500
+ selected_tab = TAB_LEADERBOARDS
1501
+ elif tab == TAB_PARETO and not can_pareto:
1502
+ selected_tab = TAB_LEADERBOARDS
1503
  view = resolve_view(datasets, metrics, dataset_id, metric_id)
1504
  extra_updates = _leaderboard_extras(
1505
  view["data"] if view else None,
 
1537
  extras[2],
1538
  num_prompts,
1539
  seed,
 
 
1540
  **flags,
1541
  ),
1542
  "state": _commit_state(
 
1550
  ),
1551
  }
1552
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1553
  def on_dataset(
1554
  dataset_id,
1555
  metric_id,
 
1677
  )
1678
  dataset_update = _dataset_dropdown_update(datasets, tab, dataset_id)
1679
  metric_id = _coerce_metric(datasets, metrics, dataset_id, metric_id)
1680
+ models = list(models or [])
 
 
 
 
 
 
 
 
 
 
1681
  view_state["current_tab"] = tab
1682
  view_state["dataset_id"] = dataset_id
1683
  view_state["metric_id"] = metric_id
 
1714
  filters_vis,
1715
  dataset_update,
1716
  metric_vis,
1717
+ gr.skip(),
1718
  *lb_filters,
1719
  )
1720
  tab_select = (
 
1739
  optimized_value,
1740
  num_prompts,
1741
  seed,
 
 
1742
  **flags,
1743
  )
1744
  stale[tab] = False
 
1795
  next_seed,
1796
  )
1797
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1798
  def _on_tab(tab):
1799
  def handler(
1800
  dataset_id,
 
1823
  handler.__name__ = f"on_tab_{tab}"
1824
  return handler
1825
 
 
1826
  view_state = gr.State(
1827
  {
1828
  "dataset_id": default_dataset_id,
 
 
1829
  "metric_id": None,
1830
  "models": [],
1831
  "current_tab": TAB_LEADERBOARDS,
1832
  "platform": [],
1833
  "owner": [],
1834
  "optimized": [],
 
 
1835
  "stale": {
1836
  TAB_LEADERBOARDS: False,
1837
  TAB_PARETO: True,
 
1843
  pareto_dataset_note,
1844
  *[
1845
  component
1846
+ for slot_group, slot_title, slot_note, slot_layout, slot_price_col, slot_price, slot_time_col, slot_time in pareto_slots
1847
  for component in (
1848
  slot_group,
1849
  slot_title,
 
1856
  )
1857
  ],
1858
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1859
  view_inputs = [
1860
  platform,
1861
  owner,
 
1887
  main_tabs,
1888
  view_state,
1889
  ]
 
 
 
 
 
 
1890
  dataset_dd.change(
1891
  on_dataset,
1892
  inputs=filter_inputs,
 
1960
  show_progress="hidden",
1961
  )
1962
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1963
  prompt_count.change(
1964
  on_samples_controls,
1965
  inputs=[dataset_dd, models_dd, prompt_count, seed_state],