Skip to content

Commit

Permalink
chat backend somewhat working
Browse files Browse the repository at this point in the history
  • Loading branch information
eksno committed Feb 27, 2024
1 parent 5f4f343 commit bf8b19c
Show file tree
Hide file tree
Showing 8 changed files with 360 additions and 257 deletions.
40 changes: 36 additions & 4 deletions apps/aitino/src/app.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,38 @@
@tailwind utilities;

@layer base {
/* Universal */
--md-sys-color-primary: 69 223 164;
--md-sys-color-on-primary: 0 56 37;
--md-sys-color-primary-container: 0 81 55;
--md-sys-color-on-primary-container: 104 252 191;
--md-sys-color-secondary: 60 221 199;
--md-sys-color-on-secondary: 0 55 49;
--md-sys-color-secondary-container: 0 80 71;
--md-sys-color-on-secondary-container: 98 250 227;
--md-sys-color-tertiary: 255 175 211;
--md-sys-color-on-tertiary: 98 0 64;
--md-sys-color-tertiary-container: 133 20 90;
--md-sys-color-on-tertiary-container: 255 216 231;
--md-sys-color-error: 255 180 171;
--md-sys-color-error-container: 147 0 10;
--md-sys-color-on-error: 105 0 5;
--md-sys-color-on-error-container: 255 218 214;
--md-sys-color-background: 23 25 25;
--md-sys-color-on-background: 225 227 223;
--md-sys-color-surface: 30 30 30;
--md-sys-color-on-surface: 225 227 223;
--md-sys-color-surface-variant: 64 73 67;
--md-sys-color-on-surface-variant: 191 201 193;
--md-sys-color-outline: 138 147 140;
--md-sys-color-inverse-on-surface: 25 28 26;
--md-sys-color-inverse-surface: 225 227 223;
--md-sys-color-inverse-primary: 0 108 75;
--md-sys-color-shadow: 0 0 0;
--md-sys-color-surface-tint: 69 223 164;
--md-sys-color-outline-variant: 64 73 67;
--md-sys-color-scrim: 0 0 0;

:root {
--background: 255 255 255;
--foreground: 13 13 13;
Expand All @@ -26,7 +58,7 @@
--radius: 0.5rem;
}
.dark {
--background: 9 16 16;
--background: 23 25 25;
--foreground: 248 250 252;
--card: 13 13 13;
--card-foreground: 249 249 249;
Expand All @@ -35,16 +67,16 @@
--primary: 69 223 164;
--primary-foreground: 0 56 37;
--secondary: 60 221 199;
--secondary-foreground: 249 249 249;
--secondary-foreground: 0 55 49;
--muted: 45 45 45;
--muted-foreground: 166 166 166;
--accent: 255 175 211;
--accent-foreground: 98 0 64;
--destructive: 251 113 133;
--destructive-foreground: 249 249 249;
--border: 45 45 45;
--input: 30 41 59;
--ring: 123 123 123;
--input: 0 81 55;
--ring: 69 223 164;
--radius: 0.5rem;
}
}
Expand Down
8 changes: 7 additions & 1 deletion apps/aitino/src/lib/components/ui/textarea/textarea.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
<script lang="ts">
import type { HTMLTextareaAttributes } from "svelte/elements";
import { cn } from "$lib/utils";
export let minRows = 1;
export let maxRows: number;
type $$Props = HTMLTextareaAttributes;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"] = undefined;
export { className as class };
$: minHeight = `${1 + minRows * 1.5}em`;
$: maxHeight = maxRows ? `${1 + maxRows * 1.5}em` : `auto`;
</script>

<textarea
class={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
style="min-height: {minHeight}; max-height: {maxHeight}"
bind:value
on:blur
on:change
Expand Down
188 changes: 107 additions & 81 deletions apps/aitino/src/routes/app/sessions/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script lang="ts">
import { Loader, Send } from "lucide-svelte";
import { Input } from "$lib/components/ui/input";
import { Button } from "$lib/components/ui/button";
import Message from "./Message.svelte";
import * as Card from "$lib/components/ui/card";
import { afterUpdate, onMount } from "svelte";
import { v4 as uuidv4 } from "uuid";
import Chat from "./Chat.svelte";
import { onMount } from "svelte";
let maeveId: string;
let sessionId: string;
// get maeveId and sessionId from the page store
let loading = true;
let maeveId: string | null;
let sessionId: string | null;
let awaitingReply = false;
let messages: {
id: string;
session_id: string;
Expand All @@ -20,92 +20,118 @@
}[] = [];
onMount(() => {
const _id: string | null = localStorage.getItem("currentMeaveId");
if (_id == null) {
console.error("No maeve id found");
return;
maeveId = localStorage.getItem("currentMeaveId");
sessionId = localStorage.getItem("currentSessionId");
messages = JSON.parse(localStorage.getItem("currentMessages") || "[]");
loading = false;
});
async function* callMaeve(url: string): AsyncGenerator<string, void, unknown> {
const response = await fetch(url);
const reader = response.body?.getReader();
if (!reader) {
throw new Error("Invalid response");
}
maeveId = _id;
console.log(maeveId, "maeveId");
});
while (true) {
const { done, value } = await reader.read();
function handleKeyDown(event: { key: string }) {
if (event.key === "Enter") {
sendMessage();
if (done) {
break;
}
const line = new TextDecoder().decode(value);
if (!line) {
break;
}
yield line;
}
}
function handleInputChange(event: { target: { value: string } }) {
newMessageContent = event.target.value;
}
async function main(): Promise<void> {
const url = `https://api.aiti.no/maeve?id=${maeveId}`;
let newMessageContent = "";
const sendMessage = () => {
if (newMessageContent.trim() !== "") {
const newMessage = {
id: uuidv4(),
status: "success",
data: {
content: newMessageContent,
role: "user",
name: "Admin",
created_at: new Date().toLocaleTimeString(),
session_id: sessionId
}
};
messages = [...messages, newMessage];
newMessageContent = "";
if (!url) {
console.log("Usage: Provide a valid URL as a parameter");
return;
}
};
let chatContainerElement: HTMLDivElement;
for await (const event of callMaeve(url)) {
let e = null;
try {
e = JSON.parse(event.trim());
} catch (error) {
console.error(`Error parsing JSON ${error}:`, event);
continue;
}
if (!e) {
continue;
}
afterUpdate(() => {
if (chatContainerElement) {
chatContainerElement.scrollTop = chatContainerElement.scrollHeight;
if (e.id === 0) {
sessionId = e.data.session_id;
localStorage.setItem("currentSessionId", e.data.session_id);
loading = false;
continue;
}
if (e.data === "done") {
awaitingReply = true;
console.log("done");
return;
}
messages = [...messages, e.data];
localStorage.setItem("currentMessages", JSON.stringify(messages));
}
});
}
function runMaeve() {
localStorage.removeItem("currentSessionId");
localStorage.removeItem("currentMessages");
sessionId = null;
messages = [];
loading = true;
main();
}
function redirectToCreateMaeve() {
window.location.href = "/app/maeves/create";
}
</script>

<div class="container -mb-6 flex h-screen max-w-6xl flex-col justify-end p-6">
<div class="no-scrollbar max-h-full overflow-y-auto" bind:this={chatContainerElement}>
<!-- add scroll to the bottom of the chat -->
{#each messages as message}
<Message {message} />
{/each}
{#if loading}
<div
class="xl:prose-md prose prose-sm prose-main mx-auto flex h-screen max-w-none flex-col items-center justify-center gap-4 px-12 text-center md:prose-base 2xl:prose-lg"
>
<h1>Loading...</h1>
</div>

<div class="mb-2 space-y-16">
<Card.Root class="mt-4 max-w-full border border-secondary">
<Card.Content class="grid gap-4 p-2">
<div class="flex justify-between">
<p
class="text-background-on prose prose-main text-sm font-medium leading-8 tracking-widest"
>
Waiting on your response...
</p>
<Loader class="prose" />
</div>
</Card.Content>
</Card.Root>

<form class="relative flex w-full max-w-full items-center">
<Input
bind:value={newMessageContent}
on:input={handleInputChange}
on:keydown={handleKeyDown}
class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-6 text-sm shadow-sm ring-offset-0 transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50"
placeholder="Join the conversation by typing a message..."
/>
<Button
variant="ghost"
class="hover:bg-default absolute right-0 hover:scale-95"
disabled={newMessageContent.length === 0}
on:click={sendMessage}
>
<Send class="hover:text-primary" />
</Button>
</form>
{:else if sessionId && maeveId}
<Chat {maeveId} {sessionId} {messages} {awaitingReply} />
<div
class="absolute top-0 mx-auto flex h-min w-full flex-col items-center justify-center bg-transparent p-4 backdrop-blur"
>
<Button on:click={runMaeve}>Start New Session</Button>
</div>
{:else if maeveId}
<div
class="xl:prose-md prose prose-sm prose-main mx-auto flex h-screen max-w-none flex-col items-center justify-center gap-4 px-12 text-center md:prose-base 2xl:prose-lg"
>
<h1>It looks like you don't have session yet...</h1>
<Button on:click={runMaeve}>Run Your Maeve!</Button>
</div>
{:else}
<div
class="xl:prose-md prose prose-sm prose-main mx-auto flex h-screen max-w-none flex-col items-center justify-center gap-4 px-12 text-center md:prose-base 2xl:prose-lg"
>
<h1>It looks like you haven't created a maeve yet...</h1>
<Button on:click={redirectToCreateMaeve}>Go Create One!</Button>
</div>
{/if}
<div class="absolute bottom-1 mx-auto flex h-min w-full flex-col items-center justify-center">
<code class="text-muted">debug:</code>
<code class="text-muted">maeve id: {maeveId} - session id: {sessionId}</code>
</div>
Loading

0 comments on commit bf8b19c

Please sign in to comment.