route.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import type { ChatRequest } from "../chat/typing";
  2. import { createParser } from "eventsource-parser";
  3. import { NextRequest } from "next/server";
  4. async function createStream(req: NextRequest) {
  5. const encoder = new TextEncoder();
  6. const decoder = new TextDecoder();
  7. let apiKey = process.env.OPENAI_API_KEY;
  8. const userApiKey = req.headers.get("token");
  9. if (userApiKey) {
  10. apiKey = userApiKey;
  11. console.log("[Stream] using user api key");
  12. }
  13. const res = await fetch("https://api.openai.com/v1/chat/completions", {
  14. headers: {
  15. "Content-Type": "application/json",
  16. Authorization: `Bearer ${apiKey}`,
  17. },
  18. method: "POST",
  19. body: req.body,
  20. });
  21. const stream = new ReadableStream({
  22. async start(controller) {
  23. function onParse(event: any) {
  24. if (event.type === "event") {
  25. const data = event.data;
  26. // https://beta.openai.com/docs/api-reference/completions/create#completions/create-stream
  27. if (data === "[DONE]") {
  28. controller.close();
  29. return;
  30. }
  31. try {
  32. const json = JSON.parse(data);
  33. const text = json.choices[0].delta.content;
  34. const queue = encoder.encode(text);
  35. controller.enqueue(queue);
  36. } catch (e) {
  37. controller.error(e);
  38. }
  39. }
  40. }
  41. const parser = createParser(onParse);
  42. for await (const chunk of res.body as any) {
  43. parser.feed(decoder.decode(chunk));
  44. }
  45. },
  46. });
  47. return stream;
  48. }
  49. export async function POST(req: NextRequest) {
  50. try {
  51. const stream = await createStream(req);
  52. return new Response(stream);
  53. } catch (error) {
  54. console.error("[Chat Stream]", error);
  55. }
  56. }
  57. export const config = {
  58. runtime: "edge",
  59. };