feat: add NEXT_PUBLIC_ALLOW_SELF_OPENAI_KEY

This commit is contained in:
tianzhou
2023-09-01 19:07:32 +08:00
parent 4948f8130b
commit 7ad1160111
8 changed files with 54 additions and 34 deletions

View File

@ -51,6 +51,8 @@ docker run --name sqlchat --platform linux/amd64 -env NEXTAUTH_SECRET=xxx -p 300
### Variables relacionadas con OpenAI: ### Variables relacionadas con OpenAI:
- `NEXT_PUBLIC_ALLOW_SELF_OPENAI_KEY`: Establezca en "verdadero" para permitir a los usuarios traer su propia clave API de OpenAI.
- `OPENAI_API_KEY`: Clave API de OpenAI. Puedes conseguir una [aquí](https://beta.openai.com/docs/developer-quickstart/api-keys). - `OPENAI_API_KEY`: Clave API de OpenAI. Puedes conseguir una [aquí](https://beta.openai.com/docs/developer-quickstart/api-keys).
- `OPENAI_API_ENDPOINT`: Endpoint de la API de OpenAI. El predeterminado es `https://api.openai.com`. - `OPENAI_API_ENDPOINT`: Endpoint de la API de OpenAI. El predeterminado es `https://api.openai.com`.

View File

@ -51,6 +51,7 @@ docker run --name sqlchat --platform linux/amd64 -env NEXTAUTH_SECRET=xxx -p 300
### OpenAI related variables: ### OpenAI related variables:
- `NEXT_PUBLIC_ALLOW_SELF_OPENAI_KEY`: Set to `true` to allow users to bring their own OpenAI API key.
- `OPENAI_API_KEY`: OpenAI API key. You can get one from [here](https://beta.openai.com/docs/developer-quickstart/api-keys). - `OPENAI_API_KEY`: OpenAI API key. You can get one from [here](https://beta.openai.com/docs/developer-quickstart/api-keys).
- `OPENAI_API_ENDPOINT`: OpenAI API endpoint. Defaults to `https://api.openai.com`. - `OPENAI_API_ENDPOINT`: OpenAI API endpoint. Defaults to `https://api.openai.com`.

View File

@ -51,6 +51,7 @@ docker run --name sqlchat --platform linux/amd64 -env NEXTAUTH_SECRET=xxx -p 300
### OpenAI 相关变量: ### OpenAI 相关变量:
- `NEXT_PUBLIC_ALLOW_SELF_OPENAI_KEY`: 设置为 `true` 如果你允许用户提供自己的 OpenAI API key.
- `OPENAI_API_KEY`: OpenAI API Key通过[这里](https://beta.openai.com/docs/developer-quickstart/api-keys)申请。 - `OPENAI_API_KEY`: OpenAI API Key通过[这里](https://beta.openai.com/docs/developer-quickstart/api-keys)申请。
- `OPENAI_API_ENDPOINT`: OpenAI API 端点,默认为 `https://api.openai.com` - `OPENAI_API_ENDPOINT`: OpenAI API 端点,默认为 `https://api.openai.com`

2
process.d.ts vendored
View File

@ -6,6 +6,8 @@ declare namespace NodeJS {
// We can't prefix DATABASE_URL with NEXT_PUBLIC_ because it contains sensitive information that // We can't prefix DATABASE_URL with NEXT_PUBLIC_ because it contains sensitive information that
// should not be exposed to the client. // should not be exposed to the client.
NEXT_PUBLIC_DATABASE_LESS: string; NEXT_PUBLIC_DATABASE_LESS: string;
// Optional. Set to "true" to allow users to bring their own OpenAI API key.
NEXT_PUBLIC_ALLOW_SELF_OPENAI_KEY: string;
// Required if NEXT_PUBLIC_DATABASE_LESS is false. Postgres database connection string to store // Required if NEXT_PUBLIC_DATABASE_LESS is false. Postgres database connection string to store
// the data. e.g. postgresql://postgres:YOUR_PASSWORD@localhost:5432/sqlchat?schema=sqlchat // the data. e.g. postgresql://postgres:YOUR_PASSWORD@localhost:5432/sqlchat?schema=sqlchat
DATABASE_URL: string; DATABASE_URL: string;

View File

@ -3,9 +3,11 @@ import { useTranslation } from "react-i18next";
import { useDebounce } from "react-use"; import { useDebounce } from "react-use";
import { useSettingStore } from "@/store"; import { useSettingStore } from "@/store";
import { OpenAIApiConfig } from "@/types"; import { OpenAIApiConfig } from "@/types";
import { allowSelfOpenAIKey } from "@/utils";
import Radio from "./kit/Radio"; import Radio from "./kit/Radio";
import TextField from "./kit/TextField"; import TextField from "./kit/TextField";
import Tooltip from "./kit/Tooltip"; import Tooltip from "./kit/Tooltip";
const OpenAIApiConfigView = () => { const OpenAIApiConfigView = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const settingStore = useSettingStore(); const settingStore = useSettingStore();
@ -75,7 +77,7 @@ const OpenAIApiConfigView = () => {
<div className="w-full border border-gray-200 dark:border-zinc-700 p-4 rounded-lg"> <div className="w-full border border-gray-200 dark:border-zinc-700 p-4 rounded-lg">
<div> <div>
<label className="text-base font-semibold ">{t("setting.openai-api-configuration.model")}</label> <label className="text-base font-semibold ">{t("setting.openai-api-configuration.model")}</label>
<p className="text-sm text-gray-500">{t("setting.openai-api-configuration.model-description")}</p> {allowSelfOpenAIKey() && <p className="text-sm text-gray-500">{t("setting.openai-api-configuration.model-description")}</p>}
<fieldset className="mt-4"> <fieldset className="mt-4">
<div className="space-y-4 sm:flex sm:items-center sm:space-x-10 sm:space-y-0"> <div className="space-y-4 sm:flex sm:items-center sm:space-x-10 sm:space-y-0">
{models.map((model) => {models.map((model) =>
@ -90,35 +92,39 @@ const OpenAIApiConfigView = () => {
</div> </div>
</fieldset> </fieldset>
</div> </div>
<div className="flex flex-col mt-4"> {allowSelfOpenAIKey() && (
<label className="text-base font-semibold">OpenAI API Key</label> <>
<p className="text-sm text-gray-500">{t("setting.openai-api-configuration.key-description")}</p> <div className="flex flex-col mt-4">
<TextField <label className="text-base font-semibold">OpenAI API Key</label>
className="mt-4" <p className="text-sm text-gray-500">{t("setting.openai-api-configuration.key-description")}</p>
placeholder="OpenAI API Key" <TextField
value={maskKey ? maskedKey(openAIApiConfig.key) : openAIApiConfig.key} className="mt-4"
onChange={(value) => handleSetOpenAIApiConfig({ key: value })} placeholder="OpenAI API Key"
/> value={maskKey ? maskedKey(openAIApiConfig.key) : openAIApiConfig.key}
</div> onChange={(value) => handleSetOpenAIApiConfig({ key: value })}
<div className="flex flex-col mt-4"> />
<label className="text-base font-semibold">OpenAI API Endpoint</label> </div>
<div className="flex"> <div className="flex flex-col mt-4">
<p className="text-sm text-gray-500">{t("setting.openai-api-configuration.endpoint-description")}</p> <label className="text-base font-semibold">OpenAI API Endpoint</label>
<a <div className="flex">
href="https://platform.openai.com/account/api-keys" <p className="text-sm text-gray-500">{t("setting.openai-api-configuration.endpoint-description")}</p>
target="_blank" <a
className="text-sm text-indigo-600 hover:text-indigo-900" href="https://platform.openai.com/account/api-keys"
> target="_blank"
{t("setting.openai-api-configuration.find-my-key")} className="text-sm text-indigo-600 hover:text-indigo-900"
</a> >
</div> {t("setting.openai-api-configuration.find-my-key")}
<TextField </a>
className="mt-4" </div>
placeholder="API Endpoint" <TextField
value={openAIApiConfig.endpoint} className="mt-4"
onChange={(value) => handleSetOpenAIApiConfig({ endpoint: value })} placeholder="API Endpoint"
/> value={openAIApiConfig.endpoint}
</div> onChange={(value) => handleSetOpenAIApiConfig({ endpoint: value })}
/>
</div>
</>
)}
</div> </div>
</> </>
); );

View File

@ -1,5 +1,6 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useLocalStorage } from "react-use"; import { useLocalStorage } from "react-use";
import { allowSelfOpenAIKey } from "@/utils";
import Link from "next/link"; import Link from "next/link";
import Icon from "./Icon"; import Icon from "./Icon";
@ -22,9 +23,11 @@ const QuotaOverflowBanner = (props: Props) => {
> >
<div className="text-sm leading-6 pr-4 cursor-pointer"> <div className="text-sm leading-6 pr-4 cursor-pointer">
{t("banner.quota-overflow")}{" "} {t("banner.quota-overflow")}{" "}
<Link className="ml-1 underline hover:opacity-80" href="/setting"> {allowSelfOpenAIKey() && (
{t("banner.use-my-key")} <Link className="ml-1 underline hover:opacity-80" href="/setting">
</Link> {t("banner.use-my-key")}
</Link>
)}
</div> </div>
<button className="absolute right-2 sm:right-4 opacity-60 hover:opacity-100" onClick={() => setHideBanner(true)}> <button className="absolute right-2 sm:right-4 opacity-60 hover:opacity-100" onClick={() => setHideBanner(true)}>
<Icon.BiX className="w-6 h-auto" /> <Icon.BiX className="w-6 h-auto" />

View File

@ -5,6 +5,7 @@ import Link from "next/link";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Quota } from "@/types"; import { Quota } from "@/types";
import getEventEmitter from "@/utils/event-emitter"; import getEventEmitter from "@/utils/event-emitter";
import { allowSelfOpenAIKey } from "@/utils";
interface Props { interface Props {
className?: string; className?: string;
@ -78,7 +79,7 @@ const QuotaView = (props: Props) => {
{t("setting.plan.signup-for-more")} {t("setting.plan.signup-for-more")}
</button> </button>
))} ))}
{!!showSupplyOwnKey && ( {allowSelfOpenAIKey() && !!showSupplyOwnKey && (
<Link className="text-center rounded-full underline hover:opacity-80 px-2 py-0.5 text-xs font-medium text-gray-700" href="/setting"> <Link className="text-center rounded-full underline hover:opacity-80 px-2 py-0.5 text-xs font-medium text-gray-700" href="/setting">
{t("banner.use-my-key")} {t("banner.use-my-key")}
</Link> </Link>

View File

@ -50,3 +50,7 @@ export function generateDbPromptFromContext(
} }
return promptGenerator(engine, finalTableList.join("\n\n")); return promptGenerator(engine, finalTableList.join("\n\n"));
} }
export function allowSelfOpenAIKey() {
return process.env.NEXT_PUBLIC_ALLOW_SELF_OPENAI_KEY == "true";
}