Upload folder using huggingface_hub
Browse files- README.md +1 -1
- app.py +132 -63
- requirements.txt +1 -1
README.md
CHANGED
|
@@ -9,7 +9,7 @@ emoji: 🛍️
|
|
| 9 |
|
| 10 |
# PEFT Shop
|
| 11 |
|
| 12 |
-
A Gradio app to browse PEFT methods like an online store: filter by capabilities (merging, multi-adapter support, quantization backends, targetable layer types, …) and check benchmark results — star ratings for the benchmark-specific metrics (test accuracy and forgetting for MetaMathQA, DINO similarity and drift for image generation) as well as peak memory, checkpoint size, and train time, switchable between the benchmarks of the method comparison suite. Methods can be added to a cart 🛒, which shows usage code snippets and a feature comparison table for the collected methods — and checkout is, of course, free.
|
| 13 |
|
| 14 |
## Running
|
| 15 |
|
|
|
|
| 9 |
|
| 10 |
# PEFT Shop
|
| 11 |
|
| 12 |
+
A Gradio app to browse PEFT methods like an online store: filter by capabilities (merging, multi-adapter support, quantization backends, targetable layer types, …) or by minimum customer rating ("★★★☆☆ & up"), and check benchmark results — star ratings for the benchmark-specific metrics (test accuracy and forgetting for MetaMathQA, DINO similarity and drift for image generation) as well as peak memory, checkpoint size, and train time, switchable between the benchmarks of the method comparison suite. Methods can be added to a cart 🛒, which shows usage code snippets and a feature comparison table for the collected methods — and checkout is, of course, free.
|
| 13 |
|
| 14 |
## Running
|
| 15 |
|
app.py
CHANGED
|
@@ -14,8 +14,8 @@
|
|
| 14 |
"""The PEFT shop: a Gradio app to browse PEFT methods like an online store.
|
| 15 |
|
| 16 |
Users can filter methods by their capabilities (merging, multi-adapter support, quantization backends, targetable
|
| 17 |
-
layer types, ...), check benchmark results (switchable between the benchmarks of the
|
| 18 |
-
MetaMathQA or image generation), and jump to the PEFT docs. The app has two tabs: one to browse the shop, one for the
|
| 19 |
cart, which shows usage code snippets and a feature comparison table for the collected methods. In keeping with the
|
| 20 |
shop theme, every method has a (crossed-out) price tag, benchmark results double as customer star ratings, and
|
| 21 |
checkout is free.
|
|
@@ -509,8 +509,8 @@ def _stars_span(n_stars: int, title: str) -> str:
|
|
| 509 |
return f'<span class="stars" title="{esc(title)}">{"★" * n_stars}{"☆" * (5 - n_stars)}</span>'
|
| 510 |
|
| 511 |
|
| 512 |
-
def
|
| 513 |
-
"""
|
| 514 |
|
| 515 |
The best 20% of the methods get five stars, the next 20% four, and so on; even the worst method keeps one star.
|
| 516 |
Quantiles are used instead of e.g. min-max scaling so that a single outlier cannot compress everyone else's
|
|
@@ -519,8 +519,35 @@ def benchmark_stars(spec: BenchmarkSpec, field: str, value: float, title: str, l
|
|
| 519 |
"""
|
| 520 |
values = [info["benchmarks"][spec.key][field] for info in METHODS.values() if spec.key in info["benchmarks"]]
|
| 521 |
rank = sum(other < value if lower_is_better else other > value for other in values)
|
| 522 |
-
|
| 523 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
|
| 525 |
|
| 526 |
def badge(value: bool | None, label: str, title: str | None = None) -> str:
|
|
@@ -559,55 +586,30 @@ def render_card(method: str, spec: BenchmarkSpec) -> str:
|
|
| 559 |
else ""
|
| 560 |
)
|
| 561 |
|
| 562 |
-
# per
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
bench_rows += [
|
| 576 |
-
(
|
| 577 |
-
"peak_memory_bytes",
|
| 578 |
-
"max memory allocated",
|
| 579 |
-
fmt_bytes(bench["peak_memory_bytes"]),
|
| 580 |
-
f"Peak accelerator memory while training on the PEFT {spec.label} benchmark",
|
| 581 |
-
True,
|
| 582 |
-
"",
|
| 583 |
-
),
|
| 584 |
-
(
|
| 585 |
-
"adapter_file_size_bytes",
|
| 586 |
-
"checkpoint size",
|
| 587 |
-
fmt_megabytes(bench["adapter_file_size_bytes"]),
|
| 588 |
-
f"Size of the saved checkpoint on the PEFT {spec.label} benchmark",
|
| 589 |
-
True,
|
| 590 |
-
"",
|
| 591 |
-
),
|
| 592 |
-
(
|
| 593 |
-
"train_time_sec",
|
| 594 |
-
"train time",
|
| 595 |
-
fmt_minutes(bench["train_time_sec"]),
|
| 596 |
-
f"Training time on the PEFT {spec.label} benchmark",
|
| 597 |
-
True,
|
| 598 |
-
"",
|
| 599 |
-
),
|
| 600 |
-
]
|
| 601 |
# the hover text sits on the whole row (and, redundantly, on the stars span inside it), so hovering the
|
| 602 |
# metric name or the value explains the metric as well
|
| 603 |
row_html = []
|
| 604 |
-
for field, label,
|
| 605 |
direction = "lower is better" if lower_is_better else "higher is better"
|
| 606 |
-
|
|
|
|
| 607 |
stars = benchmark_stars(spec, field, bench[field], title, lower_is_better=lower_is_better)
|
| 608 |
row_html.append(
|
| 609 |
f'<div class="bench-row" title="{esc(title)}"><span>{stars} {esc(label)}:</span>'
|
| 610 |
-
f"<strong>{esc(
|
| 611 |
)
|
| 612 |
bench_html = f"""
|
| 613 |
<div class="bench" title="Best of {bench["num_runs"]} run(s): {esc(bench["experiment_name"])}">
|
|
@@ -660,6 +662,7 @@ def matches_filters(
|
|
| 660 |
quant: list[str],
|
| 661 |
benchmarked_only: bool,
|
| 662 |
bench_key: str,
|
|
|
|
| 663 |
) -> bool:
|
| 664 |
"""Filter semantics ("e-commerce" style):
|
| 665 |
|
|
@@ -669,25 +672,39 @@ def matches_filters(
|
|
| 669 |
- across filter groups: AND
|
| 670 |
- values reported as "unknown" by the capability script never match a positive filter: users filtering for a
|
| 671 |
feature should only see methods where support is established.
|
|
|
|
|
|
|
| 672 |
"""
|
| 673 |
info = METHODS[method]
|
| 674 |
if search:
|
| 675 |
haystack = f"{method} {info['config_class']} {info['description']}".lower()
|
| 676 |
if search.lower() not in haystack:
|
| 677 |
return False
|
|
|
|
| 678 |
if categories and feature(method, "category")["value"] not in categories:
|
| 679 |
return False
|
|
|
|
| 680 |
if any(capability_value(method, key) is not True for key in capabilities):
|
| 681 |
return False
|
|
|
|
| 682 |
if layers:
|
| 683 |
supported = layer_types(method)
|
| 684 |
if supported is None or any(not supported.get(layer) for layer in layers):
|
| 685 |
return False
|
|
|
|
| 686 |
if quant and not any(supports_quant(method, backend) for backend in quant):
|
| 687 |
return False
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 691 |
|
| 692 |
|
| 693 |
def sort_key(sort_by: str, bench_key: str):
|
|
@@ -714,19 +731,24 @@ ADD_TO_CART_LABEL = "🛒 Add to cart"
|
|
| 714 |
IN_CART_LABEL = "✅ In cart"
|
| 715 |
|
| 716 |
|
| 717 |
-
def update_cards(
|
|
|
|
|
|
|
| 718 |
"""Assign the filtered, sorted methods to the fixed pool of card slots.
|
| 719 |
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
|
|
|
| 723 |
"""
|
| 724 |
spec = BENCHMARKS_BY_KEY[bench_key]
|
| 725 |
cart = cart or []
|
| 726 |
selected = [
|
| 727 |
method
|
| 728 |
for method in METHODS
|
| 729 |
-
if matches_filters(
|
|
|
|
|
|
|
| 730 |
]
|
| 731 |
selected.sort(key=sort_key(sort_by, bench_key))
|
| 732 |
count = f"**{len(selected)} of {len(METHODS)} items** — all free, all in stock"
|
|
@@ -751,7 +773,17 @@ def reset_filters():
|
|
| 751 |
|
| 752 |
Programmatically resetting the components triggers their change listeners, which re-render the cards.
|
| 753 |
"""
|
| 754 |
-
return "", [], [], [], [], False, BENCHMARKS[0].key, "name"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 755 |
|
| 756 |
|
| 757 |
# ---------------------------------------------------------------------------------------------------------------
|
|
@@ -1019,6 +1051,18 @@ CSS = """
|
|
| 1019 |
hidden, independently of whether Gradio applies the visible=False update to the column. */
|
| 1020 |
.method-card:not(:has(.card)) { display: none !important; }
|
| 1021 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1022 |
/* Enlarge the tab labels (Browse methods / Cart) so they are hard to miss. Tab buttons carry the ARIA role "tab";
|
| 1023 |
the .tab-nav fallback covers Gradio versions that don't set it. */
|
| 1024 |
button[role="tab"], .tab-nav button { font-size: 1.3rem !important; font-weight: 600 !important;
|
|
@@ -1065,6 +1109,25 @@ def build_demo() -> gr.Blocks:
|
|
| 1065 |
quant = gr.CheckboxGroup(
|
| 1066 |
choices=sorted(quant_names), label="Quantization (any selected backend)"
|
| 1067 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1068 |
benchmarked_only = gr.Checkbox(label="Only methods with results on the selected benchmark")
|
| 1069 |
with gr.Column(scale=3):
|
| 1070 |
with gr.Row():
|
|
@@ -1116,10 +1179,12 @@ def build_demo() -> gr.Blocks:
|
|
| 1116 |
"each method shows its best run on the selected benchmark.</small>"
|
| 1117 |
)
|
| 1118 |
|
| 1119 |
-
|
| 1120 |
-
|
| 1121 |
-
#
|
| 1122 |
-
|
|
|
|
|
|
|
| 1123 |
slot_outputs = [count_md]
|
| 1124 |
for slot_column, slot_html, slot_method, slot_button in slots:
|
| 1125 |
slot_outputs.extend([slot_column, slot_html, slot_method, slot_button])
|
|
@@ -1142,9 +1207,13 @@ def build_demo() -> gr.Blocks:
|
|
| 1142 |
trigger_mode="always_last",
|
| 1143 |
)
|
| 1144 |
demo.load(update_cards, inputs=card_inputs, outputs=slot_outputs, show_progress="hidden")
|
|
|
|
|
|
|
| 1145 |
|
| 1146 |
for _, _, slot_method, slot_button in slots:
|
| 1147 |
-
slot_button.click(
|
|
|
|
|
|
|
| 1148 |
|
| 1149 |
# Updating cart_select programmatically (from the cards' add buttons or "clear cart") also triggers these
|
| 1150 |
# listeners, so the code snippet, the comparison table, the pay receipt, the cart tab label, and the
|
|
@@ -1152,7 +1221,7 @@ def build_demo() -> gr.Blocks:
|
|
| 1152 |
cart_outputs = [cart_code, compare_html, receipt_html, cart_tab]
|
| 1153 |
cart_select.change(update_cart, inputs=cart_select, outputs=cart_outputs, show_progress="hidden")
|
| 1154 |
cart_select.change(update_cards, inputs=card_inputs, outputs=slot_outputs, show_progress="hidden")
|
| 1155 |
-
clear_button.click(
|
| 1156 |
# the receipt is kept up to date by update_cart, so paying only needs to open the popover, which is a purely
|
| 1157 |
# client-side affair (fn=None + js); same for writing to the clipboard, which only the browser can do
|
| 1158 |
pay_button.click(None, js="() => document.getElementById('pay-receipt')?.togglePopover(true)")
|
|
|
|
| 14 |
"""The PEFT shop: a Gradio app to browse PEFT methods like an online store.
|
| 15 |
|
| 16 |
Users can filter methods by their capabilities (merging, multi-adapter support, quantization backends, targetable
|
| 17 |
+
layer types, ...) and by minimum star ratings, check benchmark results (switchable between the benchmarks of the
|
| 18 |
+
method comparison suite, e.g. MetaMathQA or image generation), and jump to the PEFT docs. The app has two tabs: one to browse the shop, one for the
|
| 19 |
cart, which shows usage code snippets and a feature comparison table for the collected methods. In keeping with the
|
| 20 |
shop theme, every method has a (crossed-out) price tag, benchmark results double as customer star ratings, and
|
| 21 |
checkout is free.
|
|
|
|
| 509 |
return f'<span class="stars" title="{esc(title)}">{"★" * n_stars}{"☆" * (5 - n_stars)}</span>'
|
| 510 |
|
| 511 |
|
| 512 |
+
def star_rating(spec: BenchmarkSpec, field: str, value: float, lower_is_better: bool = False) -> int:
|
| 513 |
+
"""The customer star rating of one benchmark metric value, based on quantiles among the benchmarked PEFT methods.
|
| 514 |
|
| 515 |
The best 20% of the methods get five stars, the next 20% four, and so on; even the worst method keeps one star.
|
| 516 |
Quantiles are used instead of e.g. min-max scaling so that a single outlier cannot compress everyone else's
|
|
|
|
| 519 |
"""
|
| 520 |
values = [info["benchmarks"][spec.key][field] for info in METHODS.values() if spec.key in info["benchmarks"]]
|
| 521 |
rank = sum(other < value if lower_is_better else other > value for other in values)
|
| 522 |
+
return 5 - int(5 * rank / len(values))
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
def benchmark_stars(spec: BenchmarkSpec, field: str, value: float, title: str, lower_is_better: bool = False) -> str:
|
| 526 |
+
"""A benchmark metric as a customer star rating (see star_rating), rendered as a hoverable span."""
|
| 527 |
+
return _stars_span(star_rating(spec, field, value, lower_is_better), title)
|
| 528 |
+
|
| 529 |
+
|
| 530 |
+
def rated_metrics(spec: BenchmarkSpec) -> list[tuple[str, str, bool]]:
|
| 531 |
+
"""(field, label, lower_is_better) of every star-rated metric of a benchmark, in card-row order.
|
| 532 |
+
|
| 533 |
+
This is the single source of truth for the rated rows: the cards, the rating filters, and their labels all
|
| 534 |
+
derive from it.
|
| 535 |
+
"""
|
| 536 |
+
rows = [(metric.field, metric.label, not metric.higher_is_better) for metric in spec.metrics]
|
| 537 |
+
rows += [
|
| 538 |
+
("peak_memory_bytes", "max memory allocated", True),
|
| 539 |
+
("adapter_file_size_bytes", "checkpoint size", True),
|
| 540 |
+
("train_time_sec", "train time", True),
|
| 541 |
+
]
|
| 542 |
+
return rows
|
| 543 |
+
|
| 544 |
+
|
| 545 |
+
# The five clickable stars of a minimum-rating filter (a gr.Radio restyled into a star bar via the .star-filter
|
| 546 |
+
# CSS). Every choice renders as one star, the value is the minimum rating ("n stars & up"). The default of 1 filters
|
| 547 |
+
# nothing, as even the worst-rated method keeps one star.
|
| 548 |
+
RATING_CHOICES = [("★", n) for n in range(1, 6)]
|
| 549 |
+
# Number of rating filter slots; for benchmarks with fewer rated metrics, the surplus slots are hidden.
|
| 550 |
+
N_RATING_SLOTS = max(len(rated_metrics(spec)) for spec in BENCHMARKS)
|
| 551 |
|
| 552 |
|
| 553 |
def badge(value: bool | None, label: str, title: str | None = None) -> str:
|
|
|
|
| 586 |
else ""
|
| 587 |
)
|
| 588 |
|
| 589 |
+
# per-field value formatting and hover-text description; the rows themselves come from rated_metrics
|
| 590 |
+
formatters = {metric.field: (lambda v, metric=metric: fmt_metric(metric, v)) for metric in spec.metrics}
|
| 591 |
+
formatters |= {
|
| 592 |
+
"peak_memory_bytes": fmt_bytes,
|
| 593 |
+
"adapter_file_size_bytes": fmt_megabytes,
|
| 594 |
+
"train_time_sec": fmt_minutes,
|
| 595 |
+
}
|
| 596 |
+
descriptions = {metric.field: f"{metric.label} on the PEFT {spec.label} benchmark" for metric in spec.metrics}
|
| 597 |
+
descriptions |= {
|
| 598 |
+
"peak_memory_bytes": f"Peak accelerator memory while training on the PEFT {spec.label} benchmark",
|
| 599 |
+
"adapter_file_size_bytes": f"Size of the saved checkpoint on the PEFT {spec.label} benchmark",
|
| 600 |
+
"train_time_sec": f"Training time on the PEFT {spec.label} benchmark",
|
| 601 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
# the hover text sits on the whole row (and, redundantly, on the stars span inside it), so hovering the
|
| 603 |
# metric name or the value explains the metric as well
|
| 604 |
row_html = []
|
| 605 |
+
for field, label, lower_is_better in rated_metrics(spec):
|
| 606 |
direction = "lower is better" if lower_is_better else "higher is better"
|
| 607 |
+
ref = reference if field == score.field else ""
|
| 608 |
+
title = f"{descriptions[field]}; {direction}{ref}. Stars rank the method among the other PEFT methods."
|
| 609 |
stars = benchmark_stars(spec, field, bench[field], title, lower_is_better=lower_is_better)
|
| 610 |
row_html.append(
|
| 611 |
f'<div class="bench-row" title="{esc(title)}"><span>{stars} {esc(label)}:</span>'
|
| 612 |
+
f"<strong>{esc(formatters[field](bench[field]))}</strong></div>"
|
| 613 |
)
|
| 614 |
bench_html = f"""
|
| 615 |
<div class="bench" title="Best of {bench["num_runs"]} run(s): {esc(bench["experiment_name"])}">
|
|
|
|
| 662 |
quant: list[str],
|
| 663 |
benchmarked_only: bool,
|
| 664 |
bench_key: str,
|
| 665 |
+
min_stars: tuple[int, ...],
|
| 666 |
) -> bool:
|
| 667 |
"""Filter semantics ("e-commerce" style):
|
| 668 |
|
|
|
|
| 672 |
- across filter groups: AND
|
| 673 |
- values reported as "unknown" by the capability script never match a positive filter: users filtering for a
|
| 674 |
feature should only see methods where support is established.
|
| 675 |
+
- min_stars holds the minimum-rating filters, one per rated metric (in rated_metrics order, 1 = no minimum);
|
| 676 |
+
they apply to the selected benchmark, so methods without results on it cannot match.
|
| 677 |
"""
|
| 678 |
info = METHODS[method]
|
| 679 |
if search:
|
| 680 |
haystack = f"{method} {info['config_class']} {info['description']}".lower()
|
| 681 |
if search.lower() not in haystack:
|
| 682 |
return False
|
| 683 |
+
|
| 684 |
if categories and feature(method, "category")["value"] not in categories:
|
| 685 |
return False
|
| 686 |
+
|
| 687 |
if any(capability_value(method, key) is not True for key in capabilities):
|
| 688 |
return False
|
| 689 |
+
|
| 690 |
if layers:
|
| 691 |
supported = layer_types(method)
|
| 692 |
if supported is None or any(not supported.get(layer) for layer in layers):
|
| 693 |
return False
|
| 694 |
+
|
| 695 |
if quant and not any(supports_quant(method, backend) for backend in quant):
|
| 696 |
return False
|
| 697 |
+
|
| 698 |
+
if any(minimum > 1 for minimum in min_stars):
|
| 699 |
+
bench = info["benchmarks"].get(bench_key)
|
| 700 |
+
if bench is None:
|
| 701 |
+
return False
|
| 702 |
+
spec = BENCHMARKS_BY_KEY[bench_key]
|
| 703 |
+
for (field, _, lower_is_better), minimum in zip(rated_metrics(spec), min_stars):
|
| 704 |
+
if star_rating(spec, field, bench[field], lower_is_better) < minimum:
|
| 705 |
+
return False
|
| 706 |
+
|
| 707 |
+
return not (benchmarked_only and bench_key not in info["benchmarks"])
|
| 708 |
|
| 709 |
|
| 710 |
def sort_key(sort_by: str, bench_key: str):
|
|
|
|
| 731 |
IN_CART_LABEL = "✅ In cart"
|
| 732 |
|
| 733 |
|
| 734 |
+
def update_cards(
|
| 735 |
+
search, categories, capabilities, layers, quant, benchmarked_only, bench_key, sort_by, cart, *min_stars
|
| 736 |
+
):
|
| 737 |
"""Assign the filtered, sorted methods to the fixed pool of card slots.
|
| 738 |
|
| 739 |
+
The trailing arguments are the values of the rating filter slots (in rated_metrics order). Returns the count
|
| 740 |
+
markdown followed by (visibility, card HTML, method name, add button) for every slot; the button label shows
|
| 741 |
+
whether the slot's method is already in the cart. Slots beyond the number of matching methods are hidden and get
|
| 742 |
+
an empty method name, which add_to_cart treats as a no-op.
|
| 743 |
"""
|
| 744 |
spec = BENCHMARKS_BY_KEY[bench_key]
|
| 745 |
cart = cart or []
|
| 746 |
selected = [
|
| 747 |
method
|
| 748 |
for method in METHODS
|
| 749 |
+
if matches_filters(
|
| 750 |
+
method, search, categories, capabilities, layers, quant, benchmarked_only, bench_key, min_stars
|
| 751 |
+
)
|
| 752 |
]
|
| 753 |
selected.sort(key=sort_key(sort_by, bench_key))
|
| 754 |
count = f"**{len(selected)} of {len(METHODS)} items** — all free, all in stock"
|
|
|
|
| 773 |
|
| 774 |
Programmatically resetting the components triggers their change listeners, which re-render the cards.
|
| 775 |
"""
|
| 776 |
+
return ("", [], [], [], [], False, BENCHMARKS[0].key, "name") + (1,) * N_RATING_SLOTS
|
| 777 |
+
|
| 778 |
+
|
| 779 |
+
def update_rating_filters(bench_key):
|
| 780 |
+
"""Relabel the rating filter slots to the selected benchmark's rated metrics; surplus slots are hidden and
|
| 781 |
+
reset, so that a stale minimum cannot keep filtering invisibly."""
|
| 782 |
+
rows = rated_metrics(BENCHMARKS_BY_KEY[bench_key])
|
| 783 |
+
return [
|
| 784 |
+
gr.update(label=rows[i][1], visible=True) if i < len(rows) else gr.update(value=1, visible=False)
|
| 785 |
+
for i in range(N_RATING_SLOTS)
|
| 786 |
+
]
|
| 787 |
|
| 788 |
|
| 789 |
# ---------------------------------------------------------------------------------------------------------------
|
|
|
|
| 1051 |
hidden, independently of whether Gradio applies the visible=False update to the column. */
|
| 1052 |
.method-card:not(:has(.card)) { display: none !important; }
|
| 1053 |
|
| 1054 |
+
/* The minimum-rating filters: a gr.Radio restyled into a clickable star bar. The radio circles are hidden and every
|
| 1055 |
+
choice renders as one star; the stars up to the selected one stay gold, the ones after it are dimmed -- clicking
|
| 1056 |
+
the n-th star therefore reads as "n stars & up". */
|
| 1057 |
+
.star-filter .wrap { display: flex; flex-direction: row; flex-wrap: nowrap; gap: 0.15rem; }
|
| 1058 |
+
.star-filter label { background: none !important; border: none !important; box-shadow: none !important;
|
| 1059 |
+
padding: 0 !important; margin: 0 !important; cursor: pointer; }
|
| 1060 |
+
.star-filter label span { font-size: 1.5rem; line-height: 1; color: #f5b50a; padding: 0;
|
| 1061 |
+
display: inline-block; transition: transform 0.1s ease; }
|
| 1062 |
+
.star-filter label:hover span { transform: scale(1.2); }
|
| 1063 |
+
.star-filter input[type="radio"] { display: none; }
|
| 1064 |
+
.star-filter label:has(input:checked) ~ label span { color: #9ca3af; opacity: 0.45; }
|
| 1065 |
+
|
| 1066 |
/* Enlarge the tab labels (Browse methods / Cart) so they are hard to miss. Tab buttons carry the ARIA role "tab";
|
| 1067 |
the .tab-nav fallback covers Gradio versions that don't set it. */
|
| 1068 |
button[role="tab"], .tab-nav button { font-size: 1.3rem !important; font-weight: 600 !important;
|
|
|
|
| 1109 |
quant = gr.CheckboxGroup(
|
| 1110 |
choices=sorted(quant_names), label="Quantization (any selected backend)"
|
| 1111 |
)
|
| 1112 |
+
# one minimum-rating filter per star-rated card row, like a shop's "customer rating" filter;
|
| 1113 |
+
# the labels follow the selected benchmark (see update_rating_filters)
|
| 1114 |
+
with gr.Accordion("⭐ Minimum customer rating", open=False):
|
| 1115 |
+
gr.Markdown(
|
| 1116 |
+
"<small>Click the lowest acceptable rating ('n stars & up'). Ratings refer to the "
|
| 1117 |
+
"selected benchmark; with a minimum above one star, methods without results on it "
|
| 1118 |
+
"are filtered out.</small>"
|
| 1119 |
+
)
|
| 1120 |
+
default_rows = rated_metrics(BENCHMARKS[0])
|
| 1121 |
+
rating_filters = [
|
| 1122 |
+
gr.Radio(
|
| 1123 |
+
choices=RATING_CHOICES,
|
| 1124 |
+
value=1,
|
| 1125 |
+
label=default_rows[i][1] if i < len(default_rows) else "",
|
| 1126 |
+
visible=i < len(default_rows),
|
| 1127 |
+
elem_classes="star-filter",
|
| 1128 |
+
)
|
| 1129 |
+
for i in range(N_RATING_SLOTS)
|
| 1130 |
+
]
|
| 1131 |
benchmarked_only = gr.Checkbox(label="Only methods with results on the selected benchmark")
|
| 1132 |
with gr.Column(scale=3):
|
| 1133 |
with gr.Row():
|
|
|
|
| 1179 |
"each method shows its best run on the selected benchmark.</small>"
|
| 1180 |
)
|
| 1181 |
|
| 1182 |
+
basic_filters = [search, categories, capabilities, layers, quant, benchmarked_only, benchmark, sort_by]
|
| 1183 |
+
filter_inputs = basic_filters + rating_filters
|
| 1184 |
+
# The cart is an extra input to the card rendering (for the "in cart" button labels) but deliberately not
|
| 1185 |
+
# part of filter_inputs: resetting the filters must not clear the cart. It sits between the basic filters
|
| 1186 |
+
# and the rating filters so that update_cards can take the latter as its variadic tail.
|
| 1187 |
+
card_inputs = basic_filters + [cart_select] + rating_filters
|
| 1188 |
slot_outputs = [count_md]
|
| 1189 |
for slot_column, slot_html, slot_method, slot_button in slots:
|
| 1190 |
slot_outputs.extend([slot_column, slot_html, slot_method, slot_button])
|
|
|
|
| 1207 |
trigger_mode="always_last",
|
| 1208 |
)
|
| 1209 |
demo.load(update_cards, inputs=card_inputs, outputs=slot_outputs, show_progress="hidden")
|
| 1210 |
+
# the rating filters are labeled after the selected benchmark's metrics
|
| 1211 |
+
benchmark.change(update_rating_filters, inputs=benchmark, outputs=rating_filters, show_progress="hidden")
|
| 1212 |
|
| 1213 |
for _, _, slot_method, slot_button in slots:
|
| 1214 |
+
slot_button.click(
|
| 1215 |
+
add_to_cart, inputs=[cart_select, slot_method], outputs=cart_select, show_progress="hidden"
|
| 1216 |
+
)
|
| 1217 |
|
| 1218 |
# Updating cart_select programmatically (from the cards' add buttons or "clear cart") also triggers these
|
| 1219 |
# listeners, so the code snippet, the comparison table, the pay receipt, the cart tab label, and the
|
|
|
|
| 1221 |
cart_outputs = [cart_code, compare_html, receipt_html, cart_tab]
|
| 1222 |
cart_select.change(update_cart, inputs=cart_select, outputs=cart_outputs, show_progress="hidden")
|
| 1223 |
cart_select.change(update_cards, inputs=card_inputs, outputs=slot_outputs, show_progress="hidden")
|
| 1224 |
+
clear_button.click(list, outputs=cart_select, show_progress="hidden")
|
| 1225 |
# the receipt is kept up to date by update_cart, so paying only needs to open the popover, which is a purely
|
| 1226 |
# client-side affair (fn=None + js); same for writing to the clipboard, which only the browser can do
|
| 1227 |
pay_button.click(None, js="() => document.getElementById('pay-receipt')?.togglePopover(true)")
|
requirements.txt
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
gradio>=
|
|
|
|
| 1 |
+
gradio>=6.2
|