Skip to content

Commit 0eba3df

Browse files
committed
refac
1 parent aa851d9 commit 0eba3df

2 files changed

Lines changed: 82 additions & 5 deletions

File tree

backend/open_webui/routers/chats.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747

4848
router = APIRouter()
4949

50+
SEARCH_FILTER_PREFIXES = ('tag:', 'folder:', 'pinned:', 'archived:', 'shared:')
51+
5052
CHAT_CONFIG_KEYS = {
5153
'ENABLE_CONTEXT_COMPACTION': 'chat.context_compaction.enable',
5254
'CONTEXT_COMPACTION_TOKEN_THRESHOLD': 'chat.context_compaction.token_threshold',
@@ -64,6 +66,43 @@ class CompactChatForm(BaseModel):
6466
model: str | None = None
6567

6668

69+
def chat_search_content_text(text: str) -> str:
70+
words = text.lower().strip().split(' ')
71+
return ' '.join(word for word in words if not word.startswith(SEARCH_FILTER_PREFIXES)).strip()
72+
73+
74+
def chat_search_snippet(chat: dict, search_text: str, max_length: int = 200) -> str | None:
75+
if not search_text:
76+
return None
77+
78+
messages = chat.get('messages', [])
79+
if isinstance(messages, dict):
80+
messages = messages.values()
81+
82+
for message in messages:
83+
if not isinstance(message, dict):
84+
continue
85+
86+
content = message.get('content')
87+
if not isinstance(content, str):
88+
continue
89+
90+
index = content.lower().find(search_text)
91+
if index == -1:
92+
continue
93+
94+
start = max(index - max_length // 2, 0)
95+
end = min(start + max_length, len(content))
96+
if index + len(search_text) > end:
97+
end = min(index + len(search_text), len(content))
98+
start = max(end - max_length, 0)
99+
100+
snippet = ' '.join(content[start:end].split())
101+
return f'{"..." if start else ""}{snippet}{"..." if end < len(content) else ""}'
102+
103+
return None
104+
105+
67106
async def get_chat_config_values() -> dict:
68107
values = await Config.get_many(*CHAT_CONFIG_KEYS.values())
69108
return {field: values[storage_key] for field, storage_key in CHAT_CONFIG_KEYS.items() if storage_key in values}
@@ -704,10 +743,10 @@ async def search_user_chats(
704743
limit = 60
705744
skip = (page - 1) * limit
706745

707-
chat_list = [
708-
ChatTitleIdResponse(**chat.model_dump())
709-
for chat in await Chats.get_chats_by_user_id_and_search_text(user.id, text, skip=skip, limit=limit, db=db)
710-
]
746+
search_text = chat_search_content_text(text)
747+
chat_list = []
748+
for chat in await Chats.get_chats_by_user_id_and_search_text(user.id, text, skip=skip, limit=limit, db=db):
749+
chat_list.append(ChatTitleIdResponse(**chat.model_dump(), snippet=chat_search_snippet(chat.chat, search_text)))
711750

712751
# Delete tag if no chat is found
713752
words = text.strip().split(' ')

src/lib/components/layout/SearchModal.svelte

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,34 @@
281281
let history = null;
282282
let messages = null;
283283
284+
const searchFilterPrefixes = ['tag:', 'folder:', 'pinned:', 'archived:', 'shared:'];
285+
286+
const getSnippetQuery = (query: string) => {
287+
return query
288+
.trim()
289+
.split(/\s+/)
290+
.filter(
291+
(word) => !searchFilterPrefixes.some((prefix) => word.toLowerCase().startsWith(prefix))
292+
)
293+
.join(' ')
294+
.trim();
295+
};
296+
297+
const getHighlightedSnippet = (snippet: string, query: string) => {
298+
const match = getSnippetQuery(query).toLowerCase();
299+
const index = match ? snippet.toLowerCase().indexOf(match) : -1;
300+
301+
if (index === -1) {
302+
return [{ text: snippet, highlight: false }];
303+
}
304+
305+
return [
306+
{ text: snippet.slice(0, index), highlight: false },
307+
{ text: snippet.slice(index, index + match.length), highlight: true },
308+
{ text: snippet.slice(index + match.length), highlight: false }
309+
].filter((part) => part.text);
310+
};
311+
284312
$: if (!chatListLoading && chatList) {
285313
loadChatPreview(selectedIdx);
286314
}
@@ -699,7 +727,17 @@
699727
</div>
700728
{#if chat?.snippet}
701729
<div class="text-xs text-gray-500 dark:text-gray-400 line-clamp-2 mt-0.5">
702-
{chat.snippet}
730+
{#each getHighlightedSnippet(chat.snippet, query) as part}
731+
{#if part.highlight}
732+
<mark
733+
class="rounded bg-yellow-200/70 px-0.5 text-inherit dark:bg-yellow-500/30"
734+
>
735+
{part.text}
736+
</mark>
737+
{:else}
738+
{part.text}
739+
{/if}
740+
{/each}
703741
</div>
704742
{/if}
705743
</a>

0 commit comments

Comments
 (0)