From 0f0281dd63f042ab06508ee2c78ee7a229ce0aef Mon Sep 17 00:00:00 2001 From: josc146 Date: Sat, 20 May 2023 13:46:33 +0800 Subject: [PATCH] downloads page --- backend-golang/download.go | 108 ++++++++++++---- frontend/src/_locales/zh-hans/main.json | 5 +- frontend/src/pages/Downloads.tsx | 49 ++++++++ frontend/src/pages/Models.tsx | 4 +- frontend/src/pages/index.tsx | 132 +++++++++++--------- frontend/src/stores/commonStore.ts | 1 + frontend/src/utils/index.tsx | 8 ++ frontend/wailsjs/go/backend_golang/App.d.ts | 4 + frontend/wailsjs/go/backend_golang/App.js | 8 ++ 9 files changed, 231 insertions(+), 88 deletions(-) create mode 100644 frontend/src/pages/Downloads.tsx diff --git a/backend-golang/download.go b/backend-golang/download.go index 397f601..501d9b6 100644 --- a/backend-golang/download.go +++ b/backend-golang/download.go @@ -25,27 +25,84 @@ type DownloadStatus struct { Size int64 `json:"size"` Speed float64 `json:"speed"` Progress float64 `json:"progress"` + Downloading bool `json:"downloading"` Done bool `json:"done"` } var downloadList []DownloadStatus -func (a *App) AddToDownloadList(path string, url string) { - client := grab.NewClient() - req, _ := grab.NewRequest(path, url) - resp := client.Do(req) +func existsInDownloadList(url string) bool { + for _, ds := range downloadList { + if ds.Url == url { + return true + } + } + return false +} - downloadList = append(downloadList, DownloadStatus{ - resp: resp, - Name: filepath.Base(path), - Path: path, - Url: url, - Transferred: 0, - Size: 0, - Speed: 0, - Progress: 0, - Done: 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) { + if !existsInDownloadList(url) { + client := grab.NewClient() + req, _ := grab.NewRequest(path, url) + resp := client.Do(req) + + downloadList = append(downloadList, DownloadStatus{ + resp: resp, + Name: filepath.Base(path), + Path: path, + Url: url, + Transferred: 0, + Size: 0, + Speed: 0, + Progress: 0, + Downloading: true, + Done: false, + }) + } } func (a *App) downloadLoop() { @@ -53,17 +110,18 @@ func (a *App) downloadLoop() { go func() { for { <-ticker.C - for i, downloadStatus := range downloadList { + for i, ds := range downloadList { downloadList[i] = DownloadStatus{ - resp: downloadStatus.resp, - Name: downloadStatus.Name, - Path: downloadStatus.Path, - Url: downloadStatus.Url, - Transferred: downloadStatus.resp.BytesComplete(), - Size: downloadStatus.resp.Size(), - Speed: downloadStatus.resp.BytesPerSecond(), - Progress: 100 * downloadStatus.resp.Progress(), - Done: downloadStatus.resp.IsComplete(), + resp: ds.resp, + Name: ds.Name, + Path: ds.Path, + Url: ds.Url, + Transferred: ds.resp.BytesComplete(), + Size: ds.resp.Size(), + Speed: ds.resp.BytesPerSecond(), + Progress: 100 * ds.resp.Progress(), + Downloading: !ds.resp.IsComplete(), + Done: ds.resp.Progress() == 1, } } runtime.EventsEmit(a.ctx, "downloadList", downloadList) diff --git a/frontend/src/_locales/zh-hans/main.json b/frontend/src/_locales/zh-hans/main.json index 9e5eb0f..94c6f93 100644 --- a/frontend/src/_locales/zh-hans/main.json +++ b/frontend/src/_locales/zh-hans/main.json @@ -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在至今的文本中出现的频率/次数, 来对其进行惩罚, 从而减少模型原封不动地重复相同句子的可能性", "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.": "载入显存的神经网络层数, 载入越多, 速度越快, 但显存消耗越大", - "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": "继续" } \ No newline at end of file diff --git a/frontend/src/pages/Downloads.tsx b/frontend/src/pages/Downloads.tsx new file mode 100644 index 0000000..d9d7bd7 --- /dev/null +++ b/frontend/src/pages/Downloads.tsx @@ -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 ( + + {commonStore.downloadList.map((status, index) => ( +
+ +
+ + {!status.done && + : } + onClick={() => { + if (status.downloading) + PauseDownload(status.url); + else + ContinueDownload(status.url); + }}/>} + } onClick={() => { + OpenFileFolder(status.path); + }}/> +
+
+ +
+ )) + } + + }/> + ); +}); diff --git a/frontend/src/pages/Models.tsx b/frontend/src/pages/Models.tsx index bc3828c..473bc92 100644 --- a/frontend/src/pages/Models.tsx +++ b/frontend/src/pages/Models.tsx @@ -21,7 +21,7 @@ import {AddToDownloadList, OpenFileFolder} from '../../wailsjs/go/backend_golang import manifest from '../../../manifest.json'; import {toast} from 'react-toastify'; import {Page} from '../components/Page'; -import {refreshModels, saveConfigs} from '../utils'; +import {bytesToGb, refreshModels, saveConfigs} from '../utils'; import {useTranslation} from 'react-i18next'; const columns: TableColumnDefinition[] = [ @@ -86,7 +86,7 @@ const columns: TableColumnDefinition[] = [ renderCell: (item) => { return ( - {(item.size / (1024 * 1024 * 1024)).toFixed(2) + 'GB'} + {bytesToGb(item.size) + 'GB'} ); } diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index 9030121..933d745 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -1,10 +1,14 @@ -import { ReactElement } from "react"; -import { Configs } from "./Configs"; +import {ReactElement} from 'react'; +import {Configs} from './Configs'; import { - Chat20Regular, - DataUsageSettings20Regular, - DocumentSettings20Regular, - Home20Regular, Info20Regular, Settings20Regular, Storage20Regular + ArrowDownload20Regular, + Chat20Regular, + DataUsageSettings20Regular, + DocumentSettings20Regular, + Home20Regular, + Info20Regular, + Settings20Regular, + Storage20Regular } from '@fluentui/react-icons'; import {Home} from './Home'; import {Chat} from './Chat'; @@ -12,63 +16,71 @@ import {Models} from './Models'; import {Train} from './Train'; import {Settings} from './Settings'; import {About} from './About'; +import {Downloads} from './Downloads'; type NavigationItem = { - label: string; - path: string; - icon: ReactElement; - element: ReactElement; - top: boolean; + label: string; + path: string; + icon: ReactElement; + element: ReactElement; + top: boolean; }; export const pages: NavigationItem[] = [ - { - label: "Home", - path: "/", - icon:, - element: , - top: true, - }, - { - label: "Chat", - path: "/chat", - icon:, - element: , - top:true - }, - { - label: "Configs", - path: "/configs", - icon:, - element: , - top:true - }, - { - label: "Models", - path: "/models", - icon:, - element: , - top:true - }, - { - label: "Train", - path: "/train", - icon:, - element: , - top:true - }, - { - label: "Settings", - path: "/settings", - icon:, - element: , - top:false - }, - { - label: "About", - path: "/about", - icon:, - element: , - top:false - } + { + label: 'Home', + path: '/', + icon: , + element: , + top: true + }, + { + label: 'Chat', + path: '/chat', + icon: , + element: , + top: true + }, + { + label: 'Configs', + path: '/configs', + icon: , + element: , + top: true + }, + { + label: 'Models', + path: '/models', + icon: , + element: , + top: true + }, + { + label: 'Downloads', + path: '/downloads', + icon: , + element: , + top: true + }, + { + label: 'Train', + path: '/train', + icon: , + element: , + top: true + }, + { + label: 'Settings', + path: '/settings', + icon: , + element: , + top: false + }, + { + label: 'About', + path: '/about', + icon: , + element: , + top: false + } ]; diff --git a/frontend/src/stores/commonStore.ts b/frontend/src/stores/commonStore.ts index f8df3bb..12b8180 100644 --- a/frontend/src/stores/commonStore.ts +++ b/frontend/src/stores/commonStore.ts @@ -60,6 +60,7 @@ export type DownloadStatus = { size: number; speed: number; progress: number; + downloading: boolean; done: boolean; } diff --git a/frontend/src/utils/index.tsx b/frontend/src/utils/index.tsx index 93ab70c..8dc159c 100644 --- a/frontend/src/utils/index.tsx +++ b/frontend/src/utils/index.tsx @@ -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() { let updateUrl = ''; await fetch('https://api.github.com/repos/josstorer/RWKV-Runner/releases/latest').then((r) => { diff --git a/frontend/wailsjs/go/backend_golang/App.d.ts b/frontend/wailsjs/go/backend_golang/App.d.ts index f75492d..c844e11 100644 --- a/frontend/wailsjs/go/backend_golang/App.d.ts +++ b/frontend/wailsjs/go/backend_golang/App.d.ts @@ -4,6 +4,8 @@ import {backend_golang} from '../models'; export function AddToDownloadList(arg1:string,arg2:string):Promise; +export function ContinueDownload(arg1:string):Promise; + export function ConvertModel(arg1:string,arg2:string,arg3:string):Promise; export function DeleteFile(arg1:string):Promise; @@ -16,6 +18,8 @@ export function ListDirFiles(arg1:string):Promise export function OpenFileFolder(arg1:string):Promise; +export function PauseDownload(arg1:string):Promise; + export function ReadFileInfo(arg1:string):Promise; export function ReadJson(arg1:string):Promise; diff --git a/frontend/wailsjs/go/backend_golang/App.js b/frontend/wailsjs/go/backend_golang/App.js index 9e2a9d8..3fa22f1 100644 --- a/frontend/wailsjs/go/backend_golang/App.js +++ b/frontend/wailsjs/go/backend_golang/App.js @@ -6,6 +6,10 @@ export function 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) { 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); } +export function PauseDownload(arg1) { + return window['go']['backend_golang']['App']['PauseDownload'](arg1); +} + export function ReadFileInfo(arg1) { return window['go']['backend_golang']['App']['ReadFileInfo'](arg1); }