Merge pull request #1189 from Yidadaa/bugfix-0501

Bugfix 0501
This commit is contained in:
Yifei Zhang 2023-05-01 23:44:32 +08:00 committed by GitHub
commit 5e544891aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 92 additions and 96 deletions

View File

@ -67,7 +67,10 @@ export function ChatItem(props: {
</> </>
)} )}
<div className={styles["chat-item-delete"]} onClick={props.onDelete}> <div
className={styles["chat-item-delete"]}
onClickCapture={props.onDelete}
>
<DeleteIcon /> <DeleteIcon />
</div> </div>
</div> </div>
@ -77,14 +80,14 @@ export function ChatItem(props: {
} }
export function ChatList(props: { narrow?: boolean }) { export function ChatList(props: { narrow?: boolean }) {
const [sessions, selectedIndex, selectSession, removeSession, moveSession] = const [sessions, selectedIndex, selectSession, moveSession] = useChatStore(
useChatStore((state) => [ (state) => [
state.sessions, state.sessions,
state.currentSessionIndex, state.currentSessionIndex,
state.selectSession, state.selectSession,
state.removeSession,
state.moveSession, state.moveSession,
]); ],
);
const chatStore = useChatStore(); const chatStore = useChatStore();
const navigate = useNavigate(); const navigate = useNavigate();

View File

@ -391,7 +391,7 @@ export function Chat() {
const onPromptSelect = (prompt: Prompt) => { const onPromptSelect = (prompt: Prompt) => {
setPromptHints([]); setPromptHints([]);
inputRef.current?.focus(); inputRef.current?.focus();
setUserInput(prompt.content); setTimeout(() => setUserInput(prompt.content), 60);
}; };
// auto grow input // auto grow input

View File

@ -296,7 +296,10 @@ export function MaskPage() {
icon={<AddIcon />} icon={<AddIcon />}
text={Locale.Mask.Page.Create} text={Locale.Mask.Page.Create}
bordered bordered
onClick={() => maskStore.create()} onClick={() => {
const createdMask = maskStore.create();
setEditingMaskId(createdMask.id);
}}
/> />
</div> </div>
</div> </div>

View File

@ -138,7 +138,11 @@ export function SideBar(props: { className?: string }) {
<div className={styles["sidebar-action"] + " " + styles.mobile}> <div className={styles["sidebar-action"] + " " + styles.mobile}>
<IconButton <IconButton
icon={<CloseIcon />} icon={<CloseIcon />}
onClick={chatStore.deleteSession} onClick={() => {
if (confirm(Locale.Home.DeleteChat)) {
chatStore.deleteSession(chatStore.currentSessionIndex);
}
}}
/> />
</div> </div>
<div className={styles["sidebar-action"]}> <div className={styles["sidebar-action"]}>

View File

@ -158,6 +158,7 @@ export type ToastProps = {
text: string; text: string;
onClick: () => void; onClick: () => void;
}; };
onClose?: () => void;
}; };
export function Toast(props: ToastProps) { export function Toast(props: ToastProps) {
@ -167,7 +168,10 @@ export function Toast(props: ToastProps) {
<span>{props.content}</span> <span>{props.content}</span>
{props.action && ( {props.action && (
<button <button
onClick={props.action.onClick} onClick={() => {
props.action?.onClick?.();
props.onClose?.();
}}
className={styles["toast-action"]} className={styles["toast-action"]}
> >
{props.action.text} {props.action.text}
@ -201,7 +205,7 @@ export function showToast(
close(); close();
}, delay); }, delay);
root.render(<Toast content={content} action={action} />); root.render(<Toast content={content} action={action} onClose={close} />);
} }
export type InputProps = React.HTMLProps<HTMLTextAreaElement> & { export type InputProps = React.HTMLProps<HTMLTextAreaElement> & {

View File

@ -14,9 +14,8 @@ const TIME_OUT_MS = 60000;
const makeRequestParam = ( const makeRequestParam = (
messages: Message[], messages: Message[],
options?: { options?: {
filterBot?: boolean;
stream?: boolean; stream?: boolean;
model?: ModelType; overrideModel?: ModelType;
}, },
): ChatRequest => { ): ChatRequest => {
let sendMessages = messages.map((v) => ({ let sendMessages = messages.map((v) => ({
@ -24,18 +23,14 @@ const makeRequestParam = (
content: v.content, content: v.content,
})); }));
if (options?.filterBot) {
sendMessages = sendMessages.filter((m) => m.role !== "assistant");
}
const modelConfig = { const modelConfig = {
...useAppConfig.getState().modelConfig, ...useAppConfig.getState().modelConfig,
...useChatStore.getState().currentSession().mask.modelConfig, ...useChatStore.getState().currentSession().mask.modelConfig,
}; };
// override model config // override model config
if (options?.model) { if (options?.overrideModel) {
modelConfig.model = options.model; modelConfig.model = options.overrideModel;
} }
return { return {
@ -82,8 +77,7 @@ export async function requestChat(
}, },
) { ) {
const req: ChatRequest = makeRequestParam(messages, { const req: ChatRequest = makeRequestParam(messages, {
filterBot: true, overrideModel: options?.model,
model: options?.model,
}); });
const res = await requestOpenaiClient("v1/chat/completions")(req); const res = await requestOpenaiClient("v1/chat/completions")(req);
@ -102,11 +96,11 @@ export async function requestUsage() {
.getDate() .getDate()
.toString() .toString()
.padStart(2, "0")}`; .padStart(2, "0")}`;
const ONE_DAY = 2 * 24 * 60 * 60 * 1000; const ONE_DAY = 1 * 24 * 60 * 60 * 1000;
const now = new Date(Date.now() + ONE_DAY); const now = new Date();
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
const startDate = formatDate(startOfMonth); const startDate = formatDate(startOfMonth);
const endDate = formatDate(now); const endDate = formatDate(new Date(Date.now() + ONE_DAY));
const [used, subs] = await Promise.all([ const [used, subs] = await Promise.all([
requestOpenaiClient( requestOpenaiClient(
@ -149,9 +143,8 @@ export async function requestUsage() {
export async function requestChatStream( export async function requestChatStream(
messages: Message[], messages: Message[],
options?: { options?: {
filterBot?: boolean;
modelConfig?: ModelConfig; modelConfig?: ModelConfig;
model?: ModelType; overrideModel?: ModelType;
onMessage: (message: string, done: boolean) => void; onMessage: (message: string, done: boolean) => void;
onError: (error: Error, statusCode?: number) => void; onError: (error: Error, statusCode?: number) => void;
onController?: (controller: AbortController) => void; onController?: (controller: AbortController) => void;
@ -159,8 +152,7 @@ export async function requestChatStream(
) { ) {
const req = makeRequestParam(messages, { const req = makeRequestParam(messages, {
stream: true, stream: true,
filterBot: options?.filterBot, overrideModel: options?.overrideModel,
model: options?.model,
}); });
console.log("[Request] ", req); console.log("[Request] ", req);

View File

@ -83,11 +83,10 @@ interface ChatStore {
currentSessionIndex: number; currentSessionIndex: number;
globalId: number; globalId: number;
clearSessions: () => void; clearSessions: () => void;
removeSession: (index: number) => void;
moveSession: (from: number, to: number) => void; moveSession: (from: number, to: number) => void;
selectSession: (index: number) => void; selectSession: (index: number) => void;
newSession: (mask?: Mask) => void; newSession: (mask?: Mask) => void;
deleteSession: (index?: number) => void; deleteSession: (index: number) => void;
currentSession: () => ChatSession; currentSession: () => ChatSession;
onNewMessage: (message: Message) => void; onNewMessage: (message: Message) => void;
onUserInput: (content: string) => Promise<void>; onUserInput: (content: string) => Promise<void>;
@ -130,31 +129,6 @@ export const useChatStore = create<ChatStore>()(
}); });
}, },
removeSession(index: number) {
set((state) => {
let nextIndex = state.currentSessionIndex;
const sessions = state.sessions;
if (sessions.length === 1) {
return {
currentSessionIndex: 0,
sessions: [createEmptySession()],
};
}
sessions.splice(index, 1);
if (nextIndex === index) {
nextIndex -= 1;
}
return {
currentSessionIndex: nextIndex,
sessions,
};
});
},
moveSession(from: number, to: number) { moveSession(from: number, to: number) {
set((state) => { set((state) => {
const { sessions, currentSessionIndex: oldIndex } = state; const { sessions, currentSessionIndex: oldIndex } = state;
@ -197,31 +171,46 @@ export const useChatStore = create<ChatStore>()(
})); }));
}, },
deleteSession(i?: number) { deleteSession(index) {
const deletedSession = get().currentSession(); const deletingLastSession = get().sessions.length === 1;
const index = i ?? get().currentSessionIndex; const deletedSession = get().sessions.at(index);
const isLastSession = get().sessions.length === 1;
if (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) {
get().removeSession(index);
showToast( if (!deletedSession) return;
Locale.Home.DeleteToast,
{ const sessions = get().sessions.slice();
text: Locale.Home.Revert, sessions.splice(index, 1);
onClick() {
set((state) => ({ let nextIndex = Math.min(
sessions: state.sessions get().currentSessionIndex,
.slice(0, index) sessions.length - 1,
.concat([deletedSession]) );
.concat(
state.sessions.slice(index + Number(isLastSession)), if (deletingLastSession) {
), nextIndex = 0;
})); sessions.push(createEmptySession());
},
},
5000,
);
} }
// for undo delete action
const restoreState = {
currentSessionIndex: get().currentSessionIndex,
sessions: get().sessions.slice(),
};
set(() => ({
currentSessionIndex: nextIndex,
sessions,
}));
showToast(
Locale.Home.DeleteToast,
{
text: Locale.Home.Revert,
onClick() {
set(() => restoreState);
},
},
5000,
);
}, },
currentSession() { currentSession() {
@ -247,6 +236,9 @@ export const useChatStore = create<ChatStore>()(
}, },
async onUserInput(content) { async onUserInput(content) {
const session = get().currentSession();
const modelConfig = session.mask.modelConfig;
const userMessage: Message = createMessage({ const userMessage: Message = createMessage({
role: "user", role: "user",
content, content,
@ -256,7 +248,7 @@ export const useChatStore = create<ChatStore>()(
role: "assistant", role: "assistant",
streaming: true, streaming: true,
id: userMessage.id! + 1, id: userMessage.id! + 1,
model: useAppConfig.getState().modelConfig.model, model: modelConfig.model,
}); });
// get recent messages // get recent messages
@ -290,14 +282,16 @@ export const useChatStore = create<ChatStore>()(
} }
}, },
onError(error, statusCode) { onError(error, statusCode) {
const isAborted = error.message.includes("aborted");
if (statusCode === 401) { if (statusCode === 401) {
botMessage.content = Locale.Error.Unauthorized; botMessage.content = Locale.Error.Unauthorized;
} else if (!error.message.includes("aborted")) { } else if (!isAborted) {
botMessage.content += "\n\n" + Locale.Store.Error; botMessage.content += "\n\n" + Locale.Store.Error;
} }
botMessage.streaming = false; botMessage.streaming = false;
userMessage.isError = true; userMessage.isError = !isAborted;
botMessage.isError = true; botMessage.isError = !isAborted;
set(() => ({})); set(() => ({}));
ControllerPool.remove(sessionIndex, botMessage.id ?? messageIndex); ControllerPool.remove(sessionIndex, botMessage.id ?? messageIndex);
}, },
@ -309,8 +303,7 @@ export const useChatStore = create<ChatStore>()(
controller, controller,
); );
}, },
filterBot: !useAppConfig.getState().sendBotMessages, modelConfig: { ...modelConfig },
modelConfig: useAppConfig.getState().modelConfig,
}); });
}, },
@ -329,7 +322,7 @@ export const useChatStore = create<ChatStore>()(
getMessagesWithMemory() { getMessagesWithMemory() {
const session = get().currentSession(); const session = get().currentSession();
const config = useAppConfig.getState(); const modelConfig = session.mask.modelConfig;
const messages = session.messages.filter((msg) => !msg.isError); const messages = session.messages.filter((msg) => !msg.isError);
const n = messages.length; const n = messages.length;
@ -337,7 +330,7 @@ export const useChatStore = create<ChatStore>()(
// long term memory // long term memory
if ( if (
session.mask.modelConfig.sendMemory && modelConfig.sendMemory &&
session.memoryPrompt && session.memoryPrompt &&
session.memoryPrompt.length > 0 session.memoryPrompt.length > 0
) { ) {
@ -348,14 +341,14 @@ export const useChatStore = create<ChatStore>()(
// get short term and unmemoried long term memory // get short term and unmemoried long term memory
const shortTermMemoryMessageIndex = Math.max( const shortTermMemoryMessageIndex = Math.max(
0, 0,
n - config.modelConfig.historyMessageCount, n - modelConfig.historyMessageCount,
); );
const longTermMemoryMessageIndex = session.lastSummarizeIndex; const longTermMemoryMessageIndex = session.lastSummarizeIndex;
const oldestIndex = Math.max( const oldestIndex = Math.max(
shortTermMemoryMessageIndex, shortTermMemoryMessageIndex,
longTermMemoryMessageIndex, longTermMemoryMessageIndex,
); );
const threshold = config.modelConfig.compressMessageLengthThreshold; const threshold = modelConfig.compressMessageLengthThreshold;
// get recent messages as many as possible // get recent messages as many as possible
const reversedRecentMessages = []; const reversedRecentMessages = [];
@ -414,17 +407,17 @@ export const useChatStore = create<ChatStore>()(
}); });
} }
const config = useAppConfig.getState(); const modelConfig = session.mask.modelConfig;
let toBeSummarizedMsgs = session.messages.slice( let toBeSummarizedMsgs = session.messages.slice(
session.lastSummarizeIndex, session.lastSummarizeIndex,
); );
const historyMsgLength = countMessages(toBeSummarizedMsgs); const historyMsgLength = countMessages(toBeSummarizedMsgs);
if (historyMsgLength > config?.modelConfig?.max_tokens ?? 4000) { if (historyMsgLength > modelConfig?.max_tokens ?? 4000) {
const n = toBeSummarizedMsgs.length; const n = toBeSummarizedMsgs.length;
toBeSummarizedMsgs = toBeSummarizedMsgs.slice( toBeSummarizedMsgs = toBeSummarizedMsgs.slice(
Math.max(0, n - config.modelConfig.historyMessageCount), Math.max(0, n - modelConfig.historyMessageCount),
); );
} }
@ -437,12 +430,11 @@ export const useChatStore = create<ChatStore>()(
"[Chat History] ", "[Chat History] ",
toBeSummarizedMsgs, toBeSummarizedMsgs,
historyMsgLength, historyMsgLength,
config.modelConfig.compressMessageLengthThreshold, modelConfig.compressMessageLengthThreshold,
); );
if ( if (
historyMsgLength > historyMsgLength > modelConfig.compressMessageLengthThreshold &&
config.modelConfig.compressMessageLengthThreshold &&
session.mask.modelConfig.sendMemory session.mask.modelConfig.sendMemory
) { ) {
requestChatStream( requestChatStream(
@ -452,8 +444,7 @@ export const useChatStore = create<ChatStore>()(
date: "", date: "",
}), }),
{ {
filterBot: false, overrideModel: "gpt-3.5-turbo",
model: "gpt-3.5-turbo",
onMessage(message, done) { onMessage(message, done) {
session.memoryPrompt = message; session.memoryPrompt = message;
if (done) { if (done) {

View File

@ -17,7 +17,6 @@ export enum Theme {
} }
export const DEFAULT_CONFIG = { export const DEFAULT_CONFIG = {
sendBotMessages: true as boolean,
submitKey: SubmitKey.CtrlEnter as SubmitKey, submitKey: SubmitKey.CtrlEnter as SubmitKey,
avatar: "1f603", avatar: "1f603",
fontSize: 14, fontSize: 14,