|
@@ -18,6 +18,7 @@ import { ChatControllerPool } from "../client/controller";
|
|
import { prettyObject } from "../utils/format";
|
|
import { prettyObject } from "../utils/format";
|
|
import { estimateTokenLength } from "../utils/token";
|
|
import { estimateTokenLength } from "../utils/token";
|
|
import { nanoid } from "nanoid";
|
|
import { nanoid } from "nanoid";
|
|
|
|
+import { createPersistStore } from "../utils/store";
|
|
|
|
|
|
export type ChatMessage = RequestMessage & {
|
|
export type ChatMessage = RequestMessage & {
|
|
date: string;
|
|
date: string;
|
|
@@ -140,12 +141,22 @@ function fillTemplateWith(input: string, modelConfig: ModelConfig) {
|
|
return output;
|
|
return output;
|
|
}
|
|
}
|
|
|
|
|
|
-export const useChatStore = create<ChatStore>()(
|
|
|
|
- persist(
|
|
|
|
- (set, get) => ({
|
|
|
|
- sessions: [createEmptySession()],
|
|
|
|
- currentSessionIndex: 0,
|
|
|
|
|
|
+const DEFAULT_CHAT_STATE = {
|
|
|
|
+ sessions: [createEmptySession()],
|
|
|
|
+ currentSessionIndex: 0,
|
|
|
|
+};
|
|
|
|
|
|
|
|
+export const useChatStore = createPersistStore(
|
|
|
|
+ DEFAULT_CHAT_STATE,
|
|
|
|
+ (set, _get) => {
|
|
|
|
+ function get() {
|
|
|
|
+ return {
|
|
|
|
+ ..._get(),
|
|
|
|
+ ...methods,
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const methods = {
|
|
clearSessions() {
|
|
clearSessions() {
|
|
set(() => ({
|
|
set(() => ({
|
|
sessions: [createEmptySession()],
|
|
sessions: [createEmptySession()],
|
|
@@ -184,7 +195,7 @@ export const useChatStore = create<ChatStore>()(
|
|
});
|
|
});
|
|
},
|
|
},
|
|
|
|
|
|
- newSession(mask) {
|
|
|
|
|
|
+ newSession(mask: Mask) {
|
|
const session = createEmptySession();
|
|
const session = createEmptySession();
|
|
|
|
|
|
if (mask) {
|
|
if (mask) {
|
|
@@ -207,14 +218,14 @@ export const useChatStore = create<ChatStore>()(
|
|
}));
|
|
}));
|
|
},
|
|
},
|
|
|
|
|
|
- nextSession(delta) {
|
|
|
|
|
|
+ nextSession(delta: number) {
|
|
const n = get().sessions.length;
|
|
const n = get().sessions.length;
|
|
const limit = (x: number) => (x + n) % n;
|
|
const limit = (x: number) => (x + n) % n;
|
|
const i = get().currentSessionIndex;
|
|
const i = get().currentSessionIndex;
|
|
get().selectSession(limit(i + delta));
|
|
get().selectSession(limit(i + delta));
|
|
},
|
|
},
|
|
|
|
|
|
- deleteSession(index) {
|
|
|
|
|
|
+ deleteSession(index: number) {
|
|
const deletingLastSession = get().sessions.length === 1;
|
|
const deletingLastSession = get().sessions.length === 1;
|
|
const deletedSession = get().sessions.at(index);
|
|
const deletedSession = get().sessions.at(index);
|
|
|
|
|
|
@@ -271,7 +282,7 @@ export const useChatStore = create<ChatStore>()(
|
|
return session;
|
|
return session;
|
|
},
|
|
},
|
|
|
|
|
|
- onNewMessage(message) {
|
|
|
|
|
|
+ onNewMessage(message: ChatMessage) {
|
|
get().updateCurrentSession((session) => {
|
|
get().updateCurrentSession((session) => {
|
|
session.messages = session.messages.concat();
|
|
session.messages = session.messages.concat();
|
|
session.lastUpdate = Date.now();
|
|
session.lastUpdate = Date.now();
|
|
@@ -280,7 +291,7 @@ export const useChatStore = create<ChatStore>()(
|
|
get().summarizeSession();
|
|
get().summarizeSession();
|
|
},
|
|
},
|
|
|
|
|
|
- async onUserInput(content) {
|
|
|
|
|
|
+ async onUserInput(content: string) {
|
|
const session = get().currentSession();
|
|
const session = get().currentSession();
|
|
const modelConfig = session.mask.modelConfig;
|
|
const modelConfig = session.mask.modelConfig;
|
|
|
|
|
|
@@ -580,14 +591,14 @@ export const useChatStore = create<ChatStore>()(
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
|
|
- updateStat(message) {
|
|
|
|
|
|
+ updateStat(message: ChatMessage) {
|
|
get().updateCurrentSession((session) => {
|
|
get().updateCurrentSession((session) => {
|
|
session.stat.charCount += message.content.length;
|
|
session.stat.charCount += message.content.length;
|
|
// TODO: should update chat count and word count
|
|
// TODO: should update chat count and word count
|
|
});
|
|
});
|
|
},
|
|
},
|
|
|
|
|
|
- updateCurrentSession(updater) {
|
|
|
|
|
|
+ updateCurrentSession(updater: (session: ChatSession) => void) {
|
|
const sessions = get().sessions;
|
|
const sessions = get().sessions;
|
|
const index = get().currentSessionIndex;
|
|
const index = get().currentSessionIndex;
|
|
updater(sessions[index]);
|
|
updater(sessions[index]);
|
|
@@ -598,56 +609,60 @@ export const useChatStore = create<ChatStore>()(
|
|
localStorage.clear();
|
|
localStorage.clear();
|
|
location.reload();
|
|
location.reload();
|
|
},
|
|
},
|
|
- }),
|
|
|
|
- {
|
|
|
|
- name: StoreKey.Chat,
|
|
|
|
- version: 3.1,
|
|
|
|
- migrate(persistedState, version) {
|
|
|
|
- const state = persistedState as any;
|
|
|
|
- const newState = JSON.parse(JSON.stringify(state)) as ChatStore;
|
|
|
|
-
|
|
|
|
- if (version < 2) {
|
|
|
|
- newState.sessions = [];
|
|
|
|
-
|
|
|
|
- const oldSessions = state.sessions;
|
|
|
|
- for (const oldSession of oldSessions) {
|
|
|
|
- const newSession = createEmptySession();
|
|
|
|
- newSession.topic = oldSession.topic;
|
|
|
|
- newSession.messages = [...oldSession.messages];
|
|
|
|
- newSession.mask.modelConfig.sendMemory = true;
|
|
|
|
- newSession.mask.modelConfig.historyMessageCount = 4;
|
|
|
|
- newSession.mask.modelConfig.compressMessageLengthThreshold = 1000;
|
|
|
|
- newState.sessions.push(newSession);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (version < 3) {
|
|
|
|
- // migrate id to nanoid
|
|
|
|
- newState.sessions.forEach((s) => {
|
|
|
|
- s.id = nanoid();
|
|
|
|
- s.messages.forEach((m) => (m.id = nanoid()));
|
|
|
|
- });
|
|
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ return methods;
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: StoreKey.Chat,
|
|
|
|
+ version: 3.1,
|
|
|
|
+ migrate(persistedState, version) {
|
|
|
|
+ const state = persistedState as any;
|
|
|
|
+ const newState = JSON.parse(
|
|
|
|
+ JSON.stringify(state),
|
|
|
|
+ ) as typeof DEFAULT_CHAT_STATE;
|
|
|
|
+
|
|
|
|
+ if (version < 2) {
|
|
|
|
+ newState.sessions = [];
|
|
|
|
+
|
|
|
|
+ const oldSessions = state.sessions;
|
|
|
|
+ for (const oldSession of oldSessions) {
|
|
|
|
+ const newSession = createEmptySession();
|
|
|
|
+ newSession.topic = oldSession.topic;
|
|
|
|
+ newSession.messages = [...oldSession.messages];
|
|
|
|
+ newSession.mask.modelConfig.sendMemory = true;
|
|
|
|
+ newSession.mask.modelConfig.historyMessageCount = 4;
|
|
|
|
+ newSession.mask.modelConfig.compressMessageLengthThreshold = 1000;
|
|
|
|
+ newState.sessions.push(newSession);
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- // Enable `enableInjectSystemPrompts` attribute for old sessions.
|
|
|
|
- // Resolve issue of old sessions not automatically enabling.
|
|
|
|
- if (version < 3.1) {
|
|
|
|
- newState.sessions.forEach((s) => {
|
|
|
|
- if (
|
|
|
|
- // Exclude those already set by user
|
|
|
|
- !s.mask.modelConfig.hasOwnProperty("enableInjectSystemPrompts")
|
|
|
|
- ) {
|
|
|
|
- // Because users may have changed this configuration,
|
|
|
|
- // the user's current configuration is used instead of the default
|
|
|
|
- const config = useAppConfig.getState();
|
|
|
|
- s.mask.modelConfig.enableInjectSystemPrompts =
|
|
|
|
- config.modelConfig.enableInjectSystemPrompts;
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
|
|
+ if (version < 3) {
|
|
|
|
+ // migrate id to nanoid
|
|
|
|
+ newState.sessions.forEach((s) => {
|
|
|
|
+ s.id = nanoid();
|
|
|
|
+ s.messages.forEach((m) => (m.id = nanoid()));
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Enable `enableInjectSystemPrompts` attribute for old sessions.
|
|
|
|
+ // Resolve issue of old sessions not automatically enabling.
|
|
|
|
+ if (version < 3.1) {
|
|
|
|
+ newState.sessions.forEach((s) => {
|
|
|
|
+ if (
|
|
|
|
+ // Exclude those already set by user
|
|
|
|
+ !s.mask.modelConfig.hasOwnProperty("enableInjectSystemPrompts")
|
|
|
|
+ ) {
|
|
|
|
+ // Because users may have changed this configuration,
|
|
|
|
+ // the user's current configuration is used instead of the default
|
|
|
|
+ const config = useAppConfig.getState();
|
|
|
|
+ s.mask.modelConfig.enableInjectSystemPrompts =
|
|
|
|
+ config.modelConfig.enableInjectSystemPrompts;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
|
|
- return newState;
|
|
|
|
- },
|
|
|
|
|
|
+ return newState as any;
|
|
},
|
|
},
|
|
- ),
|
|
|
|
|
|
+ },
|
|
);
|
|
);
|