downloads page

This commit is contained in:
josc146 2023-05-20 13:46:33 +08:00
parent 0761df8df5
commit 0f0281dd63
9 changed files with 231 additions and 88 deletions

View File

@ -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,26 +99,29 @@ 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() {
ticker := time.NewTicker(500 * time.Millisecond) ticker := time.NewTicker(500 * time.Millisecond)
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)

View File

@ -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": "继续"
} }

View 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>
}/>
);
});

View File

@ -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>
); );
} }

View File

@ -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,50 +28,57 @@ 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: <ArrowDownload20Regular/>,
element: <Downloads/>,
top: true
},
{
label: 'Train',
path: '/train',
icon: <Storage20Regular/>, icon: <Storage20Regular/>,
element: <Train/>, element: <Train/>,
top: true top: true
}, },
{ {
label: "Settings", label: 'Settings',
path: "/settings", path: '/settings',
icon: <Settings20Regular/>, icon: <Settings20Regular/>,
element: <Settings/>, element: <Settings/>,
top: false top: false
}, },
{ {
label: "About", label: 'About',
path: "/about", path: '/about',
icon: <Info20Regular/>, icon: <Info20Regular/>,
element: <About/>, element: <About/>,
top: false top: false

View File

@ -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;
} }

View File

@ -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) => {

View File

@ -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>;

View File

@ -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);
} }