common.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import { NextRequest, NextResponse } from "next/server";
  2. import { getServerSideConfig } from "../config/server";
  3. import { DEFAULT_MODELS, OPENAI_BASE_URL } from "../constant";
  4. import { collectModelTable } from "../utils/model";
  5. import { makeAzurePath } from "../azure";
  6. const serverConfig = getServerSideConfig();
  7. export async function requestOpenai(req: NextRequest) {
  8. const controller = new AbortController();
  9. const authValue = req.headers.get("Authorization") ?? "";
  10. const authHeaderName = serverConfig.isAzure ? "api-key" : "Authorization";
  11. let path = `${req.nextUrl.pathname}${req.nextUrl.search}`.replaceAll(
  12. "/api/openai/",
  13. "",
  14. );
  15. let baseUrl =
  16. serverConfig.azureUrl || serverConfig.baseUrl || OPENAI_BASE_URL;
  17. if (!baseUrl.startsWith("http")) {
  18. baseUrl = `https://${baseUrl}`;
  19. }
  20. if (baseUrl.endsWith("/")) {
  21. baseUrl = baseUrl.slice(0, -1);
  22. }
  23. console.log("[Proxy] ", path);
  24. console.log("[Base Url]", baseUrl);
  25. const timeoutId = setTimeout(
  26. () => {
  27. controller.abort();
  28. },
  29. 10 * 60 * 1000,
  30. );
  31. if (serverConfig.isAzure) {
  32. if (!serverConfig.azureApiVersion) {
  33. return NextResponse.json({
  34. error: true,
  35. message: `missing AZURE_API_VERSION in server env vars`,
  36. });
  37. }
  38. path = makeAzurePath(path, serverConfig.azureApiVersion);
  39. }
  40. const fetchUrl = `${baseUrl}/${path}`;
  41. const fetchOptions: RequestInit = {
  42. headers: {
  43. "Content-Type": "application/json",
  44. "Cache-Control": "no-store",
  45. [authHeaderName]: authValue,
  46. ...(serverConfig.openaiOrgId && {
  47. "OpenAI-Organization": serverConfig.openaiOrgId,
  48. }),
  49. },
  50. method: req.method,
  51. body: req.body,
  52. // to fix #2485: https://stackoverflow.com/questions/55920957/cloudflare-worker-typeerror-one-time-use-body
  53. redirect: "manual",
  54. // @ts-ignore
  55. duplex: "half",
  56. signal: controller.signal,
  57. };
  58. // #1815 try to refuse gpt4 request
  59. if (serverConfig.customModels && req.body) {
  60. try {
  61. const modelTable = collectModelTable(
  62. DEFAULT_MODELS,
  63. serverConfig.customModels,
  64. );
  65. const clonedBody = await req.text();
  66. fetchOptions.body = clonedBody;
  67. const jsonBody = JSON.parse(clonedBody) as { model?: string };
  68. // not undefined and is false
  69. if (modelTable[jsonBody?.model ?? ""].available === false) {
  70. return NextResponse.json(
  71. {
  72. error: true,
  73. message: `you are not allowed to use ${jsonBody?.model} model`,
  74. },
  75. {
  76. status: 403,
  77. },
  78. );
  79. }
  80. } catch (e) {
  81. console.error("[OpenAI] gpt4 filter", e);
  82. }
  83. }
  84. try {
  85. const res = await fetch(fetchUrl, fetchOptions);
  86. // Extract the OpenAI-Organization header from the response
  87. const openaiOrganizationHeader = res.headers.get("OpenAI-Organization");
  88. // Check if serverConfig.openaiOrgId is defined
  89. if (serverConfig.openaiOrgId !== undefined) {
  90. // If openaiOrganizationHeader is present, log it; otherwise, log that the header is not present
  91. console.log("[Org ID]", openaiOrganizationHeader);
  92. } else {
  93. console.log("[Org ID] is not set up.");
  94. }
  95. // to prevent browser prompt for credentials
  96. const newHeaders = new Headers(res.headers);
  97. newHeaders.delete("www-authenticate");
  98. // to disable nginx buffering
  99. newHeaders.set("X-Accel-Buffering", "no");
  100. // Conditionally delete the OpenAI-Organization header from the response if [Org ID] is undefined (not setup in ENV)
  101. // Also This one is to prevent the header from being sent to the client
  102. if (!serverConfig.openaiOrgId) {
  103. newHeaders.delete("OpenAI-Organization");
  104. }
  105. return new Response(res.body, {
  106. status: res.status,
  107. statusText: res.statusText,
  108. headers: newHeaders,
  109. });
  110. } finally {
  111. clearTimeout(timeoutId);
  112. }
  113. }