feat(gui): make status update interval configurable
This commit is contained in:
parent
d349e8cc10
commit
80f3438ebd
|
@ -1,9 +1,9 @@
|
|||
/* eslint-disable max-lines */
|
||||
import { doesExist, InvalidArgumentError, Maybe } from '@apextoaster/js-utils';
|
||||
import { create as batcher, windowScheduler, keyResolver } from '@yornaath/batshit';
|
||||
import { create as batcher, keyResolver, windowScheduler } from '@yornaath/batshit';
|
||||
|
||||
import { ServerParams } from '../config.js';
|
||||
import { FIXED_FLOAT, FIXED_INTEGER, POLL_TIME, STATUS_SUCCESS } from '../constants.js';
|
||||
import { FIXED_FLOAT, FIXED_INTEGER, STATUS_SUCCESS } from '../constants.js';
|
||||
import { JobResponse, JobResponseWithRetry, SuccessJobResponse } from '../types/api-v2.js';
|
||||
import {
|
||||
FilterResponse,
|
||||
|
@ -125,7 +125,7 @@ export function appendHighresToURL(url: URL, highres: HighresParams) {
|
|||
/**
|
||||
* Make an API client using the given API root and fetch client.
|
||||
*/
|
||||
export function makeClient(root: string, token: Maybe<string> = undefined, f = fetch): ApiClient {
|
||||
export function makeClient(root: string, batchInterval: number, token: Maybe<string> = undefined, f = fetch): ApiClient {
|
||||
function parseRequest(url: URL, options: RequestInit): Promise<JobResponse> {
|
||||
return f(url, options).then((res) => parseJobResponse(root, res));
|
||||
}
|
||||
|
@ -505,7 +505,7 @@ export function makeClient(root: string, token: Maybe<string> = undefined, f = f
|
|||
const batchStatus = batcher({
|
||||
fetcher: async (jobs: Array<string>) => client.status(jobs),
|
||||
resolver: keyResolver('name'),
|
||||
scheduler: windowScheduler(POLL_TIME),
|
||||
scheduler: windowScheduler(batchInterval),
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
|
@ -48,14 +48,16 @@ export function newSeed(): number {
|
|||
return Math.floor(Math.random() * MAX_SEED);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
||||
export const RANDOM_SEED = [-1, '-1'];
|
||||
|
||||
export function replaceRandomSeeds(key: string, values: Array<number | string>): Array<number | string> {
|
||||
if (key !== 'seed') {
|
||||
return values;
|
||||
}
|
||||
|
||||
return values.map((it) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
||||
if (it === '-1' || it === -1) {
|
||||
if (RANDOM_SEED.includes(it)) {
|
||||
return newSeed();
|
||||
}
|
||||
|
||||
|
@ -108,8 +110,8 @@ export function makeTxt2ImgGridPipeline(
|
|||
defaults: {
|
||||
...model,
|
||||
...params,
|
||||
...(upscale || {}),
|
||||
...(highres || {}),
|
||||
...(upscale ?? {}),
|
||||
...(highres ?? {}),
|
||||
},
|
||||
stages: [],
|
||||
};
|
||||
|
|
|
@ -8,10 +8,11 @@ import { useTranslation } from 'react-i18next';
|
|||
import { useStore } from 'zustand';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { POLL_TIME, STANDARD_SPACING } from '../../constants.js';
|
||||
import { STANDARD_SPACING } from '../../constants.js';
|
||||
import { ClientContext, ConfigContext, OnnxState, StateContext } from '../../state/full.js';
|
||||
import { JobResponse, JobStatus } from '../../types/api-v2.js';
|
||||
import { visibleIndex } from '../../utils.js';
|
||||
import { getBatchInterval } from '../utils.js';
|
||||
|
||||
const LOADING_PERCENT = 100;
|
||||
const LOADING_OVERAGE = 99;
|
||||
|
@ -22,6 +23,7 @@ export interface LoadingCardProps {
|
|||
|
||||
export function LoadingCard(props: LoadingCardProps) {
|
||||
const { image } = props;
|
||||
const batch = getBatchInterval();
|
||||
|
||||
const client = mustExist(useContext(ClientContext));
|
||||
const { params } = mustExist(useContext(ConfigContext));
|
||||
|
@ -34,7 +36,7 @@ export function LoadingCard(props: LoadingCardProps) {
|
|||
const ready = useQuery(['ready', image.name], () => client.status([image.name]), {
|
||||
// data will always be ready without this, even if the API says its not
|
||||
cacheTime: 0,
|
||||
refetchInterval: POLL_TIME,
|
||||
refetchInterval: batch,
|
||||
});
|
||||
|
||||
function renderProgress() {
|
||||
|
|
|
@ -55,7 +55,7 @@ export function Settings() {
|
|||
max={6}
|
||||
step={1}
|
||||
value={state.historyWidth}
|
||||
onChange={(value) => state.setWidth(value)}
|
||||
onChange={(value) => state.setHistoryWidth(value)}
|
||||
/>
|
||||
<Button variant='contained' onClick={() => state.setLayout(state.layout === 'horizontal' ? 'vertical' : 'horizontal')}>Toggle Layout</Button>
|
||||
<TextField variant='outlined' label={t('setting.prompt')} value={state.defaults.prompt} onChange={(event) => {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Maybe, doesExist } from '@apextoaster/js-utils';
|
||||
import { PaletteMode } from '@mui/material';
|
||||
|
||||
import { Theme } from '../state/types.js';
|
||||
|
@ -31,3 +32,18 @@ export function getTheme(currentTheme: Theme, preferDark: boolean): PaletteMode
|
|||
}
|
||||
return currentTheme as PaletteMode;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
||||
export function getBatchInterval(defaultInterval = 5000): number {
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
const interval = query.get('interval');
|
||||
if (doesExist(interval)) {
|
||||
return parseInt(interval, 10);
|
||||
}
|
||||
return defaultInterval;
|
||||
}
|
||||
|
||||
export function getToken(): Maybe<string> {
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
return query.get('token');
|
||||
}
|
||||
|
|
|
@ -123,14 +123,15 @@ export function getApiRoot(config: Config): string {
|
|||
}
|
||||
}
|
||||
|
||||
export const TRUE_VALUES = ['1', 't', 'true', 'y', 'yes'];
|
||||
|
||||
export function isDebug(): boolean {
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
const debug = query.get('debug');
|
||||
|
||||
if (doesExist(debug)) {
|
||||
const val = debug.toLowerCase();
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return val === '1' || val === 't' || val === 'true' || val === 'y' || val === 'yes';
|
||||
return TRUE_VALUES.includes(val);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -73,7 +73,6 @@ export const LAYOUT_STYLES = {
|
|||
export const INITIAL_LOAD_TIMEOUT = 5_000;
|
||||
|
||||
export const STALE_TIME = 300_000; // 5 minutes
|
||||
export const POLL_TIME = 5_000; // 5 seconds
|
||||
export const SAVE_TIME = 5_000; // 5 seconds
|
||||
|
||||
export const IMAGE_FILTER = '.bmp, .jpg, .jpeg, .png';
|
||||
|
|
|
@ -11,14 +11,16 @@ import { createStore } from 'zustand';
|
|||
import { createJSONStorage, persist } from 'zustand/middleware';
|
||||
|
||||
import { makeClient } from './client/api.js';
|
||||
import { LOCAL_CLIENT } from './client/local.js';
|
||||
import { ApiClient } from './client/base.js';
|
||||
import { LOCAL_CLIENT } from './client/local.js';
|
||||
import { ParamsVersionError } from './components/error/ParamsVersion.js';
|
||||
import { ServerParamsError } from './components/error/ServerParams.js';
|
||||
import { LoadingScreen } from './components/LoadingScreen.js';
|
||||
import { OnnxError } from './components/OnnxError.js';
|
||||
import { OnnxWeb } from './components/OnnxWeb.js';
|
||||
import { getBatchInterval, getToken } from './components/utils.js';
|
||||
import { Config, getApiRoot, isDebug, loadConfig, mergeConfig, ServerParams } from './config.js';
|
||||
import { INITIAL_LOAD_TIMEOUT, PARAM_VERSION } from './constants.js';
|
||||
import {
|
||||
ClientContext,
|
||||
ConfigContext,
|
||||
|
@ -29,9 +31,8 @@ import {
|
|||
STATE_VERSION,
|
||||
StateContext,
|
||||
} from './state/full.js';
|
||||
import { I18N_STRINGS } from './strings/all.js';
|
||||
import { applyStateMigrations, UnknownState } from './state/migration/default.js';
|
||||
import { INITIAL_LOAD_TIMEOUT, PARAM_VERSION } from './constants.js';
|
||||
import { I18N_STRINGS } from './strings/all.js';
|
||||
|
||||
export async function renderApp(config: Config, params: ServerParams, logger: Logger, client: ApiClient) {
|
||||
const completeConfig = mergeConfig(config, params);
|
||||
|
@ -149,13 +150,13 @@ export async function main() {
|
|||
// load config from GUI server
|
||||
const config = await loadConfig();
|
||||
|
||||
// get token from query string
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
const token = query.get('token');
|
||||
// get client params from query string
|
||||
const root = getApiRoot(config);
|
||||
const batch = getBatchInterval();
|
||||
const token = getToken();
|
||||
|
||||
// use that to create an API client
|
||||
const root = getApiRoot(config);
|
||||
const client = makeClient(root, token);
|
||||
const client = makeClient(root, batch, token);
|
||||
|
||||
// prep react-dom
|
||||
const appElement = mustExist(document.getElementById('app'));
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Slice } from './types.js';
|
|||
|
||||
export type Layout = 'horizontal' | 'vertical';
|
||||
|
||||
export const DEFAULT_LAYOUT = {
|
||||
export const DEFAULT_SETTINGS = {
|
||||
historyWidth: 4,
|
||||
layout: 'vertical' as Layout,
|
||||
} as const;
|
||||
|
@ -11,23 +11,23 @@ export interface SettingsSlice {
|
|||
historyWidth: number;
|
||||
layout: Layout;
|
||||
|
||||
setHistoryWidth(width: number): void;
|
||||
setLayout(layout: Layout): void;
|
||||
setWidth(width: number): void;
|
||||
}
|
||||
|
||||
export function createSettingsSlice<TState extends SettingsSlice>(): Slice<TState, SettingsSlice> {
|
||||
return (set) => ({
|
||||
...DEFAULT_LAYOUT,
|
||||
...DEFAULT_SETTINGS,
|
||||
setLayout(layout) {
|
||||
set((prev) => ({
|
||||
...prev,
|
||||
layout,
|
||||
}));
|
||||
},
|
||||
setWidth(width) {
|
||||
setHistoryWidth(historyWidth) {
|
||||
set((prev) => ({
|
||||
...prev,
|
||||
historyWidth: width,
|
||||
historyWidth,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue