improve details

This commit is contained in:
josc146 2023-05-21 12:54:37 +08:00
parent d4d71898ed
commit c02ce51d86
3 changed files with 306 additions and 286 deletions

View File

@ -95,5 +95,6 @@
"Python dependencies are incomplete, would you like to install them?": "Python依赖缺失, 是否安装?", "Python dependencies are incomplete, would you like to install them?": "Python依赖缺失, 是否安装?",
"Install": "安装", "Install": "安装",
"This is the latest version": "已是最新版", "This is the latest version": "已是最新版",
"Use Tsinghua Pip Mirrors": "使用清华大学Pip镜像源" "Use Tsinghua Pip Mirrors": "使用清华大学Pip镜像源",
"Model Config Exception": "模型配置异常"
} }

View File

@ -1,16 +1,17 @@
import React, {FC, MouseEventHandler, ReactElement} from 'react'; import React, { FC, MouseEventHandler, ReactElement } from 'react';
import commonStore, {ModelStatus} from '../stores/commonStore'; import commonStore, { ModelStatus } from '../stores/commonStore';
import {AddToDownloadList, DepCheck, FileExists, InstallPyDep, StartServer} from '../../wailsjs/go/backend_golang/App'; import { AddToDownloadList, DepCheck, FileExists, InstallPyDep, StartServer } from '../../wailsjs/go/backend_golang/App';
import {Button} from '@fluentui/react-components'; import { Button } from '@fluentui/react-components';
import {observer} from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import {exit, readRoot, switchModel, updateConfig} from '../apis'; import { exit, readRoot, switchModel, updateConfig } from '../apis';
import {toast} from 'react-toastify'; import { toast } from 'react-toastify';
import manifest from '../../../manifest.json'; import manifest from '../../../manifest.json';
import {getStrategy, saveCache, toastWithButton} from '../utils'; import { getStrategy, saveCache, toastWithButton } from '../utils';
import {useTranslation} from 'react-i18next'; import { useTranslation } from 'react-i18next';
import {ToolTipButton} from './ToolTipButton'; import { ToolTipButton } from './ToolTipButton';
import {Play16Regular, Stop16Regular} from '@fluentui/react-icons'; import { Play16Regular, Stop16Regular } from '@fluentui/react-icons';
import {useNavigate} from 'react-router'; import { useNavigate } from 'react-router';
import { WindowShow } from '../../wailsjs/runtime/runtime';
const mainButtonText = { const mainButtonText = {
[ModelStatus.Offline]: 'Run', [ModelStatus.Offline]: 'Run',
@ -20,10 +21,10 @@ const mainButtonText = {
}; };
const iconModeButtonIcon: { [modelStatus: number]: ReactElement } = { const iconModeButtonIcon: { [modelStatus: number]: ReactElement } = {
[ModelStatus.Offline]: <Play16Regular/>, [ModelStatus.Offline]: <Play16Regular />,
[ModelStatus.Starting]: <Stop16Regular/>, [ModelStatus.Starting]: <Stop16Regular />,
[ModelStatus.Loading]: <Stop16Regular/>, [ModelStatus.Loading]: <Stop16Regular />,
[ModelStatus.Working]: <Stop16Regular/> [ModelStatus.Working]: <Stop16Regular />
}; };
export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean }> export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean }>
@ -31,34 +32,48 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean
onClickRun, onClickRun,
iconMode iconMode
}) => { }) => {
const {t} = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const onClickMainButton = async () => { const onClickMainButton = async () => {
if (commonStore.modelStatus === ModelStatus.Offline) {
commonStore.setModelStatus(ModelStatus.Starting);
const modelConfig = commonStore.getCurrentModelConfig(); const modelConfig = commonStore.getCurrentModelConfig();
const modelName = modelConfig.modelParameters.modelName; let modelName = ''
const modelPath = `./${manifest.localModelDir}/${modelName}`; let modelPath = ''
if (modelConfig && modelConfig.modelParameters) {
modelName = modelConfig.modelParameters.modelName;
modelPath = `./${manifest.localModelDir}/${modelName}`;
} else {
toast(t('Model Config Exception'), { type: 'error' });
commonStore.setModelStatus(ModelStatus.Offline);
return;
}
if (!commonStore.depComplete) { if (!commonStore.depComplete) {
let depErrorMsg = ''; let depErrorMsg = '';
await DepCheck().catch((e) => { await DepCheck().catch((e) => {
depErrorMsg = e.message || e; depErrorMsg = e.message || e;
WindowShow();
if (depErrorMsg === 'python zip not found') { if (depErrorMsg === 'python zip not found') {
toastWithButton(t('Python target not found, would you like to download it?'), t('Download'), () => { toastWithButton(t('Python target not found, would you like to download it?'), t('Download'), () => {
toastWithButton(`${t('Downloading')} Python`, t('Check'), () => { toastWithButton(`${t('Downloading')} Python`, t('Check'), () => {
navigate({pathname: '/downloads'}); navigate({ pathname: '/downloads' });
}, {autoClose: 3000}); }, { autoClose: 3000 });
AddToDownloadList('python-3.10.11-embed-amd64.zip', 'https://www.python.org/ftp/python/3.10.11/python-3.10.11-embed-amd64.zip'); AddToDownloadList('python-3.10.11-embed-amd64.zip', 'https://www.python.org/ftp/python/3.10.11/python-3.10.11-embed-amd64.zip');
}); });
} else if (depErrorMsg.includes('DepCheck Error')) { } else if (depErrorMsg.includes('DepCheck Error')) {
toastWithButton(t('Python dependencies are incomplete, would you like to install them?'), t('Install'), () => { toastWithButton(t('Python dependencies are incomplete, would you like to install them?'), t('Install'), () => {
InstallPyDep(commonStore.settings.cnMirror); InstallPyDep(commonStore.settings.cnMirror);
setTimeout(WindowShow, 1000)
}); });
} else { } else {
toast(depErrorMsg, {type: 'error'}); toast(depErrorMsg, { type: 'error' });
} }
}); });
if (depErrorMsg) { if (depErrorMsg) {
commonStore.setModelStatus(ModelStatus.Offline);
return; return;
} }
commonStore.setDepComplete(true); commonStore.setDepComplete(true);
@ -70,25 +85,25 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean
const downloadUrl = commonStore.modelSourceList.find(item => item.name === modelName)?.downloadUrl; const downloadUrl = commonStore.modelSourceList.find(item => item.name === modelName)?.downloadUrl;
if (downloadUrl) { if (downloadUrl) {
toastWithButton(`${t('Downloading')} ${modelName}`, t('Check'), () => { toastWithButton(`${t('Downloading')} ${modelName}`, t('Check'), () => {
navigate({pathname: '/downloads'}); navigate({ pathname: '/downloads' });
}, },
{autoClose: 3000}); { autoClose: 3000 });
AddToDownloadList(modelPath, downloadUrl); AddToDownloadList(modelPath, downloadUrl);
} else { } else {
toast(t('Can not find download url'), {type: 'error'}); toast(t('Can not find download url'), { type: 'error' });
} }
}); });
commonStore.setModelStatus(ModelStatus.Offline);
return; return;
} }
const port = modelConfig.apiParameters.apiPort; const port = modelConfig.apiParameters.apiPort;
if (commonStore.modelStatus === ModelStatus.Offline) {
commonStore.setModelStatus(ModelStatus.Starting);
await exit(1000).catch(() => { await exit(1000).catch(() => {
}); });
StartServer(port); StartServer(port);
setTimeout(WindowShow, 1000)
let timeoutCount = 6; let timeoutCount = 6;
let loading = false; let loading = false;
@ -99,7 +114,7 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean
clearInterval(intervalId); clearInterval(intervalId);
commonStore.setModelStatus(ModelStatus.Loading); commonStore.setModelStatus(ModelStatus.Loading);
loading = true; loading = true;
toast(t('Loading Model'), {type: 'info'}); toast(t('Loading Model'), { type: 'info' });
updateConfig({ updateConfig({
max_tokens: modelConfig.apiParameters.maxResponseToken, max_tokens: modelConfig.apiParameters.maxResponseToken,
temperature: modelConfig.apiParameters.temperature, temperature: modelConfig.apiParameters.temperature,
@ -113,16 +128,18 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean
}).then((r) => { }).then((r) => {
if (r.ok) { if (r.ok) {
commonStore.setModelStatus(ModelStatus.Working); commonStore.setModelStatus(ModelStatus.Working);
toast(t('Startup Completed'), {type: 'success'}); toastWithButton(t('Startup Completed'), t('Chat'), () => {
navigate({ pathname: '/chat' });
}, { type: 'success', autoClose: 3000 });
} else if (r.status === 304) { } else if (r.status === 304) {
toast(t('Loading Model'), {type: 'info'}); toast(t('Loading Model'), { type: 'info' });
} else { } else {
commonStore.setModelStatus(ModelStatus.Offline); commonStore.setModelStatus(ModelStatus.Offline);
toast(t('Failed to switch model'), {type: 'error'}); toast(t('Failed to switch model'), { type: 'error' });
} }
}).catch(() => { }).catch(() => {
commonStore.setModelStatus(ModelStatus.Offline); commonStore.setModelStatus(ModelStatus.Offline);
toast(t('Failed to switch model'), {type: 'error'}); toast(t('Failed to switch model'), { type: 'error' });
}); });
} }
}).catch(() => { }).catch(() => {
@ -150,11 +167,11 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean
<ToolTipButton disabled={commonStore.modelStatus === ModelStatus.Starting} <ToolTipButton disabled={commonStore.modelStatus === ModelStatus.Starting}
icon={iconModeButtonIcon[commonStore.modelStatus]} icon={iconModeButtonIcon[commonStore.modelStatus]}
desc={t(mainButtonText[commonStore.modelStatus])} desc={t(mainButtonText[commonStore.modelStatus])}
size="small" onClick={onClick}/> size="small" onClick={onClick} />
: :
<Button disabled={commonStore.modelStatus === ModelStatus.Starting} appearance="primary" size="large" <Button disabled={commonStore.modelStatus === ModelStatus.Starting} appearance="primary" size="large"
onClick={onClick}> onClick={onClick}>
{t(mainButtonText[commonStore.modelStatus])} {t(mainButtonText[commonStore.modelStatus])}
</Button> </Button>
); );
}); });

View File

@ -1,22 +1,23 @@
import {Dropdown, Input, Label, Option, Select, Switch} from '@fluentui/react-components'; import { Dropdown, Input, Label, Option, Select, Switch } from '@fluentui/react-components';
import {AddCircle20Regular, DataUsageSettings20Regular, Delete20Regular, Save20Regular} from '@fluentui/react-icons'; import { AddCircle20Regular, DataUsageSettings20Regular, Delete20Regular, Save20Regular } from '@fluentui/react-icons';
import React, {FC} from 'react'; import React, { FC } from 'react';
import {Section} from '../components/Section'; import { Section } from '../components/Section';
import {Labeled} from '../components/Labeled'; import { Labeled } from '../components/Labeled';
import {ToolTipButton} from '../components/ToolTipButton'; import { ToolTipButton } from '../components/ToolTipButton';
import commonStore from '../stores/commonStore'; import commonStore from '../stores/commonStore';
import {observer} from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import {toast} from 'react-toastify'; import { toast } from 'react-toastify';
import {ValuedSlider} from '../components/ValuedSlider'; import { ValuedSlider } from '../components/ValuedSlider';
import {NumberInput} from '../components/NumberInput'; import { NumberInput } from '../components/NumberInput';
import {Page} from '../components/Page'; import { Page } from '../components/Page';
import {useNavigate} from 'react-router'; import { useNavigate } from 'react-router';
import {RunButton} from '../components/RunButton'; import { RunButton } from '../components/RunButton';
import {updateConfig} from '../apis'; import { updateConfig } from '../apis';
import {ConvertModel, FileExists} from '../../wailsjs/go/backend_golang/App'; import { ConvertModel, FileExists } from '../../wailsjs/go/backend_golang/App';
import manifest from '../../../manifest.json'; import manifest from '../../../manifest.json';
import {getStrategy, refreshLocalModels} from '../utils'; import { getStrategy, refreshLocalModels } from '../utils';
import {useTranslation} from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { WindowShow } from '../../wailsjs/runtime/runtime';
export type ApiParameters = { export type ApiParameters = {
apiPort: number apiPort: number
@ -70,7 +71,7 @@ export const defaultModelConfigs: ModelConfig[] = [
]; ];
export const Configs: FC = observer(() => { export const Configs: FC = observer(() => {
const {t} = useTranslation(); const { t } = useTranslation();
const [selectedIndex, setSelectedIndex] = React.useState(commonStore.currentModelConfigIndex); const [selectedIndex, setSelectedIndex] = React.useState(commonStore.currentModelConfigIndex);
const [selectedConfig, setSelectedConfig] = React.useState(commonStore.modelConfigs[selectedIndex]); const [selectedConfig, setSelectedConfig] = React.useState(commonStore.modelConfigs[selectedIndex]);
const navigate = useNavigate(); const navigate = useNavigate();
@ -85,7 +86,7 @@ export const Configs: FC = observer(() => {
}; };
const setSelectedConfigName = (newName: string) => { const setSelectedConfigName = (newName: string) => {
setSelectedConfig({...selectedConfig, name: newName}); setSelectedConfig({ ...selectedConfig, name: newName });
}; };
const setSelectedConfigApiParams = (newParams: Partial<ApiParameters>) => { const setSelectedConfigApiParams = (newParams: Partial<ApiParameters>) => {
@ -115,14 +116,14 @@ export const Configs: FC = observer(() => {
presence_penalty: selectedConfig.apiParameters.presencePenalty, presence_penalty: selectedConfig.apiParameters.presencePenalty,
frequency_penalty: selectedConfig.apiParameters.frequencyPenalty frequency_penalty: selectedConfig.apiParameters.frequencyPenalty
}); });
toast(t('Config Saved'), {autoClose: 300, type: 'success'}); toast(t('Config Saved'), { autoClose: 300, type: 'success' });
}; };
return ( return (
<Page title={t('Configs')} content={ <Page title={t('Configs')} content={
<div className="flex flex-col gap-2 overflow-hidden"> <div className="flex flex-col gap-2 overflow-hidden">
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">
<Dropdown style={{minWidth: 0}} className="grow" value={commonStore.modelConfigs[selectedIndex].name} <Dropdown style={{ minWidth: 0 }} className="grow" value={commonStore.modelConfigs[selectedIndex].name}
selectedOptions={[selectedIndex.toString()]} selectedOptions={[selectedIndex.toString()]}
onOptionSelect={(_, data) => { onOptionSelect={(_, data) => {
if (data.optionValue) { if (data.optionValue) {
@ -133,21 +134,21 @@ export const Configs: FC = observer(() => {
<Option key={index} value={index.toString()}>{config.name}</Option> <Option key={index} value={index.toString()}>{config.name}</Option>
)} )}
</Dropdown> </Dropdown>
<ToolTipButton desc={t('New Config')} icon={<AddCircle20Regular/>} onClick={() => { <ToolTipButton desc={t('New Config')} icon={<AddCircle20Regular />} onClick={() => {
commonStore.createModelConfig(); commonStore.createModelConfig();
updateSelectedIndex(commonStore.modelConfigs.length - 1); updateSelectedIndex(commonStore.modelConfigs.length - 1);
}}/> }} />
<ToolTipButton desc={t('Delete Config')} icon={<Delete20Regular/>} onClick={() => { <ToolTipButton desc={t('Delete Config')} icon={<Delete20Regular />} onClick={() => {
commonStore.deleteModelConfig(selectedIndex); commonStore.deleteModelConfig(selectedIndex);
updateSelectedIndex(Math.min(selectedIndex, commonStore.modelConfigs.length - 1)); updateSelectedIndex(Math.min(selectedIndex, commonStore.modelConfigs.length - 1));
}}/> }} />
<ToolTipButton desc={t('Save Config')} icon={<Save20Regular/>} onClick={onClickSave}/> <ToolTipButton desc={t('Save Config')} icon={<Save20Regular />} onClick={onClickSave} />
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<Label>{t('Config Name')}</Label> <Label>{t('Config Name')}</Label>
<Input className="grow" value={selectedConfig.name} onChange={(e, data) => { <Input className="grow" value={selectedConfig.name} onChange={(e, data) => {
setSelectedConfigName(data.value); setSelectedConfigName(data.value);
}}/> }} />
</div> </div>
<div className="flex flex-col gap-2 overflow-y-hidden"> <div className="flex flex-col gap-2 overflow-y-hidden">
<Section <Section
@ -164,8 +165,8 @@ export const Configs: FC = observer(() => {
setSelectedConfigApiParams({ setSelectedConfigApiParams({
apiPort: data.value apiPort: data.value
}); });
}}/> }} />
}/> } />
<Labeled label={t('Max Response Token *')} <Labeled label={t('Max Response Token *')}
desc={t('By default, the maximum number of tokens that can be answered in a single response, it can be changed by the user by specifying API parameters.')} desc={t('By default, the maximum number of tokens that can be answered in a single response, it can be changed by the user by specifying API parameters.')}
content={ content={
@ -176,8 +177,8 @@ export const Configs: FC = observer(() => {
setSelectedConfigApiParams({ setSelectedConfigApiParams({
maxResponseToken: data.value maxResponseToken: data.value
}); });
}}/> }} />
}/> } />
<Labeled label={t('Temperature *')} <Labeled label={t('Temperature *')}
desc={t('Sampling temperature, the higher the stronger the randomness and creativity, while the lower, the more focused and deterministic it will be.')} desc={t('Sampling temperature, the higher the stronger the randomness and creativity, while the lower, the more focused and deterministic it will be.')}
content={ content={
@ -187,8 +188,8 @@ export const Configs: FC = observer(() => {
setSelectedConfigApiParams({ setSelectedConfigApiParams({
temperature: data.value temperature: data.value
}); });
}}/> }} />
}/> } />
<Labeled label={t('Top_P *')} <Labeled label={t('Top_P *')}
desc={t('Consider the results of the top n% probability mass, 0.1 considers the top 10%, with higher quality but more conservative, 1 considers all results, with lower quality but more diverse.')} desc={t('Consider the results of the top n% probability mass, 0.1 considers the top 10%, with higher quality but more conservative, 1 considers all results, with lower quality but more diverse.')}
content={ content={
@ -197,8 +198,8 @@ export const Configs: FC = observer(() => {
setSelectedConfigApiParams({ setSelectedConfigApiParams({
topP: data.value topP: data.value
}); });
}}/> }} />
}/> } />
<Labeled label={t('Presence Penalty *')} <Labeled label={t('Presence Penalty *')}
desc={t('Positive values penalize new tokens based on whether they appear in the text so far, increasing the model\'s likelihood to talk about new topics.')} desc={t('Positive values penalize new tokens based on whether they appear in the text so far, increasing the model\'s likelihood to talk about new topics.')}
content={ content={
@ -208,8 +209,8 @@ export const Configs: FC = observer(() => {
setSelectedConfigApiParams({ setSelectedConfigApiParams({
presencePenalty: data.value presencePenalty: data.value
}); });
}}/> }} />
}/> } />
<Labeled label={t('Frequency Penalty *')} <Labeled label={t('Frequency Penalty *')}
desc={t('Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model\'s likelihood to repeat the same line verbatim.')} desc={t('Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model\'s likelihood to repeat the same line verbatim.')}
content={ content={
@ -219,8 +220,8 @@ export const Configs: FC = observer(() => {
setSelectedConfigApiParams({ setSelectedConfigApiParams({
frequencyPenalty: data.value frequencyPenalty: data.value
}); });
}}/> }} />
}/> } />
</div> </div>
} }
/> />
@ -230,7 +231,7 @@ export const Configs: FC = observer(() => {
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
<Labeled label={t('Model')} content={ <Labeled label={t('Model')} content={
<div className="flex gap-2 grow"> <div className="flex gap-2 grow">
<Select style={{minWidth: 0}} className="grow" <Select style={{ minWidth: 0 }} className="grow"
value={selectedConfig.modelParameters.modelName} value={selectedConfig.modelParameters.modelName}
onChange={(e, data) => { onChange={(e, data) => {
setSelectedConfigModelParams({ setSelectedConfigModelParams({
@ -241,29 +242,30 @@ export const Configs: FC = observer(() => {
modelItem.isLocal && <option key={index} value={modelItem.name}>{modelItem.name}</option> modelItem.isLocal && <option key={index} value={modelItem.name}>{modelItem.name}</option>
)} )}
</Select> </Select>
<ToolTipButton desc={t('Manage Models')} icon={<DataUsageSettings20Regular/>} onClick={() => { <ToolTipButton desc={t('Manage Models')} icon={<DataUsageSettings20Regular />} onClick={() => {
navigate({pathname: '/models'}); navigate({ pathname: '/models' });
}}/> }} />
</div> </div>
}/> } />
<ToolTipButton text={t('Convert')} desc={t('Convert model with these configs')} onClick={async () => { <ToolTipButton text={t('Convert')} desc={t('Convert model with these configs')} onClick={async () => {
const modelPath = `${manifest.localModelDir}/${selectedConfig.modelParameters.modelName}`; const modelPath = `${manifest.localModelDir}/${selectedConfig.modelParameters.modelName}`;
if (await FileExists(modelPath)) { if (await FileExists(modelPath)) {
const strategy = getStrategy(selectedConfig); const strategy = getStrategy(selectedConfig);
const newModelPath = modelPath + '-' + strategy.replace(/[> *+]/g, '-'); const newModelPath = modelPath + '-' + strategy.replace(/[> *+]/g, '-');
toast(t('Start Converting'), {autoClose: 1000, type: 'info'}); toast(t('Start Converting'), { autoClose: 1000, type: 'info' });
ConvertModel(modelPath, strategy, newModelPath).then(() => { ConvertModel(modelPath, strategy, newModelPath).then(() => {
toast(`${t('Convert Success')} - ${newModelPath}`, {type: 'success'}); toast(`${t('Convert Success')} - ${newModelPath}`, { type: 'success' });
refreshLocalModels({models: commonStore.modelSourceList}, false); refreshLocalModels({ models: commonStore.modelSourceList }, false);
}).catch(e => { }).catch(e => {
toast(`${t('Convert Failed')} - ${e.message || e}`, {type: 'error'}); toast(`${t('Convert Failed')} - ${e.message || e}`, { type: 'error' });
}); });
setTimeout(WindowShow, 1000)
} else { } else {
toast(`${t('Model Not Found')} - ${modelPath}`, {type: 'error'}); toast(`${t('Model Not Found')} - ${modelPath}`, { type: 'error' });
} }
}}/> }} />
<Labeled label={t('Device')} content={ <Labeled label={t('Device')} content={
<Dropdown style={{minWidth: 0}} className="grow" value={selectedConfig.modelParameters.device} <Dropdown style={{ minWidth: 0 }} className="grow" value={selectedConfig.modelParameters.device}
selectedOptions={[selectedConfig.modelParameters.device]} selectedOptions={[selectedConfig.modelParameters.device]}
onOptionSelect={(_, data) => { onOptionSelect={(_, data) => {
if (data.optionText) { if (data.optionText) {
@ -275,11 +277,11 @@ export const Configs: FC = observer(() => {
<Option>CPU</Option> <Option>CPU</Option>
<Option>CUDA</Option> <Option>CUDA</Option>
</Dropdown> </Dropdown>
}/> } />
<Labeled label={t('Precision')} <Labeled label={t('Precision')}
desc={t('int8 uses less VRAM, and is faster, but has slightly lower quality. fp16 has higher quality, and fp32 has the best quality.')} desc={t('int8 uses less VRAM, and is faster, but has slightly lower quality. fp16 has higher quality, and fp32 has the best quality.')}
content={ content={
<Dropdown style={{minWidth: 0}} className="grow" <Dropdown style={{ minWidth: 0 }} className="grow"
value={selectedConfig.modelParameters.precision} value={selectedConfig.modelParameters.precision}
selectedOptions={[selectedConfig.modelParameters.precision]} selectedOptions={[selectedConfig.modelParameters.precision]}
onOptionSelect={(_, data) => { onOptionSelect={(_, data) => {
@ -293,7 +295,7 @@ export const Configs: FC = observer(() => {
<Option>int8</Option> <Option>int8</Option>
<Option>fp32</Option> <Option>fp32</Option>
</Dropdown> </Dropdown>
}/> } />
<Labeled label={t('Stored Layers')} <Labeled label={t('Stored Layers')}
desc={t('Number of the neural network layers loaded into VRAM, the more you load, the faster the speed, but it consumes more VRAM.')} desc={t('Number of the neural network layers loaded into VRAM, the more you load, the faster the speed, but it consumes more VRAM.')}
content={ content={
@ -303,8 +305,8 @@ export const Configs: FC = observer(() => {
setSelectedConfigModelParams({ setSelectedConfigModelParams({
storedLayers: data.value storedLayers: data.value
}); });
}}/> }} />
}/> } />
<Labeled label={t('Enable High Precision For Last Layer')} <Labeled label={t('Enable High Precision For Last Layer')}
desc={t('Whether to use CPU to calculate the last output layer of the neural network with FP32 precision to obtain better quality.')} desc={t('Whether to use CPU to calculate the last output layer of the neural network with FP32 precision to obtain better quality.')}
content={ content={
@ -313,16 +315,16 @@ export const Configs: FC = observer(() => {
setSelectedConfigModelParams({ setSelectedConfigModelParams({
enableHighPrecisionForLastLayer: data.checked enableHighPrecisionForLastLayer: data.checked
}); });
}}/> }} />
}/> } />
</div> </div>
} }
/> />
</div> </div>
<div className="flex flex-row-reverse sm:fixed bottom-2 right-2"> <div className="flex flex-row-reverse sm:fixed bottom-2 right-2">
<RunButton onClickRun={onClickSave}/> <RunButton onClickRun={onClickSave} />
</div> </div>
</div> </div>
}/> } />
); );
}); });