import * as React from 'react'; import { shallow } from 'zustand/shallow'; import { Box, Button, FormControl, FormHelperText, FormLabel, IconButton, Input, Modal, ModalClose, ModalDialog, Slider, Stack, Switch, Typography } from '@mui/joy'; import KeyIcon from '@mui/icons-material/Key'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; import { Link } from '@/components/util/Link'; import { useSettingsStore } from '@/lib/store-settings'; export const isValidOpenAIApiKey = (apiKey?: string) => !!apiKey && apiKey.startsWith('sk-') && apiKey.length > 40; function Section(props: { title?: string; collapsible?: boolean, collapsed?: boolean, disclaimer?: string, children: React.ReactNode }) { const [collapsed, setCollapsed] = React.useState(props.collapsed ?? false); return <> {!!props.title && ( {props.title} )} {!!props.collapsible && ( setCollapsed(!collapsed)}> {!collapsed ? : } )} {!collapsed && {props.children} } {!!props.disclaimer && ( {props.disclaimer} )} ; } /** * Component that allows the User to modify the application settings, * persisted on the client via localStorage. * * @param {boolean} open Whether the Settings modal is open * @param {() => void} onClose Call this to close the dialog from outside */ export function SettingsModal({ open, onClose }: { open: boolean, onClose: () => void; }) { // external state const { renderMarkdown, setRenderMarkdown, apiKey, setApiKey, modelTemperature, setModelTemperature, modelMaxResponseTokens, setModelMaxResponseTokens, modelApiHost, setModelApiHost } = useSettingsStore(state => ({ renderMarkdown: state.renderMarkdown, setRenderMarkdown: state.setRenderMarkdown, apiKey: state.apiKey, setApiKey: state.setApiKey, modelTemperature: state.modelTemperature, setModelTemperature: state.setModelTemperature, modelMaxResponseTokens: state.modelMaxResponseTokens, setModelMaxResponseTokens: state.setModelMaxResponseTokens, modelApiHost: state.modelApiHost, setModelApiHost: state.setModelApiHost, }), shallow); const handleApiKeyChange = (e: React.ChangeEvent) => setApiKey((e.target as HTMLInputElement).value); const handleApiKeyDown = (e: React.KeyboardEvent) => (e.key === 'Enter') && onClose(); const handleTemperatureChange = (event: Event, newValue: number | number[]) => setModelTemperature(newValue as number); const handleMaxTokensChange = (event: Event, newValue: number | number[]) => setModelMaxResponseTokens(newValue as number); const handleModelApiHostChange = (e: React.ChangeEvent) => setModelApiHost((e.target as HTMLInputElement).value); const handleRenderMarkdownChange = (event: React.ChangeEvent) => setRenderMarkdown(event.target.checked); const needsApiKey = !!process.env.REQUIRE_USER_API_KEYS; const isValidKey = isValidOpenAIApiKey(apiKey); return ( Settings
OpenAI API Key {needsApiKey ? '' : '(optional)'} } /> {needsApiKey ? <>Create Key, then apply to the GPT-4 waitlist : `This key will take precedence over the server's.`} Check usage here.
Markdown {renderMarkdown ? 'Best looks' : 'Raw text'}
{/* Advanced Settings */}
Temperature Creative freedom Max-Tokens Response length API host {/**/} {/* */} {/**/} E.g. for Helicone
); }