// TODO refactor import React, { FC, lazy, PropsWithChildren, ReactElement, useState } from 'react'; import { Button, Dialog, DialogBody, DialogContent, DialogSurface, DialogTrigger, Input, Switch, Tab, TabList, Text } from '@fluentui/react-components'; import { Accessibility28Regular, Chat20Regular, ClipboardEdit20Regular, Delete20Regular, Dismiss20Regular, Edit20Regular, Globe20Regular } from '@fluentui/react-icons'; import { ToolTipButton } from '../../components/ToolTipButton'; import { useTranslation } from 'react-i18next'; import { SelectTabEventHandler } from '@fluentui/react-tabs'; import { Labeled } from '../../components/Labeled'; import commonStore from '../../stores/commonStore'; import logo from '../../assets/images/logo.png'; import { observer } from 'mobx-react-lite'; import { ClipboardGetText, ClipboardSetText } from '../../../wailsjs/runtime'; import { toast } from 'react-toastify'; import { CustomToastContainer } from '../../components/CustomToastContainer'; import { absPathAsset, setActivePreset } from '../../utils'; import { Preset, PresetsNavigationItem } from '../../types/presets'; import { LazyImportComponent } from '../../components/LazyImportComponent'; const defaultPreset: Preset = { name: 'RWKV', tag: 'default', sourceUrl: '', desc: '', avatarImg: logo, type: 'chat', welcomeMessage: '', displayPresetMessages: true, messages: [], prompt: '', stop: '', injectStart: '', injectEnd: '', presystem: true, userName: '', assistantName: '' }; const MessagesEditor = lazy(() => import('./MessagesEditor')); const PresetCardFrame: FC }> = (props) => { return ; }; const PresetCard: FC<{ avatarImg: string, name: string, desc: string, tag: string, editable: boolean, presetIndex: number, onClick?: () => void }> = observer(({ avatarImg, name, desc, tag, editable, presetIndex, onClick }) => { const { t } = useTranslation(); return { if (onClick && e.currentTarget.contains(e.target as Node)) onClick(); }}> {name} {desc}
{t(tag)}
{editable ? } onClick={(e) => { e.stopPropagation(); commonStore.setEditingPreset({ ...commonStore.presets[presetIndex] }); }} /> } /> :
}
; }); const ChatPresetEditor: FC<{ triggerButton: ReactElement, presetIndex: number }> = observer(({ triggerButton, presetIndex }) => { const { t } = useTranslation(); const [editingMessages, setEditingMessages] = useState(false); if (!commonStore.editingPreset) commonStore.setEditingPreset({ ...defaultPreset }); const editingPreset = commonStore.editingPreset!; const setEditingPreset = (newParams: Partial) => { commonStore.setEditingPreset({ ...editingPreset, ...newParams }); }; const importPreset = () => { ClipboardGetText().then((text) => { try { if (!text.trim().startsWith('{')) text = new TextDecoder().decode( new Uint8Array(atob(text) .split('') .map((c) => c.charCodeAt(0)))); const preset = JSON.parse(text); setEditingPreset(preset); setEditingMessages(false); toast(t('Imported successfully'), { type: 'success', autoClose: 1000 }); } catch (e) { toast(t('Failed to import. Please copy a preset to the clipboard.'), { type: 'error', autoClose: 2500 }); } }).catch(() => { toast(t('Clipboard is empty.'), { type: 'info', autoClose: 1000 }); }); }; const copyPreset = () => { ClipboardSetText(JSON.stringify(editingPreset)).then((success) => { if (success) toast(t('Successfully copied to clipboard.'), { type: 'success', autoClose: 1000 }); }); }; const savePreset = () => { if (presetIndex === -1) { commonStore.setPresets([...commonStore.presets, { ...editingPreset }]); setEditingPreset(defaultPreset); } else { commonStore.presets[presetIndex] = editingPreset; commonStore.setPresets(commonStore.presets); } }; const activatePreset = () => { savePreset(); setActivePreset(editingPreset); }; const deletePreset = () => { commonStore.presets.splice(presetIndex, 1); commonStore.setPresets(commonStore.presets); }; return {triggerButton}
{ presetIndex === -1 ?
:
{ setEditingPreset({ name: data.value }); }} />
} /> { editingMessages ?
{ setEditingPreset({ presystem: data.checked }); }} /> } /> { setEditingPreset({ userName: data.value }); }} /> } /> { setEditingPreset({ assistantName: data.value }); }} /> } />
:
{ setEditingPreset({ desc: data.value }); }} /> } /> { setEditingPreset({ avatarImg: data.value }); }} /> } /> { setEditingPreset({ welcomeMessage: data.value }); }} /> } /> { setEditingPreset({ displayPresetMessages: data.checked }); }} /> } /> { setEditingPreset({ tag: data.value }); }} /> } />
}
; }); const ChatPresets: FC = observer(() => { const { t } = useTranslation(); return
{t('New Preset')}
} /> {/*TODO */} {/*
*/} {/* {t('Import')}*/} {/*
*/} {/*
*/} { setActivePreset(defaultPreset); }} avatarImg={defaultPreset.avatarImg} name={defaultPreset.name} desc={defaultPreset.desc} tag={defaultPreset.tag} /> {commonStore.presets.map((preset, index) => { return { setActivePreset(preset); }} key={index} avatarImg={preset.avatarImg} name={preset.name} desc={preset.desc} tag={preset.tag} />; })}
; }); const pages: { [label: string]: PresetsNavigationItem } = { Chat: { icon: , element: }, Completion: { icon: , element:
In Development
}, Online: { icon: , element:
In Development
} }; const PresetsManager: FC<{ initTab: string }> = ({ initTab }) => { const { t } = useTranslation(); const [tab, setTab] = useState(initTab); const selectTab: SelectTabEventHandler = (e, data) => typeof data.value === 'string' ? setTab(data.value) : null; return
{Object.entries(pages).map(([label, { icon }]) => ( {t(label)} ))}
{pages[tab].element}
; }; export const PresetsButton: FC<{ tab: string, size?: 'small' | 'medium' | 'large', shape?: 'rounded' | 'circular' | 'square'; appearance?: 'secondary' | 'primary' | 'outline' | 'subtle' | 'transparent'; }> = ({ tab, size, shape, appearance }) => { const { t } = useTranslation(); return } /> ; };