fetchsse.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import { createParser } from 'eventsource-parser'
  2. import * as types from './types'
  3. import { fetch as globalFetch } from './fetch'
  4. import { streamAsyncIterable } from './stream-async-iterable'
  5. export class ChatGPTError2 extends types.ChatGPTError{
  6. reason?:string
  7. }
  8. export async function fetchSSE(
  9. url: string,
  10. options: Parameters<typeof fetch>[1] & {
  11. onMessage: (data: string) => void
  12. onError?: (error: any) => void
  13. },
  14. fetch: types.FetchFn = globalFetch
  15. ) {
  16. const { onMessage, onError, ...fetchOptions } = options
  17. let res ;
  18. try{
  19. res = await fetch(url, fetchOptions)
  20. console.log("resbody==========",res.body)
  21. }catch(e :any ){
  22. throw {reason: JSON.stringify({message:'fetch error, pleace check url',url ,code:'fetch_error'}) }
  23. }
  24. if (!res.ok) {
  25. let reason: string
  26. try {
  27. reason = await res.text()
  28. } catch (err) {
  29. reason = res.statusText
  30. }
  31. const msg = `ChatGPT error ${res.status}: ${reason}`
  32. const error = new ChatGPTError2(msg, { cause: res })
  33. error.statusCode = res.status
  34. error.statusText = res.statusText
  35. error.reason =reason
  36. throw error
  37. }
  38. const parser = createParser((event) => {
  39. if (event.type === 'event') {
  40. onMessage(event.data)
  41. }
  42. })
  43. // handle special response errors
  44. const feed = (chunk: string) => {
  45. let response = null
  46. try {
  47. response = JSON.parse(chunk)
  48. } catch {
  49. // ignore
  50. }
  51. if (response?.detail?.type === 'invalid_request_error') {
  52. const msg = `ChatGPT error ${response.detail.message}: ${response.detail.code} (${response.detail.type})`
  53. const error = new types.ChatGPTError(msg, { cause: response })
  54. error.statusCode = response.detail.code
  55. error.statusText = response.detail.message
  56. if (onError) {
  57. onError(error)
  58. } else {
  59. console.error(error)
  60. }
  61. // don't feed to the event parser
  62. return
  63. }
  64. parser.feed(chunk)
  65. }
  66. if (!res.body.getReader) {
  67. // Vercel polyfills `fetch` with `node-fetch`, which doesn't conform to
  68. // web standards, so this is a workaround...
  69. const body: NodeJS.ReadableStream = res.body as any
  70. if (!body.on || !body.read) {
  71. throw new types.ChatGPTError('unsupported "fetch" implementation')
  72. }
  73. body.on('readable', () => {
  74. let chunk: string | Buffer
  75. while (null !== (chunk = body.read())) {
  76. feed(chunk.toString())
  77. }
  78. })
  79. } else {
  80. for await (const chunk of streamAsyncIterable(res.body)) {
  81. const str = new TextDecoder().decode(chunk)
  82. //console.log(str );
  83. feed(str)
  84. }
  85. }
  86. }