🚸 (openai) Parse stream on client to correctly handle errors
This commit is contained in:
@@ -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 }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user