enzostvs HF staff commited on
Commit
59131f2
·
1 Parent(s): f565d19

add details gpu

Browse files
components/spaces/details.tsx ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+ import { useEffect, useState } from "react";
3
+
4
+ import { SpaceProps } from "@/utils/type";
5
+ import { GpuIcon } from "../gpu_icon";
6
+ import { Progress } from "./progress";
7
+
8
+ export const Details: React.FC<{ space: SpaceProps }> = ({ space }) => {
9
+ const [metric, setMetric] = useState<any>(null);
10
+ const [gpuNumber, setGpuNumber] = useState<number>(0);
11
+
12
+ useEffect(() => {
13
+ const esMetric = new EventSource(
14
+ `https://api.hf.space/v1/${space.id}/live-metrics/sse`
15
+ );
16
+ const esGpu = new EventSource(`https://api.hf.space/v1/${space.id}/sse`);
17
+
18
+ esGpu.addEventListener("zero-gpu-count", (event) => {
19
+ setGpuNumber(parseInt(event.data));
20
+ });
21
+ esMetric.addEventListener("metric", (event) => {
22
+ setMetric(JSON.parse(event.data));
23
+ });
24
+
25
+ return () => {
26
+ esMetric.close();
27
+ esGpu.close();
28
+ };
29
+ }, [space]);
30
+
31
+ return (
32
+ <div className="border border-gray-200 shadow-md bg-white p-4 rounded-lg absolute -bottom-2 translate-y-full left-0 z-[99999]">
33
+ <p className="text-sm text-gray-600 flex items-center justify-start gap-1 font-medium">
34
+ This Space is currently using{" "}
35
+ <span className="border border-emerald-200 bg-emerald-50 font-medium text-emerald-500 flex items-center justify-center gap-1 max-w-max rounded-md px-1 py-0.5 text-xs">
36
+ {gpuNumber} <GpuIcon />
37
+ </span>{" "}
38
+ GPU{gpuNumber > 1 && "s"}.
39
+ </p>
40
+ <div className="mt-3 space-y-1">
41
+ <div className="flex items-center justify-between font-mono text-[.8rem]">
42
+ <div className="flex flex-col">
43
+ <p className="font-semibold uppercase">CPU</p>{" "}
44
+ <p className="text-gray-400">{metric?.cpu_usage_pct}%</p>
45
+ </div>{" "}
46
+ <Progress usage={metric?.cpu_usage_pct} max={100} />
47
+ </div>
48
+ <div className="flex items-center justify-between font-mono text-[.8rem]">
49
+ <div className="flex flex-col">
50
+ <p className="font-semibold uppercase">RAM</p>{" "}
51
+ <p className="text-gray-400">{metric?.cpu_usage_pct}%</p>
52
+ </div>{" "}
53
+ <Progress
54
+ usage={Math.ceil(metric?.memory_used_bytes / 1_000_000_000)}
55
+ max={Math.ceil(metric?.memory_total_bytes / 1_000_000_000)}
56
+ />
57
+ </div>
58
+ </div>
59
+ </div>
60
+ );
61
+ };
components/spaces/index.tsx CHANGED
@@ -1,9 +1,8 @@
1
  "use client";
2
- import { useMemo, useState } from "react";
3
 
4
  import { SpaceProps } from "@/utils/type";
5
  import { SpaceIcon } from "@/components/space_icon";
6
- import { fetchAllPages, sortByCreatedAt, sortByLikes } from "@/utils";
7
 
8
  import { Space } from "@/components/spaces/space";
9
  import { Sort } from "@/components/sort";
@@ -11,6 +10,7 @@ import { useUpdateEffect } from "react-use";
11
  import { useRouter } from "next/navigation";
12
 
13
  export const Spaces: React.FC<{ spaces: SpaceProps[] }> = ({ spaces }) => {
 
14
  const router = useRouter();
15
  const [sort, setSort] = useState<"likes" | "createdAt">("likes");
16
 
@@ -18,6 +18,14 @@ export const Spaces: React.FC<{ spaces: SpaceProps[] }> = ({ spaces }) => {
18
  router.push("/?sort=" + sort);
19
  }, [sort]);
20
 
 
 
 
 
 
 
 
 
21
  return (
22
  <>
23
  <header className="max-w-5xl mx-auto w-full max-lg:flex-col items-start flex lg:items-end lg:justify-between gap-4">
@@ -37,7 +45,12 @@ export const Spaces: React.FC<{ spaces: SpaceProps[] }> = ({ spaces }) => {
37
  </header>
38
  <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
39
  {spaces?.map((space: SpaceProps) => (
40
- <Space key={space.id} space={space} />
 
 
 
 
 
41
  ))}
42
  </div>
43
  </>
 
1
  "use client";
2
+ import { useState } from "react";
3
 
4
  import { SpaceProps } from "@/utils/type";
5
  import { SpaceIcon } from "@/components/space_icon";
 
6
 
7
  import { Space } from "@/components/spaces/space";
8
  import { Sort } from "@/components/sort";
 
10
  import { useRouter } from "next/navigation";
11
 
12
  export const Spaces: React.FC<{ spaces: SpaceProps[] }> = ({ spaces }) => {
13
+ const [selectedGpu, setSelectedGpu] = useState<string | undefined>(undefined);
14
  const router = useRouter();
15
  const [sort, setSort] = useState<"likes" | "createdAt">("likes");
16
 
 
18
  router.push("/?sort=" + sort);
19
  }, [sort]);
20
 
21
+ const handleSelectGpu = (gpu: string) => {
22
+ if (selectedGpu === gpu) {
23
+ setSelectedGpu(undefined);
24
+ return;
25
+ }
26
+ setSelectedGpu(gpu);
27
+ };
28
+
29
  return (
30
  <>
31
  <header className="max-w-5xl mx-auto w-full max-lg:flex-col items-start flex lg:items-end lg:justify-between gap-4">
 
45
  </header>
46
  <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
47
  {spaces?.map((space: SpaceProps) => (
48
+ <Space
49
+ key={space.id}
50
+ space={space}
51
+ selected={selectedGpu === space.id}
52
+ onSelect={handleSelectGpu}
53
+ />
54
  ))}
55
  </div>
56
  </>
components/spaces/progress.tsx ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useMemo } from "react";
2
+
3
+ export const Progress: React.FC<{ usage: number; max: number }> = ({
4
+ usage,
5
+ max,
6
+ }) => {
7
+ const percentage = useMemo(() => {
8
+ return (100 * usage) / max;
9
+ }, [usage, max]);
10
+
11
+ return (
12
+ <div className="flex h-8 w-3 flex-col-reverse overflow-hidden rounded-[.1rem] bg-gray-200">
13
+ <div
14
+ className="border-green-600 bg-green-600/40 shadow-[inset_0_2px_0_rgb(5,150,105)] transition-[height] dark:bg-green-800"
15
+ style={{ height: `${percentage.toFixed(0)}%` }}
16
+ ></div>
17
+ </div>
18
+ );
19
+ };
components/spaces/space.tsx CHANGED
@@ -1,19 +1,26 @@
 
1
  import Image from "next/image";
2
  import { TiHeartFullOutline } from "react-icons/ti";
 
 
3
 
4
  import { SpaceProps } from "@/utils/type";
5
- import Link from "next/link";
6
  import { GpuIcon } from "../gpu_icon";
 
7
 
8
  interface Props {
9
  space: SpaceProps;
 
 
10
  }
11
- export const Space: React.FC<Props> = ({ space }) => {
12
  return (
13
  <Link
14
  href={`https://huggingface.co/spaces/${space.id}`}
15
  target="_blank"
16
- className="bg-gray-50 border border-gray-200 px-6 py-4 rounded-xl transition-all duration-300 hover:-translate-y-1.5 hover:border-amber-400 hover:shadow-xl hover:shadow-black/5 group"
 
 
17
  >
18
  <header className="flex items-center justify-between gap-5">
19
  <div>
@@ -68,6 +75,7 @@ export const Space: React.FC<Props> = ({ space }) => {
68
  </div>
69
  </div>
70
  </header>
 
71
  </Link>
72
  );
73
  };
 
1
+ import Link from "next/link";
2
  import Image from "next/image";
3
  import { TiHeartFullOutline } from "react-icons/ti";
4
+ import { FiChevronRight } from "react-icons/fi";
5
+ import classNames from "classnames";
6
 
7
  import { SpaceProps } from "@/utils/type";
 
8
  import { GpuIcon } from "../gpu_icon";
9
+ import { Details } from "./details";
10
 
11
  interface Props {
12
  space: SpaceProps;
13
+ selected?: boolean;
14
+ onSelect?: (gpu: string) => void;
15
  }
16
+ export const Space: React.FC<Props> = ({ space, selected, onSelect }) => {
17
  return (
18
  <Link
19
  href={`https://huggingface.co/spaces/${space.id}`}
20
  target="_blank"
21
+ className="relative hover:z-40 bg-gray-50 border border-gray-200 px-6 py-4 rounded-xl transition-all duration-300 hover:-translate-y-1.5 hover:border-amber-400 hover:shadow-xl hover:shadow-black/5 group"
22
+ onMouseEnter={() => onSelect?.(space.id)}
23
+ onMouseLeave={() => onSelect?.(space.id)}
24
  >
25
  <header className="flex items-center justify-between gap-5">
26
  <div>
 
75
  </div>
76
  </div>
77
  </header>
78
+ {selected && <Details space={space} />}
79
  </Link>
80
  );
81
  };