Browse Source

feat: close #118 add stop all button

Yidadaa 1 year ago
parent
commit
dc3883ed1a

+ 14 - 2
app/components/chat.tsx

@@ -19,6 +19,7 @@ import LightIcon from "../icons/light.svg";
 import DarkIcon from "../icons/dark.svg";
 import AutoIcon from "../icons/auto.svg";
 import BottomIcon from "../icons/bottom.svg";
+import StopIcon from "../icons/pause.svg";
 
 import {
   Message,
@@ -38,7 +39,6 @@ import {
   isMobileScreen,
   selectOrCopy,
   autoGrowTextArea,
-  getCSSVar,
 } from "../utils";
 
 import dynamic from "next/dynamic";
@@ -355,8 +355,8 @@ export function ChatActions(props: {
 }) {
   const chatStore = useChatStore();
 
+  // switch themes
   const theme = chatStore.config.theme;
-
   function nextTheme() {
     const themes = [Theme.Auto, Theme.Light, Theme.Dark];
     const themeIndex = themes.indexOf(theme);
@@ -365,8 +365,20 @@ export function ChatActions(props: {
     chatStore.updateConfig((config) => (config.theme = nextTheme));
   }
 
+  // stop all responses
+  const couldStop = ControllerPool.hasPending();
+  const stopAll = () => ControllerPool.stopAll();
+
   return (
     <div className={chatStyle["chat-input-actions"]}>
+      {couldStop && (
+        <div
+          className={`${chatStyle["chat-input-action"]} clickable`}
+          onClick={stopAll}
+        >
+          <StopIcon />
+        </div>
+      )}
       {!props.hitBottom && (
         <div
           className={`${chatStyle["chat-input-action"]} clickable`}

+ 1 - 1
app/icons/bottom.svg

@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><defs><rect id="path_0" x="0" y="0" width="16" height="16" /></defs><g opacity="1" transform="translate(0 0)  rotate(0 8 8)"><mask id="bg-mask-0" fill="white"><use xlink:href="#path_0"></use></mask><g mask="url(#bg-mask-0)" ><path  id="路径 1" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(8.002766666666666 2)  rotate(0 0 4.649916666666667)" d="M0,9.3L0,0 " /><path  id="路径 2" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(4 7.333333333333333)  rotate(0 4 2)" d="M8,0L4,4L0,0 " /><path  id="路径 3" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(4 14)  rotate(0 4 0)" d="M8,0L0,0 " /></g></g></svg>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><defs><rect id="path_0" x="0" y="0" width="16" height="16" /></defs><g opacity="1" transform="translate(0 0)  rotate(0 8 8)"><mask id="bg-mask-0" fill="white"><use xlink:href="#path_0"></use></mask><g mask="url(#bg-mask-0)" ><path  id="路径 1" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(4 4)  rotate(0 4 2)" d="M8,0L4,4L0,0 " /><path  id="路径 2" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(4 8)  rotate(0 4 2)" d="M8,0L4,4L0,0 " /></g></g></svg>

+ 1 - 0
app/icons/pause.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><defs><rect id="path_0" x="0" y="0" width="16" height="16" /></defs><g opacity="1" transform="translate(0 0)  rotate(0 8 8)"><mask id="bg-mask-0" fill="white"><use xlink:href="#path_0"></use></mask><g mask="url(#bg-mask-0)" ><path  id="路径 1" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(1.3333333333333333 1.3333333333333333)  rotate(0 6.666666666666666 6.666666666666666)" d="M13.33,6.67C13.33,2.98 10.35,0 6.67,0C2.98,0 0,2.98 0,6.67C0,10.35 2.98,13.33 6.67,13.33C10.35,13.33 13.33,10.35 13.33,6.67Z " /><path  id="路径 2" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(6.333333333333333 6)  rotate(0 0 2)" d="M0,0L0,4 " /><path  id="路径 3" style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0" transform="translate(9.666666666666666 6)  rotate(0 0 2)" d="M0,0L0,4 " /></g></g></svg>

+ 11 - 4
app/requests.ts

@@ -2,7 +2,7 @@ import type { ChatRequest, ChatResponse } from "./api/openai/typing";
 import { Message, ModelConfig, useAccessStore, useChatStore } from "./store";
 import { showToast } from "./components/ui-lib";
 
-const TIME_OUT_MS = 30000;
+const TIME_OUT_MS = 60000;
 
 const makeRequestParam = (
   messages: Message[],
@@ -167,15 +167,14 @@ export async function requestChatStream(
       options?.onController?.(controller);
 
       while (true) {
-        // handle time out, will stop if no response in 10 secs
         const resTimeoutId = setTimeout(() => finish(), TIME_OUT_MS);
         const content = await reader?.read();
         clearTimeout(resTimeoutId);
-      
+
         if (!content || !content.value) {
           break;
         }
-      
+
         const text = decoder.decode(content.value, { stream: true });
         responseText += text;
 
@@ -235,6 +234,14 @@ export const ControllerPool = {
     controller?.abort();
   },
 
+  stopAll() {
+    Object.values(this.controllers).forEach((v) => v.abort());
+  },
+
+  hasPending() {
+    return Object.values(this.controllers).length > 0;
+  },
+
   remove(sessionIndex: number, messageId: number) {
     const key = this.key(sessionIndex, messageId);
     delete this.controllers[key];

+ 1 - 1
app/store/app.ts

@@ -421,7 +421,7 @@ export const useChatStore = create<ChatStore>()(
           onError(error, statusCode) {
             if (statusCode === 401) {
               botMessage.content = Locale.Error.Unauthorized;
-            } else {
+            } else if (!error.message.includes("aborted")) {
               botMessage.content += "\n\n" + Locale.Store.Error;
             }
             botMessage.streaming = false;

+ 2 - 1
package.json

@@ -9,7 +9,8 @@
     "start": "next start",
     "lint": "next lint",
     "fetch": "node ./scripts/fetch-prompts.mjs",
-    "prepare": "husky install"
+    "prepare": "husky install",
+    "proxy-dev": "sh ./scripts/init-proxy.sh && proxychains -f ./scripts/proxychains.conf yarn dev"
   },
   "dependencies": {
     "@hello-pangea/dnd": "^16.2.0",

+ 1 - 0
scripts/.gitignore

@@ -0,0 +1 @@
+proxychains.conf

+ 5 - 0
scripts/init-proxy.sh

@@ -0,0 +1,5 @@
+dir="$(dirname "$0")"
+config=$dir/proxychains.conf
+host_ip=$(grep nameserver /etc/resolv.conf | sed 's/nameserver //')
+cp $dir/proxychains.template.conf $config 
+sed -i "\$s/.*/http $host_ip 7890/" $config

+ 12 - 0
scripts/proxychains.template.conf

@@ -0,0 +1,12 @@
+strict_chain
+proxy_dns 
+
+remote_dns_subnet 224
+
+tcp_read_time_out 15000
+tcp_connect_time_out 8000
+
+localnet 127.0.0.0/255.0.0.0
+
+[ProxyList]
+socks4 	127.0.0.1 9050