nsarrazin HF Staff commited on
Commit
4f1e27f
·
unverified ·
1 Parent(s): 8214a6c

feat(assistants): remove intermediate modal (#1516)

Browse files

* feat(assistants): remove intermediate modal

* fix: remove waterfall

* fix: correctly set assistant when going to assistant page

src/routes/assistant/[assistantId]/+page.server.ts CHANGED
@@ -2,8 +2,9 @@ import { base } from "$app/paths";
2
  import { collections } from "$lib/server/database";
3
  import { redirect } from "@sveltejs/kit";
4
  import { ObjectId } from "mongodb";
 
5
 
6
- export const load = async ({ params }) => {
7
  try {
8
  const assistant = await collections.assistants.findOne({
9
  _id: new ObjectId(params.assistantId),
@@ -13,8 +14,29 @@ export const load = async ({ params }) => {
13
  redirect(302, `${base}`);
14
  }
15
 
16
- return { assistant: JSON.parse(JSON.stringify(assistant)) };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  } catch {
18
  redirect(302, `${base}`);
19
  }
20
- };
 
2
  import { collections } from "$lib/server/database";
3
  import { redirect } from "@sveltejs/kit";
4
  import { ObjectId } from "mongodb";
5
+ import { authCondition } from "$lib/server/auth.js";
6
 
7
+ export async function load({ params, locals }) {
8
  try {
9
  const assistant = await collections.assistants.findOne({
10
  _id: new ObjectId(params.assistantId),
 
14
  redirect(302, `${base}`);
15
  }
16
 
17
+ if (locals.user?._id ?? locals.sessionId) {
18
+ await collections.settings.updateOne(
19
+ authCondition(locals),
20
+ {
21
+ $set: {
22
+ activeModel: assistant._id.toString(),
23
+ updatedAt: new Date(),
24
+ },
25
+ $push: { assistants: assistant._id },
26
+ $setOnInsert: {
27
+ createdAt: new Date(),
28
+ },
29
+ },
30
+ {
31
+ upsert: true,
32
+ }
33
+ );
34
+ }
35
+
36
+ return {
37
+ assistant: JSON.parse(JSON.stringify(assistant)),
38
+ };
39
  } catch {
40
  redirect(302, `${base}`);
41
  }
42
+ }
src/routes/assistant/[assistantId]/+page.svelte CHANGED
@@ -1,26 +1,70 @@
1
  <script lang="ts">
 
2
  import { base } from "$app/paths";
3
- import { clickOutside } from "$lib/actions/clickOutside";
4
- import { afterNavigate, goto } from "$app/navigation";
5
-
6
- import { useSettingsStore } from "$lib/stores/settings";
7
- import type { PageData } from "./$types";
8
- import { applyAction, enhance } from "$app/forms";
9
  import { env as envPublic } from "$env/dynamic/public";
10
- import { page } from "$app/stores";
11
- import IconGear from "~icons/bi/gear-fill";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- export let data: PageData;
14
 
15
- let previousPage: string = base;
 
 
 
 
16
 
17
- afterNavigate(({ from }) => {
18
- if (!from?.url.pathname.includes("settings")) {
19
- previousPage = from?.url.toString() || previousPage;
 
 
 
 
20
  }
21
- });
22
 
23
- const settings = useSettingsStore();
 
 
 
 
 
 
 
24
  </script>
25
 
26
  <svelte:head>
@@ -39,107 +83,11 @@
39
  <meta name="twitter:card" content="summary_large_image" />
40
  </svelte:head>
41
 
42
- <div
43
- class="fixed inset-0 z-20 flex items-center justify-center bg-black/80 backdrop-blur-sm dark:bg-black/50"
44
- >
45
- <dialog
46
- open
47
- use:clickOutside={() => {
48
- goto(previousPage);
49
- }}
50
- 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"
51
- >
52
- <div class="absolute right-0 top-0 m-6">
53
- <form
54
- method="POST"
55
- action="{base}/settings/assistants/{data.assistant._id}?/subscribe"
56
- class="w-full"
57
- use:enhance={() => {
58
- return async ({ result }) => {
59
- // `result` is an `ActionResult` object
60
- if (result.type === "success") {
61
- $settings.activeModel = data.assistant._id;
62
- await goto(`${base}/settings/assistants/${data.assistant._id}`, {
63
- invalidateAll: true,
64
- });
65
- } else {
66
- await applyAction(result);
67
- }
68
- };
69
- }}
70
- >
71
- <button
72
- class="flex items-center rounded-full border border-gray-200 px-2.5 py-1 text-sm text-gray-900 hover:bg-gray-100"
73
- name="Settings"
74
- type="submit"
75
- >
76
- <IconGear class="mr-1.5 text-xxs" />
77
- Settings
78
- </button>
79
- </form>
80
- </div>
81
- {#if data.assistant.avatar}
82
- <img
83
- class="size-16 flex-none rounded-full object-cover sm:size-24"
84
- src="{base}/settings/assistants/{data.assistant._id}/avatar.jpg?hash={data.assistant
85
- .avatar}"
86
- alt="avatar"
87
- />
88
- {:else}
89
- <div
90
- 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"
91
- >
92
- {data.assistant.name[0]}
93
- </div>
94
- {/if}
95
- <h1 class="text-balance text-xl font-bold">
96
- {data.assistant.name}
97
- </h1>
98
- {#if data.assistant.description}
99
- <h3 class="line-clamp-6 text-balance text-sm text-gray-500">
100
- {data.assistant.description}
101
- </h3>
102
- {/if}
103
- {#if data.assistant.createdByName}
104
- <p class="mt-2 text-sm text-gray-500">
105
- Created by <a
106
- class="hover:underline"
107
- href="{base}/assistants?user={data.assistant.createdByName}"
108
- >
109
- {data.assistant.createdByName}
110
- </a>
111
- </p>
112
- {/if}
113
- <button
114
- class="mt-4 w-full rounded-full bg-gray-200 px-4 py-2 font-semibold text-gray-700"
115
- on:click={() => {
116
- goto(previousPage);
117
- }}
118
- >
119
- Cancel
120
- </button>
121
- <form
122
- method="POST"
123
- action="{base}/settings/assistants/{data.assistant._id}?/subscribe"
124
- class="w-full"
125
- use:enhance={() => {
126
- return async ({ result }) => {
127
- // `result` is an `ActionResult` object
128
- if (result.type === "success") {
129
- $settings.activeModel = data.assistant._id;
130
- goto(`${base}` || "/");
131
- } else {
132
- await applyAction(result);
133
- }
134
- };
135
- }}
136
- >
137
- <button
138
- type="submit"
139
- class=" w-full rounded-full bg-black px-4 py-3 font-semibold text-white"
140
- >
141
- Start chatting
142
- </button>
143
- </form>
144
- </dialog>
145
- </div>
 
1
  <script lang="ts">
2
+ import { page } from "$app/stores";
3
  import { base } from "$app/paths";
4
+ import { goto } from "$app/navigation";
5
+ import { onMount } from "svelte";
 
 
 
 
6
  import { env as envPublic } from "$env/dynamic/public";
7
+ import ChatWindow from "$lib/components/chat/ChatWindow.svelte";
8
+ import { findCurrentModel } from "$lib/utils/models";
9
+ import { useSettingsStore } from "$lib/stores/settings";
10
+ import { ERROR_MESSAGES, error } from "$lib/stores/errors";
11
+ import { pendingMessage } from "$lib/stores/pendingMessage";
12
+
13
+ export let data;
14
+
15
+ let loading = false;
16
+ let files: File[] = [];
17
+
18
+ const settings = useSettingsStore();
19
+ const modelId = $page.params.model;
20
+
21
+ async function createConversation(message: string) {
22
+ try {
23
+ loading = true;
24
+
25
+ const res = await fetch(`${base}/conversation`, {
26
+ method: "POST",
27
+ headers: {
28
+ "Content-Type": "application/json",
29
+ },
30
+ body: JSON.stringify({
31
+ model: data.assistant.modelId,
32
+ assistantId: data.assistant._id,
33
+ }),
34
+ });
35
+
36
+ if (!res.ok) {
37
+ error.set("Error while creating conversation, try again.");
38
+ console.error("Error while creating conversation: " + (await res.text()));
39
+ return;
40
+ }
41
 
42
+ const { conversationId } = await res.json();
43
 
44
+ // Ugly hack to use a store as temp storage, feel free to improve ^^
45
+ pendingMessage.set({
46
+ content: message,
47
+ files,
48
+ });
49
 
50
+ // invalidateAll to update list of conversations
51
+ await goto(`${base}/conversation/${conversationId}`, { invalidateAll: true });
52
+ } catch (err) {
53
+ error.set(ERROR_MESSAGES.default);
54
+ console.error(err);
55
+ } finally {
56
+ loading = false;
57
  }
58
+ }
59
 
60
+ onMount(async () => {
61
+ settings.instantSet({
62
+ activeModel: modelId,
63
+ });
64
+
65
+ const query = $page.url.searchParams.get("q");
66
+ if (query) createConversation(query);
67
+ });
68
  </script>
69
 
70
  <svelte:head>
 
83
  <meta name="twitter:card" content="summary_large_image" />
84
  </svelte:head>
85
 
86
+ <ChatWindow
87
+ on:message={(ev) => createConversation(ev.detail)}
88
+ {loading}
89
+ currentModel={findCurrentModel([...data.models, ...data.oldModels], data.assistant.modelId)}
90
+ assistant={data.assistant}
91
+ models={data.models}
92
+ bind:files
93
+ />