prompt.ts 4.2 KB

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