🚸 (openai) Parse stream on client to correctly handle errors

This commit is contained in:
Baptiste Arnaud
2023-06-16 19:26:29 +02:00
parent 83f2a29faa
commit 524f1565d8
11 changed files with 209 additions and 154 deletions

View File

@@ -1,5 +1,10 @@
import { getOpenAiStreamerQuery } from '@/queries/getOpenAiStreamerQuery'
import { ClientSideActionContext } from '@/types'
import {
createParser,
ParsedEvent,
ReconnectInterval,
} from 'eventsource-parser'
export const streamChat =
(context: ClientSideActionContext) =>
@@ -8,25 +13,59 @@ export const streamChat =
content?: string | undefined
role?: 'system' | 'user' | 'assistant' | undefined
}[],
{ onStreamedMessage }: { onStreamedMessage?: (message: string) => void }
) => {
{
onStreamedMessage,
isRetrying,
}: { onStreamedMessage?: (message: string) => void; isRetrying?: boolean }
): Promise<{ message?: string; error?: object }> => {
const data = await getOpenAiStreamerQuery(context)(messages)
if (!data) {
return
}
if (!data) return { error: { message: "Couldn't get streamer data" } }
let message = ''
const reader = data.getReader()
const decoder = new TextDecoder()
let done = false
let message = ''
while (!done) {
const { value, done: doneReading } = await reader.read()
done = doneReading
const chunkValue = decoder.decode(value)
message += chunkValue
onStreamedMessage?.(message)
const onParse = (event: ParsedEvent | ReconnectInterval) => {
if (event.type === 'event') {
const data = event.data
try {
const json = JSON.parse(data) as {
choices: { delta: { content: string } }[]
}
const text = json.choices.at(0)?.delta.content
if (!text) return
message += text
onStreamedMessage?.(message)
} catch (e) {
console.error(e)
}
}
}
return message
const parser = createParser(onParse)
// eslint-disable-next-line no-constant-condition
while (true) {
const { value, done } = await reader.read()
if (done || !value) break
const dataString = decoder.decode(value)
if (dataString.includes('503 Service Temporarily Unavailable')) {
if (isRetrying)
return { error: { message: "Couldn't get streamer data" } }
await new Promise((resolve) => setTimeout(resolve, 1000))
return streamChat(context)(messages, {
onStreamedMessage,
isRetrying: true,
})
}
if (dataString.includes('[DONE]')) break
if (dataString.includes('"error":')) {
return { error: JSON.parse(dataString).error }
}
parser.feed(dataString)
}
return { message }
}