Louis 6aae985a55
re-#143: use OpenAI decoder and mutate final result from client (#164)
* chore: use OpenAI parser

* chore: access host's services

* chore: take out llm service - GGUF model for the latest llama.cpp support
2023-09-12 16:29:26 +07:00

115 lines
2.9 KiB
TypeScript

import React, { useEffect } from "react";
import { displayDate } from "@/_utils/datetime";
import { useStore } from "@/_models/RootStore";
import { StreamingText, useTextBuffer } from "nextjs-openai";
import { MessageSenderType, MessageStatus } from "@/_models/ChatMessage";
import { Role } from "@/_models/History";
import { useMutation } from "@apollo/client";
import { OpenAI } from "openai-streams";
import {
UpdateMessageDocument,
UpdateMessageMutation,
UpdateMessageMutationVariables,
} from "@/graphql";
type Props = {
id?: string;
avatarUrl?: string;
senderName: string;
createdAt: number;
text?: string;
};
const StreamTextMessage: React.FC<Props> = ({
id,
senderName,
createdAt,
avatarUrl = "",
}) => {
const [data, setData] = React.useState<any | undefined>();
const { historyStore } = useStore();
const conversation = historyStore?.getActiveConversation();
const [updateMessage] = useMutation<UpdateMessageMutation>(
UpdateMessageDocument
);
React.useEffect(() => {
if (
!conversation ||
conversation.chatMessages.findIndex((e) => e.id === id) !==
conversation.chatMessages.length - 1
) {
return;
}
const messages = conversation?.chatMessages
.slice(-10)
.filter((e) => e.id !== id)
.map((e) => ({
role:
e.messageSenderType === MessageSenderType.User
? Role.User
: Role.Assistant,
content: e.text,
}));
setData({
messages,
});
}, [conversation]);
const { buffer, done } = useTextBuffer({
url: `api/openai`,
data,
});
useEffect(() => {
if (done) {
// mutate result
const variables: UpdateMessageMutationVariables = {
id: id,
data: {
content: buffer.join(""),
status: MessageStatus.Ready,
},
};
updateMessage({
variables,
});
}
}, [done]);
useEffect(() => {
if (buffer.length > 0 && conversation?.isWaitingForModelResponse) {
historyStore.finishActiveConversationWaiting();
}
}, [buffer]);
return data ? (
<div className="flex items-start gap-2">
<img
className="rounded-full"
src={avatarUrl}
width={32}
height={32}
alt=""
/>
<div className="flex flex-col gap-1 w-full">
<div className="flex gap-1 justify-start items-baseline">
<div className="text-[#1B1B1B] text-[13px] font-extrabold leading-[15.2px] dark:text-[#d1d5db]">
{senderName}
</div>
<div className="text-[11px] leading-[13.2px] font-medium text-gray-400">
{displayDate(createdAt)}
</div>
</div>
<div className="leading-[20px] whitespace-break-spaces text-[14px] font-normal dark:text-[#d1d5db]">
<StreamingText buffer={buffer} fade={100} />
</div>
</div>
</div>
) : (
<></>
);
};
export default React.memo(StreamTextMessage);