diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 35e7b0653be..1fe5ed595d8 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -266,83 +266,6 @@ def add_message_status_to_chat_by_id_and_message_id( chat["history"] = history return self.update_chat_by_id(id, chat) - def insert_shared_chat_by_chat_id(self, chat_id: str) -> Optional[ChatModel]: - with get_db() as db: - # Get the existing chat to share - chat = db.get(Chat, chat_id) - # Check if the chat is already shared - if chat.share_id: - return self.get_chat_by_id_and_user_id(chat.share_id, "shared") - # Create a new chat with the same data, but with a new ID - shared_chat = ChatModel( - **{ - "id": str(uuid.uuid4()), - "user_id": f"shared-{chat_id}", - "title": chat.title, - "chat": chat.chat, - "created_at": chat.created_at, - "updated_at": int(time.time()), - } - ) - shared_result = Chat(**shared_chat.model_dump()) - db.add(shared_result) - db.commit() - db.refresh(shared_result) - - # Update the original chat with the share_id - result = ( - db.query(Chat) - .filter_by(id=chat_id) - .update({"share_id": shared_chat.id}) - ) - db.commit() - return shared_chat if (shared_result and result) else None - - def update_shared_chat_by_chat_id(self, chat_id: str) -> Optional[ChatModel]: - try: - with get_db() as db: - chat = db.get(Chat, chat_id) - shared_chat = ( - db.query(Chat).filter_by(user_id=f"shared-{chat_id}").first() - ) - - if shared_chat is None: - return self.insert_shared_chat_by_chat_id(chat_id) - - shared_chat.title = chat.title - shared_chat.chat = chat.chat - - shared_chat.updated_at = int(time.time()) - db.commit() - db.refresh(shared_chat) - - return ChatModel.model_validate(shared_chat) - except Exception: - return None - - def delete_shared_chat_by_chat_id(self, chat_id: str) -> bool: - try: - with get_db() as db: - db.query(Chat).filter_by(user_id=f"shared-{chat_id}").delete() - db.commit() - - return True - except Exception: - return False - - def update_chat_share_id_by_id( - self, id: str, share_id: Optional[str] - ) -> Optional[ChatModel]: - try: - with get_db() as db: - chat = db.get(Chat, id) - chat.share_id = share_id - db.commit() - db.refresh(chat) - return ChatModel.model_validate(chat) - except Exception: - return None - def toggle_chat_pinned_by_id(self, id: str) -> Optional[ChatModel]: try: with get_db() as db: @@ -470,20 +393,6 @@ def get_chat_by_id(self, id: str) -> Optional[ChatModel]: except Exception: return None - 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 checking if a chat with the share_id exists - chat = db.query(Chat).filter_by(share_id=id).first() - - if chat: - return self.get_chat_by_id(id) - else: - return None - except Exception: - return None - def get_chat_by_id_and_user_id(self, id: str, user_id: str) -> Optional[ChatModel]: try: with get_db() as db: @@ -857,25 +766,13 @@ def delete_chat_by_id(self, id: str) -> bool: db.query(Chat).filter_by(id=id).delete() db.commit() - return True and self.delete_shared_chat_by_chat_id(id) - except Exception: - return False - - def delete_chat_by_id_and_user_id(self, id: str, user_id: str) -> bool: - try: - with get_db() as db: - db.query(Chat).filter_by(id=id, user_id=user_id).delete() - db.commit() - - return True and self.delete_shared_chat_by_chat_id(id) + return True except Exception: return False def delete_chats_by_user_id(self, user_id: str) -> bool: try: with get_db() as db: - self.delete_shared_chats_by_user_id(user_id) - db.query(Chat).filter_by(user_id=user_id).delete() db.commit() @@ -895,18 +792,4 @@ def delete_chats_by_user_id_and_folder_id( except Exception: return False - def delete_shared_chats_by_user_id(self, user_id: str) -> bool: - try: - with get_db() as db: - chats_by_user = db.query(Chat).filter_by(user_id=user_id).all() - shared_chat_ids = [f"shared-{chat.id}" for chat in chats_by_user] - - db.query(Chat).filter(Chat.user_id.in_(shared_chat_ids)).delete() - db.commit() - - return True - except Exception: - return False - - Chats = ChatTable() diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index f3389b6541f..dd33c48990d 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -290,32 +290,6 @@ async def archive_all_chats(user=Depends(get_verified_user)): return Chats.archive_all_chats_by_user_id(user.id) -############################ -# GetSharedChatById -############################ - - -@router.get("/share/{share_id}", response_model=Optional[ChatResponse]) -async def get_shared_chat_by_id(share_id: str, user=Depends(get_verified_user)): - if user.role == "pending": - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND - ) - - if user.role == "user" or (user.role == "admin" and not ENABLE_ADMIN_CHAT_ACCESS): - chat = Chats.get_chat_by_share_id(share_id) - elif user.role == "admin" and ENABLE_ADMIN_CHAT_ACCESS: - chat = Chats.get_chat_by_id(share_id) - - if chat: - return ChatResponse(**chat.model_dump()) - - else: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND - ) - - ############################ # GetChatsByTags ############################ @@ -582,36 +556,6 @@ async def clone_chat_by_id( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT() ) - -############################ -# CloneSharedChatById -############################ - - -@router.post("/{id}/clone/shared", response_model=Optional[ChatResponse]) -async def clone_shared_chat_by_id(id: str, user=Depends(get_verified_user)): - - if user.role == "admin": - chat = Chats.get_chat_by_id(id) - else: - 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 ############################ @@ -642,58 +586,6 @@ async def archive_chat_by_id(id: str, user=Depends(get_verified_user)): status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT() ) - -############################ -# ShareChatById -############################ - - -@router.post("/{id}/share", response_model=Optional[ChatResponse]) -async def share_chat_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) - if chat: - if chat.share_id: - shared_chat = Chats.update_shared_chat_by_chat_id(chat.id) - return ChatResponse(**shared_chat.model_dump()) - - shared_chat = Chats.insert_shared_chat_by_chat_id(chat.id) - if not shared_chat: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=ERROR_MESSAGES.DEFAULT(), - ) - return ChatResponse(**shared_chat.model_dump()) - - else: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ERROR_MESSAGES.ACCESS_PROHIBITED, - ) - - -############################ -# DeletedSharedChatById -############################ - - -@router.delete("/{id}/share", response_model=Optional[bool]) -async def delete_shared_chat_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) - if chat: - if not chat.share_id: - return False - - result = Chats.delete_shared_chat_by_chat_id(id) - update_result = Chats.update_chat_share_id_by_id(id, None) - - return result and update_result != None - else: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ERROR_MESSAGES.ACCESS_PROHIBITED, - ) - - ############################ # UpdateChatFolderIdById ############################ diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts index 02bdd4eb31e..92fa7b801e4 100644 --- a/src/lib/apis/chats/index.ts +++ b/src/lib/apis/chats/index.ts @@ -472,37 +472,6 @@ 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 getChatPinnedStatusById = async (token: string, id: string) => { let error = null; @@ -621,76 +590,6 @@ export const cloneChatById = async (token: string, id: string, title?: 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; - - 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 updateChatFolderIdById = async (token: string, id: string, folderId?: string) => { let error = null; @@ -758,38 +657,6 @@ export const archiveChatById = async (token: string, id: string) => { return res; }; -export const deleteSharedChatById = async (token: string, id: string) => { - let error = null; - - const res = await fetch(`${WEBUI_API_BASE_URL}/chats/${id}/share`, { - 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/Navbar.svelte b/src/lib/components/chat/Navbar.svelte index 4d51b42af7b..dc2e99333e4 100644 --- a/src/lib/components/chat/Navbar.svelte +++ b/src/lib/components/chat/Navbar.svelte @@ -20,7 +20,6 @@ import { goto } from '$app/navigation'; import { page } from '$app/stores'; - import ShareChatModal from '../chat/ShareChatModal.svelte'; import ModelSelector from '../chat/ModelSelector.svelte'; import Tooltip from '../common/Tooltip.svelte'; import Menu from '$lib/components/layout/Navbar/Menu.svelte'; @@ -50,8 +49,6 @@ let showDownloadChatModal = false; - - { - showShareChatModal = !showShareChatModal; - }} + shareHandler={() => { }} downloadHandler={() => { showDownloadChatModal = !showDownloadChatModal; }} diff --git a/src/lib/components/chat/ShareChatModal.svelte b/src/lib/components/chat/ShareChatModal.svelte deleted file mode 100644 index f3f62132481..00000000000 --- a/src/lib/components/chat/ShareChatModal.svelte +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - {$i18n.t('Share Chat')} - { - show = false; - }} - > - - - - - - - {#if chat} - - - {#if chat.share_id} - {$i18n.t('You have shared this chat')} - {$i18n.t('before')}. - {$i18n.t('Click here to')} - { - const res = await deleteSharedChatById(localStorage.token, chatId); - - if (res) { - chat = await getChatById(localStorage.token, chatId); - } - }} - >{$i18n.t('delete this link')} - - {$i18n.t('and create a new shared link.')} - {:else} - {$i18n.t( - "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat." - )} - {/if} - - - - - - {#if $config?.features.enable_community_sharing} - { - shareChat(); - show = false; - }} - > - {$i18n.t('Share to Open WebUI Community')} - - {/if} - - { - const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - - if (isSafari) { - // Oh, Safari, you're so special, let's give you some extra love and attention - console.log('isSafari'); - - const getUrlPromise = async () => { - const url = await shareLocalChat(); - return new Blob([url], { type: 'text/plain' }); - }; - - navigator.clipboard - .write([ - new ClipboardItem({ - 'text/plain': getUrlPromise() - }) - ]) - .then(() => { - console.log('Async: Copying to clipboard was successful!'); - return true; - }) - .catch((error) => { - console.error('Async: Could not copy text: ', error); - return false; - }); - } else { - copyToClipboard(await shareLocalChat()); - } - - toast.success($i18n.t('Copied shared chat URL to clipboard!')); - show = false; - }} - > - - - {#if chat.share_id} - {$i18n.t('Update and Copy Link')} - {:else} - {$i18n.t('Copy Link')} - {/if} - - - - - - {/if} - - diff --git a/src/lib/components/chat/ToolServersModal.svelte b/src/lib/components/chat/ToolServersModal.svelte index 24a86e48b88..7b09c39a399 100644 --- a/src/lib/components/chat/ToolServersModal.svelte +++ b/src/lib/components/chat/ToolServersModal.svelte @@ -3,7 +3,6 @@ import { models, config, toolServers, tools } from '$lib/stores'; import { toast } from 'svelte-sonner'; - import { deleteSharedChatById, getChatById, shareChatById } from '$lib/apis/chats'; import { copyToClipboard } from '$lib/utils'; import Modal from '../common/Modal.svelte'; diff --git a/src/lib/components/layout/Navbar.svelte b/src/lib/components/layout/Navbar.svelte index b92d5fcf3f9..2cae175575e 100644 --- a/src/lib/components/layout/Navbar.svelte +++ b/src/lib/components/layout/Navbar.svelte @@ -15,7 +15,6 @@ } from '$lib/stores'; import { slide } from 'svelte/transition'; - import ShareChatModal from '../chat/ShareChatModal.svelte'; import ModelSelector from '../chat/ModelSelector.svelte'; import Tooltip from '../common/Tooltip.svelte'; import Menu from './Navbar/Menu.svelte'; @@ -38,12 +37,9 @@ export let selectedModels; export let showModelSelector = true; - let showShareChatModal = false; let showDownloadChatModal = false; - - { - showShareChatModal = !showShareChatModal; - }} + shareHandler={() => { }} downloadHandler={() => { showDownloadChatModal = !showDownloadChatModal; }} diff --git a/src/lib/components/layout/Sidebar/ChatItem.svelte b/src/lib/components/layout/Sidebar/ChatItem.svelte index eb2c33ff220..2f362c2da0e 100644 --- a/src/lib/components/layout/Sidebar/ChatItem.svelte +++ b/src/lib/components/layout/Sidebar/ChatItem.svelte @@ -30,7 +30,6 @@ import ChatMenu from './ChatMenu.svelte'; import DeleteConfirmDialog from '$lib/IONOS/components/common/Confirm.svelte'; - import ShareChatModal from '$lib/components/chat/ShareChatModal.svelte'; import GarbageBin from '$lib/components/icons/GarbageBin.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte'; import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte'; @@ -63,7 +62,6 @@ } }; - let showShareChatModal = false; let confirmEdit = false; let chatTitle = title; @@ -88,27 +86,6 @@ } }; - const cloneChatHandler = async (id) => { - const res = await cloneChatById( - localStorage.token, - id, - $i18n.t('Clone of {{TITLE}}', { - TITLE: title - }) - ).catch((error) => { - toast.error(`${error}`); - return null; - }); - - if (res) { - goto(`/c/${res.id}`); - - currentChatPage.set(1); - await chats.set(await getChatList(localStorage.token, $currentChatPage)); - await pinnedChats.set(await getPinnedChatList(localStorage.token)); - } - }; - const deleteChatHandler = async (id) => { const res = await deleteChatById(localStorage.token, id).catch((error) => { toast.error(`${error}`); @@ -216,8 +193,6 @@ }; - - { - cloneChatHandler(id); - }} - shareHandler={() => { - showShareChatModal = true; - }} archiveChatHandler={() => { archiveChatHandler(id); }} diff --git a/src/lib/components/layout/Sidebar/ChatMenu.svelte b/src/lib/components/layout/Sidebar/ChatMenu.svelte index 9b5e8ae10f7..0ac16a00f6b 100644 --- a/src/lib/components/layout/Sidebar/ChatMenu.svelte +++ b/src/lib/components/layout/Sidebar/ChatMenu.svelte @@ -32,8 +32,6 @@ const i18n = getContext('i18n'); - export const shareHandler: Function = () => {}; - export const cloneChatHandler: Function = () => {}; export const archiveChatHandler: Function = () => {}; export let renameHandler: Function; export let deleteHandler: Function; diff --git a/src/routes/s/[id]/+page.svelte b/src/routes/s/[id]/+page.svelte deleted file mode 100644 index d8f3f42eae5..00000000000 --- a/src/routes/s/[id]/+page.svelte +++ /dev/null @@ -1,212 +0,0 @@ - - - - - {title - ? `${title.length > 30 ? `${title.slice(0, 30)}...` : title} | ${$WEBUI_NAME}` - : `${$WEBUI_NAME}`} - - - -{#if loaded} - - - - - - - {title} - - - - - {dayjs(chat.chat.timestamp).format('LLL')} - - - - - - - - 0} - sendPrompt={() => {}} - continueResponse={() => {}} - regenerateResponse={() => {}} - /> - - - - - - - - {$i18n.t('Clone Chat')} - - - - - -{/if}