feat: close #118 add stop all button

This commit is contained in:
Yidadaa 2023-04-16 18:07:43 +08:00
parent bd69c8f5dd
commit dc3883ed1a
9 changed files with 48 additions and 9 deletions

View File

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

View File

@ -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>

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 736 B

1
app/icons/pause.svg Normal file
View File

@ -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>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

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

View File

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

View File

@ -9,7 +9,8 @@
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"fetch": "node ./scripts/fetch-prompts.mjs", "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": { "dependencies": {
"@hello-pangea/dnd": "^16.2.0", "@hello-pangea/dnd": "^16.2.0",

1
scripts/.gitignore vendored Normal file
View File

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

5
scripts/init-proxy.sh Normal file
View File

@ -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

View File

@ -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