Skip to content

Commit

Permalink
Add page to search chat history
Browse files Browse the repository at this point in the history
  • Loading branch information
heweikang committed Aug 14, 2024
1 parent edb92f7 commit cd92036
Show file tree
Hide file tree
Showing 10 changed files with 12,522 additions and 1,278 deletions.
8 changes: 8 additions & 0 deletions app/components/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ const MaskPage = dynamic(async () => (await import("./mask")).MaskPage, {
loading: () => <Loading noLogo />,
});

const SearchChat = dynamic(
async () => (await import("./search-chat")).SearchChatPage,
{
loading: () => <Loading noLogo />,
},
);

const Sd = dynamic(async () => (await import("./sd")).Sd, {
loading: () => <Loading noLogo />,
});
Expand Down Expand Up @@ -174,6 +181,7 @@ function Screen() {
<Route path={Path.Home} element={<Chat />} />
<Route path={Path.NewChat} element={<NewChat />} />
<Route path={Path.Masks} element={<MaskPage />} />
<Route path={Path.SearchChat} element={<SearchChat />} />
<Route path={Path.Chat} element={<Chat />} />
<Route path={Path.Settings} element={<Settings />} />
</Routes>
Expand Down
159 changes: 159 additions & 0 deletions app/components/search-chat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { useState, useEffect } from "react";
import { ErrorBoundary } from "./error";
import styles from "./mask.module.scss";
import { useNavigate } from "react-router-dom";
import { IconButton } from "./button";
import CloseIcon from "../icons/close.svg";
import EyeIcon from "../icons/eye.svg";
import Locale from "../locales";
import { Path } from "../constant";

import { useChatStore } from "../store";

type Item = {
id: number;
name: string;
content: string;
};
export function SearchChatPage() {
const navigate = useNavigate();

const chatStore = useChatStore();

const sessions = chatStore.sessions;
const selectSession = chatStore.selectSession;

const [searchResults, setSearchResults] = useState<Item[]>([]);

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 doSearch = (text: string) => {
// 分割关键词
const keywords = text.split(" ");

// 存储每个会话的匹配结果
const searchResults: Item[] = [];

sessions.forEach((session, index) => {
let matchCount = 0;
const contents: 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));
}
});
});

if (matchCount > 0) {
searchResults.push({
id: index,
name: session.topic,
content: contents.join("... "), // 使用...连接不同消息中的内容
});
}
});

// 按匹配数量排序,取前10个结果
return searchResults
.sort((a, b) => b.content.length - a.content.length)
.slice(0, 10);
};

return (
<ErrorBoundary>
<div className={styles["mask-page"]}>
{/* header */}
<div className="window-header">
<div className="window-header-title">
<div className="window-header-main-title">
{Locale.SearchChat.Page.Title}
</div>
<div className="window-header-submai-title">
{Locale.SearchChat.Page.SubTitle(searchResults.length)}
</div>
</div>

<div className="window-actions">
<div className="window-action-button">
<IconButton
icon={<CloseIcon />}
bordered
onClick={() => navigate(-1)}
/>
</div>
</div>
</div>

<div className={styles["mask-page-body"]}>
<div className={styles["mask-filter"]}>
{/**搜索输入框 */}
<input
type="text"
className={styles["search-bar"]}
placeholder={Locale.SearchChat.Page.Search}
autoFocus
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
const searchText = e.currentTarget.value;
if (searchText.length > 0) {
const result = doSearch(searchText);
setSearchResults(result);
}
}
}}
/>
</div>

<div>
{searchResults.map((item) => (
<div className={styles["mask-item"]} key={item.id}>
{/** 搜索匹配的文本 */}
<div className={styles["mask-header"]}>
<div className={styles["mask-title"]}>
<div className={styles["mask-name"]}>{item.name}</div>
{item.content.slice(0, 70)}
</div>
</div>
{/** 操作按钮 */}
<div className={styles["mask-actions"]}>
<IconButton
icon={<EyeIcon />}
text={Locale.SearchChat.Item.View}
onClick={() => {
navigate(Path.Chat);
selectSession(item.id);
}}
/>
</div>
</div>
))}
</div>
</div>
</div>
</ErrorBoundary>
);
}
9 changes: 9 additions & 0 deletions app/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,15 @@ export function SideBar(props: { className?: string }) {
onClick={() => setShowPluginSelector(true)}
shadow
/>
<IconButton
icon={<DiscoveryIcon />}
text={shouldNarrow ? undefined : Locale.SearchChat.Name}
className={styles["sidebar-bar-button"]}
onClick={() =>
navigate(Path.SearchChat, { state: { fromHome: true } })
}
shadow
/>
</div>
{showPluginSelector && (
<Selector
Expand Down
1 change: 1 addition & 0 deletions app/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export enum Path {
Sd = "/sd",
SdNew = "/sd-new",
Artifacts = "/artifacts",
SearchChat = "/search-chat",
}

export enum ApiPath {
Expand Down
15 changes: 15 additions & 0 deletions app/locales/cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,21 @@ const cn = {
FineTuned: {
Sysmessage: "你是一个助手",
},
SearchChat: {
Name: "搜索",
Page: {
Title: "搜索聊天记录",
Search: "输入多个关键词(空格分隔), 回车搜索",
NoResult: "没有找到结果",
NoData: "没有数据",
Loading: "加载中",

SubTitle: (count: number) => `搜索到 ${count} 条结果`,
},
Item: {
View: "查看",
},
},
Mask: {
Name: "面具",
Page: {
Expand Down
16 changes: 16 additions & 0 deletions app/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,22 @@ const en: LocaleType = {
FineTuned: {
Sysmessage: "You are an assistant that",
},
SearchChat: {
Name: "Search",
Page: {
Title: "Search Chat History",
Search:
"Enter multiple keywords (separated by spaces), press Enter to search",
NoResult: "No results found",
NoData: "No data",
Loading: "Loading...",

SubTitle: (count: number) => `Found ${count} results`,
},
Item: {
View: "View",
},
},
Mask: {
Name: "Mask",
Page: {
Expand Down
16 changes: 16 additions & 0 deletions app/locales/jp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,22 @@ const jp: PartialLocaleType = {
},
Plugin: { Name: "プラグイン" },
FineTuned: { Sysmessage: "あなたはアシスタントです" },
SearchChat: {
Name: "検索",
Page: {
Title: "チャット履歴を検索",
Search:
"複数のキーワードを入力してください(スペースで区切る)、エンターキーを押して検索",
NoResult: "結果が見つかりませんでした",
NoData: "データがありません",
Loading: "読み込み中...",

SubTitle: (count: number) => `${count} 件の結果を見つけました`,
},
Item: {
View: "表示",
},
},
Mask: {
Name: "キャラクタープリセット",
Page: {
Expand Down
16 changes: 16 additions & 0 deletions app/locales/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,22 @@ const ru: PartialLocaleType = {
FineTuned: {
Sysmessage: "Вы - ассистент, который",
},
SearchChat: {
Name: "Поиск",
Page: {
Title: "Поиск в истории чата",
Search:
"Введите несколько ключевых слов (разделенных пробелами), нажмите Enter для поиска",
NoResult: "Результаты не найдены",
NoData: "Данные отсутствуют",
Loading: "Загрузка...",

SubTitle: (count: number) => `Найдено результатов: ${count}`,
},
Item: {
View: "Просмотр",
},
},
Mask: {
Name: "Маска",
Page: {
Expand Down
Loading

0 comments on commit cd92036

Please sign in to comment.