import { Accordion, AccordionHeader, AccordionItem, AccordionPanel, Checkbox, Dropdown, Input, Label, Link, Option, PresenceBadge, Select, Switch, Text, Tooltip } from '@fluentui/react-components'; import { AddCircle20Regular, DataUsageSettings20Regular, Delete20Regular, Save20Regular } from '@fluentui/react-icons'; import React, { FC, useCallback, useEffect, useRef } from 'react'; import { Section } from '../components/Section'; import { Labeled } from '../components/Labeled'; import { ToolTipButton } from '../components/ToolTipButton'; import commonStore from '../stores/commonStore'; import { observer } from 'mobx-react-lite'; import { toast } from 'react-toastify'; import { ValuedSlider } from '../components/ValuedSlider'; import { NumberInput } from '../components/NumberInput'; import { Page } from '../components/Page'; import { useNavigate } from 'react-router'; import { RunButton } from '../components/RunButton'; import { updateConfig } from '../apis'; import { getStrategy, isDynamicStateSupported } from '../utils'; import { useTranslation } from 'react-i18next'; import strategyImg from '../assets/images/strategy.jpg'; import strategyZhImg from '../assets/images/strategy_zh.jpg'; import { ResetConfigsButton } from '../components/ResetConfigsButton'; import { useMediaQuery } from 'usehooks-ts'; import { ApiParameters, Device, ModelParameters, Precision } from '../types/configs'; import { convertModel, convertToGGML, convertToSt } from '../utils/convert-model'; import { defaultPenaltyDecay } from './defaultConfigs'; import { BrowserOpenURL } from '../../wailsjs/runtime'; const ConfigSelector: FC<{ selectedIndex: number, updateSelectedIndex: (i: number) => void }> = observer(({ selectedIndex, updateSelectedIndex }) => { return ( { if (data.optionValue) { updateSelectedIndex(Number(data.optionValue)); } }}> {commonStore.modelConfigs.map((config, index) => )} ); }); const Configs: FC = observer(() => { const { t } = useTranslation(); const [selectedIndex, setSelectedIndex] = React.useState(commonStore.currentModelConfigIndex); const [selectedConfig, setSelectedConfig] = React.useState(commonStore.modelConfigs[selectedIndex]); const [displayStrategyImg, setDisplayStrategyImg] = React.useState(false); const advancedHeaderRef1 = useRef(null); const advancedHeaderRef2 = useRef(null); const mq = useMediaQuery('(min-width: 640px)'); const navigate = useNavigate(); const port = selectedConfig.apiParameters.apiPort; useEffect(() => { if (advancedHeaderRef1.current) (advancedHeaderRef1.current.firstElementChild as HTMLElement).style.padding = '0'; if (advancedHeaderRef2.current) (advancedHeaderRef2.current.firstElementChild as HTMLElement).style.padding = '0'; }, []); const updateSelectedIndex = useCallback((newIndex: number) => { setSelectedIndex(newIndex); setSelectedConfig(commonStore.modelConfigs[newIndex]); // if you don't want to update the config used by the current startup in real time, comment out this line commonStore.setCurrentConfigIndex(newIndex); }, []); const setSelectedConfigName = (newName: string) => { setSelectedConfig({ ...selectedConfig, name: newName }); }; const setSelectedConfigApiParams = (newParams: Partial) => { setSelectedConfig({ ...selectedConfig, apiParameters: { ...selectedConfig.apiParameters, ...newParams } }); }; const setSelectedConfigModelParams = (newParams: Partial) => { setSelectedConfig({ ...selectedConfig, modelParameters: { ...selectedConfig.modelParameters, ...newParams } }); }; const onClickSave = () => { commonStore.setModelConfig(selectedIndex, selectedConfig); // When clicking RunButton in Configs page, updateConfig will be called twice, // because there are also RunButton in other pages, and the calls to updateConfig in both places are necessary. updateConfig({ max_tokens: selectedConfig.apiParameters.maxResponseToken, temperature: selectedConfig.apiParameters.temperature, top_p: selectedConfig.apiParameters.topP, presence_penalty: selectedConfig.apiParameters.presencePenalty, frequency_penalty: selectedConfig.apiParameters.frequencyPenalty, penalty_decay: selectedConfig.apiParameters.penaltyDecay, global_penalty: selectedConfig.apiParameters.globalPenalty, state: selectedConfig.apiParameters.stateModel }).then(async r => { if (r.status !== 200) { const error = await r.text(); if (error.includes('state shape mismatch')) toast(t('State model mismatch'), { type: 'error' }); else if (error.includes('file format of the model or state model not supported')) toast(t('File format of the model or state model not supported'), { type: 'error' }); else toast(error, { type: 'error' }); } }); toast(t('Config Saved'), { autoClose: 300, type: 'success' }); }; return (
} onClick={() => { commonStore.createModelConfig(); updateSelectedIndex(commonStore.modelConfigs.length - 1); }} /> } onClick={() => { commonStore.deleteModelConfig(selectedIndex); updateSelectedIndex(Math.min(selectedIndex, commonStore.modelConfigs.length - 1)); }} /> { setSelectedIndex(0); setSelectedConfig(commonStore.modelConfigs[0]); }} /> } text={mq ? t('Save Config') : null} onClick={onClickSave} />
{ setSelectedConfigName(data.value); }} />
{ setSelectedConfigApiParams({ apiPort: data.value }); }} /> } /> { setSelectedConfigApiParams({ maxResponseToken: data.value }); }} /> } /> { setSelectedConfigApiParams({ temperature: data.value }); }} /> } /> { setSelectedConfigApiParams({ topP: data.value }); }} /> } /> {isDynamicStateSupported(selectedConfig) &&
{t('State-tuned Model')}, {t('See More')}: BrowserOpenURL('https://github.com/BlinkDL/RWKV-LM#state-tuning-tuning-the-initial-state-zero-inference-overhead')}>{'https://github.com/BlinkDL/RWKV-LM#state-tuning-tuning-the-initial-state-zero-inference-overhead'}
} showDelay={0} hideDelay={0} relationship="description">
{t('State Model') + ' *'}
} { if (data.value === 'advanced') commonStore.setApiParamsCollapsed(!commonStore.apiParamsCollapsed); }}> {t('Advanced')}
{ setSelectedConfigApiParams({ presencePenalty: data.value }); }} /> } /> { setSelectedConfigApiParams({ frequencyPenalty: data.value }); }} /> } /> { setSelectedConfigApiParams({ penaltyDecay: data.value }); }} /> } /> { setSelectedConfigApiParams({ globalPenalty: data.checked }); }} /> } />
} />
{t('Model')}
} onClick={() => { navigate({ pathname: '/models' }); }} />
{ !selectedConfig.modelParameters.device.startsWith('WebGPU') ? (selectedConfig.modelParameters.device !== 'CPU (rwkv.cpp)' ? convertModel(selectedConfig, navigate)} /> : convertToGGML(selectedConfig, navigate)} />) : convertToSt(selectedConfig, navigate)} /> }
{ if (data.optionValue) { setSelectedConfigModelParams({ device: data.optionValue as Device }); } }}> {/*{commonStore.platform === 'darwin' && }*/} {/**/} } /> { selectedConfig.modelParameters.device !== 'Custom' && { if (data.optionText) { setSelectedConfigModelParams({ precision: data.optionText as Precision }); } }}> {selectedConfig.modelParameters.device !== 'CPU' && selectedConfig.modelParameters.device !== 'MPS' && } {selectedConfig.modelParameters.device !== 'CPU (rwkv.cpp)' && } {selectedConfig.modelParameters.device.startsWith('WebGPU') && } {selectedConfig.modelParameters.device !== 'CPU (rwkv.cpp)' && !selectedConfig.modelParameters.device.startsWith('WebGPU') && } {selectedConfig.modelParameters.device === 'CPU (rwkv.cpp)' && } } /> } { selectedConfig.modelParameters.device.startsWith('CUDA') && {getStrategy(selectedConfig)} } /> } { selectedConfig.modelParameters.device.startsWith('CUDA') && { setSelectedConfigModelParams({ storedLayers: data.value }); }} /> } /> } { selectedConfig.modelParameters.device.startsWith('WebGPU') && { setSelectedConfigModelParams({ tokenChunkSize: data.value }); }} /> } /> } { selectedConfig.modelParameters.device.startsWith('WebGPU') && { setSelectedConfigModelParams({ quantizedLayers: data.value }); }} /> } /> } {selectedConfig.modelParameters.device.startsWith('CUDA') &&
} { displayStrategyImg && } { selectedConfig.modelParameters.device === 'Custom' && setDisplayStrategyImg(true)} onMouseLeave={() => setDisplayStrategyImg(false)} content={ cuda:1 fp16' : 'mps fp32'} value={selectedConfig.modelParameters.customStrategy} onChange={(e, data) => { setSelectedConfigModelParams({ customStrategy: data.value }); }} /> } /> } {selectedConfig.modelParameters.device === 'Custom' &&
} { (selectedConfig.modelParameters.device.startsWith('CUDA') || selectedConfig.modelParameters.device === 'Custom') && { setSelectedConfigModelParams({ useCustomCuda: data.checked }); }} /> } /> } {selectedConfig.modelParameters.device !== 'WebGPU' && { if (data.value === 'advanced') commonStore.setModelParamsCollapsed(!commonStore.modelParamsCollapsed); }}> {t('Advanced')}
{ setSelectedConfigModelParams({ useCustomTokenizer: data.checked as boolean }); }} /> { setSelectedConfigModelParams({ customTokenizer: data.value }); }} />
}
} /> {mq &&
}
{selectedConfig.modelParameters.device !== 'WebGPU' && { setSelectedConfig({ ...selectedConfig, enableWebUI: data.checked as boolean }); }} />}
} /> ); }); export default Configs;