diff --git a/app/components/search-chat.tsx b/app/components/search-chat.tsx index bba9ab2160a..4d8cdbbf762 100644 --- a/app/components/search-chat.tsx +++ b/app/components/search-chat.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import { ErrorBoundary } from "./error"; import styles from "./mask.module.scss"; import { useNavigate } from "react-router-dom"; @@ -25,63 +25,80 @@ export function SearchChatPage() { const [searchResults, setSearchResults] = useState([]); - const setDefaultItems = () => { - setSearchResults( - sessions.slice(1, 7).map((session, index) => { - console.log(session.messages[0]); - return { - id: index, - name: session.topic, - content: session.messages[0].content as string, //.map((m) => m.content).join("\n") - }; - }), - ); - }; - useEffect(() => { - setDefaultItems(); - }, []); - + // const setDefaultItems = () => { + // setSearchResults( + // sessions.slice(1, 7).map((session, index) => { + // return { + // id: index, + // name: session.topic, + // content: session.messages[0].content as string, //.map((m) => m.content).join("\n") + // }; + // }), + // ); + // }; + // useEffect(() => { + // setDefaultItems(); + // }, []); + + const previousValueRef = useRef(""); + const searchInputRef = useRef(null); const doSearch = (text: string) => { - // 分割关键词 - const keywords = text.split(" "); - - // 存储每个会话的匹配结果 - const searchResults: Item[] = []; + const lowerCaseText = text.toLowerCase(); + const results: Item[] = []; sessions.forEach((session, index) => { - let matchCount = 0; - const contents: string[] = []; + const fullTextContents: string[] = []; session.messages.forEach((message) => { const content = message.content as string; const lowerCaseContent = content.toLowerCase(); - keywords.forEach((keyword) => { - const pos = lowerCaseContent.indexOf(keyword.toLowerCase()); - if (pos !== -1) { - matchCount++; - // 提取关键词前后70个字符的内容 - const start = Math.max(0, pos - 35); - const end = Math.min(content.length, pos + keyword.length + 35); - contents.push(content.substring(start, end)); - } - }); + + // 全文搜索 + let pos = lowerCaseContent.indexOf(lowerCaseText); + while (pos !== -1) { + const start = Math.max(0, pos - 35); + const end = Math.min(content.length, pos + lowerCaseText.length + 35); + fullTextContents.push(content.substring(start, end)); + pos = lowerCaseContent.indexOf( + lowerCaseText, + pos + lowerCaseText.length, + ); + } }); - if (matchCount > 0) { - searchResults.push({ + if (fullTextContents.length > 0) { + results.push({ id: index, name: session.topic, - content: contents.join("... "), // 使用...连接不同消息中的内容 + content: fullTextContents.join("... "), // 使用...连接不同消息中的内容 }); } }); - // 按匹配数量排序,取前10个结果 - return searchResults - .sort((a, b) => b.content.length - a.content.length) - .slice(0, 10); + // 按内容长度排序 + results.sort((a, b) => b.content.length - a.content.length); + + return results; }; + useEffect(() => { + const intervalId = setInterval(() => { + if (searchInputRef.current) { + const currentValue = searchInputRef.current.value; + if (currentValue !== previousValueRef.current) { + if (currentValue.length > 0) { + const result = doSearch(currentValue); + setSearchResults(result); + } + previousValueRef.current = currentValue; + } + } + }, 1000); + + // Cleanup the interval on component unmount + return () => clearInterval(intervalId); + }, []); + return (
@@ -115,6 +132,7 @@ export function SearchChatPage() { className={styles["search-bar"]} placeholder={Locale.SearchChat.Page.Search} autoFocus + ref={searchInputRef} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); diff --git a/app/components/sidebar.tsx b/app/components/sidebar.tsx index f8abb000b54..570569b0538 100644 --- a/app/components/sidebar.tsx +++ b/app/components/sidebar.tsx @@ -12,7 +12,7 @@ import DeleteIcon from "../icons/delete.svg"; import MaskIcon from "../icons/mask.svg"; import DragIcon from "../icons/drag.svg"; import DiscoveryIcon from "../icons/discovery.svg"; - +import SearchIcon from "../icons/zoom.svg"; import Locale from "../locales"; import { useAppConfig, useChatStore } from "../store"; @@ -251,7 +251,7 @@ export function SideBar(props: { className?: string }) { shadow /> } + icon={} text={shouldNarrow ? undefined : Locale.SearchChat.Name} className={styles["sidebar-bar-button"]} onClick={() => diff --git a/app/icons/zoom.svg b/app/icons/zoom.svg new file mode 100644 index 00000000000..507b4957fdc --- /dev/null +++ b/app/icons/zoom.svg @@ -0,0 +1 @@ + diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 989b32a90b3..9a3227d68a5 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -523,7 +523,7 @@ const cn = { Name: "搜索", Page: { Title: "搜索聊天记录", - Search: "输入多个关键词(空格分隔), 回车搜索", + Search: "输入搜索关键词", NoResult: "没有找到结果", NoData: "没有数据", Loading: "加载中", diff --git a/app/locales/en.ts b/app/locales/en.ts index 6af23954ff4..77f3a700ae1 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -531,8 +531,7 @@ const en: LocaleType = { Name: "Search", Page: { Title: "Search Chat History", - Search: - "Enter multiple keywords (separated by spaces), press Enter to search", + Search: "Enter search query to search chat history", NoResult: "No results found", NoData: "No data", Loading: "Loading...", diff --git a/app/locales/jp.ts b/app/locales/jp.ts index d0ff43b0bde..32ec8ae56b1 100644 --- a/app/locales/jp.ts +++ b/app/locales/jp.ts @@ -248,8 +248,7 @@ const jp: PartialLocaleType = { Name: "検索", Page: { Title: "チャット履歴を検索", - Search: - "複数のキーワードを入力してください(スペースで区切る)、エンターキーを押して検索", + Search: "キーワードを入力してください", NoResult: "結果が見つかりませんでした", NoData: "データがありません", Loading: "読み込み中...", diff --git a/app/locales/ru.ts b/app/locales/ru.ts index d83337795e9..90f46690c38 100644 --- a/app/locales/ru.ts +++ b/app/locales/ru.ts @@ -196,8 +196,7 @@ const ru: PartialLocaleType = { Name: "Поиск", Page: { Title: "Поиск в истории чата", - Search: - "Введите несколько ключевых слов (разделенных пробелами), нажмите Enter для поиска", + Search: "Введите текст для поиска", NoResult: "Результаты не найдены", NoData: "Данные отсутствуют", Loading: "Загрузка...",