prompt.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { create } from "zustand";
  2. import { persist } from "zustand/middleware";
  3. import Fuse from "fuse.js";
  4. import { getLang } from "../locales";
  5. import { StoreKey } from "../constant";
  6. export interface Prompt {
  7. id?: number;
  8. isUser?: boolean;
  9. title: string;
  10. content: string;
  11. }
  12. export interface PromptStore {
  13. counter: number;
  14. latestId: number;
  15. prompts: Record<number, Prompt>;
  16. add: (prompt: Prompt) => number;
  17. get: (id: number) => Prompt | undefined;
  18. remove: (id: number) => void;
  19. search: (text: string) => Prompt[];
  20. update: (id: number, updater: (prompt: Prompt) => void) => void;
  21. getUserPrompts: () => Prompt[];
  22. }
  23. export const SearchService = {
  24. ready: false,
  25. builtinEngine: new Fuse<Prompt>([], { keys: ["title"] }),
  26. userEngine: new Fuse<Prompt>([], { keys: ["title"] }),
  27. count: {
  28. builtin: 0,
  29. },
  30. allPrompts: [] as Prompt[],
  31. builtinPrompts: [] as Prompt[],
  32. init(builtinPrompts: Prompt[], userPrompts: Prompt[]) {
  33. if (this.ready) {
  34. return;
  35. }
  36. this.allPrompts = userPrompts.concat(builtinPrompts);
  37. this.builtinPrompts = builtinPrompts.slice();
  38. this.builtinEngine.setCollection(builtinPrompts);
  39. this.userEngine.setCollection(userPrompts);
  40. this.ready = true;
  41. },
  42. remove(id: number) {
  43. this.userEngine.remove((doc) => doc.id === id);
  44. },
  45. add(prompt: Prompt) {
  46. this.userEngine.add(prompt);
  47. },
  48. search(text: string) {
  49. const userResults = this.userEngine.search(text);
  50. const builtinResults = this.builtinEngine.search(text);
  51. return userResults.concat(builtinResults).map((v) => v.item);
  52. },
  53. };
  54. export const usePromptStore = create<PromptStore>()(
  55. persist(
  56. (set, get) => ({
  57. counter: 0,
  58. latestId: 0,
  59. prompts: {},
  60. add(prompt) {
  61. const prompts = get().prompts;
  62. prompt.id = get().latestId + 1;
  63. prompt.isUser = true;
  64. prompts[prompt.id] = prompt;
  65. set(() => ({
  66. latestId: prompt.id!,
  67. prompts: prompts,
  68. }));
  69. return prompt.id!;
  70. },
  71. get(id) {
  72. const targetPrompt = get().prompts[id];
  73. if (!targetPrompt) {
  74. return SearchService.builtinPrompts.find((v) => v.id === id);
  75. }
  76. return targetPrompt;
  77. },
  78. remove(id) {
  79. const prompts = get().prompts;
  80. delete prompts[id];
  81. SearchService.remove(id);
  82. set(() => ({
  83. prompts,
  84. counter: get().counter + 1,
  85. }));
  86. },
  87. getUserPrompts() {
  88. const userPrompts = Object.values(get().prompts ?? {});
  89. userPrompts.sort((a, b) => (b.id && a.id ? b.id - a.id : 0));
  90. return userPrompts;
  91. },
  92. update(id: number, updater) {
  93. const prompt = get().prompts[id] ?? {
  94. title: "",
  95. content: "",
  96. id,
  97. };
  98. SearchService.remove(id);
  99. updater(prompt);
  100. const prompts = get().prompts;
  101. prompts[id] = prompt;
  102. set(() => ({ prompts }));
  103. SearchService.add(prompt);
  104. },
  105. search(text) {
  106. if (text.length === 0) {
  107. // return all rompts
  108. return SearchService.allPrompts.concat([...get().getUserPrompts()]);
  109. }
  110. return SearchService.search(text) as Prompt[];
  111. },
  112. }),
  113. {
  114. name: StoreKey.Prompt,
  115. version: 1,
  116. onRehydrateStorage(state) {
  117. const PROMPT_URL = "./prompts.json";
  118. type PromptList = Array<[string, string]>;
  119. fetch(PROMPT_URL)
  120. .then((res) => res.json())
  121. .then((res) => {
  122. let fetchPrompts = [res.en, res.cn];
  123. if (getLang() === "cn") {
  124. fetchPrompts = fetchPrompts.reverse();
  125. }
  126. const builtinPrompts = fetchPrompts.map(
  127. (promptList: PromptList) => {
  128. return promptList.map(
  129. ([title, content]) =>
  130. ({
  131. id: Math.random(),
  132. title,
  133. content,
  134. } as Prompt),
  135. );
  136. },
  137. );
  138. const userPrompts =
  139. usePromptStore.getState().getUserPrompts() ?? [];
  140. const allPromptsForSearch = builtinPrompts
  141. .reduce((pre, cur) => pre.concat(cur), [])
  142. .filter((v) => !!v.title && !!v.content);
  143. SearchService.count.builtin = res.en.length + res.cn.length;
  144. SearchService.init(allPromptsForSearch, userPrompts);
  145. });
  146. },
  147. },
  148. ),
  149. );