Skip to content

Commit

Permalink
feat(assistants): remove intermediate modal (#1516)
Browse files Browse the repository at this point in the history
* feat(assistants): remove intermediate modal

* fix: remove waterfall

* fix: correctly set assistant when going to assistant page
  • Loading branch information
nsarrazin authored Nov 7, 2024
1 parent 7e32421 commit f1da644
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 122 deletions.
28 changes: 25 additions & 3 deletions src/routes/assistant/[assistantId]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { base } from "$app/paths";
import { collections } from "$lib/server/database";
import { redirect } from "@sveltejs/kit";
import { ObjectId } from "mongodb";
import { authCondition } from "$lib/server/auth.js";

export const load = async ({ params }) => {
export async function load({ params, locals }) {
try {
const assistant = await collections.assistants.findOne({
_id: new ObjectId(params.assistantId),
Expand All @@ -13,8 +14,29 @@ export const load = async ({ params }) => {
redirect(302, `${base}`);
}

return { assistant: JSON.parse(JSON.stringify(assistant)) };
if (locals.user?._id ?? locals.sessionId) {
await collections.settings.updateOne(
authCondition(locals),
{
$set: {
activeModel: assistant._id.toString(),
updatedAt: new Date(),
},
$push: { assistants: assistant._id },
$setOnInsert: {
createdAt: new Date(),
},
},
{
upsert: true,
}
);
}

return {
assistant: JSON.parse(JSON.stringify(assistant)),
};
} catch {
redirect(302, `${base}`);
}
};
}
186 changes: 67 additions & 119 deletions src/routes/assistant/[assistantId]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,26 +1,70 @@
<script lang="ts">
import { page } from "$app/stores";
import { base } from "$app/paths";
import { clickOutside } from "$lib/actions/clickOutside";
import { afterNavigate, goto } from "$app/navigation";
import { useSettingsStore } from "$lib/stores/settings";
import type { PageData } from "./$types";
import { applyAction, enhance } from "$app/forms";
import { goto } from "$app/navigation";
import { onMount } from "svelte";
import { env as envPublic } from "$env/dynamic/public";
import { page } from "$app/stores";
import IconGear from "~icons/bi/gear-fill";
import ChatWindow from "$lib/components/chat/ChatWindow.svelte";
import { findCurrentModel } from "$lib/utils/models";
import { useSettingsStore } from "$lib/stores/settings";
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
import { pendingMessage } from "$lib/stores/pendingMessage";
export let data;
let loading = false;
let files: File[] = [];
const settings = useSettingsStore();
const modelId = $page.params.model;
async function createConversation(message: string) {
try {
loading = true;
const res = await fetch(`${base}/conversation`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
model: data.assistant.modelId,
assistantId: data.assistant._id,
}),
});
if (!res.ok) {
error.set("Error while creating conversation, try again.");
console.error("Error while creating conversation: " + (await res.text()));
return;
}
export let data: PageData;
const { conversationId } = await res.json();
let previousPage: string = base;
// Ugly hack to use a store as temp storage, feel free to improve ^^
pendingMessage.set({
content: message,
files,
});
afterNavigate(({ from }) => {
if (!from?.url.pathname.includes("settings")) {
previousPage = from?.url.toString() || previousPage;
// invalidateAll to update list of conversations
await goto(`${base}/conversation/${conversationId}`, { invalidateAll: true });
} catch (err) {
error.set(ERROR_MESSAGES.default);
console.error(err);
} finally {
loading = false;
}
});
}
const settings = useSettingsStore();
onMount(async () => {
settings.instantSet({
activeModel: modelId,
});
const query = $page.url.searchParams.get("q");
if (query) createConversation(query);
});
</script>

<svelte:head>
Expand All @@ -39,107 +83,11 @@
<meta name="twitter:card" content="summary_large_image" />
</svelte:head>

<div
class="fixed inset-0 z-20 flex items-center justify-center bg-black/80 backdrop-blur-sm dark:bg-black/50"
>
<dialog
open
use:clickOutside={() => {
goto(previousPage);
}}
class="flex flex-col content-center items-center gap-x-10 gap-y-3 overflow-hidden rounded-2xl bg-white p-4 pt-6 text-center shadow-2xl outline-none max-sm:w-[85dvw] max-sm:px-6 md:w-96 md:grid-cols-3 md:grid-rows-[auto,1fr] md:p-8"
>
<div class="absolute right-0 top-0 m-6">
<form
method="POST"
action="{base}/settings/assistants/{data.assistant._id}?/subscribe"
class="w-full"
use:enhance={() => {
return async ({ result }) => {
// `result` is an `ActionResult` object
if (result.type === "success") {
$settings.activeModel = data.assistant._id;
await goto(`${base}/settings/assistants/${data.assistant._id}`, {
invalidateAll: true,
});
} else {
await applyAction(result);
}
};
}}
>
<button
class="flex items-center rounded-full border border-gray-200 px-2.5 py-1 text-sm text-gray-900 hover:bg-gray-100"
name="Settings"
type="submit"
>
<IconGear class="mr-1.5 text-xxs" />
Settings
</button>
</form>
</div>
{#if data.assistant.avatar}
<img
class="size-16 flex-none rounded-full object-cover sm:size-24"
src="{base}/settings/assistants/{data.assistant._id}/avatar.jpg?hash={data.assistant
.avatar}"
alt="avatar"
/>
{:else}
<div
class="flex size-16 flex-none items-center justify-center rounded-full bg-gray-300 text-2xl font-bold uppercase text-gray-500 sm:size-24"
>
{data.assistant.name[0]}
</div>
{/if}
<h1 class="text-balance text-xl font-bold">
{data.assistant.name}
</h1>
{#if data.assistant.description}
<h3 class="line-clamp-6 text-balance text-sm text-gray-500">
{data.assistant.description}
</h3>
{/if}
{#if data.assistant.createdByName}
<p class="mt-2 text-sm text-gray-500">
Created by <a
class="hover:underline"
href="{base}/assistants?user={data.assistant.createdByName}"
>
{data.assistant.createdByName}
</a>
</p>
{/if}
<button
class="mt-4 w-full rounded-full bg-gray-200 px-4 py-2 font-semibold text-gray-700"
on:click={() => {
goto(previousPage);
}}
>
Cancel
</button>
<form
method="POST"
action="{base}/settings/assistants/{data.assistant._id}?/subscribe"
class="w-full"
use:enhance={() => {
return async ({ result }) => {
// `result` is an `ActionResult` object
if (result.type === "success") {
$settings.activeModel = data.assistant._id;
goto(`${base}` || "/");
} else {
await applyAction(result);
}
};
}}
>
<button
type="submit"
class=" w-full rounded-full bg-black px-4 py-3 font-semibold text-white"
>
Start chatting
</button>
</form>
</dialog>
</div>
<ChatWindow
on:message={(ev) => createConversation(ev.detail)}
{loading}
currentModel={findCurrentModel([...data.models, ...data.oldModels], data.assistant.modelId)}
assistant={data.assistant}
models={data.models}
bind:files
/>

0 comments on commit f1da644

Please sign in to comment.