preliminary usable features
This commit is contained in:
1781
frontend/package-lock.json
generated
1781
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,26 +9,26 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluentui/react-components": "^9.19.1",
|
||||
"@fluentui/react-components": "^9.20.0",
|
||||
"@fluentui/react-icons": "^2.0.201",
|
||||
"mobx": "^6.9.0",
|
||||
"mobx-react-lite": "^3.4.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^6.11.0",
|
||||
"react-router-dom": "^6.11.0",
|
||||
"react-toastify": "^9.1.2",
|
||||
"react-router": "^6.11.1",
|
||||
"react-router-dom": "^6.11.1",
|
||||
"react-toastify": "^9.1.3",
|
||||
"usehooks-ts": "^2.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.17",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@vitejs/plugin-react": "^2.0.1",
|
||||
"@types/react": "^18.2.6",
|
||||
"@types/react-dom": "^18.2.4",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"postcss": "^8.4.23",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.0.7"
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.3.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,8 +85,9 @@ const App: FC = () => {
|
||||
style={{
|
||||
width: '250px'
|
||||
}}
|
||||
position="top-right"
|
||||
position="top-center"
|
||||
autoClose={4000}
|
||||
hideProgressBar={true}
|
||||
newestOnTop={true}
|
||||
closeOnClick={false}
|
||||
rtl={false}
|
||||
|
||||
34
frontend/src/apis/index.ts
Normal file
34
frontend/src/apis/index.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import commonStore, {ModelStatus} from '../stores/commonStore';
|
||||
|
||||
export const readRoot = async () => {
|
||||
const port = commonStore.getCurrentModelConfig().apiParameters.apiPort;
|
||||
return fetch(`http://127.0.0.1:${port}`);
|
||||
};
|
||||
|
||||
export const exit = async () => {
|
||||
commonStore.setModelStatus(ModelStatus.Offline);
|
||||
const port = commonStore.getCurrentModelConfig().apiParameters.apiPort;
|
||||
return fetch(`http://127.0.0.1:${port}/exit`, {method: 'POST'});
|
||||
};
|
||||
|
||||
export const switchModel = async (body: any) => {
|
||||
const port = commonStore.getCurrentModelConfig().apiParameters.apiPort;
|
||||
return fetch(`http://127.0.0.1:${port}/switch-model`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
};
|
||||
|
||||
export const updateConfig = async (body: any) => {
|
||||
const port = commonStore.getCurrentModelConfig().apiParameters.apiPort;
|
||||
return fetch(`http://127.0.0.1:${port}/update-config`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
};
|
||||
@@ -1,8 +1,10 @@
|
||||
import React, {FC} from 'react';
|
||||
import React, {FC, MouseEventHandler} from 'react';
|
||||
import commonStore, {ModelStatus} from '../stores/commonStore';
|
||||
import {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';
|
||||
|
||||
const mainButtonText = {
|
||||
[ModelStatus.Offline]: 'Run',
|
||||
@@ -12,28 +14,42 @@ const mainButtonText = {
|
||||
};
|
||||
|
||||
const onClickMainButton = async () => {
|
||||
const modelConfig = commonStore.getCurrentModelConfig();
|
||||
const port = modelConfig.apiParameters.apiPort;
|
||||
|
||||
if (commonStore.modelStatus === ModelStatus.Offline) {
|
||||
commonStore.setModelStatus(ModelStatus.Starting);
|
||||
StartServer(commonStore.getStrategy(), `models\\${commonStore.getCurrentModelConfig().modelParameters.modelName}`);
|
||||
StartServer(port);
|
||||
|
||||
let timeoutCount = 5;
|
||||
let timeoutCount = 6;
|
||||
let loading = false;
|
||||
const intervalId = setInterval(() => {
|
||||
fetch('http://127.0.0.1:8000')
|
||||
readRoot()
|
||||
.then(r => {
|
||||
if (r.ok && !loading) {
|
||||
clearInterval(intervalId);
|
||||
commonStore.setModelStatus(ModelStatus.Loading);
|
||||
loading = true;
|
||||
fetch('http://127.0.0.1:8000/update-config', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({})
|
||||
}).then(async (r) => {
|
||||
if (r.ok)
|
||||
toast('Loading Model', {type: 'info'});
|
||||
updateConfig({
|
||||
max_tokens: modelConfig.apiParameters.maxResponseToken,
|
||||
temperature: modelConfig.apiParameters.temperature,
|
||||
top_p: modelConfig.apiParameters.topP,
|
||||
presence_penalty: modelConfig.apiParameters.presencePenalty,
|
||||
frequency_penalty: modelConfig.apiParameters.frequencyPenalty
|
||||
});
|
||||
switchModel({
|
||||
model: `models\\${modelConfig.modelParameters.modelName}`,
|
||||
strategy: commonStore.getStrategy(modelConfig)
|
||||
}).then((r) => {
|
||||
if (r.ok) {
|
||||
commonStore.setModelStatus(ModelStatus.Working);
|
||||
} else if (r.status === 304) {
|
||||
toast('Loading Model', {type: 'info'});
|
||||
} else {
|
||||
commonStore.setModelStatus(ModelStatus.Offline);
|
||||
toast('Failed to switch model', {type: 'error'});
|
||||
}
|
||||
});
|
||||
}
|
||||
}).catch(() => {
|
||||
@@ -46,15 +62,18 @@ const onClickMainButton = async () => {
|
||||
timeoutCount--;
|
||||
}, 1000);
|
||||
} else {
|
||||
commonStore.setModelStatus(ModelStatus.Offline);
|
||||
fetch('http://127.0.0.1:8000/exit', {method: 'POST'});
|
||||
exit();
|
||||
}
|
||||
};
|
||||
|
||||
export const RunButton: FC = observer(() => {
|
||||
export const RunButton: FC<{ onClickRun?: MouseEventHandler }> = observer(({onClickRun}) => {
|
||||
return (
|
||||
<Button disabled={commonStore.modelStatus === ModelStatus.Starting} appearance="primary" size="large"
|
||||
onClick={onClickMainButton}>
|
||||
onClick={async (e) => {
|
||||
if (commonStore.modelStatus === ModelStatus.Offline)
|
||||
await onClickRun?.(e);
|
||||
await onClickMainButton();
|
||||
}}>
|
||||
{mainButtonText[commonStore.modelStatus]}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -12,6 +12,7 @@ import {NumberInput} from '../components/NumberInput';
|
||||
import {Page} from '../components/Page';
|
||||
import {useNavigate} from 'react-router';
|
||||
import {RunButton} from '../components/RunButton';
|
||||
import {updateConfig} from '../apis';
|
||||
|
||||
export const Configs: FC = observer(() => {
|
||||
const [selectedIndex, setSelectedIndex] = React.useState(commonStore.currentModelConfigIndex);
|
||||
@@ -49,6 +50,18 @@ export const Configs: FC = observer(() => {
|
||||
});
|
||||
};
|
||||
|
||||
const onClickSave = () => {
|
||||
commonStore.setModelConfig(selectedIndex, selectedConfig);
|
||||
updateConfig({
|
||||
max_tokens: selectedConfig.apiParameters.maxResponseToken,
|
||||
temperature: selectedConfig.apiParameters.temperature,
|
||||
top_p: selectedConfig.apiParameters.topP,
|
||||
presence_penalty: selectedConfig.apiParameters.presencePenalty,
|
||||
frequency_penalty: selectedConfig.apiParameters.frequencyPenalty
|
||||
});
|
||||
toast('Config Saved', {autoClose: 300, type: 'success'});
|
||||
};
|
||||
|
||||
return (
|
||||
<Page title="Configs" content={
|
||||
<div className="flex flex-col gap-2 overflow-hidden">
|
||||
@@ -72,10 +85,7 @@ export const Configs: FC = observer(() => {
|
||||
commonStore.deleteModelConfig(selectedIndex);
|
||||
updateSelectedIndex(Math.min(selectedIndex, commonStore.modelConfigs.length - 1));
|
||||
}}/>
|
||||
<ToolTipButton desc="Save Config" icon={<Save20Regular/>} onClick={() => {
|
||||
commonStore.setModelConfig(selectedIndex, selectedConfig);
|
||||
toast('Config Saved', {hideProgressBar: true, autoClose: 300, position: 'top-center'});
|
||||
}}/>
|
||||
<ToolTipButton desc="Save Config" icon={<Save20Regular/>} onClick={onClickSave}/>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<Label>Config Name</Label>
|
||||
@@ -89,7 +99,7 @@ export const Configs: FC = observer(() => {
|
||||
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={
|
||||
<Labeled label="API Port" desc={`127.0.0.1:${selectedConfig.apiParameters.apiPort}`} content={
|
||||
<NumberInput value={selectedConfig.apiParameters.apiPort} min={1} max={65535} step={1}
|
||||
onChange={(e, data) => {
|
||||
setSelectedConfigApiParams({
|
||||
@@ -130,11 +140,11 @@ export const Configs: FC = observer(() => {
|
||||
});
|
||||
}}/>
|
||||
}/>
|
||||
<Labeled label="Count Penalty *" content={
|
||||
<ValuedSlider value={selectedConfig.apiParameters.countPenalty} min={-2} max={2} step={0.1} input
|
||||
<Labeled label="Frequency Penalty *" content={
|
||||
<ValuedSlider value={selectedConfig.apiParameters.frequencyPenalty} min={-2} max={2} step={0.1} input
|
||||
onChange={(e, data) => {
|
||||
setSelectedConfigApiParams({
|
||||
countPenalty: data.value
|
||||
frequencyPenalty: data.value
|
||||
});
|
||||
}}/>
|
||||
}/>
|
||||
@@ -193,12 +203,12 @@ export const Configs: FC = observer(() => {
|
||||
<Option>fp32</Option>
|
||||
</Dropdown>
|
||||
}/>
|
||||
<Labeled label="Streamed Layers" content={
|
||||
<ValuedSlider value={selectedConfig.modelParameters.streamedLayers} min={0}
|
||||
max={selectedConfig.modelParameters.maxStreamedLayers} step={1} input
|
||||
<Labeled label="Stored Layers" content={
|
||||
<ValuedSlider value={selectedConfig.modelParameters.storedLayers} min={0}
|
||||
max={selectedConfig.modelParameters.maxStoredLayers} step={1} input
|
||||
onChange={(e, data) => {
|
||||
setSelectedConfigModelParams({
|
||||
streamedLayers: data.value
|
||||
storedLayers: data.value
|
||||
});
|
||||
}}/>
|
||||
}/>
|
||||
@@ -215,7 +225,7 @@ export const Configs: FC = observer(() => {
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row-reverse sm:fixed bottom-2 right-2">
|
||||
<RunButton/>
|
||||
<RunButton onClickRun={onClickSave}/>
|
||||
</div>
|
||||
</div>
|
||||
}/>
|
||||
|
||||
@@ -11,6 +11,8 @@ import {useNavigate} from 'react-router';
|
||||
import commonStore from '../stores/commonStore';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import {RunButton} from '../components/RunButton';
|
||||
import manifest from '../../../manifest.json';
|
||||
import {BrowserOpenURL} from '../../wailsjs/runtime';
|
||||
|
||||
type NavCard = {
|
||||
label: string;
|
||||
@@ -94,8 +96,8 @@ export const Home: FC = observer(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4 items-end">
|
||||
Version: 1.0.0
|
||||
<Link>Help</Link>
|
||||
Version: {manifest.version}
|
||||
<Link onClick={() => BrowserOpenURL('https://github.com/josStorer/RWKV-Runner')}>Help</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,7 @@ export type ApiParameters = {
|
||||
temperature: number;
|
||||
topP: number;
|
||||
presencePenalty: number;
|
||||
countPenalty: number;
|
||||
frequencyPenalty: number;
|
||||
}
|
||||
|
||||
export type Device = 'CPU' | 'CUDA';
|
||||
@@ -38,8 +38,8 @@ export type ModelParameters = {
|
||||
modelName: string;
|
||||
device: Device;
|
||||
precision: Precision;
|
||||
streamedLayers: number;
|
||||
maxStreamedLayers: number;
|
||||
storedLayers: number;
|
||||
maxStoredLayers: number;
|
||||
enableHighPrecisionForLastLayer: boolean;
|
||||
}
|
||||
|
||||
@@ -59,14 +59,14 @@ export const defaultModelConfigs: ModelConfig[] = [
|
||||
temperature: 1,
|
||||
topP: 1,
|
||||
presencePenalty: 0,
|
||||
countPenalty: 0
|
||||
frequencyPenalty: 0
|
||||
},
|
||||
modelParameters: {
|
||||
modelName: 'RWKV-4-Raven-1B5-v11-Eng99%-Other1%-20230425-ctx4096.pth',
|
||||
device: 'CUDA',
|
||||
precision: 'fp16',
|
||||
streamedLayers: 25,
|
||||
maxStreamedLayers: 25,
|
||||
storedLayers: 25,
|
||||
maxStoredLayers: 25,
|
||||
enableHighPrecisionForLastLayer: false
|
||||
}
|
||||
}
|
||||
@@ -98,8 +98,8 @@ class CommonStore {
|
||||
let strategy = '';
|
||||
strategy += (params.device === 'CPU' ? 'cpu' : 'cuda') + ' ';
|
||||
strategy += (params.precision === 'fp16' ? 'fp16' : params.precision === 'int8' ? 'fp16i8' : 'fp32');
|
||||
if (params.streamedLayers < params.maxStreamedLayers)
|
||||
strategy += ` *${params.streamedLayers}+`;
|
||||
if (params.storedLayers < params.maxStoredLayers)
|
||||
strategy += ` *${params.storedLayers}+`;
|
||||
if (params.enableHighPrecisionForLastLayer)
|
||||
strategy += ' -> cpu fp32 *1';
|
||||
return strategy;
|
||||
|
||||
2
frontend/wailsjs/go/backend_golang/App.d.ts
vendored
2
frontend/wailsjs/go/backend_golang/App.d.ts
vendored
@@ -16,4 +16,4 @@ export function ReadJson(arg1:string):Promise<any>;
|
||||
|
||||
export function SaveJson(arg1:string,arg2:any):Promise<void>;
|
||||
|
||||
export function StartServer(arg1:string,arg2:string):Promise<string>;
|
||||
export function StartServer(arg1:number):Promise<string>;
|
||||
|
||||
@@ -30,6 +30,6 @@ export function SaveJson(arg1, arg2) {
|
||||
return window['go']['backend_golang']['App']['SaveJson'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function StartServer(arg1, arg2) {
|
||||
return window['go']['backend_golang']['App']['StartServer'](arg1, arg2);
|
||||
export function StartServer(arg1) {
|
||||
return window['go']['backend_golang']['App']['StartServer'](arg1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user