Spaces:
Runtime error
Runtime error
first
Browse files- frontend/.env.example +1 -0
- frontend/package-lock.json +42 -6
- frontend/package.json +5 -1
- frontend/postcss.config.cjs +5 -5
- frontend/src/app.css +1 -1
- frontend/src/app.html +11 -14
- frontend/src/lib/App.svelte +203 -0
- frontend/src/lib/ChatInput.svelte +39 -0
- frontend/src/lib/ChatMessage.svelte +24 -0
- frontend/src/lib/ChatNewBtn.svelte +6 -0
- frontend/src/lib/Input +0 -0
- frontend/src/lib/constants.ts +1 -0
- frontend/src/lib/store.ts +77 -0
- frontend/src/lib/types.ts +29 -0
- frontend/src/routes/+page.svelte +6 -6
- frontend/src/routes/+page.ts +2 -1
- frontend/svelte.config.js +2 -2
- frontend/tailwind.config.cjs +6 -6
frontend/.env.example
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
PUBLIC_BACKEND_WS_URL="wss://ysharma-instructpix2pix-chatbot.hf.space/queue/join"
|
frontend/package-lock.json
CHANGED
@@ -7,6 +7,10 @@
|
|
7 |
"": {
|
8 |
"name": "frontend",
|
9 |
"version": "0.0.1",
|
|
|
|
|
|
|
|
|
10 |
"devDependencies": {
|
11 |
"@sveltejs/adapter-static": "^1.0.5",
|
12 |
"@sveltejs/kit": "^1.0.0",
|
@@ -1868,6 +1872,11 @@
|
|
1868 |
"node": ">= 4"
|
1869 |
}
|
1870 |
},
|
|
|
|
|
|
|
|
|
|
|
1871 |
"node_modules/import-fresh": {
|
1872 |
"version": "3.3.0",
|
1873 |
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
@@ -2034,6 +2043,14 @@
|
|
2034 |
"node": ">= 0.8.0"
|
2035 |
}
|
2036 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2037 |
"node_modules/lilconfig": {
|
2038 |
"version": "2.0.6",
|
2039 |
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz",
|
@@ -2043,6 +2060,14 @@
|
|
2043 |
"node": ">=10"
|
2044 |
}
|
2045 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2046 |
"node_modules/locate-path": {
|
2047 |
"version": "6.0.0",
|
2048 |
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
@@ -2189,15 +2214,14 @@
|
|
2189 |
"dev": true
|
2190 |
},
|
2191 |
"node_modules/nanoid": {
|
2192 |
-
"version": "
|
2193 |
-
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-
|
2194 |
-
"integrity": "sha512-
|
2195 |
-
"dev": true,
|
2196 |
"bin": {
|
2197 |
-
"nanoid": "bin/nanoid.
|
2198 |
},
|
2199 |
"engines": {
|
2200 |
-
"node": "^
|
2201 |
}
|
2202 |
},
|
2203 |
"node_modules/natural-compare": {
|
@@ -2509,6 +2533,18 @@
|
|
2509 |
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
2510 |
"dev": true
|
2511 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2512 |
"node_modules/prelude-ls": {
|
2513 |
"version": "1.2.1",
|
2514 |
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
|
|
7 |
"": {
|
8 |
"name": "frontend",
|
9 |
"version": "0.0.1",
|
10 |
+
"dependencies": {
|
11 |
+
"localforage": "^1.10.0",
|
12 |
+
"nanoid": "^4.0.0"
|
13 |
+
},
|
14 |
"devDependencies": {
|
15 |
"@sveltejs/adapter-static": "^1.0.5",
|
16 |
"@sveltejs/kit": "^1.0.0",
|
|
|
1872 |
"node": ">= 4"
|
1873 |
}
|
1874 |
},
|
1875 |
+
"node_modules/immediate": {
|
1876 |
+
"version": "3.0.6",
|
1877 |
+
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
1878 |
+
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
1879 |
+
},
|
1880 |
"node_modules/import-fresh": {
|
1881 |
"version": "3.3.0",
|
1882 |
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
|
|
2043 |
"node": ">= 0.8.0"
|
2044 |
}
|
2045 |
},
|
2046 |
+
"node_modules/lie": {
|
2047 |
+
"version": "3.1.1",
|
2048 |
+
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
2049 |
+
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
|
2050 |
+
"dependencies": {
|
2051 |
+
"immediate": "~3.0.5"
|
2052 |
+
}
|
2053 |
+
},
|
2054 |
"node_modules/lilconfig": {
|
2055 |
"version": "2.0.6",
|
2056 |
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz",
|
|
|
2060 |
"node": ">=10"
|
2061 |
}
|
2062 |
},
|
2063 |
+
"node_modules/localforage": {
|
2064 |
+
"version": "1.10.0",
|
2065 |
+
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
|
2066 |
+
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
|
2067 |
+
"dependencies": {
|
2068 |
+
"lie": "3.1.1"
|
2069 |
+
}
|
2070 |
+
},
|
2071 |
"node_modules/locate-path": {
|
2072 |
"version": "6.0.0",
|
2073 |
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
|
|
2214 |
"dev": true
|
2215 |
},
|
2216 |
"node_modules/nanoid": {
|
2217 |
+
"version": "4.0.0",
|
2218 |
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
|
2219 |
+
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
|
|
|
2220 |
"bin": {
|
2221 |
+
"nanoid": "bin/nanoid.js"
|
2222 |
},
|
2223 |
"engines": {
|
2224 |
+
"node": "^14 || ^16 || >=18"
|
2225 |
}
|
2226 |
},
|
2227 |
"node_modules/natural-compare": {
|
|
|
2533 |
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
2534 |
"dev": true
|
2535 |
},
|
2536 |
+
"node_modules/postcss/node_modules/nanoid": {
|
2537 |
+
"version": "3.3.4",
|
2538 |
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
2539 |
+
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
2540 |
+
"dev": true,
|
2541 |
+
"bin": {
|
2542 |
+
"nanoid": "bin/nanoid.cjs"
|
2543 |
+
},
|
2544 |
+
"engines": {
|
2545 |
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
2546 |
+
}
|
2547 |
+
},
|
2548 |
"node_modules/prelude-ls": {
|
2549 |
"version": "1.2.1",
|
2550 |
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
frontend/package.json
CHANGED
@@ -30,5 +30,9 @@
|
|
30 |
"typescript": "^4.9.3",
|
31 |
"vite": "^4.0.0"
|
32 |
},
|
33 |
-
"type": "module"
|
|
|
|
|
|
|
|
|
34 |
}
|
|
|
30 |
"typescript": "^4.9.3",
|
31 |
"vite": "^4.0.0"
|
32 |
},
|
33 |
+
"type": "module",
|
34 |
+
"dependencies": {
|
35 |
+
"localforage": "^1.10.0",
|
36 |
+
"nanoid": "^4.0.0"
|
37 |
+
}
|
38 |
}
|
frontend/postcss.config.cjs
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
module.exports = {
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
}
|
|
|
1 |
module.exports = {
|
2 |
+
plugins: {
|
3 |
+
tailwindcss: {},
|
4 |
+
autoprefixer: {}
|
5 |
+
}
|
6 |
+
};
|
frontend/src/app.css
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
@tailwind base;
|
2 |
@tailwind components;
|
3 |
-
@tailwind utilities;
|
|
|
1 |
@tailwind base;
|
2 |
@tailwind components;
|
3 |
+
@tailwind utilities;
|
frontend/src/app.html
CHANGED
@@ -1,17 +1,14 @@
|
|
1 |
<!DOCTYPE html>
|
2 |
<html lang="en">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
-
<
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
<script
|
9 |
-
src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
|
10 |
-
%sveltekit.head%
|
11 |
-
</head>
|
12 |
-
|
13 |
-
<body class="dark:bg-[rgb(11,15,25)] bg-white dark:text-white text-black">
|
14 |
-
<div>%sveltekit.body%</div>
|
15 |
-
</body>
|
16 |
-
|
17 |
-
</html>
|
|
|
1 |
<!DOCTYPE html>
|
2 |
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="utf-8" />
|
5 |
+
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
6 |
+
<meta name="viewport" content="width=device-width" />
|
7 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
|
8 |
+
%sveltekit.head%
|
9 |
+
</head>
|
10 |
|
11 |
+
<body class="dark:bg-[rgb(11,15,25)] bg-white dark:text-white text-black">
|
12 |
+
<div>%sveltekit.body%</div>
|
13 |
+
</body>
|
14 |
+
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/lib/App.svelte
ADDED
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { PUBLIC_BACKEND_WS_URL } from '$env/static/public';
|
3 |
+
import { onMount } from 'svelte';
|
4 |
+
import { nanoid } from 'nanoid';
|
5 |
+
import { chatsStore, selectedChatId, loadingState } from '$lib/store';
|
6 |
+
import type { Message, Chat } from '$lib/types';
|
7 |
+
import { MessageType, Sender } from '$lib/types';
|
8 |
+
import ChatInput from '$lib/ChatInput.svelte';
|
9 |
+
import ChatMessage from '$lib/ChatMessage.svelte';
|
10 |
+
import ChatNewBtn from '$lib/ChatNewBtn.svelte';
|
11 |
+
|
12 |
+
$: isLoading = false;
|
13 |
+
|
14 |
+
function clearStateMsg(t = 5000) {
|
15 |
+
setTimeout(() => {
|
16 |
+
$loadingState = '';
|
17 |
+
}, t);
|
18 |
+
}
|
19 |
+
onMount(() => {
|
20 |
+
// generateImage();
|
21 |
+
});
|
22 |
+
|
23 |
+
$: chatData = $chatsStore.find((chat) => chat.id === $selectedChatId);
|
24 |
+
$: messages = chatData?.messages || [];
|
25 |
+
|
26 |
+
$: console.log($chatsStore);
|
27 |
+
|
28 |
+
function newChat() {
|
29 |
+
const chatId = nanoid();
|
30 |
+
const chat: Chat = {
|
31 |
+
id: chatId,
|
32 |
+
blurb: `New Chat - ${chatId}`,
|
33 |
+
messages: [],
|
34 |
+
timestamp: new Date().getTime()
|
35 |
+
};
|
36 |
+
$chatsStore = [chat].concat($chatsStore);
|
37 |
+
$selectedChatId = chat.id;
|
38 |
+
}
|
39 |
+
|
40 |
+
function submitMessage(event: CustomEvent) {
|
41 |
+
const value = event.detail;
|
42 |
+
const message: Message = {
|
43 |
+
sender: Sender.USER,
|
44 |
+
id: nanoid(),
|
45 |
+
type: MessageType.TEXT,
|
46 |
+
content: value,
|
47 |
+
timestamp: new Date().getTime()
|
48 |
+
};
|
49 |
+
$chatsStore = $chatsStore.map((chat) => {
|
50 |
+
if (chat.id === $selectedChatId) {
|
51 |
+
chat.messages.push(message);
|
52 |
+
}
|
53 |
+
return chat;
|
54 |
+
});
|
55 |
+
}
|
56 |
+
const timeFormater = new Intl.DateTimeFormat('en-US', {
|
57 |
+
day: 'numeric',
|
58 |
+
month: 'short',
|
59 |
+
hour: 'numeric',
|
60 |
+
minute: 'numeric'
|
61 |
+
}).format;
|
62 |
+
async function generateImage() {
|
63 |
+
if (isLoading) return;
|
64 |
+
|
65 |
+
$loadingState = 'Pending';
|
66 |
+
|
67 |
+
const sessionHash = crypto.randomUUID();
|
68 |
+
const hashpayload = {
|
69 |
+
fn_index: 1,
|
70 |
+
session_hash: sessionHash
|
71 |
+
};
|
72 |
+
const image = '';
|
73 |
+
const datapayload = {
|
74 |
+
data: [
|
75 |
+
'make him wear shirts', // prompt
|
76 |
+
10.5, // text guidance
|
77 |
+
1.5, // image guidance
|
78 |
+
image,
|
79 |
+
15, // steps
|
80 |
+
'', // negative promtp,
|
81 |
+
512, // width
|
82 |
+
512, // height
|
83 |
+
0 // seed
|
84 |
+
]
|
85 |
+
};
|
86 |
+
|
87 |
+
const websocket = new WebSocket(PUBLIC_BACKEND_WS_URL);
|
88 |
+
// websocket.onopen = async function (event) {
|
89 |
+
// websocket.send(JSON.stringify({ hash: sessionHash }));
|
90 |
+
// };
|
91 |
+
websocket.onclose = (evt) => {
|
92 |
+
if (!evt.wasClean) {
|
93 |
+
$loadingState = 'Error';
|
94 |
+
}
|
95 |
+
};
|
96 |
+
websocket.onmessage = async function (event) {
|
97 |
+
try {
|
98 |
+
const data = JSON.parse(event.data);
|
99 |
+
$loadingState = '';
|
100 |
+
switch (data.msg) {
|
101 |
+
case 'send_hash':
|
102 |
+
websocket.send(JSON.stringify(hashpayload));
|
103 |
+
break;
|
104 |
+
case 'send_data':
|
105 |
+
$loadingState = 'Sending Data';
|
106 |
+
websocket.send(JSON.stringify({ ...hashpayload, ...datapayload }));
|
107 |
+
break;
|
108 |
+
case 'queue_full':
|
109 |
+
$loadingState = 'Queue full';
|
110 |
+
websocket.close();
|
111 |
+
|
112 |
+
return;
|
113 |
+
case 'estimation':
|
114 |
+
const { rank, queue_size } = data;
|
115 |
+
$loadingState = `On queue ${rank}/${queue_size}`;
|
116 |
+
break;
|
117 |
+
case 'process_generating':
|
118 |
+
$loadingState = data.success ? 'Generating' : 'Error';
|
119 |
+
break;
|
120 |
+
case 'process_completed':
|
121 |
+
try {
|
122 |
+
console.log(data);
|
123 |
+
// const params = data.output.data[0] as {
|
124 |
+
// is_nsfw: boolean;
|
125 |
+
// image: {
|
126 |
+
// url: string;
|
127 |
+
// filename: string;
|
128 |
+
// };
|
129 |
+
// };
|
130 |
+
// const isNSWF = params.is_nsfw;
|
131 |
+
// if (isNSWF) {
|
132 |
+
// throw new Error('NFSW');
|
133 |
+
// }
|
134 |
+
// // const imgBlob = await base64ToBlob(imgBase64);
|
135 |
+
// const promptImgParams = {
|
136 |
+
// imgURL: params.image.filename
|
137 |
+
// };
|
138 |
+
// // const imgURL = await uploadImage(imgBlob, promptImgParams);
|
139 |
+
// // $promptImgStorage.set(imageKey, promptImgParams);
|
140 |
+
// console.log(params.image.url);
|
141 |
+
$loadingState = data.success ? 'Complete' : 'Error';
|
142 |
+
clearStateMsg();
|
143 |
+
} catch (err) {
|
144 |
+
const tError = err as Error;
|
145 |
+
$loadingState = tError?.message;
|
146 |
+
|
147 |
+
clearStateMsg(10000);
|
148 |
+
}
|
149 |
+
websocket.close();
|
150 |
+
return;
|
151 |
+
case 'process_starts':
|
152 |
+
$loadingState = 'Processing';
|
153 |
+
break;
|
154 |
+
}
|
155 |
+
} catch (e) {
|
156 |
+
console.error(e);
|
157 |
+
$loadingState = 'Error';
|
158 |
+
}
|
159 |
+
};
|
160 |
+
}
|
161 |
+
</script>
|
162 |
+
|
163 |
+
<div>
|
164 |
+
<h1 class="text-2xl">CHATS</h1>
|
165 |
+
<div class="grid min-h-[40rem] grid-cols-4">
|
166 |
+
<div class="col-span-1 flex flex-col border-r p-4">
|
167 |
+
<ChatNewBtn on:click={newChat} />
|
168 |
+
<div class="max-h-[40rem] flex flex-col gap-2 overflow-y-scroll">
|
169 |
+
{#if $chatsStore.length}
|
170 |
+
{#each $chatsStore as chat}
|
171 |
+
<button on:click={() => ($selectedChatId = chat.id)}>
|
172 |
+
<div
|
173 |
+
class="flex h-16 flex-col items-start justify-center rounded-xl bg-gray-100 px-4 text-gray-900
|
174 |
+
{chat.id === $selectedChatId ? 'bg-gray-400' : ''}"
|
175 |
+
>
|
176 |
+
<h3 class="w-full truncate font-semibold">{chat.blurb}</h3>
|
177 |
+
<p class="w-full truncate text-sm text-gray-500">
|
178 |
+
{timeFormater(new Date(chat.timestamp))}
|
179 |
+
</p>
|
180 |
+
</div>
|
181 |
+
</button>
|
182 |
+
{/each}
|
183 |
+
{:else}
|
184 |
+
<div
|
185 |
+
class="flex h-16 flex-col items-start justify-center rounded-xl bg-gray-100 px-4 text-gray-900"
|
186 |
+
>
|
187 |
+
<h3 class="w-full truncate font-semibold">No chats</h3>
|
188 |
+
<p class="w-full truncate text-sm text-gray-500">Start a new Chat!</p>
|
189 |
+
</div>
|
190 |
+
{/if}
|
191 |
+
</div>
|
192 |
+
</div>
|
193 |
+
<div class="col-span-3 flex flex-col">
|
194 |
+
{#each messages as message}
|
195 |
+
<ChatMessage {message} />
|
196 |
+
{/each}
|
197 |
+
<ChatInput on:submitMessage={submitMessage} />
|
198 |
+
</div>
|
199 |
+
</div>
|
200 |
+
</div>
|
201 |
+
|
202 |
+
<style lang="postcss" scoped>
|
203 |
+
</style>
|
frontend/src/lib/ChatInput.svelte
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { createEventDispatcher, onMount } from 'svelte';
|
3 |
+
|
4 |
+
const dispatch = createEventDispatcher();
|
5 |
+
|
6 |
+
let textInput: string = '';
|
7 |
+
let inputEl: HTMLInputElement;
|
8 |
+
|
9 |
+
function onSubmit(event: Event) {
|
10 |
+
event.stopPropagation();
|
11 |
+
event.preventDefault();
|
12 |
+
event.stopImmediatePropagation();
|
13 |
+
|
14 |
+
if (textInput.trim() !== '') {
|
15 |
+
dispatch('submitMessage', textInput);
|
16 |
+
textInput = '';
|
17 |
+
}
|
18 |
+
}
|
19 |
+
onMount(() => {
|
20 |
+
inputEl.focus();
|
21 |
+
});
|
22 |
+
</script>
|
23 |
+
|
24 |
+
<form class="mt-auto flex w-full gap-2 border-t px-3 pt-4 pb-6" on:submit={onSubmit}>
|
25 |
+
<input
|
26 |
+
bind:value={textInput}
|
27 |
+
bind:this={inputEl}
|
28 |
+
on:click|stopPropagation
|
29 |
+
type="text"
|
30 |
+
class="flex h-11 flex-1 items-center rounded-full border bg-gray-100 px-4 text-black"
|
31 |
+
placeholder="Type here"
|
32 |
+
title="Type here to send a message"
|
33 |
+
/>
|
34 |
+
<button
|
35 |
+
title="Send your message"
|
36 |
+
type="submit"
|
37 |
+
class="rounded-full bg-black dark:bg-white dark:text-black px-4 font-semibold text-gray-200">Submit</button
|
38 |
+
>
|
39 |
+
</form>
|
frontend/src/lib/ChatMessage.svelte
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import type { Message, Chat } from '$lib/types';
|
3 |
+
import { MessageType, Sender } from '$lib/types';
|
4 |
+
|
5 |
+
export let message: Message;
|
6 |
+
</script>
|
7 |
+
|
8 |
+
<div class="flex flex-col gap-4 p-4">
|
9 |
+
<img
|
10 |
+
class="self-end max-h-[328px] rounded-xl bg-gray-200"
|
11 |
+
src="https://huggingface.co/datasets/victor/assets/resolve/main/Frame%201.png"
|
12 |
+
alt=""
|
13 |
+
/>
|
14 |
+
<p
|
15 |
+
class="self-end rounded-3 -mt-2 rounded-t rounded-b-2xl bg-black dark:bg-white py-2 px-4 text-white dark:text-black"
|
16 |
+
>
|
17 |
+
{message.content}
|
18 |
+
</p>
|
19 |
+
<img
|
20 |
+
class="max-h-[328px] self-start rounded-xl bg-gray-200"
|
21 |
+
src="https://huggingface.co/datasets/victor/assets/resolve/main/Frame%202.png"
|
22 |
+
alt=""
|
23 |
+
/>
|
24 |
+
</div>
|
frontend/src/lib/ChatNewBtn.svelte
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<button
|
2 |
+
on:click|preventDefault|stopPropagation
|
3 |
+
class="self-end mb-8 flex h-6 w-6 items-center justify-center rounded bg-black dark:bg-white"
|
4 |
+
>
|
5 |
+
<div class="h-2 w-2 rounded-full bg-white dark:bg-black" />
|
6 |
+
</button>
|
frontend/src/lib/Input
ADDED
File without changes
|
frontend/src/lib/constants.ts
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
export const FRAME_SIZE = 512;
|
frontend/src/lib/store.ts
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import localforage from 'localforage';
|
2 |
+
import { writable } from 'svelte/store';
|
3 |
+
import type { ChatData } from './types';
|
4 |
+
import { nanoid } from 'nanoid';
|
5 |
+
|
6 |
+
const intitalChatId = nanoid();
|
7 |
+
const initialData: ChatData = [{
|
8 |
+
id: intitalChatId,
|
9 |
+
messages: [],
|
10 |
+
blurb: `New Chat - ${intitalChatId}`,
|
11 |
+
timestamp: new Date().getTime()
|
12 |
+
}];
|
13 |
+
|
14 |
+
|
15 |
+
const loadingState = writable<string>('');
|
16 |
+
const chatsStore = writable<ChatData>(initialData);
|
17 |
+
const selectedChatId = writable<string>(intitalChatId);
|
18 |
+
|
19 |
+
localforage.config({
|
20 |
+
name: 'Pix2PixChat',
|
21 |
+
storeName: 'chatsStore'
|
22 |
+
});
|
23 |
+
|
24 |
+
localforage.getItem<ChatData>('chatsStore').then((value) => {
|
25 |
+
if (value) {
|
26 |
+
chatsStore.set(value);
|
27 |
+
} else {
|
28 |
+
chatsStore.set(initialData);
|
29 |
+
}
|
30 |
+
});
|
31 |
+
|
32 |
+
chatsStore.subscribe((value) => localforage.setItem<ChatData>('chatsStore', value));
|
33 |
+
|
34 |
+
localforage.getItem<string>('selectedChatId').then((value) => {
|
35 |
+
if (value) {
|
36 |
+
selectedChatId.set(value);
|
37 |
+
} else {
|
38 |
+
selectedChatId.set(intitalChatId);
|
39 |
+
}
|
40 |
+
});
|
41 |
+
|
42 |
+
selectedChatId.subscribe((value) => localforage.setItem<string>('selectedChatId', value));
|
43 |
+
|
44 |
+
export { loadingState, chatsStore, selectedChatId };
|
45 |
+
|
46 |
+
// import { writable } from 'svelte/store';
|
47 |
+
// import { browser } from '$app/environment';
|
48 |
+
// import type { ChatData } from './types';
|
49 |
+
// import { nanoid } from 'nanoid';
|
50 |
+
|
51 |
+
|
52 |
+
// const intitalChatId = nanoid();
|
53 |
+
// const initialData: ChatData = [{
|
54 |
+
// id: intitalChatId,
|
55 |
+
// messages: [],
|
56 |
+
// blurb: `New Chat - ${new Date().getTime()}`
|
57 |
+
// }
|
58 |
+
// ]
|
59 |
+
|
60 |
+
// export const loadingState = writable<string>('');
|
61 |
+
// export const chatsStore = writable<ChatData>(
|
62 |
+
// browser ? JSON.parse(localStorage['chatsStore'] || JSON.stringify(initialData)) : initialData
|
63 |
+
// );
|
64 |
+
// chatsStore.subscribe((value) => {
|
65 |
+
// if (browser) {
|
66 |
+
// return (localStorage['chatsStore'] = JSON.stringify(value));
|
67 |
+
// }
|
68 |
+
// });
|
69 |
+
|
70 |
+
// export const selectedChatId = writable<string>(
|
71 |
+
// browser ? JSON.parse(localStorage['selectedChatId'] || JSON.stringify(intitalChatId)) : intitalChatId
|
72 |
+
// );
|
73 |
+
// selectedChatId.subscribe((value) => {
|
74 |
+
// if (browser) {
|
75 |
+
// return (localStorage['selectedChatId'] = JSON.stringify(value));
|
76 |
+
// }
|
77 |
+
// });
|
frontend/src/lib/types.ts
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export const enum MessageType {
|
2 |
+
TEXT = 'text',
|
3 |
+
IMAGE = 'image',
|
4 |
+
VIDEO = 'video',
|
5 |
+
AUDIO = 'audio',
|
6 |
+
FILE = 'file'
|
7 |
+
}
|
8 |
+
|
9 |
+
export const enum Sender {
|
10 |
+
USER = 'user',
|
11 |
+
BOT = 'bot'
|
12 |
+
}
|
13 |
+
|
14 |
+
export interface Message {
|
15 |
+
id: string;
|
16 |
+
content: string;
|
17 |
+
sender: Sender;
|
18 |
+
type: MessageType;
|
19 |
+
timestamp: number;
|
20 |
+
}
|
21 |
+
|
22 |
+
export interface Chat {
|
23 |
+
id: string;
|
24 |
+
messages: Message[];
|
25 |
+
blurb: string;
|
26 |
+
timestamp: number;
|
27 |
+
}
|
28 |
+
|
29 |
+
export type ChatData = Chat[];
|
frontend/src/routes/+page.svelte
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
-
<
|
|
|
|
|
2 |
|
3 |
-
<
|
4 |
-
|
5 |
-
|
6 |
-
}
|
7 |
-
</style>
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import App from '$lib/App.svelte';
|
3 |
+
</script>
|
4 |
|
5 |
+
<div class="max-w-7xl mx-auto px-4">
|
6 |
+
<App />
|
7 |
+
</div>
|
|
|
|
frontend/src/routes/+page.ts
CHANGED
@@ -1 +1,2 @@
|
|
1 |
-
export const prerender = true;
|
|
|
|
1 |
+
export const prerender = true;
|
2 |
+
export const ssr = false;
|
frontend/svelte.config.js
CHANGED
@@ -14,8 +14,8 @@ const config = {
|
|
14 |
assets: 'build',
|
15 |
fallback: null,
|
16 |
precompress: false
|
17 |
-
})
|
18 |
}
|
19 |
};
|
20 |
|
21 |
-
export default config;
|
|
|
14 |
assets: 'build',
|
15 |
fallback: null,
|
16 |
precompress: false
|
17 |
+
}),
|
18 |
}
|
19 |
};
|
20 |
|
21 |
+
export default config;
|
frontend/tailwind.config.cjs
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
/** @type {import('tailwindcss').Config} */
|
2 |
module.exports = {
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
};
|
|
|
1 |
/** @type {import('tailwindcss').Config} */
|
2 |
module.exports = {
|
3 |
+
content: ['./src/**/*.{html,js,svelte,ts}'],
|
4 |
+
theme: {
|
5 |
+
extend: {}
|
6 |
+
},
|
7 |
+
plugins: []
|
8 |
+
};
|