Spaces:
				
			
			
	
			
			
		Paused
		
	
	
	
			
			
	
	
	
	
		
		
		Paused
		
	Remove shared routes (#478)
Browse files* rm shared route
* fix sharing of shared convs
- src/lib/shareConversation.ts +21 -15
- src/lib/stores/pendingMessageIdToRetry.ts +0 -4
- src/lib/utils/getShareUrl.ts +6 -0
- src/routes/conversation/[id]/+page.server.ts +35 -19
- src/routes/conversation/[id]/+page.svelte +70 -11
- src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts +16 -9
- src/routes/conversation/[id]/share/+server.ts +1 -6
- src/routes/r/[id]/+page.server.ts +0 -20
- src/routes/r/[id]/+page.svelte +0 -87
- src/routes/r/[id]/+page.ts +5 -0
- src/routes/r/[id]/message/[messageId]/prompt/+server.ts +0 -47
    	
        src/lib/shareConversation.ts
    CHANGED
    
    | @@ -1,25 +1,31 @@ | |
| 1 | 
             
            import { base } from "$app/paths";
         | 
| 2 | 
             
            import { ERROR_MESSAGES, error } from "$lib/stores/errors";
         | 
| 3 | 
             
            import { share } from "./utils/share";
         | 
| 4 | 
            -
             | 
|  | |
|  | |
| 5 | 
             
            export async function shareConversation(id: string, title: string) {
         | 
| 6 | 
             
            	try {
         | 
| 7 | 
            -
            		 | 
| 8 | 
            -
            			 | 
| 9 | 
            -
            			 | 
| 10 | 
            -
             | 
| 11 | 
            -
            			} | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
            			 | 
| 17 | 
            -
            			return;
         | 
| 18 | 
            -
            		}
         | 
| 19 |  | 
| 20 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
| 21 |  | 
| 22 | 
            -
             | 
|  | |
|  | |
| 23 | 
             
            	} catch (err) {
         | 
| 24 | 
             
            		error.set(ERROR_MESSAGES.default);
         | 
| 25 | 
             
            		console.error(err);
         | 
|  | |
| 1 | 
             
            import { base } from "$app/paths";
         | 
| 2 | 
             
            import { ERROR_MESSAGES, error } from "$lib/stores/errors";
         | 
| 3 | 
             
            import { share } from "./utils/share";
         | 
| 4 | 
            +
            import { page } from "$app/stores";
         | 
| 5 | 
            +
            import { get } from "svelte/store";
         | 
| 6 | 
            +
            import { getShareUrl } from "./utils/getShareUrl";
         | 
| 7 | 
             
            export async function shareConversation(id: string, title: string) {
         | 
| 8 | 
             
            	try {
         | 
| 9 | 
            +
            		if (id.length === 7) {
         | 
| 10 | 
            +
            			const url = get(page).url;
         | 
| 11 | 
            +
            			share(getShareUrl(url, id), title);
         | 
| 12 | 
            +
            		} else {
         | 
| 13 | 
            +
            			const res = await fetch(`${base}/conversation/${id}/share`, {
         | 
| 14 | 
            +
            				method: "POST",
         | 
| 15 | 
            +
            				headers: {
         | 
| 16 | 
            +
            					"Content-Type": "application/json",
         | 
| 17 | 
            +
            				},
         | 
| 18 | 
            +
            			});
         | 
|  | |
|  | |
| 19 |  | 
| 20 | 
            +
            			if (!res.ok) {
         | 
| 21 | 
            +
            				error.set("Error while sharing conversation, try again.");
         | 
| 22 | 
            +
            				console.error("Error while sharing conversation: " + (await res.text()));
         | 
| 23 | 
            +
            				return;
         | 
| 24 | 
            +
            			}
         | 
| 25 |  | 
| 26 | 
            +
            			const { url } = await res.json();
         | 
| 27 | 
            +
            			share(url, title);
         | 
| 28 | 
            +
            		}
         | 
| 29 | 
             
            	} catch (err) {
         | 
| 30 | 
             
            		error.set(ERROR_MESSAGES.default);
         | 
| 31 | 
             
            		console.error(err);
         | 
    	
        src/lib/stores/pendingMessageIdToRetry.ts
    DELETED
    
    | @@ -1,4 +0,0 @@ | |
| 1 | 
            -
            import type { Message } from "$lib/types/Message";
         | 
| 2 | 
            -
            import { writable } from "svelte/store";
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            export const pendingMessageIdToRetry = writable<Message["id"] | null>(null);
         | 
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        src/lib/utils/getShareUrl.ts
    ADDED
    
    | @@ -0,0 +1,6 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import { base } from "$app/paths";
         | 
| 2 | 
            +
            import { PUBLIC_ORIGIN, PUBLIC_SHARE_PREFIX } from "$env/static/public";
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            export function getShareUrl(url: URL, shareId: string): string {
         | 
| 5 | 
            +
            	return `${PUBLIC_SHARE_PREFIX || `${PUBLIC_ORIGIN || url.origin}${base}`}/r/${shareId}`;
         | 
| 6 | 
            +
            }
         | 
    	
        src/routes/conversation/[id]/+page.server.ts
    CHANGED
    
    | @@ -5,34 +5,50 @@ import { authCondition } from "$lib/server/auth"; | |
| 5 | 
             
            import { UrlDependency } from "$lib/types/UrlDependency";
         | 
| 6 |  | 
| 7 | 
             
            export const load = async ({ params, depends, locals }) => {
         | 
| 8 | 
            -
            	 | 
| 9 | 
            -
            	 | 
| 10 | 
            -
            		_id: new ObjectId(params.id),
         | 
| 11 | 
            -
            		...authCondition(locals),
         | 
| 12 | 
            -
            	});
         | 
| 13 |  | 
| 14 | 
            -
            	 | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 15 |  | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
            			(await collections.conversations.countDocuments({
         | 
| 19 | 
            -
            				_id: new ObjectId(params.id),
         | 
| 20 | 
            -
            			})) !== 0;
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            		if (conversationExists) {
         | 
| 23 | 
            -
            			throw error(
         | 
| 24 | 
            -
            				403,
         | 
| 25 | 
            -
            				"You don't have access to this conversation. If someone gave you this link, ask them to use the 'share' feature instead."
         | 
| 26 | 
            -
            			);
         | 
| 27 | 
             
            		}
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 28 |  | 
| 29 | 
            -
            		 | 
| 30 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 31 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 32 | 
             
            	return {
         | 
| 33 | 
             
            		messages: conversation.messages,
         | 
| 34 | 
             
            		title: conversation.title,
         | 
| 35 | 
             
            		model: conversation.model,
         | 
| 36 | 
             
            		preprompt: conversation.preprompt,
         | 
|  | |
| 37 | 
             
            	};
         | 
| 38 | 
             
            };
         | 
|  | |
| 5 | 
             
            import { UrlDependency } from "$lib/types/UrlDependency";
         | 
| 6 |  | 
| 7 | 
             
            export const load = async ({ params, depends, locals }) => {
         | 
| 8 | 
            +
            	let conversation;
         | 
| 9 | 
            +
            	let shared = false;
         | 
|  | |
|  | |
|  | |
| 10 |  | 
| 11 | 
            +
            	// if the conver
         | 
| 12 | 
            +
            	if (params.id.length === 7) {
         | 
| 13 | 
            +
            		// shared link of length 7
         | 
| 14 | 
            +
            		conversation = await collections.sharedConversations.findOne({
         | 
| 15 | 
            +
            			_id: params.id,
         | 
| 16 | 
            +
            		});
         | 
| 17 | 
            +
            		shared = true;
         | 
| 18 |  | 
| 19 | 
            +
            		if (!conversation) {
         | 
| 20 | 
            +
            			throw error(404, "Conversation not found");
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 21 | 
             
            		}
         | 
| 22 | 
            +
            	} else {
         | 
| 23 | 
            +
            		// todo: add validation on params.id
         | 
| 24 | 
            +
            		conversation = await collections.conversations.findOne({
         | 
| 25 | 
            +
            			_id: new ObjectId(params.id),
         | 
| 26 | 
            +
            			...authCondition(locals),
         | 
| 27 | 
            +
            		});
         | 
| 28 |  | 
| 29 | 
            +
            		depends(UrlDependency.Conversation);
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            		if (!conversation) {
         | 
| 32 | 
            +
            			const conversationExists =
         | 
| 33 | 
            +
            				(await collections.conversations.countDocuments({
         | 
| 34 | 
            +
            					_id: new ObjectId(params.id),
         | 
| 35 | 
            +
            				})) !== 0;
         | 
| 36 |  | 
| 37 | 
            +
            			if (conversationExists) {
         | 
| 38 | 
            +
            				throw error(
         | 
| 39 | 
            +
            					403,
         | 
| 40 | 
            +
            					"You don't have access to this conversation. If someone gave you this link, ask them to use the 'share' feature instead."
         | 
| 41 | 
            +
            				);
         | 
| 42 | 
            +
            			}
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            			throw error(404, "Conversation not found.");
         | 
| 45 | 
            +
            		}
         | 
| 46 | 
            +
            	}
         | 
| 47 | 
             
            	return {
         | 
| 48 | 
             
            		messages: conversation.messages,
         | 
| 49 | 
             
            		title: conversation.title,
         | 
| 50 | 
             
            		model: conversation.model,
         | 
| 51 | 
             
            		preprompt: conversation.preprompt,
         | 
| 52 | 
            +
            		shared,
         | 
| 53 | 
             
            	};
         | 
| 54 | 
             
            };
         | 
    	
        src/routes/conversation/[id]/+page.svelte
    CHANGED
    
    | @@ -1,10 +1,9 @@ | |
| 1 | 
             
            <script lang="ts">
         | 
| 2 | 
             
            	import ChatWindow from "$lib/components/chat/ChatWindow.svelte";
         | 
| 3 | 
             
            	import { pendingMessage } from "$lib/stores/pendingMessage";
         | 
| 4 | 
            -
            	import { pendingMessageIdToRetry } from "$lib/stores/pendingMessageIdToRetry";
         | 
| 5 | 
             
            	import { onMount } from "svelte";
         | 
| 6 | 
             
            	import { page } from "$app/stores";
         | 
| 7 | 
            -
            	import { invalidate } from "$app/navigation";
         | 
| 8 | 
             
            	import { base } from "$app/paths";
         | 
| 9 | 
             
            	import { shareConversation } from "$lib/shareConversation";
         | 
| 10 | 
             
            	import { UrlDependency } from "$lib/types/UrlDependency";
         | 
| @@ -34,6 +33,35 @@ | |
| 34 | 
             
            	let pending = false;
         | 
| 35 | 
             
            	let loginRequired = false;
         | 
| 36 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 37 | 
             
            	// this function is used to send new message to the backends
         | 
| 38 | 
             
            	async function writeMessage(message: string, messageId = randomUUID()) {
         | 
| 39 | 
             
            		if (!message.trim()) return;
         | 
| @@ -76,6 +104,10 @@ | |
| 76 | 
             
            				throw new Error("Body not defined");
         | 
| 77 | 
             
            			}
         | 
| 78 |  | 
|  | |
|  | |
|  | |
|  | |
| 79 | 
             
            			// eslint-disable-next-line no-undef
         | 
| 80 | 
             
            			const encoder = new TextDecoderStream();
         | 
| 81 | 
             
            			const reader = response?.body?.pipeThrough(encoder).getReader();
         | 
| @@ -84,7 +116,7 @@ | |
| 84 | 
             
            			// this is a bit ugly
         | 
| 85 | 
             
            			// we read the stream until we get the final answer
         | 
| 86 | 
             
            			while (finalAnswer === "") {
         | 
| 87 | 
            -
            				 | 
| 88 |  | 
| 89 | 
             
            				// check for abort
         | 
| 90 | 
             
            				if (isAborted) {
         | 
| @@ -111,6 +143,7 @@ | |
| 111 | 
             
            							let update = JSON.parse(el) as MessageUpdate;
         | 
| 112 | 
             
            							if (update.type === "finalAnswer") {
         | 
| 113 | 
             
            								finalAnswer = update.text;
         | 
|  | |
| 114 | 
             
            								invalidate(UrlDependency.Conversation);
         | 
| 115 | 
             
            							} else if (update.type === "stream") {
         | 
| 116 | 
             
            								pending = false;
         | 
| @@ -128,6 +161,8 @@ | |
| 128 | 
             
            								}
         | 
| 129 | 
             
            							} else if (update.type === "webSearch") {
         | 
| 130 | 
             
            								webSearchMessages = [...webSearchMessages, update];
         | 
|  | |
|  | |
| 131 | 
             
            							}
         | 
| 132 | 
             
            						} catch (parseError) {
         | 
| 133 | 
             
            							// in case of parsing error we wait for the next message
         | 
| @@ -185,15 +220,38 @@ | |
| 185 | 
             
            	}
         | 
| 186 |  | 
| 187 | 
             
            	onMount(async () => {
         | 
|  | |
| 188 | 
             
            		if ($pendingMessage) {
         | 
| 189 | 
            -
            			 | 
| 190 | 
            -
            			const messageId = $pendingMessageIdToRetry || undefined;
         | 
| 191 | 
            -
            			$pendingMessage = "";
         | 
| 192 | 
            -
            			$pendingMessageIdToRetry = null;
         | 
| 193 | 
            -
             | 
| 194 | 
            -
            			writeMessage(val, messageId);
         | 
| 195 | 
             
            		}
         | 
| 196 | 
             
            	});
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 197 | 
             
            	$: $page.params.id, (isAborted = true);
         | 
| 198 | 
             
            	$: title = data.conversations.find((conv) => conv.id === $page.params.id)?.title ?? data.title;
         | 
| 199 |  | 
| @@ -218,10 +276,11 @@ | |
| 218 | 
             
            	{loading}
         | 
| 219 | 
             
            	{pending}
         | 
| 220 | 
             
            	{messages}
         | 
|  | |
| 221 | 
             
            	preprompt={data.preprompt}
         | 
| 222 | 
             
            	bind:webSearchMessages
         | 
| 223 | 
            -
            	on:message={ | 
| 224 | 
            -
            	on:retry={ | 
| 225 | 
             
            	on:vote={(event) => voteMessage(event.detail.score, event.detail.id)}
         | 
| 226 | 
             
            	on:share={() => shareConversation($page.params.id, data.title)}
         | 
| 227 | 
             
            	on:stop={() => (isAborted = true)}
         | 
|  | |
| 1 | 
             
            <script lang="ts">
         | 
| 2 | 
             
            	import ChatWindow from "$lib/components/chat/ChatWindow.svelte";
         | 
| 3 | 
             
            	import { pendingMessage } from "$lib/stores/pendingMessage";
         | 
|  | |
| 4 | 
             
            	import { onMount } from "svelte";
         | 
| 5 | 
             
            	import { page } from "$app/stores";
         | 
| 6 | 
            +
            	import { goto, invalidate } from "$app/navigation";
         | 
| 7 | 
             
            	import { base } from "$app/paths";
         | 
| 8 | 
             
            	import { shareConversation } from "$lib/shareConversation";
         | 
| 9 | 
             
            	import { UrlDependency } from "$lib/types/UrlDependency";
         | 
|  | |
| 33 | 
             
            	let pending = false;
         | 
| 34 | 
             
            	let loginRequired = false;
         | 
| 35 |  | 
| 36 | 
            +
            	async function convFromShared() {
         | 
| 37 | 
            +
            		try {
         | 
| 38 | 
            +
            			loading = true;
         | 
| 39 | 
            +
            			const res = await fetch(`${base}/conversation`, {
         | 
| 40 | 
            +
            				method: "POST",
         | 
| 41 | 
            +
            				headers: {
         | 
| 42 | 
            +
            					"Content-Type": "application/json",
         | 
| 43 | 
            +
            				},
         | 
| 44 | 
            +
            				body: JSON.stringify({
         | 
| 45 | 
            +
            					fromShare: $page.params.id,
         | 
| 46 | 
            +
            					model: data.model,
         | 
| 47 | 
            +
            				}),
         | 
| 48 | 
            +
            			});
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            			if (!res.ok) {
         | 
| 51 | 
            +
            				error.set("Error while creating conversation, try again.");
         | 
| 52 | 
            +
            				console.error("Error while creating conversation: " + (await res.text()));
         | 
| 53 | 
            +
            				return;
         | 
| 54 | 
            +
            			}
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            			const { conversationId } = await res.json();
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            			return conversationId;
         | 
| 59 | 
            +
            		} catch (err) {
         | 
| 60 | 
            +
            			error.set(ERROR_MESSAGES.default);
         | 
| 61 | 
            +
            			console.error(String(err));
         | 
| 62 | 
            +
            			throw err;
         | 
| 63 | 
            +
            		}
         | 
| 64 | 
            +
            	}
         | 
| 65 | 
             
            	// this function is used to send new message to the backends
         | 
| 66 | 
             
            	async function writeMessage(message: string, messageId = randomUUID()) {
         | 
| 67 | 
             
            		if (!message.trim()) return;
         | 
|  | |
| 104 | 
             
            				throw new Error("Body not defined");
         | 
| 105 | 
             
            			}
         | 
| 106 |  | 
| 107 | 
            +
            			if (!response.ok) {
         | 
| 108 | 
            +
            				error.set((await response.json())?.message);
         | 
| 109 | 
            +
            				return;
         | 
| 110 | 
            +
            			}
         | 
| 111 | 
             
            			// eslint-disable-next-line no-undef
         | 
| 112 | 
             
            			const encoder = new TextDecoderStream();
         | 
| 113 | 
             
            			const reader = response?.body?.pipeThrough(encoder).getReader();
         | 
|  | |
| 116 | 
             
            			// this is a bit ugly
         | 
| 117 | 
             
            			// we read the stream until we get the final answer
         | 
| 118 | 
             
            			while (finalAnswer === "") {
         | 
| 119 | 
            +
            				await new Promise((r) => setTimeout(r, 25));
         | 
| 120 |  | 
| 121 | 
             
            				// check for abort
         | 
| 122 | 
             
            				if (isAborted) {
         | 
|  | |
| 143 | 
             
            							let update = JSON.parse(el) as MessageUpdate;
         | 
| 144 | 
             
            							if (update.type === "finalAnswer") {
         | 
| 145 | 
             
            								finalAnswer = update.text;
         | 
| 146 | 
            +
            								reader.cancel();
         | 
| 147 | 
             
            								invalidate(UrlDependency.Conversation);
         | 
| 148 | 
             
            							} else if (update.type === "stream") {
         | 
| 149 | 
             
            								pending = false;
         | 
|  | |
| 161 | 
             
            								}
         | 
| 162 | 
             
            							} else if (update.type === "webSearch") {
         | 
| 163 | 
             
            								webSearchMessages = [...webSearchMessages, update];
         | 
| 164 | 
            +
            							} else {
         | 
| 165 | 
            +
            								console.log();
         | 
| 166 | 
             
            							}
         | 
| 167 | 
             
            						} catch (parseError) {
         | 
| 168 | 
             
            							// in case of parsing error we wait for the next message
         | 
|  | |
| 220 | 
             
            	}
         | 
| 221 |  | 
| 222 | 
             
            	onMount(async () => {
         | 
| 223 | 
            +
            		// only used in case of creating new conversations (from the parent POST endpoint)
         | 
| 224 | 
             
            		if ($pendingMessage) {
         | 
| 225 | 
            +
            			writeMessage($pendingMessage);
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 226 | 
             
            		}
         | 
| 227 | 
             
            	});
         | 
| 228 | 
            +
             | 
| 229 | 
            +
            	async function onMessage(event: CustomEvent<string>) {
         | 
| 230 | 
            +
            		if (!data.shared) {
         | 
| 231 | 
            +
            			writeMessage(event.detail);
         | 
| 232 | 
            +
            		} else {
         | 
| 233 | 
            +
            			convFromShared()
         | 
| 234 | 
            +
            				.then(async (convId) => {
         | 
| 235 | 
            +
            					await goto(`${base}/conversation/${convId}`, { invalidateAll: true });
         | 
| 236 | 
            +
            				})
         | 
| 237 | 
            +
            				.then(() => writeMessage(event.detail))
         | 
| 238 | 
            +
            				.finally(() => (loading = false));
         | 
| 239 | 
            +
            		}
         | 
| 240 | 
            +
            	}
         | 
| 241 | 
            +
             | 
| 242 | 
            +
            	async function onRetry(event: CustomEvent<{ id: Message["id"]; content: string }>) {
         | 
| 243 | 
            +
            		if (!data.shared) {
         | 
| 244 | 
            +
            			writeMessage(event.detail.content, event.detail.id);
         | 
| 245 | 
            +
            		} else {
         | 
| 246 | 
            +
            			convFromShared()
         | 
| 247 | 
            +
            				.then(async (convId) => {
         | 
| 248 | 
            +
            					await goto(`${base}/conversation/${convId}`, { invalidateAll: true });
         | 
| 249 | 
            +
            				})
         | 
| 250 | 
            +
            				.then(() => writeMessage(event.detail.content, event.detail.id))
         | 
| 251 | 
            +
            				.finally(() => (loading = false));
         | 
| 252 | 
            +
            		}
         | 
| 253 | 
            +
            	}
         | 
| 254 | 
            +
             | 
| 255 | 
             
            	$: $page.params.id, (isAborted = true);
         | 
| 256 | 
             
            	$: title = data.conversations.find((conv) => conv.id === $page.params.id)?.title ?? data.title;
         | 
| 257 |  | 
|  | |
| 276 | 
             
            	{loading}
         | 
| 277 | 
             
            	{pending}
         | 
| 278 | 
             
            	{messages}
         | 
| 279 | 
            +
            	shared={data.shared}
         | 
| 280 | 
             
            	preprompt={data.preprompt}
         | 
| 281 | 
             
            	bind:webSearchMessages
         | 
| 282 | 
            +
            	on:message={onMessage}
         | 
| 283 | 
            +
            	on:retry={onRetry}
         | 
| 284 | 
             
            	on:vote={(event) => voteMessage(event.detail.score, event.detail.id)}
         | 
| 285 | 
             
            	on:share={() => shareConversation($page.params.id, data.title)}
         | 
| 286 | 
             
            	on:stop={() => (isAborted = true)}
         | 
    	
        src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts
    CHANGED
    
    | @@ -6,14 +6,17 @@ import { error } from "@sveltejs/kit"; | |
| 6 | 
             
            import { ObjectId } from "mongodb";
         | 
| 7 |  | 
| 8 | 
             
            export async function GET({ params, locals }) {
         | 
| 9 | 
            -
            	const  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
|  | |
|  | |
|  | |
| 17 | 
             
            		throw error(404, "Conversation not found");
         | 
| 18 | 
             
            	}
         | 
| 19 |  | 
| @@ -31,8 +34,12 @@ export async function GET({ params, locals }) { | |
| 31 | 
             
            		throw error(404, "Conversation model not found");
         | 
| 32 | 
             
            	}
         | 
| 33 |  | 
|  | |
|  | |
| 34 | 
             
            	const prompt = await buildPrompt({
         | 
| 35 | 
            -
            		 | 
|  | |
|  | |
| 36 | 
             
            		model: model,
         | 
| 37 | 
             
            	});
         | 
| 38 |  | 
|  | |
| 6 | 
             
            import { ObjectId } from "mongodb";
         | 
| 7 |  | 
| 8 | 
             
            export async function GET({ params, locals }) {
         | 
| 9 | 
            +
            	const conv =
         | 
| 10 | 
            +
            		params.id.length === 7
         | 
| 11 | 
            +
            			? await collections.sharedConversations.findOne({
         | 
| 12 | 
            +
            					_id: params.id,
         | 
| 13 | 
            +
            			  })
         | 
| 14 | 
            +
            			: await collections.conversations.findOne({
         | 
| 15 | 
            +
            					_id: new ObjectId(params.id),
         | 
| 16 | 
            +
            					...authCondition(locals),
         | 
| 17 | 
            +
            			  });
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            	if (conv === null) {
         | 
| 20 | 
             
            		throw error(404, "Conversation not found");
         | 
| 21 | 
             
            	}
         | 
| 22 |  | 
|  | |
| 34 | 
             
            		throw error(404, "Conversation model not found");
         | 
| 35 | 
             
            	}
         | 
| 36 |  | 
| 37 | 
            +
            	const messagesUpTo = conv.messages.slice(0, messageIndex + 1);
         | 
| 38 | 
            +
             | 
| 39 | 
             
            	const prompt = await buildPrompt({
         | 
| 40 | 
            +
            		preprompt: conv.preprompt,
         | 
| 41 | 
            +
            		webSearch: messagesUpTo[messagesUpTo.length - 1].webSearch,
         | 
| 42 | 
            +
            		messages: messagesUpTo,
         | 
| 43 | 
             
            		model: model,
         | 
| 44 | 
             
            	});
         | 
| 45 |  | 
    	
        src/routes/conversation/[id]/share/+server.ts
    CHANGED
    
    | @@ -1,8 +1,7 @@ | |
| 1 | 
            -
            import { base } from "$app/paths";
         | 
| 2 | 
            -
            import { PUBLIC_ORIGIN, PUBLIC_SHARE_PREFIX } from "$env/static/public";
         | 
| 3 | 
             
            import { authCondition } from "$lib/server/auth";
         | 
| 4 | 
             
            import { collections } from "$lib/server/database";
         | 
| 5 | 
             
            import type { SharedConversation } from "$lib/types/SharedConversation";
         | 
|  | |
| 6 | 
             
            import { hashConv } from "$lib/utils/hashConv";
         | 
| 7 | 
             
            import { error } from "@sveltejs/kit";
         | 
| 8 | 
             
            import { ObjectId } from "mongodb";
         | 
| @@ -51,7 +50,3 @@ export async function POST({ params, url, locals }) { | |
| 51 | 
             
            		{ headers: { "Content-Type": "application/json" } }
         | 
| 52 | 
             
            	);
         | 
| 53 | 
             
            }
         | 
| 54 | 
            -
             | 
| 55 | 
            -
            function getShareUrl(url: URL, shareId: string): string {
         | 
| 56 | 
            -
            	return `${PUBLIC_SHARE_PREFIX || `${PUBLIC_ORIGIN || url.origin}${base}`}/r/${shareId}`;
         | 
| 57 | 
            -
            }
         | 
|  | |
|  | |
|  | |
| 1 | 
             
            import { authCondition } from "$lib/server/auth";
         | 
| 2 | 
             
            import { collections } from "$lib/server/database";
         | 
| 3 | 
             
            import type { SharedConversation } from "$lib/types/SharedConversation";
         | 
| 4 | 
            +
            import { getShareUrl } from "$lib/utils/getShareUrl.js";
         | 
| 5 | 
             
            import { hashConv } from "$lib/utils/hashConv";
         | 
| 6 | 
             
            import { error } from "@sveltejs/kit";
         | 
| 7 | 
             
            import { ObjectId } from "mongodb";
         | 
|  | |
| 50 | 
             
            		{ headers: { "Content-Type": "application/json" } }
         | 
| 51 | 
             
            	);
         | 
| 52 | 
             
            }
         | 
|  | |
|  | |
|  | |
|  | 
    	
        src/routes/r/[id]/+page.server.ts
    DELETED
    
    | @@ -1,20 +0,0 @@ | |
| 1 | 
            -
            import type { PageServerLoad } from "./$types";
         | 
| 2 | 
            -
            import { collections } from "$lib/server/database";
         | 
| 3 | 
            -
            import { error } from "@sveltejs/kit";
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            export const load: PageServerLoad = async ({ params }) => {
         | 
| 6 | 
            -
            	const conversation = await collections.sharedConversations.findOne({
         | 
| 7 | 
            -
            		_id: params.id,
         | 
| 8 | 
            -
            	});
         | 
| 9 | 
            -
             | 
| 10 | 
            -
            	if (!conversation) {
         | 
| 11 | 
            -
            		throw error(404, "Conversation not found");
         | 
| 12 | 
            -
            	}
         | 
| 13 | 
            -
             | 
| 14 | 
            -
            	return {
         | 
| 15 | 
            -
            		preprompt: conversation.preprompt,
         | 
| 16 | 
            -
            		messages: conversation.messages,
         | 
| 17 | 
            -
            		title: conversation.title,
         | 
| 18 | 
            -
            		model: conversation.model,
         | 
| 19 | 
            -
            	};
         | 
| 20 | 
            -
            };
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        src/routes/r/[id]/+page.svelte
    DELETED
    
    | @@ -1,87 +0,0 @@ | |
| 1 | 
            -
            <script lang="ts">
         | 
| 2 | 
            -
            	import { goto } from "$app/navigation";
         | 
| 3 | 
            -
            	import { base } from "$app/paths";
         | 
| 4 | 
            -
            	import { page } from "$app/stores";
         | 
| 5 | 
            -
            	import { PUBLIC_APP_DISCLAIMER } from "$env/static/public";
         | 
| 6 | 
            -
            	import ChatWindow from "$lib/components/chat/ChatWindow.svelte";
         | 
| 7 | 
            -
            	import { ERROR_MESSAGES, error } from "$lib/stores/errors";
         | 
| 8 | 
            -
            	import { pendingMessage } from "$lib/stores/pendingMessage";
         | 
| 9 | 
            -
            	import { pendingMessageIdToRetry } from "$lib/stores/pendingMessageIdToRetry";
         | 
| 10 | 
            -
            	import { findCurrentModel } from "$lib/utils/models";
         | 
| 11 | 
            -
            	import { share } from "$lib/utils/share";
         | 
| 12 | 
            -
            	import type { PageData } from "./$types";
         | 
| 13 | 
            -
             | 
| 14 | 
            -
            	export let data: PageData;
         | 
| 15 | 
            -
             | 
| 16 | 
            -
            	let loading = false;
         | 
| 17 | 
            -
             | 
| 18 | 
            -
            	async function createConversation() {
         | 
| 19 | 
            -
            		try {
         | 
| 20 | 
            -
            			loading = true;
         | 
| 21 | 
            -
            			const res = await fetch(`${base}/conversation`, {
         | 
| 22 | 
            -
            				method: "POST",
         | 
| 23 | 
            -
            				headers: {
         | 
| 24 | 
            -
            					"Content-Type": "application/json",
         | 
| 25 | 
            -
            				},
         | 
| 26 | 
            -
            				body: JSON.stringify({
         | 
| 27 | 
            -
            					fromShare: $page.params.id,
         | 
| 28 | 
            -
            					model: data.model,
         | 
| 29 | 
            -
            				}),
         | 
| 30 | 
            -
            			});
         | 
| 31 | 
            -
             | 
| 32 | 
            -
            			if (!res.ok) {
         | 
| 33 | 
            -
            				error.set("Error while creating conversation, try again.");
         | 
| 34 | 
            -
            				console.error("Error while creating conversation: " + (await res.text()));
         | 
| 35 | 
            -
            				return;
         | 
| 36 | 
            -
            			}
         | 
| 37 | 
            -
             | 
| 38 | 
            -
            			const { conversationId } = await res.json();
         | 
| 39 | 
            -
             | 
| 40 | 
            -
            			return conversationId;
         | 
| 41 | 
            -
            		} catch (err) {
         | 
| 42 | 
            -
            			error.set(ERROR_MESSAGES.default);
         | 
| 43 | 
            -
            			console.error(String(err));
         | 
| 44 | 
            -
            			throw err;
         | 
| 45 | 
            -
            		}
         | 
| 46 | 
            -
            	}
         | 
| 47 | 
            -
             | 
| 48 | 
            -
            	async function shareConversation() {
         | 
| 49 | 
            -
            		const url = `${window.location.origin}${window.location.pathname}`;
         | 
| 50 | 
            -
             | 
| 51 | 
            -
            		share(url, data.title);
         | 
| 52 | 
            -
            	}
         | 
| 53 | 
            -
            </script>
         | 
| 54 | 
            -
             | 
| 55 | 
            -
            <svelte:head>
         | 
| 56 | 
            -
            	<title>{data.title}</title>
         | 
| 57 | 
            -
            </svelte:head>
         | 
| 58 | 
            -
             | 
| 59 | 
            -
            <ChatWindow
         | 
| 60 | 
            -
            	{loading}
         | 
| 61 | 
            -
            	shared={true}
         | 
| 62 | 
            -
            	messages={data.messages}
         | 
| 63 | 
            -
            	preprompt={data.preprompt}
         | 
| 64 | 
            -
            	on:message={(ev) =>
         | 
| 65 | 
            -
            		createConversation()
         | 
| 66 | 
            -
            			.then((convId) => {
         | 
| 67 | 
            -
            				$pendingMessage = ev.detail;
         | 
| 68 | 
            -
            				return goto(`${base}/conversation/${convId}`, { invalidateAll: true });
         | 
| 69 | 
            -
            			})
         | 
| 70 | 
            -
            			.finally(() => (loading = false))}
         | 
| 71 | 
            -
            	on:share={shareConversation}
         | 
| 72 | 
            -
            	on:retry={(ev) =>
         | 
| 73 | 
            -
            		createConversation()
         | 
| 74 | 
            -
            			.then((convId) => {
         | 
| 75 | 
            -
            				$pendingMessageIdToRetry = ev.detail.id;
         | 
| 76 | 
            -
            				$pendingMessage = ev.detail.content;
         | 
| 77 | 
            -
            				return goto(`${base}/conversation/${convId}`, { invalidateAll: true });
         | 
| 78 | 
            -
            			})
         | 
| 79 | 
            -
            			.finally(() => (loading = false))}
         | 
| 80 | 
            -
            	models={data.models}
         | 
| 81 | 
            -
            	currentModel={findCurrentModel(data.models, data.model)}
         | 
| 82 | 
            -
            	settings={data.settings}
         | 
| 83 | 
            -
            	loginRequired={!$page.error &&
         | 
| 84 | 
            -
            		(data.requiresLogin
         | 
| 85 | 
            -
            			? !data.user
         | 
| 86 | 
            -
            			: !data.settings.ethicsModalAcceptedAt && !!PUBLIC_APP_DISCLAIMER)}
         | 
| 87 | 
            -
            />
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
    	
        src/routes/r/[id]/+page.ts
    ADDED
    
    | @@ -0,0 +1,5 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import { redirect } from "@sveltejs/kit";
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            export const load = async ({ params }) => {
         | 
| 4 | 
            +
            	throw redirect(302, "../conversation/" + params.id);
         | 
| 5 | 
            +
            };
         | 
    	
        src/routes/r/[id]/message/[messageId]/prompt/+server.ts
    DELETED
    
    | @@ -1,47 +0,0 @@ | |
| 1 | 
            -
            import { buildPrompt } from "$lib/buildPrompt";
         | 
| 2 | 
            -
            import { collections } from "$lib/server/database";
         | 
| 3 | 
            -
            import { models } from "$lib/server/models";
         | 
| 4 | 
            -
            import { error } from "@sveltejs/kit";
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            export async function GET({ params }) {
         | 
| 7 | 
            -
            	const conv = await collections.sharedConversations.findOne({
         | 
| 8 | 
            -
            		_id: params.id,
         | 
| 9 | 
            -
            	});
         | 
| 10 | 
            -
             | 
| 11 | 
            -
            	if (!conv) {
         | 
| 12 | 
            -
            		throw error(404, "Conversation not found");
         | 
| 13 | 
            -
            	}
         | 
| 14 | 
            -
             | 
| 15 | 
            -
            	const messageId = params.messageId;
         | 
| 16 | 
            -
             | 
| 17 | 
            -
            	const messageIndex = conv.messages.findIndex((msg) => msg.id === messageId);
         | 
| 18 | 
            -
             | 
| 19 | 
            -
            	if (messageIndex === -1) {
         | 
| 20 | 
            -
            		throw error(404, "Message not found");
         | 
| 21 | 
            -
            	}
         | 
| 22 | 
            -
             | 
| 23 | 
            -
            	const model = models.find((m) => m.id === conv.model);
         | 
| 24 | 
            -
             | 
| 25 | 
            -
            	if (!model) {
         | 
| 26 | 
            -
            		throw error(404, "Conversation model not found");
         | 
| 27 | 
            -
            	}
         | 
| 28 | 
            -
             | 
| 29 | 
            -
            	const prompt = await buildPrompt({ messages: conv.messages.slice(0, messageIndex + 1), model });
         | 
| 30 | 
            -
             | 
| 31 | 
            -
            	return new Response(
         | 
| 32 | 
            -
            		JSON.stringify(
         | 
| 33 | 
            -
            			{
         | 
| 34 | 
            -
            				note: "This is a preview of the prompt that will be sent to the model when retrying the message. It may differ from what was sent in the past if the parameters have been updated since",
         | 
| 35 | 
            -
            				prompt,
         | 
| 36 | 
            -
            				model: model.name,
         | 
| 37 | 
            -
            				parameters: {
         | 
| 38 | 
            -
            					...model.parameters,
         | 
| 39 | 
            -
            					return_full_text: false,
         | 
| 40 | 
            -
            				},
         | 
| 41 | 
            -
            			},
         | 
| 42 | 
            -
            			null,
         | 
| 43 | 
            -
            			2
         | 
| 44 | 
            -
            		),
         | 
| 45 | 
            -
            		{ headers: { "Content-Type": "application/json" } }
         | 
| 46 | 
            -
            	);
         | 
| 47 | 
            -
            }
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
 
			
