Spaces:
Runtime error
Runtime error
renaming, debounce input
Browse files- frontend/src/lib/App.svelte +15 -18
- frontend/src/lib/Frame.svelte +6 -5
- frontend/src/lib/Menu.svelte +0 -1
- frontend/src/lib/{Canvas.svelte → PaintCanvas.svelte} +1 -2
- frontend/src/lib/PaintFrame.svelte +3 -5
- frontend/src/lib/PromptModal.svelte +21 -11
- frontend/src/lib/store.ts +0 -7
- frontend/src/lib/types.ts +0 -1
frontend/src/lib/App.svelte
CHANGED
@@ -2,13 +2,13 @@
|
|
2 |
import Cursor from '$lib/Cursor.svelte';
|
3 |
import Frame from '$lib/Frame.svelte';
|
4 |
import PaintFrame from '$lib/PaintFrame.svelte';
|
5 |
-
import
|
6 |
import Menu from '$lib/Menu.svelte';
|
7 |
import PromptModal from '$lib/PromptModal.svelte';
|
8 |
import { COLORS, EMOJIS } from '$lib/constants';
|
9 |
import { PUBLIC_WS_INPAINTING } from '$env/static/public';
|
10 |
import type { PromptImgObject, PromptImgKey, Presence } from '$lib/types';
|
11 |
-
import { loadingState, currZoomTransform
|
12 |
|
13 |
import { useMyPresence, useObject, useOthers } from '$lib/liveblocks';
|
14 |
|
@@ -30,7 +30,6 @@
|
|
30 |
frame: null,
|
31 |
isPrompting: false,
|
32 |
isLoading: false,
|
33 |
-
isMoving: true,
|
34 |
currentPrompt: ''
|
35 |
};
|
36 |
myPresence.update(initialPresence);
|
@@ -41,18 +40,10 @@
|
|
41 |
|
42 |
const promptImgStorage = useObject('promptImgStorage');
|
43 |
|
44 |
-
function getpromptImgList(promptImgList: PromptImgObject[]): PromptImgObject[] {
|
45 |
-
if (promptImgList) {
|
46 |
-
const list: PromptImgObject[] = Object.values(promptImgList);
|
47 |
-
return list.sort((a, b) => a.date - b.date);
|
48 |
-
}
|
49 |
-
return [];
|
50 |
-
}
|
51 |
let showModal = false;
|
52 |
-
let promptImgList: PromptImgObject[] = [];
|
53 |
-
$: promptImgList = getpromptImgList($promptImgStorage?.toObject());
|
54 |
|
55 |
$: isPrompting = $myPresence?.isPrompting || false;
|
|
|
56 |
|
57 |
let canvasEl: HTMLCanvasElement;
|
58 |
|
@@ -69,7 +60,8 @@
|
|
69 |
showModal = false;
|
70 |
}
|
71 |
|
72 |
-
function onPrompt(
|
|
|
73 |
generateImage();
|
74 |
showModal = false;
|
75 |
}
|
@@ -94,7 +86,7 @@
|
|
94 |
return base64Crop;
|
95 |
}
|
96 |
async function generateImage() {
|
97 |
-
if (
|
98 |
$loadingState = 'Pending';
|
99 |
const prompt = $myPresence.currentPrompt;
|
100 |
const position = $myPresence.frame;
|
@@ -106,7 +98,7 @@
|
|
106 |
const sessionHash = crypto.randomUUID();
|
107 |
const payload = {
|
108 |
fn_index: 0,
|
109 |
-
data: [getImageCrop(position), prompt, 0.75, 7.5,
|
110 |
session_hash: sessionHash
|
111 |
};
|
112 |
console.log('payload', payload);
|
@@ -137,7 +129,8 @@
|
|
137 |
$loadingState = 'Queue full';
|
138 |
websocket.close();
|
139 |
myPresence.update({
|
140 |
-
isPrompting: false
|
|
|
141 |
});
|
142 |
return;
|
143 |
case 'estimation':
|
@@ -167,13 +160,17 @@
|
|
167 |
$promptImgStorage.set(key, promptImg);
|
168 |
console.log(imgURL);
|
169 |
$loadingState = data.success ? 'Complete' : 'Error';
|
|
|
|
|
|
|
170 |
} catch (err) {
|
171 |
const tError = err as Error;
|
172 |
$loadingState = tError?.message;
|
173 |
}
|
174 |
websocket.close();
|
175 |
myPresence.update({
|
176 |
-
isPrompting: false
|
|
|
177 |
});
|
178 |
return;
|
179 |
case 'process_starts':
|
@@ -196,7 +193,7 @@
|
|
196 |
<PromptModal on:prompt={onPrompt} on:close={onClose} />
|
197 |
{/if}
|
198 |
<div class="fixed top-0 left-0 z-0 w-screen h-screen">
|
199 |
-
<
|
200 |
|
201 |
<main class="z-10 relative">
|
202 |
<PaintFrame transform={$currZoomTransform} interactive={!isPrompting} />
|
|
|
2 |
import Cursor from '$lib/Cursor.svelte';
|
3 |
import Frame from '$lib/Frame.svelte';
|
4 |
import PaintFrame from '$lib/PaintFrame.svelte';
|
5 |
+
import PaintCanvas from '$lib/PaintCanvas.svelte';
|
6 |
import Menu from '$lib/Menu.svelte';
|
7 |
import PromptModal from '$lib/PromptModal.svelte';
|
8 |
import { COLORS, EMOJIS } from '$lib/constants';
|
9 |
import { PUBLIC_WS_INPAINTING } from '$env/static/public';
|
10 |
import type { PromptImgObject, PromptImgKey, Presence } from '$lib/types';
|
11 |
+
import { loadingState, currZoomTransform } from '$lib/store';
|
12 |
|
13 |
import { useMyPresence, useObject, useOthers } from '$lib/liveblocks';
|
14 |
|
|
|
30 |
frame: null,
|
31 |
isPrompting: false,
|
32 |
isLoading: false,
|
|
|
33 |
currentPrompt: ''
|
34 |
};
|
35 |
myPresence.update(initialPresence);
|
|
|
40 |
|
41 |
const promptImgStorage = useObject('promptImgStorage');
|
42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
let showModal = false;
|
|
|
|
|
44 |
|
45 |
$: isPrompting = $myPresence?.isPrompting || false;
|
46 |
+
$: isLoading = $myPresence?.isLoading || false;
|
47 |
|
48 |
let canvasEl: HTMLCanvasElement;
|
49 |
|
|
|
60 |
showModal = false;
|
61 |
}
|
62 |
|
63 |
+
function onPrompt() {
|
64 |
+
console.log('onPrompt');
|
65 |
generateImage();
|
66 |
showModal = false;
|
67 |
}
|
|
|
86 |
return base64Crop;
|
87 |
}
|
88 |
async function generateImage() {
|
89 |
+
if (isLoading) return;
|
90 |
$loadingState = 'Pending';
|
91 |
const prompt = $myPresence.currentPrompt;
|
92 |
const position = $myPresence.frame;
|
|
|
98 |
const sessionHash = crypto.randomUUID();
|
99 |
const payload = {
|
100 |
fn_index: 0,
|
101 |
+
data: [getImageCrop(position), prompt, 0.75, 7.5, 40, 'patchmatch'],
|
102 |
session_hash: sessionHash
|
103 |
};
|
104 |
console.log('payload', payload);
|
|
|
129 |
$loadingState = 'Queue full';
|
130 |
websocket.close();
|
131 |
myPresence.update({
|
132 |
+
isPrompting: false,
|
133 |
+
isLoading: false
|
134 |
});
|
135 |
return;
|
136 |
case 'estimation':
|
|
|
160 |
$promptImgStorage.set(key, promptImg);
|
161 |
console.log(imgURL);
|
162 |
$loadingState = data.success ? 'Complete' : 'Error';
|
163 |
+
setTimeout(() => {
|
164 |
+
$loadingState = '';
|
165 |
+
}, 2000);
|
166 |
} catch (err) {
|
167 |
const tError = err as Error;
|
168 |
$loadingState = tError?.message;
|
169 |
}
|
170 |
websocket.close();
|
171 |
myPresence.update({
|
172 |
+
isPrompting: false,
|
173 |
+
isLoading: false
|
174 |
});
|
175 |
return;
|
176 |
case 'process_starts':
|
|
|
193 |
<PromptModal on:prompt={onPrompt} on:close={onClose} />
|
194 |
{/if}
|
195 |
<div class="fixed top-0 left-0 z-0 w-screen h-screen">
|
196 |
+
<PaintCanvas bind:canvasEl />
|
197 |
|
198 |
<main class="z-10 relative">
|
199 |
<PaintFrame transform={$currZoomTransform} interactive={!isPrompting} />
|
frontend/src/lib/Frame.svelte
CHANGED
@@ -7,6 +7,7 @@
|
|
7 |
export let color = '';
|
8 |
export let position = { x: 0, y: 0 };
|
9 |
export let prompt = '';
|
|
|
10 |
export let interactive = false;
|
11 |
export let isDragging = false;
|
12 |
$: coord = {
|
@@ -19,11 +20,11 @@
|
|
19 |
class="frame z-0 flex relative
|
20 |
{!interactive ? 'pointer-events-none touch-none' : ''}
|
21 |
{isDragging ? 'cursor-grabbing' : 'cursor-grab'}"
|
22 |
-
style={`transform: translateX(${coord.x}px) translateY(${coord.y}px) scale(${transform.k});
|
23 |
-
background-image: linear-gradient(${color}, rgba(255,255,255,0));
|
24 |
-
color: ${color};
|
25 |
-
`}
|
26 |
>
|
|
|
|
|
|
|
27 |
<div class="small-frame z-0 flex relative" />
|
28 |
<LoadingIcon />
|
29 |
<h2 class="text-lg">Click to paint</h2>
|
@@ -37,7 +38,7 @@
|
|
37 |
transform-origin: 0 0;
|
38 |
}
|
39 |
.small-frame {
|
40 |
-
@apply pointer-events-none touch-none absolute top-1/2
|
41 |
transform: translateX(-50%) translateY(-50%);
|
42 |
}
|
43 |
</style>
|
|
|
7 |
export let color = '';
|
8 |
export let position = { x: 0, y: 0 };
|
9 |
export let prompt = '';
|
10 |
+
export let loadingState = '';
|
11 |
export let interactive = false;
|
12 |
export let isDragging = false;
|
13 |
$: coord = {
|
|
|
20 |
class="frame z-0 flex relative
|
21 |
{!interactive ? 'pointer-events-none touch-none' : ''}
|
22 |
{isDragging ? 'cursor-grabbing' : 'cursor-grab'}"
|
23 |
+
style={`transform: translateX(${coord.x}px) translateY(${coord.y}px) scale(${transform.k}); border-color: ${color};`}
|
|
|
|
|
|
|
24 |
>
|
25 |
+
{#if loadingState}
|
26 |
+
<span class="text-white drop-shadow-lg">{loadingState}</span>
|
27 |
+
{/if}
|
28 |
<div class="small-frame z-0 flex relative" />
|
29 |
<LoadingIcon />
|
30 |
<h2 class="text-lg">Click to paint</h2>
|
|
|
38 |
transform-origin: 0 0;
|
39 |
}
|
40 |
.small-frame {
|
41 |
+
@apply pointer-events-none touch-none absolute top-1/2 left-1/2 border-2 border-spacing-3 w-[256px] h-[256px];
|
42 |
transform: translateX(-50%) translateY(-50%);
|
43 |
}
|
44 |
</style>
|
frontend/src/lib/Menu.svelte
CHANGED
@@ -4,7 +4,6 @@
|
|
4 |
const dispatch = createEventDispatcher();
|
5 |
|
6 |
const onKeyup = (e: KeyboardEvent) => {
|
7 |
-
e.preventDefault();
|
8 |
if (e.key === 'Enter') {
|
9 |
dispatch('paintMode', { mode: 'paint' });
|
10 |
}
|
|
|
4 |
const dispatch = createEventDispatcher();
|
5 |
|
6 |
const onKeyup = (e: KeyboardEvent) => {
|
|
|
7 |
if (e.key === 'Enter') {
|
8 |
dispatch('paintMode', { mode: 'paint' });
|
9 |
}
|
frontend/src/lib/{Canvas.svelte → PaintCanvas.svelte}
RENAMED
@@ -15,8 +15,7 @@
|
|
15 |
const height = 512 * 4;
|
16 |
const width = 512 * 4;
|
17 |
|
18 |
-
let canvasEl: HTMLCanvasElement;
|
19 |
-
export { canvasEl as value };
|
20 |
|
21 |
let containerEl: HTMLDivElement;
|
22 |
let canvasCtx: CanvasRenderingContext2D;
|
|
|
15 |
const height = 512 * 4;
|
16 |
const width = 512 * 4;
|
17 |
|
18 |
+
export let canvasEl: HTMLCanvasElement = undefined;
|
|
|
19 |
|
20 |
let containerEl: HTMLDivElement;
|
21 |
let canvasCtx: CanvasRenderingContext2D;
|
frontend/src/lib/PaintFrame.svelte
CHANGED
@@ -1,5 +1,4 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import LoadingIcon from '$lib/LoadingIcon.svelte';
|
3 |
import Frame from '$lib/Frame.svelte';
|
4 |
import { drag } from 'd3-drag';
|
5 |
import { select } from 'd3-selection';
|
@@ -8,9 +7,8 @@
|
|
8 |
import type { ZoomTransform } from 'd3-zoom';
|
9 |
import { onMount } from 'svelte';
|
10 |
|
11 |
-
import { loadingState } from '$lib/store';
|
12 |
import { useMyPresence } from '$lib/liveblocks';
|
13 |
-
|
14 |
const myPresence = useMyPresence();
|
15 |
|
16 |
export let transform: ZoomTransform;
|
@@ -27,7 +25,7 @@
|
|
27 |
$: prompt = $myPresence?.currentPrompt;
|
28 |
|
29 |
onMount(() => {
|
30 |
-
function dragstarted(
|
31 |
isDragging = true;
|
32 |
}
|
33 |
|
@@ -59,5 +57,5 @@
|
|
59 |
</script>
|
60 |
|
61 |
<div bind:this={frameElement}>
|
62 |
-
<Frame {color} {position} {prompt} {transform} {isDragging} {interactive} />
|
63 |
</div>
|
|
|
1 |
<script lang="ts">
|
|
|
2 |
import Frame from '$lib/Frame.svelte';
|
3 |
import { drag } from 'd3-drag';
|
4 |
import { select } from 'd3-selection';
|
|
|
7 |
import type { ZoomTransform } from 'd3-zoom';
|
8 |
import { onMount } from 'svelte';
|
9 |
|
|
|
10 |
import { useMyPresence } from '$lib/liveblocks';
|
11 |
+
import { loadingState } from '$lib/store';
|
12 |
const myPresence = useMyPresence();
|
13 |
|
14 |
export let transform: ZoomTransform;
|
|
|
25 |
$: prompt = $myPresence?.currentPrompt;
|
26 |
|
27 |
onMount(() => {
|
28 |
+
function dragstarted() {
|
29 |
isDragging = true;
|
30 |
}
|
31 |
|
|
|
57 |
</script>
|
58 |
|
59 |
<div bind:this={frameElement}>
|
60 |
+
<Frame {color} {position} loadingState={$loadingState} {prompt} {transform} {isDragging} {interactive} />
|
61 |
</div>
|
frontend/src/lib/PromptModal.svelte
CHANGED
@@ -3,39 +3,49 @@
|
|
3 |
import { useMyPresence } from '$lib/liveblocks';
|
4 |
|
5 |
const dispatch = createEventDispatcher();
|
6 |
-
let prompt
|
7 |
let inputEl: HTMLInputElement;
|
8 |
const myPresence = useMyPresence();
|
9 |
|
10 |
-
$: {
|
11 |
-
myPresence.update({
|
12 |
-
currentPrompt: prompt,
|
13 |
-
isPrompting: true
|
14 |
-
});
|
15 |
-
}
|
16 |
-
|
17 |
const onKeyup = (e: KeyboardEvent) => {
|
18 |
if (e.key === 'Escape') {
|
19 |
-
dispatch('close');
|
20 |
myPresence.update({
|
21 |
currentPrompt: '',
|
22 |
isPrompting: false
|
23 |
});
|
|
|
24 |
}
|
25 |
};
|
26 |
onMount(() => {
|
27 |
inputEl.focus();
|
|
|
28 |
window.addEventListener('keyup', onKeyup);
|
29 |
return () => {
|
30 |
window.removeEventListener('keyup', onKeyup);
|
31 |
};
|
32 |
});
|
33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
function onPrompt() {
|
35 |
if (prompt.trim() !== '') {
|
36 |
-
|
|
|
37 |
}
|
38 |
}
|
|
|
|
|
|
|
|
|
39 |
</script>
|
40 |
|
41 |
<form
|
@@ -45,8 +55,8 @@
|
|
45 |
>
|
46 |
<input
|
47 |
bind:this={inputEl}
|
48 |
-
bind:value={prompt}
|
49 |
on:click|stopPropagation
|
|
|
50 |
class="input"
|
51 |
placeholder="Type a prompt..."
|
52 |
title="Input prompt to generate image and obtain palette"
|
|
|
3 |
import { useMyPresence } from '$lib/liveblocks';
|
4 |
|
5 |
const dispatch = createEventDispatcher();
|
6 |
+
let prompt = '';
|
7 |
let inputEl: HTMLInputElement;
|
8 |
const myPresence = useMyPresence();
|
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
const onKeyup = (e: KeyboardEvent) => {
|
11 |
if (e.key === 'Escape') {
|
|
|
12 |
myPresence.update({
|
13 |
currentPrompt: '',
|
14 |
isPrompting: false
|
15 |
});
|
16 |
+
dispatch('close');
|
17 |
}
|
18 |
};
|
19 |
onMount(() => {
|
20 |
inputEl.focus();
|
21 |
+
prompt = '';
|
22 |
window.addEventListener('keyup', onKeyup);
|
23 |
return () => {
|
24 |
window.removeEventListener('keyup', onKeyup);
|
25 |
};
|
26 |
});
|
27 |
|
28 |
+
let timer: NodeJS.Timeout;
|
29 |
+
function debouce(newPrompt: string) {
|
30 |
+
clearTimeout(timer);
|
31 |
+
timer = setTimeout(() => {
|
32 |
+
prompt = newPrompt;
|
33 |
+
myPresence.update({
|
34 |
+
currentPrompt: prompt,
|
35 |
+
isPrompting: true
|
36 |
+
});
|
37 |
+
}, 100);
|
38 |
+
}
|
39 |
function onPrompt() {
|
40 |
if (prompt.trim() !== '') {
|
41 |
+
console.log('Prompting with: ', prompt);
|
42 |
+
dispatch('prompt');
|
43 |
}
|
44 |
}
|
45 |
+
function onInput(event: Event) {
|
46 |
+
const target = event.target as HTMLInputElement;
|
47 |
+
debouce(target.value);
|
48 |
+
}
|
49 |
</script>
|
50 |
|
51 |
<form
|
|
|
55 |
>
|
56 |
<input
|
57 |
bind:this={inputEl}
|
|
|
58 |
on:click|stopPropagation
|
59 |
+
on:input={onInput}
|
60 |
class="input"
|
61 |
placeholder="Type a prompt..."
|
62 |
title="Input prompt to generate image and obtain palette"
|
frontend/src/lib/store.ts
CHANGED
@@ -1,13 +1,6 @@
|
|
1 |
import { writable } from 'svelte/store';
|
2 |
import { type ZoomTransform, zoomIdentity } from 'd3-zoom';
|
3 |
|
4 |
-
|
5 |
export const loadingState = writable<string>('');
|
6 |
-
export const isLoading = writable<boolean>(false);
|
7 |
-
export const isPrompting = writable<boolean>(false);
|
8 |
-
export const clickedPosition = writable<{ x: number; y: number }>();
|
9 |
-
export const showFrames = writable<boolean>(false);
|
10 |
-
|
11 |
-
|
12 |
export const currZoomTransform = writable<ZoomTransform>(zoomIdentity);
|
13 |
|
|
|
1 |
import { writable } from 'svelte/store';
|
2 |
import { type ZoomTransform, zoomIdentity } from 'd3-zoom';
|
3 |
|
|
|
4 |
export const loadingState = writable<string>('');
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
export const currZoomTransform = writable<ZoomTransform>(zoomIdentity);
|
6 |
|
frontend/src/lib/types.ts
CHANGED
@@ -9,7 +9,6 @@ export type Presence = {
|
|
9 |
} | null;
|
10 |
isPrompting: boolean;
|
11 |
isLoading: boolean;
|
12 |
-
isMoving: boolean;
|
13 |
currentPrompt: string
|
14 |
}
|
15 |
|
|
|
9 |
} | null;
|
10 |
isPrompting: boolean;
|
11 |
isLoading: boolean;
|
|
|
12 |
currentPrompt: string
|
13 |
}
|
14 |
|