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 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
- console.log('Starting Hugging Face Repository Validation...\n');
 
 
 
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 across all providers.\n`);
41
 
42
  const invalidIds = new Set();
43
- const results = {
44
- valid: 0,
45
- invalid: 0,
46
- errors: 0
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 check = await checkHfId(id);
 
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('\n' + '='.repeat(50));
70
- console.log('VALIDATION SUMMARY');
71
- console.log('='.repeat(50));
72
- console.log(`Total Unique IDs: ${ids.length}`);
73
- console.log(`Valid IDs: ${results.valid}`);
74
- console.log(`Invalid (404s): ${results.invalid}`);
75
- console.log('='.repeat(50));
76
-
77
- if (invalidIds.size > 0) {
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
- fs.writeFileSync(PROVIDERS_FILE, JSON.stringify(data, null, 2));
89
- console.log(`Successfully removed ${removalCount} occurrences.`);
90
- } else {
91
- console.log('\nSuccess: All checked HF IDs exist on Hugging Face.');
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
- try {
631
- const bm = findBenchmark(model.name);
632
- return <>
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">{fmtNum(bm?.ocr_avg, 1)}</td>
640
- <td className="benchmark-cell">{fmtPct(bm?.lb_global)}</td>
641
- <td className="benchmark-cell">{fmtPct(bm?.lb_math)}</td>
642
- <td className="benchmark-cell">{fmtPct(bm?.lb_coding)}</td>
643
- <td className="benchmark-cell">{fmtPct(bm?.lb_reasoning)}</td>
644
- <td className="benchmark-cell">{fmtPct(bm?.gpqa)}</td>
645
- <td className="benchmark-cell">{fmtPct(bm?.mmlu_pro)}</td>
646
- <td className="benchmark-cell">{fmtPct(bm?.ifeval)}</td>
647
- <td className="benchmark-cell">{fmtPct(bm?.bbh)}</td>
648
- <td className="benchmark-cell">{fmtPct(bm?.hf_math_lvl5)}</td>
649
- <td className="benchmark-cell">{fmtPct(bm?.hf_musr)}</td>
650
- <td className="benchmark-cell">{fmtPct(bm?.mmlu)}</td>
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
  })}