Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat (Azure): support Azure deployment selection #3260

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 38 additions & 33 deletions app/api/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import { getServerSideConfig } from "../config/server";
import { DEFAULT_MODELS, OPENAI_BASE_URL } from "../constant";
import { collectModelTable } from "../utils/model";
import { makeAzurePath } from "../azure";
import { makeAzurePath, makeAzureBaseUrl } from "../azure";

const serverConfig = getServerSideConfig();

Expand All @@ -17,8 +17,42 @@ export async function requestOpenai(req: NextRequest) {
"",
);

let baseUrl =
serverConfig.azureUrl || serverConfig.baseUrl || OPENAI_BASE_URL;
let requestBody: ReadableStream<Uint8Array> | string | null = req.body;
let azureUrl = serverConfig.azureUrl;
if (serverConfig.customModels && requestBody) {
try {
const modelTable = collectModelTable(
DEFAULT_MODELS,
serverConfig.customModels,
);
const clonedBody = await req.text();
requestBody = clonedBody;
const jsonBody = JSON.parse(clonedBody) as { model?: string };

const model = modelTable[jsonBody?.model ?? ""];
if (!azureUrl && model.available === false) {
// not undefined and is false
// #1815 try to refuse gpt4 request
return NextResponse.json(
{
error: true,
message: `you are not allowed to use ${jsonBody?.model} model`,
},
{
status: 403,
},
);
} else if (azureUrl && model.available === true) {
// if there is an avaliable model, update the deployment id in the url.
// otherwise leave the url unchanged.
azureUrl = makeAzureBaseUrl(azureUrl, model.name);
}
} catch (e) {
console.error("[OpenAI] gpt4 filter", e);
}
}

let baseUrl = azureUrl || serverConfig.baseUrl || OPENAI_BASE_URL;

if (!baseUrl.startsWith("http")) {
baseUrl = `https://${baseUrl}`;
Expand Down Expand Up @@ -60,43 +94,14 @@ export async function requestOpenai(req: NextRequest) {
}),
},
method: req.method,
body: req.body,
body: requestBody,
// to fix #2485: https://stackoverflow.com/questions/55920957/cloudflare-worker-typeerror-one-time-use-body
redirect: "manual",
// @ts-ignore
duplex: "half",
signal: controller.signal,
};

// #1815 try to refuse gpt4 request
if (serverConfig.customModels && req.body) {
try {
const modelTable = collectModelTable(
DEFAULT_MODELS,
serverConfig.customModels,
);
const clonedBody = await req.text();
fetchOptions.body = clonedBody;

const jsonBody = JSON.parse(clonedBody) as { model?: string };

// not undefined and is false
if (modelTable[jsonBody?.model ?? ""].available === false) {
return NextResponse.json(
{
error: true,
message: `you are not allowed to use ${jsonBody?.model} model`,
},
{
status: 403,
},
);
}
} catch (e) {
console.error("[OpenAI] gpt4 filter", e);
}
}

try {
const res = await fetch(fetchUrl, fetchOptions);

Expand Down
13 changes: 13 additions & 0 deletions app/azure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,16 @@ export function makeAzurePath(path: string, apiVersion: string) {

return path;
}

export function makeAzureBaseUrl(
url: string,
deploymentId: string | undefined,
) {
const DEPLOYMENTS = "deployments";
if (!deploymentId || url.indexOf(DEPLOYMENTS) == -1) {
return url;
}

const end = url.indexOf(DEPLOYMENTS) + DEPLOYMENTS.length;
return url.substring(0, end) + "/" + deploymentId;
}
Loading