Merge branch 'main' into model-classification-api

This commit is contained in:
Billy
2025-03-13 13:03:51 +11:00
83 changed files with 1965 additions and 1051 deletions

View File

@@ -1,6 +1,7 @@
import queryString from 'query-string';
import type { paths } from 'services/api/schema';
import type { ApiTagDescription } from '..';
import { api, buildV1Url, LIST_TAG } from '..';
/**
@@ -19,15 +20,6 @@ export const workflowsApi = api.injectEndpoints({
>({
query: (workflow_id) => buildWorkflowsUrl(`i/${workflow_id}`),
providesTags: (result, error, workflow_id) => [{ type: 'Workflow', id: workflow_id }, 'FetchOnReconnect'],
onQueryStarted: async (arg, api) => {
const { dispatch, queryFulfilled } = api;
try {
await queryFulfilled;
dispatch(workflowsApi.util.invalidateTags([{ type: 'WorkflowsRecent', id: LIST_TAG }]));
} catch {
// no-op
}
},
}),
deleteWorkflow: build.mutation<void, string>({
query: (workflow_id) => ({
@@ -35,9 +27,11 @@ export const workflowsApi = api.injectEndpoints({
method: 'DELETE',
}),
invalidatesTags: (result, error, workflow_id) => [
// Because this may change the order of the list, we need to invalidate the whole list
{ type: 'Workflow', id: LIST_TAG },
{ type: 'Workflow', id: workflow_id },
{ type: 'WorkflowsRecent', id: LIST_TAG },
'WorkflowTagCounts',
'WorkflowCategoryCounts',
],
}),
createWorkflow: build.mutation<
@@ -50,8 +44,10 @@ export const workflowsApi = api.injectEndpoints({
body: { workflow },
}),
invalidatesTags: [
// Because this may change the order of the list, we need to invalidate the whole list
{ type: 'Workflow', id: LIST_TAG },
{ type: 'WorkflowsRecent', id: LIST_TAG },
'WorkflowTagCounts',
'WorkflowCategoryCounts',
],
}),
updateWorkflow: build.mutation<
@@ -64,27 +60,28 @@ export const workflowsApi = api.injectEndpoints({
body: { workflow },
}),
invalidatesTags: (response, error, workflow) => [
{ type: 'WorkflowsRecent', id: LIST_TAG },
{ type: 'Workflow', id: LIST_TAG },
{ type: 'Workflow', id: workflow.id },
'WorkflowTagCounts',
'WorkflowCategoryCounts',
],
}),
listWorkflows: build.query<
paths['/api/v1/workflows/']['get']['responses']['200']['content']['application/json'],
NonNullable<paths['/api/v1/workflows/']['get']['parameters']['query']>
getCountsByTag: build.query<
paths['/api/v1/workflows/counts_by_tag']['get']['responses']['200']['content']['application/json'],
NonNullable<paths['/api/v1/workflows/counts_by_tag']['get']['parameters']['query']>
>({
query: (params) => ({
url: `${buildWorkflowsUrl()}?${queryString.stringify(params, { arrayFormat: 'none' })}`,
url: `${buildWorkflowsUrl('counts_by_tag')}?${queryString.stringify(params, { arrayFormat: 'none' })}`,
}),
providesTags: ['FetchOnReconnect', { type: 'Workflow', id: LIST_TAG }],
providesTags: ['WorkflowTagCounts'],
}),
getCounts: build.query<
paths['/api/v1/workflows/counts']['get']['responses']['200']['content']['application/json'],
NonNullable<paths['/api/v1/workflows/counts']['get']['parameters']['query']>
getCountsByCategory: build.query<
paths['/api/v1/workflows/counts_by_category']['get']['responses']['200']['content']['application/json'],
NonNullable<paths['/api/v1/workflows/counts_by_category']['get']['parameters']['query']>
>({
query: (params) => ({
url: `${buildWorkflowsUrl('counts')}?${queryString.stringify(params, { arrayFormat: 'none' })}`,
url: `${buildWorkflowsUrl('counts_by_category')}?${queryString.stringify(params, { arrayFormat: 'none' })}`,
}),
providesTags: ['WorkflowCategoryCounts'],
}),
listWorkflowsInfinite: build.infiniteQuery<
paths['/api/v1/workflows/']['get']['responses']['200']['content']['application/json'],
@@ -108,13 +105,29 @@ export const workflowsApi = api.injectEndpoints({
return firstPageParam > -1 ? firstPageParam - 1 : undefined;
},
},
providesTags: (result) => {
const tags: ApiTagDescription[] = ['FetchOnReconnect', { type: 'Workflow', id: LIST_TAG }];
if (result) {
tags.push(
...result.pages
.map(({ items }) => items)
.flat()
.map((workflow) => ({ type: 'Workflow', id: workflow.workflow_id }) as const)
);
}
return tags;
},
}),
updateOpenedAt: build.mutation<void, { workflow_id: string }>({
query: ({ workflow_id }) => ({
url: buildWorkflowsUrl(`i/${workflow_id}/opened_at`),
method: 'PUT',
}),
invalidatesTags: (result, error, { workflow_id }) => [{ type: 'Workflow', id: workflow_id }],
invalidatesTags: (result, error, { workflow_id }) => [
{ type: 'Workflow', id: workflow_id },
// Because this may change the order of the list, we need to invalidate the whole list
{ type: 'Workflow', id: LIST_TAG },
],
}),
setWorkflowThumbnail: build.mutation<void, { workflow_id: string; image: File }>({
query: ({ workflow_id, image }) => {
@@ -126,33 +139,27 @@ export const workflowsApi = api.injectEndpoints({
body: formData,
};
},
invalidatesTags: (result, error, { workflow_id }) => [
{ type: 'Workflow', id: workflow_id },
{ type: 'WorkflowsRecent', id: LIST_TAG },
],
invalidatesTags: (result, error, { workflow_id }) => [{ type: 'Workflow', id: workflow_id }],
}),
deleteWorkflowThumbnail: build.mutation<void, string>({
query: (workflow_id) => ({
url: buildWorkflowsUrl(`i/${workflow_id}/thumbnail`),
method: 'DELETE',
}),
invalidatesTags: (result, error, workflow_id) => [
{ type: 'Workflow', id: workflow_id },
{ type: 'WorkflowsRecent', id: LIST_TAG },
],
invalidatesTags: (result, error, workflow_id) => [{ type: 'Workflow', id: workflow_id }],
}),
}),
});
export const {
useUpdateOpenedAtMutation,
useGetCountsQuery,
useGetCountsByTagQuery,
useGetCountsByCategoryQuery,
useLazyGetWorkflowQuery,
useGetWorkflowQuery,
useCreateWorkflowMutation,
useDeleteWorkflowMutation,
useUpdateWorkflowMutation,
useListWorkflowsQuery,
useListWorkflowsInfiniteInfiniteQuery,
useSetWorkflowThumbnailMutation,
useDeleteWorkflowThumbnailMutation,

View File

@@ -39,7 +39,7 @@ const buildModelsHook =
typeGuard: (config: AnyModelConfig, excludeSubmodels?: boolean) => config is T,
excludeSubmodels?: boolean
) =>
() => {
(filter: (config: T) => boolean = () => true) => {
const result = useGetModelConfigsQuery(undefined);
const modelConfigs = useMemo(() => {
if (!result.data) {
@@ -48,8 +48,9 @@ const buildModelsHook =
return modelConfigsAdapterSelectors
.selectAll(result.data)
.filter((config) => typeGuard(config, excludeSubmodels));
}, [result]);
.filter((config) => typeGuard(config, excludeSubmodels))
.filter(filter);
}, [filter, result.data]);
return [modelConfigs, result] as const;
};
@@ -78,6 +79,9 @@ export const useFluxVAEModels = (args?: ModelHookArgs) =>
export const useCLIPVisionModels = buildModelsHook(isCLIPVisionModelConfig);
export const useSigLipModels = buildModelsHook(isSigLipModelConfig);
export const useFluxReduxModels = buildModelsHook(isFluxReduxModelConfig);
export const useIPAdapterOrFLUXReduxModels = buildModelsHook(
(config) => isIPAdapterModelConfig(config) || isFluxReduxModelConfig(config)
);
// const buildModelsSelector =
// <T extends AnyModelConfig>(typeGuard: (config: AnyModelConfig) => config is T): Selector<RootState, T[]> =>

View File

@@ -44,7 +44,8 @@ const tagTypes = [
'LoRAModel',
'SDXLRefinerModel',
'Workflow',
'WorkflowsRecent',
'WorkflowTagCounts',
'WorkflowCategoryCounts',
'StylePreset',
'Schema',
'QueueCountsByDestination',

View File

@@ -1438,7 +1438,7 @@ export type paths = {
patch?: never;
trace?: never;
};
"/api/v1/workflows/counts": {
"/api/v1/workflows/counts_by_tag": {
parameters: {
query?: never;
header?: never;
@@ -1446,10 +1446,30 @@ export type paths = {
cookie?: never;
};
/**
* Get Counts
* @description Gets a the count of workflows that include the specified tags and categories
* Get Counts By Tag
* @description Counts workflows by tag
*/
get: operations["get_counts"];
get: operations["get_counts_by_tag"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v1/workflows/counts_by_category": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Counts By Category
* @description Counts workflows by category
*/
get: operations["counts_by_category"];
put?: never;
post?: never;
delete?: never;
@@ -7970,12 +7990,6 @@ export type components = {
* @default null
*/
redux_model?: components["schemas"]["ModelIdentifierField"];
/**
* SigLIP Model
* @description The SigLIP model to use.
* @default null
*/
siglip_model?: components["schemas"]["ModelIdentifierField"];
/**
* type
* @default flux_redux
@@ -21100,7 +21114,7 @@ export type components = {
* Opened At
* @description The opened timestamp of the workflow.
*/
opened_at: string;
opened_at: string | null;
/** @description The workflow. */
workflow: components["schemas"]["Workflow"];
};
@@ -21130,7 +21144,7 @@ export type components = {
* Opened At
* @description The opened timestamp of the workflow.
*/
opened_at: string;
opened_at: string | null;
/**
* Description
* @description The description of the workflow.
@@ -21181,7 +21195,7 @@ export type components = {
* Opened At
* @description The opened timestamp of the workflow.
*/
opened_at: string;
opened_at: string | null;
/** @description The workflow. */
workflow: components["schemas"]["Workflow"];
/**
@@ -24243,6 +24257,8 @@ export interface operations {
tags?: string[] | null;
/** @description The text to query by (matches name and description) */
query?: string | null;
/** @description Whether to include/exclude recent workflows */
has_been_opened?: boolean | null;
};
header?: never;
path?: never;
@@ -24417,13 +24433,15 @@ export interface operations {
};
};
};
get_counts: {
get_counts_by_tag: {
parameters: {
query?: {
/** @description The tags to include */
tags?: string[] | null;
query: {
/** @description The tags to get counts for */
tags: string[];
/** @description The categories to include */
categories?: components["schemas"]["WorkflowCategory"][] | null;
/** @description Whether to include/exclude recent workflows */
has_been_opened?: boolean | null;
};
header?: never;
path?: never;
@@ -24437,7 +24455,45 @@ export interface operations {
[name: string]: unknown;
};
content: {
"application/json": number;
"application/json": {
[key: string]: number;
};
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
counts_by_category: {
parameters: {
query: {
/** @description The categories to include */
categories: components["schemas"]["WorkflowCategory"][];
/** @description Whether to include/exclude recent workflows */
has_been_opened?: boolean | null;
};
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
[key: string]: number;
};
};
};
/** @description Validation Error */

View File

@@ -63,7 +63,7 @@ type DiffusersModelConfig = S['MainDiffusersConfig'];
export type CheckpointModelConfig = S['MainCheckpointConfig'];
type CLIPVisionDiffusersConfig = S['CLIPVisionDiffusersConfig'];
export type SigLipModelConfig = S['SigLIPConfig'];
export type FluxReduxModelConfig = S['FluxReduxConfig'];
export type FLUXReduxModelConfig = S['FluxReduxConfig'];
export type MainModelConfig = DiffusersModelConfig | CheckpointModelConfig;
export type AnyModelConfig =
| ControlLoRAModelConfig
@@ -80,7 +80,7 @@ export type AnyModelConfig =
| MainModelConfig
| CLIPVisionDiffusersConfig
| SigLipModelConfig
| FluxReduxModelConfig;
| FLUXReduxModelConfig;
/**
* Checks if a list of submodels contains any that match a given variant or type
@@ -217,7 +217,7 @@ export const isSigLipModelConfig = (config: AnyModelConfig): config is SigLipMod
return config.type === 'siglip';
};
export const isFluxReduxModelConfig = (config: AnyModelConfig): config is FluxReduxModelConfig => {
export const isFluxReduxModelConfig = (config: AnyModelConfig): config is FLUXReduxModelConfig => {
return config.type === 'flux_redux';
};