feat: add openai api key and endpoint in setting (#23)

This commit is contained in:
boojack
2023-04-07 10:34:08 +08:00
committed by GitHub
parent 3341af871f
commit de861ae5c5
7 changed files with 106 additions and 4 deletions

View File

@ -1,7 +1,14 @@
import { head, last } from "lodash-es"; import { head, last } from "lodash-es";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { getAssistantById, getPromptGeneratorOfAssistant, useConversationStore, useMessageStore, useConnectionStore } from "@/store"; import {
getAssistantById,
getPromptGeneratorOfAssistant,
useConversationStore,
useMessageStore,
useConnectionStore,
useSettingStore,
} from "@/store";
import { CreatorRole, Message } from "@/types"; import { CreatorRole, Message } from "@/types";
import { countTextTokens, generateUUID } from "@/utils"; import { countTextTokens, generateUUID } from "@/utils";
import Header from "./Header"; import Header from "./Header";
@ -15,6 +22,7 @@ import DataStorageBanner from "../DataStorageBanner";
const MAX_TOKENS = 4000; const MAX_TOKENS = 4000;
const ConversationView = () => { const ConversationView = () => {
const settingStore = useSettingStore();
const connectionStore = useConnectionStore(); const connectionStore = useConnectionStore();
const conversationStore = useConversationStore(); const conversationStore = useConversationStore();
const messageStore = useMessageStore(); const messageStore = useMessageStore();
@ -151,6 +159,7 @@ const ConversationView = () => {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
messages: formatedMessageList, messages: formatedMessageList,
openAIApiConfig: settingStore.setting.openAIApiConfig,
}), }),
}); });

View File

@ -9,7 +9,7 @@ const LocaleSelector = () => {
}; };
return ( return (
<select className="select select-bordered !h-auto !min-h-fit" value={locale} onChange={handleLocaleChange}> <select className="select select-bordered select-sm" value={locale} onChange={handleLocaleChange}>
<option value="en">English</option> <option value="en">English</option>
<option value="zh"></option> <option value="zh"></option>
</select> </select>

View File

@ -0,0 +1,64 @@
import { useState } from "react";
import { useDebounce } from "react-use";
import { useSettingStore } from "@/store";
import { OpenAIApiConfig } from "@/types";
const OpenAIApiConfigView = () => {
const settingStore = useSettingStore();
const [openAIApiConfig, setOpenAIApiConfig] = useState(settingStore.setting.openAIApiConfig);
useDebounce(
() => {
settingStore.setOpenAIApiConfig(openAIApiConfig);
},
300,
[openAIApiConfig]
);
const handleSetOpenAIApiConfig = (config: Partial<OpenAIApiConfig>) => {
setOpenAIApiConfig({
...openAIApiConfig,
...config,
});
};
return (
<>
<h3>OpenAI API configuration</h3>
<div className="w-full border border-gray-200 p-4 rounded-lg">
<div className="flex flex-col">
<label htmlFor="openai-api-key">Key</label>
<input
id="openai-api-key"
className="input input-bordered input-sm mt-1"
type="text"
placeholder="OpenAI API Key"
value={openAIApiConfig.key}
onChange={(e) => {
handleSetOpenAIApiConfig({
key: e.target.value,
});
}}
/>
</div>
<div className="flex flex-col mt-2">
<label htmlFor="openai-api-endpoint">Endpoint</label>
<input
id="openai-api-endpoint"
className="input input-bordered input-sm mt-1"
type="text"
placeholder="OpenAI API Endpoint"
value={openAIApiConfig.endpoint}
onChange={(e) => {
handleSetOpenAIApiConfig({
endpoint: e.target.value,
});
}}
/>
</div>
</div>
</>
);
};
export default OpenAIApiConfigView;

View File

@ -3,6 +3,7 @@ import Icon from "./Icon";
import WeChatQRCodeView from "./WeChatQRCodeView"; import WeChatQRCodeView from "./WeChatQRCodeView";
import ClearDataButton from "./ClearDataButton"; import ClearDataButton from "./ClearDataButton";
import LocaleSelector from "./LocaleSelector"; import LocaleSelector from "./LocaleSelector";
import OpenAIApiConfigView from "./OpenAIApiConfigView";
interface Props { interface Props {
show: boolean; show: boolean;
@ -40,6 +41,8 @@ const SettingModal = (props: Props) => {
</div> </div>
</div> </div>
<OpenAIApiConfigView />
<h3>Danger Zone</h3> <h3>Danger Zone</h3>
<div className="w-full border border-red-200 p-4 rounded-lg"> <div className="w-full border border-red-200 p-4 rounded-lg">
<div className="w-full flex flex-row justify-between items-center gap-2"> <div className="w-full flex flex-row justify-between items-center gap-2">

View File

@ -6,14 +6,19 @@ export const config = {
runtime: "edge", runtime: "edge",
}; };
const apiEndpoint = new URL(`${openAIApiEndpoint}/v1/chat/completions`); const getApiEndpoint = (apiEndpoint: string) => {
return new URL(`${apiEndpoint}/v1/chat/completions`);
};
const handler = async (req: NextRequest) => { const handler = async (req: NextRequest) => {
const reqBody = await req.json(); const reqBody = await req.json();
const openAIApiConfig = reqBody.openAIApiConfig;
const apiKey = openAIApiConfig?.key || openAIApiKey;
const apiEndpoint = getApiEndpoint(openAIApiConfig?.endpoint || openAIApiEndpoint);
const res = await fetch(apiEndpoint, { const res = await fetch(apiEndpoint, {
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: `Bearer ${openAIApiKey}`, Authorization: `Bearer ${apiKey}`,
}, },
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({

View File

@ -1,3 +1,4 @@
import { merge } from "lodash-es";
import { create } from "zustand"; import { create } from "zustand";
import { persist } from "zustand/middleware"; import { persist } from "zustand/middleware";
import { Setting } from "@/types"; import { Setting } from "@/types";
@ -5,12 +6,17 @@ import { Setting } from "@/types";
const getDefaultSetting = (): Setting => { const getDefaultSetting = (): Setting => {
return { return {
locale: "en", locale: "en",
openAIApiConfig: {
key: "",
endpoint: "",
},
}; };
}; };
interface SettingState { interface SettingState {
setting: Setting; setting: Setting;
setLocale: (locale: Setting["locale"]) => void; setLocale: (locale: Setting["locale"]) => void;
setOpenAIApiConfig: (openAIApiConfig: Setting["openAIApiConfig"]) => void;
} }
export const useSettingStore = create<SettingState>()( export const useSettingStore = create<SettingState>()(
@ -26,9 +32,18 @@ export const useSettingStore = create<SettingState>()(
}, },
}); });
}, },
setOpenAIApiConfig: (openAIApiConfig: Setting["openAIApiConfig"]) => {
set({
setting: {
...get().setting,
openAIApiConfig,
},
});
},
}), }),
{ {
name: "setting-storage", name: "setting-storage",
merge: (persistedState, currentState) => merge(currentState, persistedState),
} }
) )
); );

View File

@ -1,5 +1,11 @@
export type Locale = "en" | "zh"; export type Locale = "en" | "zh";
export interface OpenAIApiConfig {
key: string;
endpoint: string;
}
export interface Setting { export interface Setting {
locale: Locale; locale: Locale;
openAIApiConfig: OpenAIApiConfig;
} }