David Pomerenke commited on
Commit
9dbdcb2
·
1 Parent(s): 3ed02d5

Nicer model table with type and size and filters and colourful score bars

Browse files
evals/models.py CHANGED
@@ -91,7 +91,7 @@ api = HfApi()
91
  def get_metadata(id):
92
  try:
93
  info = api.model_info(id)
94
- license = info.card_data.license.replace("_", " ").replace("mit", "MIT").title()
95
  return {
96
  "hf_id": info.id,
97
  "creation_date": info.created_at,
 
91
  def get_metadata(id):
92
  try:
93
  info = api.model_info(id)
94
+ license = info.card_data.license.replace("-", " ").replace("mit", "MIT").title()
95
  return {
96
  "hf_id": info.id,
97
  "creation_date": info.created_at,
frontend/public/results.json CHANGED
@@ -53,7 +53,7 @@
53
  "creation_date": "2025-01-28",
54
  "size": 23572403200.0,
55
  "type": "Open",
56
- "license": "Apache-2.0",
57
  "average": 0.58,
58
  "classification_accuracy": 0.55,
59
  "language_modeling_chrf": 0.86,
 
53
  "creation_date": "2025-01-28",
54
  "size": 23572403200.0,
55
  "type": "Open",
56
+ "license": "Apache 2.0",
57
  "average": 0.58,
58
  "classification_accuracy": 0.55,
59
  "language_modeling_chrf": 0.86,
frontend/src/App.js CHANGED
@@ -38,7 +38,7 @@ function App() {
38
  <h1>Global AI Language Monitor</h1>
39
  <p>Tracking language proficiency of AI models for every language</p>
40
 
41
- <div className="data-container">
42
  <PrimeReactProvider>
43
  {loading && <p>...</p>}
44
  {error && <p>Error: {error}</p>}
 
38
  <h1>Global AI Language Monitor</h1>
39
  <p>Tracking language proficiency of AI models for every language</p>
40
 
41
+ <div className="data-container" style={{ width: '100%' }}>
42
  <PrimeReactProvider>
43
  {loading && <p>...</p>}
44
  {error && <p>Error: {error}</p>}
frontend/src/components/ModelTable.js CHANGED
@@ -1,73 +1,228 @@
1
- import { DataTable } from 'primereact/datatable';
2
- import { Column } from 'primereact/column';
3
- import { FilterMatchMode } from 'primereact/api';
4
- import { MultiSelect } from 'primereact/multiselect';
5
- import { useState } from 'react';
6
- import Medal from './Medal';
 
 
 
7
  const ModelTable = ({ data }) => {
8
- const [filters, setFilters] = useState({
9
- "provider": { value: null, matchMode: FilterMatchMode.IN },
10
- "model": { value: null, matchMode: FilterMatchMode.CONTAINS }
11
- });
12
- const table = data.model_table;
13
- const rankBodyTemplate = (rowData) => {
14
- return <Medal rank={rowData.rank} />;
15
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
- const providers = [...new Set(table.map(item => item.provider))];
18
- const providerRowFilterTemplate = (options) => {
19
- return (
20
- <MultiSelect
21
- value={options.value}
22
- options={providers}
23
- onChange={(e) => {
24
- options.filterApplyCallback(e.value);
25
- setFilters(prevFilters => ({
26
- ...prevFilters,
27
- provider: { value: e.value, matchMode: FilterMatchMode.IN }
28
- }));
29
- }}
30
- placeholder="All providers"
31
- />
32
- );
33
- };
34
 
35
- const sizeBodyTemplate = (rowData) => {
36
- const size = rowData.size;
37
- if (size === null) {
38
- return <div>N/A</div>;
39
- }
40
- let sizeStr;
41
- if (size < 1000) {
42
- sizeStr = size.toFixed(0) + "";
43
- } else if (size < 1000 * 1000) {
44
- sizeStr = (size / 1000).toFixed(0) + "K";
45
- } else if (size < 1000 * 1000 * 1000) {
46
- sizeStr = (size / 1000 / 1000).toFixed(0) + "M";
47
- } else {
48
- sizeStr = (size / 1000 / 1000 / 1000).toFixed(0) + "B";
49
- }
50
- return <div>{sizeStr}</div>;
51
- };
52
 
53
- const modelBodyTemplate = (rowData) => {
54
- // bold
55
- return <div style={{ fontWeight: 'bold' }}>{rowData.model}</div>;
56
- };
 
57
 
58
  return (
59
- <DataTable value={table} header={<>AI Models</>} sortField="average" removableSort filters={filters} filterDisplay="menu" scrollable scrollHeight="500px">
60
- <Column field="rank" body={rankBodyTemplate} />
61
- <Column field="provider" header="Provider" filter filterElement={providerRowFilterTemplate} showFilterMatchModes={false} style={{ minWidth: '5rem' }} />
62
- <Column field="model" header="Model" filter showFilterMatchModes={false} style={{ minWidth: '15rem' }} body={modelBodyTemplate} />
63
- <Column field="type" header="Type" style={{ minWidth: '10rem' }} />
64
- <Column field="size" header="Size" sortable body={sizeBodyTemplate} style={{ minWidth: '5rem' }} />
65
- <Column field="average" header="Average" sortable style={{ minWidth: '5rem' }} />
66
- <Column field="translation_chrf" header="Translation" sortable style={{ minWidth: '5rem' }} />
67
- <Column field="classification_accuracy" header="Classification" sortable style={{ minWidth: '5rem' }} />
68
- <Column field="language_modeling_chrf" header="Language Modeling" sortable style={{ minWidth: '5rem' }} />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  </DataTable>
70
- );
71
- };
72
 
73
- export default ModelTable;
 
1
+ import { DataTable } from 'primereact/datatable'
2
+ import { Column } from 'primereact/column'
3
+ import { FilterMatchMode } from 'primereact/api'
4
+ import { MultiSelect } from 'primereact/multiselect'
5
+ import { useState, useEffect } from 'react'
6
+ import Medal from './Medal'
7
+ import { Slider } from 'primereact/slider'
8
+ import ScoreField from './ScoreField'
9
+
10
  const ModelTable = ({ data }) => {
11
+ const [filters, setFilters] = useState({
12
+ provider: { value: null, matchMode: FilterMatchMode.IN },
13
+ model: { value: null, matchMode: FilterMatchMode.CONTAINS },
14
+ type: { value: null, matchMode: FilterMatchMode.IN },
15
+ size: { value: null, matchMode: FilterMatchMode.BETWEEN }
16
+ })
17
+ const table = data.model_table
18
+ const rankBodyTemplate = rowData => {
19
+ return <Medal rank={rowData.rank} />
20
+ }
21
+
22
+ const providers = [...new Set(table.map(item => item.provider))]
23
+ const providerRowFilterTemplate = options => {
24
+ return (
25
+ <MultiSelect
26
+ value={options.value}
27
+ options={providers}
28
+ onChange={e => {
29
+ options.filterApplyCallback(e.value)
30
+ setFilters(prevFilters => ({
31
+ ...prevFilters,
32
+ provider: { value: e.value, matchMode: FilterMatchMode.IN }
33
+ }))
34
+ }}
35
+ placeholder='All providers'
36
+ />
37
+ )
38
+ }
39
+ const typeRowFilterTemplate = options => {
40
+ return (
41
+ <MultiSelect
42
+ value={options.value}
43
+ options={['Open', 'Commercial']}
44
+ onChange={e => {
45
+ options.filterApplyCallback(e.value)
46
+ setFilters(prevFilters => ({
47
+ ...prevFilters,
48
+ type: { value: e.value, matchMode: FilterMatchMode.IN }
49
+ }))
50
+ }}
51
+ placeholder='All types'
52
+ />
53
+ )
54
+ }
55
+
56
+ const formatSize = size => {
57
+ if (size === null) {
58
+ return ''
59
+ } else if (size < 1000) {
60
+ return size.toFixed(0) + ''
61
+ } else if (size < 1000 * 1000) {
62
+ return (size / 1000).toFixed(0) + 'K'
63
+ } else if (size < 1000 * 1000 * 1000) {
64
+ return (size / 1000 / 1000).toFixed(0) + 'M'
65
+ } else {
66
+ return (size / 1000 / 1000 / 1000).toFixed(0) + 'B'
67
+ }
68
+ }
69
+
70
+ const SliderWithLabel = ({ value, onChange }) => {
71
+ const p = 10
72
+ const min = 8
73
+ const max = 12
74
+ const start = value === null ? min : Math.log(value[0]) / Math.log(p)
75
+ const stop = value === null ? max : Math.log(value[1]) / Math.log(p)
76
+ const [_value, _setValue] = useState([start, stop])
77
+ useEffect(() => {
78
+ const timer = setTimeout(() => {
79
+ onChange({
80
+ value:
81
+ _value[0] <= min + 0.1 && _value[1] >= max - 0.1
82
+ ? null
83
+ : [p ** _value[0], p ** _value[1]]
84
+ })
85
+ }, 1000)
86
+ return () => clearTimeout(timer)
87
+ }, [_value, onChange])
88
+ return (
89
+ <div style={{ minWidth: '20rem' }}>
90
+ <div>{formatSize(p ** _value[0])}</div>
91
+ <div>{formatSize(p ** _value[1])}</div>
92
+ <Slider
93
+ value={_value}
94
+ onChange={e => _setValue(e.value)}
95
+ placeholder='All sizes'
96
+ min={min}
97
+ max={max}
98
+ step={0.01}
99
+ range
100
+ style={{ marginTop: '5rem' }}
101
+ />
102
+ </div>
103
+ )
104
+ }
105
+
106
+ const sizeFilterTemplate = options => {
107
+ return (
108
+ <SliderWithLabel
109
+ value={options.value}
110
+ onChange={e => {
111
+ options.filterApplyCallback(e.value)
112
+ setFilters(prevFilters => ({
113
+ ...prevFilters,
114
+ size: { value: e.value, matchMode: FilterMatchMode.BETWEEN }
115
+ }))
116
+ }}
117
+ />
118
+ )
119
+ }
120
+
121
+ const sizeBodyTemplate = rowData => {
122
+ const sizeStr = formatSize(rowData.size)
123
+ return <div>{sizeStr}</div>
124
+ }
125
 
126
+ const modelBodyTemplate = rowData => {
127
+ return <div style={{ fontWeight: 'bold' }}>{rowData.model}</div>
128
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
+ const scoreBodyTemplate = (field, options = {}) => {
131
+ const { minScore = 0, maxScore = 1 } = options
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
+ return rowData => {
134
+ const score = rowData[field]
135
+ return ScoreField(score, minScore, maxScore)
136
+ }
137
+ }
138
 
139
  return (
140
+ <DataTable
141
+ value={table}
142
+ header={<>AI Models</>}
143
+ sortField='average'
144
+ removableSort
145
+ filters={filters}
146
+ filterDisplay='menu'
147
+ scrollable
148
+ scrollHeight='500px'
149
+ style={{ minWidth: '200px' }}
150
+ >
151
+ <Column field='rank' body={rankBodyTemplate} />
152
+ <Column
153
+ field='provider'
154
+ header='Provider'
155
+ filter
156
+ filterElement={providerRowFilterTemplate}
157
+ showFilterMatchModes={false}
158
+ style={{ minWidth: '5rem' }}
159
+ />
160
+ <Column
161
+ field='model'
162
+ header='Model'
163
+ filter
164
+ showFilterMatchModes={false}
165
+ style={{ minWidth: '15rem' }}
166
+ body={modelBodyTemplate}
167
+ frozen
168
+ />
169
+ <Column
170
+ field='type'
171
+ header='Type'
172
+ filter
173
+ filterElement={typeRowFilterTemplate}
174
+ showFilterMatchModes={false}
175
+ style={{ minWidth: '10rem' }}
176
+ />
177
+ <Column
178
+ field='size'
179
+ header='Size'
180
+ filter
181
+ filterElement={sizeFilterTemplate}
182
+ showFilterMatchModes={false}
183
+ sortable
184
+ body={sizeBodyTemplate}
185
+ style={{ minWidth: '5rem' }}
186
+ />
187
+ <Column
188
+ field='average'
189
+ header='Average'
190
+ sortable
191
+ body={scoreBodyTemplate('average', { minScore: 0.4, maxScore: 0.8 })}
192
+ style={{ minWidth: '5rem', maxWidth: '10rem' }}
193
+ />
194
+ <Column
195
+ field='translation_chrf'
196
+ header='Translation'
197
+ sortable
198
+ body={scoreBodyTemplate('translation_chrf', {
199
+ minScore: 0.4,
200
+ maxScore: 0.7
201
+ })}
202
+ style={{ minWidth: '5rem', maxWidth: '10rem' }}
203
+ />
204
+ <Column
205
+ field='classification_accuracy'
206
+ header='Classification'
207
+ sortable
208
+ body={scoreBodyTemplate('classification_accuracy', {
209
+ minScore: 0.4,
210
+ maxScore: 1
211
+ })}
212
+ style={{ minWidth: '5rem', maxWidth: '10rem' }}
213
+ />
214
+ <Column
215
+ field='language_modeling_chrf'
216
+ header='Language Modeling'
217
+ sortable
218
+ body={scoreBodyTemplate('language_modeling_chrf', {
219
+ minScore: 0.8,
220
+ maxScore: 1
221
+ })}
222
+ style={{ minWidth: '5rem', maxWidth: '10rem' }}
223
+ />
224
  </DataTable>
225
+ )
226
+ }
227
 
228
+ export default ModelTable
frontend/src/components/ScoreField.js ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const ScoreField = (score, minScore, maxScore) => {
2
+ // Calculate percentage based on the provided min and max scores
3
+ // This normalizes the score to a 0-100 range for visualization
4
+ const normalizedScore = Math.min(Math.max(score, minScore), maxScore)
5
+ const percentage =
6
+ ((normalizedScore - minScore) / (maxScore - minScore)) * 100
7
+
8
+ // Continuous color gradient from red to green based on score
9
+ // For a smooth transition, calculate the RGB values directly
10
+
11
+ // Red component decreases as score increases
12
+ const red = Math.round(255 * (1 - percentage / 100))
13
+ // Green component increases as score increases
14
+ const green = Math.round(255 * (percentage / 100))
15
+ // Use a low opacity for subtlety (0.1-0.2 range)
16
+ const opacity = 0.1 + (percentage / 100) * 0.1
17
+
18
+ const barColor = `rgba(${red}, ${green}, 0, ${opacity.toFixed(2)})`
19
+
20
+ return (
21
+ <div
22
+ style={{
23
+ width: '100%',
24
+ height: '100%',
25
+ position: 'relative',
26
+ padding: '0.5rem'
27
+ }}
28
+ >
29
+ <div
30
+ style={{
31
+ position: 'absolute',
32
+ top: 0,
33
+ left: 0,
34
+ height: '100%',
35
+ width: `${percentage}%`,
36
+ backgroundColor: barColor,
37
+ zIndex: 0
38
+ }}
39
+ />
40
+
41
+ <span
42
+ style={{
43
+ position: 'relative',
44
+ zIndex: 1
45
+ }}
46
+ >
47
+ {(score * 100).toFixed(1)}%
48
+ </span>
49
+ </div>
50
+ )
51
+ }
52
+
53
+ export default ScoreField