Skip to content

Commit 182557b

Browse files
authored
Merge pull request #84 from Dogtiti/refactor/endpoint-url
feat: setting endpoint url
2 parents fea75d7 + 393ffa8 commit 182557b

File tree

12 files changed

+162
-98
lines changed

12 files changed

+162
-98
lines changed

public/locales/en/common.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
"share": "Share",
2929
"sign-in": "Sign In",
3030
"sign-out": "Sign Out",
31-
"export": "Export"
31+
"export": "Export",
32+
"reset": "Reset"
3233
}

public/locales/en/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
"api-key-notice": "<0>NOTE: To get a key, sign up for an OpenAI account and visit the following <1>link.</1>,This key is only used in the current browser session</0>",
1414
"tokens-tips": "Controls the maximum number of tokens used in each API call (higher value will make responses more detailed but cost more).",
1515
"tokens": "Tokens: ",
16-
"guest-key": "Guest Key: "
16+
"guest-key": "Guest Key: ",
17+
"endPoint": "Endpoint: "
1718
}

public/locales/zh/common.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
"share": "分享",
2929
"sign-in": "登录",
3030
"sign-out": "登出",
31-
"export": "导出"
31+
"export": "导出",
32+
"reset": "重置"
3233
}

public/locales/zh/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@
1313
"api-key-notice": "<0>注意:要获取密钥,请注册OpenAI账户并访问以下<1>链接。</1>此密钥仅在当前浏览器会话中使用。</0>",
1414
"tokens-tips": "控制每个 API 调用中使用的最大令牌数(更高的值将使响应更详细,但更昂贵)。",
1515
"tokens": "字节数:",
16-
"guest-key": "访问码:"
16+
"guest-key": "访问码:",
17+
"endPoint": "代理地址:"
1718
}

src/components/Dialog.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
import React from "react";
22
import Button from "./Button";
33
import { useTranslation } from "next-i18next";
4+
import clsx from "clsx";
45

56
export default function Dialog({
67
header,
78
children,
89
isShown,
910
close,
1011
footerButton,
12+
contentClassName,
1113
}: {
1214
header: React.ReactNode;
1315
children: React.ReactNode;
1416
isShown: boolean;
1517
close: () => void;
1618
footerButton?: React.ReactNode;
19+
contentClassName?: string;
1720
}) {
1821
const { t } = useTranslation();
1922
if (!isShown) {
@@ -42,7 +45,12 @@ export default function Dialog({
4245
</button>
4346
</div>
4447
{/*body*/}
45-
<div className="text-md relative my-3 max-h-[50vh] flex-auto overflow-y-auto p-3 leading-relaxed">
48+
<div
49+
className={clsx(
50+
"text-md relative max-h-[50vh] flex-auto overflow-y-auto p-3 leading-relaxed",
51+
contentClassName
52+
)}
53+
>
4654
{children}
4755
</div>
4856
{/*footer*/}

src/components/SettingsDialog.tsx

Lines changed: 113 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,29 @@ import {
99
FaSyncAlt,
1010
FaCoins,
1111
FaCode,
12+
FaServer,
1213
} from "react-icons/fa";
1314
import Dialog from "./Dialog";
1415
import Input from "./Input";
1516
import { GPT_MODEL_NAMES, GPT_4 } from "../utils/constants";
1617
import Accordion from "./Accordion";
17-
import type { ModelSettings } from "../utils/types";
18+
import type { ModelSettings, SettingModel } from "../utils/types";
1819
import { useGuestMode } from "../hooks/useGuestMode";
20+
import clsx from "clsx";
1921

2022
export const SettingsDialog: React.FC<{
2123
show: boolean;
2224
close: () => void;
23-
customSettings: [ModelSettings, (settings: ModelSettings) => void];
24-
}> = ({ show, close, customSettings: [customSettings, setCustomSettings] }) => {
25+
customSettings: SettingModel;
26+
}> = ({ show, close, customSettings }) => {
2527
const [settings, setSettings] = React.useState<ModelSettings>({
26-
...customSettings,
28+
...customSettings.settings,
2729
});
28-
const { isGuestMode } = useGuestMode(settings.guestKey);
30+
const { isGuestMode } = useGuestMode(settings.customGuestKey);
2931
const { t } = useTranslation(["settings", "common"]);
3032

3133
useEffect(() => {
32-
setSettings(customSettings);
34+
setSettings(customSettings.settings);
3335
}, [customSettings, close]);
3436

3537
const updateSettings = <Key extends keyof ModelSettings>(
@@ -41,15 +43,53 @@ export const SettingsDialog: React.FC<{
4143
});
4244
};
4345

46+
function urlIsValid(url: string | undefined) {
47+
if (url) {
48+
const pattern = /^(https?:\/\/)?[\w.-]+\.[a-zA-Z]{2,}(\/\S*)?$/;
49+
return pattern.test(url);
50+
}
51+
return true;
52+
}
53+
4454
const handleSave = () => {
45-
setCustomSettings(settings);
55+
if (!urlIsValid(settings.customEndPoint)) {
56+
alert(
57+
t(
58+
"Endpoint URL is invalid. Please ensure that you have set a correct URL."
59+
)
60+
);
61+
return;
62+
}
63+
64+
if (!settings.customApiKey) {
65+
customSettings.resetSettings();
66+
} else {
67+
customSettings.saveSettings(settings);
68+
}
4669
close();
4770
return;
4871
};
4972

73+
const handleReset = () => {
74+
customSettings.resetSettings();
75+
updateSettings("customApiKey", "");
76+
close();
77+
};
78+
5079
const disabled = !settings.customApiKey;
5180
const advancedSettings = (
52-
<>
81+
<div className="flex flex-col gap-2">
82+
<Input
83+
left={
84+
<>
85+
<FaServer />
86+
<span className="ml-2">{t("endPoint")}</span>
87+
</>
88+
}
89+
disabled={disabled}
90+
value={settings.customEndPoint}
91+
onChange={(e) => updateSettings("customEndPoint", e.target.value)}
92+
/>
5393
<Input
5494
left={
5595
<>
@@ -72,7 +112,6 @@ export const SettingsDialog: React.FC<{
72112
step: 0.01,
73113
}}
74114
/>
75-
<br />
76115
<Input
77116
left={
78117
<>
@@ -96,18 +135,17 @@ export const SettingsDialog: React.FC<{
96135
step: 1,
97136
}}
98137
/>
99-
<br />
100138
<Input
101139
left={
102140
<>
103141
<FaCoins />
104142
<span className="ml-2">{t("tokens")}</span>
105143
</>
106144
}
107-
value={settings.maxTokens ?? 400}
145+
value={settings.customMaxTokens ?? 400}
108146
disabled={disabled}
109147
onChange={(e) =>
110-
updateSettings("maxTokens", parseFloat(e.target.value))
148+
updateSettings("customMaxTokens", parseFloat(e.target.value))
111149
}
112150
type="range"
113151
toolTipProperties={{
@@ -120,24 +158,31 @@ export const SettingsDialog: React.FC<{
120158
step: 100,
121159
}}
122160
/>
123-
</>
161+
</div>
124162
);
125163

126164
return (
127165
<Dialog
128166
header={`${t("settings")} ⚙`}
129167
isShown={show}
130168
close={close}
131-
footerButton={<Button onClick={handleSave}>{t("common:save")}</Button>}
169+
footerButton={
170+
<>
171+
<Button className="bg-red-400 hover:bg-red-500" onClick={handleReset}>
172+
{t("common:reset")}
173+
</Button>
174+
<Button onClick={handleSave}>{t("common:save")}</Button>
175+
</>
176+
}
177+
contentClassName="text-md relative flex flex-col gap-2 p-2 leading-relaxed"
132178
>
133179
<p>{t("usage")}</p>
134-
<br />
135180
<p
136-
className={
137-
settings.customModelName === GPT_4
138-
? "rounded-md border-[2px] border-white/10 bg-yellow-300 text-black"
139-
: ""
140-
}
181+
className={clsx(
182+
"my-2",
183+
settings.customModelName === GPT_4 &&
184+
"rounded-md border-[2px] border-white/10 bg-yellow-300 text-black"
185+
)}
141186
>
142187
<FaExclamationCircle className="inline-block" />
143188
&nbsp;
@@ -155,67 +200,60 @@ export const SettingsDialog: React.FC<{
155200
</b>
156201
</Trans>
157202
</p>
158-
<br />
159-
<div className="text-md relative flex-auto p-2 leading-relaxed">
160-
<Input
161-
left={
162-
<>
163-
<FaKey />
164-
<span className="ml-2">{t("key")}</span>
165-
</>
166-
}
167-
placeholder={"sk-..."}
168-
value={settings.customApiKey}
169-
onChange={(e) => updateSettings("customApiKey", e.target.value)}
170-
/>
171-
<br className="md:inline" />
203+
<Input
204+
left={
205+
<>
206+
<FaKey />
207+
<span className="ml-2">{t("key")}</span>
208+
</>
209+
}
210+
placeholder={"sk-..."}
211+
value={settings.customApiKey}
212+
onChange={(e) => updateSettings("customApiKey", e.target.value)}
213+
/>
214+
<Input
215+
left={
216+
<>
217+
<FaMicrochip />
218+
<span className="ml-2">{t("model")}</span>
219+
</>
220+
}
221+
type="combobox"
222+
value={settings.customModelName}
223+
onChange={() => null}
224+
setValue={(e) => updateSettings("customModelName", e)}
225+
attributes={{ options: GPT_MODEL_NAMES }}
226+
disabled={disabled}
227+
/>
228+
{isGuestMode && (
172229
<Input
173230
left={
174231
<>
175-
<FaMicrochip />
176-
<span className="ml-2">{t("model")}</span>
232+
<FaCode />
233+
<span className="ml-2">{t("guest-key")}</span>
177234
</>
178235
}
179-
type="combobox"
180-
value={settings.customModelName}
181-
onChange={() => null}
182-
setValue={(e) => updateSettings("customModelName", e)}
183-
attributes={{ options: GPT_MODEL_NAMES }}
184-
disabled={disabled}
236+
value={settings.customGuestKey}
237+
onChange={(e) => updateSettings("customGuestKey", e.target.value)}
185238
/>
186-
<br className="md:inline" />
187-
{isGuestMode && (
188-
<Input
189-
left={
190-
<>
191-
<FaCode />
192-
<span className="ml-2">{t("guest-key")}</span>
193-
</>
194-
}
195-
value={settings.guestKey}
196-
onChange={(e) => updateSettings("guestKey", e.target.value)}
197-
/>
198-
)}
199-
<br className="hidden md:inline" />
200-
<Accordion
201-
child={advancedSettings}
202-
name={t("advanced-settings")}
203-
></Accordion>
204-
<br />
205-
<Trans i18nKey="api-key-notice" ns="settings">
206-
<strong className="mt-10">
207-
NOTE: To get a key, sign up for an OpenAI account and visit the
208-
following
209-
<a
210-
href="https://platform.openai.com/account/api-keys"
211-
className="text-blue-500"
212-
>
213-
link.
214-
</a>
215-
This key is only used in the current browser session
216-
</strong>
217-
</Trans>
218-
</div>
239+
)}
240+
<Accordion
241+
child={advancedSettings}
242+
name={t("advanced-settings")}
243+
></Accordion>
244+
<Trans i18nKey="api-key-notice" ns="settings">
245+
<strong className="mt-10">
246+
NOTE: To get a key, sign up for an OpenAI account and visit the
247+
following
248+
<a
249+
href="https://platform.openai.com/account/api-keys"
250+
className="text-blue-500"
251+
>
252+
link.
253+
</a>
254+
This key is only used in the current browser session
255+
</strong>
256+
</Trans>
219257
</Dialog>
220258
);
221259
};

src/env/schema.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ export const serverSchema = z.object({
4646
NEXTAUTH_SECRET: requiredAuthEnabledForProduction(),
4747
NEXTAUTH_URL: validateNextUrl(),
4848
OPENAI_API_KEY: z.string(),
49-
OPENAI_API_BASE_URL: z.string().url().optional(),
5049
GOOGLE_CLIENT_ID: requiredAuthEnabledForProduction(),
5150
GOOGLE_CLIENT_SECRET: requiredAuthEnabledForProduction(),
5251
GITHUB_CLIENT_ID: requiredAuthEnabledForProduction(),
@@ -74,7 +73,6 @@ export const serverEnv = {
7473
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
7574
NEXTAUTH_URL: process.env.NEXTAUTH_URL ?? "http://localhost:3000",
7675
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
77-
OPENAI_API_BASE_URL: process.env.OPENAI_API_BASE_URL,
7876
GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
7977
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
8078
GITHUB_CLIENT_ID: process.env.GITHUB_CLIENT_ID,

src/hooks/useGuestMode.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import { useState, useEffect } from "react";
22
import { env } from "../env/client.mjs";
33

4-
export function useGuestMode(guestKey = "") {
4+
export function useGuestMode(customGuestKey = "") {
55
const [isValidGuest, setIsValidGuest] = useState(false);
66
const [isGuestMode, setIsGuestMode] = useState(false);
77

88
useEffect(() => {
99
const publicGuestKey = env.NEXT_PUBLIC_GUEST_KEY ?? "";
1010
const keys = publicGuestKey.split(",").filter((key) => !!key);
1111
const isGuestMode = keys.length > 0;
12-
const isMatchedGuestKey = !!keys.find((key) => key === guestKey);
12+
const isMatchedGuestKey = !!keys.find((key) => key === customGuestKey);
1313
const isValidGuest = isMatchedGuestKey;
1414
setIsValidGuest(isValidGuest);
1515
setIsGuestMode(isGuestMode);
16-
}, [guestKey]);
16+
}, [customGuestKey]);
1717

1818
return {
1919
isValidGuest,

0 commit comments

Comments
 (0)