Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
machineuser
commited on
Commit
·
388ac76
1
Parent(s):
767bfd8
Sync widgets demo
Browse files
packages/widgets/README.md
CHANGED
@@ -6,13 +6,26 @@ Open-source version of the inference widgets from huggingface.co
|
|
6 |
|
7 |
**Demo page:** https://huggingface.co/spaces/huggingfacejs/inference-widgets
|
8 |
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
```console
|
12 |
pnpm install
|
13 |
pnpm dev
|
14 |
```
|
15 |
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
-
|
|
|
6 |
|
7 |
**Demo page:** https://huggingface.co/spaces/huggingfacejs/inference-widgets
|
8 |
|
9 |
+
## Publishing
|
10 |
+
|
11 |
+
Because `@huggingface/widgets` depends on `@huggingface/tasks`, you need to publish `@huggingface/tasks` first, and then `@huggingface/widgets`. There should be a CI check to prevent publishing `@huggingface/widgets` if `@huggingface/tasks` hasn't been published yet.
|
12 |
+
|
13 |
+
## Demo
|
14 |
+
|
15 |
+
You can run the demo locally:
|
16 |
|
17 |
```console
|
18 |
pnpm install
|
19 |
pnpm dev
|
20 |
```
|
21 |
|
22 |
+
If you want to try the "Sign-in with HF" feature locally, you will need to https://huggingface.co/settings/applications/new an OAuth application with `"openid"` and `"inference-api"` scopes and `http://localhost:5173/auth/callback/huggingface` as the redirect URL.
|
23 |
+
|
24 |
+
Then you can create a `.env.local` file with the following content:
|
25 |
+
|
26 |
+
```env
|
27 |
+
OAUTH_CLIENT_ID=...
|
28 |
+
OAUTH_CLIENT_SECRET=...
|
29 |
+
```
|
30 |
|
31 |
+
If you want to try the "Sign-in with HF" feature in a Space, you can just duplicate https://huggingface.co/spaces/huggingfacejs/inference-widgets, it should work out of the box thanks to the metadata in the `README.md` file.
|
packages/widgets/package.json
CHANGED
@@ -38,6 +38,8 @@
|
|
38 |
"svelte": "^3.59.2"
|
39 |
},
|
40 |
"devDependencies": {
|
|
|
|
|
41 |
"@fontsource/ibm-plex-mono": "^5.0.8",
|
42 |
"@fontsource/source-sans-pro": "^5.0.8",
|
43 |
"@sveltejs/adapter-node": "^1.3.1",
|
|
|
38 |
"svelte": "^3.59.2"
|
39 |
},
|
40 |
"devDependencies": {
|
41 |
+
"@auth/core": "^0.18.3",
|
42 |
+
"@auth/sveltekit": "^0.3.14",
|
43 |
"@fontsource/ibm-plex-mono": "^5.0.8",
|
44 |
"@fontsource/source-sans-pro": "^5.0.8",
|
45 |
"@sveltejs/adapter-node": "^1.3.1",
|
packages/widgets/pnpm-lock.yaml
CHANGED
@@ -10,6 +10,12 @@ dependencies:
|
|
10 |
version: link:../tasks
|
11 |
|
12 |
devDependencies:
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
'@fontsource/ibm-plex-mono':
|
14 |
specifier: ^5.0.8
|
15 |
version: 5.0.8
|
@@ -68,6 +74,35 @@ packages:
|
|
68 |
engines: {node: '>=10'}
|
69 |
dev: true
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
/@esbuild/[email protected]:
|
72 |
resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
|
73 |
engines: {node: '>=12'}
|
@@ -367,6 +402,10 @@ packages:
|
|
367 |
fastq: 1.15.0
|
368 |
dev: true
|
369 |
|
|
|
|
|
|
|
|
|
370 |
/@polka/[email protected]:
|
371 |
resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==}
|
372 |
dev: true
|
@@ -1230,6 +1269,10 @@ packages:
|
|
1230 |
hasBin: true
|
1231 |
dev: true
|
1232 |
|
|
|
|
|
|
|
|
|
1233 | |
1234 |
resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==}
|
1235 |
dev: true
|
@@ -1440,6 +1483,10 @@ packages:
|
|
1440 |
npm-normalize-package-bin: 2.0.0
|
1441 |
dev: true
|
1442 |
|
|
|
|
|
|
|
|
|
1443 | |
1444 |
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
1445 |
engines: {node: '>=0.10.0'}
|
@@ -1604,11 +1651,28 @@ packages:
|
|
1604 |
source-map-js: 1.0.2
|
1605 |
dev: true
|
1606 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1607 | |
1608 |
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
1609 |
engines: {node: '>= 0.8.0'}
|
1610 |
dev: true
|
1611 |
|
|
|
|
|
|
|
|
|
1612 | |
1613 |
resolution: {integrity: sha512-O53y7vbePxuGFmEjgcrafMSlDpOJwOkj8YdexOt7yWlv7SB3rXoT3mHknyMJ3lf2UFH5Bmt6tnIkHcOTR6dEoA==}
|
1614 |
engines: {node: '>=16'}
|
|
|
10 |
version: link:../tasks
|
11 |
|
12 |
devDependencies:
|
13 |
+
'@auth/core':
|
14 |
+
specifier: ^0.18.3
|
15 |
+
version: 0.18.3
|
16 |
+
'@auth/sveltekit':
|
17 |
+
specifier: ^0.3.14
|
18 |
+
version: 0.3.14(@sveltejs/[email protected])([email protected])
|
19 |
'@fontsource/ibm-plex-mono':
|
20 |
specifier: ^5.0.8
|
21 |
version: 5.0.8
|
|
|
74 |
engines: {node: '>=10'}
|
75 |
dev: true
|
76 |
|
77 |
+
/@auth/[email protected]:
|
78 |
+
resolution: {integrity: sha512-YXQWxi3pKxngt+2vo3dq8+wDANlUH8nhQgX6EVdd3Enfe3vweBtHqzaWrtWzQnVb8wdGxdhxaoOlYroEBE+/yw==}
|
79 |
+
peerDependencies:
|
80 |
+
nodemailer: ^6.8.0
|
81 |
+
peerDependenciesMeta:
|
82 |
+
nodemailer:
|
83 |
+
optional: true
|
84 |
+
dependencies:
|
85 |
+
'@panva/hkdf': 1.1.1
|
86 |
+
cookie: 0.5.0
|
87 |
+
jose: 5.1.2
|
88 |
+
oauth4webapi: 2.4.0
|
89 |
+
preact: 10.11.3
|
90 |
+
preact-render-to-string: 5.2.3([email protected])
|
91 |
+
dev: true
|
92 |
+
|
93 |
+
/@auth/[email protected](@sveltejs/[email protected])([email protected]):
|
94 |
+
resolution: {integrity: sha512-Ealyi4uM4V42tk4UhhRQ+iZKah0OOp12siXwgDsCj1uBOCeZwL97RkvdMDX7pg18zBP/h2qFAuMWjW5q7bSYxA==}
|
95 |
+
peerDependencies:
|
96 |
+
'@sveltejs/kit': ^1.0.0
|
97 |
+
svelte: ^3.54.0 || ^4.0.0
|
98 |
+
dependencies:
|
99 |
+
'@auth/core': 0.18.3
|
100 |
+
'@sveltejs/kit': 1.27.4([email protected])([email protected])
|
101 |
+
svelte: 3.59.2
|
102 |
+
transitivePeerDependencies:
|
103 |
+
- nodemailer
|
104 |
+
dev: true
|
105 |
+
|
106 |
/@esbuild/[email protected]:
|
107 |
resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
|
108 |
engines: {node: '>=12'}
|
|
|
402 |
fastq: 1.15.0
|
403 |
dev: true
|
404 |
|
405 |
+
/@panva/[email protected]:
|
406 |
+
resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==}
|
407 |
+
dev: true
|
408 |
+
|
409 |
/@polka/[email protected]:
|
410 |
resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==}
|
411 |
dev: true
|
|
|
1269 |
hasBin: true
|
1270 |
dev: true
|
1271 |
|
1272 | |
1273 |
+
resolution: {integrity: sha512-X7TOC/d8KPvx4wPUuLHVgTSdoWw0UW5TQOUwhvCvj+ZPfsf9vUPhhksYPjNBWVGPQ/6yd/JrL1gQxBnIDwYdFg==}
|
1274 |
+
dev: true
|
1275 |
+
|
1276 | |
1277 |
resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==}
|
1278 |
dev: true
|
|
|
1483 |
npm-normalize-package-bin: 2.0.0
|
1484 |
dev: true
|
1485 |
|
1486 | |
1487 |
+
resolution: {integrity: sha512-ZWl8ov8HeGVyc9Icl1cag76HvIcDAp23eIIT+UVGir+dEu8BMgMlvZeZwqLVd0P8DqaumH4N+QLQXN69G1QjSA==}
|
1488 |
+
dev: true
|
1489 |
+
|
1490 | |
1491 |
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
1492 |
engines: {node: '>=0.10.0'}
|
|
|
1651 |
source-map-js: 1.0.2
|
1652 |
dev: true
|
1653 |
|
1654 | |
1655 |
+
resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==}
|
1656 |
+
peerDependencies:
|
1657 |
+
preact: '>=10'
|
1658 |
+
dependencies:
|
1659 |
+
preact: 10.11.3
|
1660 |
+
pretty-format: 3.8.0
|
1661 |
+
dev: true
|
1662 |
+
|
1663 | |
1664 |
+
resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==}
|
1665 |
+
dev: true
|
1666 |
+
|
1667 | |
1668 |
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
1669 |
engines: {node: '>= 0.8.0'}
|
1670 |
dev: true
|
1671 |
|
1672 | |
1673 |
+
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
|
1674 |
+
dev: true
|
1675 |
+
|
1676 | |
1677 |
resolution: {integrity: sha512-O53y7vbePxuGFmEjgcrafMSlDpOJwOkj8YdexOt7yWlv7SB3rXoT3mHknyMJ3lf2UFH5Bmt6tnIkHcOTR6dEoA==}
|
1678 |
engines: {node: '>=16'}
|
packages/widgets/src/app.d.ts
CHANGED
@@ -7,6 +7,16 @@ declare global {
|
|
7 |
// interface PageData {}
|
8 |
// interface Platform {}
|
9 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
}
|
11 |
|
12 |
export {};
|
|
|
7 |
// interface PageData {}
|
8 |
// interface Platform {}
|
9 |
}
|
10 |
+
|
11 |
+
export interface Session {
|
12 |
+
access_token?: string;
|
13 |
+
}
|
14 |
+
}
|
15 |
+
|
16 |
+
declare module "@auth/core/types" {
|
17 |
+
export interface Session {
|
18 |
+
access_token?: string;
|
19 |
+
}
|
20 |
}
|
21 |
|
22 |
export {};
|
packages/widgets/src/hooks.server.ts
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { env } from "$env/dynamic/private";
|
2 |
+
import { skipCSRFCheck } from "@auth/core";
|
3 |
+
import { SvelteKitAuth } from "@auth/sveltekit";
|
4 |
+
import type { Handle } from "@sveltejs/kit";
|
5 |
+
import { sequence } from "@sveltejs/kit/hooks";
|
6 |
+
|
7 |
+
const handleSSO =
|
8 |
+
env.OAUTH_CLIENT_ID && env.OAUTH_CLIENT_SECRET
|
9 |
+
? SvelteKitAuth({
|
10 |
+
// Should be fine as long as your reverse proxy is configured to only accept traffic with the correct host header
|
11 |
+
trustHost: true,
|
12 |
+
/**
|
13 |
+
* SvelteKit has built-in CSRF protection, so we can skip the check
|
14 |
+
*/
|
15 |
+
skipCSRFCheck: skipCSRFCheck,
|
16 |
+
providers: [
|
17 |
+
{
|
18 |
+
name: "Hugging Face",
|
19 |
+
id: "huggingface",
|
20 |
+
type: "oidc",
|
21 |
+
clientId: env.OAUTH_CLIENT_ID,
|
22 |
+
clientSecret: env.OAUTH_CLIENT_SECRET,
|
23 |
+
issuer: "https://huggingface.co",
|
24 |
+
wellKnown: "https://huggingface.co/.well-known/openid-configuration",
|
25 |
+
/** Add "inference-api" scope and remove "email" scope */
|
26 |
+
authorization: { params: { scope: "openid profile inference-api" } },
|
27 |
+
checks: ["state" as never, "pkce" as never],
|
28 |
+
},
|
29 |
+
],
|
30 |
+
secret: env.OAUTH_CLIENT_SECRET,
|
31 |
+
/**
|
32 |
+
* Get the access_token without an account in DB, to make calls to the inference API
|
33 |
+
*/
|
34 |
+
callbacks: {
|
35 |
+
async jwt({ token, account }) {
|
36 |
+
if (account) {
|
37 |
+
return {
|
38 |
+
...token,
|
39 |
+
access_token: account.access_token,
|
40 |
+
};
|
41 |
+
}
|
42 |
+
return token;
|
43 |
+
},
|
44 |
+
async session({ session, token }) {
|
45 |
+
return {
|
46 |
+
...session,
|
47 |
+
access_token: token.access_token,
|
48 |
+
};
|
49 |
+
},
|
50 |
+
},
|
51 |
+
})
|
52 |
+
: null;
|
53 |
+
|
54 |
+
const handleGlobal: Handle = async ({ event, resolve }) => {
|
55 |
+
const response = await resolve(event);
|
56 |
+
return response;
|
57 |
+
};
|
58 |
+
|
59 |
+
export const handle = handleSSO ? sequence(handleSSO, handleGlobal) : handleGlobal;
|
packages/widgets/src/routes/+layout.server.ts
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { env } from "$env/dynamic/private";
|
2 |
+
import type { LayoutServerLoad } from "./$types.js";
|
3 |
+
|
4 |
+
export const load: LayoutServerLoad = async ({ locals }) => {
|
5 |
+
const session = await locals.getSession();
|
6 |
+
|
7 |
+
return {
|
8 |
+
access_token: session?.access_token,
|
9 |
+
supportsOAuth: !!env.OAUTH_CLIENT_ID && !!env.OAUTH_CLIENT_SECRET,
|
10 |
+
};
|
11 |
+
};
|
packages/widgets/src/routes/+page.svelte
CHANGED
@@ -5,17 +5,27 @@
|
|
5 |
import InferenceWidget from "$lib/components/InferenceWidget/InferenceWidget.svelte";
|
6 |
import ModeSwitcher from "$lib/components/DemoThemeSwitcher/DemoThemeSwitcher.svelte";
|
7 |
import { onMount } from "svelte";
|
|
|
8 |
|
9 |
-
let
|
|
|
10 |
|
11 |
function storeHFToken() {
|
12 |
window.localStorage.setItem("hf_token", apiToken);
|
13 |
}
|
14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
onMount(() => {
|
16 |
-
|
17 |
-
|
18 |
-
|
|
|
|
|
19 |
}
|
20 |
});
|
21 |
|
@@ -526,10 +536,24 @@
|
|
526 |
<div class="flex flex-col gap-6 py-12 px-4">
|
527 |
<ModeSwitcher />
|
528 |
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
533 |
|
534 |
<div>
|
535 |
<h1 class="mb-8 text-4xl font-semibold">Showcase of all types of inference widgets running</h1>
|
|
|
5 |
import InferenceWidget from "$lib/components/InferenceWidget/InferenceWidget.svelte";
|
6 |
import ModeSwitcher from "$lib/components/DemoThemeSwitcher/DemoThemeSwitcher.svelte";
|
7 |
import { onMount } from "svelte";
|
8 |
+
import { browser } from "$app/environment";
|
9 |
|
10 |
+
export let data;
|
11 |
+
let apiToken = data.access_token || "";
|
12 |
|
13 |
function storeHFToken() {
|
14 |
window.localStorage.setItem("hf_token", apiToken);
|
15 |
}
|
16 |
|
17 |
+
/**
|
18 |
+
* If we are in an iframe, we need to open the auth page in a new tab
|
19 |
+
* to avoid issues with third-party cookies in a space
|
20 |
+
*/
|
21 |
+
const isIframe = browser && window.self !== window.parent;
|
22 |
+
|
23 |
onMount(() => {
|
24 |
+
if (!data.supportsOAuth) {
|
25 |
+
const token = window.localStorage.getItem("hf_token");
|
26 |
+
if (token) {
|
27 |
+
apiToken = token;
|
28 |
+
}
|
29 |
}
|
30 |
});
|
31 |
|
|
|
536 |
<div class="flex flex-col gap-6 py-12 px-4">
|
537 |
<ModeSwitcher />
|
538 |
|
539 |
+
{#if data.supportsOAuth}
|
540 |
+
{#if !data.access_token}
|
541 |
+
<form class="contents" method="post" action="/auth/signin/huggingface" target={isIframe ? "_blank" : ""}>
|
542 |
+
<button type="submit" title="Sign in with Hugging Face">
|
543 |
+
<img
|
544 |
+
src="https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-xl-dark.svg"
|
545 |
+
alt="Sign in with Hugging Face"
|
546 |
+
class="h-12 w-auto"
|
547 |
+
/>
|
548 |
+
</button>
|
549 |
+
</form>
|
550 |
+
{/if}
|
551 |
+
{:else}
|
552 |
+
<label>
|
553 |
+
<div class="text-xl font-semibold">First, Enter HF token</div>
|
554 |
+
<input class="form-input" type="text" bind:value={apiToken} placeholder="hf_..." on:change={storeHFToken} />
|
555 |
+
</label>
|
556 |
+
{/if}
|
557 |
|
558 |
<div>
|
559 |
<h1 class="mb-8 text-4xl font-semibold">Showcase of all types of inference widgets running</h1>
|