Spaces:
Running
Running
store generation + add loading
Browse files
src/lib/components/generate/Response.svelte
CHANGED
|
@@ -1,16 +1,20 @@
|
|
| 1 |
<script lang="ts">
|
| 2 |
-
|
|
|
|
| 3 |
|
| 4 |
-
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
let loading: boolean = false;
|
| 8 |
let already_saved: boolean = false;
|
| 9 |
|
| 10 |
const saveImage = () => {
|
| 11 |
const link = document.createElement('a');
|
| 12 |
-
link.href =
|
| 13 |
-
link.download = `${form?.inputs?.slice(0, 20)}.png`;
|
| 14 |
document.body.appendChild(link);
|
| 15 |
link.click();
|
| 16 |
document.body.removeChild(link);
|
|
@@ -24,70 +28,113 @@
|
|
| 24 |
headers: {
|
| 25 |
"Content-Type": "application/json"
|
| 26 |
},
|
| 27 |
-
body: JSON.stringify({ image:
|
| 28 |
}).then(() => {
|
| 29 |
loading = false;
|
| 30 |
already_saved = true;
|
| 31 |
})
|
| 32 |
}
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
</script>
|
| 35 |
|
| 36 |
-
<div class="w-full border-t xl:border-t-0 xl:border-l border-neutral-800 h-full col-span-5 xl:col-span-2" class:!border-black={!
|
| 37 |
-
{#if
|
| 38 |
-
|
| 39 |
-
<
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
>
|
| 52 |
-
{
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
</div>
|
| 76 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
</div>
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
{/if}
|
| 86 |
-
</div>
|
| 87 |
-
{:else}
|
| 88 |
-
<div>
|
| 89 |
-
error displayed.
|
| 90 |
-
</div>
|
| 91 |
{/if}
|
| 92 |
{/if}
|
| 93 |
</div>
|
|
|
|
| 1 |
<script lang="ts">
|
| 2 |
+
import { get } from "svelte/store";
|
| 3 |
+
import { generationStore } from "$lib/stores/use-generation";
|
| 4 |
|
| 5 |
+
import Button from "$lib/components/Button.svelte";
|
| 6 |
+
import Loading from "$lib/components/Loading.svelte";
|
| 7 |
+
|
| 8 |
+
let generation = get(generationStore);
|
| 9 |
+
export let loading_generation: boolean = false;
|
| 10 |
|
| 11 |
let loading: boolean = false;
|
| 12 |
let already_saved: boolean = false;
|
| 13 |
|
| 14 |
const saveImage = () => {
|
| 15 |
const link = document.createElement('a');
|
| 16 |
+
link.href = generation?.image as string;
|
| 17 |
+
link.download = `${generation?.form?.inputs?.slice(0, 20)}.png`;
|
| 18 |
document.body.appendChild(link);
|
| 19 |
link.click();
|
| 20 |
document.body.removeChild(link);
|
|
|
|
| 28 |
headers: {
|
| 29 |
"Content-Type": "application/json"
|
| 30 |
},
|
| 31 |
+
body: JSON.stringify({ image: generation?.image, generation: generation?.form })
|
| 32 |
}).then(() => {
|
| 33 |
loading = false;
|
| 34 |
already_saved = true;
|
| 35 |
})
|
| 36 |
}
|
| 37 |
|
| 38 |
+
generationStore.subscribe((value) => {
|
| 39 |
+
console.log(value);
|
| 40 |
+
generation = value;
|
| 41 |
+
})
|
| 42 |
+
|
| 43 |
+
// create a ms countup depending on the generation time, to show the user how long it took to generate the image
|
| 44 |
+
let ms = 0;
|
| 45 |
+
let interval: any;
|
| 46 |
+
const start = () => {
|
| 47 |
+
interval = setInterval(() => {
|
| 48 |
+
ms += 100;
|
| 49 |
+
}, 100)
|
| 50 |
+
}
|
| 51 |
+
const stop = () => {
|
| 52 |
+
clearInterval(interval);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
$: if (!loading_generation) {
|
| 56 |
+
ms = 0;
|
| 57 |
+
stop();
|
| 58 |
+
} else {
|
| 59 |
+
start();
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
const format = (ms: number) => {
|
| 63 |
+
const date = new Date(ms);
|
| 64 |
+
const seconds = date.getSeconds();
|
| 65 |
+
const milliseconds = Math.round(date.getMilliseconds() / 100);
|
| 66 |
+
return `${seconds}.${milliseconds}s`;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
|
| 70 |
</script>
|
| 71 |
|
| 72 |
+
<div class=" w-full border-t xl:border-t-0 xl:border-l border-neutral-800 h-full col-span-5 xl:col-span-2" class:!border-black={!generation?.image || loading_generation} class:animate-pulse={loading_generation}>
|
| 73 |
+
{#if loading_generation}
|
| 74 |
+
<div class="w-full h-full flex items-center justify-center flex-col gap-3 bg-neutral-950 relative">
|
| 75 |
+
<p class="text-neutral-100 text-xl font-semibold">
|
| 76 |
+
{format(ms)}
|
| 77 |
+
</p>
|
| 78 |
+
<p class="text-xs italic text-neutral-500">
|
| 79 |
+
Generating image...
|
| 80 |
+
</p>
|
| 81 |
+
</div>
|
| 82 |
+
{:else}
|
| 83 |
+
{#if generation?.image}
|
| 84 |
+
{#if typeof generation?.image === "string"}
|
| 85 |
+
<img src={generation?.image} alt="Generation" class="w-full mx-auto object-contain" />
|
| 86 |
+
<div class="p-8 w-full">
|
| 87 |
+
<div class="w-full flex items-center justify-end gap-4">
|
| 88 |
+
<Button size="lg" theme="light" icon="material-symbols:save" iconPosition="right" onClick={saveImage}>Save</Button>
|
| 89 |
+
<Button
|
| 90 |
+
size="lg"
|
| 91 |
+
theme="blue"
|
| 92 |
+
icon="bxs:share"
|
| 93 |
+
iconPosition="right"
|
| 94 |
+
loading={loading}
|
| 95 |
+
disabled={loading || already_saved}
|
| 96 |
+
onClick={share}
|
| 97 |
+
>
|
| 98 |
+
{#if already_saved}
|
| 99 |
+
Shared!
|
| 100 |
+
{:else}
|
| 101 |
+
Share with community
|
| 102 |
+
{/if}
|
| 103 |
+
</Button>
|
| 104 |
+
</div>
|
| 105 |
+
<p class="text-neutral-500 text-sm text-right mt-2.5">
|
| 106 |
+
All images not shared with the community are deleted right after generation.
|
| 107 |
+
<br>
|
| 108 |
+
Your informations are not shared with anyone.
|
| 109 |
+
</p>
|
| 110 |
+
{#if generation?.form}
|
| 111 |
+
<div class="mt-6 grid grid-cols-1 gap-4">
|
| 112 |
+
<div>
|
| 113 |
+
<p class="text-neutral-400 font-semibold text-xs uppercase">
|
| 114 |
+
Model selected
|
| 115 |
+
</p>
|
| 116 |
+
<div class="flex items-center justify-start gap-4 px-2 py-2.5 hover:bg-neutral-800/60 transition-all duration-200 rounded-lg cursor-pointer w-full text-left">
|
| 117 |
+
<img src={generation?.form?.model.image} alt={generation?.form?.model.title} class="w-14 h-14 rounded-lg object-cover" />
|
| 118 |
+
<div>
|
| 119 |
+
<p class="text-neutral-200 text-base font-medium">{generation?.form?.model.title}</p>
|
| 120 |
+
<p class="text-neutral-400 text-sm">{generation?.form?.model.id}</p>
|
| 121 |
+
</div>
|
| 122 |
</div>
|
| 123 |
</div>
|
| 124 |
+
<div>
|
| 125 |
+
<p class="text-neutral-400 font-semibold text-xs uppercase">
|
| 126 |
+
Prompt
|
| 127 |
+
</p>
|
| 128 |
+
<p class="text-neutral-200 text-base font-medium mt-2">"{generation?.form.inputs}"</p>
|
| 129 |
+
</div>
|
| 130 |
</div>
|
| 131 |
+
{/if}
|
| 132 |
+
</div>
|
| 133 |
+
{:else}
|
| 134 |
+
<div>
|
| 135 |
+
Something went wrong
|
| 136 |
+
</div>
|
| 137 |
+
{/if}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
{/if}
|
| 139 |
{/if}
|
| 140 |
</div>
|
src/lib/components/sidebar/Sidebar.svelte
CHANGED
|
@@ -69,8 +69,7 @@
|
|
| 69 |
class="text-white text-center text-base pb-8 px-8 flex items-center justify-center gap-2 cursor-pointer"
|
| 70 |
on:click={openWindowLogin}
|
| 71 |
>
|
| 72 |
-
<img src=
|
| 73 |
-
<u>Sign in with Hugging Face</u>
|
| 74 |
</button>
|
| 75 |
{/if}
|
| 76 |
</aside>
|
|
|
|
| 69 |
class="text-white text-center text-base pb-8 px-8 flex items-center justify-center gap-2 cursor-pointer"
|
| 70 |
on:click={openWindowLogin}
|
| 71 |
>
|
| 72 |
+
<img src="https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-lg.svg" alt="Hugging Face Sign In" class="w-auto inline-block" />
|
|
|
|
| 73 |
</button>
|
| 74 |
{/if}
|
| 75 |
</aside>
|
src/lib/stores/use-generation.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
| 2 |
+
import { writable } from "svelte/store";
|
| 3 |
+
|
| 4 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
| 5 |
+
export const generationStore = writable<{
|
| 6 |
+
form?: Record<string, any>,
|
| 7 |
+
image?: string | ArrayBuffer | null,
|
| 8 |
+
}>(undefined);
|
src/routes/generate/+page.svelte
CHANGED
|
@@ -4,18 +4,21 @@
|
|
| 4 |
</svelte:head>
|
| 5 |
|
| 6 |
<script lang="ts">
|
|
|
|
|
|
|
| 7 |
import Button from "$lib/components/Button.svelte";
|
| 8 |
import Textarea from "$lib/components/fields/Textarea.svelte";
|
| 9 |
import Banner from "$lib/components/generate/Banner.svelte";
|
| 10 |
import Response from "$lib/components/generate/Response.svelte";
|
| 11 |
import Autocomplete from "$lib/components/models/autocomplete/Autocomplete.svelte";
|
|
|
|
| 12 |
|
| 13 |
export let data
|
|
|
|
| 14 |
|
| 15 |
let loading: boolean = false;
|
| 16 |
-
let response: string | ArrayBuffer | null = '';
|
| 17 |
|
| 18 |
-
let form = {
|
| 19 |
model: data?.model ?? null,
|
| 20 |
inputs: "",
|
| 21 |
parameters: {
|
|
@@ -41,15 +44,13 @@
|
|
| 41 |
reader.readAsDataURL(blob)
|
| 42 |
reader.onloadend = () => {
|
| 43 |
const base64data = reader.result
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
| 45 |
}
|
| 46 |
}
|
| 47 |
|
| 48 |
-
const res = await request.clone().json().catch(() => ({}))
|
| 49 |
-
if (res) {
|
| 50 |
-
response = res
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
loading = false
|
| 54 |
}
|
| 55 |
</script>
|
|
@@ -100,5 +101,5 @@
|
|
| 100 |
</div>
|
| 101 |
</div>
|
| 102 |
</div>
|
| 103 |
-
<Response
|
| 104 |
</main>
|
|
|
|
| 4 |
</svelte:head>
|
| 5 |
|
| 6 |
<script lang="ts">
|
| 7 |
+
import { get } from "svelte/store";
|
| 8 |
+
|
| 9 |
import Button from "$lib/components/Button.svelte";
|
| 10 |
import Textarea from "$lib/components/fields/Textarea.svelte";
|
| 11 |
import Banner from "$lib/components/generate/Banner.svelte";
|
| 12 |
import Response from "$lib/components/generate/Response.svelte";
|
| 13 |
import Autocomplete from "$lib/components/models/autocomplete/Autocomplete.svelte";
|
| 14 |
+
import { generationStore } from "$lib/stores/use-generation";
|
| 15 |
|
| 16 |
export let data
|
| 17 |
+
let generation = get(generationStore);
|
| 18 |
|
| 19 |
let loading: boolean = false;
|
|
|
|
| 20 |
|
| 21 |
+
let form = generation?.form ?? {
|
| 22 |
model: data?.model ?? null,
|
| 23 |
inputs: "",
|
| 24 |
parameters: {
|
|
|
|
| 44 |
reader.readAsDataURL(blob)
|
| 45 |
reader.onloadend = () => {
|
| 46 |
const base64data = reader.result
|
| 47 |
+
generationStore.set({
|
| 48 |
+
image: base64data,
|
| 49 |
+
form: form
|
| 50 |
+
})
|
| 51 |
}
|
| 52 |
}
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
loading = false
|
| 55 |
}
|
| 56 |
</script>
|
|
|
|
| 101 |
</div>
|
| 102 |
</div>
|
| 103 |
</div>
|
| 104 |
+
<Response loading_generation={loading} />
|
| 105 |
</main>
|