Browse Source

fix: #410 can not stop response

Yidadaa 1 year ago
parent
commit
8e560d2b2e
5 changed files with 57 additions and 32 deletions
  1. 3 0
      app/api/chat-stream/route.ts
  2. 21 10
      app/components/chat.tsx
  3. 6 7
      app/requests.ts
  4. 25 14
      app/store/app.ts
  5. 2 1
      scripts/setup.sh

+ 3 - 0
app/api/chat-stream/route.ts

@@ -53,6 +53,9 @@ export async function POST(req: NextRequest) {
     return new Response(stream);
   } catch (error) {
     console.error("[Chat Stream]", error);
+    return new Response(
+      ["```json\n", JSON.stringify(error, null, "  "), "\n```"].join(""),
+    );
   }
 }
 

+ 21 - 10
app/components/chat.tsx

@@ -12,7 +12,14 @@ import BotIcon from "../icons/bot.svg";
 import AddIcon from "../icons/add.svg";
 import DeleteIcon from "../icons/delete.svg";
 
-import { Message, SubmitKey, useChatStore, BOT_HELLO, ROLES } from "../store";
+import {
+  Message,
+  SubmitKey,
+  useChatStore,
+  BOT_HELLO,
+  ROLES,
+  createMessage,
+} from "../store";
 
 import {
   copyToClipboard,
@@ -407,8 +414,8 @@ export function Chat(props: {
   };
 
   // stop response
-  const onUserStop = (messageIndex: number) => {
-    ControllerPool.stop(sessionIndex, messageIndex);
+  const onUserStop = (messageId: number) => {
+    ControllerPool.stop(sessionIndex, messageId);
   };
 
   // check if should send message
@@ -439,6 +446,7 @@ export function Chat(props: {
           .onUserInput(messages[i].content)
           .then(() => setIsLoading(false));
         inputRef.current?.focus();
+        messages.splice(i, 2);
         return;
       }
     }
@@ -462,9 +470,10 @@ export function Chat(props: {
       isLoading
         ? [
             {
-              role: "assistant",
-              content: "……",
-              date: new Date().toLocaleString(),
+              ...createMessage({
+                role: "assistant",
+                content: "……",
+              }),
               preview: true,
             },
           ]
@@ -474,9 +483,10 @@ export function Chat(props: {
       userInput.length > 0 && config.sendPreviewBubble
         ? [
             {
-              role: "user",
-              content: userInput,
-              date: new Date().toLocaleString(),
+              ...createMessage({
+                role: "user",
+                content: userInput,
+              }),
               preview: true,
             },
           ]
@@ -489,6 +499,7 @@ export function Chat(props: {
   useEffect(() => {
     if (props.sideBarShowing && isMobileScreen()) return;
     inputRef.current?.focus();
+    // eslint-disable-next-line react-hooks/exhaustive-deps
   }, []);
 
   return (
@@ -592,7 +603,7 @@ export function Chat(props: {
                         {message.streaming ? (
                           <div
                             className={styles["chat-message-top-action"]}
-                            onClick={() => onUserStop(i)}
+                            onClick={() => onUserStop(message.id ?? i)}
                           >
                             {Locale.Chat.Actions.Stop}
                           </div>

+ 6 - 7
app/requests.ts

@@ -204,23 +204,22 @@ export const ControllerPool = {
 
   addController(
     sessionIndex: number,
-    messageIndex: number,
+    messageId: number,
     controller: AbortController,
   ) {
-    const key = this.key(sessionIndex, messageIndex);
+    const key = this.key(sessionIndex, messageId);
     this.controllers[key] = controller;
     return key;
   },
 
-  stop(sessionIndex: number, messageIndex: number) {
-    const key = this.key(sessionIndex, messageIndex);
+  stop(sessionIndex: number, messageId: number) {
+    const key = this.key(sessionIndex, messageId);
     const controller = this.controllers[key];
-    console.log(controller);
     controller?.abort();
   },
 
-  remove(sessionIndex: number, messageIndex: number) {
-    const key = this.key(sessionIndex, messageIndex);
+  remove(sessionIndex: number, messageId: number) {
+    const key = this.key(sessionIndex, messageId);
     delete this.controllers[key];
   },
 

+ 25 - 14
app/store/app.ts

@@ -15,8 +15,19 @@ export type Message = ChatCompletionResponseMessage & {
   date: string;
   streaming?: boolean;
   isError?: boolean;
+  id?: number;
 };
 
+export function createMessage(override: Partial<Message>): Message {
+  return {
+    id: Date.now(),
+    date: new Date().toLocaleString(),
+    role: "user",
+    content: "",
+    ...override,
+  };
+}
+
 export enum SubmitKey {
   Enter = "Enter",
   CtrlEnter = "Ctrl + Enter",
@@ -159,11 +170,10 @@ export interface ChatSession {
 }
 
 const DEFAULT_TOPIC = Locale.Store.DefaultTopic;
-export const BOT_HELLO: Message = {
+export const BOT_HELLO: Message = createMessage({
   role: "assistant",
   content: Locale.Store.BotHello,
-  date: "",
-};
+});
 
 function createEmptySession(): ChatSession {
   const createDate = new Date().toLocaleString();
@@ -311,18 +321,15 @@ export const useChatStore = create<ChatStore>()(
       },
 
       async onUserInput(content) {
-        const userMessage: Message = {
+        const userMessage: Message = createMessage({
           role: "user",
           content,
-          date: new Date().toLocaleString(),
-        };
+        });
 
-        const botMessage: Message = {
-          content: "",
+        const botMessage: Message = createMessage({
           role: "assistant",
-          date: new Date().toLocaleString(),
           streaming: true,
-        };
+        });
 
         // get recent messages
         const recentMessages = get().getMessagesWithMemory();
@@ -345,7 +352,10 @@ export const useChatStore = create<ChatStore>()(
               botMessage.streaming = false;
               botMessage.content = content;
               get().onNewMessage(botMessage);
-              ControllerPool.remove(sessionIndex, messageIndex);
+              ControllerPool.remove(
+                sessionIndex,
+                botMessage.id ?? messageIndex,
+              );
             } else {
               botMessage.content = content;
               set(() => ({}));
@@ -361,13 +371,13 @@ export const useChatStore = create<ChatStore>()(
             userMessage.isError = true;
             botMessage.isError = true;
             set(() => ({}));
-            ControllerPool.remove(sessionIndex, messageIndex);
+            ControllerPool.remove(sessionIndex, botMessage.id ?? messageIndex);
           },
           onController(controller) {
             // collect controller for stop/retry
             ControllerPool.addController(
               sessionIndex,
-              messageIndex,
+              botMessage.id ?? messageIndex,
               controller,
             );
           },
@@ -441,7 +451,8 @@ export const useChatStore = create<ChatStore>()(
           requestWithPrompt(session.messages, Locale.Store.Prompt.Topic).then(
             (res) => {
               get().updateCurrentSession(
-                (session) => (session.topic = trimTopic(res)),
+                (session) =>
+                  (session.topic = res ? trimTopic(res) : DEFAULT_TOPIC),
               );
             },
           );

+ 2 - 1
scripts/setup.sh

@@ -61,4 +61,5 @@ read -p "Enter CODE: " CODE
 read -p "Enter PORT: " PORT
 
 # Build and run the project using the environment variables
-OPENAI_API_KEY=$OPENAI_API_KEY CODE=$CODE PORT=$PORT yarn build && OPENAI_API_KEY=$OPENAI_API_KEY CODE=$CODE PORT=$PORT yarn start
+OPENAI_API_KEY=$OPENAI_API_KEY CODE=$CODE PORT=$PORT yarn build
+OPENAI_API_KEY=$OPENAI_API_KEY CODE=$CODE PORT=$PORT yarn start