chore & auto dep
This commit is contained in:
parent
9076ff3fd7
commit
b8f7582513
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,3 +10,6 @@ __pycache__
|
||||
/cache.json
|
||||
/frontend/stats.html
|
||||
/frontend/package.json.md5
|
||||
/backend-python/get-pip.py
|
||||
/py310
|
||||
*.zip
|
@ -5,9 +5,10 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
|
||||
"github.com/minio/selfupdate"
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
)
|
||||
|
||||
// App struct
|
||||
@ -46,6 +47,10 @@ func (a *App) UpdateApp(url string) (broken bool, err error) {
|
||||
return false, err
|
||||
}
|
||||
exec.Command(name, os.Args[1:]...).Start()
|
||||
runtime.Quit(a.ctx)
|
||||
wruntime.Quit(a.ctx)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (a *App) GetPlatform() string {
|
||||
return runtime.GOOS
|
||||
}
|
||||
|
@ -1,28 +1,52 @@
|
||||
package backend_golang
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func cmd(args ...string) (string, error) {
|
||||
cmdHelper, err := filepath.Abs("./cmd-helper")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cmd := exec.Command(cmdHelper, args...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func (a *App) StartServer(port int) (string, error) {
|
||||
return cmd("python", "./backend-python/main.py", strconv.Itoa(port))
|
||||
python, err := GetPython()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Cmd(python, "./backend-python/main.py", strconv.Itoa(port))
|
||||
}
|
||||
|
||||
func (a *App) ConvertModel(modelPath string, strategy string, outPath string) (string, error) {
|
||||
return cmd("python", "./backend-python/convert_model.py", "--in", modelPath, "--out", outPath, "--strategy", strategy)
|
||||
python, err := GetPython()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Cmd(python, "./backend-python/convert_model.py", "--in", modelPath, "--out", outPath, "--strategy", strategy)
|
||||
}
|
||||
|
||||
func (a *App) DepCheck() error {
|
||||
python, err := GetPython()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err := exec.Command(python, "./backend-python/dep_check.py").CombinedOutput()
|
||||
if err != nil {
|
||||
return errors.New("DepCheck Error: " + string(out))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) InstallPyDep() (string, error) {
|
||||
python, err := GetPython()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = Cmd(python, "./backend-python/get-pip.py")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ChangeFileLine("./py310/python310._pth", 3, "Lib\\site-packages")
|
||||
_, err = Cmd(python, "-m", "pip", "install", "torch", "torchvision", "torchaudio", "--index-url", "https://download.pytorch.org/whl/cu117")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Cmd(python, "-m", "pip", "install", "-r", "./backend-python/requirements_versions.txt")
|
||||
}
|
||||
|
130
backend-golang/utils.go
Normal file
130
backend-golang/utils.go
Normal file
@ -0,0 +1,130 @@
|
||||
package backend_golang
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Cmd(args ...string) (string, error) {
|
||||
cmdHelper, err := filepath.Abs("./cmd-helper")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cmd := exec.Command(cmdHelper, args...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func GetPython() (string, error) {
|
||||
switch platform := runtime.GOOS; platform {
|
||||
case "windows":
|
||||
_, err := os.Stat("py310/python.exe")
|
||||
if err != nil {
|
||||
_, err := os.Stat("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")
|
||||
if err != nil {
|
||||
return "", errors.New("failed to unzip python")
|
||||
} else {
|
||||
return "py310/python.exe", nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "py310/python.exe", nil
|
||||
}
|
||||
case "darwin":
|
||||
return "python3", nil
|
||||
case "linux":
|
||||
return "python3", nil
|
||||
}
|
||||
return "", errors.New("unsupported OS")
|
||||
}
|
||||
|
||||
func ChangeFileLine(filePath string, lineNumber int, newText string) error {
|
||||
file, err := os.OpenFile(filePath, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
content := make([]string, 0)
|
||||
for scanner.Scan() {
|
||||
content = append(content, scanner.Text())
|
||||
}
|
||||
|
||||
content[lineNumber-1] = newText
|
||||
|
||||
newContent := strings.Join(content, "\n")
|
||||
|
||||
err = file.Truncate(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = file.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = file.WriteString(newContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://gist.github.com/paulerickson/6d8650947ee4e3f3dbcc28fde10eaae7
|
||||
func Unzip(source, destination string) error {
|
||||
archive, err := zip.OpenReader(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer archive.Close()
|
||||
for _, file := range archive.Reader.File {
|
||||
reader, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
path := filepath.Join(destination, file.Name)
|
||||
// Remove file if it already exists; no problem if it doesn't; other cases can error out below
|
||||
_ = os.Remove(path)
|
||||
// Create a directory at path, including parents
|
||||
err = os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If file is _supposed_ to be a directory, we're done
|
||||
if file.FileInfo().IsDir() {
|
||||
continue
|
||||
}
|
||||
// otherwise, remove that directory (_not_ including parents)
|
||||
err = os.Remove(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// and create the actual file. This ensures that the parent directories exist!
|
||||
// An archive may have a single file with a nested path, rather than a file for each parent dir
|
||||
writer, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer writer.Close()
|
||||
_, err = io.Copy(writer, reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
import os
|
||||
import psutil
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
import psutil
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
import uvicorn
|
||||
|
@ -90,5 +90,8 @@
|
||||
"Continue": "继续",
|
||||
"Check": "查看",
|
||||
"Model file not found": "模型文件不存在",
|
||||
"Can not find download url": "找不到下载地址"
|
||||
"Can not find download url": "找不到下载地址",
|
||||
"Python target not found, would you like to download it?": "没有找到目标Python, 是否下载?",
|
||||
"Python dependencies are incomplete, would you like to install them?": "Python依赖缺失, 是否安装?",
|
||||
"Install": "安装"
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import React, {FC, MouseEventHandler, ReactElement} from 'react';
|
||||
import commonStore, {ModelStatus} from '../stores/commonStore';
|
||||
import {AddToDownloadList, FileExists, 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 {observer} from 'mobx-react-lite';
|
||||
import {exit, readRoot, switchModel, updateConfig} from '../apis';
|
||||
import {toast} from 'react-toastify';
|
||||
import manifest from '../../../manifest.json';
|
||||
import {getStrategy, toastWithButton} from '../utils';
|
||||
import {getStrategy, saveCache, toastWithButton} from '../utils';
|
||||
import {useTranslation} from 'react-i18next';
|
||||
import {ToolTipButton} from './ToolTipButton';
|
||||
import {Play16Regular, Stop16Regular} from '@fluentui/react-icons';
|
||||
@ -39,6 +39,32 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean
|
||||
const modelName = modelConfig.modelParameters.modelName;
|
||||
const modelPath = `./${manifest.localModelDir}/${modelName}`;
|
||||
|
||||
if (!commonStore.depComplete) {
|
||||
let depErrorMsg = '';
|
||||
await DepCheck().catch((e) => {
|
||||
depErrorMsg = e.message || e;
|
||||
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')) {
|
||||
toastWithButton(t('Python dependencies are incomplete, would you like to install them?'), t('Install'), () => {
|
||||
InstallPyDep();
|
||||
});
|
||||
} else {
|
||||
toast(depErrorMsg, {type: 'error'});
|
||||
}
|
||||
});
|
||||
if (depErrorMsg) {
|
||||
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;
|
||||
|
@ -256,7 +256,7 @@ export const Configs: FC = observer(() => {
|
||||
toast(`${t('Convert Success')} - ${newModelPath}`, {type: 'success'});
|
||||
refreshLocalModels({models: commonStore.modelSourceList}, false);
|
||||
}).catch(e => {
|
||||
toast(`${t('Convert Failed')} - ${e}`, {type: 'error'});
|
||||
toast(`${t('Convert Failed')} - ${e.message || e}`, {type: 'error'});
|
||||
});
|
||||
} else {
|
||||
toast(`${t('Model Not Found')} - ${modelPath}`, {type: 'error'});
|
||||
|
@ -4,7 +4,7 @@ import {Page} from '../components/Page';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import commonStore from '../stores/commonStore';
|
||||
import {Divider, Field, ProgressBar} from '@fluentui/react-components';
|
||||
import {bytesToGb, bytesToMb, refreshLocalModels} from '../utils';
|
||||
import {bytesToGb, bytesToKb, bytesToMb, refreshLocalModels} from '../utils';
|
||||
import {ToolTipButton} from '../components/ToolTipButton';
|
||||
import {Folder20Regular, Pause20Regular, Play20Regular} from '@fluentui/react-icons';
|
||||
import {ContinueDownload, OpenFileFolder, PauseDownload} from '../../wailsjs/go/backend_golang/App';
|
||||
@ -23,21 +23,31 @@ export type DownloadStatus = {
|
||||
|
||||
export const Downloads: FC = observer(() => {
|
||||
const {t} = useTranslation();
|
||||
const finishedDownloads = commonStore.downloadList.filter((status) => status.done).length;
|
||||
const finishedModelsLen = commonStore.downloadList.filter((status) => status.done && status.name.endsWith('.pth')).length;
|
||||
useEffect(() => {
|
||||
if (finishedDownloads > 0)
|
||||
if (finishedModelsLen > 0)
|
||||
refreshLocalModels({models: commonStore.modelSourceList}, false);
|
||||
console.log('finishedDownloads:', finishedDownloads);
|
||||
}, [finishedDownloads]);
|
||||
console.log('finishedModelsLen:', finishedModelsLen);
|
||||
}, [finishedModelsLen]);
|
||||
|
||||
return (
|
||||
<Page title={t('Downloads')} content={
|
||||
<div className="flex flex-col gap-2 overflow-y-auto overflow-x-hidden p-1">
|
||||
{commonStore.downloadList.map((status, index) => (
|
||||
<div className="flex flex-col gap-1" key={index}>
|
||||
{commonStore.downloadList.slice().reverse().map((status, index) => {
|
||||
const downloadProgress = `${status.progress.toFixed(2)}%`;
|
||||
const downloadSpeed = `${status.downloading ? bytesToMb(status.speed) : '0'}MB/s`;
|
||||
let downloadDetails: string;
|
||||
if (status.size < 1024 * 1024)
|
||||
downloadDetails = `${bytesToKb(status.transferred) + 'KB'}/${bytesToKb(status.size) + 'KB'}`;
|
||||
else if (status.size < 1024 * 1024 * 1024)
|
||||
downloadDetails = `${bytesToMb(status.transferred) + 'MB'}/${bytesToMb(status.size) + 'MB'}`;
|
||||
else
|
||||
downloadDetails = `${bytesToGb(status.transferred) + 'GB'}/${bytesToGb(status.size) + 'GB'}`;
|
||||
|
||||
return <div className="flex flex-col gap-1" key={index}>
|
||||
<Field
|
||||
label={`${status.downloading ? (t('Downloading') + ': ') : ''}${status.name}`}
|
||||
validationMessage={`${status.progress.toFixed(2)}% - ${bytesToGb(status.transferred) + 'GB'}/${bytesToGb(status.size) + 'GB'} - ${status.downloading ? bytesToMb(status.speed) : 0}MB/s - ${status.url}`}
|
||||
validationMessage={`${downloadProgress} - ${downloadDetails} - ${downloadSpeed} - ${status.url}`}
|
||||
validationState={status.done ? 'success' : 'none'}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
@ -57,8 +67,8 @@ export const Downloads: FC = observer(() => {
|
||||
</div>
|
||||
</Field>
|
||||
<Divider style={{flexGrow: 0}}/>
|
||||
</div>
|
||||
))
|
||||
</div>;
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}/>
|
||||
|
@ -1,29 +1,28 @@
|
||||
import commonStore from './stores/commonStore';
|
||||
import {ReadJson} from '../wailsjs/go/backend_golang/App';
|
||||
import {Cache, checkUpdate, downloadProgramFiles, LocalConfig, refreshModels} from './utils';
|
||||
import {Cache, checkUpdate, downloadProgramFiles, LocalConfig, refreshModels, saveCache} from './utils';
|
||||
import {getStatus} from './apis';
|
||||
import {EventsOn} from '../wailsjs/runtime';
|
||||
import {defaultModelConfigs} from './pages/Configs';
|
||||
|
||||
export async function startup() {
|
||||
downloadProgramFiles();
|
||||
|
||||
initRemoteText();
|
||||
initCache();
|
||||
await initConfig();
|
||||
|
||||
if (commonStore.settings.autoUpdatesCheck)
|
||||
checkUpdate();
|
||||
|
||||
getStatus(500).then(status => {
|
||||
if (status)
|
||||
commonStore.setModelStatus(status);
|
||||
});
|
||||
|
||||
EventsOn('downloadList', (data) => {
|
||||
if (data)
|
||||
commonStore.setDownloadList(data);
|
||||
});
|
||||
|
||||
initCache().then(initRemoteText);
|
||||
|
||||
await initConfig();
|
||||
|
||||
if (commonStore.settings.autoUpdatesCheck) // depends on config settings
|
||||
checkUpdate();
|
||||
|
||||
getStatus(500).then(status => { // depends on config api port
|
||||
if (status)
|
||||
commonStore.setModelStatus(status);
|
||||
});
|
||||
}
|
||||
|
||||
async function initRemoteText() {
|
||||
@ -33,7 +32,7 @@ async function initRemoteText() {
|
||||
commonStore.setIntroduction(data.introduction);
|
||||
if (data.about)
|
||||
commonStore.setAbout(data.about);
|
||||
});
|
||||
}).then(saveCache);
|
||||
}
|
||||
|
||||
async function initConfig() {
|
||||
@ -61,6 +60,8 @@ async function initCache() {
|
||||
commonStore.setIntroduction(cacheData.introduction);
|
||||
if (cacheData.about)
|
||||
commonStore.setAbout(cacheData.about);
|
||||
if (cacheData.depComplete)
|
||||
commonStore.setDepComplete(cacheData.depComplete);
|
||||
}).catch(() => {
|
||||
});
|
||||
await refreshModels(false);
|
||||
|
@ -24,6 +24,7 @@ class CommonStore {
|
||||
|
||||
// global
|
||||
modelStatus: ModelStatus = ModelStatus.Offline;
|
||||
depComplete: boolean = false;
|
||||
|
||||
// home
|
||||
introduction: IntroductionContent = manifest.introduction;
|
||||
@ -130,6 +131,10 @@ class CommonStore {
|
||||
this.about = value;
|
||||
};
|
||||
|
||||
setDepComplete = (value: boolean) => {
|
||||
this.depComplete = value;
|
||||
};
|
||||
|
||||
setDownloadList = (value: DownloadStatus[]) => {
|
||||
this.downloadList = value;
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {
|
||||
AddToDownloadList,
|
||||
DeleteFile,
|
||||
DownloadFile,
|
||||
FileExists,
|
||||
@ -23,6 +24,7 @@ export type Cache = {
|
||||
models: ModelSourceItem[]
|
||||
introduction: IntroductionContent,
|
||||
about: AboutContent
|
||||
depComplete: boolean
|
||||
}
|
||||
|
||||
export type LocalConfig = {
|
||||
@ -153,7 +155,8 @@ export const saveCache = async () => {
|
||||
const data: Cache = {
|
||||
models: commonStore.modelSourceList,
|
||||
introduction: commonStore.introduction,
|
||||
about: commonStore.about
|
||||
about: commonStore.about,
|
||||
depComplete: commonStore.depComplete
|
||||
};
|
||||
return SaveJson('cache.json', data);
|
||||
};
|
||||
@ -175,7 +178,7 @@ export function downloadProgramFiles() {
|
||||
manifest.programFiles.forEach(({url, path}) => {
|
||||
FileExists(path).then(exists => {
|
||||
if (!exists)
|
||||
DownloadFile(path, url);
|
||||
AddToDownloadList(path, url);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -188,7 +191,7 @@ export function forceDownloadProgramFiles() {
|
||||
|
||||
export function deletePythonProgramFiles() {
|
||||
manifest.programFiles.forEach(({path}) => {
|
||||
if (path.endsWith('.py'))
|
||||
if (path.endsWith('.py') && !path.includes('get-pip.py'))
|
||||
DeleteFile(path);
|
||||
});
|
||||
}
|
||||
@ -201,6 +204,10 @@ export function bytesToMb(size: number) {
|
||||
return (size / 1024 / 1024).toFixed(2);
|
||||
}
|
||||
|
||||
export function bytesToKb(size: number) {
|
||||
return (size / 1024).toFixed(2);
|
||||
}
|
||||
|
||||
export async function checkUpdate() {
|
||||
let updateUrl = '';
|
||||
await fetch('https://api.github.com/repos/josstorer/RWKV-Runner/releases/latest').then((r) => {
|
||||
@ -214,7 +221,7 @@ export async function checkUpdate() {
|
||||
deletePythonProgramFiles();
|
||||
setTimeout(() => {
|
||||
UpdateApp(updateUrl).catch((e) => {
|
||||
toast(t('Update Error, Please restart this program') + ' - ' + e.message, {
|
||||
toast(t('Update Error, Please restart this program') + ' - ' + e.message || e, {
|
||||
type: 'error',
|
||||
position: 'bottom-left',
|
||||
autoClose: false
|
||||
@ -235,7 +242,7 @@ export async function checkUpdate() {
|
||||
}
|
||||
}
|
||||
).catch((e) => {
|
||||
toast(t('Updates Check Error') + ' - ' + e.message, {type: 'error', position: 'bottom-left'});
|
||||
toast(t('Updates Check Error') + ' - ' + e.message || e, {type: 'error', position: 'bottom-left'});
|
||||
});
|
||||
return updateUrl;
|
||||
}
|
||||
|
6
frontend/wailsjs/go/backend_golang/App.d.ts
vendored
6
frontend/wailsjs/go/backend_golang/App.d.ts
vendored
@ -10,10 +10,16 @@ export function ConvertModel(arg1:string,arg2:string,arg3:string):Promise<string
|
||||
|
||||
export function DeleteFile(arg1:string):Promise<void>;
|
||||
|
||||
export function DepCheck():Promise<void>;
|
||||
|
||||
export function DownloadFile(arg1:string,arg2:string):Promise<void>;
|
||||
|
||||
export function FileExists(arg1:string):Promise<boolean>;
|
||||
|
||||
export function GetPlatform():Promise<string>;
|
||||
|
||||
export function InstallPyDep():Promise<string>;
|
||||
|
||||
export function ListDirFiles(arg1:string):Promise<Array<backend_golang.FileInfo>>;
|
||||
|
||||
export function OpenFileFolder(arg1:string):Promise<void>;
|
||||
|
@ -18,6 +18,10 @@ export function DeleteFile(arg1) {
|
||||
return window['go']['backend_golang']['App']['DeleteFile'](arg1);
|
||||
}
|
||||
|
||||
export function DepCheck() {
|
||||
return window['go']['backend_golang']['App']['DepCheck']();
|
||||
}
|
||||
|
||||
export function DownloadFile(arg1, arg2) {
|
||||
return window['go']['backend_golang']['App']['DownloadFile'](arg1, arg2);
|
||||
}
|
||||
@ -26,6 +30,14 @@ export function FileExists(arg1) {
|
||||
return window['go']['backend_golang']['App']['FileExists'](arg1);
|
||||
}
|
||||
|
||||
export function GetPlatform() {
|
||||
return window['go']['backend_golang']['App']['GetPlatform']();
|
||||
}
|
||||
|
||||
export function InstallPyDep() {
|
||||
return window['go']['backend_golang']['App']['InstallPyDep']();
|
||||
}
|
||||
|
||||
export function ListDirFiles(arg1) {
|
||||
return window['go']['backend_golang']['App']['ListDirFiles'](arg1);
|
||||
}
|
||||
|
@ -61,6 +61,10 @@
|
||||
{
|
||||
"url": "https://cdn.jsdelivr.net/gh/josstorer/RWKV-Runner/backend-python/20B_tokenizer.json",
|
||||
"path": "backend-python/20B_tokenizer.json"
|
||||
},
|
||||
{
|
||||
"url": "https://raw.githubusercontent.com/pypa/get-pip/main/public/get-pip.py",
|
||||
"path": "backend-python/get-pip.py"
|
||||
}
|
||||
],
|
||||
"models": [
|
||||
|
Loading…
Reference in New Issue
Block a user