Spaces:
Running
Running
prompt-samples
#6
by minette-kaunismaki - opened
- app.py +163 -21
- data/video-editing-leaderboard.csv +12 -0
- data/video_editing_combined/generations.jsonl +3 -0
- data/video_editing_combined/prompts.jsonl +78 -0
- model_display.py +17 -1
- ui.py +403 -72
app.py
CHANGED
|
@@ -581,14 +581,19 @@ 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 .rank,
|
| 585 |
.prose .ranking-table .rank,
|
| 586 |
.ranking-table th.rank {
|
| 587 |
position: sticky !important;
|
| 588 |
left: 0 !important;
|
| 589 |
-
width:
|
| 590 |
-
min-width:
|
| 591 |
-
|
|
|
|
| 592 |
}
|
| 593 |
.ranking-table .model-cell,
|
| 594 |
.prose .ranking-table .model-cell {
|
|
@@ -598,6 +603,7 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
|
|
| 598 |
min-width: 140px;
|
| 599 |
max-width: none;
|
| 600 |
background: transparent !important;
|
|
|
|
| 601 |
}
|
| 602 |
.ranking-table th.model-cell,
|
| 603 |
.prose .ranking-table th.model-cell {
|
|
@@ -608,6 +614,7 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
|
|
| 608 |
min-width: 140px;
|
| 609 |
max-width: none;
|
| 610 |
background: var(--pruna-bg-header) !important;
|
|
|
|
| 611 |
}
|
| 612 |
.ranking-table tbody tr:hover .model-cell {
|
| 613 |
background: var(--pruna-table-hover) !important;
|
|
@@ -1107,11 +1114,11 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
|
|
| 1107 |
max-height: min(70vh, 720px);
|
| 1108 |
overflow-x: auto;
|
| 1109 |
overflow-y: auto;
|
| 1110 |
-
-
|
| 1111 |
-
overscroll-behavior-x: contain;
|
| 1112 |
}
|
| 1113 |
.ranking-table,
|
| 1114 |
.prose .ranking-table {
|
|
|
|
| 1115 |
width: 100%;
|
| 1116 |
margin: 0 !important;
|
| 1117 |
overflow: visible;
|
|
@@ -1187,10 +1194,14 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
|
|
| 1187 |
.prose .ranking-table .rank {
|
| 1188 |
position: sticky;
|
| 1189 |
left: 0;
|
| 1190 |
-
z-index:
|
| 1191 |
box-sizing: border-box;
|
| 1192 |
-
width:
|
| 1193 |
-
min-width:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1194 |
color: var(--pruna-lavender) !important;
|
| 1195 |
font-weight: 700 !important;
|
| 1196 |
text-align: center;
|
|
@@ -1207,18 +1218,21 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
|
|
| 1207 |
.ranking-table .model-cell,
|
| 1208 |
.prose .ranking-table .model-cell {
|
| 1209 |
position: sticky;
|
| 1210 |
-
left:
|
| 1211 |
-
z-index:
|
|
|
|
| 1212 |
min-width: 180px;
|
| 1213 |
max-width: 260px;
|
| 1214 |
background: var(--pruna-table-sticky) !important;
|
|
|
|
| 1215 |
}
|
| 1216 |
.ranking-table th.model-cell,
|
| 1217 |
.prose .ranking-table th.model-cell {
|
| 1218 |
top: 0;
|
| 1219 |
-
left:
|
| 1220 |
z-index: 5;
|
| 1221 |
background: var(--pruna-bg-header) !important;
|
|
|
|
| 1222 |
}
|
| 1223 |
.ranking-table tbody tr:hover .rank,
|
| 1224 |
.ranking-table tbody tr:hover .model-cell {
|
|
@@ -1769,6 +1783,9 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
|
|
| 1769 |
max-width: 100% !important;
|
| 1770 |
}
|
| 1771 |
.compare-cell { min-width: 0; }
|
|
|
|
|
|
|
|
|
|
| 1772 |
.compare-model-label {
|
| 1773 |
margin-bottom: 6px;
|
| 1774 |
color: var(--pruna-lavender);
|
|
@@ -1776,15 +1793,23 @@ button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !import
|
|
| 1776 |
font-weight: 700;
|
| 1777 |
word-break: break-word;
|
| 1778 |
}
|
| 1779 |
-
.compare-cell img
|
|
|
|
| 1780 |
display: block;
|
| 1781 |
width: 100%;
|
| 1782 |
-
aspect-ratio: 1 / 1;
|
| 1783 |
-
object-fit: cover;
|
| 1784 |
border-radius: 12px;
|
| 1785 |
border: 1px solid var(--pruna-border);
|
| 1786 |
background: var(--pruna-bg-elevated);
|
| 1787 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1788 |
.compare-empty,
|
| 1789 |
.pareto-note-copy {
|
| 1790 |
margin: 0;
|
|
@@ -2143,14 +2168,20 @@ def load_sample_comparison_data(folder):
|
|
| 2143 |
return None
|
| 2144 |
|
| 2145 |
prompts = {}
|
|
|
|
| 2146 |
with prompts_path.open() as handle:
|
| 2147 |
for line in handle:
|
| 2148 |
if not line.strip():
|
| 2149 |
continue
|
| 2150 |
row = json.loads(line)
|
| 2151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2152 |
|
| 2153 |
images = defaultdict(dict)
|
|
|
|
| 2154 |
with generations_path.open() as handle:
|
| 2155 |
for line in handle:
|
| 2156 |
if not line.strip():
|
|
@@ -2158,20 +2189,33 @@ def load_sample_comparison_data(folder):
|
|
| 2158 |
row = json.loads(line)
|
| 2159 |
model_id = row["model_id"]
|
| 2160 |
prompt_id = row["prompt_id"]
|
| 2161 |
-
|
| 2162 |
-
if
|
| 2163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2164 |
|
| 2165 |
models = sorted(images)
|
| 2166 |
if not models or not prompts:
|
| 2167 |
return None
|
| 2168 |
|
| 2169 |
-
|
| 2170 |
"prompts": prompts,
|
| 2171 |
"images": {model: dict(prompt_map) for model, prompt_map in images.items()},
|
| 2172 |
"models": models,
|
| 2173 |
"prompt_ids": sorted(prompts),
|
|
|
|
| 2174 |
}
|
|
|
|
|
|
|
|
|
|
| 2175 |
|
| 2176 |
|
| 2177 |
def _as_numeric(df, columns):
|
|
@@ -2301,6 +2345,60 @@ def load_qwen_combined_dataframe(path):
|
|
| 2301 |
return df.reset_index(drop=True)
|
| 2302 |
|
| 2303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2304 |
df = load_oneig_dataframe(oneig_path)
|
| 2305 |
|
| 2306 |
oneig_metric_columns = [
|
|
@@ -2348,6 +2446,10 @@ qwen_combined_dir = _resolve_data_path(
|
|
| 2348 |
data_dir / "qwen_image_bench_combined",
|
| 2349 |
space_root.parent / "qwen_image_bench_combined",
|
| 2350 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2351 |
qwen_path = _resolve_data_path(
|
| 2352 |
data_dir / "qwen_image_bench_model_price_and_median_generation_time_10_august.csv",
|
| 2353 |
space_root.parent / "qwen_image_bench_model_price_and_median_generation_time_10_august.csv",
|
|
@@ -2360,10 +2462,15 @@ arena_path = _resolve_data_path(
|
|
| 2360 |
data_dir / "arena_ai_text_to_image_leaderboard.csv",
|
| 2361 |
space_root.parent / "arena_ai_text_to_image_leaderboard.csv",
|
| 2362 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2363 |
|
| 2364 |
qwen_df = load_qwen_combined_dataframe(qwen_path)
|
| 2365 |
aa_df = load_artificial_analysis_dataframe(aa_path)
|
| 2366 |
arena_df = load_arena_ai_dataframe(arena_path)
|
|
|
|
| 2367 |
qwen_display_columns = [
|
| 2368 |
col
|
| 2369 |
for col in [
|
|
@@ -2395,9 +2502,22 @@ arena_display_columns = [
|
|
| 2395 |
]
|
| 2396 |
if col in arena_df.columns
|
| 2397 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2398 |
|
| 2399 |
oneig_samples = load_sample_comparison_data(oneig_combined_dir)
|
| 2400 |
qwen_samples = load_sample_comparison_data(qwen_combined_dir)
|
|
|
|
| 2401 |
|
| 2402 |
metrics = [
|
| 2403 |
{"id": "datapoint_elo", "column": "Datapoint Elo"},
|
|
@@ -2456,11 +2576,27 @@ arena_metric_ids = _metric_ids_for(
|
|
| 2456 |
"arena_text",
|
| 2457 |
],
|
| 2458 |
)
|
|
|
|
| 2459 |
|
| 2460 |
datasets = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2461 |
{
|
| 2462 |
"id": "qwen",
|
| 2463 |
"name": "Qwen Image Dataset",
|
|
|
|
| 2464 |
"data": qwen_df,
|
| 2465 |
"columns": qwen_display_columns,
|
| 2466 |
"metric_ids": qwen_metric_ids,
|
|
@@ -2470,6 +2606,7 @@ datasets = [
|
|
| 2470 |
{
|
| 2471 |
"id": "oneig",
|
| 2472 |
"name": "OneIG Alignment Dataset",
|
|
|
|
| 2473 |
"data": oneig_df,
|
| 2474 |
"columns": oneig_display_columns,
|
| 2475 |
"metric_ids": oneig_metric_ids,
|
|
@@ -2482,6 +2619,7 @@ datasets = [
|
|
| 2482 |
{
|
| 2483 |
"id": "artificial_analysis",
|
| 2484 |
"name": "Artificial Analysis Dataset",
|
|
|
|
| 2485 |
"data": aa_df,
|
| 2486 |
"columns": aa_display_columns,
|
| 2487 |
"metric_ids": aa_metric_ids,
|
|
@@ -2491,6 +2629,7 @@ datasets = [
|
|
| 2491 |
{
|
| 2492 |
"id": "arena_ai",
|
| 2493 |
"name": "Arena AI Dataset",
|
|
|
|
| 2494 |
"data": arena_df,
|
| 2495 |
"columns": arena_display_columns,
|
| 2496 |
"metric_ids": arena_metric_ids,
|
|
@@ -2501,8 +2640,11 @@ datasets = [
|
|
| 2501 |
datasets = [dataset for dataset in datasets if dataset["metric_ids"]]
|
| 2502 |
|
| 2503 |
DEFAULT_DATASET_ID = next(
|
| 2504 |
-
(dataset["id"] for dataset in datasets if dataset["id"] == "
|
| 2505 |
-
|
|
|
|
|
|
|
|
|
|
| 2506 |
)
|
| 2507 |
DEFAULT_METRIC_ID = None
|
| 2508 |
|
|
|
|
| 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 {
|
|
|
|
| 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 {
|
|
|
|
| 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;
|
|
|
|
| 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 |
.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 |
.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 {
|
|
|
|
| 1783 |
max-width: 100% !important;
|
| 1784 |
}
|
| 1785 |
.compare-cell { min-width: 0; }
|
| 1786 |
+
.compare-cell.compare-source .compare-model-label {
|
| 1787 |
+
color: var(--pruna-text-muted);
|
| 1788 |
+
}
|
| 1789 |
.compare-model-label {
|
| 1790 |
margin-bottom: 6px;
|
| 1791 |
color: var(--pruna-lavender);
|
|
|
|
| 1793 |
font-weight: 700;
|
| 1794 |
word-break: break-word;
|
| 1795 |
}
|
| 1796 |
+
.compare-cell img,
|
| 1797 |
+
.compare-cell video {
|
| 1798 |
display: block;
|
| 1799 |
width: 100%;
|
|
|
|
|
|
|
| 1800 |
border-radius: 12px;
|
| 1801 |
border: 1px solid var(--pruna-border);
|
| 1802 |
background: var(--pruna-bg-elevated);
|
| 1803 |
}
|
| 1804 |
+
.compare-cell img {
|
| 1805 |
+
aspect-ratio: 1 / 1;
|
| 1806 |
+
object-fit: cover;
|
| 1807 |
+
}
|
| 1808 |
+
.compare-cell video {
|
| 1809 |
+
aspect-ratio: 16 / 9;
|
| 1810 |
+
max-height: 360px;
|
| 1811 |
+
object-fit: contain;
|
| 1812 |
+
}
|
| 1813 |
.compare-empty,
|
| 1814 |
.pareto-note-copy {
|
| 1815 |
margin: 0;
|
|
|
|
| 2168 |
return None
|
| 2169 |
|
| 2170 |
prompts = {}
|
| 2171 |
+
source_videos = {}
|
| 2172 |
with prompts_path.open() as handle:
|
| 2173 |
for line in handle:
|
| 2174 |
if not line.strip():
|
| 2175 |
continue
|
| 2176 |
row = json.loads(line)
|
| 2177 |
+
prompt_id = row["prompt_id"]
|
| 2178 |
+
prompts[prompt_id] = row.get("text", "")
|
| 2179 |
+
source_video = row.get("source_video")
|
| 2180 |
+
if source_video:
|
| 2181 |
+
source_videos[prompt_id] = source_video
|
| 2182 |
|
| 2183 |
images = defaultdict(dict)
|
| 2184 |
+
kinds = set()
|
| 2185 |
with generations_path.open() as handle:
|
| 2186 |
for line in handle:
|
| 2187 |
if not line.strip():
|
|
|
|
| 2189 |
row = json.loads(line)
|
| 2190 |
model_id = row["model_id"]
|
| 2191 |
prompt_id = row["prompt_id"]
|
| 2192 |
+
media_url = row.get("image") or row.get("video")
|
| 2193 |
+
if row.get("video"):
|
| 2194 |
+
kinds.add("video")
|
| 2195 |
+
elif row.get("image"):
|
| 2196 |
+
kinds.add("image")
|
| 2197 |
+
if model_id and prompt_id and media_url:
|
| 2198 |
+
images[model_id][prompt_id] = media_url
|
| 2199 |
+
if prompt_id and prompt_id not in source_videos:
|
| 2200 |
+
params = row.get("params") or {}
|
| 2201 |
+
input_video = params.get("input_video") or row.get("input_video")
|
| 2202 |
+
if input_video:
|
| 2203 |
+
source_videos[prompt_id] = input_video
|
| 2204 |
|
| 2205 |
models = sorted(images)
|
| 2206 |
if not models or not prompts:
|
| 2207 |
return None
|
| 2208 |
|
| 2209 |
+
loaded = {
|
| 2210 |
"prompts": prompts,
|
| 2211 |
"images": {model: dict(prompt_map) for model, prompt_map in images.items()},
|
| 2212 |
"models": models,
|
| 2213 |
"prompt_ids": sorted(prompts),
|
| 2214 |
+
"kind": "video" if "video" in kinds else "image",
|
| 2215 |
}
|
| 2216 |
+
if source_videos:
|
| 2217 |
+
loaded["source_videos"] = source_videos
|
| 2218 |
+
return loaded
|
| 2219 |
|
| 2220 |
|
| 2221 |
def _as_numeric(df, columns):
|
|
|
|
| 2345 |
return df.reset_index(drop=True)
|
| 2346 |
|
| 2347 |
|
| 2348 |
+
def load_video_editing_dataframe(path):
|
| 2349 |
+
"""Load the video-to-video editing leaderboard."""
|
| 2350 |
+
df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
|
| 2351 |
+
df = df.rename(
|
| 2352 |
+
columns={
|
| 2353 |
+
"display_name": "Model",
|
| 2354 |
+
"elo": "Datapoint Elo",
|
| 2355 |
+
"min_generation_s": "Min Generation Time (s)",
|
| 2356 |
+
"median_generation_s": "Median Generation Time (s)",
|
| 2357 |
+
"p20_generation_s": "P20 Generation Time (s)",
|
| 2358 |
+
"generation_s_per_output_video_s": "Time / Output Video Second (s)",
|
| 2359 |
+
"predict_time_s_per_output_video_s": "Predict Time / Output Video Second (s)",
|
| 2360 |
+
"model_execution_time_s_per_output_video_s": (
|
| 2361 |
+
"Execution Time / Output Video Second (s)"
|
| 2362 |
+
),
|
| 2363 |
+
"price": "Price / Second of Video (USD)",
|
| 2364 |
+
}
|
| 2365 |
+
)
|
| 2366 |
+
df = df.drop(columns=["wandb_run_ids", "n_generations"], errors="ignore")
|
| 2367 |
+
df["Model"] = df["Model"].astype(str).str.strip()
|
| 2368 |
+
df = _as_numeric(
|
| 2369 |
+
df,
|
| 2370 |
+
[
|
| 2371 |
+
"Datapoint Elo",
|
| 2372 |
+
"Min Generation Time (s)",
|
| 2373 |
+
"Median Generation Time (s)",
|
| 2374 |
+
"P20 Generation Time (s)",
|
| 2375 |
+
"Time / Output Video Second (s)",
|
| 2376 |
+
"Predict Time / Output Video Second (s)",
|
| 2377 |
+
"Execution Time / Output Video Second (s)",
|
| 2378 |
+
"Price / Second of Video (USD)",
|
| 2379 |
+
],
|
| 2380 |
+
)
|
| 2381 |
+
end_to_end = df.get("Time / Output Video Second (s)")
|
| 2382 |
+
execution = df.get("Execution Time / Output Video Second (s)")
|
| 2383 |
+
if end_to_end is not None:
|
| 2384 |
+
if "model_id" in df.columns:
|
| 2385 |
+
is_ours = df["model_id"].astype(str).str.lower().str.startswith(
|
| 2386 |
+
"p_video_edit"
|
| 2387 |
+
)
|
| 2388 |
+
else:
|
| 2389 |
+
is_ours = df["Model"].astype(str).str.casefold().str.startswith(
|
| 2390 |
+
"p-video-edit"
|
| 2391 |
+
)
|
| 2392 |
+
if execution is None:
|
| 2393 |
+
pareto_time = end_to_end
|
| 2394 |
+
else:
|
| 2395 |
+
ours_time = execution.where(execution.notna(), end_to_end)
|
| 2396 |
+
pareto_time = end_to_end.where(~is_ours, ours_time)
|
| 2397 |
+
df["Pareto Time / Output Video Second (s)"] = pareto_time
|
| 2398 |
+
df = df.drop(columns=["model_id"], errors="ignore")
|
| 2399 |
+
return df.reset_index(drop=True)
|
| 2400 |
+
|
| 2401 |
+
|
| 2402 |
df = load_oneig_dataframe(oneig_path)
|
| 2403 |
|
| 2404 |
oneig_metric_columns = [
|
|
|
|
| 2446 |
data_dir / "qwen_image_bench_combined",
|
| 2447 |
space_root.parent / "qwen_image_bench_combined",
|
| 2448 |
)
|
| 2449 |
+
video_combined_dir = _resolve_data_path(
|
| 2450 |
+
data_dir / "video_editing_combined",
|
| 2451 |
+
space_root.parent / "video_editing_combined",
|
| 2452 |
+
)
|
| 2453 |
qwen_path = _resolve_data_path(
|
| 2454 |
data_dir / "qwen_image_bench_model_price_and_median_generation_time_10_august.csv",
|
| 2455 |
space_root.parent / "qwen_image_bench_model_price_and_median_generation_time_10_august.csv",
|
|
|
|
| 2462 |
data_dir / "arena_ai_text_to_image_leaderboard.csv",
|
| 2463 |
space_root.parent / "arena_ai_text_to_image_leaderboard.csv",
|
| 2464 |
)
|
| 2465 |
+
video_path = _resolve_data_path(
|
| 2466 |
+
data_dir / "video-editing-leaderboard.csv",
|
| 2467 |
+
space_root.parent / "video-editing-leaderboard.csv",
|
| 2468 |
+
)
|
| 2469 |
|
| 2470 |
qwen_df = load_qwen_combined_dataframe(qwen_path)
|
| 2471 |
aa_df = load_artificial_analysis_dataframe(aa_path)
|
| 2472 |
arena_df = load_arena_ai_dataframe(arena_path)
|
| 2473 |
+
video_df = load_video_editing_dataframe(video_path)
|
| 2474 |
qwen_display_columns = [
|
| 2475 |
col
|
| 2476 |
for col in [
|
|
|
|
| 2502 |
]
|
| 2503 |
if col in arena_df.columns
|
| 2504 |
]
|
| 2505 |
+
video_display_columns = [
|
| 2506 |
+
col
|
| 2507 |
+
for col in [
|
| 2508 |
+
"Model",
|
| 2509 |
+
"Datapoint Elo",
|
| 2510 |
+
"Time / Output Video Second (s)",
|
| 2511 |
+
"Median Generation Time (s)",
|
| 2512 |
+
"Min Generation Time (s)",
|
| 2513 |
+
"Price / Second of Video (USD)",
|
| 2514 |
+
]
|
| 2515 |
+
if col in video_df.columns
|
| 2516 |
+
]
|
| 2517 |
|
| 2518 |
oneig_samples = load_sample_comparison_data(oneig_combined_dir)
|
| 2519 |
qwen_samples = load_sample_comparison_data(qwen_combined_dir)
|
| 2520 |
+
video_samples = load_sample_comparison_data(video_combined_dir)
|
| 2521 |
|
| 2522 |
metrics = [
|
| 2523 |
{"id": "datapoint_elo", "column": "Datapoint Elo"},
|
|
|
|
| 2576 |
"arena_text",
|
| 2577 |
],
|
| 2578 |
)
|
| 2579 |
+
video_metric_ids = _metric_ids_for(video_df, ["datapoint_elo"])
|
| 2580 |
|
| 2581 |
datasets = [
|
| 2582 |
+
{
|
| 2583 |
+
"id": "video_editing",
|
| 2584 |
+
"name": "Pruna Internal Video-Edit Benchmark",
|
| 2585 |
+
"modality": "video_to_video",
|
| 2586 |
+
"data": video_df,
|
| 2587 |
+
"columns": video_display_columns,
|
| 2588 |
+
"metric_ids": video_metric_ids,
|
| 2589 |
+
"note": (
|
| 2590 |
+
"Datapoint Elo from pairwise video-edit preference. Price is USD "
|
| 2591 |
+
"per second of output video. Generation time per second of video "
|
| 2592 |
+
"is end-to-end wall time to produce one second of output."
|
| 2593 |
+
),
|
| 2594 |
+
"samples": video_samples,
|
| 2595 |
+
},
|
| 2596 |
{
|
| 2597 |
"id": "qwen",
|
| 2598 |
"name": "Qwen Image Dataset",
|
| 2599 |
+
"modality": "text_to_image",
|
| 2600 |
"data": qwen_df,
|
| 2601 |
"columns": qwen_display_columns,
|
| 2602 |
"metric_ids": qwen_metric_ids,
|
|
|
|
| 2606 |
{
|
| 2607 |
"id": "oneig",
|
| 2608 |
"name": "OneIG Alignment Dataset",
|
| 2609 |
+
"modality": "text_to_image",
|
| 2610 |
"data": oneig_df,
|
| 2611 |
"columns": oneig_display_columns,
|
| 2612 |
"metric_ids": oneig_metric_ids,
|
|
|
|
| 2619 |
{
|
| 2620 |
"id": "artificial_analysis",
|
| 2621 |
"name": "Artificial Analysis Dataset",
|
| 2622 |
+
"modality": "text_to_image",
|
| 2623 |
"data": aa_df,
|
| 2624 |
"columns": aa_display_columns,
|
| 2625 |
"metric_ids": aa_metric_ids,
|
|
|
|
| 2629 |
{
|
| 2630 |
"id": "arena_ai",
|
| 2631 |
"name": "Arena AI Dataset",
|
| 2632 |
+
"modality": "text_to_image",
|
| 2633 |
"data": arena_df,
|
| 2634 |
"columns": arena_display_columns,
|
| 2635 |
"metric_ids": arena_metric_ids,
|
|
|
|
| 2640 |
datasets = [dataset for dataset in datasets if dataset["metric_ids"]]
|
| 2641 |
|
| 2642 |
DEFAULT_DATASET_ID = next(
|
| 2643 |
+
(dataset["id"] for dataset in datasets if dataset["id"] == "video_editing"),
|
| 2644 |
+
next(
|
| 2645 |
+
(dataset["id"] for dataset in datasets if dataset["id"] == "qwen"),
|
| 2646 |
+
datasets[0]["id"] if datasets else None,
|
| 2647 |
+
),
|
| 2648 |
)
|
| 2649 |
DEFAULT_METRIC_ID = None
|
| 2650 |
|
data/video-editing-leaderboard.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
ltx_2_3_quality_reference_video_to_video__fal,LTX 2.3 Video Edit,911,p19ks8ad,73,60.768441981999786,73.62109239100027,70.20137865180223,15.83,,,0.054
|
| 6 |
+
lucy_edit_pro__fal,Lucy Edit Pro,879,na6bz9xx,72,118.3459930579993,136.44442766549764,124.13885582720104,27.18,,,0.15
|
| 7 |
+
minimax_h3_reference_to_video__fal,MiniMax H3 Reference-to-Video,1060,639xmakz,63,180.8385945170012,308.29198316100155,248.2394383729996,58.31,,,0.06
|
| 8 |
+
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
|
| 9 |
+
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
|
| 10 |
+
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
|
| 11 |
+
wan_2_7_video_edit__wavespeed,Wan 2.7 Video Edit,1055,9lq803be,66,134.3744560209998,313.957433804002,219.2491260079987,68.04,,,0.2
|
| 12 |
+
|
data/video_editing_combined/generations.jsonl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3ec4ea0a431484e65f30990c8cc4292b00c665be96db587775426da1c84a4ab8
|
| 3 |
+
size 762227
|
data/video_editing_combined/prompts.jsonl
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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"}
|
model_display.py
CHANGED
|
@@ -88,6 +88,22 @@ MODEL_DISPLAY_NAMES = {
|
|
| 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 |
# Others overlapping P-Bench
|
| 92 |
"z_image": "Z-Image",
|
| 93 |
"glm_image": "GLM-Image",
|
|
@@ -210,6 +226,6 @@ def display_model_name(model_id) -> str:
|
|
| 210 |
if raw in MODEL_DISPLAY_NAMES:
|
| 211 |
return MODEL_DISPLAY_NAMES[raw]
|
| 212 |
# Already a human label (spaces / punctuation) — keep as-is.
|
| 213 |
-
if re.search(r"[\s.\[\]()]", raw):
|
| 214 |
return raw
|
| 215 |
return _prettify_snake_case(raw)
|
|
|
|
| 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 |
+
# Video-to-video leaderboard
|
| 99 |
+
"gemini_omni_flash_edit__fal": "Gemini Omni Flash Edit",
|
| 100 |
+
"grok_imagine_video__replicate": "Grok Imagine Video",
|
| 101 |
+
"happyhorse_1_0__wavespeed": "HappyHorse 1.0",
|
| 102 |
+
"ltx_2_3_quality_reference_video_to_video__fal": "LTX 2.3 Video Edit",
|
| 103 |
+
"lucy_edit_pro__fal": "Lucy Edit Pro",
|
| 104 |
+
"minimax_h3_reference_to_video__fal": "MiniMax H3 Reference-to-Video",
|
| 105 |
+
"seedance_2_5_video_edit_turbo__wavespeed": "Seedance 2.5 Video Edit Turbo",
|
| 106 |
+
"wan_2_7_video_edit__wavespeed": "Wan 2.7 Video Edit",
|
| 107 |
# Others overlapping P-Bench
|
| 108 |
"z_image": "Z-Image",
|
| 109 |
"glm_image": "GLM-Image",
|
|
|
|
| 226 |
if raw in MODEL_DISPLAY_NAMES:
|
| 227 |
return MODEL_DISPLAY_NAMES[raw]
|
| 228 |
# Already a human label (spaces / punctuation) — keep as-is.
|
| 229 |
+
if re.search(r"[\s.\[\]()-]", raw):
|
| 230 |
return raw
|
| 231 |
return _prettify_snake_case(raw)
|
ui.py
CHANGED
|
@@ -25,19 +25,41 @@ 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_TIME_COLUMN = "Min Generation Time (s)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
_PARETO_SCALE_CHOICES = [
|
| 30 |
("Log", "Logarithmic"),
|
| 31 |
("Linear", "Linear"),
|
| 32 |
]
|
| 33 |
_PARETO_SCALE_VALUES = {value for _, value in _PARETO_SCALE_CHOICES}
|
| 34 |
_PARETO_SCALE_DEFAULT = "Logarithmic"
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
TAB_LEADERBOARDS = "leaderboards"
|
| 37 |
TAB_PARETO = "pareto"
|
| 38 |
TAB_SAMPLES = "samples"
|
| 39 |
TAB_ABOUT = "about"
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
_MODEL_CHOICES_CACHE = {}
|
| 42 |
_VIEW_EVENTS = {
|
| 43 |
"show_progress": "hidden",
|
|
@@ -49,21 +71,24 @@ _VIEW_EVENTS = {
|
|
| 49 |
ABOUT_OVERVIEW_CONTENT = """
|
| 50 |
# About P-Bench
|
| 51 |
|
| 52 |
-
P-Bench compares **text-to-image
|
| 53 |
-
endpoints, on **quality, speed, and price**. Each
|
| 54 |
-
with a **metric**, written as `Dataset | Metric`.
|
| 55 |
-
across P-Bench.
|
| 56 |
|
| 57 |
## How to read it
|
| 58 |
|
| 59 |
-
1. Pick a **
|
|
|
|
| 60 |
2. **Leaderboards**: ranked by that metric. Price and generation time sit in
|
| 61 |
the same table when the source publishes them.
|
| 62 |
3. **Pareto plots**: mark models that are not beaten on both higher score
|
| 63 |
and lower price (or time). Only datasets with price or generation time
|
| 64 |
can open this tab (not Arena AI).
|
| 65 |
4. **Samples**: the same prompts, side by side. Only for datasets we
|
| 66 |
-
generated (Qwen Image Dataset
|
|
|
|
|
|
|
| 67 |
|
| 68 |
## How a score is made
|
| 69 |
|
|
@@ -82,6 +107,17 @@ prompt suites, so samples are not shown.
|
|
| 82 |
|
| 83 |
## Current datasets
|
| 84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
### Qwen Image Dataset
|
| 86 |
100 prompts from the 1,000-prompt Qwen Image Bench set, sampled for coverage
|
| 87 |
across its fine-grained (L3) categories. Metrics include Datapoint Elo,
|
|
@@ -124,12 +160,14 @@ ABOUT_DETAILS_CONTENT = """
|
|
| 124 |
- **Arena Elo**: Elo published by Arena AI on their own dataset, plus
|
| 125 |
category Elos (branding, 3D, cartoon/anime, photorealistic, art, portraits,
|
| 126 |
text rendering).
|
| 127 |
-
- **Generation time**: median and minimum generation time in seconds
|
| 128 |
-
reported in the evaluation table.
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
|
|
|
|
|
|
| 133 |
|
| 134 |
Scores from different datasets or metrics are **not interchangeable**. A high
|
| 135 |
OneIG alignment score is not the same quantity as a Datapoint Elo. Compare
|
|
@@ -143,14 +181,18 @@ models *within* a Dataset | Metric view.
|
|
| 143 |
- **Prompt counts:** OneIG Alignment uses 100 anime, 100 human, and 99 object
|
| 144 |
prompts (299 total). Qwen Image Dataset uses 100 prompts sampled from the
|
| 145 |
1,000-prompt pool for roughly even coverage of its fine-grained (L3)
|
| 146 |
-
categories.
|
| 147 |
-
|
|
|
|
|
|
|
| 148 |
- **Generation (Qwen and OneIG):** one image per prompt per endpoint when
|
| 149 |
the run exists. Default resolution is 1024×1024. Exceptions: FLUX 1.1 Pro
|
| 150 |
Ultra at 2K, FLUX 2 Flex at 1008×1008, and any endpoint labeled 2K. The
|
| 151 |
seed is derived from the prompt, so every model gets the same seed for the
|
| 152 |
same prompt. Steps, CFG, prompt rewrite, and safety filters follow each
|
| 153 |
endpoint's default. This does not describe Artificial Analysis or Arena AI.
|
|
|
|
|
|
|
| 154 |
- **Datapoint (Qwen and OneIG):** every model pair is compared on every
|
| 155 |
prompt, with 10 votes per battle.
|
| 156 |
- **Rapidata (Qwen and OneIG):** prompts longer than 400 characters are
|
|
@@ -222,7 +264,7 @@ def render_header():
|
|
| 222 |
</svg>
|
| 223 |
</button>
|
| 224 |
</div>
|
| 225 |
-
<p class="app-header-tagline">Compare
|
| 226 |
</header>
|
| 227 |
""",
|
| 228 |
padding=False,
|
|
@@ -237,10 +279,42 @@ def _item(items, item_id):
|
|
| 237 |
return items[0] if items else None
|
| 238 |
|
| 239 |
|
| 240 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
return [
|
| 242 |
(dataset["name"], dataset["id"])
|
| 243 |
-
for dataset in
|
| 244 |
if (not require_samples or dataset.get("samples"))
|
| 245 |
and (not require_pareto or _dataset_has_pareto(datasets, dataset["id"]))
|
| 246 |
]
|
|
@@ -256,20 +330,72 @@ def _sample_model_ids(datasets, dataset_id):
|
|
| 256 |
samples = dataset.get("samples") if dataset else None
|
| 257 |
if not samples:
|
| 258 |
return set()
|
| 259 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
|
| 261 |
|
| 262 |
def _dataset_has_pareto(datasets, dataset_id):
|
| 263 |
dataset = _item(datasets, dataset_id)
|
| 264 |
-
|
| 265 |
-
return
|
|
|
|
|
|
|
|
|
|
| 266 |
|
| 267 |
|
| 268 |
-
def _dataset_dropdown_update(datasets, tab, dataset_id):
|
| 269 |
"""Limit the dataset list to what the current tab can show."""
|
|
|
|
|
|
|
| 270 |
return gr.update(
|
| 271 |
choices=_dataset_choices(
|
| 272 |
datasets,
|
|
|
|
| 273 |
require_samples=tab == TAB_SAMPLES
|
| 274 |
and _dataset_has_samples(datasets, dataset_id),
|
| 275 |
require_pareto=tab == TAB_PARETO
|
|
@@ -375,9 +501,11 @@ _LEADERBOARD_IDENTITY_COLUMNS = [
|
|
| 375 |
"Optimized",
|
| 376 |
]
|
| 377 |
_LEADERBOARD_META_COLUMNS = [
|
|
|
|
| 378 |
"Median Generation Time (s)",
|
| 379 |
"Min Generation Time (s)",
|
| 380 |
"Price / Image (USD)",
|
|
|
|
| 381 |
"Evaluation Date (UTC)",
|
| 382 |
"Date",
|
| 383 |
]
|
|
@@ -604,7 +732,9 @@ def _display_label(column):
|
|
| 604 |
"Arena Text Rendering Elo": "Text Rendering",
|
| 605 |
"Median Generation Time (s)": "Median generation time",
|
| 606 |
"Min Generation Time (s)": "Min generation time",
|
|
|
|
| 607 |
"Price / Image (USD)": "Price per image",
|
|
|
|
| 608 |
"Evaluation Date (UTC)": "Date",
|
| 609 |
"Date": "Date",
|
| 610 |
}
|
|
@@ -679,6 +809,23 @@ def _applied_key(view_state):
|
|
| 679 |
)
|
| 680 |
|
| 681 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 682 |
def _build_pareto_figure(
|
| 683 |
data,
|
| 684 |
score_column,
|
|
@@ -703,6 +850,8 @@ def _build_pareto_figure(
|
|
| 703 |
|
| 704 |
dominated = scatter.loc[[not flag for flag in on_frontier]].copy()
|
| 705 |
frontier = scatter.loc[on_frontier].sort_values(x_column).copy()
|
|
|
|
|
|
|
| 706 |
if not dominated.empty:
|
| 707 |
dominated["Model"] = dominated["Model"].map(display_model_name)
|
| 708 |
if not frontier.empty:
|
|
@@ -723,10 +872,11 @@ def _build_pareto_figure(
|
|
| 723 |
name="Below frontier",
|
| 724 |
text=dominated["Model"],
|
| 725 |
hovertemplate=hover,
|
|
|
|
| 726 |
marker={
|
| 727 |
"size": 9,
|
| 728 |
-
"color":
|
| 729 |
-
"opacity": 0.
|
| 730 |
"line": {"width": 0},
|
| 731 |
},
|
| 732 |
)
|
|
@@ -740,14 +890,51 @@ def _build_pareto_figure(
|
|
| 740 |
name="On frontier",
|
| 741 |
text=frontier["Model"],
|
| 742 |
hovertemplate=hover,
|
| 743 |
-
|
|
|
|
| 744 |
marker={
|
| 745 |
"size": 12,
|
| 746 |
-
"color":
|
| 747 |
-
"line": {"width":
|
| 748 |
},
|
| 749 |
)
|
| 750 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 751 |
|
| 752 |
score_label = _display_label(score_column)
|
| 753 |
fig.update_layout(
|
|
@@ -887,23 +1074,43 @@ def _pareto_pair(
|
|
| 887 |
if data is None or not score_column or score_column not in data.columns:
|
| 888 |
return None, score_missing, None, score_missing
|
| 889 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 890 |
price_fig, price_message = _pareto_axis(
|
| 891 |
data,
|
| 892 |
score_column,
|
| 893 |
-
|
| 894 |
-
|
| 895 |
-
|
| 896 |
"No models have both a score and a price for this metric.",
|
| 897 |
x_hover_prefix="$",
|
| 898 |
x_axis_type=_pareto_axis_type(price_scale),
|
| 899 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 900 |
time_fig, time_message = _pareto_axis(
|
| 901 |
data,
|
| 902 |
score_column,
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
| 907 |
x_hover_suffix="s",
|
| 908 |
x_axis_type=_pareto_axis_type(latency_scale),
|
| 909 |
)
|
|
@@ -911,29 +1118,29 @@ def _pareto_pair(
|
|
| 911 |
|
| 912 |
|
| 913 |
def _pareto_dataset_message(data):
|
| 914 |
-
has_price = data is not None
|
| 915 |
-
has_time = data is not None
|
| 916 |
if has_price or has_time:
|
| 917 |
return None
|
| 918 |
return (
|
| 919 |
-
"Price
|
| 920 |
"this dataset, so these plots can't be drawn."
|
| 921 |
)
|
| 922 |
|
| 923 |
|
| 924 |
def _pareto_slot_note(price_fig, price_message, time_fig, time_message, data):
|
| 925 |
-
has_price = data is not None
|
| 926 |
-
has_time = data is not None
|
| 927 |
notes = []
|
| 928 |
if has_price and not has_time:
|
| 929 |
notes.append(
|
| 930 |
-
"
|
| 931 |
"price vs score is shown."
|
| 932 |
)
|
| 933 |
elif has_time and not has_price:
|
| 934 |
notes.append(
|
| 935 |
-
"Price
|
| 936 |
-
"
|
| 937 |
)
|
| 938 |
if price_fig is None and has_price:
|
| 939 |
notes.append(price_message)
|
|
@@ -954,8 +1161,8 @@ def _pareto_slot_updates(
|
|
| 954 |
score_columns = [column for column in (score_columns or []) if column]
|
| 955 |
price_scales = _normalize_pareto_scales(price_scales)
|
| 956 |
time_scales = _normalize_pareto_scales(time_scales)
|
| 957 |
-
has_price = data is not None
|
| 958 |
-
has_time = data is not None
|
| 959 |
dataset_note = _pareto_dataset_message(data)
|
| 960 |
updates = [_pareto_note_update(dataset_note)]
|
| 961 |
hide_all_slots = not has_price and not has_time
|
|
@@ -1034,15 +1241,48 @@ def _samples_html(samples, selected_models, num_prompts, seed=0):
|
|
| 1034 |
return _pareto_unavailable_html(
|
| 1035 |
"Samples aren't available for this dataset."
|
| 1036 |
)
|
| 1037 |
-
|
| 1038 |
-
|
|
|
|
|
|
|
|
|
|
| 1039 |
if not models:
|
| 1040 |
-
models = (samples
|
| 1041 |
return _build_compare_samples_html(samples, models, num_prompts, seed)
|
| 1042 |
|
| 1043 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1044 |
def _build_compare_samples_html(samples, selected_models, num_prompts, seed=0):
|
| 1045 |
selected_models = list(selected_models or [])[:MAX_COMPARE_MODELS]
|
|
|
|
|
|
|
|
|
|
| 1046 |
|
| 1047 |
if not selected_models:
|
| 1048 |
return (
|
|
@@ -1053,7 +1293,7 @@ def _build_compare_samples_html(samples, selected_models, num_prompts, seed=0):
|
|
| 1053 |
|
| 1054 |
shared_prompt_ids = None
|
| 1055 |
for model in selected_models:
|
| 1056 |
-
model_prompt_ids = set(
|
| 1057 |
shared_prompt_ids = (
|
| 1058 |
model_prompt_ids
|
| 1059 |
if shared_prompt_ids is None
|
|
@@ -1073,29 +1313,31 @@ def _build_compare_samples_html(samples, selected_models, num_prompts, seed=0):
|
|
| 1073 |
rng.shuffle(prompt_pool)
|
| 1074 |
chosen = prompt_pool[: max(1, min(int(num_prompts), len(prompt_pool)))]
|
| 1075 |
|
| 1076 |
-
columns = len(selected_models)
|
| 1077 |
blocks = []
|
| 1078 |
for index, prompt_id in enumerate(chosen, start=1):
|
| 1079 |
prompt_text = escape(samples["prompts"].get(prompt_id, ""))
|
| 1080 |
cells = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1081 |
for model in selected_models:
|
| 1082 |
-
image_url = escape(samples["images"][model][prompt_id], quote=True)
|
| 1083 |
cells.append(
|
| 1084 |
-
|
| 1085 |
-
|
| 1086 |
-
|
| 1087 |
-
|
| 1088 |
-
|
| 1089 |
-
</a>
|
| 1090 |
-
</div>
|
| 1091 |
-
"""
|
| 1092 |
)
|
|
|
|
| 1093 |
blocks.append(
|
| 1094 |
f"""
|
| 1095 |
<div class="compare-prompt-block">
|
| 1096 |
<div class="compare-prompt-meta">
|
| 1097 |
<span>Prompt {index}</span>
|
| 1098 |
-
<span>{escape(prompt_id)}</span>
|
| 1099 |
</div>
|
| 1100 |
<p class="compare-prompt-text">{prompt_text}</p>
|
| 1101 |
<div class="compare-row" style="grid-template-columns: repeat({columns}, minmax(0, 1fr));">
|
|
@@ -1123,9 +1365,19 @@ def _filter_row(datasets, metrics, default_dataset_id, default_metric_id=None):
|
|
| 1123 |
metric_id = _coerce_metric(
|
| 1124 |
datasets, metrics, default_dataset_id, default_metric_id
|
| 1125 |
)
|
|
|
|
| 1126 |
with gr.Row(elem_classes="view-filters"):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1127 |
dataset_dd = gr.Dropdown(
|
| 1128 |
-
choices=_dataset_choices(datasets),
|
| 1129 |
value=default_dataset_id,
|
| 1130 |
label="Dataset",
|
| 1131 |
type="value",
|
|
@@ -1157,7 +1409,7 @@ def _filter_row(datasets, metrics, default_dataset_id, default_metric_id=None):
|
|
| 1157 |
min_width=180,
|
| 1158 |
elem_classes="filter-chips",
|
| 1159 |
)
|
| 1160 |
-
return dataset_dd, metric_dd, models_dd
|
| 1161 |
|
| 1162 |
|
| 1163 |
def render_image_workspace(datasets, metrics, default_dataset_id, default_metric_id):
|
|
@@ -1172,15 +1424,16 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 1172 |
with gr.Column(elem_classes="workspace-filters") as filters_host:
|
| 1173 |
gr.Markdown(
|
| 1174 |
"<p class='filter-help'>"
|
| 1175 |
-
"
|
| 1176 |
-
"
|
| 1177 |
-
"
|
| 1178 |
-
"
|
| 1179 |
-
"
|
|
|
|
| 1180 |
"</p>",
|
| 1181 |
elem_classes="filter-help-host",
|
| 1182 |
)
|
| 1183 |
-
dataset_dd, metric_dd, models_dd = _filter_row(
|
| 1184 |
datasets, metrics, default_dataset_id, None
|
| 1185 |
)
|
| 1186 |
with gr.Tabs(elem_classes="main-tabs") as main_tabs:
|
|
@@ -1306,7 +1559,7 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 1306 |
elem_classes="pareto-col",
|
| 1307 |
) as slot_time_col:
|
| 1308 |
slot_time_scale = _pareto_plot_heading(
|
| 1309 |
-
"
|
| 1310 |
)
|
| 1311 |
slot_time = gr.Plot(
|
| 1312 |
value=None,
|
|
@@ -1342,7 +1595,8 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 1342 |
with gr.Column(visible=bool(initial_samples)) as samples_panel:
|
| 1343 |
gr.Markdown(
|
| 1344 |
f"<p class='view-help'>"
|
| 1345 |
-
f"The same prompts, side by side.
|
|
|
|
| 1346 |
f"<strong>{MAX_COMPARE_MODELS}</strong> models above, or leave "
|
| 1347 |
f"Models empty for two defaults."
|
| 1348 |
f"</p>",
|
|
@@ -1460,8 +1714,14 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 1460 |
):
|
| 1461 |
prev = dict(view_state or {})
|
| 1462 |
extras = extras or {}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1463 |
return {
|
| 1464 |
"dataset_id": dataset_id,
|
|
|
|
|
|
|
| 1465 |
"metric_id": metric_id,
|
| 1466 |
"models": list(models or []),
|
| 1467 |
"current_tab": tab,
|
|
@@ -1599,13 +1859,14 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 1599 |
tab = view_state.get("current_tab") or TAB_LEADERBOARDS
|
| 1600 |
selected_raw = _normalize_metric_ids(metric_id)
|
| 1601 |
incoming_models = list(models or [])
|
| 1602 |
-
|
|
|
|
| 1603 |
"dataset_id"
|
| 1604 |
)
|
| 1605 |
can_pareto = _dataset_has_pareto(datasets, dataset_id)
|
| 1606 |
can_samples = _dataset_has_samples(datasets, dataset_id)
|
| 1607 |
selected_tab = tab
|
| 1608 |
-
if
|
| 1609 |
if tab == TAB_SAMPLES and not can_samples:
|
| 1610 |
selected_tab = TAB_LEADERBOARDS
|
| 1611 |
elif tab == TAB_PARETO and not can_pareto:
|
|
@@ -1614,7 +1875,7 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 1614 |
dataset_id,
|
| 1615 |
metric_id,
|
| 1616 |
models,
|
| 1617 |
-
clear_metric=dataset_changed,
|
| 1618 |
require_samples=selected_tab == TAB_SAMPLES,
|
| 1619 |
)
|
| 1620 |
dataset_id, metric_id, models = synced[:3]
|
|
@@ -1659,7 +1920,7 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 1659 |
list(optimized_value or []),
|
| 1660 |
)
|
| 1661 |
extra_updates = None
|
| 1662 |
-
if
|
| 1663 |
view = resolve_view(datasets, metrics, dataset_id, metric_id)
|
| 1664 |
extra_updates = _leaderboard_extras(
|
| 1665 |
view["data"] if view else None,
|
|
@@ -1712,6 +1973,67 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 1712 |
),
|
| 1713 |
}
|
| 1714 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1715 |
def on_dataset(
|
| 1716 |
dataset_id,
|
| 1717 |
metric_id,
|
|
@@ -2061,9 +2383,12 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 2061 |
handler.__name__ = f"on_tab_{tab}"
|
| 2062 |
return handler
|
| 2063 |
|
|
|
|
| 2064 |
view_state = gr.State(
|
| 2065 |
{
|
| 2066 |
"dataset_id": default_dataset_id,
|
|
|
|
|
|
|
| 2067 |
"metric_id": None,
|
| 2068 |
"models": [],
|
| 2069 |
"current_tab": TAB_LEADERBOARDS,
|
|
@@ -2145,6 +2470,12 @@ def render_image_workspace(datasets, metrics, default_dataset_id, default_metric
|
|
| 2145 |
main_tabs,
|
| 2146 |
view_state,
|
| 2147 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2148 |
dataset_dd.change(
|
| 2149 |
on_dataset,
|
| 2150 |
inputs=filter_inputs,
|
|
|
|
| 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_VIDEO_TO_VIDEO = "video_to_video"
|
| 57 |
+
MODALITY_TEXT_TO_IMAGE = "text_to_image"
|
| 58 |
+
MODALITY_CHOICES = [
|
| 59 |
+
("Video to Video", MODALITY_VIDEO_TO_VIDEO),
|
| 60 |
+
("Text to Image", MODALITY_TEXT_TO_IMAGE),
|
| 61 |
+
]
|
| 62 |
+
|
| 63 |
_MODEL_CHOICES_CACHE = {}
|
| 64 |
_VIEW_EVENTS = {
|
| 65 |
"show_progress": "hidden",
|
|
|
|
| 71 |
ABOUT_OVERVIEW_CONTENT = """
|
| 72 |
# About P-Bench
|
| 73 |
|
| 74 |
+
P-Bench compares **text-to-image** and **video-to-video** models, including
|
| 75 |
+
optimized or accelerated endpoints, on **quality, speed, and price**. Each
|
| 76 |
+
view is a **dataset** scored with a **metric**, written as `Dataset | Metric`.
|
| 77 |
+
There is no single score across P-Bench.
|
| 78 |
|
| 79 |
## How to read it
|
| 80 |
|
| 81 |
+
1. Pick a **type** (Video to Video or Text to Image), then a **dataset**
|
| 82 |
+
and a **metric**.
|
| 83 |
2. **Leaderboards**: ranked by that metric. Price and generation time sit in
|
| 84 |
the same table when the source publishes them.
|
| 85 |
3. **Pareto plots**: mark models that are not beaten on both higher score
|
| 86 |
and lower price (or time). Only datasets with price or generation time
|
| 87 |
can open this tab (not Arena AI).
|
| 88 |
4. **Samples**: the same prompts, side by side. Only for datasets we
|
| 89 |
+
generated (Qwen Image Dataset, OneIG Alignment Dataset, and the
|
| 90 |
+
Pruna Internal Video-Edit Benchmark). Video samples show the source
|
| 91 |
+
clip first, then each model's edit.
|
| 92 |
|
| 93 |
## How a score is made
|
| 94 |
|
|
|
|
| 107 |
|
| 108 |
## Current datasets
|
| 109 |
|
| 110 |
+
### Pruna Internal Video-Edit Benchmark
|
| 111 |
+
Pruna's internal video-to-video editing benchmark, collected by our
|
| 112 |
+
research engineers. It combines prompts from public video-editing
|
| 113 |
+
benchmarks with use-case examples we gathered for advertisement,
|
| 114 |
+
e-commerce, real estate, concept art, and similar work. The suite also
|
| 115 |
+
covers camera-angle and movement changes, lighting, and text in video
|
| 116 |
+
(altering, adding, or removing it). Quality is Datapoint Elo from
|
| 117 |
+
pairwise preference. Price is USD per second of output video;
|
| 118 |
+
generation time is wall time per second of output video. Samples show
|
| 119 |
+
the source clip beside each model's edit.
|
| 120 |
+
|
| 121 |
### Qwen Image Dataset
|
| 122 |
100 prompts from the 1,000-prompt Qwen Image Bench set, sampled for coverage
|
| 123 |
across its fine-grained (L3) categories. Metrics include Datapoint Elo,
|
|
|
|
| 160 |
- **Arena Elo**: Elo published by Arena AI on their own dataset, plus
|
| 161 |
category Elos (branding, 3D, cartoon/anime, photorealistic, art, portraits,
|
| 162 |
text rendering).
|
| 163 |
+
- **Generation time**: median and minimum generation time in seconds for
|
| 164 |
+
images, as reported in the evaluation table. For video, generation time
|
| 165 |
+
per second of output video is the more informative figure (end-to-end
|
| 166 |
+
wall time). This is not a p95, and we do not state warm vs cold or
|
| 167 |
+
concurrent load. Not available for Arena AI.
|
| 168 |
+
- **Price**: USD per image for text-to-image, or USD per second of output
|
| 169 |
+
video for video-to-video. We do not state list price vs amount paid, or
|
| 170 |
+
whether failed generations are included. Not available for Arena AI.
|
| 171 |
|
| 172 |
Scores from different datasets or metrics are **not interchangeable**. A high
|
| 173 |
OneIG alignment score is not the same quantity as a Datapoint Elo. Compare
|
|
|
|
| 181 |
- **Prompt counts:** OneIG Alignment uses 100 anime, 100 human, and 99 object
|
| 182 |
prompts (299 total). Qwen Image Dataset uses 100 prompts sampled from the
|
| 183 |
1,000-prompt pool for roughly even coverage of its fine-grained (L3)
|
| 184 |
+
categories. The Pruna Internal Video-Edit Benchmark uses 78 prompts
|
| 185 |
+
across advertising, e-commerce, real estate, camera, lighting, text, and
|
| 186 |
+
related categories. Artificial Analysis and Arena AI use their own
|
| 187 |
+
private prompt sets.
|
| 188 |
- **Generation (Qwen and OneIG):** one image per prompt per endpoint when
|
| 189 |
the run exists. Default resolution is 1024×1024. Exceptions: FLUX 1.1 Pro
|
| 190 |
Ultra at 2K, FLUX 2 Flex at 1008×1008, and any endpoint labeled 2K. The
|
| 191 |
seed is derived from the prompt, so every model gets the same seed for the
|
| 192 |
same prompt. Steps, CFG, prompt rewrite, and safety filters follow each
|
| 193 |
endpoint's default. This does not describe Artificial Analysis or Arena AI.
|
| 194 |
+
- **Generation (Video-Edit):** one edited clip per prompt per endpoint when
|
| 195 |
+
the run exists. Every model sees the same source video for a prompt.
|
| 196 |
- **Datapoint (Qwen and OneIG):** every model pair is compared on every
|
| 197 |
prompt, with 10 votes per battle.
|
| 198 |
- **Rapidata (Qwen and OneIG):** prompts longer than 400 characters are
|
|
|
|
| 264 |
</svg>
|
| 265 |
</button>
|
| 266 |
</div>
|
| 267 |
+
<p class="app-header-tagline">Compare models on quality, speed, and price</p>
|
| 268 |
</header>
|
| 269 |
""",
|
| 270 |
padding=False,
|
|
|
|
| 279 |
return items[0] if items else None
|
| 280 |
|
| 281 |
|
| 282 |
+
def _dataset_modality(dataset):
|
| 283 |
+
return (dataset or {}).get("modality") or MODALITY_TEXT_TO_IMAGE
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def _datasets_for_modality(datasets, modality):
|
| 287 |
+
if not modality:
|
| 288 |
+
return list(datasets)
|
| 289 |
+
scoped = [
|
| 290 |
+
dataset
|
| 291 |
+
for dataset in datasets
|
| 292 |
+
if _dataset_modality(dataset) == modality
|
| 293 |
+
]
|
| 294 |
+
return scoped or list(datasets)
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
def _modality_choices(datasets):
|
| 298 |
+
present = {_dataset_modality(dataset) for dataset in datasets}
|
| 299 |
+
return [
|
| 300 |
+
(label, value) for label, value in MODALITY_CHOICES if value in present
|
| 301 |
+
]
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
def _default_dataset_id(datasets, modality, preferred=None):
|
| 305 |
+
scoped = _datasets_for_modality(datasets, modality)
|
| 306 |
+
if preferred and any(dataset["id"] == preferred for dataset in scoped):
|
| 307 |
+
return preferred
|
| 308 |
+
return scoped[0]["id"] if scoped else None
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
def _dataset_choices(
|
| 312 |
+
datasets, *, modality=None, require_samples=False, require_pareto=False
|
| 313 |
+
):
|
| 314 |
+
scoped = _datasets_for_modality(datasets, modality)
|
| 315 |
return [
|
| 316 |
(dataset["name"], dataset["id"])
|
| 317 |
+
for dataset in scoped
|
| 318 |
if (not require_samples or dataset.get("samples"))
|
| 319 |
and (not require_pareto or _dataset_has_pareto(datasets, dataset["id"]))
|
| 320 |
]
|
|
|
|
| 330 |
samples = dataset.get("samples") if dataset else None
|
| 331 |
if not samples:
|
| 332 |
return set()
|
| 333 |
+
models = set(samples.get("models") or [])
|
| 334 |
+
return models | {display_model_name(model) for model in models}
|
| 335 |
+
|
| 336 |
+
|
| 337 |
+
def _sample_media_map(samples):
|
| 338 |
+
return (samples or {}).get("images") or {}
|
| 339 |
+
|
| 340 |
+
|
| 341 |
+
def _resolve_sample_model(samples, model):
|
| 342 |
+
media = _sample_media_map(samples)
|
| 343 |
+
if model in media:
|
| 344 |
+
return model
|
| 345 |
+
wanted = {str(model or "").strip(), display_model_name(model)}
|
| 346 |
+
wanted.discard("")
|
| 347 |
+
for key in media:
|
| 348 |
+
if key in wanted or display_model_name(key) in wanted:
|
| 349 |
+
return key
|
| 350 |
+
return None
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
def _default_sample_models(samples):
|
| 354 |
+
models = list((samples or {}).get("models") or [])
|
| 355 |
+
preferred = [model for model in models if _is_pruna_model(model)]
|
| 356 |
+
preferred.sort(
|
| 357 |
+
key=lambda model: (
|
| 358 |
+
"draft" in str(model).casefold()
|
| 359 |
+
or "draft" in display_model_name(model).casefold(),
|
| 360 |
+
display_model_name(model).casefold(),
|
| 361 |
+
)
|
| 362 |
+
)
|
| 363 |
+
return (preferred or models)[:2]
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
def _pareto_price_column(data):
|
| 367 |
+
columns = getattr(data, "columns", []) if data is not None else []
|
| 368 |
+
for column in _PARETO_PRICE_COLUMNS:
|
| 369 |
+
if column in columns:
|
| 370 |
+
return column
|
| 371 |
+
return None
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
def _pareto_time_column(data):
|
| 375 |
+
columns = getattr(data, "columns", []) if data is not None else []
|
| 376 |
+
for column in _PARETO_TIME_COLUMNS:
|
| 377 |
+
if column in columns:
|
| 378 |
+
return column
|
| 379 |
+
return None
|
| 380 |
|
| 381 |
|
| 382 |
def _dataset_has_pareto(datasets, dataset_id):
|
| 383 |
dataset = _item(datasets, dataset_id)
|
| 384 |
+
data = dataset.get("data") if dataset else None
|
| 385 |
+
return (
|
| 386 |
+
_pareto_price_column(data) is not None
|
| 387 |
+
or _pareto_time_column(data) is not None
|
| 388 |
+
)
|
| 389 |
|
| 390 |
|
| 391 |
+
def _dataset_dropdown_update(datasets, tab, dataset_id, modality=None):
|
| 392 |
"""Limit the dataset list to what the current tab can show."""
|
| 393 |
+
if modality is None:
|
| 394 |
+
modality = _dataset_modality(_item(datasets, dataset_id))
|
| 395 |
return gr.update(
|
| 396 |
choices=_dataset_choices(
|
| 397 |
datasets,
|
| 398 |
+
modality=modality,
|
| 399 |
require_samples=tab == TAB_SAMPLES
|
| 400 |
and _dataset_has_samples(datasets, dataset_id),
|
| 401 |
require_pareto=tab == TAB_PARETO
|
|
|
|
| 501 |
"Optimized",
|
| 502 |
]
|
| 503 |
_LEADERBOARD_META_COLUMNS = [
|
| 504 |
+
"Time / Output Video Second (s)",
|
| 505 |
"Median Generation Time (s)",
|
| 506 |
"Min Generation Time (s)",
|
| 507 |
"Price / Image (USD)",
|
| 508 |
+
"Price / Second of Video (USD)",
|
| 509 |
"Evaluation Date (UTC)",
|
| 510 |
"Date",
|
| 511 |
]
|
|
|
|
| 732 |
"Arena Text Rendering Elo": "Text Rendering",
|
| 733 |
"Median Generation Time (s)": "Median generation time",
|
| 734 |
"Min Generation Time (s)": "Min generation time",
|
| 735 |
+
"Time / Output Video Second (s)": "Generation time per second of video",
|
| 736 |
"Price / Image (USD)": "Price per image",
|
| 737 |
+
"Price / Second of Video (USD)": "Price per second of video",
|
| 738 |
"Evaluation Date (UTC)": "Date",
|
| 739 |
"Date": "Date",
|
| 740 |
}
|
|
|
|
| 809 |
)
|
| 810 |
|
| 811 |
|
| 812 |
+
def _is_pruna_model(model_id) -> bool:
|
| 813 |
+
raw = str(model_id or "").casefold()
|
| 814 |
+
label = display_model_name(model_id).casefold()
|
| 815 |
+
return any(
|
| 816 |
+
value.startswith(prefix)
|
| 817 |
+
for value in (raw, label)
|
| 818 |
+
for prefix in ("p-image", "p_image", "p-video", "p_video")
|
| 819 |
+
)
|
| 820 |
+
|
| 821 |
+
|
| 822 |
+
def _pareto_fill_colors(models):
|
| 823 |
+
return [
|
| 824 |
+
_PARETO_PRUNA_COLOR if _is_pruna_model(model) else _PARETO_OTHER_COLOR
|
| 825 |
+
for model in models
|
| 826 |
+
]
|
| 827 |
+
|
| 828 |
+
|
| 829 |
def _build_pareto_figure(
|
| 830 |
data,
|
| 831 |
score_column,
|
|
|
|
| 850 |
|
| 851 |
dominated = scatter.loc[[not flag for flag in on_frontier]].copy()
|
| 852 |
frontier = scatter.loc[on_frontier].sort_values(x_column).copy()
|
| 853 |
+
dominated_colors = _pareto_fill_colors(dominated["Model"]) if not dominated.empty else []
|
| 854 |
+
frontier_colors = _pareto_fill_colors(frontier["Model"]) if not frontier.empty else []
|
| 855 |
if not dominated.empty:
|
| 856 |
dominated["Model"] = dominated["Model"].map(display_model_name)
|
| 857 |
if not frontier.empty:
|
|
|
|
| 872 |
name="Below frontier",
|
| 873 |
text=dominated["Model"],
|
| 874 |
hovertemplate=hover,
|
| 875 |
+
showlegend=False,
|
| 876 |
marker={
|
| 877 |
"size": 9,
|
| 878 |
+
"color": dominated_colors,
|
| 879 |
+
"opacity": 0.85,
|
| 880 |
"line": {"width": 0},
|
| 881 |
},
|
| 882 |
)
|
|
|
|
| 890 |
name="On frontier",
|
| 891 |
text=frontier["Model"],
|
| 892 |
hovertemplate=hover,
|
| 893 |
+
showlegend=False,
|
| 894 |
+
line={"color": _PARETO_FRONTIER_OUTLINE, "width": 2.5},
|
| 895 |
marker={
|
| 896 |
"size": 12,
|
| 897 |
+
"color": frontier_colors,
|
| 898 |
+
"line": {"width": 2.5, "color": _PARETO_FRONTIER_OUTLINE},
|
| 899 |
},
|
| 900 |
)
|
| 901 |
)
|
| 902 |
+
for name, marker in (
|
| 903 |
+
(
|
| 904 |
+
"Pruna",
|
| 905 |
+
{
|
| 906 |
+
"size": 10,
|
| 907 |
+
"color": _PARETO_PRUNA_COLOR,
|
| 908 |
+
"line": {"width": 0},
|
| 909 |
+
},
|
| 910 |
+
),
|
| 911 |
+
(
|
| 912 |
+
"Other models",
|
| 913 |
+
{
|
| 914 |
+
"size": 10,
|
| 915 |
+
"color": _PARETO_OTHER_COLOR,
|
| 916 |
+
"line": {"width": 0},
|
| 917 |
+
},
|
| 918 |
+
),
|
| 919 |
+
(
|
| 920 |
+
"On frontier",
|
| 921 |
+
{
|
| 922 |
+
"size": 12,
|
| 923 |
+
"color": "rgba(0,0,0,0)",
|
| 924 |
+
"line": {"width": 2.5, "color": _PARETO_FRONTIER_OUTLINE},
|
| 925 |
+
},
|
| 926 |
+
),
|
| 927 |
+
):
|
| 928 |
+
fig.add_trace(
|
| 929 |
+
go.Scatter(
|
| 930 |
+
x=[None],
|
| 931 |
+
y=[None],
|
| 932 |
+
mode="markers",
|
| 933 |
+
name=name,
|
| 934 |
+
marker=marker,
|
| 935 |
+
hoverinfo="skip",
|
| 936 |
+
)
|
| 937 |
+
)
|
| 938 |
|
| 939 |
score_label = _display_label(score_column)
|
| 940 |
fig.update_layout(
|
|
|
|
| 1074 |
if data is None or not score_column or score_column not in data.columns:
|
| 1075 |
return None, score_missing, None, score_missing
|
| 1076 |
|
| 1077 |
+
price_column = _pareto_price_column(data) or _PARETO_PRICE_COLUMN
|
| 1078 |
+
price_title = _PARETO_PRICE_TITLES.get(price_column, "Price (USD)")
|
| 1079 |
+
price_missing = (
|
| 1080 |
+
"Price per second of video isn't available for this dataset."
|
| 1081 |
+
if price_column == _PARETO_VIDEO_PRICE_COLUMN
|
| 1082 |
+
else "Price per image isn't available for this dataset."
|
| 1083 |
+
)
|
| 1084 |
price_fig, price_message = _pareto_axis(
|
| 1085 |
data,
|
| 1086 |
score_column,
|
| 1087 |
+
price_column,
|
| 1088 |
+
price_title,
|
| 1089 |
+
price_missing,
|
| 1090 |
"No models have both a score and a price for this metric.",
|
| 1091 |
x_hover_prefix="$",
|
| 1092 |
x_axis_type=_pareto_axis_type(price_scale),
|
| 1093 |
)
|
| 1094 |
+
time_column = _pareto_time_column(data) or _PARETO_TIME_COLUMN
|
| 1095 |
+
time_title = _PARETO_TIME_TITLES.get(time_column, "Generation time (s)")
|
| 1096 |
+
time_missing = (
|
| 1097 |
+
"Generation time per second of video isn't available for this dataset."
|
| 1098 |
+
if time_column == _PARETO_VIDEO_TIME_COLUMN
|
| 1099 |
+
else "Min generation time isn't available for this dataset."
|
| 1100 |
+
)
|
| 1101 |
+
time_empty = (
|
| 1102 |
+
"No models have both a score and generation time per second of "
|
| 1103 |
+
"video for this metric."
|
| 1104 |
+
if time_column == _PARETO_VIDEO_TIME_COLUMN
|
| 1105 |
+
else "No models have both a score and a min generation time for this metric."
|
| 1106 |
+
)
|
| 1107 |
time_fig, time_message = _pareto_axis(
|
| 1108 |
data,
|
| 1109 |
score_column,
|
| 1110 |
+
time_column,
|
| 1111 |
+
time_title,
|
| 1112 |
+
time_missing,
|
| 1113 |
+
time_empty,
|
| 1114 |
x_hover_suffix="s",
|
| 1115 |
x_axis_type=_pareto_axis_type(latency_scale),
|
| 1116 |
)
|
|
|
|
| 1118 |
|
| 1119 |
|
| 1120 |
def _pareto_dataset_message(data):
|
| 1121 |
+
has_price = _pareto_price_column(data) is not None
|
| 1122 |
+
has_time = _pareto_time_column(data) is not None
|
| 1123 |
if has_price or has_time:
|
| 1124 |
return None
|
| 1125 |
return (
|
| 1126 |
+
"Price and generation time aren't available for "
|
| 1127 |
"this dataset, so these plots can't be drawn."
|
| 1128 |
)
|
| 1129 |
|
| 1130 |
|
| 1131 |
def _pareto_slot_note(price_fig, price_message, time_fig, time_message, data):
|
| 1132 |
+
has_price = _pareto_price_column(data) is not None
|
| 1133 |
+
has_time = _pareto_time_column(data) is not None
|
| 1134 |
notes = []
|
| 1135 |
if has_price and not has_time:
|
| 1136 |
notes.append(
|
| 1137 |
+
"Generation time isn't available for this dataset, so only "
|
| 1138 |
"price vs score is shown."
|
| 1139 |
)
|
| 1140 |
elif has_time and not has_price:
|
| 1141 |
notes.append(
|
| 1142 |
+
"Price isn't available for this dataset, so only "
|
| 1143 |
+
"time vs score is shown."
|
| 1144 |
)
|
| 1145 |
if price_fig is None and has_price:
|
| 1146 |
notes.append(price_message)
|
|
|
|
| 1161 |
score_columns = [column for column in (score_columns or []) if column]
|
| 1162 |
price_scales = _normalize_pareto_scales(price_scales)
|
| 1163 |
time_scales = _normalize_pareto_scales(time_scales)
|
| 1164 |
+
has_price = _pareto_price_column(data) is not None
|
| 1165 |
+
has_time = _pareto_time_column(data) is not None
|
| 1166 |
dataset_note = _pareto_dataset_message(data)
|
| 1167 |
updates = [_pareto_note_update(dataset_note)]
|
| 1168 |
hide_all_slots = not has_price and not has_time
|
|
|
|
| 1241 |
return _pareto_unavailable_html(
|
| 1242 |
"Samples aren't available for this dataset."
|
| 1243 |
)
|
| 1244 |
+
models = [
|
| 1245 |
+
resolved
|
| 1246 |
+
for model in (selected_models or [])
|
| 1247 |
+
if (resolved := _resolve_sample_model(samples, model))
|
| 1248 |
+
]
|
| 1249 |
if not models:
|
| 1250 |
+
models = _default_sample_models(samples)
|
| 1251 |
return _build_compare_samples_html(samples, models, num_prompts, seed)
|
| 1252 |
|
| 1253 |
|
| 1254 |
+
def _compare_media_html(url, label, *, kind):
|
| 1255 |
+
safe_url = escape(url, quote=True)
|
| 1256 |
+
safe_label = escape(label)
|
| 1257 |
+
if kind == "video":
|
| 1258 |
+
return (
|
| 1259 |
+
f'<video src="{safe_url}" controls preload="metadata" '
|
| 1260 |
+
f'playsinline></video>'
|
| 1261 |
+
)
|
| 1262 |
+
return (
|
| 1263 |
+
f'<a href="{safe_url}" target="_blank" rel="noopener noreferrer">'
|
| 1264 |
+
f'<img src="{safe_url}" alt="{safe_label} sample" loading="lazy" />'
|
| 1265 |
+
f"</a>"
|
| 1266 |
+
)
|
| 1267 |
+
|
| 1268 |
+
|
| 1269 |
+
def _compare_cell_html(label, url, *, kind, extra_class=""):
|
| 1270 |
+
classes = "compare-cell"
|
| 1271 |
+
if extra_class:
|
| 1272 |
+
classes = f"{classes} {extra_class}"
|
| 1273 |
+
return f"""
|
| 1274 |
+
<div class="{classes}">
|
| 1275 |
+
<div class="compare-model-label">{escape(label)}</div>
|
| 1276 |
+
{_compare_media_html(url, label, kind=kind)}
|
| 1277 |
+
</div>
|
| 1278 |
+
"""
|
| 1279 |
+
|
| 1280 |
+
|
| 1281 |
def _build_compare_samples_html(samples, selected_models, num_prompts, seed=0):
|
| 1282 |
selected_models = list(selected_models or [])[:MAX_COMPARE_MODELS]
|
| 1283 |
+
media = _sample_media_map(samples)
|
| 1284 |
+
kind = (samples or {}).get("kind") or "image"
|
| 1285 |
+
source_videos = (samples or {}).get("source_videos") or {}
|
| 1286 |
|
| 1287 |
if not selected_models:
|
| 1288 |
return (
|
|
|
|
| 1293 |
|
| 1294 |
shared_prompt_ids = None
|
| 1295 |
for model in selected_models:
|
| 1296 |
+
model_prompt_ids = set(media.get(model) or [])
|
| 1297 |
shared_prompt_ids = (
|
| 1298 |
model_prompt_ids
|
| 1299 |
if shared_prompt_ids is None
|
|
|
|
| 1313 |
rng.shuffle(prompt_pool)
|
| 1314 |
chosen = prompt_pool[: max(1, min(int(num_prompts), len(prompt_pool)))]
|
| 1315 |
|
|
|
|
| 1316 |
blocks = []
|
| 1317 |
for index, prompt_id in enumerate(chosen, start=1):
|
| 1318 |
prompt_text = escape(samples["prompts"].get(prompt_id, ""))
|
| 1319 |
cells = []
|
| 1320 |
+
source_url = source_videos.get(prompt_id)
|
| 1321 |
+
if source_url:
|
| 1322 |
+
cells.append(
|
| 1323 |
+
_compare_cell_html(
|
| 1324 |
+
"Source", source_url, kind="video", extra_class="compare-source"
|
| 1325 |
+
)
|
| 1326 |
+
)
|
| 1327 |
for model in selected_models:
|
|
|
|
| 1328 |
cells.append(
|
| 1329 |
+
_compare_cell_html(
|
| 1330 |
+
display_model_name(model),
|
| 1331 |
+
media[model][prompt_id],
|
| 1332 |
+
kind=kind,
|
| 1333 |
+
)
|
|
|
|
|
|
|
|
|
|
| 1334 |
)
|
| 1335 |
+
columns = len(cells)
|
| 1336 |
blocks.append(
|
| 1337 |
f"""
|
| 1338 |
<div class="compare-prompt-block">
|
| 1339 |
<div class="compare-prompt-meta">
|
| 1340 |
<span>Prompt {index}</span>
|
|
|
|
| 1341 |
</div>
|
| 1342 |
<p class="compare-prompt-text">{prompt_text}</p>
|
| 1343 |
<div class="compare-row" style="grid-template-columns: repeat({columns}, minmax(0, 1fr));">
|
|
|
|
| 1365 |
metric_id = _coerce_metric(
|
| 1366 |
datasets, metrics, default_dataset_id, default_metric_id
|
| 1367 |
)
|
| 1368 |
+
default_modality = _dataset_modality(_item(datasets, default_dataset_id))
|
| 1369 |
with gr.Row(elem_classes="view-filters"):
|
| 1370 |
+
modality_dd = gr.Dropdown(
|
| 1371 |
+
choices=_modality_choices(datasets),
|
| 1372 |
+
value=default_modality,
|
| 1373 |
+
label="Type",
|
| 1374 |
+
type="value",
|
| 1375 |
+
filterable=False,
|
| 1376 |
+
scale=1,
|
| 1377 |
+
min_width=150,
|
| 1378 |
+
)
|
| 1379 |
dataset_dd = gr.Dropdown(
|
| 1380 |
+
choices=_dataset_choices(datasets, modality=default_modality),
|
| 1381 |
value=default_dataset_id,
|
| 1382 |
label="Dataset",
|
| 1383 |
type="value",
|
|
|
|
| 1409 |
min_width=180,
|
| 1410 |
elem_classes="filter-chips",
|
| 1411 |
)
|
| 1412 |
+
return modality_dd, dataset_dd, metric_dd, models_dd
|
| 1413 |
|
| 1414 |
|
| 1415 |
def render_image_workspace(datasets, metrics, default_dataset_id, default_metric_id):
|
|
|
|
| 1424 |
with gr.Column(elem_classes="workspace-filters") as filters_host:
|
| 1425 |
gr.Markdown(
|
| 1426 |
"<p class='filter-help'>"
|
| 1427 |
+
"Start with Type to switch between Video to Video and Text "
|
| 1428 |
+
"to Image. The rest of the filters follow you across "
|
| 1429 |
+
"Leaderboards, Pareto plots, and Samples. Samples only "
|
| 1430 |
+
"lists datasets and models we have generations for; Pareto "
|
| 1431 |
+
"plots only lists datasets with price or generation time. "
|
| 1432 |
+
"Search in Models, or leave it empty to include every model."
|
| 1433 |
"</p>",
|
| 1434 |
elem_classes="filter-help-host",
|
| 1435 |
)
|
| 1436 |
+
modality_dd, dataset_dd, metric_dd, models_dd = _filter_row(
|
| 1437 |
datasets, metrics, default_dataset_id, None
|
| 1438 |
)
|
| 1439 |
with gr.Tabs(elem_classes="main-tabs") as main_tabs:
|
|
|
|
| 1559 |
elem_classes="pareto-col",
|
| 1560 |
) as slot_time_col:
|
| 1561 |
slot_time_scale = _pareto_plot_heading(
|
| 1562 |
+
"Time vs score"
|
| 1563 |
)
|
| 1564 |
slot_time = gr.Plot(
|
| 1565 |
value=None,
|
|
|
|
| 1595 |
with gr.Column(visible=bool(initial_samples)) as samples_panel:
|
| 1596 |
gr.Markdown(
|
| 1597 |
f"<p class='view-help'>"
|
| 1598 |
+
f"The same prompts, side by side. Video edits show the "
|
| 1599 |
+
f"source clip first. Select up to "
|
| 1600 |
f"<strong>{MAX_COMPARE_MODELS}</strong> models above, or leave "
|
| 1601 |
f"Models empty for two defaults."
|
| 1602 |
f"</p>",
|
|
|
|
| 1714 |
):
|
| 1715 |
prev = dict(view_state or {})
|
| 1716 |
extras = extras or {}
|
| 1717 |
+
modality = _dataset_modality(_item(datasets, dataset_id))
|
| 1718 |
+
last_by_modality = dict(prev.get("dataset_by_modality") or {})
|
| 1719 |
+
if dataset_id:
|
| 1720 |
+
last_by_modality[modality] = dataset_id
|
| 1721 |
return {
|
| 1722 |
"dataset_id": dataset_id,
|
| 1723 |
+
"modality": modality,
|
| 1724 |
+
"dataset_by_modality": last_by_modality,
|
| 1725 |
"metric_id": metric_id,
|
| 1726 |
"models": list(models or []),
|
| 1727 |
"current_tab": tab,
|
|
|
|
| 1859 |
tab = view_state.get("current_tab") or TAB_LEADERBOARDS
|
| 1860 |
selected_raw = _normalize_metric_ids(metric_id)
|
| 1861 |
incoming_models = list(models or [])
|
| 1862 |
+
filter_changed = source in {"dataset", "modality"}
|
| 1863 |
+
dataset_changed = filter_changed and dataset_id != view_state.get(
|
| 1864 |
"dataset_id"
|
| 1865 |
)
|
| 1866 |
can_pareto = _dataset_has_pareto(datasets, dataset_id)
|
| 1867 |
can_samples = _dataset_has_samples(datasets, dataset_id)
|
| 1868 |
selected_tab = tab
|
| 1869 |
+
if filter_changed:
|
| 1870 |
if tab == TAB_SAMPLES and not can_samples:
|
| 1871 |
selected_tab = TAB_LEADERBOARDS
|
| 1872 |
elif tab == TAB_PARETO and not can_pareto:
|
|
|
|
| 1875 |
dataset_id,
|
| 1876 |
metric_id,
|
| 1877 |
models,
|
| 1878 |
+
clear_metric=source == "modality" or dataset_changed,
|
| 1879 |
require_samples=selected_tab == TAB_SAMPLES,
|
| 1880 |
)
|
| 1881 |
dataset_id, metric_id, models = synced[:3]
|
|
|
|
| 1920 |
list(optimized_value or []),
|
| 1921 |
)
|
| 1922 |
extra_updates = None
|
| 1923 |
+
if filter_changed:
|
| 1924 |
view = resolve_view(datasets, metrics, dataset_id, metric_id)
|
| 1925 |
extra_updates = _leaderboard_extras(
|
| 1926 |
view["data"] if view else None,
|
|
|
|
| 1973 |
),
|
| 1974 |
}
|
| 1975 |
|
| 1976 |
+
def on_modality(
|
| 1977 |
+
modality,
|
| 1978 |
+
dataset_id,
|
| 1979 |
+
metric_id,
|
| 1980 |
+
models,
|
| 1981 |
+
platform_value,
|
| 1982 |
+
owner_value,
|
| 1983 |
+
optimized_value,
|
| 1984 |
+
num_prompts,
|
| 1985 |
+
seed,
|
| 1986 |
+
view_state,
|
| 1987 |
+
):
|
| 1988 |
+
view_state = dict(view_state or {})
|
| 1989 |
+
last_by_modality = dict(view_state.get("dataset_by_modality") or {})
|
| 1990 |
+
current_modality = view_state.get("modality") or _dataset_modality(
|
| 1991 |
+
_item(datasets, dataset_id)
|
| 1992 |
+
)
|
| 1993 |
+
if dataset_id:
|
| 1994 |
+
last_by_modality[current_modality] = dataset_id
|
| 1995 |
+
dataset_id = _default_dataset_id(
|
| 1996 |
+
datasets, modality, last_by_modality.get(modality)
|
| 1997 |
+
)
|
| 1998 |
+
view_state["modality"] = modality
|
| 1999 |
+
view_state["dataset_by_modality"] = last_by_modality
|
| 2000 |
+
result = _apply_filter_change(
|
| 2001 |
+
"modality",
|
| 2002 |
+
dataset_id,
|
| 2003 |
+
metric_id,
|
| 2004 |
+
models,
|
| 2005 |
+
platform_value,
|
| 2006 |
+
owner_value,
|
| 2007 |
+
optimized_value,
|
| 2008 |
+
num_prompts,
|
| 2009 |
+
seed,
|
| 2010 |
+
view_state,
|
| 2011 |
+
)
|
| 2012 |
+
if result is None:
|
| 2013 |
+
return _skip_all(len(dataset_outputs))
|
| 2014 |
+
extras = result["extra_updates"]
|
| 2015 |
+
return (
|
| 2016 |
+
_dataset_dropdown_update(
|
| 2017 |
+
datasets,
|
| 2018 |
+
result["selected_tab"],
|
| 2019 |
+
result["dataset_id"],
|
| 2020 |
+
modality=modality,
|
| 2021 |
+
),
|
| 2022 |
+
result["metric_update"],
|
| 2023 |
+
result["models_update"],
|
| 2024 |
+
extras[6],
|
| 2025 |
+
extras[0],
|
| 2026 |
+
extras[1],
|
| 2027 |
+
extras[2],
|
| 2028 |
+
*result["views"],
|
| 2029 |
+
gr.update(interactive=result["can_pareto"]),
|
| 2030 |
+
gr.update(interactive=result["can_samples"]),
|
| 2031 |
+
gr.update(selected=result["selected_tab"])
|
| 2032 |
+
if result["selected_tab"] != result["tab"]
|
| 2033 |
+
else gr.skip(),
|
| 2034 |
+
result["state"],
|
| 2035 |
+
)
|
| 2036 |
+
|
| 2037 |
def on_dataset(
|
| 2038 |
dataset_id,
|
| 2039 |
metric_id,
|
|
|
|
| 2383 |
handler.__name__ = f"on_tab_{tab}"
|
| 2384 |
return handler
|
| 2385 |
|
| 2386 |
+
default_modality = _dataset_modality(_item(datasets, default_dataset_id))
|
| 2387 |
view_state = gr.State(
|
| 2388 |
{
|
| 2389 |
"dataset_id": default_dataset_id,
|
| 2390 |
+
"modality": default_modality,
|
| 2391 |
+
"dataset_by_modality": {default_modality: default_dataset_id},
|
| 2392 |
"metric_id": None,
|
| 2393 |
"models": [],
|
| 2394 |
"current_tab": TAB_LEADERBOARDS,
|
|
|
|
| 2470 |
main_tabs,
|
| 2471 |
view_state,
|
| 2472 |
]
|
| 2473 |
+
modality_dd.change(
|
| 2474 |
+
on_modality,
|
| 2475 |
+
inputs=[modality_dd, *filter_inputs],
|
| 2476 |
+
outputs=dataset_outputs,
|
| 2477 |
+
**_VIEW_EVENTS,
|
| 2478 |
+
)
|
| 2479 |
dataset_dd.change(
|
| 2480 |
on_dataset,
|
| 2481 |
inputs=filter_inputs,
|