add chat and about page, style everything, let user upload a file and have server return string array of the file's text contents chunked by 4k characters
This commit is contained in:
parent
49e60fcdb6
commit
d906c72e8b
|
@ -1,5 +1,8 @@
|
||||||
{
|
{
|
||||||
"prettier.documentSelectors": ["**/*.svelte"],
|
"prettier.documentSelectors": ["**/*.svelte"],
|
||||||
|
"[svelte]": {
|
||||||
|
"editor.defaultFormatter": "svelte.svelte-vscode"
|
||||||
|
},
|
||||||
"tailwindCSS.classAttributes": [
|
"tailwindCSS.classAttributes": [
|
||||||
"class",
|
"class",
|
||||||
"accent",
|
"accent",
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
const prompt = writable<string>(JSON.stringify([]));
|
||||||
|
|
||||||
|
export default prompt;
|
|
@ -1,4 +1,4 @@
|
||||||
<script lang='ts'>
|
<script lang="ts">
|
||||||
// The ordering of these imports is critical to your app working properly
|
// The ordering of these imports is critical to your app working properly
|
||||||
import '@skeletonlabs/skeleton/themes/theme-crimson.css';
|
import '@skeletonlabs/skeleton/themes/theme-crimson.css';
|
||||||
// If you have source.organizeImports set to true in VSCode, then it will auto change this ordering
|
// If you have source.organizeImports set to true in VSCode, then it will auto change this ordering
|
||||||
|
@ -14,33 +14,11 @@
|
||||||
<!-- App Bar -->
|
<!-- App Bar -->
|
||||||
<AppBar>
|
<AppBar>
|
||||||
<svelte:fragment slot="lead">
|
<svelte:fragment slot="lead">
|
||||||
<strong class="text-xl uppercase">Skeleton</strong>
|
<strong class="text-xl uppercase">Sumi Ai</strong>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="trail">
|
<svelte:fragment slot="trail">
|
||||||
<a
|
<a class="btn btn-sm variant-ringed-tertiary" href="/"> Home </a>
|
||||||
class="btn btn-sm variant-ghost-surface"
|
<a class="btn btn-sm variant-ringed-tertiary" href="/about"> About </a>
|
||||||
href="https://discord.gg/EXqV7W8MtY"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
Discord
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="btn btn-sm variant-ghost-surface"
|
|
||||||
href="https://twitter.com/SkeletonUI"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
Twitter
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="btn btn-sm variant-ghost-surface"
|
|
||||||
href="https://github.com/skeletonlabs/skeleton"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
GitHub
|
|
||||||
</a>
|
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
|
@ -1,71 +1,52 @@
|
||||||
<!-- YOU CAN DELETE EVERYTHING IN THIS PAGE -->
|
<script lang="ts">
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import prompt from '$lib/shared/stores/prompt';
|
||||||
|
|
||||||
|
let files: FileList;
|
||||||
|
let isDisabled = true;
|
||||||
|
|
||||||
|
$: if (files && files.length >= 0) {
|
||||||
|
isDisabled = false;
|
||||||
|
} else {
|
||||||
|
isDisabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitFile = async (file: File) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', files[0]);
|
||||||
|
|
||||||
|
const response = await fetch('/', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
return await response.json();
|
||||||
|
};
|
||||||
|
|
||||||
|
const summarize = async () => {
|
||||||
|
try {
|
||||||
|
if (files && files.length >= 1) {
|
||||||
|
const result = await submitFile(files[0]);
|
||||||
|
prompt.set(JSON.stringify(result));
|
||||||
|
goto('chat');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<div class="container h-full mx-auto flex justify-center items-center">
|
<div class="container h-full mx-auto flex justify-center items-center">
|
||||||
<div class="space-y-10 text-center">
|
<div class="text-center">
|
||||||
<h2 class="font-bold">Welcome to Skeleton.</h2>
|
<h2>Please Sumi</h2>
|
||||||
<!-- Animated Logo -->
|
<p class="my-4">Select the text file you'd like to have summarized.</p>
|
||||||
<figure>
|
<input type="file" accept=".txt" name="conversation" bind:files />
|
||||||
<section class="img-bg" />
|
<div class="flex justify-center space-x-2 my-12">
|
||||||
<svg
|
<button
|
||||||
class="fill-token -scale-x-[100%]"
|
type="button"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
class="btn variant-ringed-tertiary"
|
||||||
viewBox="0 0 200 200"
|
disabled={isDisabled}
|
||||||
|
on:click={summarize}>Summarize</button
|
||||||
>
|
>
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M98.77 50.95c25.1 0 46.54 8.7 61.86 23a41.34 41.34 0 0 0 5.19-1.93c4.35-2.02 10.06-6.17 17.13-12.43-1.15 10.91-2.38 18.93-3.7 24.04-.7 2.75-1.8 6.08-3.3 10a80.04 80.04 0 0 1 8.42 23.33c6.04 30.3-4.3 43.7-28.33 51.18.18.9.32 1.87.42 2.9.86 8.87-3.62 23.19-9 23.19-3.54 0-5.84-4.93-8.3-12.13-.78 8.34-4.58 17.9-8.98 17.9-4.73 0-7.25-8.84-10.93-20.13a214 214 0 0 1-.64 2.93l-.16.71-.16.71-.17.71c-1.84 7.58-4.46 15.07-8.5 15.07-5.06 0-2.29-15.9-10.8-22.63-43.14 2.36-79.43-13.6-79.43-59.62 0-8.48 2-16.76 5.69-24.45a93.72 93.72 0 0 1-1.77-3.68c-2.87-6.32-6.3-15.88-10.31-28.7 10.26 7.66 18.12 12.22 23.6 13.68.5.14 1.02.26 1.57.36 14.36-14.44 35.88-24.01 60.6-24.01Zm-9.99 62.3c-14.57 0-26.39 11.45-26.39 25.58 0 14.14 11.82 25.6 26.39 25.6s26.39-11.46 26.39-25.6c0-13.99-11.58-25.35-25.95-25.58Zm37.45 31.95c-4.4 0-6.73 9.4-6.73 13.62 0 3.3 1.1 5.12 2.9 5.45 4.39.4 3.05-5.97 5.23-5.97 1.06 0 2.2 1.35 3.34 2.73l.34.42c1.25 1.52 2.5 2.93 3.64 2.49 2.7-1.61 1.67-5.12.74-7.88-3.3-6.96-5.05-10.86-9.46-10.86Zm-36.85-28.45c12.57 0 22.76 9.78 22.76 21.85 0 12.07-10.2 21.85-22.76 21.85-.77 0-1.53-.04-2.29-.11 11.5-1.1 20.46-10.42 20.46-21.74 0-11.32-8.97-20.63-20.46-21.74.76-.07 1.52-.1 2.3-.1Zm65.54-5c-10.04 0-18.18 10.06-18.18 22.47 0 12.4 8.14 22.47 18.18 22.47s18.18-10.06 18.18-22.47c0-12.41-8.14-22.48-18.18-22.48Zm.6 3.62c8.38 0 15.16 8.4 15.16 18.74 0 10.35-6.78 18.74-15.16 18.74-.77 0-1.54-.07-2.28-.21 7.3-1.36 12.89-9.14 12.89-18.53 0-9.4-5.6-17.17-12.89-18.53.74-.14 1.5-.2 2.28-.2Zm3.34-72.27.12.07c.58.38.75 1.16.37 1.74l-2.99 4.6c-.35.55-1.05.73-1.61.44l-.12-.07a1.26 1.26 0 0 1-.37-1.74l2.98-4.6a1.26 1.26 0 0 1 1.62-.44ZM39.66 42l.08.1 2.76 3.93a1.26 1.26 0 0 1-2.06 1.45l-2.76-3.94A1.26 1.26 0 0 1 39.66 42Zm63.28-42 2.85 24.13 10.62-11.94.28 29.72-2.1-.47a77.8 77.8 0 0 0-16.72-2.04c-4.96 0-9.61.67-13.96 2l-2.34.73L83.5 4.96l9.72 18.37L102.94 0Zm-1.87 13.39-7.5 17.96-7.3-13.8-1.03 19.93.22-.06a51.56 51.56 0 0 1 12.1-1.45h.31c4.58 0 9.58.54 15 1.61l.35.07-.15-16.54-9.79 11-2.21-18.72Zm38.86 19.23c.67.2 1.05.89.86 1.56l-.38 1.32c-.17.62-.8 1-1.42.89l-.13-.03a1.26 1.26 0 0 1-.86-1.56l.38-1.32c.19-.66.88-1.05 1.55-.86ZM63.95 31.1l.05.12.7 2.17a1.26 1.26 0 0 1-2.34.9l-.04-.12-.71-2.17a1.26 1.26 0 0 1 2.34-.9Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</figure>
|
|
||||||
<!-- / -->
|
|
||||||
<div class="flex justify-center space-x-2">
|
|
||||||
<a
|
|
||||||
class="btn btn-filled"
|
|
||||||
href="https://skeleton.dev/"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
Launch Documentation
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="space-y-2">
|
|
||||||
<p>Try editing the following:</p>
|
|
||||||
<p><code>/src/routes/+layout.svelte</code></p>
|
|
||||||
<p><code>/src/routes/+page.svelte</code></p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
|
||||||
figure {
|
|
||||||
@apply flex relative flex-col;
|
|
||||||
}
|
|
||||||
figure svg,
|
|
||||||
.img-bg {
|
|
||||||
@apply w-64 h-64 md:w-80 md:h-80;
|
|
||||||
}
|
|
||||||
.img-bg {
|
|
||||||
@apply absolute z-[-1] rounded-full blur-[50px] transition-all;
|
|
||||||
animation: pulse 5s cubic-bezier(0, 0, 0, 0.5) infinite,
|
|
||||||
glow 5s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes glow {
|
|
||||||
0% {
|
|
||||||
@apply bg-primary-400/50;
|
|
||||||
}
|
|
||||||
33% {
|
|
||||||
@apply bg-secondary-400/50;
|
|
||||||
}
|
|
||||||
66% {
|
|
||||||
@apply bg-tertiary-400/50;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
@apply bg-primary-400/50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes pulse {
|
|
||||||
50% {
|
|
||||||
transform: scale(1.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { fail } from '@sveltejs/kit';
|
||||||
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
|
const parseFile = async (file: Blob) => {
|
||||||
|
const fileSize = file.size;
|
||||||
|
const chunkSize = 4000;
|
||||||
|
const chunks = Math.ceil(fileSize / chunkSize);
|
||||||
|
const convoArray: string[] = [];
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
|
for (let i = 0; i < chunks; i++) {
|
||||||
|
const start = i * chunkSize;
|
||||||
|
const end = Math.min(start + chunkSize, fileSize);
|
||||||
|
const buffer = await file.slice(start, end).arrayBuffer();
|
||||||
|
const text = decoder.decode(buffer);
|
||||||
|
convoArray.push(text);
|
||||||
|
}
|
||||||
|
return convoArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const POST = (async ({ request, url }) => {
|
||||||
|
try {
|
||||||
|
const data = Object.fromEntries(await request.formData());
|
||||||
|
const file = data.file as Blob;
|
||||||
|
const conversation = await parseFile(file);
|
||||||
|
|
||||||
|
return new Response(JSON.stringify(conversation), {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
throw fail(500, { err: err });
|
||||||
|
}
|
||||||
|
}) satisfies RequestHandler;
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div
|
||||||
|
class="container h-full mx-auto flex flex-col justify-center items-center text-base max-w-prose"
|
||||||
|
>
|
||||||
|
<h1 class="self-center">what dis?</h1>
|
||||||
|
<p class="font-sans my-4">
|
||||||
|
ChatGPT has a limit of ~4k characters per prompt, so to ask questions about a large body of text
|
||||||
|
would require that you split the text in 4k chunks.
|
||||||
|
</p>
|
||||||
|
<p class="font-sans">
|
||||||
|
With Sumi, you can simply upload the entire document as a text file, and it will handle
|
||||||
|
everything else.
|
||||||
|
</p>
|
||||||
|
</div>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import prompt from '$lib/shared/stores/prompt';
|
||||||
|
let currentPrompt: string[];
|
||||||
|
|
||||||
|
prompt.subscribe((val) => {
|
||||||
|
currentPrompt = JSON.parse(val);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>{currentPrompt}</div>
|
|
@ -1,9 +1,16 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
darkMode: 'class',
|
darkMode: 'class',
|
||||||
content: ['./src/**/*.{html,js,svelte,ts}', require('path').join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts}')],
|
content: [
|
||||||
|
'./src/**/*.{html,js,svelte,ts}',
|
||||||
|
require('path').join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts}')
|
||||||
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {}
|
||||||
},
|
},
|
||||||
plugins: [require('@tailwindcss/forms'),require('@tailwindcss/typography'),...require('@skeletonlabs/skeleton/tailwind/skeleton.cjs')()],
|
plugins: [
|
||||||
}
|
require('@tailwindcss/forms'),
|
||||||
|
require('@tailwindcss/typography'),
|
||||||
|
...require('@skeletonlabs/skeleton/tailwind/skeleton.cjs')()
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue