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