|
<script lang="ts"> |
|
import { onMount } from 'svelte'; |
|
import { authStore } from './lib/stores/auth'; |
|
import SignInButton from './lib/components/Auth/SignInButton.svelte'; |
|
import AuthBanner from './lib/components/Auth/AuthBanner.svelte'; |
|
import FluxGenerator from './lib/components/ImageGeneration/FluxGenerator.svelte'; |
|
import JoyCaption from './lib/components/ImageCaption/JoyCaption.svelte'; |
|
import RWKVGenerator from './lib/components/TextGeneration/RWKVGenerator.svelte'; |
|
import type { HuggingFaceLibs, GradioLibs, GradioClient, FluxGenerationResult } from './lib/types'; |
|
|
|
|
|
let hfAuth: HuggingFaceLibs | null = $state(null); |
|
let gradioClient: GradioLibs | null = $state(null); |
|
|
|
|
|
let fluxClient: GradioClient | null = $state(null); |
|
let joyCaptionClient: GradioClient | null = $state(null); |
|
let rwkvClient: GradioClient | null = $state(null); |
|
|
|
|
|
let currentImageBlob: Blob | null = $state(null); |
|
|
|
|
|
const auth = $derived(authStore); |
|
|
|
onMount(async () => { |
|
|
|
const script1 = document.createElement('script'); |
|
script1.type = 'module'; |
|
script1.textContent = ` |
|
import { |
|
oauthLoginUrl, |
|
oauthHandleRedirectIfPresent |
|
} from "https://cdn.jsdelivr.net/npm/@huggingface/[email protected]/+esm"; |
|
import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"; |
|
|
|
window.hfAuth = { oauthLoginUrl, oauthHandleRedirectIfPresent }; |
|
window.gradioClient = { Client }; |
|
`; |
|
document.head.appendChild(script1); |
|
|
|
|
|
await new Promise(resolve => { |
|
const checkLibs = setInterval(() => { |
|
if (window.hfAuth && window.gradioClient) { |
|
clearInterval(checkLibs); |
|
resolve(undefined); |
|
} |
|
}, 100); |
|
}); |
|
|
|
hfAuth = window.hfAuth as HuggingFaceLibs; |
|
gradioClient = window.gradioClient as GradioLibs; |
|
|
|
|
|
try { |
|
const session = await hfAuth.oauthHandleRedirectIfPresent(); |
|
authStore.setSession(session); |
|
|
|
|
|
await initializeClients(session?.accessToken || null); |
|
} catch (err) { |
|
console.error("OAuth handling error:", err); |
|
authStore.setSession(null); |
|
await initializeClients(null); |
|
} |
|
}); |
|
|
|
async function initializeClients(hfToken: string | null) { |
|
if (!gradioClient) return; |
|
|
|
authStore.setBannerMessage("Connecting to FLUX.1-schnell, Joy Caption, and RWKV…"); |
|
|
|
try { |
|
const opts = hfToken ? { hf_token: hfToken } : {}; |
|
|
|
|
|
fluxClient = await gradioClient.Client.connect( |
|
"black-forest-labs/FLUX.1-schnell", |
|
opts |
|
); |
|
|
|
joyCaptionClient = await gradioClient.Client.connect( |
|
"fancyfeast/joy-caption-alpha-two", |
|
opts |
|
); |
|
|
|
rwkvClient = await gradioClient.Client.connect( |
|
"BlinkDL/RWKV-Gradio-2", |
|
opts |
|
); |
|
|
|
authStore.setBannerMessage(""); |
|
} catch (err) { |
|
console.error(err); |
|
authStore.setBannerMessage(`❌ Failed to connect: ${err}`); |
|
} |
|
} |
|
|
|
function handleImageGenerated(result: FluxGenerationResult, imageBlob: Blob) { |
|
currentImageBlob = imageBlob; |
|
} |
|
</script> |
|
|
|
<div class="app"> |
|
<div class="card"> |
|
<h1>FLUX-1 Schnell + Joy Caption + RWKV Space</h1> |
|
<p> |
|
This Svelte-powered Space demonstrates how to call remote Gradio Spaces while |
|
letting <strong>each visitor's own Hugging Face subscription</strong> cover |
|
the compute costs. Generate images with FLUX-1, caption them with Joy Caption, and generate text with RWKV. |
|
</p> |
|
|
|
{#if $auth.showSignIn} |
|
<SignInButton {hfAuth} /> |
|
{/if} |
|
|
|
<AuthBanner |
|
message={$auth.bannerMessage} |
|
visible={!!$auth.bannerMessage} |
|
/> |
|
|
|
{#if $auth.userInfo} |
|
<p>Hello, {$auth.userInfo.name || $auth.userInfo.preferred_username}!</p> |
|
{/if} |
|
|
|
{#if fluxClient} |
|
<FluxGenerator |
|
client={fluxClient} |
|
onImageGenerated={handleImageGenerated} |
|
/> |
|
{/if} |
|
|
|
{#if joyCaptionClient} |
|
<JoyCaption |
|
client={joyCaptionClient} |
|
currentImage={currentImageBlob} |
|
/> |
|
{/if} |
|
|
|
{#if rwkvClient} |
|
<RWKVGenerator client={rwkvClient} /> |
|
{/if} |
|
|
|
<hr /> |
|
<p class="footer"> |
|
Source & docs: |
|
<a href="https://huggingface.co/docs/hub/spaces-oauth" target="_blank">Spaces OAuth</a>, |
|
<a href="https://github.com/huggingface/huggingface.js" target="_blank">huggingface.js</a>, |
|
<a href="https://js.gradio.app" target="_blank">@gradio/client</a> |
|
</p> |
|
</div> |
|
</div> |
|
|
|
<style> |
|
.app { |
|
min-height: 100vh; |
|
background: #f5f5f5; |
|
padding: 2rem; |
|
} |
|
|
|
.card { |
|
max-width: 900px; |
|
margin: 0 auto; |
|
background: #ffffff; |
|
padding: 2rem; |
|
border-radius: 10px; |
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); |
|
} |
|
|
|
h1 { |
|
margin-top: 0; |
|
} |
|
|
|
hr { |
|
margin: 3rem 0 2rem; |
|
border: none; |
|
border-top: 1px solid #eee; |
|
} |
|
|
|
.footer { |
|
color: #666; |
|
font-size: 0.9rem; |
|
} |
|
|
|
.footer a { |
|
color: #007bff; |
|
text-decoration: none; |
|
} |
|
|
|
.footer a:hover { |
|
text-decoration: underline; |
|
} |
|
</style> |