mask.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. };
  20. export const DEFAULT_MASK_STATE = {
  21. masks: {} as Record<string, Mask>,
  22. };
  23. export type MaskState = typeof DEFAULT_MASK_STATE;
  24. export const DEFAULT_MASK_AVATAR = "gpt-bot";
  25. export const createEmptyMask = () =>
  26. ({
  27. id: nanoid(),
  28. avatar: DEFAULT_MASK_AVATAR,
  29. name: DEFAULT_TOPIC,
  30. context: [],
  31. syncGlobalConfig: true, // use global config as default
  32. modelConfig: { ...useAppConfig.getState().modelConfig },
  33. lang: getLang(),
  34. builtin: false,
  35. createdAt: Date.now(),
  36. }) as Mask;
  37. export const useMaskStore = createPersistStore(
  38. { ...DEFAULT_MASK_STATE },
  39. (set, get) => ({
  40. create(mask?: Partial<Mask>) {
  41. const masks = get().masks;
  42. const id = nanoid();
  43. masks[id] = {
  44. ...createEmptyMask(),
  45. ...mask,
  46. id,
  47. builtin: false,
  48. };
  49. set(() => ({ masks }));
  50. get().markUpdate();
  51. return masks[id];
  52. },
  53. updateMask(id: string, updater: (mask: Mask) => void) {
  54. const masks = get().masks;
  55. const mask = masks[id];
  56. if (!mask) return;
  57. const updateMask = { ...mask };
  58. updater(updateMask);
  59. masks[id] = updateMask;
  60. set(() => ({ masks }));
  61. get().markUpdate();
  62. },
  63. delete(id: string) {
  64. const masks = get().masks;
  65. delete masks[id];
  66. set(() => ({ masks }));
  67. get().markUpdate();
  68. },
  69. get(id?: string) {
  70. return get().masks[id ?? 1145141919810];
  71. },
  72. getAll() {
  73. const userMasks = Object.values(get().masks).sort(
  74. (a, b) => b.createdAt - a.createdAt,
  75. );
  76. const config = useAppConfig.getState();
  77. if (config.hideBuiltinMasks) return userMasks;
  78. const buildinMasks = BUILTIN_MASKS.map(
  79. (m) =>
  80. ({
  81. ...m,
  82. modelConfig: {
  83. ...config.modelConfig,
  84. ...m.modelConfig,
  85. },
  86. }) as Mask,
  87. );
  88. return userMasks.concat(buildinMasks);
  89. },
  90. search(text: string) {
  91. return Object.values(get().masks);
  92. },
  93. }),
  94. {
  95. name: StoreKey.Mask,
  96. version: 3.1,
  97. migrate(state, version) {
  98. const newState = JSON.parse(JSON.stringify(state)) as MaskState;
  99. // migrate mask id to nanoid
  100. if (version < 3) {
  101. Object.values(newState.masks).forEach((m) => (m.id = nanoid()));
  102. }
  103. if (version < 3.1) {
  104. const updatedMasks: Record<string, Mask> = {};
  105. Object.values(newState.masks).forEach((m) => {
  106. updatedMasks[m.id] = m;
  107. });
  108. newState.masks = updatedMasks;
  109. }
  110. return newState as any;
  111. },
  112. },
  113. );