Spaces:
Running
Running
CrispStrobe commited on
Commit ·
704a297
1
Parent(s): 7cc1131
feat: simplify OCR display and optimize HF repo validation with caching
Browse files- data/providers.json +0 -0
- scripts/fetch-providers.js +2 -0
- scripts/validate-hf-ids.js +49 -30
- src/App.tsx +27 -31
data/providers.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/fetch-providers.js
CHANGED
|
@@ -57,6 +57,8 @@ function updateProviderModels(providers, providerName, models) {
|
|
| 57 |
ollama_id: newModel.ollama_id || existing.ollama_id,
|
| 58 |
hf_private: newModel.hf_private ?? existing.hf_private,
|
| 59 |
audio_price_per_1m: newModel.audio_price_per_1m || existing.audio_price_per_1m,
|
|
|
|
|
|
|
| 60 |
capabilities: (newModel.capabilities && newModel.capabilities.length > 0)
|
| 61 |
? newModel.capabilities
|
| 62 |
: existing.capabilities,
|
|
|
|
| 57 |
ollama_id: newModel.ollama_id || existing.ollama_id,
|
| 58 |
hf_private: newModel.hf_private ?? existing.hf_private,
|
| 59 |
audio_price_per_1m: newModel.audio_price_per_1m || existing.audio_price_per_1m,
|
| 60 |
+
hf_validated_at: existing.hf_validated_at,
|
| 61 |
+
hf_status: existing.hf_status,
|
| 62 |
capabilities: (newModel.capabilities && newModel.capabilities.length > 0)
|
| 63 |
? newModel.capabilities
|
| 64 |
: existing.capabilities,
|
scripts/validate-hf-ids.js
CHANGED
|
@@ -22,41 +22,60 @@ async function checkHfId(hfId) {
|
|
| 22 |
}
|
| 23 |
|
| 24 |
async function main() {
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
const data = JSON.parse(fs.readFileSync(PROVIDERS_FILE, 'utf8'));
|
| 28 |
const hfIdToModels = new Map();
|
|
|
|
| 29 |
|
| 30 |
data.providers.forEach(p => {
|
| 31 |
p.models.forEach(m => {
|
| 32 |
if (m.hf_id) {
|
| 33 |
if (!hfIdToModels.has(m.hf_id)) hfIdToModels.set(m.hf_id, []);
|
| 34 |
hfIdToModels.get(m.hf_id).push(`${p.name}: ${m.name}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
}
|
| 36 |
});
|
| 37 |
});
|
| 38 |
|
| 39 |
const ids = Array.from(hfIdToModels.keys());
|
| 40 |
-
console.log(`Found ${ids.length} unique HF IDs to validate
|
| 41 |
|
| 42 |
const invalidIds = new Set();
|
| 43 |
-
const
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
};
|
| 48 |
|
| 49 |
for (let i = 0; i < ids.length; i++) {
|
| 50 |
const id = ids[i];
|
| 51 |
const progress = `[${i + 1}/${ids.length}]`.padEnd(10);
|
| 52 |
|
| 53 |
-
const
|
|
|
|
| 54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
if (check.valid) {
|
| 56 |
-
results.valid++;
|
| 57 |
console.log(`${progress} ✓ VALID (${check.status}) ${id}`);
|
| 58 |
} else {
|
| 59 |
-
results.invalid++;
|
| 60 |
console.log(`${progress} ✗ INVALID (${check.status}) ${id}`);
|
| 61 |
console.log(` Used by: ${hfIdToModels.get(id).join(', ')}`);
|
| 62 |
invalidIds.add(id);
|
|
@@ -66,30 +85,30 @@ async function main() {
|
|
| 66 |
await new Promise(r => setTimeout(r, 50));
|
| 67 |
}
|
| 68 |
|
| 69 |
-
console.log('\
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
console.log(`\nAction: Removing ${invalidIds.size} invalid HF IDs from providers.json...`);
|
| 79 |
-
let removalCount = 0;
|
| 80 |
-
data.providers.forEach(p => {
|
| 81 |
-
p.models.forEach(m => {
|
| 82 |
-
if (m.hf_id && invalidIds.has(m.hf_id)) {
|
| 83 |
delete m.hf_id;
|
|
|
|
|
|
|
| 84 |
removalCount++;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
}
|
| 86 |
-
}
|
| 87 |
});
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
}
|
| 93 |
}
|
| 94 |
|
| 95 |
main().catch(err => {
|
|
|
|
| 22 |
}
|
| 23 |
|
| 24 |
async function main() {
|
| 25 |
+
const force = process.argv.includes('--force');
|
| 26 |
+
console.log('Starting Hugging Face Repository Validation...');
|
| 27 |
+
if (force) console.log(' [!] Force mode enabled: checking all IDs regardless of cache.\n');
|
| 28 |
+
else console.log(' [i] Using cache: only checking IDs not validated in the last 30 days.\n');
|
| 29 |
|
| 30 |
const data = JSON.parse(fs.readFileSync(PROVIDERS_FILE, 'utf8'));
|
| 31 |
const hfIdToModels = new Map();
|
| 32 |
+
const hfIdMeta = new Map(); // Store metadata (validated_at, status)
|
| 33 |
|
| 34 |
data.providers.forEach(p => {
|
| 35 |
p.models.forEach(m => {
|
| 36 |
if (m.hf_id) {
|
| 37 |
if (!hfIdToModels.has(m.hf_id)) hfIdToModels.set(m.hf_id, []);
|
| 38 |
hfIdToModels.get(m.hf_id).push(`${p.name}: ${m.name}`);
|
| 39 |
+
|
| 40 |
+
// Cache metadata if present
|
| 41 |
+
if (m.hf_validated_at && m.hf_status === 200) {
|
| 42 |
+
const existing = hfIdMeta.get(m.hf_id);
|
| 43 |
+
if (!existing || new Date(m.hf_validated_at) > new Date(existing.at)) {
|
| 44 |
+
hfIdMeta.set(m.hf_id, { at: m.hf_validated_at, status: m.hf_status });
|
| 45 |
+
}
|
| 46 |
+
}
|
| 47 |
}
|
| 48 |
});
|
| 49 |
});
|
| 50 |
|
| 51 |
const ids = Array.from(hfIdToModels.keys());
|
| 52 |
+
console.log(`Found ${ids.length} unique HF IDs to validate.\n`);
|
| 53 |
|
| 54 |
const invalidIds = new Set();
|
| 55 |
+
const now = new Date();
|
| 56 |
+
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
| 57 |
+
|
| 58 |
+
const validationResults = new Map(); // id -> { status, at }
|
|
|
|
| 59 |
|
| 60 |
for (let i = 0; i < ids.length; i++) {
|
| 61 |
const id = ids[i];
|
| 62 |
const progress = `[${i + 1}/${ids.length}]`.padEnd(10);
|
| 63 |
|
| 64 |
+
const cached = hfIdMeta.get(id);
|
| 65 |
+
const isRecent = cached && (now - new Date(cached.at) < THIRTY_DAYS_MS);
|
| 66 |
|
| 67 |
+
if (isRecent && !force) {
|
| 68 |
+
console.log(`${progress} ≈ CACHED (${cached.status}) ${id} (last checked ${new Date(cached.at).toLocaleDateString()})`);
|
| 69 |
+
validationResults.set(id, { status: cached.status, at: cached.at });
|
| 70 |
+
continue;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
const check = await checkHfId(id);
|
| 74 |
+
validationResults.set(id, { status: typeof check.status === 'number' ? check.status : 200, at: now.toISOString() });
|
| 75 |
+
|
| 76 |
if (check.valid) {
|
|
|
|
| 77 |
console.log(`${progress} ✓ VALID (${check.status}) ${id}`);
|
| 78 |
} else {
|
|
|
|
| 79 |
console.log(`${progress} ✗ INVALID (${check.status}) ${id}`);
|
| 80 |
console.log(` Used by: ${hfIdToModels.get(id).join(', ')}`);
|
| 81 |
invalidIds.add(id);
|
|
|
|
| 85 |
await new Promise(r => setTimeout(r, 50));
|
| 86 |
}
|
| 87 |
|
| 88 |
+
console.log('\nUpdating providers.json with validation results...');
|
| 89 |
+
let updatedCount = 0;
|
| 90 |
+
let removalCount = 0;
|
| 91 |
+
|
| 92 |
+
data.providers.forEach(p => {
|
| 93 |
+
p.models.forEach(m => {
|
| 94 |
+
if (m.hf_id) {
|
| 95 |
+
const res = validationResults.get(m.hf_id);
|
| 96 |
+
if (invalidIds.has(m.hf_id)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
delete m.hf_id;
|
| 98 |
+
delete m.hf_validated_at;
|
| 99 |
+
delete m.hf_status;
|
| 100 |
removalCount++;
|
| 101 |
+
} else if (res) {
|
| 102 |
+
m.hf_validated_at = res.at;
|
| 103 |
+
m.hf_status = res.status;
|
| 104 |
+
updatedCount++;
|
| 105 |
}
|
| 106 |
+
}
|
| 107 |
});
|
| 108 |
+
});
|
| 109 |
+
|
| 110 |
+
fs.writeFileSync(PROVIDERS_FILE, JSON.stringify(data, null, 2));
|
| 111 |
+
console.log(`Done. Updated ${updatedCount} models, removed ${removalCount} invalid IDs.`);
|
|
|
|
| 112 |
}
|
| 113 |
|
| 114 |
main().catch(err => {
|
src/App.tsx
CHANGED
|
@@ -372,8 +372,7 @@ function App() {
|
|
| 372 |
case 'aa_intelligence':
|
| 373 |
case 'aa_tokens_per_s':
|
| 374 |
case 'mteb_avg':
|
| 375 |
-
case 'mteb_retrieval':
|
| 376 |
-
case 'ocr_avg': {
|
| 377 |
try {
|
| 378 |
const bA = findBenchmark(a.name);
|
| 379 |
const bB = findBenchmark(b.name);
|
|
@@ -530,7 +529,6 @@ function App() {
|
|
| 530 |
<th onClick={() => requestSort('aa_tokens_per_s')} className="sortable" title="Artificial Analysis Median Speed (Tokens per Second)">AA Speed {getSortIcon('aa_tokens_per_s')}</th>
|
| 531 |
<th onClick={() => requestSort('mteb_avg')} className="sortable" title="MTEB (Massive Text Embedding Benchmark) Average">MTEB {getSortIcon('mteb_avg')}</th>
|
| 532 |
<th onClick={() => requestSort('mteb_retrieval')} className="sortable" title="MTEB Retrieval Average">MTEB-Ret {getSortIcon('mteb_retrieval')}</th>
|
| 533 |
-
<th onClick={() => requestSort('ocr_avg')} className="sortable" title="OCR (Optical Character Recognition) Benchmark">OCR {getSortIcon('ocr_avg')}</th>
|
| 534 |
<th onClick={() => requestSort('lb_global')} className="sortable" title="LiveBench overall average (contamination-free)">LB {getSortIcon('lb_global')}</th>
|
| 535 |
<th onClick={() => requestSort('lb_math')} className="sortable" title="LiveBench Mathematics">LB-Math {getSortIcon('lb_math')}</th>
|
| 536 |
<th onClick={() => requestSort('lb_coding')} className="sortable" title="LiveBench Coding + Agentic Coding">LB-Code {getSortIcon('lb_coding')}</th>
|
|
@@ -554,6 +552,7 @@ function App() {
|
|
| 554 |
(prev.hf_id?.toLowerCase() !== model.hf_id?.toLowerCase()) ||
|
| 555 |
(!model.hf_id && prev.name.toLowerCase() !== model.name.toLowerCase())
|
| 556 |
);
|
|
|
|
| 557 |
return (
|
| 558 |
<tr key={`${model.provider.name}-${model.name}-${idx}`} className={isGroupStart ? 'group-divider' : ''}>
|
| 559 |
<td className="provider-cell">{model.provider.name}</td>
|
|
@@ -592,6 +591,9 @@ function App() {
|
|
| 592 |
{model.capabilities && model.capabilities.length > 0 && (
|
| 593 |
<div className="tooltip-row"><strong>Caps:</strong> {model.capabilities.join(', ')}</div>
|
| 594 |
)}
|
|
|
|
|
|
|
|
|
|
| 595 |
</div>
|
| 596 |
</div>
|
| 597 |
</div>
|
|
@@ -626,34 +628,28 @@ function App() {
|
|
| 626 |
? '–'
|
| 627 |
: formatPrice(model.output_price_per_1m, model.currency)}
|
| 628 |
</td>
|
| 629 |
-
{showBenchmarks && (
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
<td className="benchmark-cell">{fmtPct(bm?.human_eval)}</td>
|
| 652 |
-
</>;
|
| 653 |
-
} catch (e) {
|
| 654 |
-
return Array(19).fill(null).map((_, i) => <td key={i} className="benchmark-cell">–</td>);
|
| 655 |
-
}
|
| 656 |
-
})()}
|
| 657 |
</tr>
|
| 658 |
)
|
| 659 |
})}
|
|
|
|
| 372 |
case 'aa_intelligence':
|
| 373 |
case 'aa_tokens_per_s':
|
| 374 |
case 'mteb_avg':
|
| 375 |
+
case 'mteb_retrieval': {
|
|
|
|
| 376 |
try {
|
| 377 |
const bA = findBenchmark(a.name);
|
| 378 |
const bB = findBenchmark(b.name);
|
|
|
|
| 529 |
<th onClick={() => requestSort('aa_tokens_per_s')} className="sortable" title="Artificial Analysis Median Speed (Tokens per Second)">AA Speed {getSortIcon('aa_tokens_per_s')}</th>
|
| 530 |
<th onClick={() => requestSort('mteb_avg')} className="sortable" title="MTEB (Massive Text Embedding Benchmark) Average">MTEB {getSortIcon('mteb_avg')}</th>
|
| 531 |
<th onClick={() => requestSort('mteb_retrieval')} className="sortable" title="MTEB Retrieval Average">MTEB-Ret {getSortIcon('mteb_retrieval')}</th>
|
|
|
|
| 532 |
<th onClick={() => requestSort('lb_global')} className="sortable" title="LiveBench overall average (contamination-free)">LB {getSortIcon('lb_global')}</th>
|
| 533 |
<th onClick={() => requestSort('lb_math')} className="sortable" title="LiveBench Mathematics">LB-Math {getSortIcon('lb_math')}</th>
|
| 534 |
<th onClick={() => requestSort('lb_coding')} className="sortable" title="LiveBench Coding + Agentic Coding">LB-Code {getSortIcon('lb_coding')}</th>
|
|
|
|
| 552 |
(prev.hf_id?.toLowerCase() !== model.hf_id?.toLowerCase()) ||
|
| 553 |
(!model.hf_id && prev.name.toLowerCase() !== model.name.toLowerCase())
|
| 554 |
);
|
| 555 |
+
const bm = findBenchmark(model.name);
|
| 556 |
return (
|
| 557 |
<tr key={`${model.provider.name}-${model.name}-${idx}`} className={isGroupStart ? 'group-divider' : ''}>
|
| 558 |
<td className="provider-cell">{model.provider.name}</td>
|
|
|
|
| 591 |
{model.capabilities && model.capabilities.length > 0 && (
|
| 592 |
<div className="tooltip-row"><strong>Caps:</strong> {model.capabilities.join(', ')}</div>
|
| 593 |
)}
|
| 594 |
+
{bm?.ocr_avg !== undefined && (
|
| 595 |
+
<div className="tooltip-row"><strong>OCR:</strong> {bm.ocr_avg.toFixed(1)} (Benchmark)</div>
|
| 596 |
+
)}
|
| 597 |
</div>
|
| 598 |
</div>
|
| 599 |
</div>
|
|
|
|
| 628 |
? '–'
|
| 629 |
: formatPrice(model.output_price_per_1m, model.currency)}
|
| 630 |
</td>
|
| 631 |
+
{showBenchmarks && (
|
| 632 |
+
<>
|
| 633 |
+
<td className="benchmark-cell">{fmtNum(bm?.arena_elo)}</td>
|
| 634 |
+
<td className="benchmark-cell">{fmtPct(bm?.aider_pass_rate)}</td>
|
| 635 |
+
<td className="benchmark-cell">{fmtNum(bm?.aa_intelligence)}</td>
|
| 636 |
+
<td className="benchmark-cell">{fmtNum(bm?.aa_tokens_per_s)}</td>
|
| 637 |
+
<td className="benchmark-cell">{fmtNum(bm?.mteb_avg, 1)}</td>
|
| 638 |
+
<td className="benchmark-cell">{fmtNum(bm?.mteb_retrieval, 1)}</td>
|
| 639 |
+
<td className="benchmark-cell">{fmtPct(bm?.lb_global)}</td>
|
| 640 |
+
<td className="benchmark-cell">{fmtPct(bm?.lb_math)}</td>
|
| 641 |
+
<td className="benchmark-cell">{fmtPct(bm?.lb_coding)}</td>
|
| 642 |
+
<td className="benchmark-cell">{fmtPct(bm?.lb_reasoning)}</td>
|
| 643 |
+
<td className="benchmark-cell">{fmtPct(bm?.gpqa)}</td>
|
| 644 |
+
<td className="benchmark-cell">{fmtPct(bm?.mmlu_pro)}</td>
|
| 645 |
+
<td className="benchmark-cell">{fmtPct(bm?.ifeval)}</td>
|
| 646 |
+
<td className="benchmark-cell">{fmtPct(bm?.bbh)}</td>
|
| 647 |
+
<td className="benchmark-cell">{fmtPct(bm?.hf_math_lvl5)}</td>
|
| 648 |
+
<td className="benchmark-cell">{fmtPct(bm?.hf_musr)}</td>
|
| 649 |
+
<td className="benchmark-cell">{fmtPct(bm?.mmlu)}</td>
|
| 650 |
+
<td className="benchmark-cell">{fmtPct(bm?.human_eval)}</td>
|
| 651 |
+
</>
|
| 652 |
+
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 653 |
</tr>
|
| 654 |
)
|
| 655 |
})}
|