You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			139 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			TypeScript
		
	
		
		
			
		
	
	
			139 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			TypeScript
		
	
| 
											9 months ago
										 | import { BUILTIN_MASKS } from "../masks"; | ||
|  | import { getLang, Lang } from "../locales"; | ||
|  | import { DEFAULT_TOPIC, ChatMessage } from "./chat"; | ||
|  | import { ModelConfig, useAppConfig } from "./config"; | ||
|  | import { StoreKey } from "../constant"; | ||
|  | import { nanoid } from "nanoid"; | ||
|  | import { createPersistStore } from "../utils/store"; | ||
|  | 
 | ||
|  | export type Mask = { | ||
|  |   id: string; | ||
|  |   createdAt: number; | ||
|  |   avatar: string; | ||
|  |   name: string; | ||
|  |   hideContext?: boolean; | ||
|  |   context: ChatMessage[]; | ||
|  |   syncGlobalConfig?: boolean; | ||
|  |   modelConfig: ModelConfig; | ||
|  |   lang: Lang; | ||
|  |   builtin: boolean; | ||
|  |   plugin?: string[]; | ||
|  |   enableArtifacts?: boolean; | ||
|  |   enableCodeFold?: boolean; | ||
|  | }; | ||
|  | 
 | ||
|  | export const DEFAULT_MASK_STATE = { | ||
|  |   masks: {} as Record<string, Mask>, | ||
|  |   language: undefined as Lang | undefined, | ||
|  | }; | ||
|  | 
 | ||
|  | export type MaskState = typeof DEFAULT_MASK_STATE & { | ||
|  |   language?: Lang | undefined; | ||
|  | }; | ||
|  | 
 | ||
|  | export const DEFAULT_MASK_AVATAR = "gpt-bot"; | ||
|  | export const createEmptyMask = () => | ||
|  |   ({ | ||
|  |     id: nanoid(), | ||
|  |     avatar: DEFAULT_MASK_AVATAR, | ||
|  |     name: DEFAULT_TOPIC, | ||
|  |     context: [], | ||
|  |     syncGlobalConfig: true, // use global config as default
 | ||
|  |     modelConfig: { ...useAppConfig.getState().modelConfig }, | ||
|  |     lang: getLang(), | ||
|  |     builtin: false, | ||
|  |     createdAt: Date.now(), | ||
|  |     plugin: [], | ||
|  |   }) as Mask; | ||
|  | 
 | ||
|  | export const useMaskStore = createPersistStore( | ||
|  |   { ...DEFAULT_MASK_STATE }, | ||
|  | 
 | ||
|  |   (set, get) => ({ | ||
|  |     create(mask?: Partial<Mask>) { | ||
|  |       const masks = get().masks; | ||
|  |       const id = nanoid(); | ||
|  |       masks[id] = { | ||
|  |         ...createEmptyMask(), | ||
|  |         ...mask, | ||
|  |         id, | ||
|  |         builtin: false, | ||
|  |       }; | ||
|  | 
 | ||
|  |       set(() => ({ masks })); | ||
|  |       get().markUpdate(); | ||
|  | 
 | ||
|  |       return masks[id]; | ||
|  |     }, | ||
|  |     updateMask(id: string, updater: (mask: Mask) => void) { | ||
|  |       const masks = get().masks; | ||
|  |       const mask = masks[id]; | ||
|  |       if (!mask) return; | ||
|  |       const updateMask = { ...mask }; | ||
|  |       updater(updateMask); | ||
|  |       masks[id] = updateMask; | ||
|  |       set(() => ({ masks })); | ||
|  |       get().markUpdate(); | ||
|  |     }, | ||
|  |     delete(id: string) { | ||
|  |       const masks = get().masks; | ||
|  |       delete masks[id]; | ||
|  |       set(() => ({ masks })); | ||
|  |       get().markUpdate(); | ||
|  |     }, | ||
|  | 
 | ||
|  |     get(id?: string) { | ||
|  |       return get().masks[id ?? 1145141919810]; | ||
|  |     }, | ||
|  |     getAll() { | ||
|  |       const userMasks = Object.values(get().masks).sort( | ||
|  |         (a, b) => b.createdAt - a.createdAt, | ||
|  |       ); | ||
|  |       const config = useAppConfig.getState(); | ||
|  |       if (config.hideBuiltinMasks) return userMasks; | ||
|  |       const buildinMasks = BUILTIN_MASKS.map( | ||
|  |         (m) => | ||
|  |           ({ | ||
|  |             ...m, | ||
|  |             modelConfig: { | ||
|  |               ...config.modelConfig, | ||
|  |               ...m.modelConfig, | ||
|  |             }, | ||
|  |           }) as Mask, | ||
|  |       ); | ||
|  |       return userMasks.concat(buildinMasks); | ||
|  |     }, | ||
|  |     search(text: string) { | ||
|  |       return Object.values(get().masks); | ||
|  |     }, | ||
|  |     setLanguage(language: Lang | undefined) { | ||
|  |       set({ | ||
|  |         language, | ||
|  |       }); | ||
|  |     }, | ||
|  |   }), | ||
|  |   { | ||
|  |     name: StoreKey.Mask, | ||
|  |     version: 3.1, | ||
|  | 
 | ||
|  |     migrate(state, version) { | ||
|  |       const newState = JSON.parse(JSON.stringify(state)) as MaskState; | ||
|  | 
 | ||
|  |       // migrate mask id to nanoid
 | ||
|  |       if (version < 3) { | ||
|  |         Object.values(newState.masks).forEach((m) => (m.id = nanoid())); | ||
|  |       } | ||
|  | 
 | ||
|  |       if (version < 3.1) { | ||
|  |         const updatedMasks: Record<string, Mask> = {}; | ||
|  |         Object.values(newState.masks).forEach((m) => { | ||
|  |           updatedMasks[m.id] = m; | ||
|  |         }); | ||
|  |         newState.masks = updatedMasks; | ||
|  |       } | ||
|  | 
 | ||
|  |       return newState as any; | ||
|  |     }, | ||
|  |   }, | ||
|  | ); |