P-Bench / app.py
minette-kaunismaki's picture
ui-updates (#1)
e680130
Raw
History Blame Contribute Delete
76.2 kB
import asyncio
import json
from collections import defaultdict
from pathlib import Path
# Gradio 5.19's safe_get_lock() returns None on Python 3.12+/3.14 when no
# event loop exists yet, which breaks /queue/join (pending_message_lock).
try:
asyncio.get_running_loop()
except RuntimeError:
asyncio.set_event_loop(asyncio.new_event_loop())
import gradio as gr
import pandas as pd
from ui import (
render_footer,
render_header,
render_image_workspace,
)
# Visual tokens from https://www.pruna.ai/ and https://playground.pruna.ai/
custom_css = """
:root, :host, .dark, :host(.dark) {
--pruna-bg-primary: #120b1b;
--pruna-bg-card: #171021;
--pruna-bg-elevated: #1d1429;
--pruna-bg-header: #17101f;
--pruna-border: rgba(74, 57, 98, 0.75);
--pruna-hairline: rgba(255, 255, 255, 0.08);
--pruna-text-primary: #fafafa;
--pruna-text-body: #d4d4d4;
--pruna-text-muted: #a3a3a3;
--pruna-accent: #9334e9;
--pruna-accent-bright: #8f35ff;
--pruna-lavender: #d8b4fe;
--pruna-link: #bf8bff;
--pruna-font: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
--pruna-glow: radial-gradient(ellipse 60% 35% at 50% -5%, rgba(147, 52, 233, 0.18), transparent 55%);
--pruna-card-bg: color-mix(in oklab, #1d1429 92%, black 8%);
--pruna-card-shadow: 0 24px 55px rgba(0, 0, 0, 0.42), inset 0 1px rgba(255, 255, 255, 0.04);
--pruna-callout-bg: color-mix(in oklab, #171021 82%, black 18%);
--pruna-menu-border: rgba(255, 255, 255, 0.08);
--pruna-menu-bg: rgba(255, 255, 255, 0.03);
--pruna-menu-hover-bg: rgba(255, 255, 255, 0.05);
--pruna-menu-hover-color: #e4e4e7;
--pruna-menu-selected-bg: rgba(143, 53, 255, 0.22);
--pruna-menu-selected-color: #ffffff;
--pruna-tab-hover: #e4e4e7;
--pruna-tab-selected: #ffffff;
--pruna-input-bg: rgba(255, 255, 255, 0.03);
--pruna-input-border: rgba(255, 255, 255, 0.08);
--pruna-focus-border: rgba(143, 53, 255, 0.45);
--pruna-focus-ring: 0 0 0 3px rgba(143, 53, 255, 0.16);
--pruna-table-hover: rgba(143, 53, 255, 0.16);
--pruna-table-hover-text: #ffffff;
--pruna-table-sticky: #17101f;
--pruna-table-sticky-hover: #2a1844;
--pruna-rank-bg: rgba(143, 53, 255, 0.22);
--pruna-rank-ring: 0 0 0 1px rgba(143, 53, 255, 0.45);
--pruna-score: #ddd6fe;
--pruna-accordion-bg: rgba(255, 255, 255, 0.02);
--pruna-accordion-border: rgba(216, 180, 254, 0.15);
--pruna-dropdown-hover: #2a1844;
color-scheme: dark;
}
.light, :host(.light) {
--pruna-bg-primary: #f6f3fa;
--pruna-bg-card: #ffffff;
--pruna-bg-elevated: #ffffff;
--pruna-bg-header: #f3eef8;
--pruna-border: rgba(126, 34, 206, 0.16);
--pruna-hairline: rgba(24, 24, 27, 0.08);
--pruna-text-primary: #18181b;
--pruna-text-body: #3f3f46;
--pruna-text-muted: #71717a;
--pruna-accent: #9334e9;
--pruna-accent-bright: #7c22ce;
--pruna-lavender: #7e22ce;
--pruna-link: #6d28d9;
--pruna-glow: radial-gradient(ellipse 60% 35% at 50% -5%, rgba(147, 52, 233, 0.10), transparent 55%);
--pruna-card-bg: #ffffff;
--pruna-card-shadow: 0 10px 28px rgba(88, 28, 135, 0.08);
--pruna-callout-bg: #ffffff;
--pruna-menu-border: var(--pruna-border);
--pruna-menu-bg: var(--pruna-bg-card);
--pruna-menu-hover-bg: rgba(147, 52, 233, 0.06);
--pruna-menu-hover-color: var(--pruna-text-primary);
--pruna-menu-selected-bg: rgba(147, 52, 233, 0.12);
--pruna-menu-selected-color: var(--pruna-accent-bright);
--pruna-tab-hover: var(--pruna-text-primary);
--pruna-tab-selected: var(--pruna-text-primary);
--pruna-input-bg: var(--pruna-bg-card);
--pruna-input-border: var(--pruna-border);
--pruna-focus-border: rgba(124, 34, 206, 0.45);
--pruna-focus-ring: 0 0 0 3px rgba(143, 53, 255, 0.16);
--pruna-table-hover: rgba(147, 52, 233, 0.08);
--pruna-table-hover-text: var(--pruna-text-primary);
--pruna-table-sticky: var(--pruna-bg-card);
--pruna-table-sticky-hover: #f3e8ff;
--pruna-rank-bg: rgba(147, 52, 233, 0.12);
--pruna-rank-ring: 0 0 0 1px rgba(147, 52, 233, 0.28);
--pruna-score: var(--pruna-accent-bright);
--pruna-accordion-bg: var(--pruna-bg-card);
--pruna-accordion-border: var(--pruna-border);
--pruna-dropdown-hover: #f3e8ff;
color-scheme: light;
}
html, body {
width: 100% !important;
max-width: 100% !important;
overflow-x: clip;
-webkit-tap-highlight-color: transparent;
}
html, body, .gradio-container, .main {
background: var(--pruna-bg-primary) !important;
color: var(--pruna-text-primary) !important;
font-family: var(--pruna-font) !important;
}
button, a, label, input, select, textarea,
[role="button"], [role="tab"], [role="radio"],
.gradio-container * {
-webkit-tap-highlight-color: transparent !important;
}
.gradio-container {
--input-radius: 10px;
--container-radius: 10px;
--block-radius: 10px;
}
/* Subtle depth — not a marketing-site hero glow */
body, .gradio-container {
background-image: var(--pruna-glow) !important;
background-attachment: fixed !important;
}
.gradio-container {
width: 100% !important;
max-width: 1200px !important;
margin: 0 auto !important;
padding-top: 0 !important;
padding-left: 20px !important;
padding-right: 20px !important;
box-sizing: border-box !important;
overflow-x: clip;
}
.gradio-container .main,
.gradio-container .wrap,
.gradio-container .contain,
.gradio-container .block,
.gradio-container .form,
.gradio-container .row,
.gradio-container .column,
.gradio-container .gap,
.gradio-container .html-container,
.gradio-container .prose,
.gradio-container .padded,
.main-tabs,
.main-tabs .tab-wrapper,
.main-tabs .tabitem,
.leaderboard-controls,
.workspace-shell,
.workspace-filters,
.view-filters {
max-width: 100% !important;
}
/* —— App header (P-Bench only) —— */
.app-header-host,
.app-header-host .html-container,
.app-header-host .prose,
.app-header-host.block,
.app-header-host .padded {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 auto !important;
width: 100% !important;
max-width: none !important;
display: block !important;
text-align: center !important;
overflow: visible !important;
}
.app-header {
position: relative;
display: flex;
flex-direction: column;
align-items: stretch;
width: 100%;
margin: 8px 0 0;
padding: 4px 0 10px;
text-align: center;
}
.app-header-bar {
display: grid;
grid-template-columns: minmax(36px, 1fr) auto minmax(36px, 1fr);
align-items: center;
width: 100%;
column-gap: 8px;
}
.app-header .theme-toggle,
button.theme-toggle {
position: static !important;
top: auto;
right: auto;
grid-column: 3;
justify-self: end;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
width: 36px !important;
height: 36px !important;
min-width: 36px !important;
min-height: 36px !important;
margin: 0 !important;
padding: 0 !important;
border: 1px solid var(--pruna-menu-border) !important;
border-radius: 10px !important;
background: var(--pruna-menu-bg) !important;
color: var(--pruna-text-muted) !important;
box-shadow: none !important;
appearance: none !important;
-webkit-appearance: none !important;
box-sizing: border-box !important;
font: inherit !important;
line-height: 0 !important;
cursor: pointer;
z-index: 6;
}
.app-header .theme-toggle:hover,
.app-header .theme-toggle:active,
button.theme-toggle:hover,
button.theme-toggle:active {
color: var(--pruna-menu-hover-color) !important;
background: var(--pruna-menu-hover-bg) !important;
border-color: var(--pruna-menu-border) !important;
box-shadow: none !important;
}
.app-header .theme-toggle:focus,
button.theme-toggle:focus {
outline: none !important;
}
.app-header .theme-toggle:focus-visible,
button.theme-toggle:focus-visible {
color: var(--pruna-menu-hover-color) !important;
background: var(--pruna-menu-hover-bg) !important;
border-color: var(--pruna-focus-border) !important;
box-shadow: var(--pruna-focus-ring) !important;
}
.app-header .theme-toggle svg,
button.theme-toggle svg {
width: 18px;
height: 18px;
flex-shrink: 0;
}
.app-header .theme-toggle .theme-icon-sun,
button.theme-toggle .theme-icon-sun { display: block !important; }
.app-header .theme-toggle .theme-icon-moon,
button.theme-toggle .theme-icon-moon { display: none !important; }
.app-header .theme-toggle[data-mode="light"] .theme-icon-sun,
button.theme-toggle[data-mode="light"] .theme-icon-sun { display: none !important; }
.app-header .theme-toggle[data-mode="light"] .theme-icon-moon,
button.theme-toggle[data-mode="light"] .theme-icon-moon { display: block !important; }
.app-header-brand {
display: inline-flex !important;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 12px;
grid-column: 2;
justify-self: center;
width: auto !important;
max-width: 100%;
margin: 0;
}
.app-header-logo {
display: block !important;
width: 44px !important;
height: 52px !important;
margin: 0 !important;
object-fit: contain;
flex: 0 0 auto;
}
/* —— Page tabs: centered underline nav —— */
.workspace-shell,
.workspace-shell.block,
.workspace-shell.column,
.workspace-shell.gap {
display: flex !important;
flex-direction: column !important;
gap: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
}
.workspace-shell > .tabs,
.workspace-shell > .main-tabs,
.workspace-shell > .block:not(.workspace-filters),
.workspace-shell .tabs.main-tabs {
display: contents !important;
}
.workspace-filters {
order: 2 !important;
}
.main-tabs .tabitem {
order: 3 !important;
}
.tabs {
gap: 0 !important;
}
.main-tabs > .tab-wrapper {
order: 1 !important;
height: auto !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 0 16px !important;
justify-content: center !important;
width: 100% !important;
}
.main-tabs .tab-container {
height: auto !important;
justify-content: center !important;
flex-wrap: wrap !important;
overflow: hidden !important;
max-width: 100% !important;
gap: 2px;
}
.main-tabs .tab-container::after {
background: var(--pruna-hairline) !important;
}
.main-tabs .tab-container > button {
font-family: var(--pruna-font) !important;
font-size: 0.95rem !important;
font-weight: 600 !important;
letter-spacing: -0.015em !important;
color: var(--pruna-text-muted) !important;
background: transparent !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
padding: 12px 20px !important;
min-height: 44px !important;
height: auto !important;
}
.main-tabs .tab-container > button:hover:not(.selected),
.main-tabs .tab-container > button:active:not(.selected) {
color: var(--pruna-tab-hover) !important;
background: transparent !important;
}
.main-tabs .tab-container > button.selected,
.main-tabs .tab-container > button[aria-selected="true"] {
color: var(--pruna-tab-selected) !important;
background: transparent !important;
}
.main-tabs .tab-container > button:disabled,
.main-tabs .tab-container > button[disabled] {
opacity: 0.4 !important;
color: var(--pruna-text-muted) !important;
cursor: not-allowed !important;
}
.main-tabs .tab-container > button.selected::after,
.main-tabs .tab-container > button[aria-selected="true"]::after {
background: var(--pruna-accent-bright) !important;
height: 2px !important;
}
.main-tabs .tabitem {
padding: 8px 0 0 !important;
border-radius: 0 !important;
overflow: visible !important;
}
/* —— About: two columns on desktop, stacked on phone —— */
.about-layout,
.about-layout.row,
.about-layout .form {
display: flex !important;
flex-wrap: wrap !important;
align-items: flex-start !important;
gap: 8px 40px !important;
width: 100% !important;
}
.about-layout > .about-col,
.about-layout .form > .about-col {
flex: 1 1 340px !important;
min-width: 280px !important;
max-width: 100% !important;
}
.about-copy,
.about-copy.block,
.about-copy .prose,
.about-copy.prose,
.about-copy.padded {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
width: 100% !important;
max-width: 100% !important;
overflow-wrap: break-word !important;
word-break: break-word !important;
}
.about-copy ol,
.about-copy ul,
.about-copy .prose ol,
.about-copy .prose ul {
padding-left: 1.25rem !important;
margin: 0 0 0.8rem !important;
}
.about-copy li,
.about-copy .prose li {
overflow-wrap: break-word;
}
@media (max-width: 700px) {
.gradio-container {
padding-left: 12px !important;
padding-right: 12px !important;
}
.gradio-container .block,
.gradio-container .form,
.gradio-container .row,
.gradio-container .column,
.gradio-container .wrap,
.leaderboard-controls,
.view-filters {
min-width: 0 !important;
max-width: 100% !important;
}
.app-header {
padding: 4px 0 8px;
margin: 4px 0 0;
}
.app-header-logo {
width: 36px !important;
height: 42px !important;
}
.app-header-brand h1,
.gradio-container .app-header-brand h1 {
font-size: 1.55rem !important;
}
.app-header-tagline {
font-size: 0.88rem !important;
padding: 0 8px !important;
}
.main-tabs > .tab-wrapper {
margin: 4px 0 14px !important;
}
.main-tabs .tab-container {
flex-wrap: wrap !important;
justify-content: center !important;
gap: 0 !important;
}
.main-tabs .tab-container > button {
padding: 10px 12px !important;
font-size: 0.88rem !important;
min-height: 40px !important;
}
.about-layout,
.about-layout.row,
.about-layout .form {
flex-direction: column !important;
flex-wrap: nowrap !important;
gap: 8px !important;
}
.about-layout > .about-col,
.about-layout > div {
flex: 1 1 auto !important;
width: 100% !important;
}
.about-copy h1,
.about-copy .prose h1 {
font-size: 1.3rem !important;
}
.about-copy h2,
.about-copy .prose h2 {
margin-top: 1.25rem !important;
font-size: 1.12rem !important;
}
.community-footer-links {
gap: 10px 14px;
}
.leaderboard-controls,
.leaderboard-controls.row,
.leaderboard-controls .form,
.view-filters,
.view-filters.row,
.view-filters .form {
flex-direction: column !important;
align-items: stretch !important;
}
.leaderboard-controls > div,
.leaderboard-controls .form > div,
.view-filters > div,
.view-filters .form > div {
flex: 1 1 auto !important;
width: 100% !important;
max-width: 100% !important;
}
.ranking-table-scroll {
max-height: min(75vh, 640px);
width: 100%;
}
.ranking-table th,
.ranking-table td,
.prose .ranking-table th,
.prose .ranking-table td {
padding: 8px 10px !important;
}
.ranking-table .rank,
.prose .ranking-table .rank,
.ranking-table th.rank {
position: sticky !important;
left: 0 !important;
width: 2.4rem;
min-width: 2.4rem;
}
.ranking-table .model-cell,
.prose .ranking-table .model-cell,
.ranking-table th.model-cell {
position: sticky !important;
left: 2.4rem !important;
min-width: 108px;
max-width: 36vw;
}
.ranking-table .model-cell strong {
white-space: nowrap;
}
.compare-controls,
.compare-controls.row,
.compare-controls .form {
flex-direction: column !important;
flex-wrap: nowrap !important;
flex: 0 0 auto !important;
align-items: stretch !important;
align-content: flex-start !important;
height: auto !important;
min-height: 0 !important;
gap: 10px !important;
margin-bottom: 12px !important;
}
.compare-controls .compare-models,
.compare-controls .compare-prompt-count,
.compare-controls .compare-shuffle,
.compare-controls .form > div {
flex: 0 0 auto !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
align-self: stretch !important;
}
.compare-controls .compare-prompt-count {
max-width: 100% !important;
}
.compare-controls .compare-models .wrap,
.compare-controls .compare-models .wrap-inner {
height: auto !important;
min-height: 40px !important;
}
.compare-controls .compare-shuffle,
.compare-controls .compare-shuffle button {
width: 100% !important;
align-self: stretch !important;
margin-top: 0 !important;
}
.compare-row {
grid-template-columns: 1fr !important;
}
.compare-prompt-meta {
flex-wrap: wrap;
}
.pareto-layout,
.pareto-layout.row,
.pareto-layout .form {
flex-direction: column !important;
}
.pareto-layout > .pareto-col,
.pareto-layout > div,
.pareto-layout .form > div {
flex: 1 1 auto !important;
width: 100% !important;
}
}
/* —— Workspace filters (dataset / metric / models) —— */
.workspace-filters,
.workspace-filters.block,
.workspace-filters.column,
.workspace-filters.gap {
margin: 0 0 12px;
padding: 0 !important;
gap: 12px !important;
overflow: visible !important;
}
.view-filters {
display: flex !important;
flex-wrap: wrap !important;
align-items: end !important;
gap: 12px !important;
margin: 0;
overflow: visible !important;
}
.view-filters > div,
.view-filters > .block,
.view-filters > .form {
flex: 1 1 0 !important;
min-width: 0 !important;
}
.view-filters > .block,
.view-filters .form,
.view-filters .block {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
overflow: visible !important;
--block-border-width: 0 !important;
}
.view-filters label {
display: block !important;
margin: 0 !important;
padding: 0 0 8px !important;
color: var(--pruna-text-muted) !important;
font-size: 0.8rem !important;
font-weight: 500 !important;
line-height: 1.2 !important;
}
.view-filters .wrap {
min-width: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
overflow: visible !important;
}
.view-filters .wrap-inner {
display: flex !important;
flex-wrap: nowrap !important;
align-items: center !important;
gap: 6px !important;
min-height: 40px !important;
height: 40px !important;
padding: 0 10px !important;
border: 1px solid var(--pruna-input-border) !important;
border-radius: 10px !important;
background: var(--pruna-input-bg) !important;
box-shadow: none !important;
overflow: hidden !important;
}
.view-filters .secondary-wrap {
display: flex !important;
flex-wrap: nowrap !important;
align-items: center !important;
flex: 1 1 auto !important;
min-width: 0 !important;
height: 40px !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
overflow: visible !important;
}
.view-filters .filter-chips .wrap-inner {
overflow-x: auto !important;
overflow-y: hidden !important;
overscroll-behavior-x: contain;
scrollbar-width: thin;
scrollbar-color: var(--pruna-border) transparent;
}
.view-filters .filter-chips .secondary-wrap {
min-width: 2.5rem !important;
}
.view-filters .filter-chips .wrap-inner::-webkit-scrollbar {
height: 6px;
}
.view-filters .filter-chips .wrap-inner::-webkit-scrollbar-thumb {
background: var(--pruna-border);
border-radius: 99px;
}
.view-filters .filter-chips .token {
flex: 0 0 auto !important;
white-space: nowrap !important;
word-break: keep-all !important;
}
.view-filters .filter-chips .token span {
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
max-width: 14rem;
}
.view-filters .token:empty {
display: none !important;
}
.view-filters input {
border: none !important;
background: transparent !important;
box-shadow: none !important;
min-height: 28px !important;
height: 28px !important;
width: 100% !important;
min-width: 0 !important;
padding: 0 4px !important;
line-height: 28px !important;
}
.view-filters .dropdown-arrow,
.view-filters .icon-wrap {
flex: 0 0 auto !important;
align-self: center !important;
margin-left: auto !important;
}
.view-title,
.view-title.block,
.view-title .padded {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 0 8px !important;
}
.view-title h1,
.view-title .prose h1,
.gradio-container .view-title h1 {
margin: 0.35rem 0 0.4rem !important;
font-size: 1.45rem !important;
}
.filter-help-host,
.filter-help-host.block,
.filter-help-host .padded,
.filter-help-host .html-container,
.filter-help-host .prose {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
}
.view-help-host,
.view-help-host.block,
.view-help-host .padded,
.view-help-host .html-container,
.view-help-host .prose {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 0 10px !important;
}
.filter-help,
.prose .filter-help,
.view-help,
.prose .view-help {
margin: 0 !important;
color: var(--pruna-text-muted) !important;
font-size: 0.95rem !important;
line-height: 1.45 !important;
font-weight: 400 !important;
}
.view-filters span[data-testid="block-info"],
.view-filters .info,
.view-filters .block-info {
color: var(--pruna-text-muted) !important;
font-size: 0.75rem !important;
line-height: 1.35 !important;
margin-top: 4px !important;
}
.compare-prompt-block {
border: 1px solid var(--pruna-border) !important;
border-radius: 16px !important;
background: var(--pruna-card-bg) !important;
box-shadow: var(--pruna-card-shadow) !important;
}
/* Page footer — flat community strip + quiet citation accordion */
.page-footer-host,
.page-footer-host .html-container,
.page-footer-host .prose,
.page-footer-host.block,
.page-footer-host .padded {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
width: 100% !important;
max-width: none !important;
overflow: visible !important;
}
.page-footer {
margin: 32px 0 16px;
padding: 20px 0 0;
border-top: 1px solid var(--pruna-hairline);
}
.page-footer h3 {
margin: 0 0 10px !important;
font-size: 1.05rem !important;
font-weight: 600 !important;
letter-spacing: -0.015em !important;
text-transform: none !important;
color: var(--pruna-text-primary) !important;
}
.community-footer-links {
display: flex;
flex-wrap: wrap;
gap: 8px 16px;
align-items: center;
}
.community-footer-links a {
color: var(--pruna-text-muted) !important;
text-decoration: none !important;
font-size: 0.9rem !important;
font-weight: 500 !important;
}
.community-footer-links a:hover {
color: var(--pruna-link) !important;
}
/* Citation accordion — full-width control, not a section heading */
.citation-accordion {
margin: 0 0 28px !important;
}
.citation-accordion,
.citation-accordion.block {
border: 1px solid var(--pruna-accordion-border) !important;
border-radius: 10px !important;
background: var(--pruna-accordion-bg) !important;
box-shadow: none !important;
overflow: hidden !important;
}
.citation-accordion > .label-wrap,
.citation-accordion .label-wrap {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 11px 14px !important;
font-size: 0.92rem !important;
font-weight: 500 !important;
color: var(--pruna-text-primary) !important;
letter-spacing: -0.01em !important;
}
.citation-accordion > .label-wrap:hover,
.citation-accordion .label-wrap:hover {
background: var(--pruna-menu-hover-bg) !important;
}
.citation-accordion > .label-wrap span,
.citation-accordion .label-wrap span {
color: var(--pruna-text-primary) !important;
font-size: 0.92rem !important;
font-weight: 500 !important;
}
.citation-accordion .icon,
.citation-accordion .label-wrap .icon {
color: var(--pruna-text-muted) !important;
opacity: 0.9;
}
.citation-accordion .prose,
.citation-accordion .markdown,
.citation-accordion pre,
.citation-accordion code {
color: var(--pruna-text-muted) !important;
background: transparent !important;
border: none !important;
box-shadow: none !important;
}
.citation-accordion .wrap,
.citation-accordion > .wrap {
border-top: 1px solid var(--pruna-hairline) !important;
padding: 4px 14px 12px !important;
background: transparent !important;
}
.citation-accordion pre {
margin: 0 !important;
padding: 0 !important;
font-size: 0.8rem !important;
line-height: 1.55 !important;
overflow-x: auto;
}
.pareto-plot,
.pareto-plot.block,
.pareto-plot .plotly,
.pareto-plot .js-plotly-plot,
.pareto-plot .plot-container,
.pareto-plot .svg-container,
.pareto-plot .main-svg {
width: 100% !important;
max-width: 100% !important;
background: transparent !important;
border-color: var(--pruna-border) !important;
}
.pareto-plot .modebar { display: none !important; }
.leaderboard-controls {
display: flex !important;
flex-wrap: wrap !important;
align-items: end !important;
gap: 10px !important;
margin-bottom: 12px;
overflow: visible !important;
}
.leaderboard-controls > div {
min-width: 0 !important;
}
.leaderboard-controls > .block,
.leaderboard-controls .form,
.leaderboard-controls .block {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
--block-border-width: 0 !important;
}
.leaderboard-controls label {
color: var(--pruna-text-muted) !important;
font-size: 0.8rem !important;
font-weight: 500 !important;
}
.leaderboard-controls textarea {
min-height: 40px !important;
height: 40px !important;
padding: 0 12px !important;
border: 1px solid var(--pruna-input-border) !important;
border-radius: 10px !important;
background: var(--pruna-input-bg) !important;
box-shadow: none !important;
color: var(--pruna-text-primary) !important;
font-family: var(--pruna-font) !important;
font-size: 0.9rem !important;
line-height: 40px !important;
resize: none !important;
}
.leaderboard-controls textarea:focus {
border-color: var(--pruna-focus-border) !important;
outline: none !important;
box-shadow: var(--pruna-focus-ring) !important;
}
.leaderboard-controls .wrap {
min-height: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
overflow: visible !important;
}
.leaderboard-controls .wrap-inner {
display: flex !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 6px !important;
min-height: 40px !important;
height: auto !important;
padding: 4px 10px !important;
border: 1px solid var(--pruna-input-border) !important;
border-radius: 10px !important;
background: var(--pruna-input-bg) !important;
box-shadow: none !important;
overflow: visible !important;
}
.leaderboard-controls .secondary-wrap {
display: flex !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 6px !important;
flex: 1 1 auto !important;
min-width: 0 !important;
min-height: 0 !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
}
.leaderboard-controls .token {
display: inline-flex !important;
align-items: center !important;
max-width: 100% !important;
margin: 0 !important;
}
.leaderboard-controls .token:empty {
display: none !important;
}
.leaderboard-controls .dropdown-arrow,
.leaderboard-controls .icon-wrap {
flex: 0 0 auto !important;
align-self: center !important;
margin-left: auto !important;
}
.ranking-table-host,
.ranking-table-host .html-container,
.ranking-table-host .prose,
.ranking-table-host.block,
.ranking-table-host .padded,
.ranking-table-host.prose {
display: grid !important;
grid-template-columns: minmax(0, 1fr) !important;
border: none !important;
outline: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
overflow: hidden !important;
--block-border-width: 0 !important;
}
.ranking-table-scroll {
border: 1px solid var(--pruna-menu-border);
border-radius: 12px;
background: var(--pruna-menu-bg);
box-shadow: none;
width: 100%;
max-width: 100%;
min-width: 0;
max-height: min(70vh, 720px);
overflow-x: auto;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior-x: contain;
}
.ranking-table,
.prose .ranking-table {
width: 100%;
margin: 0 !important;
overflow: visible;
}
.ranking-table table,
.prose .ranking-table table {
display: table !important;
width: max-content !important;
min-width: 100% !important;
max-width: none !important;
margin: 0 !important;
border-collapse: separate !important;
border-spacing: 0 !important;
color: var(--pruna-text-body) !important;
font-size: 13px !important;
line-height: 1.35 !important;
background: transparent !important;
border: none !important;
outline: none !important;
}
.ranking-table thead { display: table-header-group !important; }
.ranking-table tbody { display: table-row-group !important; }
.ranking-table tr { display: table-row !important; }
.ranking-table th,
.ranking-table td,
.prose .ranking-table th,
.prose .ranking-table td {
display: table-cell !important;
vertical-align: middle !important;
padding: 11px 14px !important;
border: 0 !important;
border-bottom: 1px solid var(--pruna-hairline) !important;
background: transparent !important;
box-shadow: none !important;
outline: none !important;
}
.ranking-table th,
.prose .ranking-table th {
position: sticky;
top: 0;
z-index: 3;
background: var(--pruna-bg-header) !important;
color: var(--pruna-text-muted) !important;
font-size: 11px !important;
font-weight: 600 !important;
letter-spacing: 0.04em;
text-align: left;
text-transform: uppercase;
white-space: nowrap;
box-shadow: 0 1px 0 var(--pruna-hairline) !important;
}
.ranking-table th.sortable-col { cursor: pointer; user-select: none; }
.ranking-table th.sortable-col:hover { color: var(--pruna-lavender) !important; }
.ranking-table th.sortable-col.sorted-asc::after,
.ranking-table th.sortable-col.sorted-desc::after {
margin-left: 0.35em;
font-size: 0.85em;
opacity: 0.85;
}
.ranking-table th.sortable-col.sorted-asc::after { content: "▲"; }
.ranking-table th.sortable-col.sorted-desc::after { content: "▼"; }
.ranking-table tbody tr:last-child td { border-bottom: 0 !important; }
.ranking-table tbody tr:hover td {
background: var(--pruna-table-hover) !important;
}
.ranking-table tbody tr:hover td,
.ranking-table tbody tr:hover .rank,
.ranking-table tbody tr:hover .metric-score,
.ranking-table tbody tr:hover .text-cell,
.ranking-table tbody tr:hover .model-cell strong,
.ranking-table tbody tr:hover .model-cell span { color: var(--pruna-table-hover-text) !important; }
.ranking-table .rank,
.prose .ranking-table .rank {
position: sticky;
left: 0;
z-index: 1;
box-sizing: border-box;
width: 3.25rem;
min-width: 3.25rem;
color: var(--pruna-lavender) !important;
font-weight: 700 !important;
text-align: center;
background: var(--pruna-table-sticky) !important;
}
.ranking-table th.rank,
.prose .ranking-table th.rank {
top: 0;
left: 0;
z-index: 5;
text-align: center;
background: var(--pruna-bg-header) !important;
}
.ranking-table .model-cell,
.prose .ranking-table .model-cell {
position: sticky;
left: 3.25rem;
z-index: 1;
min-width: 180px;
max-width: 260px;
background: var(--pruna-table-sticky) !important;
}
.ranking-table th.model-cell,
.prose .ranking-table th.model-cell {
top: 0;
left: 3.25rem;
z-index: 5;
background: var(--pruna-bg-header) !important;
}
.ranking-table tbody tr:hover .rank,
.ranking-table tbody tr:hover .model-cell {
background: var(--pruna-table-sticky-hover) !important;
}
.ranking-table .model-cell strong,
.ranking-table .model-cell span { display: block; }
.ranking-table .model-cell strong {
color: var(--pruna-text-primary) !important;
font-weight: 600 !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ranking-table .model-cell span {
margin-top: 3px;
color: var(--pruna-text-muted) !important;
font-size: 12px;
}
.ranking-table .text-cell,
.prose .ranking-table .text-cell {
color: var(--pruna-text-muted) !important;
font-weight: 500 !important;
white-space: nowrap;
}
.ranking-table .metric-score,
.prose .ranking-table .metric-score {
color: var(--pruna-text-primary) !important;
font-variant-numeric: tabular-nums;
font-weight: 600 !important;
text-align: right;
white-space: nowrap;
}
.ranking-table th.metric-score { text-align: right; }
.ranking-table .empty-state {
color: var(--pruna-text-muted);
padding: 32px;
text-align: center;
}
.compare-samples-help { color: var(--pruna-text-body); margin-bottom: 8px; }
.compare-controls,
.compare-controls.row,
.compare-controls.column,
.compare-controls .form {
display: flex !important;
flex-direction: column !important;
flex-wrap: nowrap !important;
align-items: stretch !important;
align-content: flex-start !important;
justify-content: flex-start !important;
gap: 12px !important;
width: 100% !important;
max-width: 100% !important;
flex-grow: 0 !important;
height: auto !important;
min-height: 0 !important;
margin-bottom: 16px;
}
.compare-controls > .block,
.compare-controls .form,
.compare-controls .block,
.compare-controls .compare-models,
.compare-controls .compare-prompt-count {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
--block-border-width: 0 !important;
height: auto !important;
min-height: 0 !important;
}
.compare-controls label,
.compare-controls span[data-testid="block-info"] {
display: block !important;
margin: 0 0 6px !important;
padding: 0 !important;
color: var(--pruna-text-muted) !important;
font-size: 0.8rem !important;
font-weight: 500 !important;
line-height: 1.2 !important;
}
.compare-controls .compare-models span[data-testid="block-info"] {
min-height: 1.15rem;
}
.compare-controls .compare-models {
flex: 0 0 auto !important;
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
align-self: stretch !important;
}
.compare-controls .compare-prompt-count {
flex: 0 0 auto !important;
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
align-self: stretch !important;
}
.compare-controls .compare-shuffle {
flex: 0 0 auto !important;
width: 100% !important;
max-width: 100% !important;
align-self: stretch !important;
}
.compare-controls .compare-models .wrap,
.compare-controls .compare-models .wrap-inner {
min-height: 40px !important;
height: auto !important;
overflow: hidden !important;
border: 1px solid var(--pruna-input-border) !important;
border-radius: 10px !important;
background: var(--pruna-input-bg) !important;
box-shadow: none !important;
}
.compare-controls .compare-models .wrap-inner {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 6px !important;
width: 100% !important;
padding: 4px 8px !important;
}
.compare-controls .compare-models .secondary-wrap {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 6px !important;
flex: 1 1 auto !important;
width: auto !important;
min-width: 0 !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
}
.compare-controls .compare-models .token {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
width: auto !important;
max-width: 100% !important;
margin: 0 !important;
white-space: nowrap !important;
}
.compare-controls .compare-models .token:empty {
display: none !important;
}
.compare-controls .compare-models input {
width: auto !important;
min-width: 2.5rem !important;
flex: 1 1 5rem !important;
height: 28px !important;
min-height: 28px !important;
}
.compare-controls .compare-models .dropdown-arrow,
.compare-controls .compare-models .icon-wrap {
flex: 0 0 auto !important;
align-self: center !important;
margin-left: auto !important;
}
.compare-controls .compare-prompt-count .wrap {
display: grid !important;
grid-template-columns: minmax(0, 1fr) auto;
grid-template-rows: auto 40px;
gap: 6px 10px;
align-items: center;
width: 100%;
min-height: 0 !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
}
.compare-controls .compare-prompt-count .head {
display: contents;
margin: 0 !important;
}
.compare-controls .compare-prompt-count .head label {
grid-column: 1 / -1;
grid-row: 1;
}
.compare-controls .compare-prompt-count .tab-like-container {
grid-column: 2;
grid-row: 2;
height: 40px !important;
min-height: 40px !important;
align-self: stretch;
border: 1px solid var(--pruna-input-border) !important;
border-radius: 10px !important;
background: var(--pruna-input-bg) !important;
overflow: hidden;
}
.compare-controls .compare-prompt-count .slider_input_container {
grid-column: 1;
grid-row: 2;
height: 40px !important;
min-height: 40px !important;
margin: 0 !important;
gap: 0 !important;
}
.compare-controls .compare-prompt-count .min_value,
.compare-controls .compare-prompt-count .max_value {
display: none !important;
}
.compare-controls .compare-prompt-count input[type="range"] {
height: 40px !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
background: transparent !important;
border: none !important;
box-shadow: none !important;
}
.compare-controls .compare-prompt-count input[type="number"] {
height: 40px !important;
min-height: 40px !important;
min-width: 2.5rem !important;
margin: 0 !important;
padding: 0 8px !important;
line-height: 40px !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
}
.compare-controls .compare-shuffle.block:not(button) {
width: 100% !important;
max-width: 100% !important;
align-self: stretch !important;
background: transparent !important;
border: none !important;
box-shadow: none !important;
padding: 0 !important;
}
.compare-controls button.compare-shuffle,
.compare-controls .compare-shuffle button,
.compare-controls .compare-shuffle button.primary,
.compare-controls .compare-shuffle button.secondary {
display: inline-flex !important;
justify-content: center !important;
align-items: center !important;
width: 100% !important;
min-width: 0 !important;
height: 44px !important;
min-height: 44px !important;
margin: 0 !important;
padding: 0 16px !important;
border-radius: 10px !important;
align-self: stretch !important;
appearance: none !important;
-webkit-appearance: none !important;
-webkit-tap-highlight-color: transparent !important;
background: var(--pruna-accent) !important;
border: 1px solid color-mix(in oklab, var(--pruna-accent) 72%, transparent) !important;
color: #fff !important;
font-family: var(--pruna-font) !important;
font-size: 0.95rem !important;
font-weight: 600 !important;
letter-spacing: -0.01em !important;
box-shadow: inset 0 1px #fff3 !important;
outline: none !important;
}
.compare-controls button.compare-shuffle:hover,
.compare-controls button.compare-shuffle:active,
.compare-controls button.compare-shuffle:focus,
.compare-controls button.compare-shuffle:focus-visible,
.compare-controls .compare-shuffle button:hover,
.compare-controls .compare-shuffle button:active,
.compare-controls .compare-shuffle button:focus,
.compare-controls .compare-shuffle button:focus-visible {
background: var(--pruna-accent) !important;
border-color: color-mix(in oklab, var(--pruna-accent) 72%, transparent) !important;
color: #fff !important;
outline: none !important;
box-shadow: inset 0 1px #fff3 !important;
-webkit-tap-highlight-color: transparent !important;
}
@media (min-width: 701px) {
.compare-controls,
.compare-controls.row,
.compare-controls.column,
.compare-controls .form {
flex-direction: row !important;
flex-wrap: nowrap !important;
align-items: flex-end !important;
}
.compare-controls .compare-models {
flex: 4 1 0 !important;
width: auto !important;
max-width: none !important;
align-self: flex-end !important;
}
.compare-controls .compare-prompt-count {
flex: 1 1 200px !important;
width: auto !important;
min-width: 180px !important;
max-width: 280px !important;
align-self: flex-end !important;
}
.compare-controls .compare-shuffle,
.compare-controls .compare-shuffle.block:not(button) {
flex: 0 0 auto !important;
width: auto !important;
max-width: none !important;
align-self: flex-end !important;
}
.compare-controls button.compare-shuffle,
.compare-controls .compare-shuffle button {
width: auto !important;
min-width: 10.5rem !important;
}
}
.compare-prompt-block {
margin: 0 0 22px;
padding: 14px 16px;
background: var(--pruna-callout-bg) !important;
}
.compare-prompt-meta {
display: flex;
justify-content: space-between;
gap: 12px;
margin-bottom: 8px;
color: var(--pruna-text-muted);
font-size: 12px;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.compare-prompt-text {
margin: 0 0 14px;
color: var(--pruna-text-body);
font-size: 15px;
line-height: 1.45;
}
.compare-gallery,
.compare-gallery.block,
.compare-gallery .html-container,
.compare-gallery .prose {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
overflow-x: hidden !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 !important;
}
.compare-row { display: grid; gap: 12px; min-width: 0; width: 100%; }
.compare-prompt-text { overflow-wrap: anywhere; }
.pareto-layout,
.pareto-layout.row,
.pareto-layout .form {
display: flex !important;
flex-wrap: wrap !important;
align-items: stretch !important;
gap: 16px !important;
width: 100% !important;
max-width: 100% !important;
}
.pareto-layout > .pareto-col,
.pareto-layout .form > .pareto-col {
flex: 1 1 360px !important;
min-width: 0 !important;
max-width: 100% !important;
}
.compare-cell { min-width: 0; }
.compare-model-label {
margin-bottom: 6px;
color: var(--pruna-lavender);
font-size: 13px;
font-weight: 700;
word-break: break-word;
}
.compare-cell img {
display: block;
width: 100%;
aspect-ratio: 1 / 1;
object-fit: cover;
border-radius: 12px;
border: 1px solid var(--pruna-border);
background: var(--pruna-bg-elevated);
}
.compare-empty,
.pareto-note-copy {
margin: 0;
padding: 14px 16px;
background: var(--pruna-callout-bg, var(--pruna-bg-card));
border: 1px dashed color-mix(in oklab, var(--pruna-border) 70%, transparent);
border-radius: 10px;
color: var(--pruna-text-muted);
font-size: 0.95rem;
line-height: 1.5;
text-align: left;
}
/*
Type scale (playground-like):
product title > page h1 > section h2/h3 > meta labels > body
Uppercase lavender is reserved for meta labels only — not section titles.
*/
.app-header-brand h1,
.prose .app-header-brand h1,
.gradio-container .app-header-brand h1,
.app-header .app-header-brand h1 {
display: block !important;
width: max-content !important;
max-width: none !important;
flex: 0 0 auto !important;
margin: 0 !important;
padding: 0 !important;
text-align: center !important;
font-size: clamp(1.9rem, 3vw, 2.4rem) !important;
font-weight: 700 !important;
letter-spacing: -0.035em;
line-height: 1 !important;
color: var(--pruna-text-primary) !important;
}
.app-header-tagline,
.prose .app-header-tagline,
.gradio-container .app-header-tagline,
.prose p.app-header-tagline {
display: block !important;
width: 100% !important;
margin: 8px 0 0 !important;
padding: 0 !important;
text-align: center !important;
color: var(--pruna-text-muted) !important;
font-size: 0.95rem !important;
line-height: 1.45 !important;
font-weight: 400 !important;
}
.gradio-container h1,
.markdown h1, .md h1, .prose h1 {
margin: 0 0 0.65rem !important;
padding: 0 !important;
color: var(--pruna-text-primary) !important;
font-family: var(--pruna-font) !important;
font-size: 1.5rem !important;
font-weight: 700 !important;
letter-spacing: -0.03em !important;
line-height: 1.2 !important;
text-transform: none !important;
}
.gradio-container h2,
.markdown h2, .md h2, .prose h2 {
margin: 1.75rem 0 0.75rem !important;
padding: 0 !important;
color: var(--pruna-text-primary) !important;
font-family: var(--pruna-font) !important;
font-size: 1.25rem !important;
font-weight: 600 !important;
letter-spacing: -0.02em !important;
line-height: 1.3 !important;
text-transform: none !important;
}
.gradio-container h3,
.markdown h3, .md h3, .prose h3 {
margin: 1.35rem 0 0.5rem !important;
padding: 0 !important;
color: var(--pruna-text-primary) !important;
font-family: var(--pruna-font) !important;
font-size: 1.05rem !important;
font-weight: 600 !important;
letter-spacing: -0.015em !important;
line-height: 1.35 !important;
text-transform: none !important;
}
.gradio-container h4,
.markdown h4, .md h4, .prose h4 {
margin: 1rem 0 0.4rem !important;
padding: 0 !important;
color: var(--pruna-text-body) !important;
font-family: var(--pruna-font) !important;
font-size: 0.95rem !important;
font-weight: 600 !important;
letter-spacing: -0.01em !important;
line-height: 1.35 !important;
text-transform: none !important;
}
.markdown, .md, .prose,
.gradio-container .markdown,
.gradio-container .prose {
overflow-wrap: break-word;
max-width: 100%;
}
.markdown p, .md p, .prose p,
.gradio-container .markdown p {
margin: 0 0 0.8rem !important;
color: var(--pruna-text-body) !important;
font-size: 0.95rem !important;
font-weight: 400 !important;
line-height: 1.55 !important;
}
.markdown li, .md li, .prose li {
color: var(--pruna-text-body) !important;
font-size: 0.95rem;
line-height: 1.5;
}
.markdown strong, .md strong, .prose strong {
color: var(--pruna-text-primary) !important;
font-weight: 600 !important;
}
label, .block-label span {
color: var(--pruna-text-muted) !important;
font-size: 0.8rem !important;
font-weight: 500 !important;
}
a { color: var(--pruna-link); }
/* Gradio form chrome → playground */
button.primary, .gr-button-primary, .primary-button,
button.primary:hover, button.primary:active, button.primary:focus,
.gr-button-primary:hover, .gr-button-primary:active {
background: var(--pruna-accent) !important;
border: 1px solid color-mix(in oklab, var(--pruna-accent) 72%, transparent) !important;
color: #fff !important;
border-radius: 8px !important;
box-shadow: inset 0 1px #fff3 !important;
font-weight: 600 !important;
outline: none !important;
-webkit-tap-highlight-color: transparent !important;
}
button.secondary:active, button.secondary:focus,
.gr-button-secondary:active {
outline: none !important;
-webkit-tap-highlight-color: transparent !important;
}
.block, .gr-group, .form, .panel {
border-color: var(--pruna-border) !important;
background: transparent !important;
}
input, textarea, select {
background: var(--pruna-bg-card) !important;
border-color: var(--pruna-border) !important;
color: var(--pruna-text-primary) !important;
border-radius: 10px !important;
}
.view-filters input,
.leaderboard-controls .wrap-inner input {
background: transparent !important;
border: none !important;
box-shadow: none !important;
min-height: 28px !important;
height: 28px !important;
padding: 0 4px !important;
line-height: 28px !important;
}
.view-filters .wrap-inner:focus-within,
.leaderboard-controls .wrap-inner:focus-within {
border-color: var(--pruna-focus-border) !important;
box-shadow: var(--pruna-focus-ring) !important;
}
footer, .footer { display: none !important; }
.pareto-note,
.pareto-note.block,
.pareto-note .html-container,
.pareto-note .prose {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 0 12px !important;
}
.pareto-metric-block {
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--pruna-hairline);
}
.pareto-metric-block:last-child {
border-bottom: none;
}
.pareto-metric-title {
margin: 0 0 0.75rem;
color: var(--pruna-text-primary);
font-size: 1.05rem;
font-weight: 600;
}
.pareto-subhead,
.pareto-subhead.block,
.pareto-subhead .prose,
.pareto-subhead .html-container {
border: none !important;
background: transparent !important;
box-shadow: none !important;
padding: 0 !important;
margin: 0 0 0.4rem !important;
color: var(--pruna-text-muted);
}
.pareto-subhead h4,
.pareto-subhead .prose h4 {
margin: 0 !important;
color: var(--pruna-text-muted) !important;
font-size: 0.95rem !important;
font-weight: 600 !important;
}
.options,
ul.options {
position: absolute !important;
top: calc(100% + 4px) !important;
bottom: auto !important;
left: 0 !important;
right: auto !important;
width: 100% !important;
max-height: min(280px, 60vh) !important;
background: var(--pruna-bg-card) !important;
color: var(--pruna-text-primary) !important;
border: 1px solid var(--pruna-border) !important;
border-radius: 10px !important;
overflow: auto !important;
z-index: 50 !important;
}
.options .item:first-child,
.options li:first-child {
border-top-left-radius: 10px !important;
border-top-right-radius: 10px !important;
}
.options .item:last-child,
.options li:last-child {
border-bottom-left-radius: 10px !important;
border-bottom-right-radius: 10px !important;
}
.dropdown-arrow-inner {
background: var(--pruna-bg-card) !important;
color: var(--pruna-text-primary) !important;
border-color: var(--pruna-border) !important;
}
.options .item,
.options li {
color: var(--pruna-text-primary) !important;
}
.options .item:hover,
.options li:hover,
.options .item.selected {
background: var(--pruna-dropdown-hover) !important;
color: var(--pruna-text-primary) !important;
}
input[type="range"] {
accent-color: var(--pruna-accent);
}
"""
theme = gr.themes.Base(
primary_hue=gr.themes.Color(
c50="#faf5ff",
c100="#f3e8ff",
c200="#e9d5ff",
c300="#d8b4fe",
c400="#c084fc",
c500="#9334e9",
c600="#9334e9",
c700="#7e22ce",
c800="#6b21a8",
c900="#3b0764",
c950="#120b1b",
),
secondary_hue="zinc",
neutral_hue="zinc",
font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"],
font_mono=[gr.themes.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace"],
).set(
body_background_fill="#f6f3fa",
body_background_fill_dark="#120b1b",
body_text_color="#18181b",
body_text_color_dark="#fafafa",
body_text_color_subdued="#71717a",
body_text_color_subdued_dark="#a3a3a3",
background_fill_primary="#f6f3fa",
background_fill_primary_dark="#120b1b",
background_fill_secondary="#ffffff",
background_fill_secondary_dark="#171021",
block_background_fill="#ffffff",
block_background_fill_dark="#1d1429",
block_border_color="#e4d7f2",
block_border_color_dark="#4a3962bf",
block_label_text_color="#71717a",
block_label_text_color_dark="#a3a3a3",
block_title_text_color="#18181b",
block_title_text_color_dark="#fafafa",
border_color_primary="#e4d7f2",
border_color_primary_dark="#4a3962bf",
button_primary_background_fill="#9334e9",
button_primary_background_fill_dark="#9334e9",
button_primary_background_fill_hover="#7c22ce",
button_primary_background_fill_hover_dark="#8f35ff",
button_primary_text_color="#ffffff",
button_primary_text_color_dark="#ffffff",
button_secondary_background_fill="#ffffff",
button_secondary_background_fill_dark="#ffffff05",
button_secondary_background_fill_hover="#f3e8ff",
button_secondary_background_fill_hover_dark="rgba(147, 52, 233, 0.10)",
button_secondary_text_color="#18181b",
button_secondary_text_color_dark="#fafafa",
button_secondary_border_color="#e4d7f2",
button_secondary_border_color_dark="#d8b4fe26",
input_background_fill="#ffffff",
input_background_fill_dark="#171021",
input_border_color="#e4d7f2",
input_border_color_dark="#4a3962bf",
input_placeholder_color="#71717a",
input_placeholder_color_dark="#a3a3a3",
link_text_color="#6d28d9",
link_text_color_dark="#bf8bff",
link_text_color_hover="#7c22ce",
link_text_color_hover_dark="#d2a8ff",
shadow_drop="none",
shadow_drop_lg="none",
)
space_root = Path(__file__).resolve().parent
data_dir = space_root / "data"
def _resolve_data_path(*candidates):
"""Prefer Space-local data/, fall back to monorepo parent for local edits."""
for path in candidates:
if path.exists():
return path
return candidates[0]
oneig_path = _resolve_data_path(
data_dir / "oneig_model_price_and_median_generation_time.csv",
space_root.parent / "oneig_model_price_and_median_generation_time.csv",
)
def load_sample_comparison_data(folder):
"""Load prompts + generations for the Compare samples tab."""
folder = Path(folder)
prompts_path = folder / "prompts.jsonl"
generations_path = folder / "generations.jsonl"
if not prompts_path.exists() or not generations_path.exists():
return None
prompts = {}
with prompts_path.open() as handle:
for line in handle:
if not line.strip():
continue
row = json.loads(line)
prompts[row["prompt_id"]] = row.get("text", "")
images = defaultdict(dict)
with generations_path.open() as handle:
for line in handle:
if not line.strip():
continue
row = json.loads(line)
model_id = row["model_id"]
prompt_id = row["prompt_id"]
image_url = row.get("image")
if model_id and prompt_id and image_url:
images[model_id][prompt_id] = image_url
models = sorted(images)
if not models or not prompts:
return None
return {
"prompts": prompts,
"images": {model: dict(prompt_map) for model, prompt_map in images.items()},
"models": models,
"prompt_ids": sorted(prompts),
}
def _as_numeric(df, columns):
for column in columns:
if column in df.columns:
df[column] = pd.to_numeric(df[column], errors="coerce")
return df
def load_oneig_dataframe(path):
df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
df = df.rename(
columns={
"Owner": "Endpoint Owner",
"Anime Alignment Score": "OneIG (Anime Alignment)",
"Human Alignment Score": "OneIG (Human Alignment)",
"Object Alignment Score": "OneIG (Object Alignment)",
"OneIG (Anime and Stylization) (Alignment Score)": "OneIG (Anime Alignment)",
"OneIG (Portrait) (Alignment Score)": "OneIG (Human Alignment)",
"OneIG (General Object) (Alignment Score)": "OneIG (Object Alignment)",
}
)
df = df.drop(
columns=[
column
for column in ("URL", "Device", "Optimization", "Optimization Details")
if column in df.columns
]
)
if "Optimized" in df.columns:
df["Optimized"] = df["Optimized"].map(
{True: "Yes", False: "No", "TRUE": "Yes", "FALSE": "No"}
).fillna(df["Optimized"])
return _as_numeric(
df,
[
"Price / Image (USD)",
"Median Generation Time (s)",
"Min Generation Time (s)",
"OneIG (Anime Alignment)",
"OneIG (Human Alignment)",
"OneIG (Object Alignment)",
"OneIG Anime Elo",
"OneIG Human Elo",
"OneIG Object Elo",
"P-Judge Overall",
"Rapidata Elo",
],
)
def load_artificial_analysis_dataframe(path):
"""Load the Artificial Analysis text-to-image leaderboard."""
df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
df = df.rename(
columns={
"model": "Model",
"elo": "Artificial Analysis Elo",
"price_per_image_usd": "Price / Image (USD)",
}
)
df["Model"] = df["Model"].astype(str).str.strip()
return _as_numeric(
df, ["Artificial Analysis Elo", "Price / Image (USD)"]
).reset_index(drop=True)
ARENA_CATEGORY_COLUMNS = {
"product_branding_commercial_design_elo": "Arena Branding / Commercial Elo",
"3d_imaging_and_modeling_elo": "Arena 3D Imaging Elo",
"cartoon_anime_and_fantasy_elo": "Arena Cartoon / Anime Elo",
"photorealistic_and_cinematic_imagery_elo": "Arena Photorealistic Elo",
"art_elo": "Arena Art Elo",
"portraits_elo": "Arena Portraits Elo",
"text_rendering_elo": "Arena Text Rendering Elo",
}
def load_arena_ai_dataframe(path):
"""Load the Arena AI text-to-image leaderboard (overall + category Elos)."""
df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
rename_map = {"model": "Model", "elo": "Arena Elo"}
rename_map.update(
{
source: label
for source, label in ARENA_CATEGORY_COLUMNS.items()
if source in df.columns
}
)
df = df.rename(columns=rename_map)
df["Model"] = df["Model"].astype(str).str.strip()
score_columns = [
column
for column in ["Arena Elo", *ARENA_CATEGORY_COLUMNS.values()]
if column in df.columns
]
df = _as_numeric(df, score_columns)
ordered = ["Model", *score_columns]
return df[[column for column in ordered if column in df.columns]].reset_index(
drop=True
)
def load_qwen_combined_dataframe(path):
"""Load the combined Qwen Image Bench metrics table."""
df = pd.read_csv(path, na_values=["N/A", "n/a", ""])
model_column = "Rapidata Model" if "Rapidata Model" in df.columns else "Model"
df = df.rename(columns={model_column: "Model"})
# Rows prefixed with '#' are commented-out variants in the source exports.
df = df[~df["Model"].astype(str).str.startswith("#")].copy()
df["Model"] = df["Model"].astype(str).str.strip()
return _as_numeric(
df,
[
"Price / Image (USD)",
"Median Generation Time (s)",
"Min Generation Time (s)",
"P-Judge Overall",
"Rapidata Elo",
"Datapoint Elo",
],
).reset_index(drop=True)
df = load_oneig_dataframe(oneig_path)
oneig_metric_columns = [
col
for col in [
"OneIG (Anime Alignment)",
"OneIG (Human Alignment)",
"OneIG (Object Alignment)",
]
if col in df.columns
]
oneig_df = df.copy()
if oneig_metric_columns:
oneig_df["OneIG Overall Score"] = oneig_df[oneig_metric_columns].mean(
axis=1, skipna=True
)
oneig_display_columns = [
col
for col in [
"Platform",
"Endpoint Owner",
"Model",
"Optimized",
"OneIG Overall Score",
*oneig_metric_columns,
"OneIG Anime Elo",
"OneIG Human Elo",
"OneIG Object Elo",
"P-Judge Overall",
"Rapidata Elo",
"Evaluation Date (UTC)",
"Median Generation Time (s)",
"Min Generation Time (s)",
"Price / Image (USD)",
]
if col in oneig_df.columns
]
oneig_combined_dir = _resolve_data_path(
data_dir / "oneig_combined",
space_root.parent / "oneig_combined",
)
qwen_combined_dir = _resolve_data_path(
data_dir / "qwen_image_bench_combined",
space_root.parent / "qwen_image_bench_combined",
)
qwen_path = _resolve_data_path(
data_dir / "qwen_image_bench_model_price_and_median_generation_time.csv",
space_root.parent / "qwen_image_bench_model_price_and_median_generation_time.csv",
)
aa_path = _resolve_data_path(
data_dir / "artificial_analysis_text_to_image_leaderboard.csv",
space_root.parent / "artificial_analysis_text_to_image_leaderboard.csv",
)
arena_path = _resolve_data_path(
data_dir / "arena_ai_text_to_image_leaderboard.csv",
space_root.parent / "arena_ai_text_to_image_leaderboard.csv",
)
qwen_df = load_qwen_combined_dataframe(qwen_path)
aa_df = load_artificial_analysis_dataframe(aa_path)
arena_df = load_arena_ai_dataframe(arena_path)
qwen_display_columns = [
col
for col in [
"Model",
"Datapoint Elo",
"Rapidata Elo",
"P-Judge Overall",
"Raw Win Rate",
"Median Generation Time (s)",
"Min Generation Time (s)",
"Price / Image (USD)",
]
if col in qwen_df.columns
]
aa_display_columns = [
col
for col in [
"Model",
"Artificial Analysis Elo",
"Price / Image (USD)",
]
if col in aa_df.columns
]
arena_display_columns = [
col
for col in [
"Model",
"Arena Elo",
*ARENA_CATEGORY_COLUMNS.values(),
]
if col in arena_df.columns
]
oneig_samples = load_sample_comparison_data(oneig_combined_dir)
qwen_samples = load_sample_comparison_data(qwen_combined_dir)
metrics = [
{"id": "datapoint_elo", "column": "Datapoint Elo"},
{"id": "rapidata_elo", "column": "Rapidata Elo"},
{"id": "pjudger", "column": "P-Judge Overall"},
{"id": "alignment_overall", "column": "OneIG Overall Score"},
{"id": "datapoint_elo_anime", "column": "OneIG Anime Elo"},
{"id": "datapoint_elo_human", "column": "OneIG Human Elo"},
{"id": "datapoint_elo_object", "column": "OneIG Object Elo"},
{"id": "aa_elo", "column": "Artificial Analysis Elo"},
{"id": "arena_elo", "column": "Arena Elo"},
{"id": "arena_branding", "column": "Arena Branding / Commercial Elo"},
{"id": "arena_3d", "column": "Arena 3D Imaging Elo"},
{"id": "arena_cartoon", "column": "Arena Cartoon / Anime Elo"},
{"id": "arena_photo", "column": "Arena Photorealistic Elo"},
{"id": "arena_art", "column": "Arena Art Elo"},
{"id": "arena_portraits", "column": "Arena Portraits Elo"},
{"id": "arena_text", "column": "Arena Text Rendering Elo"},
]
def _metric_ids_for(data, metric_ids):
columns = getattr(data, "columns", [])
return [
metric_id
for metric_id in metric_ids
if any(metric["id"] == metric_id and metric["column"] in columns for metric in metrics)
]
qwen_metric_ids = _metric_ids_for(
qwen_df, ["datapoint_elo", "rapidata_elo", "pjudger"]
)
oneig_metric_ids = _metric_ids_for(
oneig_df,
[
"alignment_overall",
"rapidata_elo",
"pjudger",
"datapoint_elo_anime",
"datapoint_elo_human",
"datapoint_elo_object",
],
)
aa_metric_ids = _metric_ids_for(aa_df, ["aa_elo"])
arena_metric_ids = _metric_ids_for(
arena_df,
[
"arena_elo",
"arena_branding",
"arena_3d",
"arena_cartoon",
"arena_photo",
"arena_art",
"arena_portraits",
"arena_text",
],
)
datasets = [
{
"id": "qwen",
"name": "Qwen Image Dataset",
"data": qwen_df,
"columns": qwen_display_columns,
"metric_ids": qwen_metric_ids,
"note": "Rapidata Elo is a metric on this dataset, not a dataset of its own.",
"samples": qwen_samples,
},
{
"id": "oneig",
"name": "OneIG Alignment Dataset",
"data": oneig_df,
"columns": oneig_display_columns,
"metric_ids": oneig_metric_ids,
"note": (
"Alignment Overall is the mean of the available category scores. "
"Missing categories are skipped for that model."
),
"samples": oneig_samples,
},
{
"id": "artificial_analysis",
"name": "Artificial Analysis Dataset",
"data": aa_df,
"columns": aa_display_columns,
"metric_ids": aa_metric_ids,
"note": "",
"samples": None,
},
{
"id": "arena_ai",
"name": "Arena AI Dataset",
"data": arena_df,
"columns": arena_display_columns,
"metric_ids": arena_metric_ids,
"note": "",
"samples": None,
},
]
datasets = [dataset for dataset in datasets if dataset["metric_ids"]]
DEFAULT_DATASET_ID = next(
(dataset["id"] for dataset in datasets if dataset["id"] == "qwen"),
datasets[0]["id"] if datasets else None,
)
DEFAULT_METRIC_ID = None
custom_head = """
<script>
(function () {
var mode = "dark";
try {
var stored = localStorage.getItem("inferbench-theme");
if (stored === "light" || stored === "dark") mode = stored;
else {
var param = new URLSearchParams(location.search).get("__theme");
if (param === "light" || param === "dark") mode = param;
}
} catch (e) {}
document.documentElement.classList.toggle("dark", mode === "dark");
document.documentElement.dataset.theme = mode;
})();
</script>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<script>
(() => {
const STORAGE_KEY = "inferbench-theme";
const PLOT_LAYOUT = {
dark: {
paper_bgcolor: "#171021",
plot_bgcolor: "#1d1429",
"font.color": "#d4d4d4",
"legend.font.color": "#d4d4d4",
"xaxis.gridcolor": "rgba(74, 57, 98, 0.55)",
"xaxis.color": "#d4d4d4",
"xaxis.title.font.color": "#fafafa",
"xaxis.tickfont.color": "#a3a3a3",
"yaxis.gridcolor": "rgba(74, 57, 98, 0.55)",
"yaxis.color": "#d4d4d4",
"yaxis.title.font.color": "#fafafa",
"yaxis.tickfont.color": "#a3a3a3",
},
light: {
paper_bgcolor: "#f6f3fa",
plot_bgcolor: "#ffffff",
"font.color": "#3f3f46",
"legend.font.color": "#3f3f46",
"xaxis.gridcolor": "rgba(126, 34, 206, 0.12)",
"xaxis.color": "#3f3f46",
"xaxis.title.font.color": "#18181b",
"xaxis.tickfont.color": "#71717a",
"yaxis.gridcolor": "rgba(126, 34, 206, 0.12)",
"yaxis.color": "#3f3f46",
"yaxis.title.font.color": "#18181b",
"yaxis.tickfont.color": "#71717a",
},
};
const currentMode = () => {
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored === "light" || stored === "dark") return stored;
} catch (e) {}
const param = new URLSearchParams(location.search).get("__theme");
if (param === "light" || param === "dark") return param;
return "dark";
};
const queryAll = (selector) => {
const found = [...document.querySelectorAll(selector)];
document.querySelectorAll("gradio-app").forEach((app) => {
if (app.shadowRoot) found.push(...app.shadowRoot.querySelectorAll(selector));
});
return found;
};
const restylePlots = (mode) => {
const layout = PLOT_LAYOUT[mode];
if (!layout || typeof Plotly === "undefined") return;
queryAll(".js-plotly-plot").forEach((gd) => {
try { Plotly.relayout(gd, layout); } catch (e) {}
});
};
const applyMode = (mode, persist) => {
const dark = mode === "dark";
const targets = [
document.documentElement,
document.body,
...queryAll(".gradio-container"),
...document.querySelectorAll("gradio-app"),
].filter(Boolean);
targets.forEach((el) => {
el.classList.toggle("dark", dark);
el.classList.toggle("light", !dark);
});
document.documentElement.dataset.theme = mode;
const label = dark ? "Switch to light mode" : "Switch to dark mode";
queryAll(".theme-toggle").forEach((btn) => {
btn.setAttribute("data-mode", mode);
btn.setAttribute("aria-label", label);
btn.setAttribute("title", label);
});
if (persist) {
try { localStorage.setItem(STORAGE_KEY, mode); } catch (e) {}
try {
const url = new URL(location.href);
url.searchParams.set("__theme", mode);
history.replaceState(null, "", url);
} catch (e) {}
}
restylePlots(mode);
};
applyMode(currentMode(), false);
document.addEventListener("click", (event) => {
const path = typeof event.composedPath === "function" ? event.composedPath() : [event.target];
const btn = path.find((el) => el.classList && el.classList.contains("theme-toggle"));
if (!btn) return;
event.preventDefault();
const next = currentMode() === "dark" ? "light" : "dark";
applyMode(next, true);
});
const sync = () => applyMode(currentMode(), false);
document.addEventListener("DOMContentLoaded", sync);
window.addEventListener("load", () => {
sync();
setTimeout(sync, 80);
setTimeout(sync, 400);
});
const startObserver = () => {
if (!document.body || window.__inferbenchThemeObserver) return;
window.__inferbenchThemeObserver = true;
const onMutations = (mutations) => {
const mode = currentMode();
const isDark = document.documentElement.classList.contains("dark");
const added = mutations.flatMap((mutation) => [...mutation.addedNodes]).filter((node) => node.nodeType === 1);
const hasContainer = added.some((node) => (
node.classList?.contains("gradio-container") ||
node.querySelector?.(".gradio-container, .theme-toggle")
));
if ((mode === "dark") !== isDark || hasContainer) applyMode(mode, false);
const hasPlot = added.some((node) => (
node.classList?.contains("js-plotly-plot") ||
node.querySelector?.(".js-plotly-plot")
));
if (hasPlot) restylePlots(mode);
};
new MutationObserver(onMutations).observe(document.body, { childList: true, subtree: true });
document.querySelectorAll("gradio-app").forEach((app) => {
if (app.shadowRoot) {
new MutationObserver(onMutations).observe(app.shadowRoot, { childList: true, subtree: true });
}
});
};
if (document.body) startObserver();
else document.addEventListener("DOMContentLoaded", startObserver);
})();
</script>
<script>
(() => {
if (window.__inferbenchLeaderboardSortBound) return;
window.__inferbenchLeaderboardSortBound = true;
document.addEventListener("click", (event) => {
const th = event.target.closest(".ranking-table th.sortable-col");
if (!th) return;
const table = th.closest("table");
const tbody = table && table.querySelector("tbody");
if (!tbody) return;
const col = Number(th.dataset.col);
const type = th.dataset.type || "text";
const ascending = !th.classList.contains("sorted-asc");
table.querySelectorAll("th.sortable-col").forEach((header) => {
header.classList.remove("sorted-asc", "sorted-desc");
});
th.classList.add(ascending ? "sorted-asc" : "sorted-desc");
const rows = Array.from(tbody.querySelectorAll("tr"));
const parseValue = (row) => {
const cell = row.children[col];
const raw = cell ? cell.getAttribute("data-sort-value") : "";
if (raw === null || raw === "") return null;
if (type === "number") {
const number = Number(raw);
return Number.isFinite(number) ? number : null;
}
return raw;
};
rows.sort((left, right) => {
const a = parseValue(left);
const b = parseValue(right);
if (a === null && b === null) return 0;
if (a === null) return 1;
if (b === null) return -1;
if (type === "number") {
return ascending ? a - b : b - a;
}
const cmp = String(a).localeCompare(String(b), undefined, {
numeric: true,
sensitivity: "base",
});
return ascending ? cmp : -cmp;
});
rows.forEach((row) => tbody.appendChild(row));
});
})();
</script>
<script>
(() => {
if (window.__inferbenchChipScrollBound) return;
window.__inferbenchChipScrollBound = true;
document.addEventListener("wheel", (event) => {
const row = event.target.closest?.(".view-filters .filter-chips .wrap-inner");
if (!row || row.scrollWidth <= row.clientWidth + 1) return;
if (Math.abs(event.deltaY) < Math.abs(event.deltaX)) return;
row.scrollLeft += event.deltaY;
event.preventDefault();
}, { capture: true, passive: false });
})();
</script>
"""
with gr.Blocks(
title="P-Bench",
theme=theme,
fill_width=True,
css=custom_css,
head=custom_head,
) as demo:
render_header()
render_image_workspace(
datasets,
metrics,
DEFAULT_DATASET_ID,
DEFAULT_METRIC_ID,
)
render_footer()
if __name__ == "__main__":
demo.launch(
ssr_mode=False,
allowed_paths=[str(space_root)],
)