diff --git a/gui/src/client/api.ts b/gui/src/client/api.ts index 62975d07..3595a022 100644 --- a/gui/src/client/api.ts +++ b/gui/src/client/api.ts @@ -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 = undefined, f = fetch): ApiClient { +export function makeClient(root: string, batchInterval: number, token: Maybe = undefined, f = fetch): ApiClient { function parseRequest(url: URL, options: RequestInit): Promise { return f(url, options).then((res) => parseJobResponse(root, res)); } @@ -505,7 +505,7 @@ export function makeClient(root: string, token: Maybe = undefined, f = f const batchStatus = batcher({ fetcher: async (jobs: Array) => client.status(jobs), resolver: keyResolver('name'), - scheduler: windowScheduler(POLL_TIME), + scheduler: windowScheduler(batchInterval), }); return { diff --git a/gui/src/client/utils.ts b/gui/src/client/utils.ts index bde45282..903bbfeb 100644 --- a/gui/src/client/utils.ts +++ b/gui/src/client/utils.ts @@ -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): Array { 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: [], }; diff --git a/gui/src/components/card/LoadingCard.tsx b/gui/src/components/card/LoadingCard.tsx index 51c512d0..2c5c968b 100644 --- a/gui/src/components/card/LoadingCard.tsx +++ b/gui/src/components/card/LoadingCard.tsx @@ -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() { diff --git a/gui/src/components/tab/Settings.tsx b/gui/src/components/tab/Settings.tsx index 5615f1b3..f8e8559c 100644 --- a/gui/src/components/tab/Settings.tsx +++ b/gui/src/components/tab/Settings.tsx @@ -55,7 +55,7 @@ export function Settings() { max={6} step={1} value={state.historyWidth} - onChange={(value) => state.setWidth(value)} + onChange={(value) => state.setHistoryWidth(value)} /> { diff --git a/gui/src/components/utils.ts b/gui/src/components/utils.ts index 39ba9bae..691e98ed 100644 --- a/gui/src/components/utils.ts +++ b/gui/src/components/utils.ts @@ -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 { + const query = new URLSearchParams(window.location.search); + return query.get('token'); +} diff --git a/gui/src/config.ts b/gui/src/config.ts index 18e5b39f..accb7b87 100644 --- a/gui/src/config.ts +++ b/gui/src/config.ts @@ -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; } diff --git a/gui/src/constants.ts b/gui/src/constants.ts index f16d2e23..0b30e1d8 100644 --- a/gui/src/constants.ts +++ b/gui/src/constants.ts @@ -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'; diff --git a/gui/src/main.tsx b/gui/src/main.tsx index 00286119..3f5246f5 100644 --- a/gui/src/main.tsx +++ b/gui/src/main.tsx @@ -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')); diff --git a/gui/src/state/settings.ts b/gui/src/state/settings.ts index 02822dd5..37761f5a 100644 --- a/gui/src/state/settings.ts +++ b/gui/src/state/settings.ts @@ -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(): Slice { return (set) => ({ - ...DEFAULT_LAYOUT, + ...DEFAULT_SETTINGS, setLayout(layout) { set((prev) => ({ ...prev, layout, })); }, - setWidth(width) { + setHistoryWidth(historyWidth) { set((prev) => ({ ...prev, - historyWidth: width, + historyWidth, })); }, });