downloads page
This commit is contained in:
parent
0761df8df5
commit
0f0281dd63
@ -25,12 +25,67 @@ type DownloadStatus struct {
|
|||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
Speed float64 `json:"speed"`
|
Speed float64 `json:"speed"`
|
||||||
Progress float64 `json:"progress"`
|
Progress float64 `json:"progress"`
|
||||||
|
Downloading bool `json:"downloading"`
|
||||||
Done bool `json:"done"`
|
Done bool `json:"done"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var downloadList []DownloadStatus
|
var downloadList []DownloadStatus
|
||||||
|
|
||||||
|
func existsInDownloadList(url string) bool {
|
||||||
|
for _, ds := range downloadList {
|
||||||
|
if ds.Url == url {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) PauseDownload(url string) {
|
||||||
|
for i, ds := range downloadList {
|
||||||
|
if ds.Url == url {
|
||||||
|
ds.resp.Cancel()
|
||||||
|
|
||||||
|
downloadList[i] = DownloadStatus{
|
||||||
|
resp: ds.resp,
|
||||||
|
Name: ds.Name,
|
||||||
|
Path: ds.Path,
|
||||||
|
Url: ds.Url,
|
||||||
|
Transferred: ds.Transferred,
|
||||||
|
Size: ds.Size,
|
||||||
|
Speed: 0,
|
||||||
|
Progress: ds.Progress,
|
||||||
|
Downloading: false,
|
||||||
|
Done: ds.Done,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) ContinueDownload(url string) {
|
||||||
|
for i, ds := range downloadList {
|
||||||
|
if ds.Url == url {
|
||||||
|
client := grab.NewClient()
|
||||||
|
req, _ := grab.NewRequest(ds.Path, ds.Url)
|
||||||
|
resp := client.Do(req)
|
||||||
|
|
||||||
|
downloadList[i] = DownloadStatus{
|
||||||
|
resp: resp,
|
||||||
|
Name: ds.Name,
|
||||||
|
Path: ds.Path,
|
||||||
|
Url: ds.Url,
|
||||||
|
Transferred: ds.Transferred,
|
||||||
|
Size: ds.Size,
|
||||||
|
Speed: ds.Speed,
|
||||||
|
Progress: ds.Progress,
|
||||||
|
Downloading: true,
|
||||||
|
Done: ds.Done,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) AddToDownloadList(path string, url string) {
|
func (a *App) AddToDownloadList(path string, url string) {
|
||||||
|
if !existsInDownloadList(url) {
|
||||||
client := grab.NewClient()
|
client := grab.NewClient()
|
||||||
req, _ := grab.NewRequest(path, url)
|
req, _ := grab.NewRequest(path, url)
|
||||||
resp := client.Do(req)
|
resp := client.Do(req)
|
||||||
@ -44,8 +99,10 @@ func (a *App) AddToDownloadList(path string, url string) {
|
|||||||
Size: 0,
|
Size: 0,
|
||||||
Speed: 0,
|
Speed: 0,
|
||||||
Progress: 0,
|
Progress: 0,
|
||||||
|
Downloading: true,
|
||||||
Done: false,
|
Done: false,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) downloadLoop() {
|
func (a *App) downloadLoop() {
|
||||||
@ -53,17 +110,18 @@ func (a *App) downloadLoop() {
|
|||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
<-ticker.C
|
<-ticker.C
|
||||||
for i, downloadStatus := range downloadList {
|
for i, ds := range downloadList {
|
||||||
downloadList[i] = DownloadStatus{
|
downloadList[i] = DownloadStatus{
|
||||||
resp: downloadStatus.resp,
|
resp: ds.resp,
|
||||||
Name: downloadStatus.Name,
|
Name: ds.Name,
|
||||||
Path: downloadStatus.Path,
|
Path: ds.Path,
|
||||||
Url: downloadStatus.Url,
|
Url: ds.Url,
|
||||||
Transferred: downloadStatus.resp.BytesComplete(),
|
Transferred: ds.resp.BytesComplete(),
|
||||||
Size: downloadStatus.resp.Size(),
|
Size: ds.resp.Size(),
|
||||||
Speed: downloadStatus.resp.BytesPerSecond(),
|
Speed: ds.resp.BytesPerSecond(),
|
||||||
Progress: 100 * downloadStatus.resp.Progress(),
|
Progress: 100 * ds.resp.Progress(),
|
||||||
Done: downloadStatus.resp.IsComplete(),
|
Downloading: !ds.resp.IsComplete(),
|
||||||
|
Done: ds.resp.Progress() == 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runtime.EventsEmit(a.ctx, "downloadList", downloadList)
|
runtime.EventsEmit(a.ctx, "downloadList", downloadList)
|
||||||
|
@ -84,5 +84,8 @@
|
|||||||
"Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.": "频率惩罚. 正值根据新token在至今的文本中出现的频率/次数, 来对其进行惩罚, 从而减少模型原封不动地重复相同句子的可能性",
|
"Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.": "频率惩罚. 正值根据新token在至今的文本中出现的频率/次数, 来对其进行惩罚, 从而减少模型原封不动地重复相同句子的可能性",
|
||||||
"int8 uses less VRAM, and is faster, but has slightly lower quality. fp16 has higher quality, and fp32 has the best quality.": "int8占用显存更低, 速度更快, 但质量略微下降. fp16质量更好, fp32质量最好",
|
"int8 uses less VRAM, and is faster, but has slightly lower quality. fp16 has higher quality, and fp32 has the best quality.": "int8占用显存更低, 速度更快, 但质量略微下降. fp16质量更好, fp32质量最好",
|
||||||
"Number of the neural network layers loaded into VRAM, the more you load, the faster the speed, but it consumes more VRAM.": "载入显存的神经网络层数, 载入越多, 速度越快, 但显存消耗越大",
|
"Number of the neural network layers loaded into VRAM, the more you load, the faster the speed, but it consumes more VRAM.": "载入显存的神经网络层数, 载入越多, 速度越快, 但显存消耗越大",
|
||||||
"Whether to use CPU to calculate the last output layer of the neural network with FP32 precision to obtain better quality.": "是否使用cpu以fp32精度计算神经网络的最后一层输出层, 以获得更好的质量"
|
"Whether to use CPU to calculate the last output layer of the neural network with FP32 precision to obtain better quality.": "是否使用cpu以fp32精度计算神经网络的最后一层输出层, 以获得更好的质量",
|
||||||
|
"Downloads": "下载",
|
||||||
|
"Pause": "暂停",
|
||||||
|
"Continue": "继续"
|
||||||
}
|
}
|
49
frontend/src/pages/Downloads.tsx
Normal file
49
frontend/src/pages/Downloads.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import React, {FC} from 'react';
|
||||||
|
import {useTranslation} from 'react-i18next';
|
||||||
|
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} 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';
|
||||||
|
|
||||||
|
export const Downloads: FC = observer(() => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
|
||||||
|
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">
|
||||||
|
<Field
|
||||||
|
key={index}
|
||||||
|
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}`}
|
||||||
|
validationState={status.done ? 'success' : 'none'}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<ProgressBar className="grow" value={status.progress} max={100}/>
|
||||||
|
{!status.done &&
|
||||||
|
<ToolTipButton desc={status.downloading ? t('Pause') : t('Continue')}
|
||||||
|
icon={status.downloading ? <Pause20Regular/> : <Play20Regular/>}
|
||||||
|
onClick={() => {
|
||||||
|
if (status.downloading)
|
||||||
|
PauseDownload(status.url);
|
||||||
|
else
|
||||||
|
ContinueDownload(status.url);
|
||||||
|
}}/>}
|
||||||
|
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular/>} onClick={() => {
|
||||||
|
OpenFileFolder(status.path);
|
||||||
|
}}/>
|
||||||
|
</div>
|
||||||
|
</Field>
|
||||||
|
<Divider style={{flexGrow: 0}}/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}/>
|
||||||
|
);
|
||||||
|
});
|
@ -21,7 +21,7 @@ import {AddToDownloadList, OpenFileFolder} from '../../wailsjs/go/backend_golang
|
|||||||
import manifest from '../../../manifest.json';
|
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 {bytesToGb, refreshModels, saveConfigs} from '../utils';
|
||||||
import {useTranslation} from 'react-i18next';
|
import {useTranslation} from 'react-i18next';
|
||||||
|
|
||||||
const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
||||||
@ -86,7 +86,7 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
renderCell: (item) => {
|
renderCell: (item) => {
|
||||||
return (
|
return (
|
||||||
<TableCellLayout>
|
<TableCellLayout>
|
||||||
{(item.size / (1024 * 1024 * 1024)).toFixed(2) + 'GB'}
|
{bytesToGb(item.size) + 'GB'}
|
||||||
</TableCellLayout>
|
</TableCellLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import { ReactElement } from "react";
|
import {ReactElement} from 'react';
|
||||||
import { Configs } from "./Configs";
|
import {Configs} from './Configs';
|
||||||
import {
|
import {
|
||||||
|
ArrowDownload20Regular,
|
||||||
Chat20Regular,
|
Chat20Regular,
|
||||||
DataUsageSettings20Regular,
|
DataUsageSettings20Regular,
|
||||||
DocumentSettings20Regular,
|
DocumentSettings20Regular,
|
||||||
Home20Regular, Info20Regular, Settings20Regular, Storage20Regular
|
Home20Regular,
|
||||||
|
Info20Regular,
|
||||||
|
Settings20Regular,
|
||||||
|
Storage20Regular
|
||||||
} from '@fluentui/react-icons';
|
} from '@fluentui/react-icons';
|
||||||
import {Home} from './Home';
|
import {Home} from './Home';
|
||||||
import {Chat} from './Chat';
|
import {Chat} from './Chat';
|
||||||
@ -12,6 +16,7 @@ import {Models} from './Models';
|
|||||||
import {Train} from './Train';
|
import {Train} from './Train';
|
||||||
import {Settings} from './Settings';
|
import {Settings} from './Settings';
|
||||||
import {About} from './About';
|
import {About} from './About';
|
||||||
|
import {Downloads} from './Downloads';
|
||||||
|
|
||||||
type NavigationItem = {
|
type NavigationItem = {
|
||||||
label: string;
|
label: string;
|
||||||
@ -23,52 +28,59 @@ type NavigationItem = {
|
|||||||
|
|
||||||
export const pages: NavigationItem[] = [
|
export const pages: NavigationItem[] = [
|
||||||
{
|
{
|
||||||
label: "Home",
|
label: 'Home',
|
||||||
path: "/",
|
path: '/',
|
||||||
icon:<Home20Regular />,
|
icon: <Home20Regular/>,
|
||||||
element: <Home />,
|
element: <Home/>,
|
||||||
top: true,
|
top: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Chat",
|
label: 'Chat',
|
||||||
path: "/chat",
|
path: '/chat',
|
||||||
icon:<Chat20Regular />,
|
icon: <Chat20Regular/>,
|
||||||
element: <Chat />,
|
element: <Chat/>,
|
||||||
top:true
|
top: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Configs",
|
label: 'Configs',
|
||||||
path: "/configs",
|
path: '/configs',
|
||||||
icon:<DocumentSettings20Regular />,
|
icon: <DocumentSettings20Regular/>,
|
||||||
element: <Configs />,
|
element: <Configs/>,
|
||||||
top:true
|
top: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Models",
|
label: 'Models',
|
||||||
path: "/models",
|
path: '/models',
|
||||||
icon:<DataUsageSettings20Regular />,
|
icon: <DataUsageSettings20Regular/>,
|
||||||
element: <Models />,
|
element: <Models/>,
|
||||||
top:true
|
top: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Train",
|
label: 'Downloads',
|
||||||
path: "/train",
|
path: '/downloads',
|
||||||
icon:<Storage20Regular />,
|
icon: <ArrowDownload20Regular/>,
|
||||||
element: <Train />,
|
element: <Downloads/>,
|
||||||
top:true
|
top: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Settings",
|
label: 'Train',
|
||||||
path: "/settings",
|
path: '/train',
|
||||||
icon:<Settings20Regular />,
|
icon: <Storage20Regular/>,
|
||||||
element: <Settings />,
|
element: <Train/>,
|
||||||
top:false
|
top: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "About",
|
label: 'Settings',
|
||||||
path: "/about",
|
path: '/settings',
|
||||||
icon:<Info20Regular />,
|
icon: <Settings20Regular/>,
|
||||||
element: <About />,
|
element: <Settings/>,
|
||||||
top:false
|
top: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'About',
|
||||||
|
path: '/about',
|
||||||
|
icon: <Info20Regular/>,
|
||||||
|
element: <About/>,
|
||||||
|
top: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -60,6 +60,7 @@ export type DownloadStatus = {
|
|||||||
size: number;
|
size: number;
|
||||||
speed: number;
|
speed: number;
|
||||||
progress: number;
|
progress: number;
|
||||||
|
downloading: boolean;
|
||||||
done: boolean;
|
done: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,6 +196,14 @@ export function deletePythonProgramFiles() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function bytesToGb(size: number) {
|
||||||
|
return (size / 1024 / 1024 / 1024).toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bytesToMb(size: number) {
|
||||||
|
return (size / 1024 / 1024).toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
export async function checkUpdate() {
|
export async function checkUpdate() {
|
||||||
let updateUrl = '';
|
let updateUrl = '';
|
||||||
await fetch('https://api.github.com/repos/josstorer/RWKV-Runner/releases/latest').then((r) => {
|
await fetch('https://api.github.com/repos/josstorer/RWKV-Runner/releases/latest').then((r) => {
|
||||||
|
4
frontend/wailsjs/go/backend_golang/App.d.ts
vendored
4
frontend/wailsjs/go/backend_golang/App.d.ts
vendored
@ -4,6 +4,8 @@ import {backend_golang} from '../models';
|
|||||||
|
|
||||||
export function AddToDownloadList(arg1:string,arg2:string):Promise<void>;
|
export function AddToDownloadList(arg1:string,arg2:string):Promise<void>;
|
||||||
|
|
||||||
|
export function ContinueDownload(arg1:string):Promise<void>;
|
||||||
|
|
||||||
export function ConvertModel(arg1:string,arg2:string,arg3:string):Promise<string>;
|
export function ConvertModel(arg1:string,arg2:string,arg3:string):Promise<string>;
|
||||||
|
|
||||||
export function DeleteFile(arg1:string):Promise<void>;
|
export function DeleteFile(arg1:string):Promise<void>;
|
||||||
@ -16,6 +18,8 @@ export function ListDirFiles(arg1:string):Promise<Array<backend_golang.FileInfo>
|
|||||||
|
|
||||||
export function OpenFileFolder(arg1:string):Promise<void>;
|
export function OpenFileFolder(arg1:string):Promise<void>;
|
||||||
|
|
||||||
|
export function PauseDownload(arg1:string):Promise<void>;
|
||||||
|
|
||||||
export function ReadFileInfo(arg1:string):Promise<backend_golang.FileInfo>;
|
export function ReadFileInfo(arg1:string):Promise<backend_golang.FileInfo>;
|
||||||
|
|
||||||
export function ReadJson(arg1:string):Promise<any>;
|
export function ReadJson(arg1:string):Promise<any>;
|
||||||
|
@ -6,6 +6,10 @@ export function AddToDownloadList(arg1, arg2) {
|
|||||||
return window['go']['backend_golang']['App']['AddToDownloadList'](arg1, arg2);
|
return window['go']['backend_golang']['App']['AddToDownloadList'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ContinueDownload(arg1) {
|
||||||
|
return window['go']['backend_golang']['App']['ContinueDownload'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function ConvertModel(arg1, arg2, arg3) {
|
export function ConvertModel(arg1, arg2, arg3) {
|
||||||
return window['go']['backend_golang']['App']['ConvertModel'](arg1, arg2, arg3);
|
return window['go']['backend_golang']['App']['ConvertModel'](arg1, arg2, arg3);
|
||||||
}
|
}
|
||||||
@ -30,6 +34,10 @@ export function OpenFileFolder(arg1) {
|
|||||||
return window['go']['backend_golang']['App']['OpenFileFolder'](arg1);
|
return window['go']['backend_golang']['App']['OpenFileFolder'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function PauseDownload(arg1) {
|
||||||
|
return window['go']['backend_golang']['App']['PauseDownload'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function ReadFileInfo(arg1) {
|
export function ReadFileInfo(arg1) {
|
||||||
return window['go']['backend_golang']['App']['ReadFileInfo'](arg1);
|
return window['go']['backend_golang']['App']['ReadFileInfo'](arg1);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user