enzostvs HF Staff commited on
Commit
b709981
·
1 Parent(s): 7ad6fe3

load providers dynamically

Browse files
app/api/ask/route.ts CHANGED
@@ -24,7 +24,7 @@ import { Page } from "@/types";
24
  import { createRepo, RepoDesignation, uploadFiles } from "@huggingface/hub";
25
  import { isAuthenticated } from "@/lib/auth";
26
  import { getBestProvider } from "@/lib/best-provider";
27
- import { rewritePrompt } from "@/lib/rewrite-prompt";
28
  import { COLORS } from "@/lib/utils";
29
  import { templates } from "@/lib/templates";
30
 
 
24
  import { createRepo, RepoDesignation, uploadFiles } from "@huggingface/hub";
25
  import { isAuthenticated } from "@/lib/auth";
26
  import { getBestProvider } from "@/lib/best-provider";
27
+ // import { rewritePrompt } from "@/lib/rewrite-prompt";
28
  import { COLORS } from "@/lib/utils";
29
  import { templates } from "@/lib/templates";
30
 
components/editor/ask-ai/settings.tsx CHANGED
@@ -20,8 +20,10 @@ import {
20
  import { useMemo, useState, useEffect } from "react";
21
  import { useUpdateEffect } from "react-use";
22
  import Image from "next/image";
23
- import { Brain, CheckCheck, ChevronDown } from "lucide-react";
24
  import { useAi } from "@/hooks/useAi";
 
 
25
 
26
  export function Settings({
27
  open,
@@ -43,26 +45,24 @@ export function Settings({
43
  globalAiLoading,
44
  } = useAi();
45
  const [isMounted, setIsMounted] = useState(false);
 
46
 
47
  useEffect(() => {
48
  setIsMounted(true);
49
  }, []);
50
 
51
- const modelAvailableProviders = useMemo(() => {
52
- const availableProviders = MODELS.find(
53
- (m: { value: string }) => m.value === model
54
- )?.providers;
55
- if (!availableProviders) return Object.keys(PROVIDERS);
56
- return Object.keys(PROVIDERS).filter((id) =>
57
- availableProviders.includes(id)
58
- );
59
- }, [model]);
60
 
61
  useUpdateEffect(() => {
62
- if (
63
- provider !== "auto" &&
64
- !modelAvailableProviders.includes(provider as string)
65
- ) {
66
  setProvider("auto");
67
  }
68
  }, [model, provider]);
@@ -85,13 +85,41 @@ export function Settings({
85
  return lists;
86
  }, [MODELS]);
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  return (
89
  <Popover open={open} onOpenChange={onClose}>
90
  <PopoverTrigger asChild>
91
  <Button
92
  variant={open ? "default" : "outline"}
93
  className="!rounded-md"
94
- disabled={globalAiLoading}
95
  size="xs"
96
  >
97
  {/* <Brain className="size-3.5" /> */}
@@ -219,29 +247,38 @@ export function Settings({
219
  <p className="text-neutral-300 text-sm mb-2">
220
  Inference Provider
221
  </p>
222
- <div className="grid grid-cols-2 gap-1.5">
223
- {modelAvailableProviders.map((id: string) => (
224
- <Button
225
- key={id}
226
- variant={id === provider ? "default" : "secondary"}
227
- size="sm"
228
- onClick={() => {
229
- setProvider(id);
230
- }}
231
- >
232
- <Image
233
- src={`/providers/${id}.svg`}
234
- alt={PROVIDERS[id as keyof typeof PROVIDERS].name}
235
- className="size-5 mr-2"
236
- width={20}
237
- height={20}
238
- />
239
- {PROVIDERS[id as keyof typeof PROVIDERS].name}
240
- {id === provider && (
241
- <CheckCheck className="ml-2 size-4 text-blue-500" />
242
- )}
243
- </Button>
244
- ))}
 
 
 
 
 
 
 
 
 
245
  </div>
246
  </label>
247
  </div>
 
20
  import { useMemo, useState, useEffect } from "react";
21
  import { useUpdateEffect } from "react-use";
22
  import Image from "next/image";
23
+ import { Brain, BrainIcon, CheckCheck, ChevronDown } from "lucide-react";
24
  import { useAi } from "@/hooks/useAi";
25
+ import { getProviders } from "@/lib/get-providers";
26
+ import Loading from "@/components/loading";
27
 
28
  export function Settings({
29
  open,
 
45
  globalAiLoading,
46
  } = useAi();
47
  const [isMounted, setIsMounted] = useState(false);
48
+ const [loadingProviders, setLoadingProviders] = useState(false);
49
 
50
  useEffect(() => {
51
  setIsMounted(true);
52
  }, []);
53
 
54
+ // const modelAvailableProviders = useMemo(() => {
55
+ // const availableProviders = MODELS.find(
56
+ // (m: { value: string }) => m.value === model
57
+ // )?.providers;
58
+ // if (!availableProviders) return Object.keys(PROVIDERS);
59
+ // return Object.keys(PROVIDERS).filter((id) =>
60
+ // availableProviders.includes(id)
61
+ // );
62
+ // }, [model]);
63
 
64
  useUpdateEffect(() => {
65
+ if (provider !== "auto" && !providers.includes(provider as string)) {
 
 
 
66
  setProvider("auto");
67
  }
68
  }, [model, provider]);
 
85
  return lists;
86
  }, [MODELS]);
87
 
88
+ const [providers, setProviders] = useState<any[]>([]);
89
+ const [failedImages, setFailedImages] = useState<Set<string>>(new Set());
90
+
91
+ useEffect(() => {
92
+ const loadProviders = async () => {
93
+ setLoadingProviders(true);
94
+ if (!model) {
95
+ setProviders([]);
96
+ return;
97
+ }
98
+ try {
99
+ const result = await getProviders(model);
100
+ setProviders(result);
101
+ } catch (error) {
102
+ console.error("Failed to load providers:", error);
103
+ setProviders([]);
104
+ } finally {
105
+ setLoadingProviders(false);
106
+ }
107
+ };
108
+
109
+ loadProviders();
110
+ }, [model]);
111
+
112
+ const handleImageError = (providerId: string) => {
113
+ setFailedImages((prev) => new Set([...prev, providerId]));
114
+ };
115
+
116
  return (
117
  <Popover open={open} onOpenChange={onClose}>
118
  <PopoverTrigger asChild>
119
  <Button
120
  variant={open ? "default" : "outline"}
121
  className="!rounded-md"
122
+ disabled={globalAiLoading || loadingProviders}
123
  size="xs"
124
  >
125
  {/* <Brain className="size-3.5" /> */}
 
247
  <p className="text-neutral-300 text-sm mb-2">
248
  Inference Provider
249
  </p>
250
+ <div className="grid grid-cols-2 gap-1.5 relative">
251
+ {loadingProviders ? (
252
+ <Loading overlay={false} />
253
+ ) : (
254
+ providers.map((id: string) => (
255
+ <Button
256
+ key={id}
257
+ variant={id === provider ? "default" : "secondary"}
258
+ size="sm"
259
+ onClick={() => {
260
+ setProvider(id);
261
+ }}
262
+ >
263
+ {failedImages.has(id) ? (
264
+ <BrainIcon className="size-4 mr-2" />
265
+ ) : (
266
+ <Image
267
+ src={`/providers/${id}.svg`}
268
+ alt={id}
269
+ className="size-5 mr-2"
270
+ width={20}
271
+ height={20}
272
+ onError={() => handleImageError(id)}
273
+ />
274
+ )}
275
+ {PROVIDERS?.[id as keyof typeof PROVIDERS]?.name || id}
276
+ {id === provider && (
277
+ <CheckCheck className="ml-2 size-4 text-blue-500" />
278
+ )}
279
+ </Button>
280
+ ))
281
+ )}
282
  </div>
283
  </label>
284
  </div>
components/my-projects/project-card.tsx CHANGED
@@ -71,7 +71,7 @@ export function ProjectCard({
71
  "/",
72
  "-"
73
  )}.static.hf.space`}
74
- className="w-[1200px] h-[675px] border-0 origin-top-left"
75
  style={{
76
  transform: "scale(0.5)",
77
  transformOrigin: "top left",
 
71
  "/",
72
  "-"
73
  )}.static.hf.space`}
74
+ className="w-[1200px] h-[675px] border-0 origin-top-left pointer-events-none"
75
  style={{
76
  transform: "scale(0.5)",
77
  transformOrigin: "top left",
lib/best-provider.ts CHANGED
@@ -18,6 +18,5 @@ export const getBestProvider = async (model: string, provider?: string) => {
18
  }
19
  }
20
 
21
-
22
  return bestProvider
23
  }
 
18
  }
19
  }
20
 
 
21
  return bestProvider
22
  }
lib/get-providers.ts ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ export const getProviders = async (model: string) => {
2
+ const response = await fetch(`https://router.huggingface.co/v1/models/${model}`)
3
+ const { data } = await response.json()
4
+ return data.providers.map((provider: any) => provider.provider)
5
+ }