84 lines
1.9 KiB
TypeScript
84 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
import { MessageResponse } from "@/shared/ai-elements/message";
|
|
import {
|
|
createStreamingMarkdownBufferState,
|
|
resolveStreamingMarkdownDisplayContent,
|
|
takeNextStreamingMarkdownChunk,
|
|
} from "./streaming-token-response-state";
|
|
|
|
type StreamingTokenResponseProps = {
|
|
content: string;
|
|
streaming: boolean;
|
|
streamDone?: boolean;
|
|
className?: string;
|
|
messageId?: string;
|
|
};
|
|
|
|
const STREAMING_MARKDOWN_FRAME_MS = 45;
|
|
|
|
export function StreamingTokenResponse({
|
|
content,
|
|
streaming,
|
|
streamDone = !streaming,
|
|
className,
|
|
messageId,
|
|
}: StreamingTokenResponseProps) {
|
|
const [displayContent, setDisplayContent] = useState(() =>
|
|
streamDone ? content : ""
|
|
);
|
|
|
|
useEffect(() => {
|
|
setDisplayContent((currentDisplayContent) =>
|
|
resolveStreamingMarkdownDisplayContent(
|
|
content,
|
|
currentDisplayContent,
|
|
streamDone
|
|
)
|
|
);
|
|
}, [content, messageId, streamDone]);
|
|
|
|
useEffect(() => {
|
|
if (streamDone || !streaming) {
|
|
return;
|
|
}
|
|
|
|
const showNextChunk = () => {
|
|
setDisplayContent((currentDisplayContent) => {
|
|
const { chunk, state } = takeNextStreamingMarkdownChunk(
|
|
createStreamingMarkdownBufferState(content, currentDisplayContent)
|
|
);
|
|
|
|
if (chunk || state.displayContent !== currentDisplayContent) {
|
|
return state.displayContent;
|
|
}
|
|
|
|
return currentDisplayContent;
|
|
});
|
|
};
|
|
|
|
showNextChunk();
|
|
const timer = window.setInterval(showNextChunk, STREAMING_MARKDOWN_FRAME_MS);
|
|
|
|
return () => window.clearInterval(timer);
|
|
}, [content, streamDone, streaming]);
|
|
|
|
if (!displayContent) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<MessageResponse
|
|
className={cn("agent-streaming-response", className)}
|
|
isAnimating={streaming}
|
|
mode="streaming"
|
|
parseIncompleteMarkdown={true}
|
|
>
|
|
{displayContent}
|
|
</MessageResponse>
|
|
);
|
|
}
|