Skip to content

Commit

Permalink
Merge pull request #4979 from ConnectAI-E/hotfix/cf-ai-gateway
Browse files Browse the repository at this point in the history
support cloudflare ai gateway
  • Loading branch information
Dogtiti committed Jul 12, 2024
2 parents 59d9bcd + 728c383 commit e8088d6
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 15 deletions.
20 changes: 11 additions & 9 deletions app/api/anthropic/[...path]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { prettyObject } from "@/app/utils/format";
import { NextRequest, NextResponse } from "next/server";
import { auth } from "../../auth";
import { isModelAvailableInServer } from "@/app/utils/model";
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";

const ALLOWD_PATH = new Set([Anthropic.ChatPath, Anthropic.ChatPath1]);

Expand Down Expand Up @@ -114,7 +115,8 @@ async function request(req: NextRequest) {
10 * 60 * 1000,
);

const fetchUrl = `${baseUrl}${path}`;
// try rebuild url, when using cloudflare ai gateway in server
const fetchUrl = cloudflareAIGatewayUrl(`${baseUrl}${path}`);

const fetchOptions: RequestInit = {
headers: {
Expand Down Expand Up @@ -164,17 +166,17 @@ async function request(req: NextRequest) {
console.error(`[Anthropic] filter`, e);
}
}
console.log("[Anthropic request]", fetchOptions.headers, req.method);
// console.log("[Anthropic request]", fetchOptions.headers, req.method);
try {
const res = await fetch(fetchUrl, fetchOptions);

console.log(
"[Anthropic response]",
res.status,
" ",
res.headers,
res.url,
);
// console.log(
// "[Anthropic response]",
// res.status,
// " ",
// res.headers,
// res.url,
// );
// to prevent browser prompt for credentials
const newHeaders = new Headers(res.headers);
newHeaders.delete("www-authenticate");
Expand Down
6 changes: 4 additions & 2 deletions app/api/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ServiceProvider,
} from "../constant";
import { isModelAvailableInServer } from "../utils/model";
import { cloudflareAIGatewayUrl } from "../utils/cloudflare";

const serverConfig = getServerSideConfig();

Expand Down Expand Up @@ -37,7 +38,7 @@ export async function requestOpenai(req: NextRequest) {
);

let baseUrl =
serverConfig.azureUrl || serverConfig.baseUrl || OPENAI_BASE_URL;
(isAzure ? serverConfig.azureUrl : serverConfig.baseUrl) || OPENAI_BASE_URL;

if (!baseUrl.startsWith("http")) {
baseUrl = `https://${baseUrl}`;
Expand Down Expand Up @@ -95,7 +96,8 @@ export async function requestOpenai(req: NextRequest) {
}
}

const fetchUrl = `${baseUrl}/${path}`;
const fetchUrl = cloudflareAIGatewayUrl(`${baseUrl}/${path}`);
console.log("fetchUrl", fetchUrl);
const fetchOptions: RequestInit = {
headers: {
"Content-Type": "application/json",
Expand Down
8 changes: 5 additions & 3 deletions app/client/platforms/anthropic.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ACCESS_CODE_PREFIX, Anthropic, ApiPath } from "@/app/constant";
import { ChatOptions, getHeaders, LLMApi, MultimodalContent, } from "../api";
import { ChatOptions, getHeaders, LLMApi, MultimodalContent } from "../api";
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
import { getClientConfig } from "@/app/config/client";
import { DEFAULT_API_HOST } from "@/app/constant";
Expand All @@ -12,6 +12,7 @@ import {
import Locale from "../../locales";
import { prettyObject } from "@/app/utils/format";
import { getMessageTextContent, isVisionModel } from "@/app/utils";
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";

export type MultiBlockContent = {
type: "image" | "text";
Expand Down Expand Up @@ -190,7 +191,7 @@ export class ClaudeApi implements LLMApi {
body: JSON.stringify(requestBody),
signal: controller.signal,
headers: {
...getHeaders(), // get common headers
...getHeaders(), // get common headers
"anthropic-version": accessStore.anthropicApiVersion,
// do not send `anthropicApiKey` in browser!!!
// Authorization: getAuthKey(accessStore.anthropicApiKey),
Expand Down Expand Up @@ -375,7 +376,8 @@ export class ClaudeApi implements LLMApi {

baseUrl = trimEnd(baseUrl, "/");

return `${baseUrl}/${path}`;
// try rebuild url, when using cloudflare ai gateway in client
return cloudflareAIGatewayUrl(`${baseUrl}/${path}`);
}
}

Expand Down
4 changes: 3 additions & 1 deletion app/client/platforms/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "@/app/constant";
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
import { collectModelsWithDefaultModel } from "@/app/utils/model";
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";

import {
ChatOptions,
Expand Down Expand Up @@ -94,7 +95,8 @@ export class ChatGPTApi implements LLMApi {

console.log("[Proxy Endpoint] ", baseUrl, path);

return [baseUrl, path].join("/");
// try rebuild url, when using cloudflare ai gateway in client
return cloudflareAIGatewayUrl([baseUrl, path].join("/"));
}

extractMessage(res: any) {
Expand Down
26 changes: 26 additions & 0 deletions app/utils/cloudflare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export function cloudflareAIGatewayUrl(fetchUrl: string) {
// rebuild fetchUrl, if using cloudflare ai gateway
// document: https://developers.cloudflare.com/ai-gateway/providers/openai/

const paths = fetchUrl.split("/");
if ("gateway.ai.cloudflare.com" == paths[2]) {
// is cloudflare.com ai gateway
// https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/azure-openai/{resource_name}/{deployment_name}/chat/completions?api-version=2023-05-15'
if ("azure-openai" == paths[6]) {
// is azure gateway
return paths.slice(0, 8).concat(paths.slice(-3)).join("/"); // rebuild ai gateway azure_url
}
// https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/openai/chat/completions
if ("openai" == paths[6]) {
// is openai gateway
return paths.slice(0, 7).concat(paths.slice(-2)).join("/"); // rebuild ai gateway openai_url
}
// https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/anthropic/v1/messages \
if ("anthropic" == paths[6]) {
// is anthropic gateway
return paths.slice(0, 7).concat(paths.slice(-2)).join("/"); // rebuild ai gateway anthropic_url
}
// TODO: Amazon Bedrock, Groq, HuggingFace...
}
return fetchUrl;
}

0 comments on commit e8088d6

Please sign in to comment.