diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 18f802afe..8e721da78 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -469,6 +469,8 @@ class ChatTable: def get_chat_by_share_id(self, id: str) -> Optional[ChatModel]: try: with get_db() as db: + # it is possible that the shared link was deleted. hence, + # we check if the chat is still shared by checkng if a chat with the share_id exists chat = db.query(Chat).filter_by(share_id=id).first() if chat: diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 5e0e75e24..a001dd01f 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -463,6 +463,30 @@ async def clone_chat_by_id(id: str, user=Depends(get_verified_user)): ) +############################ +# CloneSharedChatById +############################ + + +@router.post("/{id}/clone/shared", response_model=Optional[ChatResponse]) +async def clone_shared_chat_by_id(id: str, user=Depends(get_verified_user)): + chat = Chats.get_chat_by_share_id(id) + if chat: + updated_chat = { + **chat.chat, + "originalChatId": chat.id, + "branchPointMessageId": chat.chat["history"]["currentId"], + "title": f"Clone of {chat.title}", + } + + chat = Chats.insert_new_chat(user.id, ChatForm(**{"chat": updated_chat})) + return ChatResponse(**chat.model_dump()) + else: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT() + ) + + ############################ # ArchiveChat ############################ diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts index d93d21c73..1772529d3 100644 --- a/src/lib/apis/chats/index.ts +++ b/src/lib/apis/chats/index.ts @@ -618,6 +618,44 @@ export const cloneChatById = async (token: string, id: string) => { return res; }; +export const cloneSharedChatById = async (token: string, id: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/chats/${id}/clone/shared`, { + 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; + + if ('detail' in err) { + error = err.detail; + } else { + error = err; + } + + console.log(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + export const shareChatById = async (token: string, id: string) => { let error = null; diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index 2b0748dc7..7f18f3a35 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -16,6 +16,8 @@ const i18n = getContext('i18n'); + export let className = 'h-full flex pt-8'; + export let chatId = ''; export let user = $_user; @@ -333,7 +335,7 @@ }; -
+
{#if Object.keys(history?.messages ?? {}).length == 0} { + if (!chat) return; + + const res = await cloneSharedChatById(localStorage.token, chat.id).catch((error) => { + toast.error(error); + return null; + }); + + if (res) { + goto(`/c/${res.id}`); + } + }; @@ -114,25 +128,26 @@
-
-
-
-
- {title} -
+
+