diff --git a/backend-golang/wsl.go b/backend-golang/wsl.go index 72470b6..29eaba1 100644 --- a/backend-golang/wsl.go +++ b/backend-golang/wsl.go @@ -1,3 +1,5 @@ +//go:build windows + package backend_golang import ( @@ -8,7 +10,6 @@ import ( "os" "os/exec" "path/filepath" - "runtime" "strings" "time" @@ -37,10 +38,6 @@ func isWslRunning() (bool, error) { } func (a *App) WslStart() error { - if runtime.GOOS != "windows" { - return errors.New("wsl not supported") - } - running, err := isWslRunning() if err != nil { return err @@ -100,10 +97,6 @@ func (a *App) WslStart() error { } func (a *App) WslCommand(command string) error { - if runtime.GOOS != "windows" { - return errors.New("wsl not supported") - } - running, err := isWslRunning() if err != nil { return err @@ -119,10 +112,6 @@ func (a *App) WslCommand(command string) error { } func (a *App) WslStop() error { - if runtime.GOOS != "windows" { - return errors.New("wsl not supported") - } - running, err := isWslRunning() if err != nil { return err @@ -142,10 +131,6 @@ func (a *App) WslStop() error { } func (a *App) WslIsEnabled() error { - if runtime.GOOS != "windows" { - return errors.New("wsl not supported") - } - ex, err := os.Executable() if err != nil { return err @@ -177,10 +162,6 @@ func (a *App) WslIsEnabled() error { } func (a *App) WslEnable(forceMode bool) error { - if runtime.GOOS != "windows" { - return errors.New("wsl not supported") - } - cmd := `/online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux` _, err := su.ShellExecute(su.RUNAS, "dism", cmd, `C:\`) if err != nil { @@ -193,10 +174,6 @@ func (a *App) WslEnable(forceMode bool) error { } func (a *App) WslInstallUbuntu() error { - if runtime.GOOS != "windows" { - return errors.New("wsl not supported") - } - - exec.Command("start", "ms-windows-store://pdp/?ProductId=9PN20MSR04DW").Start() - return nil + _, err := Cmd("ms-windows-store://pdp/?ProductId=9PN20MSR04DW") + return err } diff --git a/backend-golang/wsl_not_windows.go b/backend-golang/wsl_not_windows.go new file mode 100644 index 0000000..1dc5d97 --- /dev/null +++ b/backend-golang/wsl_not_windows.go @@ -0,0 +1,31 @@ +//go:build darwin || linux + +package backend_golang + +import ( + "errors" +) + +func (a *App) WslStart() error { + return errors.New("wsl not supported") +} + +func (a *App) WslCommand(command string) error { + return errors.New("wsl not supported") +} + +func (a *App) WslStop() error { + return errors.New("wsl not supported") +} + +func (a *App) WslIsEnabled() error { + return errors.New("wsl not supported") +} + +func (a *App) WslEnable(forceMode bool) error { + return errors.New("wsl not supported") +} + +func (a *App) WslInstallUbuntu() error { + return errors.New("wsl not supported") +} diff --git a/finetune/install-wsl-dep-and-train.sh b/finetune/install-wsl-dep-and-train.sh index 6faa48e..88c4c9b 100644 --- a/finetune/install-wsl-dep-and-train.sh +++ b/finetune/install-wsl-dep-and-train.sh @@ -11,13 +11,13 @@ fi if dpkg -s "python3-pip" >/dev/null 2>&1; then echo "pip installed" else - sudo apt install python3-pip + sudo apt -y install python3-pip fi if dpkg -s "ninja-build" >/dev/null 2>&1; then echo "ninja installed" else - sudo apt install ninja-build + sudo apt -y install ninja-build fi if dpkg -s "cuda" >/dev/null 2>&1; then diff --git a/frontend/src/_locales/zh-hans/main.json b/frontend/src/_locales/zh-hans/main.json index 42d8148..3319097 100644 --- a/frontend/src/_locales/zh-hans/main.json +++ b/frontend/src/_locales/zh-hans/main.json @@ -195,7 +195,7 @@ "Please convert data first.": "请先转换数据", "Ubuntu is not installed, do you want to install it?": "Ubuntu未安装,是否安装?", "Install Ubuntu": "安装Ubuntu", - "Please install Ubuntu using Microsoft Store": "请用Microsoft Store安装Ubuntu", + "Please install Ubuntu using Microsoft Store, after installation click the Open button in Microsoft Store and then click the Train button": "请用Microsoft Store安装Ubuntu,安装完成后,点击Microsoft Store界面的“打开”按钮,然后点击“训练”按钮", "WSL is not enabled, do you want to enable it?": "WSL未启用,是否启用?", "Enable WSL": "启用WSL", "After installation, please restart your computer to enable WSL": "安装完成后,请重启电脑以启用WSL", @@ -221,5 +221,7 @@ "Pre-FFN": "前馈网络预处理", "None": "空", "Merge model successfully": "合并模型成功", - "Convert Data successfully": "数据转换成功" + "Convert Data successfully": "数据转换成功", + "Please select a LoRA model": "请选择一个LoRA模型", + "You are using sample data for training. For formal training, please make sure to create your own jsonl file.": "你正在使用示例数据训练,对于正式训练场合,请务必创建你自己的jsonl训练数据" } \ No newline at end of file diff --git a/frontend/src/components/RunButton.tsx b/frontend/src/components/RunButton.tsx index ed8fc84..7cc13b2 100644 --- a/frontend/src/components/RunButton.tsx +++ b/frontend/src/components/RunButton.tsx @@ -1,23 +1,16 @@ import React, { FC, MouseEventHandler, ReactElement } from 'react'; import commonStore, { ModelStatus } from '../stores/commonStore'; -import { - AddToDownloadList, - CopyFile, - DepCheck, - FileExists, - InstallPyDep, - StartServer -} from '../../wailsjs/go/backend_golang/App'; +import { AddToDownloadList, CopyFile, FileExists, StartServer } from '../../wailsjs/go/backend_golang/App'; import { Button } from '@fluentui/react-components'; import { observer } from 'mobx-react-lite'; import { exit, getStatus, readRoot, switchModel, updateConfig } from '../apis'; import { toast } from 'react-toastify'; -import { getStrategy, getSupportedCustomCudaFile, toastWithButton } from '../utils'; +import { checkDependencies, getStrategy, getSupportedCustomCudaFile, toastWithButton } from '../utils'; import { useTranslation } from 'react-i18next'; import { ToolTipButton } from './ToolTipButton'; import { Play16Regular, Stop16Regular } from '@fluentui/react-icons'; import { useNavigate } from 'react-router'; -import { BrowserOpenURL, WindowShow } from '../../wailsjs/runtime/runtime'; +import { WindowShow } from '../../wailsjs/runtime/runtime'; const mainButtonText = { [ModelStatus.Offline]: 'Run', @@ -57,52 +50,9 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean return; } - if (!commonStore.depComplete) { - let depErrorMsg = ''; - await DepCheck(commonStore.settings.customPythonPath).catch((e) => { - depErrorMsg = e.message || e; - WindowShow(); - if (depErrorMsg === 'python zip not found') { - toastWithButton(t('Python target not found, would you like to download it?'), t('Download'), () => { - 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')) { - if (depErrorMsg.includes('vc_redist')) { - toastWithButton(t('Microsoft Visual C++ Redistributable is not installed, would you like to download it?'), t('Download'), () => { - BrowserOpenURL('https://aka.ms/vs/16/release/vc_redist.x64.exe'); - }); - } else { - toast(depErrorMsg, { type: 'info', position: 'bottom-left' }); - if (commonStore.platform != 'linux') - toastWithButton(t('Python dependencies are incomplete, would you like to install them?'), t('Install'), () => { - InstallPyDep(commonStore.settings.customPythonPath, commonStore.settings.cnMirror).catch((e) => { - const errMsg = e.message || e; - toast(t('Error') + ' - ' + errMsg, { type: 'error' }); - }); - setTimeout(WindowShow, 1000); - }, { - autoClose: 8000 - }); - else - toastWithButton(t('On Linux system, you must manually install python dependencies.'), t('Check'), () => { - BrowserOpenURL('https://github.com/josStorer/RWKV-Runner/blob/master/build/linux/Readme_Install.txt'); - }); - } - } else { - toast(depErrorMsg, { type: 'error' }); - } - }); - if (depErrorMsg) { - commonStore.setStatus({ status: ModelStatus.Offline }); - return; - } - commonStore.setDepComplete(true); - if (commonStore.platform === 'windows') - CopyFile('./backend-python/wkv_cuda_utils/wkv_cuda_model.py', './py310/Lib/site-packages/rwkv/model.py'); - } + const ok = await checkDependencies(navigate); + if (!ok) + return; const currentModelSource = commonStore.modelSourceList.find(item => item.name === modelName); diff --git a/frontend/src/pages/Train.tsx b/frontend/src/pages/Train.tsx index dfb7dde..d28a302 100644 --- a/frontend/src/pages/Train.tsx +++ b/frontend/src/pages/Train.tsx @@ -17,7 +17,7 @@ import { toast } from 'react-toastify'; import commonStore from '../stores/commonStore'; import { observer } from 'mobx-react-lite'; import { SelectTabEventHandler } from '@fluentui/react-tabs'; -import { refreshLocalModels, toastWithButton } from '../utils'; +import { checkDependencies, refreshLocalModels, toastWithButton } from '../utils'; import { Section } from '../components/Section'; import { Labeled } from '../components/Labeled'; import { ToolTipButton } from '../components/ToolTipButton'; @@ -36,6 +36,7 @@ import { } from 'chart.js'; import { Line } from 'react-chartjs-2'; import { ChartJSOrUndefined } from 'react-chartjs-2/dist/types'; +import { WindowShow } from '../../wailsjs/runtime'; ChartJS.register( CategoryScale, @@ -187,10 +188,10 @@ const Terminal: FC = observer(() => { WslStart().then(() => { addWslMessage('WSL> ' + input); setInput(''); - WslCommand(input).catch((e) => { + WslCommand(input).catch((e: any) => { toast((e.message || e), { type: 'error' }); }); - }).catch((e) => { + }).catch((e: any) => { toast((e.message || e), { type: 'error' }); }); } @@ -207,7 +208,7 @@ const Terminal: FC = observer(() => { @@ -424,15 +447,22 @@ const LoraFinetune: FC = observer(() => { )} - { @@ -491,7 +521,7 @@ const LoraFinetune: FC = observer(() => { diff --git a/frontend/src/startup.ts b/frontend/src/startup.ts index b6f69c0..8b5e797 100644 --- a/frontend/src/startup.ts +++ b/frontend/src/startup.ts @@ -59,6 +59,9 @@ async function initConfig() { if (configData.dataProcessParams) commonStore.setDataProcessParams(configData.dataProcessParams, false); + if (configData.loraFinetuneParams) + commonStore.setLoraFinetuneParameters(configData.loraFinetuneParams, false); + if (configData.modelConfigs && Array.isArray(configData.modelConfigs)) commonStore.setModelConfigs(configData.modelConfigs, false); else throw new Error('Invalid config.json'); diff --git a/frontend/src/utils/index.tsx b/frontend/src/utils/index.tsx index 5a7adc9..92ca07a 100644 --- a/frontend/src/utils/index.tsx +++ b/frontend/src/utils/index.tsx @@ -1,6 +1,9 @@ import { AddToDownloadList, + CopyFile, DeleteFile, + DepCheck, + InstallPyDep, ListDirFiles, ReadFileInfo, ReadJson, @@ -8,7 +11,7 @@ import { UpdateApp } from '../../wailsjs/go/backend_golang/App'; import manifest from '../../../manifest.json'; -import commonStore from '../stores/commonStore'; +import commonStore, { ModelStatus } from '../stores/commonStore'; import { toast } from 'react-toastify'; import { t } from 'i18next'; import { ToastOptions } from 'react-toastify/dist/types'; @@ -18,6 +21,8 @@ import { ModelSourceItem } from '../pages/Models'; import { ModelConfig, ModelParameters } from '../pages/Configs'; import { DownloadStatus } from '../pages/Downloads'; import { DataProcessParameters, LoraFinetuneParameters } from '../pages/Train'; +import { BrowserOpenURL, WindowShow } from '../../wailsjs/runtime'; +import { NavigateFunction } from 'react-router'; export type Cache = { version: string @@ -347,6 +352,56 @@ export async function checkUpdate(notifyEvenLatest: boolean = false) { }); } +export const checkDependencies = async (navigate: NavigateFunction) => { + if (!commonStore.depComplete) { + let depErrorMsg = ''; + await DepCheck(commonStore.settings.customPythonPath).catch((e) => { + depErrorMsg = e.message || e; + WindowShow(); + if (depErrorMsg === 'python zip not found') { + toastWithButton(t('Python target not found, would you like to download it?'), t('Download'), () => { + 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')) { + if (depErrorMsg.includes('vc_redist')) { + toastWithButton(t('Microsoft Visual C++ Redistributable is not installed, would you like to download it?'), t('Download'), () => { + BrowserOpenURL('https://aka.ms/vs/16/release/vc_redist.x64.exe'); + }); + } else { + toast(depErrorMsg, { type: 'info', position: 'bottom-left' }); + if (commonStore.platform != 'linux') + toastWithButton(t('Python dependencies are incomplete, would you like to install them?'), t('Install'), () => { + InstallPyDep(commonStore.settings.customPythonPath, commonStore.settings.cnMirror).catch((e) => { + const errMsg = e.message || e; + toast(t('Error') + ' - ' + errMsg, { type: 'error' }); + }); + setTimeout(WindowShow, 1000); + }, { + autoClose: 8000 + }); + else + toastWithButton(t('On Linux system, you must manually install python dependencies.'), t('Check'), () => { + BrowserOpenURL('https://github.com/josStorer/RWKV-Runner/blob/master/build/linux/Readme_Install.txt'); + }); + } + } else { + toast(depErrorMsg, { type: 'error' }); + } + }); + if (depErrorMsg) { + commonStore.setStatus({ status: ModelStatus.Offline }); + return false; + } + commonStore.setDepComplete(true); + if (commonStore.platform === 'windows') + CopyFile('./backend-python/wkv_cuda_utils/wkv_cuda_model.py', './py310/Lib/site-packages/rwkv/model.py'); + } + return true; +}; + export function toastWithButton(text: string, buttonText: string, onClickButton: () => void, options?: ToastOptions) { let triggered = false; const id = toast(