mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-09 19:46:37 +08:00
feat: 增加Azure opanai 能力支持
This commit is contained in:
parent
beb04d8181
commit
19949906c6
@ -1,15 +1,21 @@
|
|||||||
import { NextRequest } from "next/server";
|
import { NextRequest } from "next/server";
|
||||||
|
|
||||||
const OPENAI_URL = "api.openai.com";
|
const OPENAI_URL = "api.openai.com";
|
||||||
|
const AZURE_OPENAI_URL = "azure-openai-gpt.openai.azure.com";
|
||||||
const DEFAULT_PROTOCOL = "https";
|
const DEFAULT_PROTOCOL = "https";
|
||||||
const PROTOCOL = process.env.PROTOCOL ?? DEFAULT_PROTOCOL;
|
const PROTOCOL = process.env.PROTOCOL ?? DEFAULT_PROTOCOL;
|
||||||
const BASE_URL = process.env.BASE_URL ?? OPENAI_URL;
|
|
||||||
|
|
||||||
export async function requestOpenai(req: NextRequest) {
|
export async function requestOpenai(req: NextRequest) {
|
||||||
const apiKey = req.headers.get("token");
|
const apiKey = req.headers.get("token");
|
||||||
const openaiPath = req.headers.get("path");
|
const openaiPath = req.headers.get("path");
|
||||||
|
|
||||||
let baseUrl = BASE_URL;
|
let baseUrl = OPENAI_URL;
|
||||||
|
if (openaiPath?.includes("/deployments/")) {
|
||||||
|
baseUrl = AZURE_OPENAI_URL;
|
||||||
|
}
|
||||||
|
if (process.env.BASE_URL) {
|
||||||
|
baseUrl = process.env.BASE_URL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!baseUrl.startsWith("http")) {
|
if (!baseUrl.startsWith("http")) {
|
||||||
baseUrl = `${PROTOCOL}://${baseUrl}`;
|
baseUrl = `${PROTOCOL}://${baseUrl}`;
|
||||||
@ -22,6 +28,7 @@ export async function requestOpenai(req: NextRequest) {
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${apiKey}`,
|
Authorization: `Bearer ${apiKey}`,
|
||||||
|
"api-key": apiKey || "",
|
||||||
},
|
},
|
||||||
method: req.method,
|
method: req.method,
|
||||||
body: req.body,
|
body: req.body,
|
||||||
|
@ -23,6 +23,7 @@ import {
|
|||||||
useUpdateStore,
|
useUpdateStore,
|
||||||
useAccessStore,
|
useAccessStore,
|
||||||
ModalConfigValidator,
|
ModalConfigValidator,
|
||||||
|
AZURE_API_VERSION,
|
||||||
} from "../store";
|
} from "../store";
|
||||||
import { Avatar } from "./chat";
|
import { Avatar } from "./chat";
|
||||||
|
|
||||||
@ -466,6 +467,34 @@ export function Settings(props: { closeSettings: () => void }) {
|
|||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<SettingItem title={Locale.Settings.EnableAOAI}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={accessStore.enableAOAI}
|
||||||
|
onChange={(e) => {
|
||||||
|
accessStore.switchAOAI(e.currentTarget.checked);
|
||||||
|
}}
|
||||||
|
></input>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
|
{accessStore.enableAOAI ? (
|
||||||
|
<SettingItem
|
||||||
|
title={Locale.Settings.AzureDeploymentName.Title}
|
||||||
|
subTitle={Locale.Settings.AzureDeploymentName.SubTitle}
|
||||||
|
>
|
||||||
|
<PasswordInput
|
||||||
|
value={accessStore.azureDeployName}
|
||||||
|
type="text"
|
||||||
|
placeholder={Locale.Settings.AzureDeploymentName.Placeholder}
|
||||||
|
onChange={(e) => {
|
||||||
|
accessStore.updateDeployName(e.currentTarget.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SettingItem>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
|
||||||
<SettingItem
|
<SettingItem
|
||||||
title={Locale.Settings.Token.Title}
|
title={Locale.Settings.Token.Title}
|
||||||
subTitle={Locale.Settings.Token.SubTitle}
|
subTitle={Locale.Settings.Token.SubTitle}
|
||||||
@ -588,11 +617,13 @@ export function Settings(props: { closeSettings: () => void }) {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{ALL_MODELS.map((v) => (
|
{(accessStore.enableAOAI ? AZURE_API_VERSION : ALL_MODELS).map(
|
||||||
<option value={v.name} key={v.name} disabled={!v.available}>
|
(v) => (
|
||||||
{v.name}
|
<option value={v.name} key={v.name} disabled={!v.available}>
|
||||||
</option>
|
{v.name}
|
||||||
))}
|
</option>
|
||||||
|
),
|
||||||
|
)}
|
||||||
</select>
|
</select>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
<SettingItem
|
<SettingItem
|
||||||
|
@ -96,6 +96,7 @@ const cn = {
|
|||||||
Theme: "主题",
|
Theme: "主题",
|
||||||
TightBorder: "无边框模式",
|
TightBorder: "无边框模式",
|
||||||
SendPreviewBubble: "发送预览气泡",
|
SendPreviewBubble: "发送预览气泡",
|
||||||
|
|
||||||
Prompt: {
|
Prompt: {
|
||||||
Disable: {
|
Disable: {
|
||||||
Title: "禁用提示词自动补全",
|
Title: "禁用提示词自动补全",
|
||||||
@ -124,6 +125,12 @@ const cn = {
|
|||||||
SubTitle: "使用自己的 Key 可绕过密码访问限制",
|
SubTitle: "使用自己的 Key 可绕过密码访问限制",
|
||||||
Placeholder: "OpenAI API Key",
|
Placeholder: "OpenAI API Key",
|
||||||
},
|
},
|
||||||
|
EnableAOAI: "使用 Azure OpenAI",
|
||||||
|
AzureDeploymentName: {
|
||||||
|
Title: "Azure OpenAI 部署实例名称",
|
||||||
|
SubTitle: "启用Azure OpenAI后, 输入部署的实例名称",
|
||||||
|
Placeholder: "实例名称",
|
||||||
|
},
|
||||||
Usage: {
|
Usage: {
|
||||||
Title: "余额查询",
|
Title: "余额查询",
|
||||||
SubTitle(used: any, total: any) {
|
SubTitle(used: any, total: any) {
|
||||||
|
@ -48,6 +48,17 @@ function getHeaders() {
|
|||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRequestPath() {
|
||||||
|
const OPENAI_REQUEST_PATH = "v1/chat/completions";
|
||||||
|
|
||||||
|
const { enableAOAI, azureDeployName } = useAccessStore.getState();
|
||||||
|
const { modelConfig } = useChatStore.getState().config;
|
||||||
|
if (!enableAOAI) return OPENAI_REQUEST_PATH;
|
||||||
|
|
||||||
|
const AZURE_REQUEST_PATH = `openai/deployments/${azureDeployName}/chat/completions?api-version=${modelConfig.model}`;
|
||||||
|
return AZURE_REQUEST_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
export function requestOpenaiClient(path: string) {
|
export function requestOpenaiClient(path: string) {
|
||||||
return (body: any, method = "POST") =>
|
return (body: any, method = "POST") =>
|
||||||
fetch("/api/openai?_vercel_no_cache=1", {
|
fetch("/api/openai?_vercel_no_cache=1", {
|
||||||
@ -64,7 +75,7 @@ export function requestOpenaiClient(path: string) {
|
|||||||
export async function requestChat(messages: Message[]) {
|
export async function requestChat(messages: Message[]) {
|
||||||
const req: ChatRequest = makeRequestParam(messages, { filterBot: true });
|
const req: ChatRequest = makeRequestParam(messages, { filterBot: true });
|
||||||
|
|
||||||
const res = await requestOpenaiClient("v1/chat/completions")(req);
|
const res = await requestOpenaiClient(getRequestPath())(req);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = (await res.json()) as ChatResponse;
|
const response = (await res.json()) as ChatResponse;
|
||||||
@ -149,7 +160,7 @@ export async function requestChatStream(
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
path: "v1/chat/completions",
|
path: getRequestPath(),
|
||||||
...getHeaders(),
|
...getHeaders(),
|
||||||
},
|
},
|
||||||
body: JSON.stringify(req),
|
body: JSON.stringify(req),
|
||||||
|
@ -5,10 +5,15 @@ export interface AccessControlStore {
|
|||||||
accessCode: string;
|
accessCode: string;
|
||||||
token: string;
|
token: string;
|
||||||
|
|
||||||
|
enableAOAI: boolean;
|
||||||
|
azureDeployName: string;
|
||||||
|
|
||||||
needCode: boolean;
|
needCode: boolean;
|
||||||
|
|
||||||
updateToken: (_: string) => void;
|
updateToken: (_: string) => void;
|
||||||
updateCode: (_: string) => void;
|
updateCode: (_: string) => void;
|
||||||
|
updateDeployName: (_: string) => void;
|
||||||
|
switchAOAI: (_: boolean) => void;
|
||||||
enabledAccessControl: () => boolean;
|
enabledAccessControl: () => boolean;
|
||||||
isAuthorized: () => boolean;
|
isAuthorized: () => boolean;
|
||||||
fetch: () => void;
|
fetch: () => void;
|
||||||
@ -23,6 +28,8 @@ export const useAccessStore = create<AccessControlStore>()(
|
|||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
token: "",
|
token: "",
|
||||||
accessCode: "",
|
accessCode: "",
|
||||||
|
azureDeployName: "",
|
||||||
|
enableAOAI: false,
|
||||||
needCode: true,
|
needCode: true,
|
||||||
enabledAccessControl() {
|
enabledAccessControl() {
|
||||||
get().fetch();
|
get().fetch();
|
||||||
@ -35,8 +42,18 @@ export const useAccessStore = create<AccessControlStore>()(
|
|||||||
updateToken(token: string) {
|
updateToken(token: string) {
|
||||||
set((state) => ({ token }));
|
set((state) => ({ token }));
|
||||||
},
|
},
|
||||||
|
updateDeployName(azureDeployName: string) {
|
||||||
|
set((state) => ({ azureDeployName }));
|
||||||
|
},
|
||||||
|
switchAOAI(switchStatus: boolean) {
|
||||||
|
set((state) => ({ enableAOAI: switchStatus }));
|
||||||
|
},
|
||||||
isAuthorized() {
|
isAuthorized() {
|
||||||
// has token or has code or disabled access control
|
// has token or has code or disabled access control
|
||||||
|
if (get().enableAOAI) {
|
||||||
|
return !!get().azureDeployName && !!get().token;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
!!get().token || !!get().accessCode || !get().enabledAccessControl()
|
!!get().token || !!get().accessCode || !get().enabledAccessControl()
|
||||||
);
|
);
|
||||||
|
@ -71,6 +71,13 @@ export const ROLES: Message["role"][] = ["system", "user", "assistant"];
|
|||||||
|
|
||||||
const ENABLE_GPT4 = true;
|
const ENABLE_GPT4 = true;
|
||||||
|
|
||||||
|
export const AZURE_API_VERSION = [
|
||||||
|
{
|
||||||
|
name: "2023-03-15-preview",
|
||||||
|
available: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const ALL_MODELS = [
|
export const ALL_MODELS = [
|
||||||
{
|
{
|
||||||
name: "gpt-4",
|
name: "gpt-4",
|
||||||
|
Loading…
Reference in New Issue
Block a user