piclets / src /App.svelte
Fraser's picture
closer
415a17d
raw
history blame
5.33 kB
<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 MonsterGenerator from './lib/components/MonsterGenerator/MonsterGenerator.svelte';
import type { HuggingFaceLibs, GradioLibs, GradioClient, FluxGenerationResult } from './lib/types';
// These will be loaded from window after HF libs are loaded
let hfAuth: HuggingFaceLibs | null = $state(null);
let gradioClient: GradioLibs | null = $state(null);
// Gradio client instances
let fluxClient: GradioClient | null = $state(null);
let joyCaptionClient: GradioClient | null = $state(null);
let rwkvClient: GradioClient | null = $state(null);
// Auth state from store
const auth = $derived(authStore);
onMount(async () => {
// Load HF libraries
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);
// Wait for libraries to load
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;
// Handle OAuth redirect
try {
const session = await hfAuth.oauthHandleRedirectIfPresent();
authStore.setSession(session);
// Start the app
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 } : {};
// Connect to all three spaces
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}`);
}
}
</script>
<div class="app">
<div class="card">
<h1>👾 Monster Generator</h1>
<p>
Transform your photos into unique monster creations using AI
</p>
{#if $auth.showSignIn}
<SignInButton {hfAuth} />
{/if}
<AuthBanner
message={$auth.bannerMessage}
visible={!!$auth.bannerMessage}
/>
{#if $auth.userInfo}
<p class="user-greeting">Hello, {$auth.userInfo.name || $auth.userInfo.preferred_username}!</p>
{/if}
<!-- Monster Generator Content -->
{#if fluxClient && joyCaptionClient && rwkvClient}
<MonsterGenerator
{fluxClient}
{joyCaptionClient}
{rwkvClient}
/>
{:else}
<div class="loading-message">
<div class="spinner"></div>
<p>Connecting to AI services...</p>
</div>
{/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;
}
.user-greeting {
text-align: center;
color: #666;
margin-bottom: 2rem;
}
.loading-message {
text-align: center;
padding: 3rem;
color: #666;
}
.spinner {
width: 60px;
height: 60px;
border: 3px solid #f3f3f3;
border-top: 3px solid #007bff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 2rem;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>