2022-12-05 23:09:31 +00:00
|
|
|
import { createParser } from 'eventsource-parser'
|
|
|
|
|
2022-12-10 22:19:35 +00:00
|
|
|
import * as types from './types'
|
2023-02-14 06:30:06 +00:00
|
|
|
import { fetch as globalFetch } from './fetch'
|
2022-12-06 22:13:11 +00:00
|
|
|
import { streamAsyncIterable } from './stream-async-iterable'
|
2022-12-05 23:09:31 +00:00
|
|
|
|
|
|
|
export async function fetchSSE(
|
|
|
|
url: string,
|
2023-02-14 06:30:06 +00:00
|
|
|
options: Parameters<typeof fetch>[1] & { onMessage: (data: string) => void },
|
|
|
|
fetch: types.FetchFn = globalFetch
|
2022-12-05 23:09:31 +00:00
|
|
|
) {
|
|
|
|
const { onMessage, ...fetchOptions } = options
|
2022-12-07 00:19:30 +00:00
|
|
|
const res = await fetch(url, fetchOptions)
|
|
|
|
if (!res.ok) {
|
2023-02-28 10:02:46 +00:00
|
|
|
let reason: string
|
|
|
|
|
|
|
|
try {
|
|
|
|
reason = await res.text()
|
|
|
|
} catch (err) {
|
|
|
|
reason = res.statusText
|
|
|
|
}
|
|
|
|
|
|
|
|
const msg = `ChatGPT error ${res.status}: ${reason}`
|
2023-02-01 09:14:10 +00:00
|
|
|
const error = new types.ChatGPTError(msg, { cause: res })
|
2022-12-10 22:19:35 +00:00
|
|
|
error.statusCode = res.status
|
|
|
|
error.statusText = res.statusText
|
|
|
|
throw error
|
2022-12-07 00:19:30 +00:00
|
|
|
}
|
|
|
|
|
2022-12-05 23:09:31 +00:00
|
|
|
const parser = createParser((event) => {
|
|
|
|
if (event.type === 'event') {
|
|
|
|
onMessage(event.data)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-12-07 20:44:30 +00:00
|
|
|
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
|
|
|
|
|
2022-12-07 21:03:42 +00:00
|
|
|
if (!body.on || !body.read) {
|
2022-12-10 22:19:35 +00:00
|
|
|
throw new types.ChatGPTError('unsupported "fetch" implementation')
|
2022-12-07 20:44:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2022-12-06 22:13:11 +00:00
|
|
|
}
|
2022-12-05 23:09:31 +00:00
|
|
|
}
|