Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
fix some of the status
Browse files- app.py +20 -6
- backend/data_loader.py +63 -7
- frontend/leaderboard.html +51 -20
app.py
CHANGED
|
@@ -34,11 +34,25 @@ def update_leaderboard_cache():
|
|
| 34 |
if df.empty:
|
| 35 |
GLOBAL_LEADERBOARD_DATA = []
|
| 36 |
else:
|
| 37 |
-
# Fill numeric NaNs with 0, string NaNs with ""
|
| 38 |
-
df = df.fillna(0)
|
| 39 |
df = df.drop(columns=["Model Size Filter"], errors="ignore")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
if "Model Size" in df.columns:
|
| 41 |
-
df["Model Size"] =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
# Update global variable
|
| 44 |
GLOBAL_LEADERBOARD_DATA = df.drop(columns=["datetime"]).to_dict(orient="records")
|
|
@@ -122,8 +136,8 @@ async def get_model_likes(
|
|
| 122 |
"""Fetches the number of likes for a model from Hugging Face Hub."""
|
| 123 |
try:
|
| 124 |
info = API.model_info(repo_id=model_name, revision=revision, token=hf_api_token)
|
| 125 |
-
likes = info.likes
|
| 126 |
-
downloads = info.downloads
|
| 127 |
return JSONResponse(content={"likes": likes, "downloads": downloads})
|
| 128 |
except Exception as e:
|
| 129 |
logging.error(f"Error fetching likes for {model_name}: {e}")
|
|
@@ -169,4 +183,4 @@ async def read_page(request: Request, page_name: str):
|
|
| 169 |
return templates.TemplateResponse(page_name, {"request": request})
|
| 170 |
|
| 171 |
if __name__ == "__main__":
|
| 172 |
-
uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=True, access_log=False)
|
|
|
|
| 34 |
if df.empty:
|
| 35 |
GLOBAL_LEADERBOARD_DATA = []
|
| 36 |
else:
|
|
|
|
|
|
|
| 37 |
df = df.drop(columns=["Model Size Filter"], errors="ignore")
|
| 38 |
+
|
| 39 |
+
# Keep scores numeric, but show Unknown for missing metadata fields.
|
| 40 |
+
score_cols = [t[2] for t in TASKS] + ["Average", "Rank"]
|
| 41 |
+
for col in score_cols:
|
| 42 |
+
if col in df.columns:
|
| 43 |
+
df[col] = pd.to_numeric(df[col], errors="coerce").fillna(0)
|
| 44 |
+
|
| 45 |
if "Model Size" in df.columns:
|
| 46 |
+
size_series = pd.to_numeric(df["Model Size"], errors="coerce")
|
| 47 |
+
df["Model Size"] = size_series.apply(lambda v: int(v) if pd.notna(v) else "Unknown")
|
| 48 |
+
|
| 49 |
+
if "Hub ❤️" in df.columns:
|
| 50 |
+
likes_series = pd.to_numeric(df["Hub ❤️"], errors="coerce")
|
| 51 |
+
df["Hub ❤️"] = likes_series.apply(lambda v: int(v) if pd.notna(v) else "Unknown")
|
| 52 |
+
|
| 53 |
+
for col in ["License", "Revision", "Type", "Full Type", "Precision"]:
|
| 54 |
+
if col in df.columns:
|
| 55 |
+
df[col] = df[col].replace("", pd.NA).fillna("Unknown")
|
| 56 |
|
| 57 |
# Update global variable
|
| 58 |
GLOBAL_LEADERBOARD_DATA = df.drop(columns=["datetime"]).to_dict(orient="records")
|
|
|
|
| 136 |
"""Fetches the number of likes for a model from Hugging Face Hub."""
|
| 137 |
try:
|
| 138 |
info = API.model_info(repo_id=model_name, revision=revision, token=hf_api_token)
|
| 139 |
+
likes = info.likes
|
| 140 |
+
downloads = info.downloads
|
| 141 |
return JSONResponse(content={"likes": likes, "downloads": downloads})
|
| 142 |
except Exception as e:
|
| 143 |
logging.error(f"Error fetching likes for {model_name}: {e}")
|
|
|
|
| 183 |
return templates.TemplateResponse(page_name, {"request": request})
|
| 184 |
|
| 185 |
if __name__ == "__main__":
|
| 186 |
+
uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=True, access_log=False)
|
backend/data_loader.py
CHANGED
|
@@ -5,6 +5,7 @@ import os
|
|
| 5 |
import contextlib
|
| 6 |
import io
|
| 7 |
import logging
|
|
|
|
| 8 |
from pathlib import Path
|
| 9 |
from typing import Dict, List, Any, Optional
|
| 10 |
|
|
@@ -13,12 +14,14 @@ import pandas as pd
|
|
| 13 |
from huggingface_hub import snapshot_download
|
| 14 |
from datetime import datetime
|
| 15 |
from backend.config import (
|
|
|
|
| 16 |
REQUESTS_REPO_ID,
|
| 17 |
RESULTS_REPO_ID,
|
| 18 |
TASKS,
|
| 19 |
MODEL_TYPE_TO_EMOJI,
|
|
|
|
| 20 |
)
|
| 21 |
-
from backend.helpers import unify_precision
|
| 22 |
|
| 23 |
logger = logging.getLogger(__name__)
|
| 24 |
|
|
@@ -97,7 +100,7 @@ def _parse_result_file(path: Path) -> Optional[Dict[str, Any]]:
|
|
| 97 |
"Precision": precision,
|
| 98 |
"datetime": datetime.strptime(string_date, "%Y-%m-%dT%H-%M-%S.%f")
|
| 99 |
}
|
| 100 |
-
|
| 101 |
for task_key, metric_key, display in TASKS:
|
| 102 |
if isinstance(task_key,list):
|
| 103 |
weight_total = 0
|
|
@@ -122,6 +125,33 @@ def _parse_result_file(path: Path) -> Optional[Dict[str, Any]]:
|
|
| 122 |
return row
|
| 123 |
|
| 124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
def load_scoreboard() -> pd.DataFrame:
|
| 126 |
"""
|
| 127 |
Main entrypoint used by the Space UI.
|
|
@@ -155,12 +185,36 @@ def load_scoreboard() -> pd.DataFrame:
|
|
| 155 |
df[col] = (pd.to_numeric(df[col], errors="coerce") * 100).round(2)
|
| 156 |
df["Average"] = df[task_cols].mean(axis=1).round(2)
|
| 157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
# merge metadata from finished requests
|
| 159 |
finished = load_requests("finished")
|
| 160 |
if not finished.empty:
|
| 161 |
finished["precision"] = finished["precision"].apply(unify_precision)
|
| 162 |
meta = finished.groupby(["model", "precision"]).last().reset_index()
|
| 163 |
|
|
|
|
|
|
|
|
|
|
| 164 |
def enrich(row):
|
| 165 |
m = meta[
|
| 166 |
(meta["model"] == row["Model Name"]) &
|
|
@@ -168,13 +222,15 @@ def load_scoreboard() -> pd.DataFrame:
|
|
| 168 |
]
|
| 169 |
if not m.empty:
|
| 170 |
m = m.iloc[0]
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
|
|
|
| 175 |
row["Type"] = MODEL_TYPE_TO_EMOJI.get(
|
| 176 |
-
|
| 177 |
)
|
|
|
|
| 178 |
return row
|
| 179 |
|
| 180 |
df = df.apply(enrich, axis=1)
|
|
|
|
| 5 |
import contextlib
|
| 6 |
import io
|
| 7 |
import logging
|
| 8 |
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 9 |
from pathlib import Path
|
| 10 |
from typing import Dict, List, Any, Optional
|
| 11 |
|
|
|
|
| 14 |
from huggingface_hub import snapshot_download
|
| 15 |
from datetime import datetime
|
| 16 |
from backend.config import (
|
| 17 |
+
API,
|
| 18 |
REQUESTS_REPO_ID,
|
| 19 |
RESULTS_REPO_ID,
|
| 20 |
TASKS,
|
| 21 |
MODEL_TYPE_TO_EMOJI,
|
| 22 |
+
hf_api_token,
|
| 23 |
)
|
| 24 |
+
from backend.helpers import unify_precision, get_model_size
|
| 25 |
|
| 26 |
logger = logging.getLogger(__name__)
|
| 27 |
|
|
|
|
| 100 |
"Precision": precision,
|
| 101 |
"datetime": datetime.strptime(string_date, "%Y-%m-%dT%H-%M-%S.%f")
|
| 102 |
}
|
| 103 |
+
|
| 104 |
for task_key, metric_key, display in TASKS:
|
| 105 |
if isinstance(task_key,list):
|
| 106 |
weight_total = 0
|
|
|
|
| 125 |
return row
|
| 126 |
|
| 127 |
|
| 128 |
+
def _fetch_hf_metadata(model_name: str) -> Dict[str, Any]:
|
| 129 |
+
try:
|
| 130 |
+
info = API.model_info(repo_id=model_name, token=hf_api_token)
|
| 131 |
+
except Exception as e:
|
| 132 |
+
logger.warning("Could not fetch HF metadata for '%s': %s", model_name, e)
|
| 133 |
+
return {}
|
| 134 |
+
|
| 135 |
+
card_data = getattr(info, "card_data", None)
|
| 136 |
+
if isinstance(card_data, dict):
|
| 137 |
+
license_name = card_data.get("license")
|
| 138 |
+
else:
|
| 139 |
+
license_name = getattr(card_data, "license", None)
|
| 140 |
+
|
| 141 |
+
model_size = get_model_size(model_info=info, precision="")
|
| 142 |
+
if model_size == 0:
|
| 143 |
+
safetensors = getattr(info, "safetensors", None)
|
| 144 |
+
if not safetensors or not safetensors.get("total"):
|
| 145 |
+
model_size = None
|
| 146 |
+
|
| 147 |
+
return {
|
| 148 |
+
"License": license_name,
|
| 149 |
+
"Revision": getattr(info, "sha", None),
|
| 150 |
+
"Model Size": model_size,
|
| 151 |
+
"Hub ❤️": getattr(info, "likes", None),
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
|
| 155 |
def load_scoreboard() -> pd.DataFrame:
|
| 156 |
"""
|
| 157 |
Main entrypoint used by the Space UI.
|
|
|
|
| 185 |
df[col] = (pd.to_numeric(df[col], errors="coerce") * 100).round(2)
|
| 186 |
df["Average"] = df[task_cols].mean(axis=1).round(2)
|
| 187 |
|
| 188 |
+
# metadata from Hugging Face API (fetched in parallel for speed)
|
| 189 |
+
model_names = df["Model Name"].dropna().unique().tolist()
|
| 190 |
+
hf_meta: Dict[str, Dict[str, Any]] = {}
|
| 191 |
+
if model_names:
|
| 192 |
+
max_workers = min(12, len(model_names))
|
| 193 |
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
| 194 |
+
future_to_model = {
|
| 195 |
+
executor.submit(_fetch_hf_metadata, model_name): model_name
|
| 196 |
+
for model_name in model_names
|
| 197 |
+
}
|
| 198 |
+
for future in as_completed(future_to_model):
|
| 199 |
+
model_name = future_to_model[future]
|
| 200 |
+
hf_meta[model_name] = future.result() or {}
|
| 201 |
+
|
| 202 |
+
df["License"] = df["Model Name"].map(lambda name: hf_meta.get(name, {}).get("License"))
|
| 203 |
+
df["Revision"] = df["Model Name"].map(lambda name: hf_meta.get(name, {}).get("Revision"))
|
| 204 |
+
df["Model Size"] = df["Model Name"].map(lambda name: hf_meta.get(name, {}).get("Model Size"))
|
| 205 |
+
df["Hub ❤️"] = df["Model Name"].map(lambda name: hf_meta.get(name, {}).get("Hub ❤️"))
|
| 206 |
+
df["Type"] = None
|
| 207 |
+
df["Full Type"] = None
|
| 208 |
+
|
| 209 |
# merge metadata from finished requests
|
| 210 |
finished = load_requests("finished")
|
| 211 |
if not finished.empty:
|
| 212 |
finished["precision"] = finished["precision"].apply(unify_precision)
|
| 213 |
meta = finished.groupby(["model", "precision"]).last().reset_index()
|
| 214 |
|
| 215 |
+
def is_missing(v: Any) -> bool:
|
| 216 |
+
return v is None or (isinstance(v, str) and not v.strip()) or pd.isna(v)
|
| 217 |
+
|
| 218 |
def enrich(row):
|
| 219 |
m = meta[
|
| 220 |
(meta["model"] == row["Model Name"]) &
|
|
|
|
| 222 |
]
|
| 223 |
if not m.empty:
|
| 224 |
m = m.iloc[0]
|
| 225 |
+
if is_missing(row.get("License")):
|
| 226 |
+
row["License"] = m.get("license")
|
| 227 |
+
if is_missing(row.get("Revision")):
|
| 228 |
+
row["Revision"] = m.get("revision")
|
| 229 |
+
model_type_raw = m.get("model_type", "Missing")
|
| 230 |
row["Type"] = MODEL_TYPE_TO_EMOJI.get(
|
| 231 |
+
model_type_raw, model_type_raw
|
| 232 |
)
|
| 233 |
+
row["Full Type"] = model_type_raw
|
| 234 |
return row
|
| 235 |
|
| 236 |
df = df.apply(enrich, axis=1)
|
frontend/leaderboard.html
CHANGED
|
@@ -551,6 +551,19 @@
|
|
| 551 |
const $ = s => document.querySelector(s);
|
| 552 |
const $$ = s => [...document.querySelectorAll(s)];
|
| 553 |
const EVAL_COLUMNS = window.EVAL_COLUMNS;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 554 |
|
| 555 |
let lbData = [], grid, maxMeta = 100, minMeta = 0, tableColumns = [];
|
| 556 |
let currentSort = { colId: null, dir: 'none' };
|
|
@@ -565,9 +578,11 @@
|
|
| 565 |
window.initLeaderboard = function (data) {
|
| 566 |
lbData = data;
|
| 567 |
|
| 568 |
-
const sizes = lbData
|
| 569 |
-
|
| 570 |
-
|
|
|
|
|
|
|
| 571 |
|
| 572 |
if (!lbData.length) {
|
| 573 |
$('#table-wrapper').innerHTML = "<div class='p-8 text-center text-slate-500'>No data loaded.</div>";
|
|
@@ -691,30 +706,34 @@
|
|
| 691 |
`;
|
| 692 |
|
| 693 |
// Reset values
|
|
|
|
|
|
|
|
|
|
|
|
|
| 694 |
$('#modalRank').innerText = "#" + model["Rank"];
|
| 695 |
$('#modalAvg').innerText = parseFloat(model["Average"]).toFixed(2);
|
| 696 |
-
$('#modalSize').innerText =
|
| 697 |
-
$('#modalLikes').innerText =
|
| 698 |
// We don't have an ID for downloads yet in the static HTML, so we rely on the injected HTML below
|
| 699 |
-
$('#modalLicense').innerText = model["License"];
|
| 700 |
-
$('#modalPrecision').innerText = model["Precision"];
|
| 701 |
-
$('#modalRevision').innerText =
|
| 702 |
|
| 703 |
// --- 1. MODIFIED: Added Download Span to Metadata Line ---
|
| 704 |
// I added the separator dot and the Downloads span at the end of this block
|
| 705 |
const metadataHtml = `
|
| 706 |
-
<span class="flex items-center gap-1" title="License"><i data-lucide="scale" class="w-3.5 h-3.5"></i> <span id="modalLicense">${model["License"]}</span></span>
|
| 707 |
<span class="w-1 h-1 rounded-full bg-slate-300 dark:bg-slate-600"></span>
|
| 708 |
|
| 709 |
-
<span class="flex items-center gap-1" title="Precision"><i data-lucide="cpu" class="w-3.5 h-3.5"></i> <span id="modalPrecision">${model["Precision"]}</span></span>
|
| 710 |
<span class="w-1 h-1 rounded-full bg-slate-300 dark:bg-slate-600"></span>
|
| 711 |
|
| 712 |
-
<span class="flex items-center gap-1" title="Revision"><i data-lucide="git-commit" class="w-3.5 h-3.5"></i> <span id="modalRevision" class="font-mono">${
|
| 713 |
<span class="w-1 h-1 rounded-full bg-slate-300 dark:bg-slate-600"></span>
|
| 714 |
|
| 715 |
<span class="flex items-center gap-1" title="Downloads (last 30 days)">
|
| 716 |
<i data-lucide="download" class="w-3.5 h-3.5"></i>
|
| 717 |
-
<span id="modalDownloads">
|
| 718 |
</span>
|
| 719 |
`;
|
| 720 |
|
|
@@ -724,7 +743,7 @@
|
|
| 724 |
// --- Fetch Logic to include Downloads ---
|
| 725 |
const formData = new FormData();
|
| 726 |
formData.append('model_name', model["Model Name"]);
|
| 727 |
-
formData.append('revision',
|
| 728 |
|
| 729 |
fetch('/api/model-likes', {
|
| 730 |
method: 'POST',
|
|
@@ -732,16 +751,21 @@
|
|
| 732 |
})
|
| 733 |
.then(response => response.json())
|
| 734 |
.then(data => {
|
| 735 |
-
if (data.likes !== undefined) {
|
| 736 |
-
$('#modalLikes').innerText = data.likes;
|
| 737 |
}
|
| 738 |
// Check if API returns downloads and update
|
| 739 |
if (data.downloads !== undefined) {
|
| 740 |
const dl = document.getElementById('modalDownloads');
|
| 741 |
-
if (dl) dl.innerText = data.downloads
|
| 742 |
}
|
| 743 |
})
|
| 744 |
-
.catch(error =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 745 |
|
| 746 |
$('#modalLinkHF').href = `https://huggingface.co/${model["Model Name"]}`;
|
| 747 |
|
|
@@ -822,7 +846,11 @@
|
|
| 822 |
// 1. Filter Data
|
| 823 |
let filtered = lbData.filter(r =>
|
| 824 |
(r["Model Name"] || "").toLowerCase().includes(sVal) &&
|
| 825 |
-
(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 826 |
(!precs.length || precs.includes(r["Precision"])) &&
|
| 827 |
(!types.length || types.includes(r["Full Type"])) &&
|
| 828 |
(!lics.length || lics.includes(r["License"]))
|
|
@@ -850,7 +878,7 @@
|
|
| 850 |
if (!isNaN(nA) && !isNaN(nB)) {
|
| 851 |
return currentSort.dir === 'asc' ? nA - nB : nB - nA;
|
| 852 |
}
|
| 853 |
-
return
|
| 854 |
});
|
| 855 |
}
|
| 856 |
|
|
@@ -909,7 +937,10 @@
|
|
| 909 |
};
|
| 910 |
|
| 911 |
if (key === "Model Size") {
|
| 912 |
-
def.formatter = (c) =>
|
|
|
|
|
|
|
|
|
|
| 913 |
}
|
| 914 |
|
| 915 |
if (key === "Model Name") {
|
|
|
|
| 551 |
const $ = s => document.querySelector(s);
|
| 552 |
const $$ = s => [...document.querySelectorAll(s)];
|
| 553 |
const EVAL_COLUMNS = window.EVAL_COLUMNS;
|
| 554 |
+
const toNumber = (v) => {
|
| 555 |
+
const n = Number.parseFloat(v);
|
| 556 |
+
return Number.isFinite(n) ? n : null;
|
| 557 |
+
};
|
| 558 |
+
const asUnknown = (v) => {
|
| 559 |
+
if (v === undefined || v === null) return "Unknown";
|
| 560 |
+
const s = String(v).trim();
|
| 561 |
+
return s ? s : "Unknown";
|
| 562 |
+
};
|
| 563 |
+
const prettyIntOrUnknown = (v) => {
|
| 564 |
+
const n = toNumber(v);
|
| 565 |
+
return n === null ? "Unknown" : String(Math.floor(n));
|
| 566 |
+
};
|
| 567 |
|
| 568 |
let lbData = [], grid, maxMeta = 100, minMeta = 0, tableColumns = [];
|
| 569 |
let currentSort = { colId: null, dir: 'none' };
|
|
|
|
| 578 |
window.initLeaderboard = function (data) {
|
| 579 |
lbData = data;
|
| 580 |
|
| 581 |
+
const sizes = lbData
|
| 582 |
+
.map(r => toNumber(r["Model Size"]))
|
| 583 |
+
.filter(v => v !== null);
|
| 584 |
+
minMeta = sizes.length ? Math.floor(Math.min(...sizes)) : 0;
|
| 585 |
+
maxMeta = sizes.length ? Math.floor(Math.max(...sizes)) : 100;
|
| 586 |
|
| 587 |
if (!lbData.length) {
|
| 588 |
$('#table-wrapper').innerHTML = "<div class='p-8 text-center text-slate-500'>No data loaded.</div>";
|
|
|
|
| 706 |
`;
|
| 707 |
|
| 708 |
// Reset values
|
| 709 |
+
const revision = asUnknown(model["Revision"]);
|
| 710 |
+
const revisionForApi = revision === "Unknown" ? "main" : revision;
|
| 711 |
+
const modelSize = toNumber(model["Model Size"]);
|
| 712 |
+
const fallbackLikes = model["Hub ❤️"];
|
| 713 |
$('#modalRank').innerText = "#" + model["Rank"];
|
| 714 |
$('#modalAvg').innerText = parseFloat(model["Average"]).toFixed(2);
|
| 715 |
+
$('#modalSize').innerText = modelSize === null ? "Unknown" : `${Math.floor(modelSize)}B`;
|
| 716 |
+
$('#modalLikes').innerText = prettyIntOrUnknown(fallbackLikes);
|
| 717 |
// We don't have an ID for downloads yet in the static HTML, so we rely on the injected HTML below
|
| 718 |
+
$('#modalLicense').innerText = asUnknown(model["License"]);
|
| 719 |
+
$('#modalPrecision').innerText = asUnknown(model["Precision"]);
|
| 720 |
+
$('#modalRevision').innerText = revision;
|
| 721 |
|
| 722 |
// --- 1. MODIFIED: Added Download Span to Metadata Line ---
|
| 723 |
// I added the separator dot and the Downloads span at the end of this block
|
| 724 |
const metadataHtml = `
|
| 725 |
+
<span class="flex items-center gap-1" title="License"><i data-lucide="scale" class="w-3.5 h-3.5"></i> <span id="modalLicense">${asUnknown(model["License"])}</span></span>
|
| 726 |
<span class="w-1 h-1 rounded-full bg-slate-300 dark:bg-slate-600"></span>
|
| 727 |
|
| 728 |
+
<span class="flex items-center gap-1" title="Precision"><i data-lucide="cpu" class="w-3.5 h-3.5"></i> <span id="modalPrecision">${asUnknown(model["Precision"])}</span></span>
|
| 729 |
<span class="w-1 h-1 rounded-full bg-slate-300 dark:bg-slate-600"></span>
|
| 730 |
|
| 731 |
+
<span class="flex items-center gap-1" title="Revision"><i data-lucide="git-commit" class="w-3.5 h-3.5"></i> <span id="modalRevision" class="font-mono">${revision}</span></span>
|
| 732 |
<span class="w-1 h-1 rounded-full bg-slate-300 dark:bg-slate-600"></span>
|
| 733 |
|
| 734 |
<span class="flex items-center gap-1" title="Downloads (last 30 days)">
|
| 735 |
<i data-lucide="download" class="w-3.5 h-3.5"></i>
|
| 736 |
+
<span id="modalDownloads">Unknown</span>
|
| 737 |
</span>
|
| 738 |
`;
|
| 739 |
|
|
|
|
| 743 |
// --- Fetch Logic to include Downloads ---
|
| 744 |
const formData = new FormData();
|
| 745 |
formData.append('model_name', model["Model Name"]);
|
| 746 |
+
formData.append('revision', revisionForApi);
|
| 747 |
|
| 748 |
fetch('/api/model-likes', {
|
| 749 |
method: 'POST',
|
|
|
|
| 751 |
})
|
| 752 |
.then(response => response.json())
|
| 753 |
.then(data => {
|
| 754 |
+
if (data.likes !== undefined && data.likes !== null) {
|
| 755 |
+
$('#modalLikes').innerText = prettyIntOrUnknown(data.likes);
|
| 756 |
}
|
| 757 |
// Check if API returns downloads and update
|
| 758 |
if (data.downloads !== undefined) {
|
| 759 |
const dl = document.getElementById('modalDownloads');
|
| 760 |
+
if (dl) dl.innerText = prettyIntOrUnknown(data.downloads);
|
| 761 |
}
|
| 762 |
})
|
| 763 |
+
.catch(error => {
|
| 764 |
+
console.error('Error fetching stats:', error);
|
| 765 |
+
const dl = document.getElementById('modalDownloads');
|
| 766 |
+
if (dl) dl.innerText = "Unknown";
|
| 767 |
+
$('#modalLikes').innerText = prettyIntOrUnknown(fallbackLikes);
|
| 768 |
+
});
|
| 769 |
|
| 770 |
$('#modalLinkHF').href = `https://huggingface.co/${model["Model Name"]}`;
|
| 771 |
|
|
|
|
| 846 |
// 1. Filter Data
|
| 847 |
let filtered = lbData.filter(r =>
|
| 848 |
(r["Model Name"] || "").toLowerCase().includes(sVal) &&
|
| 849 |
+
(() => {
|
| 850 |
+
const s = toNumber(r["Model Size"]);
|
| 851 |
+
const sizeValue = s === null ? 0 : s;
|
| 852 |
+
return sizeValue >= minSz && sizeValue <= maxSz;
|
| 853 |
+
})() &&
|
| 854 |
(!precs.length || precs.includes(r["Precision"])) &&
|
| 855 |
(!types.length || types.includes(r["Full Type"])) &&
|
| 856 |
(!lics.length || lics.includes(r["License"]))
|
|
|
|
| 878 |
if (!isNaN(nA) && !isNaN(nB)) {
|
| 879 |
return currentSort.dir === 'asc' ? nA - nB : nB - nA;
|
| 880 |
}
|
| 881 |
+
return String(vA ?? "").localeCompare(String(vB ?? "")) * (currentSort.dir === 'asc' ? 1 : -1);
|
| 882 |
});
|
| 883 |
}
|
| 884 |
|
|
|
|
| 937 |
};
|
| 938 |
|
| 939 |
if (key === "Model Size") {
|
| 940 |
+
def.formatter = (c) => {
|
| 941 |
+
const n = toNumber(c);
|
| 942 |
+
return gridjs.html(`<span class="font-mono">${n === null ? "Unknown" : `${Math.floor(n)}B`}</span>`);
|
| 943 |
+
};
|
| 944 |
}
|
| 945 |
|
| 946 |
if (key === "Model Name") {
|