common.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { NextRequest, NextResponse } from "next/server";
  2. export const OPENAI_URL = "api.openai.com";
  3. const DEFAULT_PROTOCOL = "https";
  4. const PROTOCOL = process.env.PROTOCOL || DEFAULT_PROTOCOL;
  5. const BASE_URL = process.env.BASE_URL || OPENAI_URL;
  6. const DISABLE_GPT4 = !!process.env.DISABLE_GPT4;
  7. export async function requestOpenai(req: NextRequest) {
  8. const controller = new AbortController();
  9. const authValue = req.headers.get("Authorization") ?? "";
  10. const openaiPath = `${req.nextUrl.pathname}${req.nextUrl.search}`.replaceAll(
  11. "/api/openai/",
  12. "",
  13. );
  14. let baseUrl = BASE_URL;
  15. if (!baseUrl.startsWith("http")) {
  16. baseUrl = `${PROTOCOL}://${baseUrl}`;
  17. }
  18. if (baseUrl.endsWith("/")) {
  19. baseUrl = baseUrl.slice(0, -1);
  20. }
  21. console.log("[Proxy] ", openaiPath);
  22. console.log("[Base Url]", baseUrl);
  23. if (process.env.OPENAI_ORG_ID) {
  24. console.log("[Org ID]", process.env.OPENAI_ORG_ID);
  25. }
  26. const timeoutId = setTimeout(
  27. () => {
  28. controller.abort();
  29. },
  30. 10 * 60 * 1000,
  31. );
  32. const fetchUrl = `${baseUrl}/${openaiPath}`;
  33. const fetchOptions: RequestInit = {
  34. headers: {
  35. "Content-Type": "application/json",
  36. "Cache-Control": "no-store",
  37. Authorization: authValue,
  38. ...(process.env.OPENAI_ORG_ID && {
  39. "OpenAI-Organization": process.env.OPENAI_ORG_ID,
  40. }),
  41. },
  42. method: req.method,
  43. body: req.body,
  44. // to fix #2485: https://stackoverflow.com/questions/55920957/cloudflare-worker-typeerror-one-time-use-body
  45. redirect: "manual",
  46. // @ts-ignore
  47. duplex: "half",
  48. signal: controller.signal,
  49. };
  50. // #1815 try to refuse gpt4 request
  51. if (DISABLE_GPT4 && req.body) {
  52. try {
  53. const clonedBody = await req.text();
  54. fetchOptions.body = clonedBody;
  55. const jsonBody = JSON.parse(clonedBody);
  56. if ((jsonBody?.model ?? "").includes("gpt-4")) {
  57. return NextResponse.json(
  58. {
  59. error: true,
  60. message: "you are not allowed to use gpt-4 model",
  61. },
  62. {
  63. status: 403,
  64. },
  65. );
  66. }
  67. } catch (e) {
  68. console.error("[OpenAI] gpt4 filter", e);
  69. }
  70. }
  71. try {
  72. const res = await fetch(fetchUrl, fetchOptions);
  73. // to prevent browser prompt for credentials
  74. const newHeaders = new Headers(res.headers);
  75. newHeaders.delete("www-authenticate");
  76. // to disable nginx buffering
  77. newHeaders.set("X-Accel-Buffering", "no");
  78. return new Response(res.body, {
  79. status: res.status,
  80. statusText: res.statusText,
  81. headers: newHeaders,
  82. });
  83. } finally {
  84. clearTimeout(timeoutId);
  85. }
  86. }