improve details
This commit is contained in:
parent
d4d71898ed
commit
c02ce51d86
@ -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": "模型配置异常"
|
||||||
}
|
}
|
@ -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,141 +21,157 @@ 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 }>
|
||||||
= observer(({
|
= observer(({
|
||||||
onClickRun,
|
onClickRun,
|
||||||
iconMode
|
iconMode
|
||||||
}) => {
|
}) => {
|
||||||
const {t} = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const onClickMainButton = async () => {
|
const onClickMainButton = async () => {
|
||||||
const modelConfig = commonStore.getCurrentModelConfig();
|
if (commonStore.modelStatus === ModelStatus.Offline) {
|
||||||
const modelName = modelConfig.modelParameters.modelName;
|
commonStore.setModelStatus(ModelStatus.Starting);
|
||||||
const modelPath = `./${manifest.localModelDir}/${modelName}`;
|
|
||||||
|
|
||||||
if (!commonStore.depComplete) {
|
const modelConfig = commonStore.getCurrentModelConfig();
|
||||||
let depErrorMsg = '';
|
let modelName = ''
|
||||||
await DepCheck().catch((e) => {
|
let modelPath = ''
|
||||||
depErrorMsg = e.message || e;
|
if (modelConfig && modelConfig.modelParameters) {
|
||||||
if (depErrorMsg === 'python zip not found') {
|
modelName = modelConfig.modelParameters.modelName;
|
||||||
toastWithButton(t('Python target not found, would you like to download it?'), t('Download'), () => {
|
modelPath = `./${manifest.localModelDir}/${modelName}`;
|
||||||
toastWithButton(`${t('Downloading')} Python`, t('Check'), () => {
|
|
||||||
navigate({pathname: '/downloads'});
|
|
||||||
}, {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');
|
|
||||||
});
|
|
||||||
} else if (depErrorMsg.includes('DepCheck Error')) {
|
|
||||||
toastWithButton(t('Python dependencies are incomplete, would you like to install them?'), t('Install'), () => {
|
|
||||||
InstallPyDep(commonStore.settings.cnMirror);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
toast(depErrorMsg, {type: 'error'});
|
toast(t('Model Config Exception'), { type: 'error' });
|
||||||
|
commonStore.setModelStatus(ModelStatus.Offline);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if (depErrorMsg) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
commonStore.setDepComplete(true);
|
|
||||||
saveCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!await FileExists(modelPath)) {
|
if (!commonStore.depComplete) {
|
||||||
toastWithButton(t('Model file not found'), t('Download'), () => {
|
let depErrorMsg = '';
|
||||||
const downloadUrl = commonStore.modelSourceList.find(item => item.name === modelName)?.downloadUrl;
|
await DepCheck().catch((e) => {
|
||||||
if (downloadUrl) {
|
depErrorMsg = e.message || e;
|
||||||
toastWithButton(`${t('Downloading')} ${modelName}`, t('Check'), () => {
|
WindowShow();
|
||||||
navigate({pathname: '/downloads'});
|
if (depErrorMsg === 'python zip not found') {
|
||||||
},
|
toastWithButton(t('Python target not found, would you like to download it?'), t('Download'), () => {
|
||||||
{autoClose: 3000});
|
toastWithButton(`${t('Downloading')} Python`, t('Check'), () => {
|
||||||
AddToDownloadList(modelPath, downloadUrl);
|
navigate({ pathname: '/downloads' });
|
||||||
} else {
|
}, { autoClose: 3000 });
|
||||||
toast(t('Can not find download url'), {type: 'error'});
|
AddToDownloadList('python-3.10.11-embed-amd64.zip', 'https://www.python.org/ftp/python/3.10.11/python-3.10.11-embed-amd64.zip');
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const port = modelConfig.apiParameters.apiPort;
|
|
||||||
|
|
||||||
if (commonStore.modelStatus === ModelStatus.Offline) {
|
|
||||||
commonStore.setModelStatus(ModelStatus.Starting);
|
|
||||||
await exit(1000).catch(() => {
|
|
||||||
});
|
|
||||||
StartServer(port);
|
|
||||||
|
|
||||||
let timeoutCount = 6;
|
|
||||||
let loading = false;
|
|
||||||
const intervalId = setInterval(() => {
|
|
||||||
readRoot()
|
|
||||||
.then(r => {
|
|
||||||
if (r.ok && !loading) {
|
|
||||||
clearInterval(intervalId);
|
|
||||||
commonStore.setModelStatus(ModelStatus.Loading);
|
|
||||||
loading = true;
|
|
||||||
toast(t('Loading Model'), {type: 'info'});
|
|
||||||
updateConfig({
|
|
||||||
max_tokens: modelConfig.apiParameters.maxResponseToken,
|
|
||||||
temperature: modelConfig.apiParameters.temperature,
|
|
||||||
top_p: modelConfig.apiParameters.topP,
|
|
||||||
presence_penalty: modelConfig.apiParameters.presencePenalty,
|
|
||||||
frequency_penalty: modelConfig.apiParameters.frequencyPenalty
|
|
||||||
});
|
});
|
||||||
switchModel({
|
} else if (depErrorMsg.includes('DepCheck Error')) {
|
||||||
model: `${manifest.localModelDir}/${modelConfig.modelParameters.modelName}`,
|
toastWithButton(t('Python dependencies are incomplete, would you like to install them?'), t('Install'), () => {
|
||||||
strategy: getStrategy(modelConfig)
|
InstallPyDep(commonStore.settings.cnMirror);
|
||||||
}).then((r) => {
|
setTimeout(WindowShow, 1000)
|
||||||
if (r.ok) {
|
|
||||||
commonStore.setModelStatus(ModelStatus.Working);
|
|
||||||
toast(t('Startup Completed'), {type: 'success'});
|
|
||||||
} else if (r.status === 304) {
|
|
||||||
toast(t('Loading Model'), {type: 'info'});
|
|
||||||
} else {
|
|
||||||
commonStore.setModelStatus(ModelStatus.Offline);
|
|
||||||
toast(t('Failed to switch model'), {type: 'error'});
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
commonStore.setModelStatus(ModelStatus.Offline);
|
|
||||||
toast(t('Failed to switch model'), {type: 'error'});
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
toast(depErrorMsg, { type: 'error' });
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
});
|
||||||
if (timeoutCount <= 0) {
|
if (depErrorMsg) {
|
||||||
clearInterval(intervalId);
|
|
||||||
commonStore.setModelStatus(ModelStatus.Offline);
|
commonStore.setModelStatus(ModelStatus.Offline);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
commonStore.setDepComplete(true);
|
||||||
|
saveCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await FileExists(modelPath)) {
|
||||||
|
toastWithButton(t('Model file not found'), t('Download'), () => {
|
||||||
|
const downloadUrl = commonStore.modelSourceList.find(item => item.name === modelName)?.downloadUrl;
|
||||||
|
if (downloadUrl) {
|
||||||
|
toastWithButton(`${t('Downloading')} ${modelName}`, t('Check'), () => {
|
||||||
|
navigate({ pathname: '/downloads' });
|
||||||
|
},
|
||||||
|
{ autoClose: 3000 });
|
||||||
|
AddToDownloadList(modelPath, downloadUrl);
|
||||||
|
} else {
|
||||||
|
toast(t('Can not find download url'), { type: 'error' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
commonStore.setModelStatus(ModelStatus.Offline);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const port = modelConfig.apiParameters.apiPort;
|
||||||
|
|
||||||
|
await exit(1000).catch(() => {
|
||||||
});
|
});
|
||||||
|
StartServer(port);
|
||||||
|
setTimeout(WindowShow, 1000)
|
||||||
|
|
||||||
timeoutCount--;
|
let timeoutCount = 6;
|
||||||
}, 1000);
|
let loading = false;
|
||||||
} else {
|
const intervalId = setInterval(() => {
|
||||||
commonStore.setModelStatus(ModelStatus.Offline);
|
readRoot()
|
||||||
exit();
|
.then(r => {
|
||||||
}
|
if (r.ok && !loading) {
|
||||||
};
|
clearInterval(intervalId);
|
||||||
|
commonStore.setModelStatus(ModelStatus.Loading);
|
||||||
|
loading = true;
|
||||||
|
toast(t('Loading Model'), { type: 'info' });
|
||||||
|
updateConfig({
|
||||||
|
max_tokens: modelConfig.apiParameters.maxResponseToken,
|
||||||
|
temperature: modelConfig.apiParameters.temperature,
|
||||||
|
top_p: modelConfig.apiParameters.topP,
|
||||||
|
presence_penalty: modelConfig.apiParameters.presencePenalty,
|
||||||
|
frequency_penalty: modelConfig.apiParameters.frequencyPenalty
|
||||||
|
});
|
||||||
|
switchModel({
|
||||||
|
model: `${manifest.localModelDir}/${modelConfig.modelParameters.modelName}`,
|
||||||
|
strategy: getStrategy(modelConfig)
|
||||||
|
}).then((r) => {
|
||||||
|
if (r.ok) {
|
||||||
|
commonStore.setModelStatus(ModelStatus.Working);
|
||||||
|
toastWithButton(t('Startup Completed'), t('Chat'), () => {
|
||||||
|
navigate({ pathname: '/chat' });
|
||||||
|
}, { type: 'success', autoClose: 3000 });
|
||||||
|
} else if (r.status === 304) {
|
||||||
|
toast(t('Loading Model'), { type: 'info' });
|
||||||
|
} else {
|
||||||
|
commonStore.setModelStatus(ModelStatus.Offline);
|
||||||
|
toast(t('Failed to switch model'), { type: 'error' });
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
commonStore.setModelStatus(ModelStatus.Offline);
|
||||||
|
toast(t('Failed to switch model'), { type: 'error' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
if (timeoutCount <= 0) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
commonStore.setModelStatus(ModelStatus.Offline);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const onClick = async (e: any) => {
|
timeoutCount--;
|
||||||
if (commonStore.modelStatus === ModelStatus.Offline)
|
}, 1000);
|
||||||
await onClickRun?.(e);
|
} else {
|
||||||
await onClickMainButton();
|
commonStore.setModelStatus(ModelStatus.Offline);
|
||||||
};
|
exit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (iconMode ?
|
const onClick = async (e: any) => {
|
||||||
|
if (commonStore.modelStatus === ModelStatus.Offline)
|
||||||
|
await onClickRun?.(e);
|
||||||
|
await onClickMainButton();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (iconMode ?
|
||||||
<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>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -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,39 +116,39 @@ 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) {
|
||||||
updateSelectedIndex(Number(data.optionValue));
|
updateSelectedIndex(Number(data.optionValue));
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
{commonStore.modelConfigs.map((config, index) =>
|
{commonStore.modelConfigs.map((config, index) =>
|
||||||
<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
|
||||||
@ -156,71 +157,71 @@ export const Configs: FC = observer(() => {
|
|||||||
content={
|
content={
|
||||||
<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('API Port')}
|
<Labeled label={t('API Port')}
|
||||||
desc={t('Open the following URL with your browser to view the API documentation') + `: http://127.0.0.1:${port}/docs. ` +
|
desc={t('Open the following URL with your browser to view the API documentation') + `: http://127.0.0.1:${port}/docs. ` +
|
||||||
t('This tool’s API is compatible with OpenAI API. It can be used with any ChatGPT tool you like. Go to the settings of some ChatGPT tool, replace the \'https://api.openai.com\' part in the API address with \'') + `http://127.0.0.1:${port}` + '\'.'}
|
t('This tool’s API is compatible with OpenAI API. It can be used with any ChatGPT tool you like. Go to the settings of some ChatGPT tool, replace the \'https://api.openai.com\' part in the API address with \'') + `http://127.0.0.1:${port}` + '\'.'}
|
||||||
content={
|
content={
|
||||||
<NumberInput value={port} min={1} max={65535} step={1}
|
<NumberInput value={port} min={1} max={65535} step={1}
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
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={
|
||||||
<ValuedSlider value={selectedConfig.apiParameters.maxResponseToken} min={100} max={8100}
|
<ValuedSlider value={selectedConfig.apiParameters.maxResponseToken} min={100} max={8100}
|
||||||
step={400}
|
step={400}
|
||||||
input
|
input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
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={
|
||||||
<ValuedSlider value={selectedConfig.apiParameters.temperature} min={0} max={2} step={0.1}
|
<ValuedSlider value={selectedConfig.apiParameters.temperature} min={0} max={2} step={0.1}
|
||||||
input
|
input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
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={
|
||||||
<ValuedSlider value={selectedConfig.apiParameters.topP} min={0} max={1} step={0.1} input
|
<ValuedSlider value={selectedConfig.apiParameters.topP} min={0} max={1} step={0.1} input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
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={
|
||||||
<ValuedSlider value={selectedConfig.apiParameters.presencePenalty} min={-2} max={2}
|
<ValuedSlider value={selectedConfig.apiParameters.presencePenalty} min={-2} max={2}
|
||||||
step={0.1} input
|
step={0.1} input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
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={
|
||||||
<ValuedSlider value={selectedConfig.apiParameters.frequencyPenalty} min={-2} max={2}
|
<ValuedSlider value={selectedConfig.apiParameters.frequencyPenalty} min={-2} max={2}
|
||||||
step={0.1} input
|
step={0.1} input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
setSelectedConfigApiParams({
|
setSelectedConfigApiParams({
|
||||||
frequencyPenalty: data.value
|
frequencyPenalty: data.value
|
||||||
});
|
});
|
||||||
}}/>
|
}} />
|
||||||
}/>
|
} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -230,99 +231,100 @@ 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({
|
||||||
modelName: data.value
|
modelName: data.value
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
{commonStore.modelSourceList.map((modelItem, index) =>
|
{commonStore.modelSourceList.map((modelItem, index) =>
|
||||||
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) {
|
||||||
setSelectedConfigModelParams({
|
setSelectedConfigModelParams({
|
||||||
device: data.optionText as Device
|
device: data.optionText as Device
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<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) => {
|
||||||
if (data.optionText) {
|
if (data.optionText) {
|
||||||
setSelectedConfigModelParams({
|
setSelectedConfigModelParams({
|
||||||
precision: data.optionText as Precision
|
precision: data.optionText as Precision
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<Option>fp16</Option>
|
<Option>fp16</Option>
|
||||||
<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={
|
||||||
<ValuedSlider value={selectedConfig.modelParameters.storedLayers} min={0}
|
<ValuedSlider value={selectedConfig.modelParameters.storedLayers} min={0}
|
||||||
max={selectedConfig.modelParameters.maxStoredLayers} step={1} input
|
max={selectedConfig.modelParameters.maxStoredLayers} step={1} input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
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={
|
||||||
<Switch checked={selectedConfig.modelParameters.enableHighPrecisionForLastLayer}
|
<Switch checked={selectedConfig.modelParameters.enableHighPrecisionForLastLayer}
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
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>
|
||||||
}/>
|
} />
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user