This commit is contained in:
josc146
2023-05-06 20:17:39 +08:00
parent f6be32825f
commit ac3e34e1d8
18 changed files with 101037 additions and 295 deletions

View File

@@ -13,7 +13,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^6.11.0",
"react-router-dom": "^6.11.0"
"react-router-dom": "^6.11.0",
"usehooks-ts": "^2.9.1"
},
"devDependencies": {
"@types/react": "^18.0.17",
@@ -3315,6 +3316,22 @@
"react-dom": ">=16.8.0 <19.0.0"
}
},
"node_modules/usehooks-ts": {
"version": "2.9.1",
"resolved": "https://registry.npmmirror.com/usehooks-ts/-/usehooks-ts-2.9.1.tgz",
"integrity": "sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==",
"workspaces": [
"packages/eslint-config-custom"
],
"engines": {
"node": ">=16.15.0",
"npm": ">=8"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",

View File

@@ -14,7 +14,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^6.11.0",
"react-router-dom": "^6.11.0"
"react-router-dom": "^6.11.0",
"usehooks-ts": "^2.9.1"
},
"devDependencies": {
"@types/react": "^18.0.17",

View File

@@ -27,10 +27,12 @@ import {FluentProvider, Tab, TabList, webDarkTheme} from '@fluentui/react-compon
import {FC, useEffect, useState} from 'react';
import {Route, Routes, useLocation, useNavigate} from 'react-router';
import {pages} from './Pages';
import {useMediaQuery} from 'usehooks-ts';
const App: FC = () => {
const navigate = useNavigate();
const location = useLocation();
const mq = useMediaQuery('(min-width: 640px)');
const [path, setPath] = useState<string>(pages[0].path);
@@ -42,7 +44,7 @@ const App: FC = () => {
return (
<FluentProvider theme={webDarkTheme} className="h-screen">
<div className="flex h-full">
<div className="flex flex-col w-40 p-2 justify-between">
<div className="flex flex-col w-16 sm:w-48 p-2 justify-between">
<TabList
size="large"
appearance="subtle"
@@ -50,9 +52,9 @@ const App: FC = () => {
onTabSelect={(_, {value}) => selectTab(value)}
vertical
>
{pages.filter(page=>page.top).map(({label, path, icon}, index) => (
{pages.filter(page => page.top).map(({label, path, icon}, index) => (
<Tab icon={icon} key={`${path}-${index}`} value={path}>
{label}
{mq && label}
</Tab>
))}
</TabList>
@@ -63,9 +65,9 @@ const App: FC = () => {
onTabSelect={(_, {value}) => selectTab(value)}
vertical
>
{pages.filter(page=>!page.top).map(({label, path, icon}, index) => (
{pages.filter(page => !page.top).map(({label, path, icon}, index) => (
<Tab icon={icon} key={`${path}-${index}`} value={path}>
{label}
{mq && label}
</Tab>
))}
</TabList>

View File

@@ -1,269 +1,86 @@
import {
Avatar,
Button,
createTableColumn,
Dropdown,
Input,
PresenceBadgeStatus,
Select,
Slider,
Switch,
TableCellLayout,
TableColumnDefinition,
Text,
Tooltip
} from '@fluentui/react-components';
import {
AddCircle20Regular,
Delete20Regular,
DocumentPdfRegular,
DocumentRegular,
EditRegular,
FolderRegular,
OpenRegular,
PeopleRegular,
Save20Regular,
VideoRegular
} from '@fluentui/react-icons';
import {Button, Divider, Dropdown, Input, Option, Slider, Switch, Text} from '@fluentui/react-components';
import {AddCircle20Regular, DataUsageSettings20Regular, Delete20Regular, Save20Regular} from '@fluentui/react-icons';
import React, {FC} from 'react';
import {Section} from './components/Section';
import {Labeled} from './components/Labeled';
import {ToolTipButton} from './components/ToolTipButton';
type FileCell = {
label: string;
icon: JSX.Element;
};
type LastUpdatedCell = {
label: string;
timestamp: number;
};
type LastUpdateCell = {
label: string;
icon: JSX.Element;
};
type AuthorCell = {
label: string;
status: PresenceBadgeStatus;
};
type Item = {
file: FileCell;
author: AuthorCell;
lastUpdated: LastUpdatedCell;
lastUpdate: LastUpdateCell;
};
const items: Item[] = [
{
file: {label: 'Meeting notes', icon: <DocumentRegular/>},
author: {label: 'Max Mustermann', status: 'available'},
lastUpdated: {label: '7h ago', timestamp: 1},
lastUpdate: {
label: 'You edited this',
icon: <EditRegular/>
}
},
{
file: {label: 'Thursday presentation', icon: <FolderRegular/>},
author: {label: 'Erika Mustermann', status: 'busy'},
lastUpdated: {label: 'Yesterday at 1:45 PM', timestamp: 2},
lastUpdate: {
label: 'You recently opened this',
icon: <OpenRegular/>
}
},
{
file: {label: 'Training recording', icon: <VideoRegular/>},
author: {label: 'John Doe', status: 'away'},
lastUpdated: {label: 'Yesterday at 1:45 PM', timestamp: 2},
lastUpdate: {
label: 'You recently opened this',
icon: <OpenRegular/>
}
},
{
file: {label: 'Purchase order', icon: <DocumentPdfRegular/>},
author: {label: 'Jane Doe', status: 'offline'},
lastUpdated: {label: 'Tue at 9:30 AM', timestamp: 3},
lastUpdate: {
label: 'You shared this in a Teams chat',
icon: <PeopleRegular/>
}
}
];
const columns: TableColumnDefinition<Item>[] = [
createTableColumn<Item>({
columnId: 'file',
compare: (a, b) => {
return a.file.label.localeCompare(b.file.label);
},
renderHeaderCell: () => {
return 'File';
},
renderCell: (item) => {
return (
<TableCellLayout media={item.file.icon}>
{item.file.label}
</TableCellLayout>
);
}
}),
createTableColumn<Item>({
columnId: 'author',
compare: (a, b) => {
return a.author.label.localeCompare(b.author.label);
},
renderHeaderCell: () => {
return 'Author';
},
renderCell: (item) => {
return (
<TableCellLayout
media={
<Avatar
aria-label={item.author.label}
name={item.author.label}
badge={{status: item.author.status}}
/>
}
>
{item.author.label}
</TableCellLayout>
);
}
}),
createTableColumn<Item>({
columnId: 'lastUpdated',
compare: (a, b) => {
return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
},
renderHeaderCell: () => {
return 'Last updated';
},
renderCell: (item) => {
return item.lastUpdated.label;
}
}),
createTableColumn<Item>({
columnId: 'lastUpdate',
compare: (a, b) => {
return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
},
renderHeaderCell: () => {
return 'Last update';
},
renderCell: (item) => {
return (
<TableCellLayout media={item.lastUpdate.icon}>
{item.lastUpdate.label}
</TableCellLayout>
);
}
})
];
// <DataGrid
// items={items}
// columns={columns}
// >
// <DataGridBody<Item>>
// {({ item, rowId }) => (
// <DataGridRow<Item> key={rowId}>
// {({ renderCell }) => (
// <DataGridCell>{renderCell(item)}</DataGridCell>
// )}
// </DataGridRow>
// )}
// </DataGridBody>
// </DataGrid>
export const Configs: FC = () => {
return (
<div className="flex flex-col box-border gap-5 p-2">
<div className="flex flex-col gap-2 p-2 h-full">
<Text size={600}>Configs</Text>
<Section
title="Config List"
content={
<div className="flex gap-5 items-center w-full">
<Dropdown className="w-full"/>
<ToolTipButton desc="New Config" icon={<AddCircle20Regular/>}/>
<ToolTipButton desc="Delete Config" icon={<Delete20Regular/>}/>
<ToolTipButton desc="Save Config" icon={<Save20Regular/>}/>
</div>
}
/>
<Section
title="Default API Parameters"
desc="Hover your mouse over the text to view a detailed description. Settings marked with * will take effect immediately after being saved."
content={
<div className="flex flex-col gap-1">
<div className="grid grid-cols-2">
<Divider/>
<div className="flex gap-2 items-center w-full">
<Dropdown style={{minWidth: 0}} className="grow"/>
<ToolTipButton desc="New Config" icon={<AddCircle20Regular/>}/>
<ToolTipButton desc="Delete Config" icon={<Delete20Regular/>}/>
<ToolTipButton desc="Save Config" icon={<Save20Regular/>}/>
</div>
<div className="flex flex-col h-full gap-2 overflow-y-hidden">
<Section
title="Default API Parameters"
desc="Hover your mouse over the text to view a detailed description. Settings marked with * will take effect immediately after being saved."
content={
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
<Labeled label="API Port" desc="127.0.0.1:8000" content={
<Input type="number" min={1} max={65535} step={1}/>
}/>
<Labeled label="Max Response Token *" content={
<div className="flex items-center">
<Slider className="w-48" step={400} min={100} max={8100}/>
<div className="flex items-center grow">
<Slider style={{minWidth: 0}} className="grow" step={400} min={100} max={8100}/>
<Text>1000</Text>
</div>
}/>
</div>
<div className="grid grid-cols-2">
<Labeled label="Temperature *" content={
<Slider/>
<Slider style={{minWidth: 0}} className="grow"/>
}/>
<Labeled label="Top_P *" content={
<Slider/>
<Slider style={{minWidth: 0}} className="grow"/>
}/>
</div>
<div className="grid grid-cols-2">
<Labeled label="Presence Penalty *" content={
<Slider/>
<Slider style={{minWidth: 0}} className="grow"/>
}/>
<Labeled label="Count Penalty *" content={
<Slider/>
<Slider style={{minWidth: 0}} className="grow"/>
}/>
</div>
</div>
}
/>
<Section
title="Model Parameters"
content={
<div className="flex flex-col gap-1">
<div className="grid grid-cols-2">
}
/>
<Section
title="Model Parameters"
content={
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
<Labeled label="Model" content={
<div className="flex gap-2 grow">
<Dropdown style={{minWidth: 0}} className="grow"/>
<ToolTipButton desc="Manage Models" icon={<DataUsageSettings20Regular/>}/>
</div>
}/>
<div/>
<Labeled label="Device" content={
<Select className="w-28">
<option>CPU</option>
<option>CUDA: 0</option>
</Select>
<Dropdown style={{minWidth: 0}} className="grow">
<Option>CPU</Option>
<Option>CUDA: 0</Option>
</Dropdown>
}/>
<Labeled label="Precision" content={
<Select className="w-28">
<option>fp16</option>
<option>int8</option>
<option>fp32</option>
</Select>
<Dropdown style={{minWidth: 0}} className="grow">
<Option>fp16</Option>
<Option>int8</Option>
<Option>fp32</Option>
</Dropdown>
}/>
</div>
<div className="grid grid-cols-2">
<Labeled label="Streamed Layers" content={
<Slider/>
<Slider style={{minWidth: 0}} className="grow"/>
}/>
<Labeled label="Enable High Precision For Last Layer" content={
<Switch/>
}/>
</div>
</div>
}
/>
<div className="fixed bottom-2 right-2">
}
/>
</div>
<div className="flex flex-row-reverse sm:fixed bottom-2 right-2">
<Button appearance="primary" size="large">Run</Button>
</div>
</div>

View File

@@ -8,7 +8,7 @@ import {
Storage20Regular
} from '@fluentui/react-icons';
import {useNavigate} from 'react-router';
import {SaveConfig} from '../../wailsjs/go/backend_golang/App';
import {SaveJson} from '../../wailsjs/go/backend_golang/App';
type NavCard = {
label: string;
@@ -55,10 +55,10 @@ export const Home: FC = () => {
return (
<div className="flex flex-col justify-between h-full">
<img className="rounded-xl select-none" src={Banner}/>
<img className="rounded-xl select-none hidden sm:block" src={Banner}/>
<div className="flex flex-col gap-2">
<Text size={600} weight="medium">Introduction</Text>
<Text size={300}>
<div className="h-40 overflow-y-auto">
RWKV is an RNN with Transformer-level LLM performance, which can also be directly trained like a GPT
transformer (parallelizable). And it's 100% attention-free. You only need the hidden state at position t to
compute the state at position t+1. You can use the "GPT" mode to quickly compute the hidden state for the
@@ -66,43 +66,47 @@ export const Home: FC = () => {
<br/>
So it's combining the best of RNN and transformer - great performance, fast inference, saves VRAM, fast
training, "infinite" ctx_len, and free sentence embedding (using the final hidden state).
</Text>
</div>
</div>
<div className="flex justify-between">
<div className="grid grid-cols-2 sm:grid-cols-4 gap-5">
{navCards.map(({label, path, icon, desc}, index) => (
<CompoundButton className="w-1/5" icon={icon} secondaryContent={desc} key={`${path}-${index}`} value={path}
<CompoundButton icon={icon} secondaryContent={desc} key={`${path}-${index}`} value={path}
size="large" onClick={() => onClickNavCard(path)}>
{label}
</CompoundButton>
))}
</div>
<div className="flex justify-between">
<div className="flex flex-col gap-2">
<div className="flex flex-row-reverse sm:fixed bottom-2 right-2">
<div className="flex gap-3">
<Dropdown style={{minWidth: 0}}
placeholder="Config"
value={selectedConfig}
onOptionSelect={(_, data) => {
if (data.optionValue)
setSelectedConfig(data.optionValue);
}}>
<Option id="item-1" key="item-1">
RWKV-3B-4G MEM
</Option>
<Option id="item-2" key="item-2">
Item 2
</Option>
<Option id="item-3" key="item-3">
Item 3
</Option>
<Option id="item-4" key="item-4">
Item 4
</Option>
</Dropdown>
<Button appearance="primary" size="large"
onClick={() => SaveJson('config.json', {a: 1234, b: 'test'})}>Run</Button>
</div>
</div>
<div className="flex gap-4 items-end">
Version: 1.0.0
<Link>Help</Link>
</div>
<div className="flex gap-3">
<Dropdown placeholder="Config"
value={selectedConfig}
onOptionSelect={(_, data) => {
if (data.optionValue)
setSelectedConfig(data.optionValue);
}}>
<Option id="item-1" key="item-1">
RWKV-3B-4G MEM
</Option>
<Option id="item-2" key="item-2">
Item 2
</Option>
<Option id="item-3" key="item-3">
Item 3
</Option>
<Option id="item-4" key="item-4">
Item 4
</Option>
</Dropdown>
<Button appearance="primary" size="large" onClick={() => SaveConfig({a: 1234, b: 'test'})}>Run</Button>
</div>
</div>
</div>
);

View File

@@ -1,10 +1,167 @@
import React, {FC} from 'react';
import {Text} from '@fluentui/react-components';
import React, {FC, useEffect} from 'react';
import {
createTableColumn,
DataGrid,
DataGridBody,
DataGridCell,
DataGridHeader,
DataGridHeaderCell,
DataGridRow,
TableCellLayout,
TableColumnDefinition,
Text,
Textarea
} from '@fluentui/react-components';
import {EditRegular} from '@fluentui/react-icons/lib/fonts';
import {ToolTipButton} from './components/ToolTipButton';
import {ArrowClockwise20Regular} from '@fluentui/react-icons';
type Operation = {
icon: JSX.Element;
desc: string
}
type Item = {
filename: string;
desc: string;
size: number;
lastUpdated: number;
actions: Operation[];
isLocal: boolean;
};
const items: Item[] = [
{
filename: 'RWKV-4-Raven-14B-v11x-Eng99%-Other1%-20230501-ctx8192.pth',
desc: 'Mainly English language corpus',
size: 28297309490,
lastUpdated: 1,
actions: [{icon: <EditRegular/>, desc: 'Edit'}],
isLocal: false
}
];
const columns: TableColumnDefinition<Item>[] = [
createTableColumn<Item>({
columnId: 'file',
compare: (a, b) => {
return a.filename.localeCompare(b.filename);
},
renderHeaderCell: () => {
return 'File';
},
renderCell: (item) => {
return (
<TableCellLayout className="break-all">
{item.filename}
</TableCellLayout>
);
}
}),
createTableColumn<Item>({
columnId: 'desc',
compare: (a, b) => {
return a.desc.localeCompare(b.desc);
},
renderHeaderCell: () => {
return 'Desc';
},
renderCell: (item) => {
return (
<TableCellLayout>
{item.desc}
</TableCellLayout>
);
}
}),
createTableColumn<Item>({
columnId: 'size',
compare: (a, b) => {
return a.size - b.size;
},
renderHeaderCell: () => {
return 'Size';
},
renderCell: (item) => {
return (
<TableCellLayout>
{(item.size / (1024 * 1024 * 1024)).toFixed(2) + 'GB'}
</TableCellLayout>
);
}
}),
createTableColumn<Item>({
columnId: 'lastUpdated',
compare: (a, b) => {
return a.lastUpdated - b.lastUpdated;
},
renderHeaderCell: () => {
return 'Last updated';
},
renderCell: (item) => {
return new Date(item.lastUpdated).toLocaleString();
}
}),
createTableColumn<Item>({
columnId: 'actions',
compare: (a, b) => {
return a.isLocal === b.isLocal ? 0 : a.isLocal ? -1 : 1;
},
renderHeaderCell: () => {
return 'Actions';
},
renderCell: (item) => {
return (
<TableCellLayout>
</TableCellLayout>
);
}
})
];
export const Models: FC = () => {
useEffect(() => {
fetch('https://cdn.jsdelivr.net/gh/josstorer/RWKV-Runner/manifest.json')
.then(
res => res.json().then(console.log)
);
}, []);
return (
<div className="flex flex-col box-border gap-5 p-2">
<Text size={600}>In Development</Text>
<div className="flex flex-col gap-1">
<div className="flex justify-between">
<Text weight="medium">Model Source Url List</Text>
<ToolTipButton desc="Refresh" icon={<ArrowClockwise20Regular/>}/>
</div>
<Text size={100}>description</Text>
<Textarea size="large" resize="vertical"
defaultValue="https://cdn.jsdelivr.net/gh/josstorer/RWKV-Runner/manifest.json;"/>
</div>
<DataGrid
items={items}
columns={columns}
sortable={true}
>
<DataGridHeader>
<DataGridRow>
{({renderHeaderCell}) => (
<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
)}
</DataGridRow>
</DataGridHeader>
<DataGridBody<Item>>
{({item, rowId}) => (
<DataGridRow<Item> key={rowId}>
{({renderCell}) => (
<DataGridCell>{renderCell(item)}</DataGridCell>
)}
</DataGridRow>
)}
</DataGridBody>
</DataGrid>
</div>
);
};

View File

@@ -3,12 +3,12 @@ import {Label, Tooltip} from '@fluentui/react-components';
export const Labeled: FC<{ label: string; desc?: string, content: ReactElement }> = ({label, desc, content}) => {
return (
<div className="flex items-center">
<div className="grid grid-cols-2 items-center">
{desc ?
<Tooltip content={desc} showDelay={0} hideDelay={0} relationship="description">
<Label className="w-44">{label}</Label>
<Label>{label}</Label>
</Tooltip> :
<Label className="w-44">{label}</Label>
<Label>{label}</Label>
}
{content}
</div>

View File

@@ -1,14 +1,21 @@
import {FC, ReactElement} from 'react';
import {Text} from '@fluentui/react-components';
import {Card, Text} from '@fluentui/react-components';
export const Section: FC<{ title: string; desc?: string, content: ReactElement }> = ({title, desc, content}) => {
return (
<div className="flex flex-col gap-5">
<div className="flex flex-col gap-1">
<Text weight="medium">{title}</Text>
{desc && <Text size={100}>{desc}</Text>}
</div>
{content}
</div>
);
};
export const Section: FC<{
title: string; desc?: string, content: ReactElement, outline?: boolean
}> =
({title, desc, content, outline = true}) => {
return (
<Card size="small" appearance={outline ? 'outline' : 'subtle'}>
<div className="flex flex-col gap-5">
<div className="flex flex-col gap-1">
<Text weight="medium">{title}</Text>
{desc && <Text size={100}>{desc}</Text>}
</div>
</div>
<div className="overflow-y-auto overflow-x-hidden p-1">
{content}
</div>
</Card>
);
};

View File

@@ -3,6 +3,25 @@
@tailwind utilities;
body {
margin: 0;
overflow: hidden;
margin: 0;
overflow: hidden;
}
* {
scrollbar-width: thin;
}
/* Works on Chrome, Edge, and Safari */
*::-webkit-scrollbar {
width: 9px;
}
*::-webkit-scrollbar-thumb {
background-color: rgba(155, 155, 155, 0.5);
border-radius: 20px;
border: transparent;
}
*::-webkit-scrollbar-track {
background: transparent;
}

View File

@@ -1,4 +1,4 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function SaveConfig(arg1:any):Promise<string>;
export function SaveJson(arg1:string,arg2:any):Promise<string>;

View File

@@ -2,6 +2,6 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function SaveConfig(arg1) {
return window['go']['backend_golang']['App']['SaveConfig'](arg1);
export function SaveJson(arg1, arg2) {
return window['go']['backend_golang']['App']['SaveJson'](arg1, arg2);
}