in src/features/chat-page/chat-store.tsx [132:259]
private async chat(formData: FormData) {
this.updateAutoScroll(true);
this.loading = "loading";
const multimodalImage = formData.get("image-base64") as unknown as string;
const newUserMessage: ChatMessageModel = {
id: uniqueId(),
role: "user",
content: this.input,
name: this.userName,
multiModalImage: multimodalImage,
createdAt: new Date(),
isDeleted: false,
threadId: this.chatThreadId,
type: "CHAT_MESSAGE",
userId: "",
};
this.messages.push(newUserMessage);
this.reset();
const controller = new AbortController();
abortController = controller;
try {
if (this.chatThreadId === "" || this.chatThreadId === undefined) {
showError("Chat thread ID is empty");
return;
}
const response = await fetch("/api/chat", {
method: "POST",
body: formData,
signal: controller.signal,
});
const onParse = (event: ParsedEvent | ReconnectInterval) => {
if (event.type === "event") {
const responseType = JSON.parse(event.data) as AzureChatCompletion;
switch (responseType.type) {
case "functionCall":
const mappedFunction: ChatMessageModel = {
id: uniqueId(),
content: responseType.response.arguments,
name: responseType.response.name,
role: "function",
createdAt: new Date(),
isDeleted: false,
threadId: this.chatThreadId,
type: "CHAT_MESSAGE",
userId: "",
multiModalImage: "",
};
this.addToMessages(mappedFunction);
break;
case "functionCallResult":
const mappedFunctionResult: ChatMessageModel = {
id: uniqueId(),
content: responseType.response,
name: "tool",
role: "tool",
createdAt: new Date(),
isDeleted: false,
threadId: this.chatThreadId,
type: "CHAT_MESSAGE",
userId: "",
multiModalImage: "",
};
this.addToMessages(mappedFunctionResult);
break;
case "content":
const mappedContent: ChatMessageModel = {
id: responseType.response.id,
content: responseType.response.choices[0].message.content || "",
name: AI_NAME,
role: "assistant",
createdAt: new Date(),
isDeleted: false,
threadId: this.chatThreadId,
type: "CHAT_MESSAGE",
userId: "",
multiModalImage: "",
};
this.addToMessages(mappedContent);
this.lastMessage = mappedContent.content;
break;
case "abort":
this.removeMessage(newUserMessage.id);
this.loading = "idle";
break;
case "error":
showError(responseType.response);
this.loading = "idle";
break;
case "finalContent":
this.loading = "idle";
this.completed(this.lastMessage);
this.updateTitle();
break;
default:
break;
}
}
};
if (response.body) {
const parser = createParser(onParse);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let done = false;
while (!done) {
const { value, done: doneReading } = await reader.read();
done = doneReading;
const chunkValue = decoder.decode(value);
parser.feed(chunkValue);
}
this.loading = "idle";
}
} catch (error) {
showError("" + error);
this.loading = "idle";
}
}