mirror of
https://github.com/sqlchat/sqlchat.git
synced 2025-08-02 22:58:43 +08:00
feat: add openai api key and endpoint in setting (#23)
This commit is contained in:
@ -1,7 +1,14 @@
|
||||
import { head, last } from "lodash-es";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
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 { countTextTokens, generateUUID } from "@/utils";
|
||||
import Header from "./Header";
|
||||
@ -15,6 +22,7 @@ import DataStorageBanner from "../DataStorageBanner";
|
||||
const MAX_TOKENS = 4000;
|
||||
|
||||
const ConversationView = () => {
|
||||
const settingStore = useSettingStore();
|
||||
const connectionStore = useConnectionStore();
|
||||
const conversationStore = useConversationStore();
|
||||
const messageStore = useMessageStore();
|
||||
@ -151,6 +159,7 @@ const ConversationView = () => {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
messages: formatedMessageList,
|
||||
openAIApiConfig: settingStore.setting.openAIApiConfig,
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -9,7 +9,7 @@ const LocaleSelector = () => {
|
||||
};
|
||||
|
||||
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="zh">简体中文</option>
|
||||
</select>
|
||||
|
64
src/components/OpenAIApiConfigView.tsx
Normal file
64
src/components/OpenAIApiConfigView.tsx
Normal 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;
|
@ -3,6 +3,7 @@ import Icon from "./Icon";
|
||||
import WeChatQRCodeView from "./WeChatQRCodeView";
|
||||
import ClearDataButton from "./ClearDataButton";
|
||||
import LocaleSelector from "./LocaleSelector";
|
||||
import OpenAIApiConfigView from "./OpenAIApiConfigView";
|
||||
|
||||
interface Props {
|
||||
show: boolean;
|
||||
@ -40,6 +41,8 @@ const SettingModal = (props: Props) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<OpenAIApiConfigView />
|
||||
|
||||
<h3>Danger Zone</h3>
|
||||
<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">
|
||||
|
@ -6,14 +6,19 @@ export const config = {
|
||||
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 reqBody = await req.json();
|
||||
const openAIApiConfig = reqBody.openAIApiConfig;
|
||||
const apiKey = openAIApiConfig?.key || openAIApiKey;
|
||||
const apiEndpoint = getApiEndpoint(openAIApiConfig?.endpoint || openAIApiEndpoint);
|
||||
const res = await fetch(apiEndpoint, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${openAIApiKey}`,
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { merge } from "lodash-es";
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { Setting } from "@/types";
|
||||
@ -5,12 +6,17 @@ import { Setting } from "@/types";
|
||||
const getDefaultSetting = (): Setting => {
|
||||
return {
|
||||
locale: "en",
|
||||
openAIApiConfig: {
|
||||
key: "",
|
||||
endpoint: "",
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
interface SettingState {
|
||||
setting: Setting;
|
||||
setLocale: (locale: Setting["locale"]) => void;
|
||||
setOpenAIApiConfig: (openAIApiConfig: Setting["openAIApiConfig"]) => void;
|
||||
}
|
||||
|
||||
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",
|
||||
merge: (persistedState, currentState) => merge(currentState, persistedState),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -1,5 +1,11 @@
|
||||
export type Locale = "en" | "zh";
|
||||
|
||||
export interface OpenAIApiConfig {
|
||||
key: string;
|
||||
endpoint: string;
|
||||
}
|
||||
|
||||
export interface Setting {
|
||||
locale: Locale;
|
||||
openAIApiConfig: OpenAIApiConfig;
|
||||
}
|
||||
|
Reference in New Issue
Block a user