feat: 增加Azure opanai 能力支持

This commit is contained in:
Duang Cheng 2023-04-19 19:45:37 +08:00
parent beb04d8181
commit 19949906c6
6 changed files with 89 additions and 9 deletions

View File

@ -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,

View File

@ -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(
(v) => (
<option value={v.name} key={v.name} disabled={!v.available}> <option value={v.name} key={v.name} disabled={!v.available}>
{v.name} {v.name}
</option> </option>
))} ),
)}
</select> </select>
</SettingItem> </SettingItem>
<SettingItem <SettingItem

View File

@ -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) {

View File

@ -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),

View File

@ -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()
); );

View File

@ -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",