File size: 4,807 Bytes
f817b5c
 
 
 
 
 
 
 
 
 
 
8316e17
f817b5c
8316e17
 
f817b5c
 
 
8316e17
 
 
 
 
 
 
f817b5c
8316e17
430cd22
 
 
 
f817b5c
 
 
 
 
 
 
 
 
8316e17
 
 
f817b5c
8316e17
 
 
 
 
 
f817b5c
 
 
8316e17
f817b5c
 
8316e17
 
 
 
f817b5c
0d707b5
ee72882
f817b5c
8316e17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0d707b5
8316e17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0d707b5
f817b5c
 
8316e17
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { Inter } from 'next/font/google';
import SearchBar from '@/components/searchBar';
import Card from '@/components/card';
import { predict } from '@/pages/api/api_hf';
import { get_space_info } from '@/pages/api/hf_space';
import { useState, useEffect } from 'react';

const inter = Inter({ subsets: ['latin'] });

export default function Home() {
  const [spaceInfo, setSpaceInfo] = useState(null);
  const [sortedSpaceInfo, setSortedSpaceInfo] = useState(null);
  const [searchResults, setSearchResults] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [sortBy, setSortBy] = useState('relevance');

  useEffect(() => {
    async function fetchSpaceInfo(results) {
      setIsLoading(true);
      const spaceData = await Promise.all(
        results.map(async ([id, description]) => {
          const space = await get_space_info(id);
          return space ? { ...space, description } : null;
        })
      );
      setSpaceInfo(spaceData);
      setIsLoading(false);
      document.querySelector('.search-bar').scrollIntoView({
        behavior: 'smooth',
        block: 'start',
      });
    }

    if (searchResults.length > 0) {
      fetchSpaceInfo(searchResults);
    } else {
      setSpaceInfo(null);
    }
  }, [searchResults]);

  useEffect(() => {
    if (spaceInfo) {
      setSortedSpaceInfo(sortResults(spaceInfo, sortBy));
    }
  }, [spaceInfo, sortBy]);

  async function onSearch(query) {
    setIsLoading(true); // Show loading animation when searching
    setSortBy('relevance'); // Reset sorting to Relevance on new search
    setSearchResults(query ? await predict(query, 12) : []);
  }

  useEffect(() => {
    document.querySelector('.search-bar')?.focus();
  }, []);

  function sortResults(results, sortBy) {
    return sortBy === 'likes' ? [...results].sort((a, b) => b.likes - a.likes) : results;
  }

  return (
    <main className={`flex min-h-screen flex-col items-center p-8 md:px-24 pt-20 bg-gray-950 ${inter.className} justify-between`}>
      <h1 className="text-4xl md:text-6xl font-bold text-center mb-12 text-white">πŸ€— Hugging Face Spaces</h1>
      <SearchBar onSearch={onSearch} />
      { isLoading ? (
              <div className="col-span-full flex justify-center items-center">
                <div className="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-white"></div>
              </div>
            ) : (
      sortedSpaceInfo && (
        <>
          {!isLoading && (
            <div className="flex justify-center mt-4 items-baseline">
              <span className="text-white mr-2">Sort by:</span>
              {['relevance', 'likes'].map((option) => (
                <button
                  key={option}
                  className={`px-4 py-1 rounded-full mr-2 ${sortBy === option ? 'bg-white text-gray-900' : 'bg-gray-900 text-white'}`}
                  onClick={() => setSortBy(option)}
                >
                  {option.charAt(0).toUpperCase() + option.slice(1)}
                </button>
              ))}
            </div>
          )}
          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 w-full mt-8">
            {
              sortedSpaceInfo.map(
                (space, index) =>
                  space && (
                    <Card
                      key={index}
                      {...space}
                      space_id={space.space_id}
                      author={space.author}
                      title={space.title}
                      emoji={space.emoji}
                      lastModified={space.lastModified}
                      colorFrom={space.colorFrom}
                      colorTo={space.colorTo}
                      sdk={space.sdk}
                      runtimeStage={space.runtime_stage}
                      currentHardware={space.current_hardware}
                    />
                  )
              )
            }
          </div>
        </>
      ))}
      <footer className="text-center text-gray-500 text-sm mt-8 bottom-0 w-full p-4">
        Created by Anzor Qunash
        <br />
        <a href="https://huggingface.co/datasets/anzorq/hf-spaces-descriptions-embeddings" target="_blank" rel="noopener noreferrer">
          Dataset
        </a>
        <span className="mx-2">β€’</span>
        <a href="https://github.com/qunash" target="_blank" rel="noopener noreferrer">
          GitHub
        </a>
        <span className="mx-2">β€’</span>
        <a href="https://twitter.com/hahahahohohe" target="_blank" rel="noopener noreferrer">
          Twitter
        </a>
        <span className="mx-2">β€’</span>
        <a href="https://www.buymeacoffee.com/anzorq" target="_blank" rel="noopener noreferrer">
          Buy me a coffee
        </a>
      </footer>
    </main>
  );
}