chatbot-template/components/use-block-stream.tsx

112 lines
2.8 KiB
TypeScript
Raw Normal View History

2024-11-15 12:18:17 -05:00
import type { JSONValue } from 'ai';
import { type Dispatch, type SetStateAction, useEffect, useState } from 'react';
2024-10-30 16:01:24 +05:30
import { useSWRConfig } from 'swr';
2024-11-15 12:18:17 -05:00
import type { Suggestion } from '@/lib/db/schema';
2024-10-30 16:01:24 +05:30
2024-11-15 12:18:17 -05:00
import type { UIBlock } from './block';
import { useUserMessageId } from '@/hooks/use-user-message-id';
2024-10-30 16:01:24 +05:30
type StreamingDelta = {
type:
| 'text-delta'
| 'title'
| 'id'
| 'suggestion'
| 'clear'
| 'finish'
| 'user-message-id';
2024-10-30 16:01:24 +05:30
content: string | Suggestion;
};
2024-11-07 02:40:29 +03:00
export function useBlockStream({
2024-10-30 16:01:24 +05:30
streamingData,
2024-11-07 02:40:29 +03:00
setBlock,
2024-10-30 16:01:24 +05:30
}: {
streamingData: JSONValue[] | undefined;
2024-11-07 02:40:29 +03:00
setBlock: Dispatch<SetStateAction<UIBlock>>;
2024-10-30 16:01:24 +05:30
}) {
const { mutate } = useSWRConfig();
const [optimisticSuggestions, setOptimisticSuggestions] = useState<
Array<Suggestion>
>([]);
const { setUserMessageIdFromServer } = useUserMessageId();
2024-10-30 16:01:24 +05:30
useEffect(() => {
if (optimisticSuggestions && optimisticSuggestions.length > 0) {
const [optimisticSuggestion] = optimisticSuggestions;
const url = `/api/suggestions?documentId=${optimisticSuggestion.documentId}`;
mutate(url, optimisticSuggestions, false);
}
}, [optimisticSuggestions, mutate]);
useEffect(() => {
const mostRecentDelta = streamingData?.at(-1);
if (!mostRecentDelta) return;
const delta = mostRecentDelta as StreamingDelta;
if (delta.type === 'user-message-id') {
setUserMessageIdFromServer(delta.content as string);
return;
}
2024-11-07 02:40:29 +03:00
setBlock((draftBlock) => {
2024-10-30 16:01:24 +05:30
switch (delta.type) {
case 'id':
return {
2024-11-07 02:40:29 +03:00
...draftBlock,
documentId: delta.content as string,
};
case 'title':
return {
2024-11-07 02:40:29 +03:00
...draftBlock,
title: delta.content as string,
};
2024-10-30 16:01:24 +05:30
case 'text-delta':
return {
2024-11-07 02:40:29 +03:00
...draftBlock,
content: draftBlock.content + (delta.content as string),
2024-10-30 16:01:24 +05:30
isVisible:
2024-11-07 02:40:29 +03:00
draftBlock.status === 'streaming' &&
draftBlock.content.length > 200 &&
draftBlock.content.length < 250
2024-10-30 16:01:24 +05:30
? true
2024-11-07 02:40:29 +03:00
: draftBlock.isVisible,
2024-10-30 16:01:24 +05:30
status: 'streaming',
};
case 'suggestion':
setTimeout(() => {
setOptimisticSuggestions((currentSuggestions) => [
...currentSuggestions,
delta.content as Suggestion,
]);
}, 0);
2024-11-07 02:40:29 +03:00
return draftBlock;
2024-10-30 16:01:24 +05:30
case 'clear':
return {
2024-11-07 02:40:29 +03:00
...draftBlock,
2024-10-30 16:01:24 +05:30
content: '',
status: 'streaming',
};
case 'finish':
return {
2024-11-07 02:40:29 +03:00
...draftBlock,
2024-10-30 16:01:24 +05:30
status: 'idle',
};
default:
2024-11-07 02:40:29 +03:00
return draftBlock;
2024-10-30 16:01:24 +05:30
}
});
2024-11-07 02:40:29 +03:00
}, [streamingData, setBlock]);
2024-10-30 16:01:24 +05:30
}