From 7578c405ccd15bfb86b179bf3a872b1188237b6e Mon Sep 17 00:00:00 2001 From: Tristan Chin <23557893+maxijonson@users.noreply.github.com> Date: Mon, 1 May 2023 23:03:32 -0400 Subject: [PATCH] [web] Advanced Conversation Parameters and [lib] Proxy fix (#14) --- .../src/schemas/conversationConfig.schema.ts | 7 +- .../lib/src/utils/createChatCompletion.ts | 6 +- packages/lib/src/utils/createModeration.ts | 6 +- packages/lib/src/utils/getRequestHeaders.ts | 6 +- packages/lib/src/utils/getRequestUrl.ts | 16 +- packages/lib/src/utils/types.ts | 2 +- .../src/components/AddConversationForm.tsx | 190 +-------------- packages/web/src/components/ApiKeyInput.tsx | 27 +++ packages/web/src/components/AppNavbar.tsx | 4 +- packages/web/src/components/ContextInput.tsx | 19 ++ .../web/src/components/ConversationForm.tsx | 216 ++++++++++++++++++ .../src/components/DisableModerationInput.tsx | 39 ++++ packages/web/src/components/DryInput.tsx | 24 ++ packages/web/src/components/HeadersInput.tsx | 136 +++++++++++ .../web/src/components/LogitBiasInput.tsx | 155 +++++++++++++ .../web/src/components/ModelSelectInput.tsx | 67 ++++++ .../src/components/OptionalNumberInput.tsx | 44 ++++ packages/web/src/components/ProxyInput.tsx | 96 ++++++++ packages/web/src/components/SaveInput.tsx | 17 ++ packages/web/src/components/Settings.tsx | 132 ----------- packages/web/src/components/SettingsForm.tsx | 23 ++ packages/web/src/components/StopInput.tsx | 46 ++++ packages/web/src/components/StreamInput.tsx | 17 ++ .../contexts/ConversationManagerContext.ts | 9 +- packages/web/src/contexts/SettingsContext.ts | 27 ++- .../providers/ConversationManagerProvider.tsx | 13 +- .../contexts/providers/SettingsProvider.tsx | 12 +- packages/web/src/entities/settings.ts | 38 ++- packages/web/src/hooks/useStorage.tsx | 6 +- 29 files changed, 1038 insertions(+), 362 deletions(-) create mode 100644 packages/web/src/components/ApiKeyInput.tsx create mode 100644 packages/web/src/components/ContextInput.tsx create mode 100644 packages/web/src/components/ConversationForm.tsx create mode 100644 packages/web/src/components/DisableModerationInput.tsx create mode 100644 packages/web/src/components/DryInput.tsx create mode 100644 packages/web/src/components/HeadersInput.tsx create mode 100644 packages/web/src/components/LogitBiasInput.tsx create mode 100644 packages/web/src/components/ModelSelectInput.tsx create mode 100644 packages/web/src/components/OptionalNumberInput.tsx create mode 100644 packages/web/src/components/ProxyInput.tsx create mode 100644 packages/web/src/components/SaveInput.tsx delete mode 100644 packages/web/src/components/Settings.tsx create mode 100644 packages/web/src/components/SettingsForm.tsx create mode 100644 packages/web/src/components/StopInput.tsx create mode 100644 packages/web/src/components/StreamInput.tsx diff --git a/packages/lib/src/schemas/conversationConfig.schema.ts b/packages/lib/src/schemas/conversationConfig.schema.ts index 073b50a..351affa 100644 --- a/packages/lib/src/schemas/conversationConfig.schema.ts +++ b/packages/lib/src/schemas/conversationConfig.schema.ts @@ -16,7 +16,12 @@ export const conversationConfigSchema = z.object({ max_tokens: z.number().optional(), presence_penalty: z.number().optional(), frequency_penalty: z.number().optional(), - logit_bias: z.record(z.number(), z.number()).optional(), + logit_bias: z + .record( + z.string().refine((val) => !isNaN(Number(val))), + z.number() + ) + .optional(), user: z.string().optional(), }); diff --git a/packages/lib/src/utils/createChatCompletion.ts b/packages/lib/src/utils/createChatCompletion.ts index be44dce..f5f8968 100644 --- a/packages/lib/src/utils/createChatCompletion.ts +++ b/packages/lib/src/utils/createChatCompletion.ts @@ -20,11 +20,7 @@ export default async ( ): Promise< T["stream"] extends true ? ReadableStream : CreateChatCompletionResponse > => { - const headers: Record = getRequestHeaders( - apiKey, - optHeaders, - proxy - ); + const headers = getRequestHeaders(apiKey, optHeaders, proxy); const url = getRequestUrl(ENDPOINT_CHATCOMPLETION, proxy); const response = await fetch(url, { diff --git a/packages/lib/src/utils/createModeration.ts b/packages/lib/src/utils/createModeration.ts index 2b250a9..9955bde 100644 --- a/packages/lib/src/utils/createModeration.ts +++ b/packages/lib/src/utils/createModeration.ts @@ -18,11 +18,7 @@ export default async ( { apiKey, input }: CreateModerationRequest, { headers: optHeaders = {}, proxy }: RequestOptions ): Promise => { - const headers: Record = getRequestHeaders( - apiKey, - optHeaders, - proxy - ); + const headers = getRequestHeaders(apiKey, optHeaders, proxy); const url = getRequestUrl(ENDPOINT_MODERATION, proxy); const response = await fetch(url, { diff --git a/packages/lib/src/utils/getRequestHeaders.ts b/packages/lib/src/utils/getRequestHeaders.ts index 6c80046..cae4f59 100644 --- a/packages/lib/src/utils/getRequestHeaders.ts +++ b/packages/lib/src/utils/getRequestHeaders.ts @@ -9,17 +9,17 @@ export default ( optHeaders: Record = {}, proxy?: RequestOptionsProxy ) => { - const headers: Record = { + const headers = new Headers({ ...optHeaders, "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, - }; + }); if (proxy && proxy.auth) { const auth = base64Encode( `${proxy.auth.username}:${proxy.auth.password}` ); - headers["Proxy-Authorization"] = `Basic ${auth}`; + headers.set("Proxy-Authorization", `Basic ${auth}`); } return headers; diff --git a/packages/lib/src/utils/getRequestUrl.ts b/packages/lib/src/utils/getRequestUrl.ts index 9c5a6fa..0f34e9e 100644 --- a/packages/lib/src/utils/getRequestUrl.ts +++ b/packages/lib/src/utils/getRequestUrl.ts @@ -4,13 +4,15 @@ import { RequestOptionsProxy } from "./types.js"; * Returns the URL object for a request, taking into account a proxy. */ export default (targetUrl: string, proxy?: RequestOptionsProxy) => { - let url = new URL(targetUrl); - if (proxy) { - url = new URL( - url.pathname, - `${proxy.protocol || "http"}://${proxy.host}:${proxy.port || 80}` - ); + if (!proxy) return new URL(targetUrl); + + const protocol = proxy.protocol || "http"; + const host = proxy.host; + const port = proxy.port || (protocol === "https" ? 443 : 80); + + if (!host) { + throw new Error("Proxy host is required."); } - return url; + return new URL(`${protocol}://${host}:${port}/${targetUrl}`); }; diff --git a/packages/lib/src/utils/types.ts b/packages/lib/src/utils/types.ts index de8a797..b472ff0 100644 --- a/packages/lib/src/utils/types.ts +++ b/packages/lib/src/utils/types.ts @@ -59,7 +59,7 @@ export interface RequestOptionsProxy { /** * The port number of the proxy server. * - * @default 80 + * @default 80 for HTTP, 443 for HTTPS */ port?: number; diff --git a/packages/web/src/components/AddConversationForm.tsx b/packages/web/src/components/AddConversationForm.tsx index 63db714..fc2b4ba 100644 --- a/packages/web/src/components/AddConversationForm.tsx +++ b/packages/web/src/components/AddConversationForm.tsx @@ -1,188 +1,22 @@ -import { useForm } from "@mantine/form"; import useConversationManager from "../hooks/useConversationManager"; -import { - Group, - PasswordInput, - Select, - Stack, - Text, - Switch, - Input, - SegmentedControl, - Button, - Textarea, - Tooltip, - Anchor, - useMantineTheme, -} from "@mantine/core"; import React from "react"; -import useSettings from "../hooks/useSettings"; import usePersistence from "../hooks/usePersistence"; - -export const ModelSelectItem = React.forwardRef< - HTMLDivElement, - { label: string; value: string; selected: boolean } ->(({ label, value, ...restProps }, ref) => { - const theme = useMantineTheme(); - const { selected } = restProps; - - const subColor = (() => { - const dark = theme.colorScheme === "dark"; - - if (dark && selected) { - return theme.colors.gray[4]; - } else if (dark && !selected) { - return theme.colors.gray[6]; - } else if (selected) { - return theme.colors.gray[3]; - } else { - return theme.colors.gray[6]; - } - })(); - - return ( - - {label} - - {value} - - - ); -}); +import ConversationForm, { ConversationFormValues } from "./ConversationForm"; export default () => { const { addConversation, setActiveConversation } = useConversationManager(); const { addPersistedConversationId } = usePersistence(); - const { settings } = useSettings(); - const form = useForm({ - initialValues: { - apiKey: settings.apiKey, - model: settings.model, - context: settings.context, - dry: settings.dry, - disableModeration: settings.disableModeration, - stream: settings.stream, - save: settings.save, - }, - transformValues: (values) => ({ - ...values, - disableModeration: (values.disableModeration === "soft" - ? "soft" - : values.disableModeration === "off") as boolean | "soft", - dry: !values.apiKey || values.dry, - }), - }); - const [modelOptions, setModelOptions] = React.useState([ - { label: "GPT 3.5", value: "gpt-3.5-turbo" }, - { label: "GPT 4", value: "gpt-4" }, - { label: "GPT 4 (32k)", value: "gpt-4-32k" }, - ]); - - const handleSubmit = form.onSubmit(({ save, ...values }) => { - const newConversation = addConversation(values); - setActiveConversation(newConversation.id, true); - if (save) { - addPersistedConversationId(newConversation.id); - } - }); - return ( -
- - - You can find yours{" "} - - here - - - } - /> - -