gardarjuto commited on
Commit
76fa2a9
·
1 Parent(s): 0c88e20

simplify UI

Browse files
DEPLOYMENT.md CHANGED
@@ -59,8 +59,23 @@ The README.md contains the required HF Spaces metadata:
59
 
60
  ## Environment Variables
61
 
62
- - `HF_TOKEN`: Hugging Face API token (optional, can use HF OAuth)
 
 
 
 
 
 
63
  - `PORT`: Frontend server port (default: 7860)
64
  - `INTERNAL_API_PORT`: Backend server port (default: 7861)
 
 
 
 
 
 
 
 
 
65
 
66
- The application will automatically use HF OAuth for authentication when deployed on HF Spaces.
 
59
 
60
  ## Environment Variables
61
 
62
+ ### Required
63
+ - **`HF_TOKEN`**: Hugging Face API token with read access to datasets
64
+ - Required to access `mideind/icelandic-llm-leaderboard-*` repositories
65
+ - Get from: https://huggingface.co/settings/tokens
66
+ - Add as repository secret in HF Spaces settings
67
+
68
+ ### Optional
69
  - `PORT`: Frontend server port (default: 7860)
70
  - `INTERNAL_API_PORT`: Backend server port (default: 7861)
71
+ - `HF_HOME`: Cache directory (default: /app/.cache)
72
+
73
+ ## HF Spaces Setup
74
+
75
+ 1. **Create Space** with Docker SDK
76
+ 2. **Add HF_TOKEN secret**:
77
+ - Go to Space Settings → Repository secrets
78
+ - Add secret: Name=`HF_TOKEN`, Value=`hf_your_token_here`
79
+ 3. **Push code** and restart Space
80
 
81
+ The HF_TOKEN is essential for downloading evaluation data from the Icelandic repositories.
Dockerfile_ DELETED
@@ -1,62 +0,0 @@
1
- # Build frontend
2
- FROM node:18 as frontend-build
3
- WORKDIR /app
4
- COPY frontend/package*.json ./
5
- RUN npm install
6
- COPY frontend/ ./
7
-
8
- RUN npm run build
9
-
10
- # Build backend
11
- FROM python:3.12-slim
12
- WORKDIR /app
13
-
14
- # Create non-root user
15
- RUN useradd -m -u 1000 user
16
-
17
- # Install poetry
18
- RUN pip install poetry
19
-
20
- # Create and configure cache directory
21
- RUN mkdir -p /app/.cache && \
22
- chown -R user:user /app
23
-
24
- # Copy and install backend dependencies
25
- COPY backend/pyproject.toml backend/poetry.lock* ./
26
- RUN poetry config virtualenvs.create false \
27
- && poetry install --no-interaction --no-ansi --no-root --only main
28
-
29
- # Copy backend code
30
- COPY backend/ .
31
-
32
- # Install Node.js and npm
33
- RUN apt-get update && apt-get install -y \
34
- curl \
35
- netcat-openbsd \
36
- && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
37
- && apt-get install -y nodejs \
38
- && rm -rf /var/lib/apt/lists/*
39
-
40
- # Copy frontend server and build
41
- COPY --from=frontend-build /app/build ./frontend/build
42
- COPY --from=frontend-build /app/package*.json ./frontend/
43
- COPY --from=frontend-build /app/server.js ./frontend/
44
-
45
- # Install frontend production dependencies
46
- WORKDIR /app/frontend
47
- RUN npm install --production
48
- WORKDIR /app
49
-
50
- # Environment variables
51
- ENV HF_HOME=/app/.cache \
52
- HF_DATASETS_CACHE=/app/.cache \
53
- INTERNAL_API_PORT=7861 \
54
- PORT=7860 \
55
- NODE_ENV=production
56
-
57
- # Note: HF_TOKEN should be provided at runtime, not build time
58
- USER user
59
- EXPOSE 7860
60
-
61
- # Start both servers with wait-for
62
- CMD ["sh", "-c", "uvicorn app.asgi:app --host 0.0.0.0 --port 7861 & while ! nc -z localhost 7861; do sleep 1; done && cd frontend && npm run serve"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/src/pages/LeaderboardPage/components/Leaderboard/Leaderboard.js CHANGED
@@ -11,96 +11,7 @@ import LeaderboardFilters from "./components/Filters/Filters";
11
  import LeaderboardTable from "./components/Table/Table";
12
  import SearchBar, { SearchBarSkeleton } from "./components/Filters/SearchBar";
13
  import PerformanceMonitor from "./components/PerformanceMonitor";
14
- import QuickFilters, {
15
- QuickFiltersSkeleton,
16
- } from "./components/Filters/QuickFilters";
17
 
18
- const FilterAccordion = ({ expanded, quickFilters, advancedFilters }) => {
19
- const advancedFiltersRef = React.useRef(null);
20
- const quickFiltersRef = React.useRef(null);
21
- const [height, setHeight] = React.useState("auto");
22
- const resizeTimeoutRef = React.useRef(null);
23
-
24
- const updateHeight = React.useCallback(() => {
25
- if (expanded && advancedFiltersRef.current) {
26
- setHeight(`${advancedFiltersRef.current.scrollHeight}px`);
27
- } else if (!expanded && quickFiltersRef.current) {
28
- setHeight(`${quickFiltersRef.current.scrollHeight}px`);
29
- }
30
- }, [expanded]);
31
-
32
- React.useEffect(() => {
33
- // Initial height calculation
34
- const timer = setTimeout(updateHeight, 100);
35
-
36
- // Resize handler with debounce
37
- const handleResize = () => {
38
- if (resizeTimeoutRef.current) {
39
- clearTimeout(resizeTimeoutRef.current);
40
- }
41
- resizeTimeoutRef.current = setTimeout(updateHeight, 150);
42
- };
43
-
44
- window.addEventListener("resize", handleResize);
45
-
46
- return () => {
47
- clearTimeout(timer);
48
- window.removeEventListener("resize", handleResize);
49
- if (resizeTimeoutRef.current) {
50
- clearTimeout(resizeTimeoutRef.current);
51
- }
52
- };
53
- }, [updateHeight]);
54
-
55
- // Update height when expanded state changes
56
- React.useEffect(() => {
57
- updateHeight();
58
- }, [expanded, updateHeight]);
59
-
60
- return (
61
- <Box
62
- sx={{
63
- position: "relative",
64
- width: "100%",
65
- height,
66
- transition: "height 0.3s ease",
67
- mb: 0.5,
68
- overflow: "hidden",
69
- }}
70
- >
71
- <Box
72
- ref={quickFiltersRef}
73
- sx={{
74
- position: expanded ? "absolute" : "relative",
75
- top: 0,
76
- left: 0,
77
- right: 0,
78
- opacity: expanded ? 0 : 1,
79
- visibility: expanded ? "hidden" : "visible",
80
- transition: "opacity 0.3s ease",
81
- mb: 0,
82
- }}
83
- >
84
- {quickFilters}
85
- </Box>
86
- <Box
87
- ref={advancedFiltersRef}
88
- sx={{
89
- position: !expanded ? "absolute" : "relative",
90
- top: 0,
91
- left: 0,
92
- right: 0,
93
- opacity: expanded ? 1 : 0,
94
- visibility: !expanded ? "hidden" : "visible",
95
- transition: "opacity 0.3s ease",
96
- mt: 0,
97
- }}
98
- >
99
- {advancedFilters}
100
- </Box>
101
- </Box>
102
- );
103
- };
104
 
105
  const Leaderboard = () => {
106
  const { state, actions } = useLeaderboard();
@@ -266,17 +177,6 @@ const Leaderboard = () => {
266
  ]
267
  );
268
 
269
- const memoizedQuickFilters = useMemo(
270
- () => (
271
- <QuickFilters
272
- totalCount={state.models.length}
273
- filteredCount={memoizedFilteredData?.length || 0}
274
- data={memoizedFilteredData}
275
- table={memoizedTable}
276
- />
277
- ),
278
- [state.models.length, memoizedFilteredData, memoizedTable]
279
- );
280
 
281
  const memoizedLeaderboardFilters = useMemo(
282
  () => (
@@ -411,14 +311,8 @@ const Leaderboard = () => {
411
  memoizedSearchBar
412
  )}
413
  <Box sx={{ mt: 1 }}>
414
- {loadingStates.showFiltersSkeleton ? (
415
- <QuickFiltersSkeleton />
416
- ) : (
417
- <FilterAccordion
418
- expanded={state.filtersExpanded}
419
- quickFilters={memoizedQuickFilters}
420
- advancedFilters={memoizedLeaderboardFilters}
421
- />
422
  )}
423
  </Box>
424
  </Box>
 
11
  import LeaderboardTable from "./components/Table/Table";
12
  import SearchBar, { SearchBarSkeleton } from "./components/Filters/SearchBar";
13
  import PerformanceMonitor from "./components/PerformanceMonitor";
 
 
 
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  const Leaderboard = () => {
17
  const { state, actions } = useLeaderboard();
 
177
  ]
178
  );
179
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
  const memoizedLeaderboardFilters = useMemo(
182
  () => (
 
311
  memoizedSearchBar
312
  )}
313
  <Box sx={{ mt: 1 }}>
314
+ {!loadingStates.showFiltersSkeleton && state.filtersExpanded && (
315
+ memoizedLeaderboardFilters
 
 
 
 
 
 
316
  )}
317
  </Box>
318
  </Box>
frontend/src/pages/LeaderboardPage/components/Leaderboard/components/Filters/Filters.js CHANGED
@@ -348,13 +348,8 @@ const LeaderboardFilters = ({
348
  const [localParamsRange, setLocalParamsRange] = useState(paramsRange);
349
  const stableTimerRef = useRef(null);
350
  const { state, actions } = useLeaderboard();
351
- const { normal: filterCounts, officialOnly: officialOnlyCounts } =
352
- state.filterCounts;
353
- const isOfficialProviderActive = state.filters.isOfficialProviderActive;
354
- const currentCounts = useMemo(
355
- () => (isOfficialProviderActive ? officialOnlyCounts : filterCounts),
356
- [isOfficialProviderActive, officialOnlyCounts, filterCounts]
357
- );
358
 
359
  useEffect(() => {
360
  setLocalParamsRange(paramsRange);
@@ -403,17 +398,10 @@ const LeaderboardFilters = ({
403
  };
404
 
405
  // Filter options based on their hide property
406
- const showFilterOptions = BOOLEAN_FILTER_OPTIONS.filter(
407
- (option) => !option.hide
408
- );
409
  const hideFilterOptions = BOOLEAN_FILTER_OPTIONS.filter(
410
  (option) => option.hide
411
  );
412
 
413
- const handleOfficialProviderToggle = () => {
414
- actions.toggleOfficialProvider();
415
- };
416
-
417
  return loading ? null : (
418
  <Box>
419
  <Accordion
@@ -444,7 +432,7 @@ const LeaderboardFilters = ({
444
  >
445
  <Box>
446
  <Grid container spacing={3}>
447
- <Grid item xs={12} md={9} sx={{ display: "flex" }}>
448
  <Box
449
  sx={{
450
  backgroundColor: (theme) =>
@@ -692,153 +680,6 @@ const LeaderboardFilters = ({
692
  </Box>
693
  </Box>
694
  </Grid>
695
-
696
- <Grid item xs={12} md={3} sx={{ display: "flex" }}>
697
- <Box
698
- sx={{
699
- backgroundColor: (theme) =>
700
- alpha(theme.palette.secondary.main, 0.02),
701
- border: "1px solid",
702
- borderColor: (theme) =>
703
- alpha(theme.palette.secondary.main, 0.15),
704
- borderRadius: 1,
705
- p: 3,
706
- position: "relative",
707
- width: "100%",
708
- display: "flex",
709
- flexDirection: "column",
710
- alignItems: "center",
711
- justifyContent: "center",
712
- textAlign: "center",
713
- minHeight: "100%",
714
- "&:hover": {
715
- borderColor: (theme) =>
716
- alpha(theme.palette.secondary.main, 0.25),
717
- backgroundColor: (theme) =>
718
- alpha(theme.palette.secondary.main, 0.03),
719
- },
720
- transition: (theme) =>
721
- theme.transitions.create(
722
- ["border-color", "background-color"],
723
- {
724
- duration: theme.transitions.duration.short,
725
- }
726
- ),
727
- }}
728
- >
729
- <Box
730
- sx={{
731
- display: "flex",
732
- flexDirection: "column",
733
- alignItems: "center",
734
- gap: 2,
735
- }}
736
- >
737
- <Typography
738
- variant="h6"
739
- sx={{
740
- fontWeight: 600,
741
- color: "text.primary",
742
- fontSize: "1.1rem",
743
- display: "flex",
744
- alignItems: "center",
745
- gap: 1,
746
- }}
747
- >
748
- Official Models
749
- </Typography>
750
- <Typography
751
- variant="body2"
752
- sx={{
753
- color: "text.secondary",
754
- fontSize: "0.8rem",
755
- lineHeight: 1.4,
756
- maxWidth: "280px",
757
- }}
758
- >
759
- Show only models that are officially provided and
760
- maintained by their original creators.
761
- </Typography>
762
- <Box
763
- sx={{
764
- display: "flex",
765
- flexDirection: "column",
766
- gap: 1,
767
- width: "100%",
768
- alignItems: "center",
769
- }}
770
- >
771
- {showFilterOptions.map((filter) => (
772
- <Box
773
- key={filter.value}
774
- sx={{
775
- display: "flex",
776
- flexDirection: "column",
777
- alignItems: "center",
778
- gap: 1,
779
- }}
780
- >
781
- <FilterTag
782
- label={filter.label}
783
- checked={
784
- filter.value === "is_official_provider"
785
- ? isOfficialProviderActive
786
- : selectedBooleanFilters.includes(filter.value)
787
- }
788
- onChange={
789
- filter.value === "is_official_provider"
790
- ? handleOfficialProviderToggle
791
- : () => handleBooleanFilterToggle(filter.value)
792
- }
793
- count={
794
- filter.value === "is_official_provider"
795
- ? currentCounts.officialProviders
796
- : 0
797
- }
798
- showCheckbox={true}
799
- variant="secondary"
800
- />
801
- <Box
802
- sx={{
803
- display: "flex",
804
- alignItems: "center",
805
- gap: 0.5,
806
- color: "text.secondary",
807
- fontSize: "0.75rem",
808
- }}
809
- >
810
- <Box
811
- component="span"
812
- sx={{
813
- width: 6,
814
- height: 6,
815
- borderRadius: "50%",
816
- backgroundColor: (
817
- filter.value ===
818
- "is_official_provider"
819
- ? isOfficialProviderActive
820
- : selectedBooleanFilters.includes(
821
- filter.value
822
- )
823
- )
824
- ? "success.main"
825
- : "text.disabled",
826
- }}
827
- />
828
- {(
829
- filter.value === "is_official_provider"
830
- ? isOfficialProviderActive
831
- : selectedBooleanFilters.includes(filter.value)
832
- )
833
- ? "Filter active"
834
- : "Filter inactive"}
835
- </Box>
836
- </Box>
837
- ))}
838
- </Box>
839
- </Box>
840
- </Box>
841
- </Grid>
842
  </Grid>
843
  </Box>
844
  </AccordionDetails>
 
348
  const [localParamsRange, setLocalParamsRange] = useState(paramsRange);
349
  const stableTimerRef = useRef(null);
350
  const { state, actions } = useLeaderboard();
351
+ const { normal: filterCounts } = state.filterCounts;
352
+ const currentCounts = filterCounts;
 
 
 
 
 
353
 
354
  useEffect(() => {
355
  setLocalParamsRange(paramsRange);
 
398
  };
399
 
400
  // Filter options based on their hide property
 
 
 
401
  const hideFilterOptions = BOOLEAN_FILTER_OPTIONS.filter(
402
  (option) => option.hide
403
  );
404
 
 
 
 
 
405
  return loading ? null : (
406
  <Box>
407
  <Accordion
 
432
  >
433
  <Box>
434
  <Grid container spacing={3}>
435
+ <Grid item xs={12} sx={{ display: "flex" }}>
436
  <Box
437
  sx={{
438
  backgroundColor: (theme) =>
 
680
  </Box>
681
  </Box>
682
  </Grid>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
683
  </Grid>
684
  </Box>
685
  </AccordionDetails>