Spaces:
Running
Running
remove duplicates
Browse files
client/src/components/LeaderboardSection.jsx
CHANGED
@@ -13,9 +13,10 @@ const LeaderboardSection = ({ title, leaderboards }) => {
|
|
13 |
|
14 |
if (!leaderboards || leaderboards.length === 0) return null;
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
|
|
|
19 |
|
20 |
const toggleExpanded = () => {
|
21 |
setShowAll(!showAll);
|
@@ -121,9 +122,9 @@ const LeaderboardSection = ({ title, leaderboards }) => {
|
|
121 |
</Grid>
|
122 |
))}
|
123 |
</Grid>
|
124 |
-
<Collapse in={showAll} timeout={300}>
|
125 |
<Grid container spacing={3} sx={{ mt: 0 }}>
|
126 |
-
{
|
127 |
<Grid item xs={12} sm={6} md={4} key={index + ITEMS_PER_PAGE}>
|
128 |
<LeaderboardCard leaderboard={leaderboard} />
|
129 |
</Grid>
|
|
|
13 |
|
14 |
if (!leaderboards || leaderboards.length === 0) return null;
|
15 |
|
16 |
+
// On affiche toujours les 3 premiers
|
17 |
+
const displayedLeaderboards = leaderboards.slice(0, ITEMS_PER_PAGE);
|
18 |
+
// Le reste sera dans le Collapse
|
19 |
+
const remainingLeaderboards = leaderboards.slice(ITEMS_PER_PAGE);
|
20 |
|
21 |
const toggleExpanded = () => {
|
22 |
setShowAll(!showAll);
|
|
|
122 |
</Grid>
|
123 |
))}
|
124 |
</Grid>
|
125 |
+
<Collapse in={showAll} timeout={300} unmountOnExit>
|
126 |
<Grid container spacing={3} sx={{ mt: 0 }}>
|
127 |
+
{remainingLeaderboards.map((leaderboard, index) => (
|
128 |
<Grid item xs={12} sm={6} md={4} key={index + ITEMS_PER_PAGE}>
|
129 |
<LeaderboardCard leaderboard={leaderboard} />
|
130 |
</Grid>
|
client/src/context/LeaderboardContext.jsx
CHANGED
@@ -57,166 +57,206 @@ export const LeaderboardProvider = ({ children }) => {
|
|
57 |
);
|
58 |
}, []);
|
59 |
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
"eval:safety",
|
65 |
-
"modality:video",
|
66 |
-
"modality:image",
|
67 |
-
"modality:audio",
|
68 |
-
"modality:agent",
|
69 |
-
"domain:financial",
|
70 |
-
"domain:medical",
|
71 |
-
"domain:legal",
|
72 |
-
];
|
73 |
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
|
80 |
-
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
);
|
|
|
83 |
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
|
89 |
// Define sections
|
90 |
const allSections = useMemo(() => {
|
91 |
if (!leaderboards) return [];
|
92 |
|
93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
{
|
95 |
id: "agentic",
|
96 |
title: "Agentic",
|
97 |
-
data: filterByTag("modality:agent",
|
|
|
|
|
|
|
98 |
},
|
99 |
{
|
100 |
id: "code",
|
101 |
title: "Code",
|
102 |
-
data: filterByTag("eval:code",
|
|
|
|
|
|
|
103 |
},
|
104 |
{
|
105 |
id: "math",
|
106 |
title: "Math",
|
107 |
-
data: filterByTag("eval:math",
|
|
|
|
|
|
|
108 |
},
|
109 |
{
|
110 |
id: "language",
|
111 |
title: "Language Specific",
|
112 |
-
data: filterByLanguage(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
},
|
114 |
-
{ id: "vision", title: "Vision", data: filterByVision(leaderboards) },
|
115 |
{
|
116 |
id: "audio",
|
117 |
title: "Audio",
|
118 |
-
data: filterByTag("modality:audio",
|
|
|
|
|
|
|
119 |
},
|
120 |
{
|
121 |
id: "financial",
|
122 |
title: "Financial",
|
123 |
-
data: filterByTag("domain:financial",
|
|
|
|
|
|
|
124 |
},
|
125 |
{
|
126 |
id: "medical",
|
127 |
title: "Medical",
|
128 |
-
data: filterByTag("domain:medical",
|
|
|
|
|
|
|
129 |
},
|
130 |
{
|
131 |
id: "legal",
|
132 |
title: "Legal",
|
133 |
-
data: filterByTag("domain:legal",
|
|
|
|
|
|
|
134 |
},
|
135 |
{
|
136 |
id: "safety",
|
137 |
title: "Safety",
|
138 |
-
data: filterByTag("eval:safety",
|
|
|
|
|
|
|
139 |
},
|
140 |
{
|
141 |
id: "uncategorized",
|
142 |
title: "Uncategorized",
|
143 |
-
|
|
|
144 |
},
|
145 |
];
|
|
|
|
|
146 |
}, [
|
147 |
leaderboards,
|
|
|
148 |
filterByTag,
|
149 |
filterByLanguage,
|
150 |
filterByVision,
|
151 |
-
filterUncategorized,
|
152 |
]);
|
153 |
|
154 |
// Get sections with data
|
155 |
const sections = useMemo(() => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
const filteredSections = allSections.filter((section) => {
|
157 |
-
console.log(
|
158 |
data: section.data,
|
159 |
count: section.data.length,
|
|
|
160 |
boards: section.data.map((board) => ({
|
161 |
id: board.id,
|
162 |
tags: board.tags,
|
163 |
})),
|
164 |
});
|
165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
});
|
|
|
167 |
console.log(
|
168 |
-
"
|
169 |
-
filteredSections.map((s) =>
|
|
|
|
|
|
|
|
|
170 |
);
|
|
|
171 |
return filteredSections;
|
172 |
}, [allSections]);
|
173 |
|
174 |
-
// Filter leaderboards based on search query and arena toggle
|
175 |
-
const filterLeaderboards = useCallback(
|
176 |
-
(boards) => {
|
177 |
-
if (!boards) return [];
|
178 |
-
|
179 |
-
let filtered = [...boards];
|
180 |
-
|
181 |
-
// Filter by search query
|
182 |
-
if (searchQuery) {
|
183 |
-
const query = searchQuery.toLowerCase();
|
184 |
-
const searchableTagPrefixes = [
|
185 |
-
"domain:",
|
186 |
-
"language:",
|
187 |
-
"judge:",
|
188 |
-
"test:",
|
189 |
-
"modality:",
|
190 |
-
"submission:",
|
191 |
-
"domain:",
|
192 |
-
"eval:",
|
193 |
-
];
|
194 |
-
|
195 |
-
filtered = filtered.filter((board) => {
|
196 |
-
const isTagSearch = searchableTagPrefixes.some((prefix) =>
|
197 |
-
query.startsWith(prefix)
|
198 |
-
);
|
199 |
-
|
200 |
-
if (isTagSearch) {
|
201 |
-
return board.tags?.some((tag) => tag.toLowerCase().includes(query));
|
202 |
-
}
|
203 |
-
|
204 |
-
return board.card_data?.title?.toLowerCase().includes(query);
|
205 |
-
});
|
206 |
-
}
|
207 |
-
|
208 |
-
// Filter arena only
|
209 |
-
if (arenaOnly) {
|
210 |
-
filtered = filtered.filter((board) =>
|
211 |
-
board.tags?.includes("judge:humans")
|
212 |
-
);
|
213 |
-
}
|
214 |
-
|
215 |
-
return filtered;
|
216 |
-
},
|
217 |
-
[searchQuery, arenaOnly]
|
218 |
-
);
|
219 |
-
|
220 |
// Get filtered count
|
221 |
const filteredCount = useMemo(() => {
|
222 |
return filterLeaderboards(leaderboards).length;
|
|
|
57 |
);
|
58 |
}, []);
|
59 |
|
60 |
+
// Filter leaderboards based on search query and arena toggle
|
61 |
+
const filterLeaderboards = useCallback(
|
62 |
+
(boards) => {
|
63 |
+
if (!boards) return [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
+
// On évite de créer une copie inutile
|
66 |
+
let filtered = boards;
|
67 |
+
|
68 |
+
// Filter by search query
|
69 |
+
if (searchQuery) {
|
70 |
+
const query = searchQuery.toLowerCase();
|
71 |
+
const searchableTagPrefixes = [
|
72 |
+
"domain:",
|
73 |
+
"language:",
|
74 |
+
"judge:",
|
75 |
+
"test:",
|
76 |
+
"modality:",
|
77 |
+
"submission:",
|
78 |
+
"domain:",
|
79 |
+
"eval:",
|
80 |
+
];
|
81 |
|
82 |
+
filtered = filtered.filter((board) => {
|
83 |
+
const isTagSearch = searchableTagPrefixes.some((prefix) =>
|
84 |
+
query.startsWith(prefix)
|
85 |
+
);
|
86 |
+
|
87 |
+
if (isTagSearch) {
|
88 |
+
return board.tags?.some((tag) => tag.toLowerCase().includes(query));
|
89 |
+
}
|
90 |
+
|
91 |
+
return board.card_data?.title?.toLowerCase().includes(query);
|
92 |
+
});
|
93 |
+
}
|
94 |
+
|
95 |
+
// Filter arena only
|
96 |
+
if (arenaOnly) {
|
97 |
+
filtered = filtered.filter((board) =>
|
98 |
+
board.tags?.includes("judge:humans")
|
99 |
);
|
100 |
+
}
|
101 |
|
102 |
+
return filtered;
|
103 |
+
},
|
104 |
+
[searchQuery, arenaOnly]
|
105 |
+
);
|
106 |
|
107 |
// Define sections
|
108 |
const allSections = useMemo(() => {
|
109 |
if (!leaderboards) return [];
|
110 |
|
111 |
+
// D'abord filtrer les leaderboards selon la recherche
|
112 |
+
const filteredBoards = filterLeaderboards(leaderboards);
|
113 |
+
|
114 |
+
// Garder une trace des leaderboards déjà catégorisés
|
115 |
+
const categorizedIds = new Set();
|
116 |
+
|
117 |
+
const sections = [
|
118 |
{
|
119 |
id: "agentic",
|
120 |
title: "Agentic",
|
121 |
+
data: filterByTag("modality:agent", filteredBoards).map((board) => {
|
122 |
+
categorizedIds.add(board.id);
|
123 |
+
return board;
|
124 |
+
}),
|
125 |
},
|
126 |
{
|
127 |
id: "code",
|
128 |
title: "Code",
|
129 |
+
data: filterByTag("eval:code", filteredBoards).map((board) => {
|
130 |
+
categorizedIds.add(board.id);
|
131 |
+
return board;
|
132 |
+
}),
|
133 |
},
|
134 |
{
|
135 |
id: "math",
|
136 |
title: "Math",
|
137 |
+
data: filterByTag("eval:math", filteredBoards).map((board) => {
|
138 |
+
categorizedIds.add(board.id);
|
139 |
+
return board;
|
140 |
+
}),
|
141 |
},
|
142 |
{
|
143 |
id: "language",
|
144 |
title: "Language Specific",
|
145 |
+
data: filterByLanguage(filteredBoards).map((board) => {
|
146 |
+
categorizedIds.add(board.id);
|
147 |
+
return board;
|
148 |
+
}),
|
149 |
+
},
|
150 |
+
{
|
151 |
+
id: "vision",
|
152 |
+
title: "Vision",
|
153 |
+
data: filterByVision(filteredBoards).map((board) => {
|
154 |
+
categorizedIds.add(board.id);
|
155 |
+
return board;
|
156 |
+
}),
|
157 |
},
|
|
|
158 |
{
|
159 |
id: "audio",
|
160 |
title: "Audio",
|
161 |
+
data: filterByTag("modality:audio", filteredBoards).map((board) => {
|
162 |
+
categorizedIds.add(board.id);
|
163 |
+
return board;
|
164 |
+
}),
|
165 |
},
|
166 |
{
|
167 |
id: "financial",
|
168 |
title: "Financial",
|
169 |
+
data: filterByTag("domain:financial", filteredBoards).map((board) => {
|
170 |
+
categorizedIds.add(board.id);
|
171 |
+
return board;
|
172 |
+
}),
|
173 |
},
|
174 |
{
|
175 |
id: "medical",
|
176 |
title: "Medical",
|
177 |
+
data: filterByTag("domain:medical", filteredBoards).map((board) => {
|
178 |
+
categorizedIds.add(board.id);
|
179 |
+
return board;
|
180 |
+
}),
|
181 |
},
|
182 |
{
|
183 |
id: "legal",
|
184 |
title: "Legal",
|
185 |
+
data: filterByTag("domain:legal", filteredBoards).map((board) => {
|
186 |
+
categorizedIds.add(board.id);
|
187 |
+
return board;
|
188 |
+
}),
|
189 |
},
|
190 |
{
|
191 |
id: "safety",
|
192 |
title: "Safety",
|
193 |
+
data: filterByTag("eval:safety", filteredBoards).map((board) => {
|
194 |
+
categorizedIds.add(board.id);
|
195 |
+
return board;
|
196 |
+
}),
|
197 |
},
|
198 |
{
|
199 |
id: "uncategorized",
|
200 |
title: "Uncategorized",
|
201 |
+
// Mettre dans uncategorized uniquement les leaderboards qui n'apparaissent nulle part ailleurs
|
202 |
+
data: filteredBoards.filter((board) => !categorizedIds.has(board.id)),
|
203 |
},
|
204 |
];
|
205 |
+
|
206 |
+
return sections;
|
207 |
}, [
|
208 |
leaderboards,
|
209 |
+
filterLeaderboards,
|
210 |
filterByTag,
|
211 |
filterByLanguage,
|
212 |
filterByVision,
|
|
|
213 |
]);
|
214 |
|
215 |
// Get sections with data
|
216 |
const sections = useMemo(() => {
|
217 |
+
console.log("Starting sections filtering...");
|
218 |
+
console.log(
|
219 |
+
"All sections before filtering:",
|
220 |
+
allSections.map((s) => ({
|
221 |
+
title: s.title,
|
222 |
+
count: s.data.length,
|
223 |
+
ids: s.data.map((b) => b.id),
|
224 |
+
}))
|
225 |
+
);
|
226 |
+
|
227 |
+
// On garde une trace des titres déjà vus
|
228 |
+
const seenTitles = new Set();
|
229 |
const filteredSections = allSections.filter((section) => {
|
230 |
+
console.log(`\nAnalyzing section ${section.title}:`, {
|
231 |
data: section.data,
|
232 |
count: section.data.length,
|
233 |
+
uniqueIds: new Set(section.data.map((b) => b.id)).size,
|
234 |
boards: section.data.map((board) => ({
|
235 |
id: board.id,
|
236 |
tags: board.tags,
|
237 |
})),
|
238 |
});
|
239 |
+
|
240 |
+
// On garde la section si elle a des données et qu'on ne l'a pas déjà vue
|
241 |
+
if (section.data.length > 0 && !seenTitles.has(section.title)) {
|
242 |
+
seenTitles.add(section.title);
|
243 |
+
return true;
|
244 |
+
}
|
245 |
+
return false;
|
246 |
});
|
247 |
+
|
248 |
console.log(
|
249 |
+
"\nFinal sections after filtering:",
|
250 |
+
filteredSections.map((s) => ({
|
251 |
+
title: s.title,
|
252 |
+
count: s.data.length,
|
253 |
+
uniqueIds: new Set(s.data.map((b) => b.id)).size,
|
254 |
+
}))
|
255 |
);
|
256 |
+
|
257 |
return filteredSections;
|
258 |
}, [allSections]);
|
259 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
// Get filtered count
|
261 |
const filteredCount = useMemo(() => {
|
262 |
return filterLeaderboards(leaderboards).length;
|