Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
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>
|