ChatGPT-Next-Web/app/store/prompt.ts

176 lines
4.4 KiB
TypeScript
Raw Normal View History

2023-03-27 16:30:12 +00:00
import { create } from "zustand";
import { persist } from "zustand/middleware";
2023-03-28 17:30:11 +00:00
import Fuse from "fuse.js";
import { getLang } from "../locales";
2023-04-26 18:00:22 +00:00
import { StoreKey } from "../constant";
2023-03-27 16:30:12 +00:00
export interface Prompt {
id?: number;
2023-04-17 17:34:12 +00:00
isUser?: boolean;
2023-03-27 16:30:12 +00:00
title: string;
content: string;
}
export interface PromptStore {
2023-04-17 17:34:12 +00:00
counter: number;
2023-03-27 16:30:12 +00:00
latestId: number;
2023-04-17 17:34:12 +00:00
prompts: Record<number, Prompt>;
2023-03-27 16:30:12 +00:00
add: (prompt: Prompt) => number;
2023-05-01 18:26:43 +00:00
get: (id: number) => Prompt | undefined;
2023-03-27 16:30:12 +00:00
remove: (id: number) => void;
search: (text: string) => Prompt[];
2023-05-01 18:26:43 +00:00
update: (id: number, updater: (prompt: Prompt) => void) => void;
2023-04-17 17:34:12 +00:00
getUserPrompts: () => Prompt[];
2023-03-27 16:30:12 +00:00
}
export const SearchService = {
ready: false,
2023-04-17 17:34:12 +00:00
builtinEngine: new Fuse<Prompt>([], { keys: ["title"] }),
userEngine: new Fuse<Prompt>([], { keys: ["title"] }),
2023-03-28 17:30:11 +00:00
count: {
builtin: 0,
},
2023-04-17 17:34:12 +00:00
allPrompts: [] as Prompt[],
builtinPrompts: [] as Prompt[],
2023-03-28 17:30:11 +00:00
2023-04-17 17:34:12 +00:00
init(builtinPrompts: Prompt[], userPrompts: Prompt[]) {
2023-03-28 17:30:11 +00:00
if (this.ready) {
return;
2023-03-27 16:30:12 +00:00
}
2023-04-17 17:34:12 +00:00
this.allPrompts = userPrompts.concat(builtinPrompts);
this.builtinPrompts = builtinPrompts.slice();
this.builtinEngine.setCollection(builtinPrompts);
this.userEngine.setCollection(userPrompts);
2023-03-27 16:30:12 +00:00
this.ready = true;
},
remove(id: number) {
2023-04-17 17:34:12 +00:00
this.userEngine.remove((doc) => doc.id === id);
2023-03-27 16:30:12 +00:00
},
add(prompt: Prompt) {
2023-04-17 17:34:12 +00:00
this.userEngine.add(prompt);
2023-03-27 16:30:12 +00:00
},
search(text: string) {
2023-04-17 17:34:12 +00:00
const userResults = this.userEngine.search(text);
const builtinResults = this.builtinEngine.search(text);
return userResults.concat(builtinResults).map((v) => v.item);
2023-03-27 16:30:12 +00:00
},
};
export const usePromptStore = create<PromptStore>()(
persist(
(set, get) => ({
2023-04-17 17:34:12 +00:00
counter: 0,
2023-03-27 16:30:12 +00:00
latestId: 0,
2023-04-17 17:34:12 +00:00
prompts: {},
2023-03-27 16:30:12 +00:00
add(prompt) {
const prompts = get().prompts;
prompt.id = get().latestId + 1;
2023-04-17 17:34:12 +00:00
prompt.isUser = true;
prompts[prompt.id] = prompt;
2023-03-27 16:30:12 +00:00
set(() => ({
latestId: prompt.id!,
prompts: prompts,
}));
return prompt.id!;
},
2023-05-01 18:26:43 +00:00
get(id) {
const targetPrompt = get().prompts[id];
if (!targetPrompt) {
return SearchService.builtinPrompts.find((v) => v.id === id);
}
return targetPrompt;
},
2023-03-27 16:30:12 +00:00
remove(id) {
const prompts = get().prompts;
2023-04-17 17:34:12 +00:00
delete prompts[id];
2023-03-27 16:30:12 +00:00
SearchService.remove(id);
set(() => ({
prompts,
2023-04-17 17:34:12 +00:00
counter: get().counter + 1,
2023-03-27 16:30:12 +00:00
}));
},
2023-04-17 17:34:12 +00:00
getUserPrompts() {
const userPrompts = Object.values(get().prompts ?? {});
userPrompts.sort((a, b) => (b.id && a.id ? b.id - a.id : 0));
return userPrompts;
},
2023-05-01 18:26:43 +00:00
update(id: number, updater) {
2023-04-17 17:34:12 +00:00
const prompt = get().prompts[id] ?? {
title: "",
content: "",
id,
};
SearchService.remove(id);
updater(prompt);
const prompts = get().prompts;
prompts[id] = prompt;
set(() => ({ prompts }));
SearchService.add(prompt);
},
2023-03-27 16:30:12 +00:00
search(text) {
if (text.length === 0) {
2023-04-17 17:34:12 +00:00
// return all rompts
return SearchService.allPrompts.concat([...get().getUserPrompts()]);
}
2023-03-27 16:30:12 +00:00
return SearchService.search(text) as Prompt[];
},
}),
{
2023-04-26 18:00:22 +00:00
name: StoreKey.Prompt,
2023-03-27 16:30:12 +00:00
version: 1,
2023-03-28 17:30:11 +00:00
onRehydrateStorage(state) {
const PROMPT_URL = "./prompts.json";
type PromptList = Array<[string, string]>;
fetch(PROMPT_URL)
.then((res) => res.json())
.then((res) => {
let fetchPrompts = [res.en, res.cn];
if (getLang() === "cn") {
fetchPrompts = fetchPrompts.reverse();
}
2023-04-17 17:34:12 +00:00
const builtinPrompts = fetchPrompts.map(
(promptList: PromptList) => {
2023-03-28 17:30:11 +00:00
return promptList.map(
([title, content]) =>
({
2023-04-17 17:34:12 +00:00
id: Math.random(),
2023-03-28 17:30:11 +00:00
title,
content,
} as Prompt),
2023-03-28 17:30:11 +00:00
);
2023-04-17 17:34:12 +00:00
},
);
const userPrompts =
usePromptStore.getState().getUserPrompts() ?? [];
2023-03-28 17:30:11 +00:00
2023-04-16 10:11:09 +00:00
const allPromptsForSearch = builtinPrompts
.reduce((pre, cur) => pre.concat(cur), [])
.filter((v) => !!v.title && !!v.content);
2023-03-28 17:30:11 +00:00
SearchService.count.builtin = res.en.length + res.cn.length;
2023-04-17 17:34:12 +00:00
SearchService.init(allPromptsForSearch, userPrompts);
2023-03-28 17:30:11 +00:00
});
},
},
),
2023-03-27 16:30:12 +00:00
);