jbilcke-hf HF staff commited on
Commit
a64395a
1 Parent(s): 1f122c3

made some changes to the hub.js client

Browse files
src/app/main.tsx CHANGED
@@ -17,11 +17,12 @@ export function Main() {
17
  return (
18
  <div className={cn(
19
  `flex flex-row h-screen w-screen inset-0 overflow-hidden`,
 
20
  )}>
21
  <LeftMenu />
22
  <div className={cn(
23
  `flex flex-col`,
24
- `w-[calc(100vh-56px)]`
25
  )}>
26
  <TopMenu />
27
  {view === "home" && <HomeView />}
 
17
  return (
18
  <div className={cn(
19
  `flex flex-row h-screen w-screen inset-0 overflow-hidden`,
20
+ `dark`
21
  )}>
22
  <LeftMenu />
23
  <div className={cn(
24
  `flex flex-col`,
25
+ `w-[calc(100vh-96px)]`
26
  )}>
27
  <TopMenu />
28
  {view === "home" && <HomeView />}
src/app/server/actions/api.ts CHANGED
@@ -8,28 +8,17 @@ const adminUsername = `${process.env.ADMIN_HUGGING_FACE_USERNAME || ""}`
8
 
9
  const adminCredentials: Credentials = { accessToken: adminApiKey }
10
 
11
- export async function getChannels({
12
- apiKey,
13
- owner,
14
- }: { // the user wants to browse their own private or public channels
15
- apiKey: string
16
- owner: undefined
17
- } | { // the user wants to browse someone's else public channels
18
- apiKey: undefined
19
- owner: string
20
- } | { // the user wants to browse all public channels
21
- apiKey: undefined
22
- owner: undefined
23
- } = { // by default we perform a gloval search using admin credentials
24
- apiKey: undefined,
25
- owner: undefined
26
- }): Promise<ChannelInfo[]> {
27
 
28
  let credentials: Credentials = adminCredentials
 
29
 
30
- if (apiKey) {
31
  try {
32
- credentials = { accessToken: apiKey }
33
  const { name: username } = await whoAmI({ credentials })
34
  if (!username) {
35
  throw new Error(`couldn't get the username`)
@@ -48,7 +37,7 @@ export async function getChannels({
48
 
49
  let search = owner
50
  ? { owner } // search channels of a specific user
51
- : { search: prefix } // global search (note: might be costly?)
52
 
53
  console.log("search:", search)
54
 
@@ -62,7 +51,7 @@ export async function getChannels({
62
  ? chunks
63
  : [name, name]
64
 
65
- console.log(`found a candidate dataset "${datasetName}" owned by @${datasetUsername}`)
66
 
67
  if (!datasetName.startsWith(prefix)) {
68
  continue
@@ -70,7 +59,7 @@ export async function getChannels({
70
 
71
  const slug = datasetName.replaceAll(prefix, "")
72
 
73
- console.log(`the dataset is a valid channel: "${slug}"`)
74
 
75
  // TODO parse the README to get the proper label
76
  const label = slug.replaceAll("-", " ")
 
8
 
9
  const adminCredentials: Credentials = { accessToken: adminApiKey }
10
 
11
+ export async function getChannels(options: {
12
+ apiKey?: string
13
+ owner?: string
14
+ } = {}): Promise<ChannelInfo[]> {
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  let credentials: Credentials = adminCredentials
17
+ let owner = options?.owner
18
 
19
+ if (options?.apiKey) {
20
  try {
21
+ credentials = { accessToken: options.apiKey }
22
  const { name: username } = await whoAmI({ credentials })
23
  if (!username) {
24
  throw new Error(`couldn't get the username`)
 
37
 
38
  let search = owner
39
  ? { owner } // search channels of a specific user
40
+ : prefix // global search (note: might be costly?)
41
 
42
  console.log("search:", search)
43
 
 
51
  ? chunks
52
  : [name, name]
53
 
54
+ // console.log(`found a candidate dataset "${datasetName}" owned by @${datasetUsername}`)
55
 
56
  if (!datasetName.startsWith(prefix)) {
57
  continue
 
59
 
60
  const slug = datasetName.replaceAll(prefix, "")
61
 
62
+ console.log(`found an AI Tube channel: "${slug}"`)
63
 
64
  // TODO parse the README to get the proper label
65
  const label = slug.replaceAll("-", " ")
src/app/state/defaultSettings.ts ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ import { Settings } from "@/types"
2
+
3
+ export const defaultSettings: Settings = {
4
+ huggingfaceApiKey: "",
5
+ }
src/app/state/locaStorageKeys.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import { Settings } from "@/types"
2
+
3
+ export const localStorageKeys: Record<keyof Settings, string> = {
4
+ // important: prefix with AI_TUBE to avoid collisions when running the app on localhost
5
+ huggingfaceApiKey: "AI_TUBE_CONF_AUTH_HF_API_TOKEN",
6
+ }
src/app/views/channel-admin-view/index.tsx CHANGED
@@ -33,10 +33,11 @@ export function ChannelAdminView() {
33
  channelId: "",
34
  channel: {
35
  id: "",
 
36
  label: "Hugging Face",
37
- thumbnailUrl: "",
38
- systemPrompt: "",
39
- hfDatasetId: ""
40
  }
41
  }
42
  ]
 
33
  channelId: "",
34
  channel: {
35
  id: "",
36
+ slug: "",
37
  label: "Hugging Face",
38
+ thumbnail: "",
39
+ prompt: "",
40
+ likes: 0,
41
  }
42
  }
43
  ]
src/app/views/channel-public-view/index.tsx CHANGED
@@ -33,10 +33,11 @@ export function ChannelPublicView() {
33
  channelId: "",
34
  channel: {
35
  id: "",
 
36
  label: "Hugging Face",
37
- thumbnailUrl: "",
38
- systemPrompt: "",
39
- hfDatasetId: ""
40
  }
41
  }
42
  ]
 
33
  channelId: "",
34
  channel: {
35
  id: "",
36
+ slug: "",
37
  label: "Hugging Face",
38
+ thumbnail: "",
39
+ prompt: "",
40
+ likes: 0,
41
  }
42
  }
43
  ]
src/app/views/channels-admin-view/index.tsx CHANGED
@@ -1,37 +1,68 @@
1
- import { useEffect, useTransition } from "react"
 
 
 
2
 
3
  import { useStore } from "@/app/state/useStore"
4
  import { cn } from "@/lib/utils"
5
  import { getChannels } from "@/app/server/actions/api"
6
  import { ChannelList } from "@/app/interface/channel-list"
 
 
 
7
 
8
  export function ChannelsAdminView() {
9
  const [_isPending, startTransition] = useTransition()
 
 
 
 
10
 
11
  const currentChannels = useStore(s => s.currentChannels)
12
  const setCurrentChannels = useStore(s => s.setCurrentChannels)
13
- const currentCategory = useStore(s => s.currentCategory)
14
 
15
  useEffect(() => {
16
-
17
- startTransition(async () => {
18
- console.log("querying the HF API..")
19
- const channels = await getChannels()
20
-
21
- console.log("channels:", channels)
22
-
23
- setCurrentChannels(channels)
24
- })
25
-
26
- }, [currentCategory])
 
 
 
27
 
28
  return (
29
  <div className={cn(
30
- `flex flex-col`
31
  )}>
32
- <ChannelList
33
- channels={currentChannels}
34
- />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  </div>
36
  )
37
  }
 
1
+ "use client"
2
+
3
+ import { useEffect, useState, useTransition } from "react"
4
+ import { useLocalStorage } from "usehooks-ts"
5
 
6
  import { useStore } from "@/app/state/useStore"
7
  import { cn } from "@/lib/utils"
8
  import { getChannels } from "@/app/server/actions/api"
9
  import { ChannelList } from "@/app/interface/channel-list"
10
+ import { Input } from "@/components/ui/input"
11
+ import { localStorageKeys } from "@/app/state/locaStorageKeys"
12
+ import { defaultSettings } from "@/app/state/defaultSettings"
13
 
14
  export function ChannelsAdminView() {
15
  const [_isPending, startTransition] = useTransition()
16
+ const [huggingfaceApiKey, setHuggingfaceApiKey] = useLocalStorage<string>(
17
+ localStorageKeys.huggingfaceApiKey,
18
+ defaultSettings.huggingfaceApiKey
19
+ )
20
 
21
  const currentChannels = useStore(s => s.currentChannels)
22
  const setCurrentChannels = useStore(s => s.setCurrentChannels)
23
+ const [isLoaded, setLoaded] = useState(false)
24
 
25
  useEffect(() => {
26
+ if (!isLoaded) {
27
+ startTransition(async () => {
28
+ try {
29
+ const channels = await getChannels({ apiKey: huggingfaceApiKey })
30
+ setCurrentChannels(channels)
31
+ } catch (err) {
32
+ console.error("failed to load the channel for the current user:", err)
33
+ setCurrentChannels([])
34
+ } finally {
35
+ setLoaded(true)
36
+ }
37
+ })
38
+ }
39
+ }, [isLoaded])
40
 
41
  return (
42
  <div className={cn(
43
+ `flex flex-col space-y-4`
44
  )}>
45
+ <div className="flex flex-col space-y-2">
46
+ <div className="flex flex-row space-x-2 items-center">
47
+ <label className="flex w-64">Hugging Face token:</label>
48
+ <Input
49
+ placeholder="Hugging Face token (with WRITE access)"
50
+ type="password"
51
+ className="font-mono"
52
+ onChange={(x) => {
53
+ setHuggingfaceApiKey(x.target.value)
54
+ }}
55
+ value={huggingfaceApiKey}
56
+ />
57
+ </div>
58
+ <p className="text-neutral-100/70">
59
+ Note: your Hugging Face token must be a <span className="font-bold font-mono text-yellow-300">WRITE</span> access token.
60
+ </p>
61
+ </div>
62
+ {huggingfaceApiKey ?
63
+ <ChannelList
64
+ channels={currentChannels}
65
+ /> : null}
66
  </div>
67
  )
68
  }
src/app/views/channels-public-view/index.tsx CHANGED
@@ -1,54 +1,39 @@
1
- import { useEffect } from "react"
2
 
3
  import { useStore } from "@/app/state/useStore"
4
  import { cn } from "@/lib/utils"
5
- import { FullVideoInfo } from "@/types"
6
- import { VideoList } from "@/app/interface/video-list"
7
 
8
  export function ChannelsPublicView() {
9
- const displayMode = useStore(s => s.displayMode)
10
- const setDisplayMode = useStore(s => s.setDisplayMode)
11
- const currentChannel = useStore(s => s.currentChannel)
12
- const setCurrentChannel = useStore(s => s.setCurrentChannel)
13
- const currentCategory = useStore(s => s.currentCategory)
14
- const setCurrentCategory = useStore(s => s.setCurrentCategory)
15
- const currentVideos = useStore(s => s.currentVideos)
16
- const setCurrentVideos = useStore(s => s.setCurrentVideos)
17
- const currentVideo = useStore(s => s.currentVideo)
18
- const setCurrentVideo = useStore(s => s.setCurrentVideo)
19
 
20
- useEffect(() => {
 
 
21
 
22
- // we use fake data for now
23
- // this will be pulled from the Hugging Face API
24
- const newVideos: FullVideoInfo[] = [
25
- {
26
- id: "42",
27
- label: "Test Julian",
28
- thumbnailUrl: "",
29
- assetUrl: "",
30
- numberOfViews: 0,
31
- createdAt: "2023-11-27",
32
- categories: [],
33
- channelId: "",
34
- channel: {
35
- id: "",
36
- label: "Hugging Face",
37
- thumbnailUrl: "",
38
- systemPrompt: "",
39
- hfDatasetId: ""
40
  }
41
- }
42
- ]
43
- setCurrentVideos(newVideos)
44
- }, [currentCategory])
45
 
46
  return (
47
  <div className={cn(
48
  `flex flex-col`
49
  )}>
50
- <VideoList
51
- videos={currentVideos}
52
  />
53
  </div>
54
  )
 
1
+ import { useEffect, useState, useTransition } from "react"
2
 
3
  import { useStore } from "@/app/state/useStore"
4
  import { cn } from "@/lib/utils"
5
+ import { getChannels } from "@/app/server/actions/api"
6
+ import { ChannelList } from "@/app/interface/channel-list"
7
 
8
  export function ChannelsPublicView() {
9
+ const [_isPending, startTransition] = useTransition()
 
 
 
 
 
 
 
 
 
10
 
11
+ const currentChannels = useStore(s => s.currentChannels)
12
+ const setCurrentChannels = useStore(s => s.setCurrentChannels)
13
+ const [isLoaded, setLoaded] = useState(false)
14
 
15
+ useEffect(() => {
16
+ if (!isLoaded) {
17
+ startTransition(async () => {
18
+ try {
19
+ const channels = await getChannels()
20
+ setCurrentChannels(channels)
21
+ } catch (err) {
22
+ console.error("failed to load the public channels", err)
23
+ setCurrentChannels([])
24
+ } finally {
25
+ setLoaded(true)
 
 
 
 
 
 
 
26
  }
27
+ })
28
+ }
29
+ }, [isLoaded])
 
30
 
31
  return (
32
  <div className={cn(
33
  `flex flex-col`
34
  )}>
35
+ <ChannelList
36
+ channels={currentChannels}
37
  />
38
  </div>
39
  )
src/app/views/home-view/index.tsx CHANGED
@@ -32,10 +32,11 @@ export function HomeView() {
32
  channelId: "",
33
  channel: {
34
  id: "",
 
35
  label: "Hugging Face",
36
- thumbnailUrl: "",
37
- systemPrompt: "",
38
- hfDatasetId: ""
39
  }
40
  }
41
  ]
 
32
  channelId: "",
33
  channel: {
34
  id: "",
35
+ slug: "",
36
  label: "Hugging Face",
37
+ thumbnail: "",
38
+ prompt: "",
39
+ likes: 0,
40
  }
41
  }
42
  ]
src/huggingface/hub/src/lib/list-datasets.ts CHANGED
@@ -20,7 +20,7 @@ export interface DatasetEntry {
20
  export async function* listDatasets(params?: {
21
  search?: {
22
  owner?: string;
23
- };
24
  credentials?: Credentials;
25
  hubUrl?: string;
26
  /**
@@ -32,7 +32,10 @@ export async function* listDatasets(params?: {
32
  const search = new URLSearchParams([
33
  ...Object.entries({
34
  limit: "500",
35
- ...(params?.search?.owner ? { author: params.search.owner } : undefined),
 
 
 
36
  }),
37
  ...EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
38
  ]).toString();
 
20
  export async function* listDatasets(params?: {
21
  search?: {
22
  owner?: string;
23
+ } | string;
24
  credentials?: Credentials;
25
  hubUrl?: string;
26
  /**
 
32
  const search = new URLSearchParams([
33
  ...Object.entries({
34
  limit: "500",
35
+ ...(
36
+ typeof params?.search === "string" ? { search: params?.search }
37
+ : params?.search?.owner ? { author: params.search.owner }
38
+ : undefined),
39
  }),
40
  ...EXPAND_KEYS.map((val) => ["expand", val] satisfies [string, string]),
41
  ]).toString();
src/types.ts CHANGED
@@ -219,4 +219,8 @@ export type InterfaceView =
219
  | "channels_public"
220
  | "channel_admin" // for a user to admin their channels
221
  | "channel_public" // public view of a channel
222
- | "video_public" // public view of a video
 
 
 
 
 
219
  | "channels_public"
220
  | "channel_admin" // for a user to admin their channels
221
  | "channel_public" // public view of a channel
222
+ | "video_public" // public view of a video
223
+
224
+ export type Settings = {
225
+ huggingfaceApiKey: string
226
+ }