Spaces:
Running
Running
| import React, { | |
| createContext, | |
| useContext, | |
| useState, | |
| useCallback, | |
| useMemo, | |
| } from "react"; | |
| const LeaderboardContext = createContext(); | |
| export const LeaderboardProvider = ({ children }) => { | |
| const [leaderboards, setLeaderboards] = useState([]); | |
| const [searchQuery, setSearchQuery] = useState(""); | |
| const [arenaOnly, setArenaOnly] = useState(false); | |
| // Calculate total number of unique leaderboards (excluding duplicates) | |
| const totalLeaderboards = useMemo(() => { | |
| const uniqueIds = new Set(leaderboards.map((board) => board.id)); | |
| return uniqueIds.size; | |
| }, [leaderboards]); | |
| // Filter functions for categories | |
| const filterByTag = useCallback((tag, boards) => { | |
| return ( | |
| boards?.filter( | |
| (board) => | |
| board.tags?.includes(tag) || board.consolidated_tags?.includes(tag) | |
| ) || [] | |
| ); | |
| }, []); | |
| const filterByLanguage = useCallback((boards) => { | |
| return ( | |
| boards?.filter( | |
| (board) => | |
| board.tags?.some((tag) => tag.startsWith("language:")) || | |
| board.consolidated_tags?.some((tag) => tag.startsWith("language:")) | |
| ) || [] | |
| ); | |
| }, []); | |
| const filterByVision = useCallback((boards) => { | |
| return ( | |
| boards?.filter( | |
| (board) => | |
| board.tags?.some( | |
| (tag) => tag === "modality:video" || tag === "modality:image" | |
| ) || | |
| board.consolidated_tags?.some( | |
| (tag) => tag === "modality:video" || tag === "modality:image" | |
| ) | |
| ) || [] | |
| ); | |
| }, []); | |
| const filterUncategorized = useCallback((boards) => { | |
| const categorizedTags = [ | |
| "eval:code", | |
| "eval:math", | |
| "modality:video", | |
| "modality:image", | |
| "modality:audio", | |
| "modality:tools", | |
| "domain:financial", | |
| "domain:medical", | |
| "domain:legal", | |
| ]; | |
| return ( | |
| boards?.filter((board) => { | |
| if ( | |
| (!board.tags || board.tags.length === 0) && | |
| (!board.consolidated_tags || board.consolidated_tags.length === 0) | |
| ) { | |
| return true; | |
| } | |
| const hasNoTagsInCategory = !board.tags?.some( | |
| (tag) => categorizedTags.includes(tag) || tag.startsWith("language:") | |
| ); | |
| const hasNoConsolidatedTagsInCategory = !board.consolidated_tags?.some( | |
| (tag) => categorizedTags.includes(tag) || tag.startsWith("language:") | |
| ); | |
| return hasNoTagsInCategory && hasNoConsolidatedTagsInCategory; | |
| }) || [] | |
| ); | |
| }, []); | |
| // Define sections | |
| const allSections = useMemo(() => { | |
| if (!leaderboards) return []; | |
| return [ | |
| { | |
| id: "code", | |
| title: "Code", | |
| data: filterByTag("eval:code", leaderboards), | |
| }, | |
| { | |
| id: "math", | |
| title: "Math", | |
| data: filterByTag("eval:math", leaderboards), | |
| }, | |
| { | |
| id: "language", | |
| title: "Language Specific", | |
| data: filterByLanguage(leaderboards), | |
| }, | |
| { id: "vision", title: "Vision", data: filterByVision(leaderboards) }, | |
| { | |
| id: "audio", | |
| title: "Audio", | |
| data: filterByTag("modality:audio", leaderboards), | |
| }, | |
| { | |
| id: "agentic", | |
| title: "Agentic", | |
| data: filterByTag("modality:tools", leaderboards), | |
| }, | |
| { | |
| id: "financial", | |
| title: "Financial", | |
| data: filterByTag("domain:financial", leaderboards), | |
| }, | |
| { | |
| id: "medical", | |
| title: "Medical", | |
| data: filterByTag("domain:medical", leaderboards), | |
| }, | |
| { | |
| id: "legal", | |
| title: "Legal", | |
| data: filterByTag("domain:legal", leaderboards), | |
| }, | |
| { | |
| id: "uncategorized", | |
| title: "Uncategorized", | |
| data: filterUncategorized(leaderboards), | |
| }, | |
| ]; | |
| }, [ | |
| leaderboards, | |
| filterByTag, | |
| filterByLanguage, | |
| filterByVision, | |
| filterUncategorized, | |
| ]); | |
| // Get sections with data | |
| const sections = useMemo(() => { | |
| return allSections.filter((section) => section.data.length > 0); | |
| }, [allSections]); | |
| // Filter leaderboards based on search query and arena toggle | |
| const filterLeaderboards = useCallback( | |
| (boards) => { | |
| if (!boards) return []; | |
| let filtered = [...boards]; | |
| // Filter by search query | |
| if (searchQuery) { | |
| const query = searchQuery.toLowerCase(); | |
| const searchableTagPrefixes = [ | |
| "domain:", | |
| "language:", | |
| "judge:", | |
| "test:", | |
| "modality:", | |
| "submission:", | |
| ]; | |
| filtered = filtered.filter((board) => { | |
| const isTagSearch = searchableTagPrefixes.some((prefix) => | |
| query.startsWith(prefix) | |
| ); | |
| if (isTagSearch) { | |
| return ( | |
| board.tags?.some((tag) => tag.toLowerCase().includes(query)) || | |
| board.consolidated_tags?.some((tag) => | |
| tag.toLowerCase().includes(query) | |
| ) | |
| ); | |
| } | |
| return board.card_data?.title?.toLowerCase().includes(query); | |
| }); | |
| } | |
| // Filter arena only | |
| if (arenaOnly) { | |
| filtered = filtered.filter( | |
| (board) => | |
| board.tags?.includes("judge:humans") || | |
| board.consolidated_tags?.includes("judge:humans") | |
| ); | |
| } | |
| return filtered; | |
| }, | |
| [searchQuery, arenaOnly] | |
| ); | |
| // Get filtered count | |
| const filteredCount = useMemo(() => { | |
| return filterLeaderboards(leaderboards).length; | |
| }, [filterLeaderboards, leaderboards]); | |
| // Function to get highlighted parts of text | |
| const getHighlightedText = useCallback((text, searchTerm) => { | |
| if (!searchTerm || !text) return { text, shouldHighlight: false }; | |
| const query = searchTerm.toLowerCase(); | |
| const searchableTagPrefixes = [ | |
| "domain:", | |
| "language:", | |
| "judge:", | |
| "test:", | |
| "modality:", | |
| "submission:", | |
| ]; | |
| // Si c'est une recherche par tag, on ne highlight rien | |
| if (searchableTagPrefixes.some((prefix) => query.startsWith(prefix))) { | |
| return { text, shouldHighlight: false }; | |
| } | |
| // Sinon on highlight les parties qui matchent | |
| const index = text.toLowerCase().indexOf(query); | |
| if (index === -1) return { text, shouldHighlight: false }; | |
| return { | |
| text, | |
| shouldHighlight: true, | |
| highlightStart: index, | |
| highlightEnd: index + query.length, | |
| }; | |
| }, []); | |
| const value = { | |
| leaderboards, | |
| setLeaderboards, | |
| searchQuery, | |
| setSearchQuery, | |
| arenaOnly, | |
| setArenaOnly, | |
| totalLeaderboards, | |
| filteredCount, | |
| filterLeaderboards, | |
| sections, | |
| allSections, | |
| getHighlightedText, | |
| }; | |
| return ( | |
| <LeaderboardContext.Provider value={value}> | |
| {children} | |
| </LeaderboardContext.Provider> | |
| ); | |
| }; | |
| export const useLeaderboard = () => { | |
| const context = useContext(LeaderboardContext); | |
| if (!context) { | |
| throw new Error("useLeaderboard must be used within a LeaderboardProvider"); | |
| } | |
| return context; | |
| }; | |