improve path processing

This commit is contained in:
josc146 2024-02-02 22:00:01 +08:00
parent 95502b900d
commit 947e127e34
14 changed files with 237 additions and 82 deletions

View File

@ -39,10 +39,15 @@ func (a *App) OnStartup(ctx context.Context) {
a.exDir = ""
a.cmdPrefix = ""
if runtime.GOOS == "darwin" {
ex, _ := os.Executable()
a.exDir = filepath.Dir(ex) + "/../../../"
a.cmdPrefix = "cd " + a.exDir + " && "
ex, err := os.Executable()
if err == nil {
if runtime.GOOS == "darwin" {
a.exDir = filepath.Dir(ex) + "/../../../"
a.cmdPrefix = "cd " + a.exDir + " && "
} else {
a.exDir = filepath.Dir(ex) + "/"
a.cmdPrefix = "cd " + a.exDir + " && "
}
}
os.Chmod(a.exDir+"backend-rust/webgpu_server", 0777)
@ -50,9 +55,9 @@ func (a *App) OnStartup(ctx context.Context) {
os.Mkdir(a.exDir+"models", os.ModePerm)
os.Mkdir(a.exDir+"lora-models", os.ModePerm)
os.Mkdir(a.exDir+"finetune/json2binidx_tool/data", os.ModePerm)
trainLogPath := a.exDir + "lora-models/train_log.txt"
trainLogPath := "lora-models/train_log.txt"
if !a.FileExists(trainLogPath) {
f, err := os.Create(trainLogPath)
f, err := os.Create(a.exDir + trainLogPath)
if err == nil {
f.Close()
}

View File

@ -10,7 +10,11 @@ import (
)
func (a *App) DownloadFile(path string, url string) error {
_, err := grab.Get(a.exDir+path, url)
absPath, err := a.GetAbsPath(path)
if err != nil {
return err
}
_, err = grab.Get(absPath, url)
if err != nil {
return err
}
@ -88,11 +92,15 @@ func (a *App) ContinueDownload(url string) {
}
func (a *App) AddToDownloadList(path string, url string) {
if !existsInDownloadList(a.exDir+path, url) {
absPath, err := a.GetAbsPath(path)
if err != nil {
return
}
if !existsInDownloadList(absPath, url) {
downloadList = append(downloadList, &DownloadStatus{
resp: nil,
Name: filepath.Base(path),
Path: a.exDir + path,
Path: absPath,
Url: url,
Downloading: false,
})

View File

@ -14,27 +14,55 @@ import (
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
)
func (a *App) GetAbsPath(path string) (string, error) {
var absPath string
var err error
if filepath.IsAbs(path) {
absPath = path
} else {
absPath, err = filepath.Abs(filepath.Join(a.exDir, path))
if err != nil {
return "", err
}
}
absPath = strings.ReplaceAll(absPath, "/", string(os.PathSeparator))
println("GetAbsPath:", absPath)
return absPath, nil
}
func (a *App) SaveFile(path string, savedContent []byte) error {
if err := os.WriteFile(a.exDir+path, savedContent, 0644); err != nil {
absPath, err := a.GetAbsPath(path)
if err != nil {
return err
}
if err := os.WriteFile(absPath, savedContent, 0644); err != nil {
return err
}
return nil
}
func (a *App) SaveJson(fileName string, jsonData any) error {
func (a *App) SaveJson(path string, jsonData any) error {
text, err := json.MarshalIndent(jsonData, "", " ")
if err != nil {
return err
}
if err := os.WriteFile(a.exDir+fileName, text, 0644); err != nil {
absPath, err := a.GetAbsPath(path)
if err != nil {
return err
}
if err := os.WriteFile(absPath, text, 0644); err != nil {
return err
}
return nil
}
func (a *App) ReadJson(fileName string) (any, error) {
file, err := os.ReadFile(a.exDir + fileName)
func (a *App) ReadJson(path string) (any, error) {
absPath, err := a.GetAbsPath(path)
if err != nil {
return nil, err
}
file, err := os.ReadFile(absPath)
if err != nil {
return nil, err
}
@ -48,8 +76,12 @@ func (a *App) ReadJson(fileName string) (any, error) {
return data, nil
}
func (a *App) FileExists(fileName string) bool {
_, err := os.Stat(a.exDir + fileName)
func (a *App) FileExists(path string) bool {
absPath, err := a.GetAbsPath(path)
if err != nil {
return false
}
_, err = os.Stat(absPath)
return err == nil
}
@ -60,8 +92,12 @@ type FileInfo struct {
ModTime string `json:"modTime"`
}
func (a *App) ReadFileInfo(fileName string) (*FileInfo, error) {
info, err := os.Stat(a.exDir + fileName)
func (a *App) ReadFileInfo(path string) (*FileInfo, error) {
absPath, err := a.GetAbsPath(path)
if err != nil {
return nil, err
}
info, err := os.Stat(absPath)
if err != nil {
return nil, err
}
@ -74,7 +110,11 @@ func (a *App) ReadFileInfo(fileName string) (*FileInfo, error) {
}
func (a *App) ListDirFiles(dirPath string) ([]FileInfo, error) {
files, err := os.ReadDir(a.exDir + dirPath)
absDirPath, err := a.GetAbsPath(dirPath)
if err != nil {
return nil, err
}
files, err := os.ReadDir(absDirPath)
if err != nil {
return nil, err
}
@ -96,7 +136,11 @@ func (a *App) ListDirFiles(dirPath string) ([]FileInfo, error) {
}
func (a *App) DeleteFile(path string) error {
err := os.Remove(a.exDir + path)
absPath, err := a.GetAbsPath(path)
if err != nil {
return err
}
err = os.Remove(absPath)
if err != nil {
return err
}
@ -104,18 +148,27 @@ func (a *App) DeleteFile(path string) error {
}
func (a *App) CopyFile(src string, dst string) error {
sourceFile, err := os.Open(a.exDir + src)
absSrc, err := a.GetAbsPath(src)
if err != nil {
return err
}
absDst, err := a.GetAbsPath(dst)
if err != nil {
return err
}
sourceFile, err := os.Open(absSrc)
if err != nil {
return err
}
defer sourceFile.Close()
err = os.MkdirAll(a.exDir+dst[:strings.LastIndex(dst, "/")], 0755)
err = os.MkdirAll(filepath.Dir(absDst), 0755)
if err != nil {
return err
}
destFile, err := os.Create(a.exDir + dst)
destFile, err := os.Create(absDst)
if err != nil {
return err
}
@ -166,14 +219,8 @@ func (a *App) OpenOpenFileDialog(filterPattern string) (string, error) {
return path, nil
}
func (a *App) OpenFileFolder(path string, relative bool) error {
var absPath string
var err error
if relative {
absPath, err = filepath.Abs(a.exDir + path)
} else {
absPath, err = filepath.Abs(path)
}
func (a *App) OpenFileFolder(path string) error {
absPath, err := a.GetAbsPath(path)
if err != nil {
return err
}

View File

@ -1,3 +1,4 @@
// Considering some whitespace and multilingual support, the functions in rwkv.go should always be executed with cwd as RWKV-Runner, and never use a.GetAbsPath() here.
package backend_golang
import (
@ -11,14 +12,18 @@ import (
)
func (a *App) StartServer(python string, port int, host string, webui bool, rwkvBeta bool, rwkvcpp bool, webgpu bool) (string, error) {
var err error
execFile := "./backend-python/main.py"
_, err := os.Stat(execFile)
if err != nil {
return "", err
}
if python == "" {
python, err = GetPython()
}
if err != nil {
return "", err
}
args := []string{python, "./backend-python/main.py"}
args := []string{python, execFile}
if webui {
args = append(args, "--webui")
}
@ -36,41 +41,77 @@ func (a *App) StartServer(python string, port int, host string, webui bool, rwkv
}
func (a *App) StartWebGPUServer(port int, host string) (string, error) {
args := []string{"./backend-rust/webgpu_server"}
var execFile string
execFiles := []string{"./backend-rust/webgpu_server", "./backend-rust/webgpu_server.exe"}
for _, file := range execFiles {
_, err := os.Stat(file)
if err == nil {
execFile = file
break
}
}
if execFile == "" {
return "", errors.New(execFiles[0] + " not found")
}
args := []string{execFile}
args = append(args, "--port", strconv.Itoa(port), "--ip", host)
return Cmd(args...)
}
func (a *App) ConvertModel(python string, modelPath string, strategy string, outPath string) (string, error) {
var err error
execFile := "./backend-python/convert_model.py"
_, err := os.Stat(execFile)
if err != nil {
return "", err
}
if python == "" {
python, err = GetPython()
}
if err != nil {
return "", err
}
return Cmd(python, "./backend-python/convert_model.py", "--in", modelPath, "--out", outPath, "--strategy", strategy)
return Cmd(python, execFile, "--in", modelPath, "--out", outPath, "--strategy", strategy)
}
func (a *App) ConvertSafetensors(modelPath string, outPath string) (string, error) {
args := []string{"./backend-rust/web-rwkv-converter"}
var execFile string
execFiles := []string{"./backend-rust/web-rwkv-converter", "./backend-rust/web-rwkv-converter.exe"}
for _, file := range execFiles {
_, err := os.Stat(file)
if err == nil {
execFile = file
break
}
}
if execFile == "" {
return "", errors.New(execFiles[0] + " not found")
}
args := []string{execFile}
args = append(args, "--input", modelPath, "--output", outPath)
return Cmd(args...)
}
func (a *App) ConvertSafetensorsWithPython(python string, modelPath string, outPath string) (string, error) {
var err error
execFile := "./backend-python/convert_safetensors.py"
_, err := os.Stat(execFile)
if err != nil {
return "", err
}
if python == "" {
python, err = GetPython()
}
if err != nil {
return "", err
}
return Cmd(python, "./backend-python/convert_safetensors.py", "--input", modelPath, "--output", outPath)
return Cmd(python, execFile, "--input", modelPath, "--output", outPath)
}
func (a *App) ConvertGGML(python string, modelPath string, outPath string, Q51 bool) (string, error) {
var err error
execFile := "./backend-python/convert_pytorch_to_ggml.py"
_, err := os.Stat(execFile)
if err != nil {
return "", err
}
if python == "" {
python, err = GetPython()
}
@ -81,11 +122,15 @@ func (a *App) ConvertGGML(python string, modelPath string, outPath string, Q51 b
if Q51 {
dataType = "Q5_1"
}
return Cmd(python, "./backend-python/convert_pytorch_to_ggml.py", modelPath, outPath, dataType)
return Cmd(python, execFile, modelPath, outPath, dataType)
}
func (a *App) ConvertData(python string, input string, outputPrefix string, vocab string) (string, error) {
var err error
execFile := "./finetune/json2binidx_tool/tools/preprocess_data.py"
_, err := os.Stat(execFile)
if err != nil {
return "", err
}
if python == "" {
python, err = GetPython()
}
@ -129,19 +174,23 @@ func (a *App) ConvertData(python string, input string, outputPrefix string, voca
return "", err
}
return Cmd(python, "./finetune/json2binidx_tool/tools/preprocess_data.py", "--input", input, "--output-prefix", outputPrefix, "--vocab", vocab,
return Cmd(python, execFile, "--input", input, "--output-prefix", outputPrefix, "--vocab", vocab,
"--tokenizer-type", tokenizerType, "--dataset-impl", "mmap", "--append-eod")
}
func (a *App) MergeLora(python string, useGpu bool, loraAlpha int, baseModel string, loraPath string, outputPath string) (string, error) {
var err error
execFile := "./finetune/lora/merge_lora.py"
_, err := os.Stat(execFile)
if err != nil {
return "", err
}
if python == "" {
python, err = GetPython()
}
if err != nil {
return "", err
}
args := []string{python, "./finetune/lora/merge_lora.py"}
args := []string{python, execFile}
if useGpu {
args = append(args, "--use-gpu")
}
@ -157,9 +206,9 @@ func (a *App) DepCheck(python string) error {
if err != nil {
return err
}
out, err := exec.Command(python, a.exDir+"./backend-python/dep_check.py").CombinedOutput()
out, err := exec.Command(python, a.exDir+"backend-python/dep_check.py").CombinedOutput()
if err != nil {
return errors.New("DepCheck Error: " + string(out))
return errors.New("DepCheck Error: " + string(out) + " GError: " + err.Error())
}
return nil
}
@ -185,7 +234,7 @@ func (a *App) InstallPyDep(python string, cnMirror bool) (string, error) {
if !cnMirror {
installScript = strings.Replace(installScript, " -i https://pypi.tuna.tsinghua.edu.cn/simple", "", -1)
}
err = os.WriteFile("./install-py-dep.bat", []byte(installScript), 0644)
err = os.WriteFile(a.exDir+"install-py-dep.bat", []byte(installScript), 0644)
if err != nil {
return "", err
}

View File

@ -23,14 +23,19 @@ func CmdHelper(hideWindow bool, args ...string) (*exec.Cmd, error) {
if runtime.GOOS != "windows" {
return nil, errors.New("unsupported OS")
}
filename := "./cmd-helper.bat"
_, err := os.Stat(filename)
ex, err := os.Executable()
if err != nil {
if err := os.WriteFile(filename, []byte("start %*"), 0644); err != nil {
return nil, err
}
exDir := filepath.Dir(ex) + "/"
path := exDir + "cmd-helper.bat"
_, err = os.Stat(path)
if err != nil {
if err := os.WriteFile(path, []byte("start %*"), 0644); err != nil {
return nil, err
}
}
cmdHelper, err := filepath.Abs(filename)
cmdHelper, err := filepath.Abs(path)
if err != nil {
return nil, err
}
@ -86,16 +91,18 @@ func Cmd(args ...string) (string, error) {
}
func CopyEmbed(efs embed.FS) error {
prefix := ""
ex, err := os.Executable()
if err != nil {
return err
}
var prefix string
if runtime.GOOS == "darwin" {
ex, err := os.Executable()
if err != nil {
return err
}
prefix = filepath.Dir(ex) + "/../../../"
} else {
prefix = filepath.Dir(ex) + "/"
}
err := fs.WalkDir(efs, ".", func(path string, d fs.DirEntry, err error) error {
err = fs.WalkDir(efs, ".", func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
return nil
}
@ -136,13 +143,19 @@ func CopyEmbed(efs embed.FS) error {
func GetPython() (string, error) {
switch platform := runtime.GOOS; platform {
case "windows":
_, err := os.Stat("py310/python.exe")
ex, err := os.Executable()
if err != nil {
_, err := os.Stat("python-3.10.11-embed-amd64.zip")
return "", err
}
exDir := filepath.Dir(ex) + "/"
pyexe := exDir + "py310/python.exe"
_, err = os.Stat(pyexe)
if err != nil {
_, err := os.Stat(exDir + "python-3.10.11-embed-amd64.zip")
if err != nil {
return "", errors.New("python zip not found")
} else {
err := Unzip("python-3.10.11-embed-amd64.zip", "py310")
err := Unzip(exDir+"python-3.10.11-embed-amd64.zip", exDir+"py310")
if err != nil {
return "", errors.New("failed to unzip python")
} else {

View File

@ -9,7 +9,6 @@ import (
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
@ -133,13 +132,7 @@ func (a *App) WslStop() error {
}
func (a *App) WslIsEnabled() error {
ex, err := os.Executable()
if err != nil {
return err
}
exDir := filepath.Dir(ex)
data, err := os.ReadFile(exDir + "/wsl.state")
data, err := os.ReadFile(a.exDir + "wsl.state")
if err == nil {
if strings.Contains(string(data), "Enabled") {
return nil
@ -147,12 +140,12 @@ func (a *App) WslIsEnabled() error {
}
cmd := `-Command (Get-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform).State | Out-File -Encoding utf8 -FilePath ` + a.exDir + "wsl.state"
_, err = su.ShellExecute(su.RUNAS, "powershell", cmd, exDir)
_, err = su.ShellExecute(su.RUNAS, "powershell", cmd, a.exDir)
if err != nil {
return err
}
time.Sleep(2 * time.Second)
data, err = os.ReadFile(exDir + "/wsl.state")
data, err = os.ReadFile(a.exDir + "wsl.state")
if err != nil {
return err
}
@ -170,7 +163,7 @@ func (a *App) WslEnable(forceMode bool) error {
return err
}
if forceMode {
os.WriteFile("./wsl.state", []byte("Enabled"), 0644)
os.WriteFile(a.exDir+"wsl.state", []byte("Enabled"), 0644)
}
return nil
}

View File

@ -4,7 +4,7 @@ import os
import pathlib
import copy
import re
from typing import Dict, Iterable, List, Tuple, Union, Type
from typing import Dict, Iterable, List, Tuple, Union, Type, Callable
from utils.log import quick_log
from fastapi import HTTPException
from pydantic import BaseModel, Field
@ -556,7 +556,41 @@ def get_tokenizer(tokenizer_len: int):
return "rwkv_vocab_v20230424"
def get_model_path(model_path: str) -> str:
if os.path.isabs(model_path):
return model_path
working_dir: pathlib.Path = pathlib.Path(os.path.abspath(os.getcwd()))
parent_paths: List[pathlib.Path] = [
working_dir, # [cwd](RWKV-Runner)/models/xxx
working_dir.parent, # [cwd](backend-python)/../models/xxx
pathlib.Path(
os.path.abspath(__file__)
).parent.parent, # backend-python/models/xxx
pathlib.Path(
os.path.abspath(__file__)
).parent.parent.parent, # RWKV-Runner/models/xxx
]
child_paths: List[Callable[[pathlib.Path], pathlib.Path]] = [
lambda p: p / model_path,
lambda p: p / "build" / "bin" / model_path, # for dev
]
for parent_path in parent_paths:
for child_path in child_paths:
full_path: pathlib.Path = child_path(parent_path)
if os.path.isfile(full_path):
return str(full_path)
return model_path
def RWKV(model: str, strategy: str, tokenizer: Union[str, None]) -> AbstractRWKV:
model = get_model_path(model)
rwkv_beta = global_var.get(global_var.Args).rwkv_beta
rwkv_cpp = getattr(global_var.get(global_var.Args), "rwkv.cpp")
webgpu = global_var.get(global_var.Args).webgpu

View File

@ -295,7 +295,7 @@ const SidePanel: FC = observer(() => {
OpenSaveFileDialog('*.txt', 'conversation.txt', savedContent).then((path) => {
if (path)
toastWithButton(t('Conversation Saved'), t('Open'), () => {
OpenFileFolder(path, false);
OpenFileFolder(path);
});
}).catch(e => {
toast(t('Error') + ' - ' + (e.message || e), { type: 'error', autoClose: 2500 });

View File

@ -426,7 +426,7 @@ const CompositionPanel: FC = observer(() => {
OpenSaveFileDialog('*.txt', 'abc-music.txt', commonStore.compositionParams.prompt).then((path) => {
if (path)
toastWithButton(t('File Saved'), t('Open'), () => {
OpenFileFolder(path, false);
OpenFileFolder(path);
});
}).catch((e) => {
toast(t('Error') + ' - ' + (e.message || e), { type: 'error', autoClose: 2500 });
@ -437,7 +437,7 @@ const CompositionPanel: FC = observer(() => {
OpenSaveFileDialogBytes('*.mid', 'music.mid', Array.from(new Uint8Array(params.midi))).then((path) => {
if (path)
toastWithButton(t('File Saved'), t('Open'), () => {
OpenFileFolder(path, false);
OpenFileFolder(path);
});
}).catch((e) => {
toast(t('Error') + ' - ' + (e.message || e), { type: 'error', autoClose: 2500 });

View File

@ -67,7 +67,7 @@ const Downloads: FC = observer(() => {
AddToDownloadList(status.path, status.url);
}} />}
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular />} onClick={() => {
OpenFileFolder(status.path, false);
OpenFileFolder(status.path);
}} />
</div>
</Field>

View File

@ -132,7 +132,7 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
{
item.isComplete &&
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular />} onClick={() => {
OpenFileFolder(`${commonStore.settings.customModelsPath}/${item.name}`, true);
OpenFileFolder(`${commonStore.settings.customModelsPath}/${item.name}`);
}} />
}
{item.downloadUrl && !item.isComplete &&

View File

@ -398,7 +398,7 @@ const LoraFinetune: FC = observer(() => {
'Even for multi-turn conversations, they must be written in a single line using `\\n` to indicate line breaks. ' +
'If they are different dialogues or topics, they should be written in separate lines.')} />
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular />} onClick={() => {
OpenFileFolder(dataParams.dataPath, false);
OpenFileFolder(dataParams.dataPath);
}} />
</div>
<div className="flex gap-2 items-center">

View File

@ -28,6 +28,8 @@ export function DownloadFile(arg1:string,arg2:string):Promise<void>;
export function FileExists(arg1:string):Promise<boolean>;
export function GetAbsPath(arg1:string):Promise<string>;
export function GetPlatform():Promise<string>;
export function GetPyError():Promise<string>;
@ -40,7 +42,7 @@ export function ListDirFiles(arg1:string):Promise<Array<backend_golang.FileInfo>
export function MergeLora(arg1:string,arg2:boolean,arg3:number,arg4:string,arg5:string,arg6:string):Promise<string>;
export function OpenFileFolder(arg1:string,arg2:boolean):Promise<void>;
export function OpenFileFolder(arg1:string):Promise<void>;
export function OpenMidiPort(arg1:number):Promise<void>;

View File

@ -54,6 +54,10 @@ export function FileExists(arg1) {
return window['go']['backend_golang']['App']['FileExists'](arg1);
}
export function GetAbsPath(arg1) {
return window['go']['backend_golang']['App']['GetAbsPath'](arg1);
}
export function GetPlatform() {
return window['go']['backend_golang']['App']['GetPlatform']();
}
@ -78,8 +82,8 @@ export function MergeLora(arg1, arg2, arg3, arg4, arg5, arg6) {
return window['go']['backend_golang']['App']['MergeLora'](arg1, arg2, arg3, arg4, arg5, arg6);
}
export function OpenFileFolder(arg1, arg2) {
return window['go']['backend_golang']['App']['OpenFileFolder'](arg1, arg2);
export function OpenFileFolder(arg1) {
return window['go']['backend_golang']['App']['OpenFileFolder'](arg1);
}
export function OpenMidiPort(arg1) {