fix: tag unarchive/archive issue

This commit is contained in:
Timothy J. Baek 2024-10-14 22:57:11 -07:00
parent d8a30bd6ae
commit 6703cacb99
9 changed files with 72 additions and 30 deletions

View File

@ -401,10 +401,11 @@ class ChatTable:
# search_text might contain 'tag:tag_name' format so we need to extract the tag_name, split the search_text and remove the tags # search_text might contain 'tag:tag_name' format so we need to extract the tag_name, split the search_text and remove the tags
tag_ids = [ tag_ids = [
tag_name.replace("tag:", "").replace(" ", "_").lower() word.replace("tag:", "").replace(" ", "_").lower()
for tag_name in search_text_words for word in search_text_words
if tag_name.startswith("tag:") if word.startswith("tag:")
] ]
search_text_words = [ search_text_words = [
word for word in search_text_words if not word.startswith("tag:") word for word in search_text_words if not word.startswith("tag:")
] ]
@ -450,11 +451,11 @@ class ChatTable:
EXISTS ( EXISTS (
SELECT 1 SELECT 1
FROM json_each(Chat.meta, '$.tags') AS tag FROM json_each(Chat.meta, '$.tags') AS tag
WHERE tag.value = :tag_id WHERE tag.value = :tag_id_{tag_idx}
) )
""" """
).params(tag_id=tag_id) ).params(**{f"tag_id_{tag_idx}": tag_id})
for tag_id in tag_ids for tag_idx, tag_id in enumerate(tag_ids)
] ]
) )
) )
@ -488,11 +489,11 @@ class ChatTable:
EXISTS ( EXISTS (
SELECT 1 SELECT 1
FROM json_array_elements_text(Chat.meta->'tags') AS tag FROM json_array_elements_text(Chat.meta->'tags') AS tag
WHERE tag = :tag_id WHERE tag = :tag_id_{tag_idx}
) )
""" """
).params(tag_id=tag_id) ).params(**{f"tag_id_{tag_idx}": tag_id})
for tag_id in tag_ids for tag_idx, tag_id in enumerate(tag_ids)
] ]
) )
) )
@ -571,7 +572,7 @@ class ChatTable:
def count_chats_by_tag_name_and_user_id(self, tag_name: str, user_id: str) -> int: def count_chats_by_tag_name_and_user_id(self, tag_name: str, user_id: str) -> int:
with get_db() as db: # Assuming `get_db()` returns a session object with get_db() as db: # Assuming `get_db()` returns a session object
query = db.query(Chat).filter_by(user_id=user_id) query = db.query(Chat).filter_by(user_id=user_id, archived=False)
# Normalize the tag_name for consistency # Normalize the tag_name for consistency
tag_id = tag_name.replace(" ", "_").lower() tag_id = tag_name.replace(" ", "_").lower()

View File

@ -114,13 +114,24 @@ async def search_user_chats(
limit = 60 limit = 60
skip = (page - 1) * limit skip = (page - 1) * limit
return [ chat_list = [
ChatTitleIdResponse(**chat.model_dump()) ChatTitleIdResponse(**chat.model_dump())
for chat in Chats.get_chats_by_user_id_and_search_text( for chat in Chats.get_chats_by_user_id_and_search_text(
user.id, text, skip=skip, limit=limit user.id, text, skip=skip, limit=limit
) )
] ]
# Delete tag if no chat is found
words = text.strip().split(" ")
if page == 1 and len(words) == 1 and words[0].startswith("tag:"):
tag_id = words[0].replace("tag:", "")
if len(chat_list) == 0:
if Tags.get_tag_by_name_and_user_id(tag_id, user.id):
log.debug(f"deleting tag: {tag_id}")
Tags.delete_tag_by_name_and_user_id(tag_id, user.id)
return chat_list
############################ ############################
# GetPinnedChats # GetPinnedChats
@ -315,7 +326,13 @@ async def update_chat_by_id(
@router.delete("/{id}", response_model=bool) @router.delete("/{id}", response_model=bool)
async def delete_chat_by_id(request: Request, id: str, user=Depends(get_verified_user)): async def delete_chat_by_id(request: Request, id: str, user=Depends(get_verified_user)):
if user.role == "admin": if user.role == "admin":
chat = Chats.get_chat_by_id(id)
for tag in chat.meta.get("tags", []):
if Chats.count_chats_by_tag_name_and_user_id(tag, user.id) == 0:
Tags.delete_tag_by_name_and_user_id(tag, user.id)
result = Chats.delete_chat_by_id(id) result = Chats.delete_chat_by_id(id)
return result return result
else: else:
if not request.app.state.config.USER_PERMISSIONS.get("chat", {}).get( if not request.app.state.config.USER_PERMISSIONS.get("chat", {}).get(
@ -326,6 +343,11 @@ async def delete_chat_by_id(request: Request, id: str, user=Depends(get_verified
detail=ERROR_MESSAGES.ACCESS_PROHIBITED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
) )
chat = Chats.get_chat_by_id(id)
for tag in chat.meta.get("tags", []):
if Chats.count_chats_by_tag_name_and_user_id(tag, user.id) == 0:
Tags.delete_tag_by_name_and_user_id(tag, user.id)
result = Chats.delete_chat_by_id_and_user_id(id, user.id) result = Chats.delete_chat_by_id_and_user_id(id, user.id)
return result return result
@ -397,6 +419,20 @@ async def archive_chat_by_id(id: str, user=Depends(get_verified_user)):
chat = Chats.get_chat_by_id_and_user_id(id, user.id) chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat: if chat:
chat = Chats.toggle_chat_archive_by_id(id) chat = Chats.toggle_chat_archive_by_id(id)
# Delete tags if chat is archived
if chat.archived:
for tag_id in chat.meta.get("tags", []):
if Chats.count_chats_by_tag_name_and_user_id(tag_id, user.id) == 0:
log.debug(f"deleting tag: {tag_id}")
Tags.delete_tag_by_name_and_user_id(tag_id, user.id)
else:
for tag_id in chat.meta.get("tags", []):
tag = Tags.get_tag_by_name_and_user_id(tag_id, user.id)
if tag is None:
log.debug(f"inserting tag: {tag_id}")
tag = Tags.insert_new_tag(tag_id, user.id)
return ChatResponse(**chat.model_dump()) return ChatResponse(**chat.model_dump())
else: else:
raise HTTPException( raise HTTPException(

View File

@ -267,7 +267,7 @@ export const getAllUserChats = async (token: string) => {
return res; return res;
}; };
export const getAllChatTags = async (token: string) => { export const getAllTags = async (token: string) => {
let error = null; let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/chats/all/tags`, { const res = await fetch(`${WEBUI_API_BASE_URL}/chats/all/tags`, {

View File

@ -2,7 +2,7 @@
import { import {
addTagById, addTagById,
deleteTagById, deleteTagById,
getAllChatTags, getAllTags,
getChatList, getChatList,
getChatListByTagName, getChatListByTagName,
getTagsById, getTagsById,
@ -37,7 +37,7 @@
tags: tags tags: tags
}); });
await _tags.set(await getAllChatTags(localStorage.token)); await _tags.set(await getAllTags(localStorage.token));
dispatch('add', { dispatch('add', {
name: tagName name: tagName
}); });
@ -50,7 +50,7 @@
tags: tags tags: tags
}); });
await _tags.set(await getAllChatTags(localStorage.token)); await _tags.set(await getAllTags(localStorage.token));
dispatch('delete', { dispatch('delete', {
name: tagName name: tagName
}); });

View File

@ -30,7 +30,7 @@
getChatById, getChatById,
getChatListByTagName, getChatListByTagName,
updateChatById, updateChatById,
getAllChatTags, getAllTags,
archiveChatById, archiveChatById,
cloneChatById, cloneChatById,
getChatListBySearchText, getChatListBySearchText,
@ -77,6 +77,8 @@
const initChatList = async () => { const initChatList = async () => {
// Reset pagination variables // Reset pagination variables
tags.set(await getAllTags(localStorage.token));
currentChatPage.set(1); currentChatPage.set(1);
allChatsLoaded = false; allChatsLoaded = false;
await chats.set(await getChatList(localStorage.token, $currentChatPage)); await chats.set(await getChatList(localStorage.token, $currentChatPage));
@ -123,6 +125,10 @@
searchDebounceTimeout = setTimeout(async () => { searchDebounceTimeout = setTimeout(async () => {
currentChatPage.set(1); currentChatPage.set(1);
await chats.set(await getChatListBySearchText(localStorage.token, search)); await chats.set(await getChatListBySearchText(localStorage.token, search));
if ($chats.length === 0) {
tags.set(await getAllTags(localStorage.token));
}
}, 1000); }, 1000);
} }
}; };
@ -134,6 +140,8 @@
}); });
if (res) { if (res) {
tags.set(await getAllTags(localStorage.token));
if ($chatId === id) { if ($chatId === id) {
await chatId.set(''); await chatId.set('');
await tick(); await tick();
@ -143,7 +151,6 @@
allChatsLoaded = false; allChatsLoaded = false;
currentChatPage.set(1); currentChatPage.set(1);
await chats.set(await getChatList(localStorage.token, $currentChatPage)); await chats.set(await getChatList(localStorage.token, $currentChatPage));
await pinnedChats.set(await getPinnedChatList(localStorage.token)); await pinnedChats.set(await getPinnedChatList(localStorage.token));
} }
}; };
@ -324,7 +331,7 @@
bind:show={$showArchivedChats} bind:show={$showArchivedChats}
on:change={async () => { on:change={async () => {
await pinnedChats.set(await getPinnedChatList(localStorage.token)); await pinnedChats.set(await getPinnedChatList(localStorage.token));
await chats.set(await getChatList(localStorage.token)); await initChatList();
}} }}
/> />

View File

@ -15,7 +15,6 @@
getArchivedChatList getArchivedChatList
} from '$lib/apis/chats'; } from '$lib/apis/chats';
import Tooltip from '$lib/components/common/Tooltip.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
export let show = false; export let show = false;
@ -30,7 +29,6 @@
}); });
chats = await getArchivedChatList(localStorage.token); chats = await getArchivedChatList(localStorage.token);
dispatch('change'); dispatch('change');
}; };

View File

@ -10,6 +10,7 @@
archiveChatById, archiveChatById,
cloneChatById, cloneChatById,
deleteChatById, deleteChatById,
getAllTags,
getChatList, getChatList,
getChatListByTagName, getChatListByTagName,
getPinnedChatList, getPinnedChatList,
@ -22,7 +23,8 @@
mobile, mobile,
pinnedChats, pinnedChats,
showSidebar, showSidebar,
currentChatPage currentChatPage,
tags
} from '$lib/stores'; } from '$lib/stores';
import ChatMenu from './ChatMenu.svelte'; import ChatMenu from './ChatMenu.svelte';
@ -77,6 +79,7 @@
const archiveChatHandler = async (id) => { const archiveChatHandler = async (id) => {
await archiveChatById(localStorage.token, id); await archiveChatById(localStorage.token, id);
tags.set(await getAllTags(localStorage.token));
currentChatPage.set(1); currentChatPage.set(1);
await chats.set(await getChatList(localStorage.token, $currentChatPage)); await chats.set(await getChatList(localStorage.token, $currentChatPage));

View File

@ -15,13 +15,8 @@
import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte'; import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte';
import Bookmark from '$lib/components/icons/Bookmark.svelte'; import Bookmark from '$lib/components/icons/Bookmark.svelte';
import BookmarkSlash from '$lib/components/icons/BookmarkSlash.svelte'; import BookmarkSlash from '$lib/components/icons/BookmarkSlash.svelte';
import { import { getChatPinnedStatusById, toggleChatPinnedStatusById } from '$lib/apis/chats';
addTagById, import { chats } from '$lib/stores';
deleteTagById,
getChatPinnedStatusById,
getTagsById,
toggleChatPinnedStatusById
} from '$lib/apis/chats';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
@ -146,6 +141,7 @@
type: 'add', type: 'add',
name: e.detail.name name: e.detail.name
}); });
show = false; show = false;
}} }}
on:delete={(e) => { on:delete={(e) => {
@ -153,6 +149,7 @@
type: 'delete', type: 'delete',
name: e.detail.name name: e.detail.name
}); });
show = false; show = false;
}} }}
on:close={() => { on:close={() => {

View File

@ -13,7 +13,7 @@
import { getKnowledgeItems } from '$lib/apis/knowledge'; import { getKnowledgeItems } from '$lib/apis/knowledge';
import { getFunctions } from '$lib/apis/functions'; import { getFunctions } from '$lib/apis/functions';
import { getModels as _getModels, getVersionUpdates } from '$lib/apis'; import { getModels as _getModels, getVersionUpdates } from '$lib/apis';
import { getAllChatTags } from '$lib/apis/chats'; import { getAllTags } from '$lib/apis/chats';
import { getPrompts } from '$lib/apis/prompts'; import { getPrompts } from '$lib/apis/prompts';
import { getTools } from '$lib/apis/tools'; import { getTools } from '$lib/apis/tools';
import { getBanners } from '$lib/apis/configs'; import { getBanners } from '$lib/apis/configs';
@ -117,7 +117,7 @@
banners.set(await getBanners(localStorage.token)); banners.set(await getBanners(localStorage.token));
})(), })(),
(async () => { (async () => {
tags.set(await getAllChatTags(localStorage.token)); tags.set(await getAllTags(localStorage.token));
})() })()
]); ]);