From 7978adbf457be13290548b28e0169e67c227d08e Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Sun, 31 Mar 2024 22:03:28 +0100 Subject: [PATCH] feat: add frontend support for locally sharing chats --- src/lib/apis/chats/index.ts | 96 +++++++++ src/lib/components/chat/Messages.svelte | 3 + .../chat/Messages/ResponseMessage.svelte | 158 ++++++++------- .../chat/Messages/UserMessage.svelte | 49 ++--- src/lib/components/chat/ShareChatModal.svelte | 12 ++ src/lib/components/layout/Navbar.svelte | 30 ++- src/routes/(app)/+page.svelte | 2 +- src/routes/(app)/c/[id]/+page.svelte | 2 +- src/routes/(app)/s/[id]/+page.svelte | 187 ++++++++++++++++++ 9 files changed, 433 insertions(+), 106 deletions(-) create mode 100644 src/routes/(app)/s/[id]/+page.svelte diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts index 35b259d5..4fcd1b63 100644 --- a/src/lib/apis/chats/index.ts +++ b/src/lib/apis/chats/index.ts @@ -218,6 +218,102 @@ export const getChatById = async (token: string, id: string) => { return res; }; +export const getChatByShareId = async (token: string, share_id: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/chats/share/${share_id}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .then((json) => { + return json; + }) + .catch((err) => { + error = err; + + console.log(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const shareChatById = async (token: string, id: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/chats/${id}/share`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .then((json) => { + return json; + }) + .catch((err) => { + error = err; + + console.log(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + +export const deleteSharedChatById = async (token: string, id: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/chats/${id}`, { + method: 'DELETE', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .then((json) => { + return json; + }) + .catch((err) => { + error = err; + + console.log(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + export const updateChatById = async (token: string, id: string, chat: object) => { let error = null; diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index 7afb5c37..4cd97ca8 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -16,6 +16,7 @@ const i18n = getContext('i18n'); export let chatId = ''; + export let readOnly = false; export let sendPrompt: Function; export let continueGeneration: Function; export let regenerateResponse: Function; @@ -317,6 +318,7 @@ messageDeleteHandler(message.id)} user={$user} + {readOnly} {message} isFirstMessage={messageIdx === 0} siblings={message.parentId !== null @@ -335,6 +337,7 @@ modelfiles={selectedModelfiles} siblings={history.messages[message.parentId]?.childrenIds ?? []} isLastMessage={messageIdx + 1 === messages.length} + {readOnly} {confirmEditResponseMessage} {showPreviousMessage} {showNextMessage} diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 50e6e0c0..3888d764 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -33,6 +33,8 @@ export let isLastMessage = true; + export let readOnly = false; + export let confirmEditResponseMessage: Function; export let showPreviousMessage: Function; export let showNextMessage: Function; @@ -469,31 +471,33 @@ {/if} - - - + + + + + + {/if} - + + + - - - + + + + {/if} - + + + + + + {/if} + +
{$i18n.t('or')}
diff --git a/src/lib/components/layout/Navbar.svelte b/src/lib/components/layout/Navbar.svelte index 2680de8d..7be5fbd8 100644 --- a/src/lib/components/layout/Navbar.svelte +++ b/src/lib/components/layout/Navbar.svelte @@ -5,7 +5,7 @@ const { saveAs } = fileSaver; import { Separator } from 'bits-ui'; - import { getChatById } from '$lib/apis/chats'; + import { getChatById, shareChatById } from '$lib/apis/chats'; import { WEBUI_NAME, chatId, modelfiles, settings, showSettings } from '$lib/stores'; import { slide } from 'svelte/transition'; @@ -19,6 +19,7 @@ import ChevronUpDown from '../icons/ChevronUpDown.svelte'; import Menu from './Navbar/Menu.svelte'; import TagChatModal from '../chat/TagChatModal.svelte'; + import { copyToClipboard } from '$lib/utils'; const i18n = getContext('i18n'); @@ -32,7 +33,7 @@ export let addTag: Function; export let deleteTag: Function; - export let showModelSelector = false; + export let showModelSelector = true; let showShareChatModal = false; let showTagChatModal = false; @@ -64,6 +65,23 @@ ); }; + const shareLocalChat = async () => { + const chat = await getChatById(localStorage.token, $chatId); + console.log('shareLocal', chat); + if (chat.share_id) { + const shareUrl = `${window.location.origin}/s/${chat.share_id}`; + toast.info( + $i18n.t('Chat is already shared at {{shareUrl}}, copied to clipboard', { shareUrl }) + ); + copyToClipboard(shareUrl); + } else { + const sharedChat = await shareChatById(localStorage.token, $chatId); + const shareUrl = `${window.location.origin}/s/${sharedChat.id}`; + toast.info($i18n.t('Chat is now shared at {{shareUrl}}, copied to clipboard', { shareUrl })); + copyToClipboard(shareUrl); + } + }; + const downloadChat = async () => { const chat = (await getChatById(localStorage.token, $chatId)).chat; console.log('download', chat); @@ -80,7 +98,7 @@ }; - +