diff --git a/app/api/chat-stream/route.ts b/app/api/chat-stream/route.ts
index f3317554..526623ce 100644
--- a/app/api/chat-stream/route.ts
+++ b/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(""),
+ );
}
}
diff --git a/app/components/chat.tsx b/app/components/chat.tsx
index dc746e24..ea1eb7e2 100644
--- a/app/components/chat.tsx
+++ b/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 ? (
onUserStop(i)}
+ onClick={() => onUserStop(message.id ?? i)}
>
{Locale.Chat.Actions.Stop}
diff --git a/app/requests.ts b/app/requests.ts
index da9b5c97..c60efc95 100644
--- a/app/requests.ts
+++ b/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];
},
diff --git a/app/store/app.ts b/app/store/app.ts
index 9f1e8e88..64faa31d 100644
--- a/app/store/app.ts
+++ b/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 {
+ 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()(
},
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()(
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()(
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()(
requestWithPrompt(session.messages, Locale.Store.Prompt.Topic).then(
(res) => {
get().updateCurrentSession(
- (session) => (session.topic = trimTopic(res)),
+ (session) =>
+ (session.topic = res ? trimTopic(res) : DEFAULT_TOPIC),
);
},
);
diff --git a/scripts/setup.sh b/scripts/setup.sh
index 63a28bf0..b9653339 100644
--- a/scripts/setup.sh
+++ b/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