refac
This commit is contained in:
@@ -47,6 +47,8 @@ log = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
SEARCH_FILTER_PREFIXES = ('tag:', 'folder:', 'pinned:', 'archived:', 'shared:')
|
||||
|
||||
CHAT_CONFIG_KEYS = {
|
||||
'ENABLE_CONTEXT_COMPACTION': 'chat.context_compaction.enable',
|
||||
'CONTEXT_COMPACTION_TOKEN_THRESHOLD': 'chat.context_compaction.token_threshold',
|
||||
@@ -64,6 +66,43 @@ class CompactChatForm(BaseModel):
|
||||
model: str | None = None
|
||||
|
||||
|
||||
def chat_search_content_text(text: str) -> str:
|
||||
words = text.lower().strip().split(' ')
|
||||
return ' '.join(word for word in words if not word.startswith(SEARCH_FILTER_PREFIXES)).strip()
|
||||
|
||||
|
||||
def chat_search_snippet(chat: dict, search_text: str, max_length: int = 200) -> str | None:
|
||||
if not search_text:
|
||||
return None
|
||||
|
||||
messages = chat.get('messages', [])
|
||||
if isinstance(messages, dict):
|
||||
messages = messages.values()
|
||||
|
||||
for message in messages:
|
||||
if not isinstance(message, dict):
|
||||
continue
|
||||
|
||||
content = message.get('content')
|
||||
if not isinstance(content, str):
|
||||
continue
|
||||
|
||||
index = content.lower().find(search_text)
|
||||
if index == -1:
|
||||
continue
|
||||
|
||||
start = max(index - max_length // 2, 0)
|
||||
end = min(start + max_length, len(content))
|
||||
if index + len(search_text) > end:
|
||||
end = min(index + len(search_text), len(content))
|
||||
start = max(end - max_length, 0)
|
||||
|
||||
snippet = ' '.join(content[start:end].split())
|
||||
return f'{"..." if start else ""}{snippet}{"..." if end < len(content) else ""}'
|
||||
|
||||
return None
|
||||
|
||||
|
||||
async def get_chat_config_values() -> dict:
|
||||
values = await Config.get_many(*CHAT_CONFIG_KEYS.values())
|
||||
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(
|
||||
limit = 60
|
||||
skip = (page - 1) * limit
|
||||
|
||||
chat_list = [
|
||||
ChatTitleIdResponse(**chat.model_dump())
|
||||
for chat in await Chats.get_chats_by_user_id_and_search_text(user.id, text, skip=skip, limit=limit, db=db)
|
||||
]
|
||||
search_text = chat_search_content_text(text)
|
||||
chat_list = []
|
||||
for chat in await Chats.get_chats_by_user_id_and_search_text(user.id, text, skip=skip, limit=limit, db=db):
|
||||
chat_list.append(ChatTitleIdResponse(**chat.model_dump(), snippet=chat_search_snippet(chat.chat, search_text)))
|
||||
|
||||
# Delete tag if no chat is found
|
||||
words = text.strip().split(' ')
|
||||
|
||||
@@ -281,6 +281,34 @@
|
||||
let history = null;
|
||||
let messages = null;
|
||||
|
||||
const searchFilterPrefixes = ['tag:', 'folder:', 'pinned:', 'archived:', 'shared:'];
|
||||
|
||||
const getSnippetQuery = (query: string) => {
|
||||
return query
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
.filter(
|
||||
(word) => !searchFilterPrefixes.some((prefix) => word.toLowerCase().startsWith(prefix))
|
||||
)
|
||||
.join(' ')
|
||||
.trim();
|
||||
};
|
||||
|
||||
const getHighlightedSnippet = (snippet: string, query: string) => {
|
||||
const match = getSnippetQuery(query).toLowerCase();
|
||||
const index = match ? snippet.toLowerCase().indexOf(match) : -1;
|
||||
|
||||
if (index === -1) {
|
||||
return [{ text: snippet, highlight: false }];
|
||||
}
|
||||
|
||||
return [
|
||||
{ text: snippet.slice(0, index), highlight: false },
|
||||
{ text: snippet.slice(index, index + match.length), highlight: true },
|
||||
{ text: snippet.slice(index + match.length), highlight: false }
|
||||
].filter((part) => part.text);
|
||||
};
|
||||
|
||||
$: if (!chatListLoading && chatList) {
|
||||
loadChatPreview(selectedIdx);
|
||||
}
|
||||
@@ -699,7 +727,17 @@
|
||||
</div>
|
||||
{#if chat?.snippet}
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400 line-clamp-2 mt-0.5">
|
||||
{chat.snippet}
|
||||
{#each getHighlightedSnippet(chat.snippet, query) as part}
|
||||
{#if part.highlight}
|
||||
<mark
|
||||
class="rounded bg-yellow-200/70 px-0.5 text-inherit dark:bg-yellow-500/30"
|
||||
>
|
||||
{part.text}
|
||||
</mark>
|
||||
{:else}
|
||||
{part.text}
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user