fix: #410 can not stop response

This commit is contained in:
Yidadaa 2023-04-06 03:19:33 +08:00
parent c2b37f811b
commit 8e560d2b2e
5 changed files with 57 additions and 32 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -61,4 +61,5 @@ read -p "Enter CODE: " CODE
read -p "Enter PORT: " PORT read -p "Enter PORT: " PORT
# Build and run the project using the environment variables # 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