i18n
This commit is contained in:
parent
75075d6483
commit
5078a884b0
110
frontend/i18nally.json
Normal file
110
frontend/i18nally.json
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
{
|
||||||
|
"version": "1.2",
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"id": "e4cca065-e0f7-49ce-a400-75dfba1270eb",
|
||||||
|
"name": "Default",
|
||||||
|
"keyNamingPattern": "NATURAL_LANGUAGE_PATTERN",
|
||||||
|
"sink": {
|
||||||
|
"id": "93a27d2a-ff09-4608-ba13-0c08bc34c2dc",
|
||||||
|
"type": "singleFile",
|
||||||
|
"pathToFile": "$PROJECT_DIR$/frontend/src/_locales/zh-hans/main.json",
|
||||||
|
"fileType": "json",
|
||||||
|
"nestingType": "DISABLED",
|
||||||
|
"placeholderFormatterName": "I18NEXT"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"id": "efa45b89-aed3-4bc2-97d0-fa6147d13f8c",
|
||||||
|
"type": "jsx",
|
||||||
|
"scopeName": "Project Files",
|
||||||
|
"scopePattern": "",
|
||||||
|
"defaultReplacementTemplate": "t(\"%key%\")",
|
||||||
|
"attributeReplacementTemplate": "",
|
||||||
|
"inlineTagsReplacementTemplate": "",
|
||||||
|
"recognizedReplacementTemplates": [],
|
||||||
|
"inlineTagNames": [
|
||||||
|
"small",
|
||||||
|
"tt",
|
||||||
|
"big",
|
||||||
|
"sub",
|
||||||
|
"img",
|
||||||
|
"strong",
|
||||||
|
"code",
|
||||||
|
"data",
|
||||||
|
"samp",
|
||||||
|
"wbr",
|
||||||
|
"del",
|
||||||
|
"Page",
|
||||||
|
"slot",
|
||||||
|
"sup",
|
||||||
|
"br",
|
||||||
|
"output",
|
||||||
|
"abbr",
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"acronym",
|
||||||
|
"bdi",
|
||||||
|
"meter",
|
||||||
|
"var",
|
||||||
|
"em",
|
||||||
|
"i",
|
||||||
|
"label",
|
||||||
|
"bdo",
|
||||||
|
"kbd",
|
||||||
|
"dfn",
|
||||||
|
"ins",
|
||||||
|
"ruby",
|
||||||
|
"input",
|
||||||
|
"q",
|
||||||
|
"s",
|
||||||
|
"u",
|
||||||
|
"cite",
|
||||||
|
"progress",
|
||||||
|
"time",
|
||||||
|
"mark",
|
||||||
|
"span"
|
||||||
|
],
|
||||||
|
"translatableAttributeNames": [
|
||||||
|
"alt",
|
||||||
|
"placeholder",
|
||||||
|
"label",
|
||||||
|
"title",
|
||||||
|
"aria-label",
|
||||||
|
"desc",
|
||||||
|
"text"
|
||||||
|
],
|
||||||
|
"skipDefaultNamespace": false,
|
||||||
|
"inlineTagHandler": "NONE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ignores": {
|
||||||
|
"valuesInProject": [
|
||||||
|
"use strict"
|
||||||
|
],
|
||||||
|
"valuesInFile": {},
|
||||||
|
"filesInProject": [],
|
||||||
|
"unignoredFunctionNames": [],
|
||||||
|
"unignoredFunctionArguments": {},
|
||||||
|
"ignoredArrayKeys": [
|
||||||
|
"template",
|
||||||
|
"date",
|
||||||
|
"dateFormat",
|
||||||
|
"el",
|
||||||
|
"query",
|
||||||
|
"type",
|
||||||
|
"sql",
|
||||||
|
"layout",
|
||||||
|
"component",
|
||||||
|
"condition",
|
||||||
|
"name",
|
||||||
|
"selector",
|
||||||
|
"id",
|
||||||
|
"class",
|
||||||
|
"key",
|
||||||
|
"middleware"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -31,8 +31,10 @@ import {useMediaQuery} from 'usehooks-ts';
|
|||||||
import {ToastContainer} from 'react-toastify';
|
import {ToastContainer} from 'react-toastify';
|
||||||
import commonStore from './stores/commonStore';
|
import commonStore from './stores/commonStore';
|
||||||
import {observer} from 'mobx-react-lite';
|
import {observer} from 'mobx-react-lite';
|
||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
const App: FC = observer(() => {
|
const App: FC = observer(() => {
|
||||||
|
const {t} = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const mq = useMediaQuery('(min-width: 640px)');
|
const mq = useMediaQuery('(min-width: 640px)');
|
||||||
@ -57,7 +59,7 @@ const App: FC = observer(() => {
|
|||||||
>
|
>
|
||||||
{pages.filter(page => page.top).map(({label, path, icon}, index) => (
|
{pages.filter(page => page.top).map(({label, path, icon}, index) => (
|
||||||
<Tab icon={icon} key={`${path}-${index}`} value={path}>
|
<Tab icon={icon} key={`${path}-${index}`} value={path}>
|
||||||
{mq && label}
|
{mq && t(label)}
|
||||||
</Tab>
|
</Tab>
|
||||||
))}
|
))}
|
||||||
</TabList>
|
</TabList>
|
||||||
@ -70,7 +72,7 @@ const App: FC = observer(() => {
|
|||||||
>
|
>
|
||||||
{pages.filter(page => !page.top).map(({label, path, icon}, index) => (
|
{pages.filter(page => !page.top).map(({label, path, icon}, index) => (
|
||||||
<Tab icon={icon} key={`${path}-${index}`} value={path}>
|
<Tab icon={icon} key={`${path}-${index}`} value={path}>
|
||||||
{mq && label}
|
{mq && t(label)}
|
||||||
</Tab>
|
</Tab>
|
||||||
))}
|
))}
|
||||||
</TabList>
|
</TabList>
|
||||||
|
@ -1,3 +1,55 @@
|
|||||||
{
|
{
|
||||||
"Settings": "设置"
|
"Home": "主页",
|
||||||
|
"Train": "训练",
|
||||||
|
"About": "关于",
|
||||||
|
"Settings": "设置",
|
||||||
|
"Go to chat page": "前往聊天页",
|
||||||
|
"Manage your configs": "管理你的配置",
|
||||||
|
"Manage models": "管理模型",
|
||||||
|
"Run": "运行",
|
||||||
|
"Starting": "启动中",
|
||||||
|
"Loading": "读取模型中",
|
||||||
|
"Stop": "停止",
|
||||||
|
"Enable High Precision For Last Layer": "输出层使用高精度",
|
||||||
|
"Stored Layers": "载入显存层数",
|
||||||
|
"Precision": "精度",
|
||||||
|
"Device": "设备",
|
||||||
|
"Convert model with these configs": "用这些设置转换模型",
|
||||||
|
"Manage Models": "管理模型",
|
||||||
|
"Model": "模型",
|
||||||
|
"Model Parameters": "模型参数",
|
||||||
|
"Frequency Penalty *": "Frequency Penalty *",
|
||||||
|
"Presence Penalty *": "Presence Penalty *",
|
||||||
|
"Top_P *": "Top_P *",
|
||||||
|
"Temperature *": "Temperature *",
|
||||||
|
"Max Response Token *": "最大响应 Token *",
|
||||||
|
"API Port": "API 端口",
|
||||||
|
"Hover your mouse over the text to view a detailed description. Settings marked with * will take effect immediately after being saved.": "把鼠标悬停在文本上查看详细描述. 标记了星号 * 的设置在保存后会立即生效.",
|
||||||
|
"Default API Parameters": "默认 API 参数",
|
||||||
|
"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.": "填写模型描述的 JSON 文件地址. 地址间用分号分隔. JSON 文件内的 \"models\" 字段会被分析进下表.",
|
||||||
|
"Config Name": "配置名",
|
||||||
|
"Refresh": "刷新",
|
||||||
|
"Save Config": "保存配置",
|
||||||
|
"Model Source Manifest List": "模型源",
|
||||||
|
"Models": "模型",
|
||||||
|
"Delete Config": "删除配置",
|
||||||
|
"Help": "帮助",
|
||||||
|
"Version": "版本",
|
||||||
|
"New Config": "新建配置",
|
||||||
|
"Open Url": "打开网页",
|
||||||
|
"Download": "下载",
|
||||||
|
"Open Folder": "打开文件夹",
|
||||||
|
"Configs": "配置",
|
||||||
|
"Automatic Updates Check": "自动检查更新",
|
||||||
|
"Introduction": "介绍",
|
||||||
|
"Dark Mode": "深色模式",
|
||||||
|
"Language": "语言",
|
||||||
|
"In Development": "开发中",
|
||||||
|
"Chat": "聊天",
|
||||||
|
"Convert": "转换",
|
||||||
|
"Actions": "动作",
|
||||||
|
"Last updated": "上次更新",
|
||||||
|
"Desc": "描述",
|
||||||
|
"Size": "文件大小",
|
||||||
|
"File": "文件"
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ 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} from '../utils';
|
import {getStrategy} from '../utils';
|
||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
const mainButtonText = {
|
const mainButtonText = {
|
||||||
[ModelStatus.Offline]: 'Run',
|
[ModelStatus.Offline]: 'Run',
|
||||||
@ -70,6 +71,8 @@ const onClickMainButton = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const RunButton: FC<{ onClickRun?: MouseEventHandler }> = observer(({onClickRun}) => {
|
export const RunButton: FC<{ onClickRun?: MouseEventHandler }> = observer(({onClickRun}) => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button disabled={commonStore.modelStatus === ModelStatus.Starting} appearance="primary" size="large"
|
<Button disabled={commonStore.modelStatus === ModelStatus.Starting} appearance="primary" size="large"
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
@ -77,7 +80,7 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler }> = observer(({onCl
|
|||||||
await onClickRun?.(e);
|
await onClickRun?.(e);
|
||||||
await onClickMainButton();
|
await onClickMainButton();
|
||||||
}}>
|
}}>
|
||||||
{mainButtonText[commonStore.modelStatus]}
|
{t(mainButtonText[commonStore.modelStatus])}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@ import {FC, ReactElement} from 'react';
|
|||||||
import {Card, Text} from '@fluentui/react-components';
|
import {Card, Text} from '@fluentui/react-components';
|
||||||
|
|
||||||
export const Section: FC<{
|
export const Section: FC<{
|
||||||
title: string; desc?: string, content: ReactElement, outline?: boolean
|
title: string; desc?: string | null, content: ReactElement, outline?: boolean
|
||||||
}> =
|
}> =
|
||||||
({title, desc, content, outline = true}) => {
|
({title, desc, content, outline = true}) => {
|
||||||
return (
|
return (
|
||||||
|
@ -2,7 +2,7 @@ import React, {FC, MouseEventHandler, ReactElement} from 'react';
|
|||||||
import {Button, Tooltip} from '@fluentui/react-components';
|
import {Button, Tooltip} from '@fluentui/react-components';
|
||||||
|
|
||||||
export const ToolTipButton: FC<{
|
export const ToolTipButton: FC<{
|
||||||
text?: string, desc: string, icon?: ReactElement, onClick?: MouseEventHandler
|
text?: string | null, desc: string, icon?: ReactElement, onClick?: MouseEventHandler
|
||||||
}> = ({
|
}> = ({
|
||||||
text,
|
text,
|
||||||
desc,
|
desc,
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import React, {FC} from 'react';
|
import React, {FC} from 'react';
|
||||||
import {Text} from '@fluentui/react-components';
|
import {Text} from '@fluentui/react-components';
|
||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
export const About: FC = () => {
|
export const About: FC = () => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col box-border gap-5 p-2">
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import React, {FC} from 'react';
|
import React, {FC} from 'react';
|
||||||
import {Page} from '../components/Page';
|
import {Page} from '../components/Page';
|
||||||
import {PresenceBadge} from '@fluentui/react-components';
|
import {PresenceBadge} from '@fluentui/react-components';
|
||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
export const Chat: FC = () => {
|
export const Chat: FC = () => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title="Chat" content={
|
<Page title={t('Chat')} content={
|
||||||
<div className="flex flex-col gap-2 overflow-hidden">
|
<div className="flex flex-col gap-2 overflow-hidden">
|
||||||
<PresenceBadge/>
|
<PresenceBadge/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,8 +16,10 @@ import {updateConfig} from '../apis';
|
|||||||
import {ConvertModel} from '../../wailsjs/go/backend_golang/App';
|
import {ConvertModel} 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';
|
||||||
|
|
||||||
export const Configs: FC = observer(() => {
|
export const Configs: FC = observer(() => {
|
||||||
|
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]);
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ export const Configs: FC = observer(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title="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}
|
||||||
@ -80,29 +82,29 @@ 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="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="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="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>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
|
||||||
title="Default API Parameters"
|
title={t('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."
|
desc={t('Hover your mouse over the text to view a detailed description. Settings marked with * will take effect immediately after being saved.')}
|
||||||
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="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}
|
<NumberInput value={selectedConfig.apiParameters.apiPort} min={1} max={65535} step={1}
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
setSelectedConfigApiParams({
|
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}
|
<ValuedSlider value={selectedConfig.apiParameters.maxResponseToken} min={100} max={8100} step={400}
|
||||||
input
|
input
|
||||||
onChange={(e, data) => {
|
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
|
<ValuedSlider value={selectedConfig.apiParameters.temperature} min={0} max={2} step={0.1} input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
setSelectedConfigApiParams({
|
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
|
<ValuedSlider value={selectedConfig.apiParameters.topP} min={0} max={1} step={0.1} input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
setSelectedConfigApiParams({
|
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
|
<ValuedSlider value={selectedConfig.apiParameters.presencePenalty} min={-2} max={2} step={0.1} input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
setSelectedConfigApiParams({
|
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
|
<ValuedSlider value={selectedConfig.apiParameters.frequencyPenalty} min={-2} max={2} step={0.1} input
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
setSelectedConfigApiParams({
|
setSelectedConfigApiParams({
|
||||||
@ -155,10 +157,10 @@ export const Configs: FC = observer(() => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Section
|
<Section
|
||||||
title="Model Parameters"
|
title={t('Model Parameters')}
|
||||||
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="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}
|
||||||
@ -171,12 +173,12 @@ 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="Manage Models" icon={<DataUsageSettings20Regular/>} onClick={() => {
|
<ToolTipButton desc={t('Manage Models')} icon={<DataUsageSettings20Regular/>} onClick={() => {
|
||||||
navigate({pathname: '/models'});
|
navigate({pathname: '/models'});
|
||||||
}}/>
|
}}/>
|
||||||
</div>
|
</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 modelPath = `${manifest.localModelDir}/${selectedConfig.modelParameters.modelName}`;
|
||||||
const strategy = getStrategy(selectedConfig);
|
const strategy = getStrategy(selectedConfig);
|
||||||
const newModelPath = modelPath + '-' + strategy.replace(/[> *+]/g, '-');
|
const newModelPath = modelPath + '-' + strategy.replace(/[> *+]/g, '-');
|
||||||
@ -188,7 +190,7 @@ export const Configs: FC = observer(() => {
|
|||||||
toast(`Convert Failed - ${e}`, {type: 'error'});
|
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}
|
<Dropdown style={{minWidth: 0}} className="grow" value={selectedConfig.modelParameters.device}
|
||||||
selectedOptions={[selectedConfig.modelParameters.device]}
|
selectedOptions={[selectedConfig.modelParameters.device]}
|
||||||
onOptionSelect={(_, data) => {
|
onOptionSelect={(_, data) => {
|
||||||
@ -202,7 +204,7 @@ export const Configs: FC = observer(() => {
|
|||||||
<Option>CUDA</Option>
|
<Option>CUDA</Option>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
}/>
|
}/>
|
||||||
<Labeled label="Precision" content={
|
<Labeled label={t('Precision')} content={
|
||||||
<Dropdown style={{minWidth: 0}} className="grow" value={selectedConfig.modelParameters.precision}
|
<Dropdown style={{minWidth: 0}} className="grow" value={selectedConfig.modelParameters.precision}
|
||||||
selectedOptions={[selectedConfig.modelParameters.precision]}
|
selectedOptions={[selectedConfig.modelParameters.precision]}
|
||||||
onOptionSelect={(_, data) => {
|
onOptionSelect={(_, data) => {
|
||||||
@ -217,7 +219,7 @@ export const Configs: FC = observer(() => {
|
|||||||
<Option>fp32</Option>
|
<Option>fp32</Option>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
}/>
|
}/>
|
||||||
<Labeled label="Stored Layers" content={
|
<Labeled label={t('Stored Layers')} 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) => {
|
||||||
@ -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}
|
<Switch checked={selectedConfig.modelParameters.enableHighPrecisionForLastLayer}
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
setSelectedConfigModelParams({
|
setSelectedConfigModelParams({
|
||||||
|
@ -13,6 +13,7 @@ import {observer} from 'mobx-react-lite';
|
|||||||
import {RunButton} from '../components/RunButton';
|
import {RunButton} from '../components/RunButton';
|
||||||
import manifest from '../../../manifest.json';
|
import manifest from '../../../manifest.json';
|
||||||
import {BrowserOpenURL} from '../../wailsjs/runtime';
|
import {BrowserOpenURL} from '../../wailsjs/runtime';
|
||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
type NavCard = {
|
type NavCard = {
|
||||||
label: string;
|
label: string;
|
||||||
@ -49,6 +50,7 @@ const navCards: NavCard[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const Home: FC = observer(() => {
|
export const Home: FC = observer(() => {
|
||||||
|
const {t} = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const onClickNavCard = (path: string) => {
|
const onClickNavCard = (path: string) => {
|
||||||
@ -59,22 +61,17 @@ export const Home: FC = observer(() => {
|
|||||||
<div className="flex flex-col justify-between h-full">
|
<div className="flex flex-col justify-between h-full">
|
||||||
<img className="rounded-xl select-none hidden sm:block" src={banner}/>
|
<img className="rounded-xl select-none hidden sm:block" src={banner}/>
|
||||||
<div className="flex flex-col gap-2">
|
<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">
|
<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
|
{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).')}
|
||||||
transformer (parallelizable). And it's 100% attention-free. You only need the hidden state at position t to
|
{/*TODO Markdown*/}
|
||||||
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).
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-5">
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-5">
|
||||||
{navCards.map(({label, path, icon, desc}, index) => (
|
{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)}>
|
size="large" onClick={() => onClickNavCard(path)}>
|
||||||
{label}
|
{t(label)}
|
||||||
</CompoundButton>
|
</CompoundButton>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -96,8 +93,8 @@ export const Home: FC = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-4 items-end">
|
<div className="flex gap-4 items-end">
|
||||||
Version: {manifest.version}
|
{t('Version')}: {manifest.version}
|
||||||
<Link onClick={() => BrowserOpenURL('https://github.com/josStorer/RWKV-Runner')}>Help</Link>
|
<Link onClick={() => BrowserOpenURL('https://github.com/josStorer/RWKV-Runner')}>{t('Help')}</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,6 +22,7 @@ import manifest from '../../../manifest.json';
|
|||||||
import {toast} from 'react-toastify';
|
import {toast} from 'react-toastify';
|
||||||
import {Page} from '../components/Page';
|
import {Page} from '../components/Page';
|
||||||
import {refreshModels, saveConfigs} from '../utils';
|
import {refreshModels, saveConfigs} from '../utils';
|
||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
||||||
createTableColumn<ModelSourceItem>({
|
createTableColumn<ModelSourceItem>({
|
||||||
@ -30,7 +31,9 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
return a.name.localeCompare(b.name);
|
return a.name.localeCompare(b.name);
|
||||||
},
|
},
|
||||||
renderHeaderCell: () => {
|
renderHeaderCell: () => {
|
||||||
return 'File';
|
const {t} = useTranslation();
|
||||||
|
|
||||||
|
return t('File');
|
||||||
},
|
},
|
||||||
renderCell: (item) => {
|
renderCell: (item) => {
|
||||||
return (
|
return (
|
||||||
@ -49,12 +52,18 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
renderHeaderCell: () => {
|
renderHeaderCell: () => {
|
||||||
return 'Desc';
|
const {t} = useTranslation();
|
||||||
|
|
||||||
|
return t('Desc');
|
||||||
},
|
},
|
||||||
renderCell: (item) => {
|
renderCell: (item) => {
|
||||||
|
const lang: string = commonStore.settings.language;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableCellLayout>
|
<TableCellLayout>
|
||||||
{item.desc && item.desc['en']}
|
{item.desc &&
|
||||||
|
(lang in item.desc ? item.desc[lang] :
|
||||||
|
('en' in item.desc && item.desc['en']))}
|
||||||
</TableCellLayout>
|
</TableCellLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -65,7 +74,9 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
return a.size - b.size;
|
return a.size - b.size;
|
||||||
},
|
},
|
||||||
renderHeaderCell: () => {
|
renderHeaderCell: () => {
|
||||||
return 'Size';
|
const {t} = useTranslation();
|
||||||
|
|
||||||
|
return t('Size');
|
||||||
},
|
},
|
||||||
renderCell: (item) => {
|
renderCell: (item) => {
|
||||||
return (
|
return (
|
||||||
@ -85,7 +96,9 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
return b.lastUpdatedMs - a.lastUpdatedMs;
|
return b.lastUpdatedMs - a.lastUpdatedMs;
|
||||||
},
|
},
|
||||||
renderHeaderCell: () => {
|
renderHeaderCell: () => {
|
||||||
return 'Last updated';
|
const {t} = useTranslation();
|
||||||
|
|
||||||
|
return t('Last updated');
|
||||||
},
|
},
|
||||||
|
|
||||||
renderCell: (item) => {
|
renderCell: (item) => {
|
||||||
@ -98,24 +111,28 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
return a.isDownloading ? 0 : a.isLocal ? -1 : 1;
|
return a.isDownloading ? 0 : a.isLocal ? -1 : 1;
|
||||||
},
|
},
|
||||||
renderHeaderCell: () => {
|
renderHeaderCell: () => {
|
||||||
return 'Actions';
|
const {t} = useTranslation();
|
||||||
|
|
||||||
|
return t('Actions');
|
||||||
},
|
},
|
||||||
renderCell: (item) => {
|
renderCell: (item) => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableCellLayout>
|
<TableCellLayout>
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
{
|
{
|
||||||
item.isLocal &&
|
item.isLocal &&
|
||||||
<ToolTipButton desc="Open Folder" icon={<Folder20Regular/>} onClick={() => {
|
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular/>} onClick={() => {
|
||||||
OpenFileFolder(`./${manifest.localModelDir}/${item.name}`);
|
OpenFileFolder(`./${manifest.localModelDir}/${item.name}`);
|
||||||
}}/>
|
}}/>
|
||||||
}
|
}
|
||||||
{item.downloadUrl && !item.isLocal &&
|
{item.downloadUrl && !item.isLocal &&
|
||||||
<ToolTipButton desc="Download" icon={<ArrowDownload20Regular/>} onClick={() => {
|
<ToolTipButton desc={t('Download')} icon={<ArrowDownload20Regular/>} onClick={() => {
|
||||||
toast(`Downloading ${item.name}`);
|
toast(`Downloading ${item.name}`);
|
||||||
DownloadFile(`./${manifest.localModelDir}/${item.name}`, item.downloadUrl!);
|
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!);
|
BrowserOpenURL(item.url!);
|
||||||
}}/>}
|
}}/>}
|
||||||
</div>
|
</div>
|
||||||
@ -126,20 +143,21 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const Models: FC = observer(() => {
|
export const Models: FC = observer(() => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
return (
|
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-2 overflow-hidden">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<Text weight="medium">Model Source Manifest List</Text>
|
<Text weight="medium">{t('Model Source Manifest List')}</Text>
|
||||||
<ToolTipButton desc="Refresh" icon={<ArrowClockwise20Regular/>} onClick={() => {
|
<ToolTipButton desc={t('Refresh')} icon={<ArrowClockwise20Regular/>} onClick={() => {
|
||||||
refreshModels(false);
|
refreshModels(false);
|
||||||
saveConfigs();
|
saveConfigs();
|
||||||
}}/>
|
}}/>
|
||||||
</div>
|
</div>
|
||||||
<Text size={100}>
|
<Text size={100}>
|
||||||
Provide JSON file URLs for the models manifest. Separate URLs with semicolons. The "models"
|
{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.')}
|
||||||
field in JSON files will be parsed into the following table.
|
|
||||||
</Text>
|
</Text>
|
||||||
<Textarea size="large" resize="vertical"
|
<Textarea size="large" resize="vertical"
|
||||||
value={commonStore.modelSourceManifestList}
|
value={commonStore.modelSourceManifestList}
|
||||||
|
@ -14,7 +14,7 @@ export const Settings: FC = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<Page title={t('Settings')} content={
|
<Page title={t('Settings')} content={
|
||||||
<div className="flex flex-col gap-2 overflow-hidden">
|
<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}}}
|
<Dropdown style={{minWidth: 0}} listbox={{style: {minWidth: 0}}}
|
||||||
value={Languages[commonStore.settings.language]}
|
value={Languages[commonStore.settings.language]}
|
||||||
selectedOptions={[Languages[commonStore.settings.language]]}
|
selectedOptions={[Languages[commonStore.settings.language]]}
|
||||||
@ -33,7 +33,7 @@ export const Settings: FC = observer(() => {
|
|||||||
}
|
}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
}/>
|
}/>
|
||||||
<Labeled label="Dark Mode" flex spaceBetween content={
|
<Labeled label={t('Dark Mode')} flex spaceBetween content={
|
||||||
<Switch checked={commonStore.settings.darkMode}
|
<Switch checked={commonStore.settings.darkMode}
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
commonStore.setSettings({
|
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}
|
<Switch checked={commonStore.settings.autoUpdatesCheck}
|
||||||
onChange={(e, data) => {
|
onChange={(e, data) => {
|
||||||
commonStore.setSettings({
|
commonStore.setSettings({
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import React, {FC} from 'react';
|
import React, {FC} from 'react';
|
||||||
import {Text} from '@fluentui/react-components';
|
import {Text} from '@fluentui/react-components';
|
||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
export const Train: FC = () => {
|
export const Train: FC = () => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col box-border gap-5 p-2">
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user