chatgpt-api/src/fetch-sse.ts

49 wiersze
1.4 KiB
TypeScript

import { createParser } from 'eventsource-parser'
import * as types from './types'
import { fetch } from './fetch'
import { streamAsyncIterable } from './stream-async-iterable'
export async function fetchSSE(
url: string,
options: Parameters<typeof fetch>[1] & { onMessage: (data: string) => void }
) {
const { onMessage, ...fetchOptions } = options
const res = await fetch(url, fetchOptions)
if (!res.ok) {
const msg = `ChatGPT error ${res.status || res.statusText}`
const error = new types.ChatGPTError(msg, { cause: res })
error.statusCode = res.status
error.statusText = res.statusText
throw error
}
const parser = createParser((event) => {
if (event.type === 'event') {
onMessage(event.data)
}
})
if (!res.body.getReader) {
// Vercel polyfills `fetch` with `node-fetch`, which doesn't conform to
// web standards, so this is a workaround...
const body: NodeJS.ReadableStream = res.body as any
if (!body.on || !body.read) {
throw new types.ChatGPTError('unsupported "fetch" implementation')
}
body.on('readable', () => {
let chunk: string | Buffer
while (null !== (chunk = body.read())) {
parser.feed(chunk.toString())
}
})
} else {
for await (const chunk of streamAsyncIterable(res.body)) {
const str = new TextDecoder().decode(chunk)
parser.feed(str)
}
}
}