+
;
}
-export function List(props: { children: JSX.Element[] }) {
+export function List(props: { children: JSX.Element[] | JSX.Element }) {
return
{props.children}
;
}
diff --git a/app/icons/edit.svg b/app/icons/edit.svg
new file mode 100644
index 00000000..230c57b9
--- /dev/null
+++ b/app/icons/edit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/locales/cn.ts b/app/locales/cn.ts
index bed6d22c..0c81c75d 100644
--- a/app/locales/cn.ts
+++ b/app/locales/cn.ts
@@ -62,6 +62,16 @@ const cn = {
SendKey: "发送键",
Theme: "主题",
TightBorder: "紧凑边框",
+ Prompt: {
+ Disable: {
+ Title: "禁用提示词自动补全",
+ SubTitle: "禁用后将无法自动根据输入补全",
+ },
+ List: "自定义提示词列表",
+ ListCount: (builtin: number, custom: number) =>
+ `内置 ${builtin} 条,用户定义 ${custom} 条`,
+ Edit: "编辑",
+ },
HistoryCount: {
Title: "附带历史消息数",
SubTitle: "每次请求携带的历史消息数",
diff --git a/app/store/app.ts b/app/store/app.ts
index d7ff2ff7..94e25722 100644
--- a/app/store/app.ts
+++ b/app/store/app.ts
@@ -40,6 +40,8 @@ export interface ChatConfig {
theme: Theme;
tightBorder: boolean;
+ disablePromptHint: boolean;
+
modelConfig: {
model: string;
temperature: number;
@@ -124,6 +126,8 @@ const DEFAULT_CONFIG: ChatConfig = {
theme: Theme.Auto as Theme,
tightBorder: false,
+ disablePromptHint: false,
+
modelConfig: {
model: "gpt-3.5-turbo",
temperature: 1,
diff --git a/app/store/prompt.ts b/app/store/prompt.ts
index ffd6a74e..a9092936 100644
--- a/app/store/prompt.ts
+++ b/app/store/prompt.ts
@@ -1,10 +1,10 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
-import JsSearch from "js-search";
+import Fuse from "fuse.js";
+import { showToast } from "../components/ui-lib";
export interface Prompt {
id?: number;
- shortcut: string;
title: string;
content: string;
}
@@ -22,36 +22,30 @@ export const PROMPT_KEY = "prompt-store";
export const SearchService = {
ready: false,
- progress: 0, // 0 - 1, 1 means ready
- engine: new JsSearch.Search("prompts"),
- deleted: new Set
(),
+ engine: new Fuse([], { keys: ["title"] }),
+ count: {
+ builtin: 0,
+ },
- async init(prompts: PromptStore["prompts"]) {
- this.engine.addIndex("id");
- this.engine.addIndex("shortcut");
- this.engine.addIndex("title");
-
- const n = prompts.size;
- let count = 0;
- for await (const prompt of prompts.values()) {
- this.engine.addDocument(prompt);
- count += 1;
- this.progress = count / n;
+ init(prompts: Prompt[]) {
+ if (this.ready) {
+ return;
}
+ this.engine.setCollection(prompts);
this.ready = true;
},
remove(id: number) {
- this.deleted.add(id);
+ this.engine.remove((doc) => doc.id === id);
},
add(prompt: Prompt) {
- this.engine.addDocument(prompt);
+ this.engine.add(prompt);
},
search(text: string) {
- const results = this.engine.search(text) as Prompt[];
- return results.filter((v) => !v.id || !this.deleted.has(v.id));
+ const results = this.engine.search(text);
+ return results.map((v) => v.item);
},
};
@@ -91,6 +85,35 @@ export const usePromptStore = create()(
{
name: PROMPT_KEY,
version: 1,
+ onRehydrateStorage(state) {
+ const PROMPT_URL = "./prompts.json";
+
+ type PromptList = Array<[string, string]>;
+
+ fetch(PROMPT_URL)
+ .then((res) => res.json())
+ .then((res) => {
+ const builtinPrompts = [res.en, res.cn]
+ .map((promptList: PromptList) => {
+ return promptList.map(
+ ([title, content]) =>
+ ({
+ title,
+ content,
+ } as Prompt)
+ );
+ })
+ .concat([...(state?.prompts?.values() ?? [])]);
+
+ const allPromptsForSearch = builtinPrompts.reduce(
+ (pre, cur) => pre.concat(cur),
+ []
+ );
+ SearchService.count.builtin = res.en.length + res.cn.length;
+ SearchService.init(allPromptsForSearch);
+ showToast(`已加载 ${allPromptsForSearch.length} 条 Prompts`);
+ });
+ },
}
)
);
diff --git a/package.json b/package.json
index 8cf52990..fa7d09c0 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,6 @@
},
"dependencies": {
"@svgr/webpack": "^6.5.1",
- "@types/js-search": "^1.4.0",
"@types/node": "^18.14.6",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
@@ -24,7 +23,7 @@
"eslint": "8.35.0",
"eslint-config-next": "13.2.3",
"eventsource-parser": "^0.1.0",
- "js-search": "^2.0.0",
+ "fuse.js": "^6.6.2",
"next": "^13.2.3",
"node-fetch": "^3.3.1",
"openai": "^3.2.1",
@@ -38,6 +37,7 @@
"sass": "^1.59.2",
"spark-md5": "^3.0.2",
"typescript": "4.9.5",
+ "use-debounce": "^9.0.3",
"zustand": "^4.3.6"
}
}
diff --git a/yarn.lock b/yarn.lock
index 7a8baf25..e972ceb2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1320,11 +1320,6 @@
dependencies:
"@types/unist" "*"
-"@types/js-search@^1.4.0":
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/@types/js-search/-/js-search-1.4.0.tgz#f2d4afa176a4fc7b17fb46a1593847887fa1fb7b"
- integrity sha512-OMDWvQP2AmxpQI9vFh7U/TzExNGB9Sj9WQCoxUR8VXZEv6jM4cyNzLODkh1gkBHJ9Er7kdasChzEpba4FxLGaA==
-
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
@@ -2524,6 +2519,11 @@ functions-have-names@^1.2.2:
resolved "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+fuse.js@^6.6.2:
+ version "6.6.2"
+ resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.6.2.tgz#fe463fed4b98c0226ac3da2856a415576dc9a111"
+ integrity sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==
+
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@@ -3042,11 +3042,6 @@ js-sdsl@^4.1.4:
resolved "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711"
integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==
-js-search@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/js-search/-/js-search-2.0.0.tgz#84dc9d44e34ca0870d067e04b86d8038b77edc26"
- integrity sha512-lJ8KzjlwcelIWuAdKyzsXv45W6OIwRpayzc7XmU8mzgWadg5UVOKVmnq/tXudddEB9Ceic3tVaGu6QOK/eebhg==
-
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -4660,6 +4655,11 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
+use-debounce@^9.0.3:
+ version "9.0.3"
+ resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-9.0.3.tgz#bac660c19ab7b38662e08608fee23c7ad303f532"
+ integrity sha512-FhtlbDtDXILJV7Lix5OZj5yX/fW1tzq+VrvK1fnT2bUrPOGruU9Rw8NCEn+UI9wopfERBEZAOQ8lfeCJPllgnw==
+
use-sync-external-store@1.2.0:
version "1.2.0"
resolved "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"