Browse Source

Merge pull request #1189 from Yidadaa/bugfix-0501

Bugfix 0501
Yifei Zhang 1 year ago
parent
commit
5e544891aa

+ 8 - 5
app/components/chat-list.tsx

@@ -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 />
           </div>
         </div>
@@ -77,14 +80,14 @@ export function ChatItem(props: {
 }
 
 export function ChatList(props: { narrow?: boolean }) {
-  const [sessions, selectedIndex, selectSession, removeSession, moveSession] =
-    useChatStore((state) => [
+  const [sessions, selectedIndex, selectSession, moveSession] = useChatStore(
+    (state) => [
       state.sessions,
       state.currentSessionIndex,
       state.selectSession,
-      state.removeSession,
       state.moveSession,
-    ]);
+    ],
+  );
   const chatStore = useChatStore();
   const navigate = useNavigate();
 

+ 1 - 1
app/components/chat.tsx

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

+ 4 - 1
app/components/mask.tsx

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

+ 5 - 1
app/components/sidebar.tsx

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

+ 6 - 2
app/components/ui-lib.tsx

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

+ 9 - 17
app/requests.ts

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

+ 59 - 68
app/store/chat.ts

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

+ 0 - 1
app/store/config.ts

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