This commit is contained in:
josc146
2023-05-18 20:48:53 +08:00
parent 75075d6483
commit 5078a884b0
13 changed files with 252 additions and 59 deletions

View File

@@ -1,10 +1,13 @@
import React, {FC} from 'react';
import {Text} from '@fluentui/react-components';
import {useTranslation} from 'react-i18next';
export const About: FC = () => {
const {t} = useTranslation();
return (
<div className="flex flex-col box-border gap-5 p-2">
<Text size={600}>In Development</Text>
<Text size={600}>{t('In Development')}</Text>
</div>
);
};

View File

@@ -1,10 +1,13 @@
import React, {FC} from 'react';
import {Page} from '../components/Page';
import {PresenceBadge} from '@fluentui/react-components';
import {useTranslation} from 'react-i18next';
export const Chat: FC = () => {
const {t} = useTranslation();
return (
<Page title="Chat" content={
<Page title={t('Chat')} content={
<div className="flex flex-col gap-2 overflow-hidden">
<PresenceBadge/>
</div>

View File

@@ -16,8 +16,10 @@ import {updateConfig} from '../apis';
import {ConvertModel} from '../../wailsjs/go/backend_golang/App';
import manifest from '../../../manifest.json';
import {getStrategy, refreshLocalModels} from '../utils';
import {useTranslation} from 'react-i18next';
export const Configs: FC = observer(() => {
const {t} = useTranslation();
const [selectedIndex, setSelectedIndex] = React.useState(commonStore.currentModelConfigIndex);
const [selectedConfig, setSelectedConfig] = React.useState(commonStore.modelConfigs[selectedIndex]);
@@ -66,7 +68,7 @@ export const Configs: FC = observer(() => {
};
return (
<Page title="Configs" content={
<Page title={t('Configs')} content={
<div className="flex flex-col gap-2 overflow-hidden">
<div className="flex gap-2 items-center">
<Dropdown style={{minWidth: 0}} className="grow" value={commonStore.modelConfigs[selectedIndex].name}
@@ -80,29 +82,29 @@ export const Configs: FC = observer(() => {
<Option key={index} value={index.toString()}>{config.name}</Option>
)}
</Dropdown>
<ToolTipButton desc="New Config" icon={<AddCircle20Regular/>} onClick={() => {
<ToolTipButton desc={t('New Config')} icon={<AddCircle20Regular/>} onClick={() => {
commonStore.createModelConfig();
updateSelectedIndex(commonStore.modelConfigs.length - 1);
}}/>
<ToolTipButton desc="Delete Config" icon={<Delete20Regular/>} onClick={() => {
<ToolTipButton desc={t('Delete Config')} icon={<Delete20Regular/>} onClick={() => {
commonStore.deleteModelConfig(selectedIndex);
updateSelectedIndex(Math.min(selectedIndex, commonStore.modelConfigs.length - 1));
}}/>
<ToolTipButton desc="Save Config" icon={<Save20Regular/>} onClick={onClickSave}/>
<ToolTipButton desc={t('Save Config')} icon={<Save20Regular/>} onClick={onClickSave}/>
</div>
<div className="flex items-center gap-4">
<Label>Config Name</Label>
<Label>{t('Config Name')}</Label>
<Input className="grow" value={selectedConfig.name} onChange={(e, data) => {
setSelectedConfigName(data.value);
}}/>
</div>
<div className="flex flex-col gap-2 overflow-y-hidden">
<Section
title="Default API Parameters"
desc="Hover your mouse over the text to view a detailed description. Settings marked with * will take effect immediately after being saved."
title={t('Default API Parameters')}
desc={t('Hover your mouse over the text to view a detailed description. Settings marked with * will take effect immediately after being saved.')}
content={
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
<Labeled label="API Port" desc={`127.0.0.1:${selectedConfig.apiParameters.apiPort}`} content={
<Labeled label={t('API Port')} desc={`127.0.0.1:${selectedConfig.apiParameters.apiPort}`} content={
<NumberInput value={selectedConfig.apiParameters.apiPort} min={1} max={65535} step={1}
onChange={(e, data) => {
setSelectedConfigApiParams({
@@ -110,7 +112,7 @@ export const Configs: FC = observer(() => {
});
}}/>
}/>
<Labeled label="Max Response Token *" content={
<Labeled label={t('Max Response Token *')} content={
<ValuedSlider value={selectedConfig.apiParameters.maxResponseToken} min={100} max={8100} step={400}
input
onChange={(e, data) => {
@@ -119,7 +121,7 @@ export const Configs: FC = observer(() => {
});
}}/>
}/>
<Labeled label="Temperature *" content={
<Labeled label={t('Temperature *')} content={
<ValuedSlider value={selectedConfig.apiParameters.temperature} min={0} max={2} step={0.1} input
onChange={(e, data) => {
setSelectedConfigApiParams({
@@ -127,7 +129,7 @@ export const Configs: FC = observer(() => {
});
}}/>
}/>
<Labeled label="Top_P *" content={
<Labeled label={t('Top_P *')} content={
<ValuedSlider value={selectedConfig.apiParameters.topP} min={0} max={1} step={0.1} input
onChange={(e, data) => {
setSelectedConfigApiParams({
@@ -135,7 +137,7 @@ export const Configs: FC = observer(() => {
});
}}/>
}/>
<Labeled label="Presence Penalty *" content={
<Labeled label={t('Presence Penalty *')} content={
<ValuedSlider value={selectedConfig.apiParameters.presencePenalty} min={-2} max={2} step={0.1} input
onChange={(e, data) => {
setSelectedConfigApiParams({
@@ -143,7 +145,7 @@ export const Configs: FC = observer(() => {
});
}}/>
}/>
<Labeled label="Frequency Penalty *" content={
<Labeled label={t('Frequency Penalty *')} content={
<ValuedSlider value={selectedConfig.apiParameters.frequencyPenalty} min={-2} max={2} step={0.1} input
onChange={(e, data) => {
setSelectedConfigApiParams({
@@ -155,10 +157,10 @@ export const Configs: FC = observer(() => {
}
/>
<Section
title="Model Parameters"
title={t('Model Parameters')}
content={
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
<Labeled label="Model" content={
<Labeled label={t('Model')} content={
<div className="flex gap-2 grow">
<Select style={{minWidth: 0}} className="grow"
value={selectedConfig.modelParameters.modelName}
@@ -171,12 +173,12 @@ export const Configs: FC = observer(() => {
modelItem.isLocal && <option key={index} value={modelItem.name}>{modelItem.name}</option>
)}
</Select>
<ToolTipButton desc="Manage Models" icon={<DataUsageSettings20Regular/>} onClick={() => {
<ToolTipButton desc={t('Manage Models')} icon={<DataUsageSettings20Regular/>} onClick={() => {
navigate({pathname: '/models'});
}}/>
</div>
}/>
<ToolTipButton text="Convert" desc="Convert model with these configs" onClick={() => {
<ToolTipButton text={t('Convert')} desc={t('Convert model with these configs')} onClick={() => {
const modelPath = `${manifest.localModelDir}/${selectedConfig.modelParameters.modelName}`;
const strategy = getStrategy(selectedConfig);
const newModelPath = modelPath + '-' + strategy.replace(/[> *+]/g, '-');
@@ -188,7 +190,7 @@ export const Configs: FC = observer(() => {
toast(`Convert Failed - ${e}`, {type: 'error'});
});
}}/>
<Labeled label="Device" content={
<Labeled label={t('Device')} content={
<Dropdown style={{minWidth: 0}} className="grow" value={selectedConfig.modelParameters.device}
selectedOptions={[selectedConfig.modelParameters.device]}
onOptionSelect={(_, data) => {
@@ -202,7 +204,7 @@ export const Configs: FC = observer(() => {
<Option>CUDA</Option>
</Dropdown>
}/>
<Labeled label="Precision" content={
<Labeled label={t('Precision')} content={
<Dropdown style={{minWidth: 0}} className="grow" value={selectedConfig.modelParameters.precision}
selectedOptions={[selectedConfig.modelParameters.precision]}
onOptionSelect={(_, data) => {
@@ -217,7 +219,7 @@ export const Configs: FC = observer(() => {
<Option>fp32</Option>
</Dropdown>
}/>
<Labeled label="Stored Layers" content={
<Labeled label={t('Stored Layers')} content={
<ValuedSlider value={selectedConfig.modelParameters.storedLayers} min={0}
max={selectedConfig.modelParameters.maxStoredLayers} step={1} input
onChange={(e, data) => {
@@ -226,7 +228,7 @@ export const Configs: FC = observer(() => {
});
}}/>
}/>
<Labeled label="Enable High Precision For Last Layer" content={
<Labeled label={t('Enable High Precision For Last Layer')} content={
<Switch checked={selectedConfig.modelParameters.enableHighPrecisionForLastLayer}
onChange={(e, data) => {
setSelectedConfigModelParams({

View File

@@ -13,6 +13,7 @@ import {observer} from 'mobx-react-lite';
import {RunButton} from '../components/RunButton';
import manifest from '../../../manifest.json';
import {BrowserOpenURL} from '../../wailsjs/runtime';
import {useTranslation} from 'react-i18next';
type NavCard = {
label: string;
@@ -49,6 +50,7 @@ const navCards: NavCard[] = [
];
export const Home: FC = observer(() => {
const {t} = useTranslation();
const navigate = useNavigate();
const onClickNavCard = (path: string) => {
@@ -59,22 +61,17 @@ export const Home: FC = observer(() => {
<div className="flex flex-col justify-between h-full">
<img className="rounded-xl select-none hidden sm:block" src={banner}/>
<div className="flex flex-col gap-2">
<Text size={600} weight="medium">Introduction</Text>
<Text size={600} weight="medium">{t('Introduction')}</Text>
<div className="h-40 overflow-y-auto p-1">
RWKV is an RNN with Transformer-level LLM performance, which can also be directly trained like a GPT
transformer (parallelizable). And it's 100% attention-free. You only need the hidden state at position t to
compute the state at position t+1. You can use the "GPT" mode to quickly compute the hidden state for the
"RNN" mode.
<br/>
So it's combining the best of RNN and transformer - great performance, fast inference, saves VRAM, fast
training, "infinite" ctx_len, and free sentence embedding (using the final hidden state).
{t('RWKV is an RNN with Transformer-level LLM performance, which can also be directly trained like a GPT transformer (parallelizable). And it\'s 100% attention-free. You only need the hidden state at position t to compute the state at position t+1. You can use the "GPT" mode to quickly compute the hidden state for the "RNN" mode. <br/> So it\'s combining the best of RNN and transformer - great performance, fast inference, saves VRAM, fast training, "infinite" ctx_len, and free sentence embedding (using the final hidden state).')}
{/*TODO Markdown*/}
</div>
</div>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-5">
{navCards.map(({label, path, icon, desc}, index) => (
<CompoundButton icon={icon} secondaryContent={desc} key={`${path}-${index}`} value={path}
<CompoundButton icon={icon} secondaryContent={t(desc)} key={`${path}-${index}`} value={path}
size="large" onClick={() => onClickNavCard(path)}>
{label}
{t(label)}
</CompoundButton>
))}
</div>
@@ -96,8 +93,8 @@ export const Home: FC = observer(() => {
</div>
</div>
<div className="flex gap-4 items-end">
Version: {manifest.version}
<Link onClick={() => BrowserOpenURL('https://github.com/josStorer/RWKV-Runner')}>Help</Link>
{t('Version')}: {manifest.version}
<Link onClick={() => BrowserOpenURL('https://github.com/josStorer/RWKV-Runner')}>{t('Help')}</Link>
</div>
</div>
</div>

View File

@@ -22,6 +22,7 @@ import manifest from '../../../manifest.json';
import {toast} from 'react-toastify';
import {Page} from '../components/Page';
import {refreshModels, saveConfigs} from '../utils';
import {useTranslation} from 'react-i18next';
const columns: TableColumnDefinition<ModelSourceItem>[] = [
createTableColumn<ModelSourceItem>({
@@ -30,7 +31,9 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
return a.name.localeCompare(b.name);
},
renderHeaderCell: () => {
return 'File';
const {t} = useTranslation();
return t('File');
},
renderCell: (item) => {
return (
@@ -49,12 +52,18 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
return 0;
},
renderHeaderCell: () => {
return 'Desc';
const {t} = useTranslation();
return t('Desc');
},
renderCell: (item) => {
const lang: string = commonStore.settings.language;
return (
<TableCellLayout>
{item.desc && item.desc['en']}
{item.desc &&
(lang in item.desc ? item.desc[lang] :
('en' in item.desc && item.desc['en']))}
</TableCellLayout>
);
}
@@ -65,7 +74,9 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
return a.size - b.size;
},
renderHeaderCell: () => {
return 'Size';
const {t} = useTranslation();
return t('Size');
},
renderCell: (item) => {
return (
@@ -85,7 +96,9 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
return b.lastUpdatedMs - a.lastUpdatedMs;
},
renderHeaderCell: () => {
return 'Last updated';
const {t} = useTranslation();
return t('Last updated');
},
renderCell: (item) => {
@@ -98,24 +111,28 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
return a.isDownloading ? 0 : a.isLocal ? -1 : 1;
},
renderHeaderCell: () => {
return 'Actions';
const {t} = useTranslation();
return t('Actions');
},
renderCell: (item) => {
const {t} = useTranslation();
return (
<TableCellLayout>
<div className="flex gap-1">
{
item.isLocal &&
<ToolTipButton desc="Open Folder" icon={<Folder20Regular/>} onClick={() => {
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular/>} onClick={() => {
OpenFileFolder(`./${manifest.localModelDir}/${item.name}`);
}}/>
}
{item.downloadUrl && !item.isLocal &&
<ToolTipButton desc="Download" icon={<ArrowDownload20Regular/>} onClick={() => {
<ToolTipButton desc={t('Download')} icon={<ArrowDownload20Regular/>} onClick={() => {
toast(`Downloading ${item.name}`);
DownloadFile(`./${manifest.localModelDir}/${item.name}`, item.downloadUrl!);
}}/>}
{item.url && <ToolTipButton desc="Open Url" icon={<Open20Regular/>} onClick={() => {
{item.url && <ToolTipButton desc={t('Open Url')} icon={<Open20Regular/>} onClick={() => {
BrowserOpenURL(item.url!);
}}/>}
</div>
@@ -126,20 +143,21 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
];
export const Models: FC = observer(() => {
const {t} = useTranslation();
return (
<Page title="Models" content={
<Page title={t('Models')} content={
<div className="flex flex-col gap-2 overflow-hidden">
<div className="flex flex-col gap-1">
<div className="flex justify-between">
<Text weight="medium">Model Source Manifest List</Text>
<ToolTipButton desc="Refresh" icon={<ArrowClockwise20Regular/>} onClick={() => {
<Text weight="medium">{t('Model Source Manifest List')}</Text>
<ToolTipButton desc={t('Refresh')} icon={<ArrowClockwise20Regular/>} onClick={() => {
refreshModels(false);
saveConfigs();
}}/>
</div>
<Text size={100}>
Provide JSON file URLs for the models manifest. Separate URLs with semicolons. The "models"
field in JSON files will be parsed into the following table.
{t('Provide JSON file URLs for the models manifest. Separate URLs with semicolons. The "models" field in JSON files will be parsed into the following table.')}
</Text>
<Textarea size="large" resize="vertical"
value={commonStore.modelSourceManifestList}

View File

@@ -14,7 +14,7 @@ export const Settings: FC = observer(() => {
return (
<Page title={t('Settings')} content={
<div className="flex flex-col gap-2 overflow-hidden">
<Labeled label="Language" flex spaceBetween content={
<Labeled label={t('Language')} flex spaceBetween content={
<Dropdown style={{minWidth: 0}} listbox={{style: {minWidth: 0}}}
value={Languages[commonStore.settings.language]}
selectedOptions={[Languages[commonStore.settings.language]]}
@@ -33,7 +33,7 @@ export const Settings: FC = observer(() => {
}
</Dropdown>
}/>
<Labeled label="Dark Mode" flex spaceBetween content={
<Labeled label={t('Dark Mode')} flex spaceBetween content={
<Switch checked={commonStore.settings.darkMode}
onChange={(e, data) => {
commonStore.setSettings({
@@ -41,7 +41,7 @@ export const Settings: FC = observer(() => {
});
}}/>
}/>
<Labeled label="Automatic Updates Check" flex spaceBetween content={
<Labeled label={t('Automatic Updates Check')} flex spaceBetween content={
<Switch checked={commonStore.settings.autoUpdatesCheck}
onChange={(e, data) => {
commonStore.setSettings({

View File

@@ -1,10 +1,13 @@
import React, {FC} from 'react';
import {Text} from '@fluentui/react-components';
import {useTranslation} from 'react-i18next';
export const Train: FC = () => {
const {t} = useTranslation();
return (
<div className="flex flex-col box-border gap-5 p-2">
<Text size={600}>In Development</Text>
<Text size={600}>{t('In Development')}</Text>
</div>
);
};