File size: 3,420 Bytes
efde01b
 
18e54c4
efde01b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80749c6
efde01b
 
 
 
 
 
 
18e54c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import fs from 'fs'
import path from 'path'
import type { ModelData, BenchmarkStats, MetricThresholds } from './types'

function pct(val: string): number | null {
  const s = val?.trim()
  if (!s) return null
  const n = parseFloat(s.replace('%', ''))
  return isNaN(n) ? null : n / 100
}

function num(val: string): number | null {
  const s = val?.trim()
  if (!s) return null
  const n = parseFloat(s)
  return isNaN(n) ? null : n
}

export function loadData(): ModelData[] {
  const filePath = path.join(process.cwd(), 'public', 'data.csv')
  const text = fs.readFileSync(filePath, 'utf-8')
  const lines = text.split('\n').filter(l => l.trim()).slice(2)

  return lines
    .map(line => {
      const cols = line.split(',')
      return {
        rank: parseInt(cols[0]) || 0,
        creator: cols[1]?.trim() || '',
        model: cols[2]?.trim() || '',
        luc: {
          general: pct(cols[3]),
          physics: pct(cols[4]),
          career: pct(cols[5]),
          jd: pct(cols[6]),
          avg: pct(cols[7]),
        },
        rag: {
          lcAbs: pct(cols[8]),
          lcFact: pct(cols[9]),
          hyAbs: pct(cols[10]),
          hyFact: pct(cols[11]),
          avg: pct(cols[12]),
        },
        fairness: {
          style: num(cols[13]),
          con: num(cols[14]),
          avg: num(cols[15]),
        },
        archived: cols[16]?.trim() === 'true',
      }
    })
    .filter(m => m.creator && m.model)
}

export function computeStats(models: ModelData[]): BenchmarkStats {
  const active = models.filter(m => !m.archived)
  const creators = new Set(models.map(m => m.creator))

  const lucScores = active.map(m => m.luc.avg).filter((v): v is number => v !== null)
  const ragScores = active.map(m => m.rag.avg).filter((v): v is number => v !== null)

  const avgLUC = lucScores.reduce((a, b) => a + b, 0) / lucScores.length
  const avgRAG = ragScores.reduce((a, b) => a + b, 0) / ragScores.length

  const topModel = active
    .filter(m => m.luc.avg !== null)
    .sort((a, b) => (b.luc.avg ?? 0) - (a.luc.avg ?? 0))[0]?.model ?? ''

  return {
    totalModels: models.length,
    totalCreators: creators.size,
    avgLUC,
    avgRAG,
    topModel,
    lastUpdated: new Date().toLocaleDateString('en-SG', { month: 'short', year: 'numeric' }),
  }
}

export function getMaxFairnessAvg(models: ModelData[]): number {
  const vals = models.map(m => m.fairness.avg).filter((v): v is number => v !== null)
  return Math.max(...vals)
}

function empiricalPercentile(vals: number[], p: number): number {
  const sorted = [...vals].sort((a, b) => a - b)
  const idx = (p / 100) * (sorted.length - 1)
  const lo = Math.floor(idx)
  const hi = Math.ceil(idx)
  return sorted[lo] + (idx - lo) * (sorted[hi] - sorted[lo])
}

export function computeThresholds(models: ModelData[]): MetricThresholds {
  const active = models.filter(m => !m.archived)
  const luc  = active.map(m => m.luc.avg).filter((v): v is number => v !== null)
  const rag  = active.map(m => m.rag.avg).filter((v): v is number => v !== null)
  const fair = active.map(m => m.fairness.avg).filter((v): v is number => v !== null)
  return {
    luc:      { p33: empiricalPercentile(luc,  33), p67: empiricalPercentile(luc,  67) },
    rag:      { p33: empiricalPercentile(rag,  33), p67: empiricalPercentile(rag,  67) },
    fairness: { p33: empiricalPercentile(fair, 33), p67: empiricalPercentile(fair, 67) },
  }
}