Timothy J. Baek 7 miesięcy temu
rodzic
commit
ba2df1c33a

+ 47 - 19
backend/open_webui/apps/webui/models/chats.py

@@ -393,28 +393,56 @@ class ChatTable:
             if not include_archived:
                 query = query.filter(Chat.archived == False)
 
-            # Fetch all potentially relevant chats
-            all_chats = query.all()
+            query = query.order_by(Chat.updated_at.desc())
 
-        # Filter chats using Python
-        filtered_chats = []
-        for chat in all_chats:
-            # Check chat title
-            title_matches = search_text in chat.title.lower()
-
-            # Check chat content in chat JSON
-            content_matches = any(
-                search_text in message.get("content", "").lower()
-                for message in chat.chat.get("messages", [])
-                if "content" in message
-            )
+            # Check if the database dialect is either 'sqlite' or 'postgresql'
+            dialect_name = db.bind.dialect.name
+            if dialect_name == "sqlite":
+                # SQLite case: using JSON1 extension for JSON searching
+                query = query.filter(
+                    (
+                        Chat.title.ilike(
+                            f"%{search_text}%"
+                        )  # Case-insensitive search in title
+                        | text(
+                            """
+                            EXISTS (
+                                SELECT 1 
+                                FROM json_each(Chat.chat, '$.messages') AS message 
+                                WHERE LOWER(message.value->>'content') LIKE '%' || :search_text || '%'
+                            )
+                            """
+                        )
+                    ).params(search_text=search_text)
+                )
+            elif dialect_name == "postgresql":
+                # PostgreSQL relies on proper JSON query for search
+                query = query.filter(
+                    (
+                        Chat.title.ilike(
+                            f"%{search_text}%"
+                        )  # Case-insensitive search in title
+                        | text(
+                            """
+                            EXISTS (
+                                SELECT 1
+                                FROM json_array_elements(Chat.chat->'messages') AS message
+                                WHERE LOWER(message->>'content') LIKE '%' || :search_text || '%'
+                            )
+                            """
+                        )
+                    ).params(search_text=search_text)
+                )
+            else:
+                raise NotImplementedError(
+                    f"Unsupported dialect: {db.bind.dialect.name}"
+                )
 
-            if title_matches or content_matches:
-                filtered_chats.append(chat)
+            # Perform pagination at the SQL level
+            all_chats = query.offset(skip).limit(limit).all()
 
-        # Implementing pagination manually
-        paginated_chats = filtered_chats[skip : skip + limit]
-        return [ChatModel.model_validate(chat) for chat in paginated_chats]
+            # Validate and return chats
+            return [ChatModel.model_validate(chat) for chat in all_chats]
 
     def get_chat_tags_by_id_and_user_id(self, id: str, user_id: str) -> list[TagModel]:
         with get_db() as db:

+ 4 - 1
src/lib/apis/chats/index.ts

@@ -199,7 +199,10 @@ export const getChatListBySearchText = async (token: string, text: string, page:
 		throw error;
 	}
 
-	return res;
+	return res.map((chat) => ({
+		...chat,
+		time_range: getTimeRange(chat.updated_at)
+	}));
 };
 
 export const getAllArchivedChats = async (token: string) => {

+ 4 - 3
src/lib/components/layout/Sidebar.svelte

@@ -111,6 +111,7 @@
 
 		if (search === '') {
 			await initChatList();
+			allChatsLoaded = false;
 			return;
 		} else {
 			searchDebounceTimeout = setTimeout(async () => {
@@ -512,7 +513,7 @@
 			</div>
 
 			{#if $tags.length > 0}
-				<div class="px-3.5 mb-1 flex gap-0.5 flex-wrap">
+				<div class="px-3.5 mb-2.5 flex gap-0.5 flex-wrap">
 					<button
 						class="px-2.5 py-[1px] text-xs transition {selectedTagName === null
 							? 'bg-gray-100 dark:bg-gray-900'
@@ -551,7 +552,7 @@
 			{/if}
 
 			{#if !search && $pinnedChats.length > 0}
-				<div class="pl-2 py-2 flex flex-col space-y-1">
+				<div class="pl-2 pb-2 flex flex-col space-y-1">
 					<div class="">
 						<div class="w-full pl-2.5 text-xs text-gray-500 dark:text-gray-500 font-medium pb-1.5">
 							{$i18n.t('Pinned')}
@@ -586,7 +587,7 @@
 				</div>
 			{/if}
 
-			<div class="pl-2 my-2 flex-1 flex flex-col space-y-1 overflow-y-auto scrollbar-hidden">
+			<div class="pl-2 flex-1 flex flex-col space-y-1 overflow-y-auto scrollbar-hidden">
 				{#if $chats}
 					{#each $chats as chat, idx}
 						{#if idx === 0 || (idx > 0 && chat.time_range !== $chats[idx - 1].time_range)}