mask.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import { BUILTIN_MASKS } from "../masks";
  2. import { getLang, Lang } from "../locales";
  3. import { DEFAULT_TOPIC, ChatMessage } from "./chat";
  4. import { ModelConfig, useAppConfig } from "./config";
  5. import { StoreKey } from "../constant";
  6. import { nanoid } from "nanoid";
  7. import { createPersistStore } from "../utils/store";
  8. export type Mask = {
  9. id: string;
  10. createdAt: number;
  11. avatar: string;
  12. name: string;
  13. hideContext?: boolean;
  14. context: ChatMessage[];
  15. syncGlobalConfig?: boolean;
  16. modelConfig: ModelConfig;
  17. lang: Lang;
  18. builtin: boolean;
  19. plugin?: string[];
  20. enableArtifacts?: boolean;
  21. enableCodeFold?: boolean;
  22. };
  23. export const DEFAULT_MASK_STATE = {
  24. masks: {} as Record<string, Mask>,
  25. language: undefined as Lang | undefined,
  26. };
  27. export type MaskState = typeof DEFAULT_MASK_STATE & {
  28. language?: Lang | undefined;
  29. };
  30. export const createEmptyMask = () =>
  31. ({
  32. id: nanoid(),
  33. avatar: "",
  34. name: DEFAULT_TOPIC,
  35. context: [],
  36. syncGlobalConfig: true, // use global config as default
  37. modelConfig: { ...useAppConfig.getState().modelConfig },
  38. lang: getLang(),
  39. builtin: false,
  40. createdAt: Date.now(),
  41. plugin: [],
  42. }) as Mask;
  43. export const useMaskStore = createPersistStore(
  44. { ...DEFAULT_MASK_STATE },
  45. (set, get) => ({
  46. create(mask?: Partial<Mask>) {
  47. const masks = get().masks;
  48. const id = nanoid();
  49. masks[id] = {
  50. ...createEmptyMask(),
  51. ...mask,
  52. id,
  53. builtin: false,
  54. };
  55. set(() => ({ masks }));
  56. get().markUpdate();
  57. return masks[id];
  58. },
  59. updateMask(id: string, updater: (mask: Mask) => void) {
  60. const masks = get().masks;
  61. const mask = masks[id];
  62. if (!mask) return;
  63. const updateMask = { ...mask };
  64. updater(updateMask);
  65. masks[id] = updateMask;
  66. set(() => ({ masks }));
  67. get().markUpdate();
  68. },
  69. delete(id: string) {
  70. const masks = get().masks;
  71. delete masks[id];
  72. set(() => ({ masks }));
  73. get().markUpdate();
  74. },
  75. get(id?: string) {
  76. return get().masks[id ?? 1145141919810];
  77. },
  78. getAll() {
  79. const userMasks = Object.values(get().masks).sort(
  80. (a, b) => b.createdAt - a.createdAt,
  81. );
  82. const config = useAppConfig.getState();
  83. if (config.hideBuiltinMasks) return userMasks;
  84. const buildinMasks = BUILTIN_MASKS.map(
  85. (m) =>
  86. ({
  87. ...m,
  88. modelConfig: {
  89. ...config.modelConfig,
  90. ...m.modelConfig,
  91. },
  92. }) as Mask,
  93. );
  94. return userMasks.concat(buildinMasks);
  95. },
  96. search(text: string) {
  97. return Object.values(get().masks);
  98. },
  99. setLanguage(language: Lang | undefined) {
  100. set({
  101. language,
  102. });
  103. },
  104. }),
  105. {
  106. name: StoreKey.Mask,
  107. version: 3.1,
  108. migrate(state, version) {
  109. const newState = JSON.parse(JSON.stringify(state)) as MaskState;
  110. // migrate mask id to nanoid
  111. if (version < 3) {
  112. Object.values(newState.masks).forEach((m) => (m.id = nanoid()));
  113. }
  114. if (version < 3.1) {
  115. const updatedMasks: Record<string, Mask> = {};
  116. Object.values(newState.masks).forEach((m) => {
  117. updatedMasks[m.id] = m;
  118. });
  119. newState.masks = updatedMasks;
  120. }
  121. return newState as any;
  122. },
  123. },
  124. );