import { useState, useEffect, useMemo } from "react"; import styles from "./settings.module.scss"; import ResetIcon from "../icons/reload.svg"; import AddIcon from "../icons/add.svg"; import CloseIcon from "../icons/close.svg"; import CopyIcon from "../icons/copy.svg"; import ClearIcon from "../icons/clear.svg"; import LoadingIcon from "../icons/three-dots.svg"; import EditIcon from "../icons/edit.svg"; import EyeIcon from "../icons/eye.svg"; import DownloadIcon from "../icons/download.svg"; import UploadIcon from "../icons/upload.svg"; import ConfigIcon from "../icons/config.svg"; import ConfirmIcon from "../icons/confirm.svg"; import ConnectionIcon from "../icons/connection.svg"; import CloudSuccessIcon from "../icons/cloud-success.svg"; import CloudFailIcon from "../icons/cloud-fail.svg"; import { Input, List, ListItem, Modal, PasswordInput, Popover, Select, showConfirm, showToast, } from "./ui-lib"; import { ModelConfigList } from "./model-config"; import { IconButton } from "./button"; import { SubmitKey, useChatStore, Theme, useUpdateStore, useAccessStore, useAppConfig, } from "../store"; import Locale, { AllLangs, ALL_LANG_OPTIONS, changeLang, getLang, } from "../locales"; import { copyToClipboard } from "../utils"; import Link from "next/link"; import { Anthropic, Azure, Google, OPENAI_BASE_URL, Path, RELEASE_URL, STORAGE_KEY, ServiceProvider, SlotID, UPDATE_URL, } from "../constant"; import { Prompt, SearchService, usePromptStore } from "../store/prompt"; import { ErrorBoundary } from "./error"; import { InputRange } from "./input-range"; import { useNavigate } from "react-router-dom"; import { Avatar, AvatarPicker } from "./emoji"; import { getClientConfig } from "../config/client"; import { useSyncStore } from "../store/sync"; import { nanoid } from "nanoid"; import { useMaskStore } from "../store/mask"; import { ProviderType } from "../utils/cloud"; function EditPromptModal(props: { id: string; onClose: () => void }) { const promptStore = usePromptStore(); const prompt = promptStore.get(props.id); return prompt ? ( <div className="modal-mask"> <Modal title={Locale.Settings.Prompt.EditModal.Title} onClose={props.onClose} actions={[ <IconButton key="" onClick={props.onClose} text={Locale.UI.Confirm} bordered />, ]} > <div className={styles["edit-prompt-modal"]}> <input type="text" value={prompt.title} readOnly={!prompt.isUser} className={styles["edit-prompt-title"]} onInput={(e) => promptStore.updatePrompt( props.id, (prompt) => (prompt.title = e.currentTarget.value), ) } ></input> <Input value={prompt.content} readOnly={!prompt.isUser} className={styles["edit-prompt-content"]} rows={10} onInput={(e) => promptStore.updatePrompt( props.id, (prompt) => (prompt.content = e.currentTarget.value), ) } ></Input> </div> </Modal> </div> ) : null; } function UserPromptModal(props: { onClose?: () => void }) { const promptStore = usePromptStore(); const userPrompts = promptStore.getUserPrompts(); const builtinPrompts = SearchService.builtinPrompts; const allPrompts = userPrompts.concat(builtinPrompts); const [searchInput, setSearchInput] = useState(""); const [searchPrompts, setSearchPrompts] = useState<Prompt[]>([]); const prompts = searchInput.length > 0 ? searchPrompts : allPrompts; const [editingPromptId, setEditingPromptId] = useState<string>(); useEffect(() => { if (searchInput.length > 0) { const searchResult = SearchService.search(searchInput); setSearchPrompts(searchResult); } else { setSearchPrompts([]); } }, [searchInput]); return ( <div className="modal-mask"> <Modal title={Locale.Settings.Prompt.Modal.Title} onClose={() => props.onClose?.()} actions={[ <IconButton key="add" onClick={() => { const promptId = promptStore.add({ id: nanoid(), createdAt: Date.now(), title: "Empty Prompt", content: "Empty Prompt Content", }); setEditingPromptId(promptId); }} icon={<AddIcon />} bordered text={Locale.Settings.Prompt.Modal.Add} />, ]} > <div className={styles["user-prompt-modal"]}> <input type="text" className={styles["user-prompt-search"]} placeholder={Locale.Settings.Prompt.Modal.Search} value={searchInput} onInput={(e) => setSearchInput(e.currentTarget.value)} ></input> <div className={styles["user-prompt-list"]}> {prompts.map((v, _) => ( <div className={styles["user-prompt-item"]} key={v.id ?? v.title}> <div className={styles["user-prompt-header"]}> <div className={styles["user-prompt-title"]}>{v.title}</div> <div className={styles["user-prompt-content"] + " one-line"}> {v.content} </div> </div> <div className={styles["user-prompt-buttons"]}> {v.isUser && ( <IconButton icon={<ClearIcon />} className={styles["user-prompt-button"]} onClick={() => promptStore.remove(v.id!)} /> )} {v.isUser ? ( <IconButton icon={<EditIcon />} className={styles["user-prompt-button"]} onClick={() => setEditingPromptId(v.id)} /> ) : ( <IconButton icon={<EyeIcon />} className={styles["user-prompt-button"]} onClick={() => setEditingPromptId(v.id)} /> )} <IconButton icon={<CopyIcon />} className={styles["user-prompt-button"]} onClick={() => copyToClipboard(v.content)} /> </div> </div> ))} </div> </div> </Modal> {editingPromptId !== undefined && ( <EditPromptModal id={editingPromptId!} onClose={() => setEditingPromptId(undefined)} /> )} </div> ); } function DangerItems() { const chatStore = useChatStore(); const appConfig = useAppConfig(); return ( <List> <ListItem title={Locale.Settings.Danger.Reset.Title} subTitle={Locale.Settings.Danger.Reset.SubTitle} > <IconButton text={Locale.Settings.Danger.Reset.Action} onClick={async () => { if (await showConfirm(Locale.Settings.Danger.Reset.Confirm)) { appConfig.reset(); } }} type="danger" /> </ListItem> <ListItem title={Locale.Settings.Danger.Clear.Title} subTitle={Locale.Settings.Danger.Clear.SubTitle} > <IconButton text={Locale.Settings.Danger.Clear.Action} onClick={async () => { if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) { chatStore.clearAllData(); } }} type="danger" /> </ListItem> </List> ); } function CheckButton() { const syncStore = useSyncStore(); const couldCheck = useMemo(() => { return syncStore.cloudSync(); }, [syncStore]); const [checkState, setCheckState] = useState< "none" | "checking" | "success" | "failed" >("none"); async function check() { setCheckState("checking"); const valid = await syncStore.check(); setCheckState(valid ? "success" : "failed"); } if (!couldCheck) return null; return ( <IconButton text={Locale.Settings.Sync.Config.Modal.Check} bordered onClick={check} icon={ checkState === "none" ? ( <ConnectionIcon /> ) : checkState === "checking" ? ( <LoadingIcon /> ) : checkState === "success" ? ( <CloudSuccessIcon /> ) : checkState === "failed" ? ( <CloudFailIcon /> ) : ( <ConnectionIcon /> ) } ></IconButton> ); } function SyncConfigModal(props: { onClose?: () => void }) { const syncStore = useSyncStore(); return ( <div className="modal-mask"> <Modal title={Locale.Settings.Sync.Config.Modal.Title} onClose={() => props.onClose?.()} actions={[ <CheckButton key="check" />, <IconButton key="confirm" onClick={props.onClose} icon={<ConfirmIcon />} bordered text={Locale.UI.Confirm} />, ]} > <List> <ListItem title={Locale.Settings.Sync.Config.SyncType.Title} subTitle={Locale.Settings.Sync.Config.SyncType.SubTitle} > <select value={syncStore.provider} onChange={(e) => { syncStore.update( (config) => (config.provider = e.target.value as ProviderType), ); }} > {Object.entries(ProviderType).map(([k, v]) => ( <option value={v} key={k}> {k} </option> ))} </select> </ListItem> <ListItem title={Locale.Settings.Sync.Config.Proxy.Title} subTitle={Locale.Settings.Sync.Config.Proxy.SubTitle} > <input type="checkbox" checked={syncStore.useProxy} onChange={(e) => { syncStore.update( (config) => (config.useProxy = e.currentTarget.checked), ); }} ></input> </ListItem> {syncStore.useProxy ? ( <ListItem title={Locale.Settings.Sync.Config.ProxyUrl.Title} subTitle={Locale.Settings.Sync.Config.ProxyUrl.SubTitle} > <input type="text" value={syncStore.proxyUrl} onChange={(e) => { syncStore.update( (config) => (config.proxyUrl = e.currentTarget.value), ); }} ></input> </ListItem> ) : null} </List> {syncStore.provider === ProviderType.WebDAV && ( <> <List> <ListItem title={Locale.Settings.Sync.Config.WebDav.Endpoint}> <input type="text" value={syncStore.webdav.endpoint} onChange={(e) => { syncStore.update( (config) => (config.webdav.endpoint = e.currentTarget.value), ); }} ></input> </ListItem> <ListItem title={Locale.Settings.Sync.Config.WebDav.UserName}> <input type="text" value={syncStore.webdav.username} onChange={(e) => { syncStore.update( (config) => (config.webdav.username = e.currentTarget.value), ); }} ></input> </ListItem> <ListItem title={Locale.Settings.Sync.Config.WebDav.Password}> <PasswordInput value={syncStore.webdav.password} onChange={(e) => { syncStore.update( (config) => (config.webdav.password = e.currentTarget.value), ); }} ></PasswordInput> </ListItem> </List> </> )} {syncStore.provider === ProviderType.UpStash && ( <List> <ListItem title={Locale.Settings.Sync.Config.UpStash.Endpoint}> <input type="text" value={syncStore.upstash.endpoint} onChange={(e) => { syncStore.update( (config) => (config.upstash.endpoint = e.currentTarget.value), ); }} ></input> </ListItem> <ListItem title={Locale.Settings.Sync.Config.UpStash.UserName}> <input type="text" value={syncStore.upstash.username} placeholder={STORAGE_KEY} onChange={(e) => { syncStore.update( (config) => (config.upstash.username = e.currentTarget.value), ); }} ></input> </ListItem> <ListItem title={Locale.Settings.Sync.Config.UpStash.Password}> <PasswordInput value={syncStore.upstash.apiKey} onChange={(e) => { syncStore.update( (config) => (config.upstash.apiKey = e.currentTarget.value), ); }} ></PasswordInput> </ListItem> </List> )} </Modal> </div> ); } function SyncItems() { const syncStore = useSyncStore(); const chatStore = useChatStore(); const promptStore = usePromptStore(); const maskStore = useMaskStore(); const couldSync = useMemo(() => { return syncStore.cloudSync(); }, [syncStore]); const [showSyncConfigModal, setShowSyncConfigModal] = useState(false); const stateOverview = useMemo(() => { const sessions = chatStore.sessions; const messageCount = sessions.reduce((p, c) => p + c.messages.length, 0); return { chat: sessions.length, message: messageCount, prompt: Object.keys(promptStore.prompts).length, mask: Object.keys(maskStore.masks).length, }; }, [chatStore.sessions, maskStore.masks, promptStore.prompts]); return ( <> <List> <ListItem title={Locale.Settings.Sync.CloudState} subTitle={ syncStore.lastProvider ? `${new Date(syncStore.lastSyncTime).toLocaleString()} [${ syncStore.lastProvider }]` : Locale.Settings.Sync.NotSyncYet } > <div style={{ display: "flex" }}> <IconButton icon={<ConfigIcon />} text={Locale.UI.Config} onClick={() => { setShowSyncConfigModal(true); }} /> {couldSync && ( <IconButton icon={<ResetIcon />} text={Locale.UI.Sync} onClick={async () => { try { await syncStore.sync(); showToast(Locale.Settings.Sync.Success); } catch (e) { showToast(Locale.Settings.Sync.Fail); console.error("[Sync]", e); } }} /> )} </div> </ListItem> <ListItem title={Locale.Settings.Sync.LocalState} subTitle={Locale.Settings.Sync.Overview(stateOverview)} > <div style={{ display: "flex" }}> <IconButton icon={<UploadIcon />} text={Locale.UI.Export} onClick={() => { syncStore.export(); }} /> <IconButton icon={<DownloadIcon />} text={Locale.UI.Import} onClick={() => { syncStore.import(); }} /> </div> </ListItem> </List> {showSyncConfigModal && ( <SyncConfigModal onClose={() => setShowSyncConfigModal(false)} /> )} </> ); } export function Settings() { const navigate = useNavigate(); const [showEmojiPicker, setShowEmojiPicker] = useState(false); const config = useAppConfig(); const updateConfig = config.update; const updateStore = useUpdateStore(); const [checkingUpdate, setCheckingUpdate] = useState(false); const currentVersion = updateStore.formatVersion(updateStore.version); const remoteId = updateStore.formatVersion(updateStore.remoteVersion); const hasNewVersion = currentVersion !== remoteId; const updateUrl = getClientConfig()?.isApp ? RELEASE_URL : UPDATE_URL; function checkUpdate(force = false) { setCheckingUpdate(true); updateStore.getLatestVersion(force).then(() => { setCheckingUpdate(false); }); console.log("[Update] local version ", updateStore.version); console.log("[Update] remote version ", updateStore.remoteVersion); } const accessStore = useAccessStore(); const shouldHideBalanceQuery = useMemo(() => { const isOpenAiUrl = accessStore.openaiUrl.includes(OPENAI_BASE_URL); return ( accessStore.hideBalanceQuery || isOpenAiUrl || accessStore.provider === ServiceProvider.Azure ); }, [ accessStore.hideBalanceQuery, accessStore.openaiUrl, accessStore.provider, ]); const usage = { used: updateStore.used, subscription: updateStore.subscription, }; const [loadingUsage, setLoadingUsage] = useState(false); function checkUsage(force = false) { if (shouldHideBalanceQuery) { return; } setLoadingUsage(true); updateStore.updateUsage(force).finally(() => { setLoadingUsage(false); }); } const enabledAccessControl = useMemo( () => accessStore.enabledAccessControl(), // eslint-disable-next-line react-hooks/exhaustive-deps [], ); const promptStore = usePromptStore(); const builtinCount = SearchService.count.builtin; const customCount = promptStore.getUserPrompts().length ?? 0; const [shouldShowPromptModal, setShowPromptModal] = useState(false); const showUsage = accessStore.isAuthorized(); useEffect(() => { // checks per minutes checkUpdate(); showUsage && checkUsage(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { const keydownEvent = (e: KeyboardEvent) => { if (e.key === "Escape") { navigate(Path.Home); } }; if (clientConfig?.isApp) { // Force to set custom endpoint to true if it's app accessStore.update((state) => { state.useCustomConfig = true; }); } document.addEventListener("keydown", keydownEvent); return () => { document.removeEventListener("keydown", keydownEvent); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const clientConfig = useMemo(() => getClientConfig(), []); const showAccessCode = enabledAccessControl && !clientConfig?.isApp; return ( <ErrorBoundary> <div className="window-header" data-tauri-drag-region> <div className="window-header-title"> <div className="window-header-main-title"> {Locale.Settings.Title} </div> <div className="window-header-sub-title"> {Locale.Settings.SubTitle} </div> </div> <div className="window-actions"> <div className="window-action-button"></div> <div className="window-action-button"></div> <div className="window-action-button"> <IconButton icon={<CloseIcon />} onClick={() => navigate(Path.Home)} bordered /> </div> </div> </div> <div className={styles["settings"]}> <List> <ListItem title={Locale.Settings.Avatar}> <Popover onClose={() => setShowEmojiPicker(false)} content={ <AvatarPicker onEmojiClick={(avatar: string) => { updateConfig((config) => (config.avatar = avatar)); setShowEmojiPicker(false); }} /> } open={showEmojiPicker} > <div className={styles.avatar} onClick={() => { setShowEmojiPicker(!showEmojiPicker); }} > <Avatar avatar={config.avatar} /> </div> </Popover> </ListItem> {/*<ListItem*/} {/* title={Locale.Settings.Update.Version(currentVersion ?? "unknown")}*/} {/* subTitle={*/} {/* checkingUpdate*/} {/* ? Locale.Settings.Update.IsChecking*/} {/* : hasNewVersion*/} {/* ? Locale.Settings.Update.FoundUpdate(remoteId ?? "ERROR")*/} {/* : Locale.Settings.Update.IsLatest*/} {/* }*/} {/*>*/} {/* {checkingUpdate ? (*/} {/* <LoadingIcon />*/} {/* ) : hasNewVersion ? (*/} {/* <Link href={updateUrl} target="_blank" className="link">*/} {/* {Locale.Settings.Update.GoToUpdate}*/} {/* </Link>*/} {/* ) : (*/} {/* <IconButton*/} {/* icon={<ResetIcon></ResetIcon>}*/} {/* text={Locale.Settings.Update.CheckUpdate}*/} {/* onClick={() => checkUpdate(true)}*/} {/* />*/} {/* )}*/} {/*</ListItem>*/} {/*<ListItem title={Locale.Settings.SendKey}>*/} {/* <Select*/} {/* value={config.submitKey}*/} {/* onChange={(e) => {*/} {/* updateConfig(*/} {/* (config) =>*/} {/* (config.submitKey = e.target.value as any as SubmitKey),*/} {/* );*/} {/* }}*/} {/* >*/} {/* {Object.values(SubmitKey).map((v) => (*/} {/* <option value={v} key={v}>*/} {/* {v}*/} {/* </option>*/} {/* ))}*/} {/* </Select>*/} {/*</ListItem>*/} {/*<ListItem title={Locale.Settings.Theme}>*/} {/* <Select*/} {/* value={config.theme}*/} {/* onChange={(e) => {*/} {/* updateConfig(*/} {/* (config) => (config.theme = e.target.value as any as Theme),*/} {/* );*/} {/* }}*/} {/* >*/} {/* {Object.values(Theme).map((v) => (*/} {/* <option value={v} key={v}>*/} {/* {v}*/} {/* </option>*/} {/* ))}*/} {/* </Select>*/} {/*</ListItem>*/} {/*<ListItem title={Locale.Settings.Lang.Name}>*/} {/* <Select*/} {/* value={getLang()}*/} {/* onChange={(e) => {*/} {/* changeLang(e.target.value as any);*/} {/* }}*/} {/* >*/} {/* {AllLangs.map((lang) => (*/} {/* <option value={lang} key={lang}>*/} {/* {ALL_LANG_OPTIONS[lang]}*/} {/* </option>*/} {/* ))}*/} {/* </Select>*/} {/*</ListItem>*/} <ListItem title={Locale.Settings.FontSize.Title} subTitle={Locale.Settings.FontSize.SubTitle} > <InputRange title={`${config.fontSize ?? 14}px`} value={config.fontSize} min="12" max="40" step="1" onChange={(e) => updateConfig( (config) => (config.fontSize = Number.parseInt(e.currentTarget.value)), ) } ></InputRange> </ListItem> {/*<ListItem*/} {/* title={Locale.Settings.AutoGenerateTitle.Title}*/} {/* subTitle={Locale.Settings.AutoGenerateTitle.SubTitle}*/} {/*>*/} {/* <input*/} {/* type="checkbox"*/} {/* checked={config.enableAutoGenerateTitle}*/} {/* onChange={(e) =>*/} {/* updateConfig(*/} {/* (config) =>*/} {/* (config.enableAutoGenerateTitle = e.currentTarget.checked),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/*</ListItem>*/} {/*<ListItem*/} {/* title={Locale.Settings.SendPreviewBubble.Title}*/} {/* subTitle={Locale.Settings.SendPreviewBubble.SubTitle}*/} {/*>*/} {/* <input*/} {/* type="checkbox"*/} {/* checked={config.sendPreviewBubble}*/} {/* onChange={(e) =>*/} {/* updateConfig(*/} {/* (config) =>*/} {/* (config.sendPreviewBubble = e.currentTarget.checked),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/*</ListItem>*/} </List> {/*<SyncItems />*/} {/*<List>*/} {/* <ListItem*/} {/* title={Locale.Settings.Mask.Splash.Title}*/} {/* subTitle={Locale.Settings.Mask.Splash.SubTitle}*/} {/* >*/} {/* <input*/} {/* type="checkbox"*/} {/* checked={!config.dontShowMaskSplashScreen}*/} {/* onChange={(e) =>*/} {/* updateConfig(*/} {/* (config) =>*/} {/* (config.dontShowMaskSplashScreen =*/} {/* !e.currentTarget.checked),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/* <ListItem*/} {/* title={Locale.Settings.Mask.Builtin.Title}*/} {/* subTitle={Locale.Settings.Mask.Builtin.SubTitle}*/} {/* >*/} {/* <input*/} {/* type="checkbox"*/} {/* checked={config.hideBuiltinMasks}*/} {/* onChange={(e) =>*/} {/* updateConfig(*/} {/* (config) =>*/} {/* (config.hideBuiltinMasks = e.currentTarget.checked),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/*</List>*/} {/*<List>*/} {/* <ListItem*/} {/* title={Locale.Settings.Prompt.Disable.Title}*/} {/* subTitle={Locale.Settings.Prompt.Disable.SubTitle}*/} {/* >*/} {/* <input*/} {/* type="checkbox"*/} {/* checked={config.disablePromptHint}*/} {/* onChange={(e) =>*/} {/* updateConfig(*/} {/* (config) =>*/} {/* (config.disablePromptHint = e.currentTarget.checked),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/* <ListItem*/} {/* title={Locale.Settings.Prompt.List}*/} {/* subTitle={Locale.Settings.Prompt.ListCount(*/} {/* builtinCount,*/} {/* customCount,*/} {/* )}*/} {/* >*/} {/* <IconButton*/} {/* icon={<EditIcon />}*/} {/* text={Locale.Settings.Prompt.Edit}*/} {/* onClick={() => setShowPromptModal(true)}*/} {/* />*/} {/* </ListItem>*/} {/*</List>*/} {/*<List id={SlotID.CustomModel}>*/} {/* {showAccessCode && (*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.AccessCode.Title}*/} {/* subTitle={Locale.Settings.Access.AccessCode.SubTitle}*/} {/* >*/} {/* <PasswordInput*/} {/* value={accessStore.accessCode}*/} {/* type="text"*/} {/* placeholder={Locale.Settings.Access.AccessCode.Placeholder}*/} {/* onChange={(e) => {*/} {/* accessStore.update(*/} {/* (access) => (access.accessCode = e.currentTarget.value),*/} {/* );*/} {/* }}*/} {/* />*/} {/* </ListItem>*/} {/* )}*/} {/* {!accessStore.hideUserApiKey && (*/} {/* <>*/} {/* {*/} {/* // Conditionally render the following ListItem based on clientConfig.isApp*/} {/* !clientConfig?.isApp && ( // only show if isApp is false*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.CustomEndpoint.Title}*/} {/* subTitle={Locale.Settings.Access.CustomEndpoint.SubTitle}*/} {/* >*/} {/* <input*/} {/* type="checkbox"*/} {/* checked={accessStore.useCustomConfig}*/} {/* onChange={(e) =>*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.useCustomConfig = e.currentTarget.checked),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/* )*/} {/* }*/} {/* {accessStore.useCustomConfig && (*/} {/* <>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.Provider.Title}*/} {/* subTitle={Locale.Settings.Access.Provider.SubTitle}*/} {/* >*/} {/* <Select*/} {/* value={accessStore.provider}*/} {/* onChange={(e) => {*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.provider = e.target*/} {/* .value as ServiceProvider),*/} {/* );*/} {/* }}*/} {/* >*/} {/* {Object.entries(ServiceProvider).map(([k, v]) => (*/} {/* <option value={v} key={k}>*/} {/* {k}*/} {/* </option>*/} {/* ))}*/} {/* </Select>*/} {/* </ListItem>*/} {/* {accessStore.provider === "OpenAI" ? (*/} {/* <>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.OpenAI.Endpoint.Title}*/} {/* subTitle={*/} {/* Locale.Settings.Access.OpenAI.Endpoint.SubTitle*/} {/* }*/} {/* >*/} {/* <input*/} {/* type="text"*/} {/* value={accessStore.openaiUrl}*/} {/* placeholder={OPENAI_BASE_URL}*/} {/* onChange={(e) =>*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.openaiUrl = e.currentTarget.value),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.OpenAI.ApiKey.Title}*/} {/* subTitle={Locale.Settings.Access.OpenAI.ApiKey.SubTitle}*/} {/* >*/} {/* <PasswordInput*/} {/* value={accessStore.openaiApiKey}*/} {/* type="text"*/} {/* placeholder={*/} {/* Locale.Settings.Access.OpenAI.ApiKey.Placeholder*/} {/* }*/} {/* onChange={(e) => {*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.openaiApiKey = e.currentTarget.value),*/} {/* );*/} {/* }}*/} {/* />*/} {/* </ListItem>*/} {/* </>*/} {/* ) : accessStore.provider === "Azure" ? (*/} {/* <>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.Azure.Endpoint.Title}*/} {/* subTitle={*/} {/* Locale.Settings.Access.Azure.Endpoint.SubTitle +*/} {/* Azure.ExampleEndpoint*/} {/* }*/} {/* >*/} {/* <input*/} {/* type="text"*/} {/* value={accessStore.azureUrl}*/} {/* placeholder={Azure.ExampleEndpoint}*/} {/* onChange={(e) =>*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.azureUrl = e.currentTarget.value),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.Azure.ApiKey.Title}*/} {/* subTitle={Locale.Settings.Access.Azure.ApiKey.SubTitle}*/} {/* >*/} {/* <PasswordInput*/} {/* value={accessStore.azureApiKey}*/} {/* type="text"*/} {/* placeholder={*/} {/* Locale.Settings.Access.Azure.ApiKey.Placeholder*/} {/* }*/} {/* onChange={(e) => {*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.azureApiKey = e.currentTarget.value),*/} {/* );*/} {/* }}*/} {/* />*/} {/* </ListItem>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.Azure.ApiVerion.Title}*/} {/* subTitle={*/} {/* Locale.Settings.Access.Azure.ApiVerion.SubTitle*/} {/* }*/} {/* >*/} {/* <input*/} {/* type="text"*/} {/* value={accessStore.azureApiVersion}*/} {/* placeholder="2023-08-01-preview"*/} {/* onChange={(e) =>*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.azureApiVersion =*/} {/* e.currentTarget.value),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/* </>*/} {/* ) : accessStore.provider === "Google" ? (*/} {/* <>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.Google.Endpoint.Title}*/} {/* subTitle={*/} {/* Locale.Settings.Access.Google.Endpoint.SubTitle +*/} {/* Google.ExampleEndpoint*/} {/* }*/} {/* >*/} {/* <input*/} {/* type="text"*/} {/* value={accessStore.googleUrl}*/} {/* placeholder={Google.ExampleEndpoint}*/} {/* onChange={(e) =>*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.googleUrl = e.currentTarget.value),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.Google.ApiKey.Title}*/} {/* subTitle={Locale.Settings.Access.Google.ApiKey.SubTitle}*/} {/* >*/} {/* <PasswordInput*/} {/* value={accessStore.googleApiKey}*/} {/* type="text"*/} {/* placeholder={*/} {/* Locale.Settings.Access.Google.ApiKey.Placeholder*/} {/* }*/} {/* onChange={(e) => {*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.googleApiKey = e.currentTarget.value),*/} {/* );*/} {/* }}*/} {/* />*/} {/* </ListItem>*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.Google.ApiVersion.Title}*/} {/* subTitle={*/} {/* Locale.Settings.Access.Google.ApiVersion.SubTitle*/} {/* }*/} {/* >*/} {/* <input*/} {/* type="text"*/} {/* value={accessStore.googleApiVersion}*/} {/* placeholder="2023-08-01-preview"*/} {/* onChange={(e) =>*/} {/* accessStore.update(*/} {/* (access) =>*/} {/* (access.googleApiVersion =*/} {/* e.currentTarget.value),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/* </>*/} {/* ) : null}*/} {/* </>*/} {/* )}*/} {/* </>*/} {/* )}*/} {/* {!shouldHideBalanceQuery && !clientConfig?.isApp ? (*/} {/* <ListItem*/} {/* title={Locale.Settings.Usage.Title}*/} {/* subTitle={*/} {/* showUsage*/} {/* ? loadingUsage*/} {/* ? Locale.Settings.Usage.IsChecking*/} {/* : Locale.Settings.Usage.SubTitle(*/} {/* usage?.used ?? "[?]",*/} {/* usage?.subscription ?? "[?]",*/} {/* )*/} {/* : Locale.Settings.Usage.NoAccess*/} {/* }*/} {/* >*/} {/* {!showUsage || loadingUsage ? (*/} {/* <div />*/} {/* ) : (*/} {/* <IconButton*/} {/* icon={<ResetIcon></ResetIcon>}*/} {/* text={Locale.Settings.Usage.Check}*/} {/* onClick={() => checkUsage(true)}*/} {/* />*/} {/* )}*/} {/* </ListItem>*/} {/* ) : null}*/} {/* <ListItem*/} {/* title={Locale.Settings.Access.CustomModel.Title}*/} {/* subTitle={Locale.Settings.Access.CustomModel.SubTitle}*/} {/* >*/} {/* <input*/} {/* type="text"*/} {/* value={config.customModels}*/} {/* placeholder="model1,model2,model3"*/} {/* onChange={(e) =>*/} {/* config.update(*/} {/* (config) => (config.customModels = e.currentTarget.value),*/} {/* )*/} {/* }*/} {/* ></input>*/} {/* </ListItem>*/} {/*</List>*/} {/*<List>*/} {/* <ModelConfigList*/} {/* modelConfig={config.modelConfig}*/} {/* updateConfig={(updater) => {*/} {/* const modelConfig = { ...config.modelConfig };*/} {/* updater(modelConfig);*/} {/* config.update((config) => (config.modelConfig = modelConfig));*/} {/* }}*/} {/* />*/} {/*</List>*/} {shouldShowPromptModal && ( <UserPromptModal onClose={() => setShowPromptModal(false)} /> )} <DangerItems /> </div> </ErrorBoundary> ); }