From 3920d5c90d4a5f16cf576438bd2fef131ffdf0cd Mon Sep 17 00:00:00 2001 From: mickr777 Date: Wed, 13 Sep 2023 21:15:36 +1000 Subject: [PATCH 01/12] Missed Translations --- invokeai/frontend/web/public/locales/en.json | 129 +++++++++++++- .../web/src/features/nodes/types/constants.ts | 161 +++++++++--------- .../web/src/features/nodes/types/types.ts | 25 ++- .../src/features/nodes/util/buildWorkflow.ts | 5 +- .../getMetadataAndWorkflowFromImageBlob.ts | 5 +- .../util/graphBuilders/buildCanvasGraph.ts | 7 +- .../buildCanvasImageToImageGraph.ts | 5 +- .../graphBuilders/buildCanvasInpaintGraph.ts | 5 +- .../graphBuilders/buildCanvasOutpaintGraph.ts | 5 +- .../buildCanvasSDXLImageToImageGraph.ts | 5 +- .../buildCanvasSDXLInpaintGraph.ts | 5 +- .../buildCanvasSDXLOutpaintGraph.ts | 5 +- .../buildCanvasSDXLTextToImageGraph.ts | 5 +- .../buildCanvasTextToImageGraph.ts | 5 +- .../buildLinearImageToImageGraph.ts | 9 +- .../buildLinearSDXLImageToImageGraph.ts | 9 +- .../buildLinearSDXLTextToImageGraph.ts | 5 +- .../buildLinearTextToImageGraph.ts | 5 +- .../src/features/nodes/util/parseSchema.ts | 26 +-- .../features/nodes/util/validateWorkflow.ts | 47 +++-- 20 files changed, 323 insertions(+), 150 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c1983c6a53..7faa10a889 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -619,56 +619,175 @@ "addNodeToolTip": "Add Node (Shift+A, Space)", "animatedEdges": "Animated Edges", "animatedEdgesHelp": "Animate selected edges and edges connected to selected nodes", + "boolean": "Booleans", + "booleanCollection": "Boolean Collection", + "booleanCollectionDescription": "A collection of booleans.", + "booleanDescription": "Booleans are true or false.", + "booleanPolymorphic": "Boolean Polymorphic", + "booleanPolymorphicDescription": "A collection of booleans.", "cannotConnectInputToInput": "Cannot connect input to input", "cannotConnectOutputToOutput": "Cannot connect output to output", "cannotConnectToSelf": "Cannot connect to self", + "clipField": "Clip", + "clipFieldDescription": "Tokenizer and text_encoder submodels.", + "collection": "Collection", + "collectionDescription": "TODO", + "collectionItem": "Collection Item", + "collectionItemDescription": "TODO", "colorCodeEdges": "Color-Code Edges", "colorCodeEdgesHelp": "Color-code edges according to their connected fields", + "colorCollectionDescription": "A collection of colors.", + "colorField": "Color", + "colorFieldDescription": "A RGBA color.", + "colorPolymorphic": "Color Polymorphic", + "colorPolymorphicDescription": "A collection of colors.", + "conditioningCollection": "Conditioning Collection", + "conditioningCollectionDescription": "Conditioning may be passed between nodes.", + "conditioningField": "Conditioning", + "conditioningFieldDescription": "Conditioning may be passed between nodes.", + "conditioningPolymorphic": "Conditioning Polymorphic", + "conditioningPolymorphicDescription": "Conditioning may be passed between nodes.", "connectionWouldCreateCycle": "Connection would create a cycle", + "controlCollection": "Control Collection", + "controlCollectionDescription": "Control info passed between nodes.", + "controlField": "Control", + "controlFieldDescription": "Control info passed between nodes.", "currentImage": "Current Image", "currentImageDescription": "Displays the current image in the Node Editor", + "denoiseMaskField": "Denoise Mask", + "denoiseMaskFieldDescription": "Denoise Mask may be passed between nodes", + "doesNotExist": "does not exist", "downloadWorkflow": "Download Workflow JSON", + "edge": "Edge", + "enum": "Enum", + "enumDescription": "Enums are values that may be one of a number of options.", + "executionStateCompleted": "Completed", + "executionStateError": "Error", + "executionStateInProgress": "In Progress", "fieldTypesMustMatch": "Field types must match", "fitViewportNodes": "Fit View", + "float": "Float", + "floatCollection": "Float Collection", + "floatCollectionDescription": "A collection of floats.", + "floatDescription": "Floats are numbers with a decimal point.", + "floatPolymorphic": "Float Polymorphic", + "floatPolymorphicDescription": "A collection of floats.", "fullyContainNodes": "Fully Contain Nodes to Select", "fullyContainNodesHelp": "Nodes must be fully inside the selection box to be selected", "hideGraphNodes": "Hide Graph Overlay", "hideLegendNodes": "Hide Field Type Legend", "hideMinimapnodes": "Hide MiniMap", + "imageCollection": "Image Collection", + "imageCollectionDescription": "A collection of images.", + "imageField": "Image", + "imageFieldDescription": "Images may be passed between nodes.", + "imagePolymorphic": "Image Polymorphic", + "imagePolymorphicDescription": "A collection of images.", + "inputFields": "Input Feilds", "inputMayOnlyHaveOneConnection": "Input may only have one connection", + "inputNode": "Input Node", + "integer": "Integer", + "integerCollection": "Integer Collection", + "integerCollectionDescription": "A collection of integers.", + "integerDescription": "Integers are whole numbers, without a decimal point.", + "integerPolymorphic": "Integer Polymorphic", + "integerPolymorphicDescription": "A collection of integers.", + "invalidOutputSchema": "Invalid output schema", + "latentsCollection": "Latents Collection", + "latentsCollectionDescription": "Latents may be passed between nodes.", + "latentsField": "Latents", + "latentsFieldDescription": "Latents may be passed between nodes.", + "latentsPolymorphic": "Latents Polymorphic", + "latentsPolymorphicDescription": "Latents may be passed between nodes.", "loadingNodes": "Loading Nodes...", "loadWorkflow": "Load Workflow", + "loRAModelField": "LoRA", + "loRAModelFieldDescription": "TODO", + "mainModelField": "Model", + "mainModelFieldDescription": "TODO", + "maybeIncompatible": "May be Incompatible With Installed", + "mismatchedVersion": "Has Mismatched Version", + "missingCanvaInitImage": "Missing canvas init image", + "missingCanvaInitMaskImages": "Missing canvas init and mask images", + "missingTemplate": "Missing Template", "noConnectionData": "No connection data", "noConnectionInProgress": "No connection in progress", + "node": "Node", "nodeOutputs": "Node Outputs", "nodeSearch": "Search for nodes", "nodeTemplate": "Node Template", + "nodeType": "Node Type", "noFieldsLinearview": "No fields added to Linear View", "noFieldType": "No field type", + "noImageFoundState": "No initial image found in state", "noMatchingNodes": "No matching nodes", + "noModelFoundState": "No model found in state", "noNodeSelected": "No node selected", "noOpacity": "Node Opacity", "noOutputRecorded": "No outputs recorded", + "noOutputSchemaName": "No output schema name found in ref object", "notes": "Notes", "notesDescription": "Add notes about your workflow", + "oNNXModelField": "ONNX Model", + "oNNXModelFieldDescription": "ONNX model field.", + "outputFields": "Output Feilds", + "outputNode": "Output node", + "outputSchemaNotFound": "Output schema not found", "pickOne": "Pick One", + "problemReadingMetadata": "Problem reading metadata from image", + "problemReadingWorkflow": "Problem reading workflow from image", "problemSettingTitle": "Problem Setting Title", "reloadNodeTemplates": "Reload Node Templates", "removeLinearView": "Remove from Linear View", "resetWorkflow": "Reset Workflow", "resetWorkflowDesc": "Are you sure you want to reset this workflow?", "resetWorkflowDesc2": "Resetting the workflow will clear all nodes, edges and workflow details.", + "scheduler": "Scheduler", + "schedulerDescription": "TODO", + "sDXLMainModelField": "SDXL Model", + "sDXLMainModelFieldDescription": "SDXL model field.", + "sDXLRefinerModelField": "Refiner Model", + "sDXLRefinerModelFieldDescription": "TODO", "showGraphNodes": "Show Graph Overlay", "showLegendNodes": "Show Field Type Legend", "showMinimapnodes": "Show MiniMap", + "skipped": "Skipped", + "skippedReservedInput": "Skipped reserved input field", + "skippedReservedOutput": "Skipped reserved output field", + "skippingInputNoTemplate": "Skipping input field with no template", + "skippingReservedFieldType": "Skipping reserved field type", + "skippingUnknownInputType": "Skipping unknown input field type", + "skippingUnknownOutputType": "Skipping unknown output field type", "snapToGrid": "Snap to Grid", "snapToGridHelp": "Snap nodes to grid when moved", + "sourceNode": "Source node", + "string": "String", + "stringCollection": "String Collection", + "stringCollectionDescription": "A collection of strings.", + "stringDescription": "Strings are text.", + "stringPolymorphic": "String Polymorphic", + "stringPolymorphicDescription": "A collection of strings.", "unableToLoadWorkflow": "Unable to Validate Workflow", + "unableToParseEdge": "Unable to parse edge", + "unableToParseNode": "Unable to parse node", "unableToValidateWorkflow": "Unable to Validate Workflow", + "uNetField": "UNet", + "uNetFieldDescription": "UNet submodel.", + "unhandledInputProperty": "Unhandled input property", + "unhandledOutputProperty": "Unhandled output property", "unknownField": "Unknown Field", + "unknownNode": "Unknown Node", + "unknownTemplate": "Unknown Template", "unkownInvocation": "Unknown Invocation type", + "updateApp": "Update App", + "vaeField": "Vae", + "vaeFieldDescription": "Vae submodel.", + "vaeModelField": "VAE", + "vaeModelFieldDescription": "TODO", "validateConnections": "Validate Connections and Graph", "validateConnectionsHelp": "Prevent invalid connections from being made, and invalid graphs from being invoked", + "version": "Version", + "versionUnknown": " Version Unknown", "workflow": "Workflow", "workflowAuthor": "Author", "workflowContact": "Contact", @@ -680,15 +799,7 @@ "workflowValidation": "Workflow Validation Error", "workflowVersion": "Version", "zoomInNodes": "Zoom In", - "zoomOutNodes": "Zoom Out", - "executionStateError": "Error", - "executionStateCompleted": "Completed", - "executionStateInProgress": "In Progress", - "versionUnknown": " Version Unknown", - "unknownNode": "Unknown Node", - "version": "Version", - "updateApp": "Update App", - "unknownTemplate": "Unknown Template" + "zoomOutNodes": "Zoom Out" }, "parameters": { "aspectRatio": "Ratio", diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index a12c1fbddc..11b74cd002 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -1,4 +1,5 @@ import { FieldType, FieldUIConfig } from './types'; +import i18n from 'i18next'; export const HANDLE_TOOLTIP_OPEN_DELAY = 500; export const COLOR_TOKEN_VALUE = 500; @@ -102,73 +103,73 @@ export const isPolymorphicItemType = ( export const FIELDS: Record = { boolean: { color: 'green.500', - description: 'Booleans are true or false.', - title: 'Boolean', + description: i18n.t('nodes.booleanDescription'), + title: i18n.t('nodes.boolean'), }, BooleanCollection: { color: 'green.500', - description: 'A collection of booleans.', - title: 'Boolean Collection', + description: i18n.t('nodes.booleanCollectionDescription'), + title: i18n.t('nodes.booleanCollection'), }, BooleanPolymorphic: { color: 'green.500', - description: 'A collection of booleans.', - title: 'Boolean Polymorphic', + description: i18n.t('nodes.booleanPolymorphicDescription'), + title: i18n.t('nodes.booleanPolymorphic'), }, ClipField: { color: 'green.500', - description: 'Tokenizer and text_encoder submodels.', - title: 'Clip', + description: i18n.t('nodes.clipFieldDescription'), + title: i18n.t('nodes.clipField'), }, Collection: { color: 'base.500', - description: 'TODO', - title: 'Collection', + description: i18n.t('nodes.collectionDescription'), + title: i18n.t('nodes.collection'), }, CollectionItem: { color: 'base.500', - description: 'TODO', - title: 'Collection Item', + description: i18n.t('nodes.collectionItemDescription'), + title: i18n.t('nodes.collectionItem'), }, ColorCollection: { color: 'pink.300', - description: 'A collection of colors.', - title: 'Color Collection', + description: i18n.t('nodes.colorCollectionDescription'), + title: i18n.t('nodes.colorCollection'), }, ColorField: { color: 'pink.300', - description: 'A RGBA color.', - title: 'Color', + description: i18n.t('nodes.colorFieldDescription'), + title: i18n.t('nodes.colorField'), }, ColorPolymorphic: { color: 'pink.300', - description: 'A collection of colors.', - title: 'Color Polymorphic', + description: i18n.t('nodes.colorPolymorphicDescription'), + title: i18n.t('nodes.colorPolymorphic'), }, ConditioningCollection: { color: 'cyan.500', - description: 'Conditioning may be passed between nodes.', - title: 'Conditioning Collection', + description: i18n.t('nodes.conditioningCollectionDescription'), + title: i18n.t('nodes.conditioningCollection'), }, ConditioningField: { color: 'cyan.500', - description: 'Conditioning may be passed between nodes.', - title: 'Conditioning', + description: i18n.t('nodes.conditioningFieldDescription'), + title: i18n.t('nodes.conditioningField'), }, ConditioningPolymorphic: { color: 'cyan.500', - description: 'Conditioning may be passed between nodes.', - title: 'Conditioning Polymorphic', + description: i18n.t('nodes.conditioningPolymorphicDescription'), + title: i18n.t('nodes.conditioningPolymorphic'), }, ControlCollection: { color: 'teal.500', - description: 'Control info passed between nodes.', - title: 'Control Collection', + description: i18n.t('nodes.controlCollectionDescription'), + title: i18n.t('nodes.controlCollection'), }, ControlField: { color: 'teal.500', - description: 'Control info passed between nodes.', - title: 'Control', + description: i18n.t('nodes.controlFieldDescription'), + title: i18n.t('nodes.controlField'), }, ControlNetModelField: { color: 'teal.500', @@ -182,132 +183,132 @@ export const FIELDS: Record = { }, DenoiseMaskField: { color: 'blue.300', - description: 'Denoise Mask may be passed between nodes', - title: 'Denoise Mask', + description: i18n.t('nodes.denoiseMaskFieldDescription'), + title: i18n.t('nodes.denoiseMaskField'), }, enum: { color: 'blue.500', - description: 'Enums are values that may be one of a number of options.', - title: 'Enum', + description: i18n.t('nodes.enumDescription'), + title: i18n.t('nodes.enum'), }, float: { color: 'orange.500', - description: 'Floats are numbers with a decimal point.', - title: 'Float', + description: i18n.t('nodes.floatDescription'), + title: i18n.t('nodes.float'), }, FloatCollection: { color: 'orange.500', - description: 'A collection of floats.', - title: 'Float Collection', + description: i18n.t('nodes.floatCollectionDescription'), + title: i18n.t('nodes.floatCollection'), }, FloatPolymorphic: { color: 'orange.500', - description: 'A collection of floats.', - title: 'Float Polymorphic', + description: i18n.t('nodes.floatPolymorphicDescription'), + title: i18n.t('nodes.floatPolymorphic'), }, ImageCollection: { color: 'purple.500', - description: 'A collection of images.', - title: 'Image Collection', + description: i18n.t('nodes.imageCollectionDescription'), + title: i18n.t('nodes.imageCollection'), }, ImageField: { color: 'purple.500', - description: 'Images may be passed between nodes.', - title: 'Image', + description: i18n.t('nodes.imageFieldDescription'), + title: i18n.t('nodes.imageField'), }, ImagePolymorphic: { color: 'purple.500', - description: 'A collection of images.', - title: 'Image Polymorphic', + description: i18n.t('nodes.imagePolymorphicDescription'), + title: i18n.t('nodes.imagePolymorphic'), }, integer: { color: 'red.500', - description: 'Integers are whole numbers, without a decimal point.', - title: 'Integer', + description: i18n.t('nodes.integerDescription'), + title: i18n.t('nodes.integer'), }, IntegerCollection: { color: 'red.500', - description: 'A collection of integers.', - title: 'Integer Collection', + description: i18n.t('nodes.integerCollectionDescription'), + title: i18n.t('nodes.integerCollection'), }, IntegerPolymorphic: { color: 'red.500', - description: 'A collection of integers.', - title: 'Integer Polymorphic', + description: i18n.t('nodes.integerPolymorphicDescription'), + title: i18n.t('nodes.integerPolymorphic'), }, LatentsCollection: { color: 'pink.500', - description: 'Latents may be passed between nodes.', - title: 'Latents Collection', + description: i18n.t('nodes.latentsCollectionDescription'), + title: i18n.t('nodes.latentsCollection'), }, LatentsField: { color: 'pink.500', - description: 'Latents may be passed between nodes.', - title: 'Latents', + description: i18n.t('nodes.latentsFieldDescription'), + title: i18n.t('nodes.latentsField'), }, LatentsPolymorphic: { color: 'pink.500', - description: 'Latents may be passed between nodes.', - title: 'Latents Polymorphic', + description: i18n.t('nodes.latentsPolymorphicDescription'), + title: i18n.t('nodes.latentsPolymorphic'), }, LoRAModelField: { color: 'teal.500', - description: 'TODO', - title: 'LoRA', + description: i18n.t('nodes.loRAModelFieldDescription'), + title: i18n.t('nodes.loRAModelField'), }, MainModelField: { color: 'teal.500', - description: 'TODO', - title: 'Model', + description: i18n.t('nodes.mainModelFieldDescription'), + title: i18n.t('nodes.mainModelField'), }, ONNXModelField: { color: 'teal.500', - description: 'ONNX model field.', - title: 'ONNX Model', + description: i18n.t('nodes.oNNXModelFieldDescription'), + title: i18n.t('nodes.oNNXModelField'), }, Scheduler: { color: 'base.500', - description: 'TODO', - title: 'Scheduler', + description: i18n.t('nodes.schedulerDescription'), + title: i18n.t('nodes.scheduler'), }, SDXLMainModelField: { color: 'teal.500', - description: 'SDXL model field.', - title: 'SDXL Model', + description: i18n.t('nodes.sDXLMainModelFieldDescription'), + title: i18n.t('nodes.sDXLMainModelField'), }, SDXLRefinerModelField: { color: 'teal.500', - description: 'TODO', - title: 'Refiner Model', + description: i18n.t('nodes.sDXLRefinerModelFieldDescription'), + title: i18n.t('nodes.sDXLRefinerModelField'), }, string: { color: 'yellow.500', - description: 'Strings are text.', - title: 'String', + description: i18n.t('nodes.stringDescription'), + title: i18n.t('nodes.string'), }, StringCollection: { color: 'yellow.500', - description: 'A collection of strings.', - title: 'String Collection', + description: i18n.t('nodes.stringCollectionDescription'), + title: i18n.t('nodes.stringCollection'), }, StringPolymorphic: { color: 'yellow.500', - description: 'A collection of strings.', - title: 'String Polymorphic', + description: i18n.t('nodes.stringPolymorphicDescription'), + title: i18n.t('nodes.stringPolymorphic'), }, UNetField: { color: 'red.500', - description: 'UNet submodel.', - title: 'UNet', + description: i18n.t('nodes.uNetFieldDescription'), + title: i18n.t('nodes.uNetField'), }, VaeField: { color: 'blue.500', - description: 'Vae submodel.', - title: 'Vae', + description: i18n.t('nodes.vaeFieldDescription'), + title: i18n.t('nodes.vaeField'), }, VaeModelField: { color: 'teal.500', - description: 'TODO', - title: 'VAE', + description: i18n.t('nodes.vaeModelFieldDescription'), + title: i18n.t('nodes.vaeModelField'), }, }; diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts index b1ad6a7b96..a4b71457f7 100644 --- a/invokeai/frontend/web/src/features/nodes/types/types.ts +++ b/invokeai/frontend/web/src/features/nodes/types/types.ts @@ -20,6 +20,7 @@ import { import { O } from 'ts-toolbelt'; import { JsonObject } from 'type-fest'; import { z } from 'zod'; +import i18n from 'i18next'; export type NonNullableGraph = O.Required; @@ -1258,23 +1259,35 @@ export const zValidatedWorkflow = zWorkflow.transform((workflow) => { const targetNode = keyedNodes[edge.target]; const issues: string[] = []; if (!sourceNode) { - issues.push(`Output node ${edge.source} does not exist`); + issues.push( + `${i18n.t('nodes.outputNode')} ${edge.source} ${i18n.t( + 'nodes.doesNotExist' + )}` + ); } else if ( edge.type === 'default' && !(edge.sourceHandle in sourceNode.data.outputs) ) { issues.push( - `Output field "${edge.source}.${edge.sourceHandle}" does not exist` + `${i18n.t('nodes.outputField')}"${edge.source}.${ + edge.sourceHandle + }" ${i18n.t('nodes.doesNotExist')}` ); } if (!targetNode) { - issues.push(`Input node ${edge.target} does not exist`); + issues.push( + `${i18n.t('nodes.inputNode')} ${edge.target} ${i18n.t( + 'nodes.doesNotExist' + )}` + ); } else if ( edge.type === 'default' && !(edge.targetHandle in targetNode.data.inputs) ) { issues.push( - `Input field "${edge.target}.${edge.targetHandle}" does not exist` + `${i18n.t('nodes.inputField')} "${edge.target}.${ + edge.targetHandle + }" ${i18n.t('nodes.doesNotExist')}` ); } if (issues.length) { @@ -1282,7 +1295,9 @@ export const zValidatedWorkflow = zWorkflow.transform((workflow) => { const src = edge.type === 'default' ? edge.sourceHandle : edge.source; const tgt = edge.type === 'default' ? edge.targetHandle : edge.target; warnings.push({ - message: `Edge "${src} -> ${tgt}" skipped`, + message: `${i18n.t('nodes.edge')} "${src} -> ${tgt}" ${i18n.t( + 'nodes.skipped' + )}`, issues, data: edge, }); diff --git a/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts b/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts index b0ade42a9f..43ee75b735 100644 --- a/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts +++ b/invokeai/frontend/web/src/features/nodes/util/buildWorkflow.ts @@ -3,6 +3,7 @@ import { NodesState } from '../store/types'; import { Workflow, zWorkflowEdge, zWorkflowNode } from '../types/types'; import { fromZodError } from 'zod-validation-error'; import { parseify } from 'common/util/serialize'; +import i18n from 'i18next'; export const buildWorkflow = (nodesState: NodesState): Workflow => { const { workflow: workflowMeta, nodes, edges } = nodesState; @@ -20,7 +21,7 @@ export const buildWorkflow = (nodesState: NodesState): Workflow => { const result = zWorkflowNode.safeParse(node); if (!result.success) { const { message } = fromZodError(result.error, { - prefix: 'Unable to parse node', + prefix: i18n.t('nodes.unableToParseNode'), }); logger('nodes').warn({ node: parseify(node) }, message); return; @@ -32,7 +33,7 @@ export const buildWorkflow = (nodesState: NodesState): Workflow => { const result = zWorkflowEdge.safeParse(edge); if (!result.success) { const { message } = fromZodError(result.error, { - prefix: 'Unable to parse edge', + prefix: i18n.t('nodes.unableToParseEdge'), }); logger('nodes').warn({ edge: parseify(edge) }, message); return; diff --git a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts index b46a701757..6f850e7d29 100644 --- a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts +++ b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts @@ -7,6 +7,7 @@ import { zWorkflow, } from 'features/nodes/types/types'; import { get } from 'lodash-es'; +import i18n from 'i18next'; export const getMetadataAndWorkflowFromImageBlob = async ( image: Blob @@ -23,7 +24,7 @@ export const getMetadataAndWorkflowFromImageBlob = async ( } else { logger('system').error( { error: parseify(metadataResult.error) }, - 'Problem reading metadata from image' + i18n.t('nodes.problemReadingMetadata') ); } } @@ -36,7 +37,7 @@ export const getMetadataAndWorkflowFromImageBlob = async ( } else { logger('system').error( { error: parseify(workflowResult.error) }, - 'Problem reading workflow from image' + i18n.t('nodes.problemReadingWorkflow') ); } } diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts index d268a3990d..bfed5f417a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts @@ -9,6 +9,7 @@ import { buildCanvasSDXLInpaintGraph } from './buildCanvasSDXLInpaintGraph'; import { buildCanvasSDXLOutpaintGraph } from './buildCanvasSDXLOutpaintGraph'; import { buildCanvasSDXLTextToImageGraph } from './buildCanvasSDXLTextToImageGraph'; import { buildCanvasTextToImageGraph } from './buildCanvasTextToImageGraph'; +import i18n from 'i18next'; export const buildCanvasGraph = ( state: RootState, @@ -29,7 +30,7 @@ export const buildCanvasGraph = ( } } else if (generationMode === 'img2img') { if (!canvasInitImage) { - throw new Error('Missing canvas init image'); + throw new Error(i18n.t('nodes.missingCanvaInitImage')); } if ( state.generation.model && @@ -41,7 +42,7 @@ export const buildCanvasGraph = ( } } else if (generationMode === 'inpaint') { if (!canvasInitImage || !canvasMaskImage) { - throw new Error('Missing canvas init and mask images'); + throw new Error(i18n.t('nodes.missingCanvaInitMaskImages')); } if ( state.generation.model && @@ -57,7 +58,7 @@ export const buildCanvasGraph = ( } } else { if (!canvasInitImage) { - throw new Error('Missing canvas init image'); + throw new Error(i18n.t('nodes.missingCanvaInitImage')); } if ( state.generation.model && diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts index e750b40220..b27ffe7149 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts @@ -25,6 +25,7 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Image to Image graph. @@ -66,8 +67,8 @@ export const buildCanvasImageToImageGraph = ( ); if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } let modelLoaderNodeId = MAIN_MODEL_LOADER; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts index 58a7726410..3a0db8c55a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts @@ -44,6 +44,7 @@ import { RANGE_OF_SIZE, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Inpaint graph. @@ -79,8 +80,8 @@ export const buildCanvasInpaintGraph = ( } = state.generation; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noImageFoundState')); + throw new Error(i18n.t('nodes.noImageFoundState')); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts index 71d3492bdc..2222fcbfe8 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts @@ -46,6 +46,7 @@ import { RANGE_OF_SIZE, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Outpaint graph. @@ -83,8 +84,8 @@ export const buildCanvasOutpaintGraph = ( } = state.generation; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noImageFoundState')); + throw new Error(i18n.t('nodes.noImageFoundState')); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts index 2a677a8775..6beb4c725c 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts @@ -27,6 +27,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Image to Image graph. @@ -74,8 +75,8 @@ export const buildCanvasSDXLImageToImageGraph = ( ); if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } // Model Loader ID diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts index baa1c0155f..6b63ec4e44 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts @@ -46,6 +46,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Inpaint graph. @@ -86,8 +87,8 @@ export const buildCanvasSDXLInpaintGraph = ( } = state.sdxl; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts index 3f8fffb70a..c1105c0ecd 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts @@ -48,6 +48,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Outpaint graph. @@ -90,8 +91,8 @@ export const buildCanvasSDXLOutpaintGraph = ( } = state.sdxl; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts index 6d787987ef..07f9b8f573 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts @@ -29,6 +29,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Text to Image graph. @@ -71,8 +72,8 @@ export const buildCanvasSDXLTextToImageGraph = ( state.sdxl; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const use_cpu = shouldUseNoiseSettings diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts index 094a7b02cc..ae06a27a3e 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts @@ -27,6 +27,7 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Canvas tab's Text to Image graph. @@ -66,8 +67,8 @@ export const buildCanvasTextToImageGraph = ( ); if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const use_cpu = shouldUseNoiseSettings diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts index dc9a34c67e..b032e6d9f7 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts @@ -27,6 +27,7 @@ import { RESIZE, SEAMLESS, } from './constants'; +import i18n from 'i18next'; /** * Builds the Image to Image tab graph. @@ -75,13 +76,13 @@ export const buildLinearImageToImageGraph = ( */ if (!initialImage) { - log.error('No initial image found in state'); - throw new Error('No initial image found in state'); + log.error(i18n.t('nodes.noImageFoundState')); + throw new Error(i18n.t('nodes.noImageFoundState')); } if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts index 757a3976bb..7dd4aaf301 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts @@ -29,6 +29,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; /** * Builds the Image to Image tab graph. @@ -75,13 +76,13 @@ export const buildLinearSDXLImageToImageGraph = ( */ if (!initialImage) { - log.error('No initial image found in state'); - throw new Error('No initial image found in state'); + log.error(i18n.t('nodes.noImageFoundState')); + throw new Error(i18n.t('nodes.noImageFoundState')); } if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts index 9590e77f89..86ea08b41c 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts @@ -23,6 +23,7 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; +import i18n from 'i18next'; export const buildLinearSDXLTextToImageGraph = ( state: RootState @@ -58,8 +59,8 @@ export const buildLinearSDXLTextToImageGraph = ( : initialGenerationState.shouldUseCpuNoise; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts index 5c534fff21..6ca16b0ae0 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts @@ -26,6 +26,7 @@ import { SEAMLESS, TEXT_TO_IMAGE_GRAPH, } from './constants'; +import i18n from 'i18next'; export const buildLinearTextToImageGraph = ( state: RootState @@ -53,8 +54,8 @@ export const buildLinearTextToImageGraph = ( : initialGenerationState.shouldUseCpuNoise; if (!model) { - log.error('No model found in state'); - throw new Error('No model found in state'); + log.error(i18n.t('nodes.noModelFoundState')); + throw new Error(i18n.t('nodes.noModelFoundState')); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index 8615a12c46..55ca593827 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -15,6 +15,7 @@ import { isInvocationSchemaObject, } from '../types/types'; import { buildInputFieldTemplate, getFieldType } from './fieldTemplateBuilders'; +import i18n from 'i18next'; const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'metadata']; const RESERVED_OUTPUT_FIELD_NAMES = ['type']; @@ -97,7 +98,7 @@ export const parseSchema = ( if (isReservedInputField(type, propertyName)) { logger('nodes').trace( { node: type, fieldName: propertyName, field: parseify(property) }, - 'Skipped reserved input field' + i18n.t('nodes.skippedReservedInput') ); return inputsAccumulator; } @@ -105,7 +106,7 @@ export const parseSchema = ( if (!isInvocationFieldSchema(property)) { logger('nodes').warn( { node: type, propertyName, property: parseify(property) }, - 'Unhandled input property' + i18n.t('nodes.unhandledInputProperty') ); return inputsAccumulator; } @@ -120,7 +121,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - 'Skipping unknown input field type' + i18n.t('nodes.skippingUnknownInputType') ); return inputsAccumulator; } @@ -133,7 +134,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - 'Skipping reserved field type' + i18n.t('nodes.skippingReservedFieldType') ); return inputsAccumulator; } @@ -153,7 +154,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - 'Skipping input field with no template' + i18n.t('nodes.skippingInputNoTemplate') ); return inputsAccumulator; } @@ -169,21 +170,24 @@ export const parseSchema = ( if (!outputSchemaName) { logger('nodes').warn( { outputRefObject: parseify(schema.output) }, - 'No output schema name found in ref object' + i18n.t('nodes.noOutputSchemaName') ); return invocationsAccumulator; } const outputSchema = openAPI.components?.schemas?.[outputSchemaName]; if (!outputSchema) { - logger('nodes').warn({ outputSchemaName }, 'Output schema not found'); + logger('nodes').warn( + { outputSchemaName }, + i18n.t('nodes.outputSchemaNotFound') + ); return invocationsAccumulator; } if (!isInvocationOutputSchemaObject(outputSchema)) { logger('nodes').error( { outputSchema: parseify(outputSchema) }, - 'Invalid output schema' + i18n.t('nodes.invalidOutputSchema') ); return invocationsAccumulator; } @@ -196,7 +200,7 @@ export const parseSchema = ( if (!isAllowedOutputField(type, propertyName)) { logger('nodes').trace( { type, propertyName, property: parseify(property) }, - 'Skipped reserved output field' + i18n.t('nodes.skippedReservedOutput') ); return outputsAccumulator; } @@ -204,7 +208,7 @@ export const parseSchema = ( if (!isInvocationFieldSchema(property)) { logger('nodes').warn( { type, propertyName, property: parseify(property) }, - 'Unhandled output property' + i18n.t('nodes.unhandledOutputProperty') ); return outputsAccumulator; } @@ -214,7 +218,7 @@ export const parseSchema = ( if (!isFieldType(fieldType)) { logger('nodes').warn( { fieldName: propertyName, fieldType, field: parseify(property) }, - 'Skipping unknown output field type' + i18n.t('nodes.skippingUnknownOutputType') ); return outputsAccumulator; } diff --git a/invokeai/frontend/web/src/features/nodes/util/validateWorkflow.ts b/invokeai/frontend/web/src/features/nodes/util/validateWorkflow.ts index a3085d516b..14b90fc731 100644 --- a/invokeai/frontend/web/src/features/nodes/util/validateWorkflow.ts +++ b/invokeai/frontend/web/src/features/nodes/util/validateWorkflow.ts @@ -7,6 +7,7 @@ import { isWorkflowInvocationNode, } from '../types/types'; import { parseify } from 'common/util/serialize'; +import i18n from 'i18next'; export const validateWorkflow = ( workflow: Workflow, @@ -25,8 +26,14 @@ export const validateWorkflow = ( const nodeTemplate = nodeTemplates[node.data.type]; if (!nodeTemplate) { errors.push({ - message: `Node "${node.data.type}" skipped`, - issues: [`Node type "${node.data.type}" does not exist`], + message: `${i18n.t('nodes.node')} "${node.data.type}" ${i18n.t( + 'nodes.skipped' + )}`, + issues: [ + `${i18n.t('nodes.nodeType')}"${node.data.type}" ${i18n.t( + 'nodes.doesNotExist' + )}`, + ], data: node, }); return; @@ -38,9 +45,13 @@ export const validateWorkflow = ( compareVersions(nodeTemplate.version, node.data.version) !== 0 ) { errors.push({ - message: `Node "${node.data.type}" has mismatched version`, + message: `${i18n.t('nodes.node')} "${node.data.type}" ${i18n.t( + 'nodes.mismatchedVersion' + )}`, issues: [ - `Node "${node.data.type}" v${node.data.version} may be incompatible with installed v${nodeTemplate.version}`, + `${i18n.t('nodes.node')} "${node.data.type}" v${ + node.data.version + } ${i18n.t('nodes.maybeIncompatible')} v${nodeTemplate.version}`, ], data: { node, nodeTemplate: parseify(nodeTemplate) }, }); @@ -52,33 +63,49 @@ export const validateWorkflow = ( const targetNode = keyedNodes[edge.target]; const issues: string[] = []; if (!sourceNode) { - issues.push(`Output node ${edge.source} does not exist`); + issues.push( + `${i18n.t('nodes.outputNode')} ${edge.source} ${i18n.t( + 'nodes.doesNotExist' + )}` + ); } else if ( edge.type === 'default' && !(edge.sourceHandle in sourceNode.data.outputs) ) { issues.push( - `Output field "${edge.source}.${edge.sourceHandle}" does not exist` + `${i18n.t('nodes.outputNodes')} "${edge.source}.${ + edge.sourceHandle + }" ${i18n.t('nodes.doesNotExist')}` ); } if (!targetNode) { - issues.push(`Input node ${edge.target} does not exist`); + issues.push( + `${i18n.t('nodes.inputNode')} ${edge.target} ${i18n.t( + 'nodes.doesNotExist' + )}` + ); } else if ( edge.type === 'default' && !(edge.targetHandle in targetNode.data.inputs) ) { issues.push( - `Input field "${edge.target}.${edge.targetHandle}" does not exist` + `${i18n.t('nodes.inputFeilds')} "${edge.target}.${ + edge.targetHandle + }" ${i18n.t('nodes.doesNotExist')}` ); } if (!nodeTemplates[sourceNode?.data.type ?? '__UNKNOWN_NODE_TYPE__']) { issues.push( - `Source node "${edge.source}" missing template "${sourceNode?.data.type}"` + `${i18n.t('nodes.sourceNode')} "${edge.source}" ${i18n.t( + 'nodes.missingTemplate' + )} "${sourceNode?.data.type}"` ); } if (!nodeTemplates[targetNode?.data.type ?? '__UNKNOWN_NODE_TYPE__']) { issues.push( - `Source node "${edge.target}" missing template "${targetNode?.data.type}"` + `${i18n.t('nodes.sourceNode')}"${edge.target}" ${i18n.t( + 'nodes.missingTemplate' + )} "${targetNode?.data.type}"` ); } if (issues.length) { From f6738d647e163793adcfbb5e0857fa6376be9f2c Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 14 Sep 2023 09:02:54 +1000 Subject: [PATCH 02/12] fix(ui): store customStarUI outside redux JSX is not serializable, so it cannot be in redux. Non-serializable global state may be put into `nanostores`. - Use `nanostores` for `customStarUI` - Use `nanostores` for `headerComponent` - Re-enable the serializable & immutable check redux middlewares --- .../frontend/web/src/app/components/App.tsx | 23 ++++---------- .../web/src/app/components/InvokeAIUI.tsx | 30 ++++++++++++++----- .../src/app/store/nanostores/customStarUI.ts | 14 +++++++++ .../app/store/nanostores/headerComponent.ts | 4 +++ .../web/src/app/store/nanostores/index.ts | 3 ++ invokeai/frontend/web/src/app/store/store.ts | 5 +--- .../MultipleSelectionMenuItems.tsx | 5 ++-- .../SingleSelectionMenuItems.tsx | 9 +++--- .../components/ImageGrid/GalleryImage.tsx | 7 +++-- .../web/src/features/ui/store/uiSlice.ts | 7 +---- .../web/src/features/ui/store/uiTypes.ts | 13 -------- 11 files changed, 64 insertions(+), 56 deletions(-) create mode 100644 invokeai/frontend/web/src/app/store/nanostores/customStarUI.ts create mode 100644 invokeai/frontend/web/src/app/store/nanostores/headerComponent.ts create mode 100644 invokeai/frontend/web/src/app/store/nanostores/index.ts diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx index aa1919abfb..8c033440e3 100644 --- a/invokeai/frontend/web/src/app/components/App.tsx +++ b/invokeai/frontend/web/src/app/components/App.tsx @@ -12,33 +12,26 @@ import { languageSelector } from 'features/system/store/systemSelectors'; import InvokeTabs from 'features/ui/components/InvokeTabs'; import i18n from 'i18n'; import { size } from 'lodash-es'; -import { ReactNode, memo, useCallback, useEffect } from 'react'; +import { memo, useCallback, useEffect } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { usePreselectedImage } from '../../features/parameters/hooks/usePreselectedImage'; import AppErrorBoundaryFallback from './AppErrorBoundaryFallback'; import GlobalHotkeys from './GlobalHotkeys'; import Toaster from './Toaster'; -import { CustomStarUi } from '../../features/ui/store/uiTypes'; -import { setCustomStarUi } from '../../features/ui/store/uiSlice'; +import { useStore } from '@nanostores/react'; +import { $headerComponent } from 'app/store/nanostores/headerComponent'; const DEFAULT_CONFIG = {}; interface Props { config?: PartialAppConfig; - headerComponent?: ReactNode; selectedImage?: { imageName: string; action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters'; }; - customStarUi?: CustomStarUi; } -const App = ({ - config = DEFAULT_CONFIG, - headerComponent, - selectedImage, - customStarUi, -}: Props) => { +const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => { const language = useAppSelector(languageSelector); const logger = useLogger('system'); @@ -61,12 +54,6 @@ const App = ({ } }, [dispatch, config, logger]); - useEffect(() => { - if (customStarUi) { - dispatch(setCustomStarUi(customStarUi)); - } - }, [customStarUi, dispatch]); - useEffect(() => { dispatch(appStarted()); }, [dispatch]); @@ -75,6 +62,8 @@ const App = ({ handlePreselectedImage(selectedImage); }, [handlePreselectedImage, selectedImage]); + const headerComponent = useStore($headerComponent); + return ( import('./App')); const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider')); @@ -83,18 +84,33 @@ const InvokeAIUI = ({ }; }, [apiUrl, token, middleware, projectId]); + useEffect(() => { + if (customStarUi) { + $customStarUI.set(customStarUi); + } + + return () => { + $customStarUI.set(undefined); + }; + }, [customStarUi]); + + useEffect(() => { + if (headerComponent) { + $headerComponent.set(headerComponent); + } + + return () => { + $headerComponent.set(undefined); + }; + }, [headerComponent]); + return ( }> - + diff --git a/invokeai/frontend/web/src/app/store/nanostores/customStarUI.ts b/invokeai/frontend/web/src/app/store/nanostores/customStarUI.ts new file mode 100644 index 0000000000..0459c2f31f --- /dev/null +++ b/invokeai/frontend/web/src/app/store/nanostores/customStarUI.ts @@ -0,0 +1,14 @@ +import { MenuItemProps } from '@chakra-ui/react'; +import { atom } from 'nanostores'; + +export type CustomStarUi = { + on: { + icon: MenuItemProps['icon']; + text: string; + }; + off: { + icon: MenuItemProps['icon']; + text: string; + }; +}; +export const $customStarUI = atom(undefined); diff --git a/invokeai/frontend/web/src/app/store/nanostores/headerComponent.ts b/invokeai/frontend/web/src/app/store/nanostores/headerComponent.ts new file mode 100644 index 0000000000..90a4775ff9 --- /dev/null +++ b/invokeai/frontend/web/src/app/store/nanostores/headerComponent.ts @@ -0,0 +1,4 @@ +import { atom } from 'nanostores'; +import { ReactNode } from 'react'; + +export const $headerComponent = atom(undefined); diff --git a/invokeai/frontend/web/src/app/store/nanostores/index.ts b/invokeai/frontend/web/src/app/store/nanostores/index.ts new file mode 100644 index 0000000000..ae43ed3035 --- /dev/null +++ b/invokeai/frontend/web/src/app/store/nanostores/index.ts @@ -0,0 +1,3 @@ +/** + * For non-serializable data that needs to be available throughout the app, or when redux is not appropriate, use nanostores. + */ diff --git a/invokeai/frontend/web/src/app/store/store.ts b/invokeai/frontend/web/src/app/store/store.ts index ce2a21c6e7..29caa69cbe 100644 --- a/invokeai/frontend/web/src/app/store/store.ts +++ b/invokeai/frontend/web/src/app/store/store.ts @@ -86,10 +86,7 @@ export const store = configureStore({ .concat(autoBatchEnhancer()); }, middleware: (getDefaultMiddleware) => - getDefaultMiddleware({ - immutableCheck: false, - serializableCheck: false, - }) + getDefaultMiddleware() .concat(api.middleware) .concat(dynamicMiddlewares) .prepend(listenerMiddleware.middleware), diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx index e2a9013aac..29b45761ee 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx @@ -1,4 +1,6 @@ import { MenuItem } from '@chakra-ui/react'; +import { useStore } from '@nanostores/react'; +import { $customStarUI } from 'app/store/nanostores/customStarUI'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { imagesToChangeSelected, @@ -12,12 +14,11 @@ import { useStarImagesMutation, useUnstarImagesMutation, } from '../../../../services/api/endpoints/images'; -import { uiSelector } from '../../../ui/store/uiSelectors'; const MultipleSelectionMenuItems = () => { const dispatch = useAppDispatch(); const selection = useAppSelector((state) => state.gallery.selection); - const { customStarUi } = useAppSelector(uiSelector); + const customStarUi = useStore($customStarUI); const [starImages] = useStarImagesMutation(); const [unstarImages] = useUnstarImagesMutation(); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index 68c5c2e1ae..e5b9d94578 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -1,5 +1,7 @@ import { Flex, MenuItem, Spinner } from '@chakra-ui/react'; +import { useStore } from '@nanostores/react'; import { useAppToaster } from 'app/components/Toaster'; +import { $customStarUI } from 'app/store/nanostores/customStarUI'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { @@ -7,6 +9,7 @@ import { isModalOpenChanged, } from 'features/changeBoardModal/store/slice'; import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice'; +import { workflowLoadRequested } from 'features/nodes/store/actions'; import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters'; import { initialImageSelected } from 'features/parameters/store/actions'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; @@ -32,10 +35,8 @@ import { useUnstarImagesMutation, } from 'services/api/endpoints/images'; import { ImageDTO } from 'services/api/types'; -import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; -import { workflowLoadRequested } from 'features/nodes/store/actions'; import { configSelector } from '../../../system/store/configSelectors'; -import { uiSelector } from '../../../ui/store/uiSelectors'; +import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; type SingleSelectionMenuItemsProps = { imageDTO: ImageDTO; @@ -51,7 +52,7 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled; const { shouldFetchMetadataFromApi } = useAppSelector(configSelector); - const { customStarUi } = useAppSelector(uiSelector); + const customStarUi = useStore($customStarUI); const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery( { image: imageDTO, shouldFetchMetadataFromApi }, diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx index 6c34bc31b8..af01eeaea8 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx @@ -1,4 +1,6 @@ import { Box, Flex } from '@chakra-ui/react'; +import { useStore } from '@nanostores/react'; +import { $customStarUI } from 'app/store/nanostores/customStarUI'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIDndImage from 'common/components/IAIDndImage'; import IAIFillSkeleton from 'common/components/IAIFillSkeleton'; @@ -10,6 +12,7 @@ import { } from 'features/dnd/types'; import { useMultiselect } from 'features/gallery/hooks/useMultiselect'; import { MouseEvent, memo, useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { FaTrash } from 'react-icons/fa'; import { MdStar, MdStarBorder } from 'react-icons/md'; import { @@ -18,8 +21,6 @@ import { useUnstarImagesMutation, } from 'services/api/endpoints/images'; import IAIDndImageIcon from '../../../../common/components/IAIDndImageIcon'; -import { uiSelector } from '../../../ui/store/uiSelectors'; -import { useTranslation } from 'react-i18next'; interface HoverableImageProps { imageName: string; @@ -35,7 +36,7 @@ const GalleryImage = (props: HoverableImageProps) => { const { handleClick, isSelected, selection, selectionCount } = useMultiselect(imageDTO); - const { customStarUi } = useAppSelector(uiSelector); + const customStarUi = useStore($customStarUI); const handleDelete = useCallback( (e: MouseEvent) => { diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index 33edc6308f..82c9ef4e77 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -4,7 +4,7 @@ import { initialImageChanged } from 'features/parameters/store/generationSlice'; import { SchedulerParam } from 'features/parameters/types/parameterSchemas'; import { setActiveTabReducer } from './extraReducers'; import { InvokeTabName } from './tabMap'; -import { CustomStarUi, UIState } from './uiTypes'; +import { UIState } from './uiTypes'; export const initialUIState: UIState = { activeTab: 0, @@ -19,7 +19,6 @@ export const initialUIState: UIState = { favoriteSchedulers: [], globalContextMenuCloseTrigger: 0, panels: {}, - customStarUi: undefined, }; export const uiSlice = createSlice({ @@ -71,9 +70,6 @@ export const uiSlice = createSlice({ ) => { state.panels[action.payload.name] = action.payload.value; }, - setCustomStarUi: (state, action: PayloadAction) => { - state.customStarUi = action.payload; - }, }, extraReducers(builder) { builder.addCase(initialImageChanged, (state) => { @@ -95,7 +91,6 @@ export const { setShouldAutoChangeDimensions, contextMenusClosed, panelsChanged, - setCustomStarUi, } = uiSlice.actions; export default uiSlice.reducer; diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts index 8f7b1999a4..41a359a651 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts @@ -1,4 +1,3 @@ -import { MenuItemProps } from '@chakra-ui/react'; import { SchedulerParam } from 'features/parameters/types/parameterSchemas'; export type Coordinates = { @@ -13,17 +12,6 @@ export type Dimensions = { export type Rect = Coordinates & Dimensions; -export type CustomStarUi = { - on: { - icon: MenuItemProps['icon']; - text: string; - }; - off: { - icon: MenuItemProps['icon']; - text: string; - }; -}; - export interface UIState { activeTab: number; shouldShowImageDetails: boolean; @@ -37,5 +25,4 @@ export interface UIState { favoriteSchedulers: SchedulerParam[]; globalContextMenuCloseTrigger: number; panels: Record; - customStarUi?: CustomStarUi; } From 0f93991087004a73c8b2d5b45599c6b60cc509fd Mon Sep 17 00:00:00 2001 From: Jonathan <34005131+JPPhoto@users.noreply.github.com> Date: Thu, 14 Sep 2023 07:56:17 -0500 Subject: [PATCH 03/12] Remove multiple of 8 requirement for ImageResizeInvocation (#4538) Testing required the width and height to be multiples of 8. This is no longer needed. --- invokeai/app/invocations/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/app/invocations/image.py b/invokeai/app/invocations/image.py index fda7561679..11e5fc90a0 100644 --- a/invokeai/app/invocations/image.py +++ b/invokeai/app/invocations/image.py @@ -335,8 +335,8 @@ class ImageResizeInvocation(BaseInvocation): """Resizes an image to specific dimensions""" image: ImageField = InputField(description="The image to resize") - width: int = InputField(default=512, ge=64, multiple_of=8, description="The width to resize to (px)") - height: int = InputField(default=512, ge=64, multiple_of=8, description="The height to resize to (px)") + width: int = InputField(default=512, gt=0, description="The width to resize to (px)") + height: int = InputField(default=512, gt=0, description="The height to resize to (px)") resample_mode: PIL_RESAMPLING_MODES = InputField(default="bicubic", description="The resampling mode") metadata: Optional[CoreMetadata] = InputField( default=None, description=FieldDescriptions.core_metadata, ui_hidden=True From 34a09cb4ca3b3fe05a4569a627e98161a2bea066 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:17:21 +1000 Subject: [PATCH 04/12] fix(ui): fix send to canvas crash A few weeks back, we changed how the canvas scales in response to changes in window/panel size. This introduced a bug where if we the user hadn't already clicked the canvas tab once to initialize the stage elements, the stage's dimensions were zero, then the calculation of the stage's scale ends up zero, then something is divided by that zero and Konva dies. This is only a problem on Chromium browsers - somehow Firefox handles it gracefully. Now, when calculating the stage scale, never return a 0 - if it's a zero, return 1 instead. This is enough to fix the crash, but the image ends up centered on the top-left corner of the stage (the origin of the canvas). Because the canvas elements are not initialized at this point (we haven't switched tabs yet), the stage dimensions fall back to (0,0). This means the center of the stage is also (0,0) - so the image is centered on (0,0), the top-left corner of the stage. To fix this, we need to ensure we: - Change to the canvas tab before actually setting the image, so the stage elements are able to initialize - Use `flushSync` to flush DOM updates for this tab change so we actually have DOM elements to work with - Update the stage dimensions once on first load of it (so in the effect that sets up the resize observer, we update the stage dimensions) The result now is the expected behaviour - images sent to canvas do not crash and end up in the center of the canvas. --- .../web/src/features/canvas/components/IAICanvas.tsx | 2 ++ .../frontend/web/src/features/canvas/util/calculateScale.ts | 2 +- .../components/ImageContextMenu/SingleSelectionMenuItems.tsx | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx index 4f9e47282d..4a67898942 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvas.tsx @@ -154,6 +154,8 @@ const IAICanvas = () => { resizeObserver.observe(containerRef.current); + dispatch(canvasResized(containerRef.current.getBoundingClientRect())); + return () => { resizeObserver.disconnect(); }; diff --git a/invokeai/frontend/web/src/features/canvas/util/calculateScale.ts b/invokeai/frontend/web/src/features/canvas/util/calculateScale.ts index 954c36869c..255cb2850b 100644 --- a/invokeai/frontend/web/src/features/canvas/util/calculateScale.ts +++ b/invokeai/frontend/web/src/features/canvas/util/calculateScale.ts @@ -8,7 +8,7 @@ const calculateScale = ( const scaleX = (containerWidth * padding) / contentWidth; const scaleY = (containerHeight * padding) / contentHeight; const scaleFit = Math.min(1, Math.min(scaleX, scaleY)); - return scaleFit; + return scaleFit ? scaleFit : 1; }; export default calculateScale; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index e5b9d94578..c50b0c13dd 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -37,6 +37,7 @@ import { import { ImageDTO } from 'services/api/types'; import { configSelector } from '../../../system/store/configSelectors'; import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; +import { flushSync } from 'react-dom'; type SingleSelectionMenuItemsProps = { imageDTO: ImageDTO; @@ -115,8 +116,10 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { const handleSendToCanvas = useCallback(() => { dispatch(sentImageToCanvas()); + flushSync(() => { + dispatch(setActiveTab('unifiedCanvas')); + }); dispatch(setInitialCanvasImage(imageDTO)); - dispatch(setActiveTab('unifiedCanvas')); toaster({ title: t('toast.sentToUnifiedCanvas'), From 704e016f058e3e1108e8e269e246c75c777864d1 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 15 Sep 2023 11:33:57 +1000 Subject: [PATCH 05/12] feat(ui): disable immutable redux check The immutable and serializable checks for redux can cause substantial performance issues. The immutable check in particular is pretty heavy. It's only run in dev mode, but this and really slow down the already-slower performance of dev mode. The most important one for us is serializable, which has far less of a performance impact. The immutable check is largely redundant because we use immer-backed RTK for everything and immer gives us confidence there. Disable the immutable check, leaving serializable in. --- invokeai/frontend/web/src/app/store/store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/app/store/store.ts b/invokeai/frontend/web/src/app/store/store.ts index 29caa69cbe..f84f3dd9c7 100644 --- a/invokeai/frontend/web/src/app/store/store.ts +++ b/invokeai/frontend/web/src/app/store/store.ts @@ -86,7 +86,7 @@ export const store = configureStore({ .concat(autoBatchEnhancer()); }, middleware: (getDefaultMiddleware) => - getDefaultMiddleware() + getDefaultMiddleware({ immutableCheck: false }) .concat(api.middleware) .concat(dynamicMiddlewares) .prepend(listenerMiddleware.middleware), From 5a42774fbe098b1efdac79654c02b0826644f023 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:04:38 +1000 Subject: [PATCH 06/12] Update FEATURE_REQUEST.yml Added some verbiage about making feature requests singular and focused. Updated the placeholder to something more Invoke-y. --- .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml index c7e7f4bc87..6d43d447f4 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -34,12 +34,9 @@ body: id: whatisexpected attributes: label: What should this feature add? - description: Please try to explain the functionality this feature should add + description: Explain the functionality this feature should add. Feature requests should be for single features. Please create multiple requests if you want to request multiple features. placeholder: | - Instead of one huge text field, it would be nice to have forms for bug-reports, feature-requests, ... - Great benefits with automatic labeling, assigning and other functionalitys not available in that form - via old-fashioned markdown-templates. I would also love to see the use of a moderator bot 🤖 like - https://github.com/marketplace/actions/issue-moderator-with-commands to auto close old issues and other things + I'd like a button that creates an image of banana sushi every time I press it. Each image should be different. There should be a toggle next to the button that enables strawberry mode, in which the images are of strawberry sushi instead. validations: required: true From 604fc006b15d9c3f3e5cedbc232e2b4907147f48 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:24:53 +1000 Subject: [PATCH 07/12] fix(ui): construct openapi url from window.location.origin --- invokeai/frontend/web/src/services/api/thunks/schema.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/services/api/thunks/schema.ts b/invokeai/frontend/web/src/services/api/thunks/schema.ts index 7dc0bdc331..c209469e02 100644 --- a/invokeai/frontend/web/src/services/api/thunks/schema.ts +++ b/invokeai/frontend/web/src/services/api/thunks/schema.ts @@ -26,7 +26,8 @@ export const receivedOpenAPISchema = createAsyncThunk( 'nodes/receivedOpenAPISchema', async (_, { rejectWithValue }) => { try { - const response = await fetch(`openapi.json`); + const url = [window.location.origin, 'openapi.json'].join('/'); + const response = await fetch(url); const openAPISchema = await response.json(); const schemaJSON = JSON.parse( From 74812511277b907360962d34b63e4cf53da54a08 Mon Sep 17 00:00:00 2001 From: mickr777 Date: Fri, 15 Sep 2023 13:43:32 +1000 Subject: [PATCH 08/12] More Translations and Fixes --- invokeai/frontend/web/public/locales/en.json | 34 +++- .../listeners/canvasCopiedToClipboard.ts | 7 +- .../listeners/canvasDownloadedAsImage.ts | 9 +- .../listeners/canvasImageToControlNet.ts | 7 +- .../listeners/canvasMaskSavedToGallery.ts | 7 +- .../listeners/canvasMaskToControlNet.ts | 7 +- .../listeners/canvasMerged.ts | 11 +- .../listeners/canvasSavedToGallery.ts | 7 +- .../listeners/imageUploaded.ts | 17 +- .../listeners/modelSelected.ts | 5 +- .../listeners/stagingAreaImageSaved.ts | 5 +- .../listeners/workflowLoaded.ts | 5 +- .../web/src/features/nodes/types/constants.ts | 162 +++++++++--------- .../util/graphBuilders/buildCanvasGraph.ts | 9 +- .../buildCanvasImageToImageGraph.ts | 5 +- .../graphBuilders/buildCanvasInpaintGraph.ts | 5 +- .../graphBuilders/buildCanvasOutpaintGraph.ts | 7 +- .../buildCanvasSDXLImageToImageGraph.ts | 5 +- .../buildCanvasSDXLInpaintGraph.ts | 5 +- .../buildCanvasSDXLOutpaintGraph.ts | 5 +- .../buildCanvasSDXLTextToImageGraph.ts | 5 +- .../buildCanvasTextToImageGraph.ts | 5 +- .../buildLinearImageToImageGraph.ts | 11 +- .../buildLinearSDXLImageToImageGraph.ts | 11 +- .../buildLinearSDXLTextToImageGraph.ts | 5 +- .../buildLinearTextToImageGraph.ts | 5 +- 26 files changed, 199 insertions(+), 167 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 7faa10a889..d846f3ca47 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -721,7 +721,6 @@ "noFieldType": "No field type", "noImageFoundState": "No initial image found in state", "noMatchingNodes": "No matching nodes", - "noModelFoundState": "No model found in state", "noNodeSelected": "No node selected", "noOpacity": "Node Opacity", "noOutputRecorded": "No outputs recorded", @@ -964,8 +963,14 @@ "useSlidersForAll": "Use Sliders For All Options" }, "toast": { + "addedToBoard": "Added to board", + "baseModelChangedCleared": "Base model changed, cleared", "canceled": "Processing Canceled", + "canvasCopiedClipboard": "Canvas Copied to Clipboard", + "canvasDownloaded": "Canvas Downloaded", "canvasMerged": "Canvas Merged", + "canvasSavedGallery": "Canvas Saved to Gallery", + "canvasSentControlnetAssets": "Canvas Sent to ControlNet & Assets", "connected": "Connected to Server", "disconnected": "Disconnected from Server", "downloadImageStarted": "Image Download Started", @@ -974,10 +979,18 @@ "imageLinkCopied": "Image Link Copied", "imageNotLoaded": "No Image Loaded", "imageNotLoadedDesc": "Could not find image", + "imageSaved": "Image Saved", "imageSavedToGallery": "Image Saved to Gallery", + "imageSavingFailed": "Image Saving Failed", + "imageUploaded": "Image Uploaded", + "imageUploadFailed": "Image Upload Failed", + "incompatibleSubmodel": "incompatible submodel", "initialImageNotSet": "Initial Image Not Set", "initialImageNotSetDesc": "Could not load initial image", "initialImageSet": "Initial Image Set", + "loadedWithWarnings": "Workflow Loaded with Warnings", + "maskSavedAssets": "Mask Saved to Assets", + "maskSentControlnetAssets": "Mask Sent to ControlNet & Assets", "metadataLoadFailed": "Failed to load metadata", "modelAdded": "Model Added: {{modelName}}", "modelAddedSimple": "Model Added", @@ -998,8 +1011,20 @@ "parametersNotSet": "Parameters Not Set", "parametersNotSetDesc": "No metadata found for this image.", "parametersSet": "Parameters Set", + "problemCopyingCanvas": "Problem Copying Canvas", + "problemCopyingCanvasDesc": "Unable to export base layer", "problemCopyingImage": "Unable to Copy Image", "problemCopyingImageLink": "Unable to Copy Image Link", + "problemDownloadingCanvas": "Problem Downloading Canvas", + "problemDownloadingCanvasDesc": "Unable to export base layer", + "problemImportingMask": "Problem Importing Mask", + "problemImportingMaskDesc": "Unable to export mask", + "problemMergingCanvas": "Problem Merging Canvas", + "problemMergingCanvasDesc": "Unable to export base layer", + "problemSavingCanvas": "Problem Saving Canvas", + "problemSavingCanvasDesc": "Unable to export base layer", + "problemSavingMask": "Problem Saving Mask", + "problemSavingMaskDesc": "Unable to export mask", "promptNotSet": "Prompt Not Set", "promptNotSetDesc": "Could not find prompt for this image.", "promptSet": "Prompt Set", @@ -1009,11 +1034,16 @@ "sentToImageToImage": "Sent To Image To Image", "sentToUnifiedCanvas": "Sent to Unified Canvas", "serverError": "Server Error", + "setCanvasInitialImage": "Set as canvas initial image", + "setControlImage": "Set as control image", + "setInitialImage": "Set as initial image", + "setNodeField": "Set as node field", "tempFoldersEmptied": "Temp Folder Emptied", "uploadFailed": "Upload failed", "uploadFailedInvalidUploadDesc": "Must be single PNG or JPEG image", "uploadFailedUnableToLoadDesc": "Unable to load file", - "upscalingFailed": "Upscaling Failed" + "upscalingFailed": "Upscaling Failed", + "workflowLoaded": "Workflow Loaded" }, "tooltip": { "feature": { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasCopiedToClipboard.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasCopiedToClipboard.ts index 9e66d1bdb8..c328aceedf 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasCopiedToClipboard.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasCopiedToClipboard.ts @@ -4,6 +4,7 @@ import { $logger } from 'app/logging/logger'; import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob'; import { addToast } from 'features/system/store/systemSlice'; import { copyBlobToClipboard } from 'features/canvas/util/copyBlobToClipboard'; +import { t } from 'i18next'; export const addCanvasCopiedToClipboardListener = () => { startAppListening({ @@ -20,8 +21,8 @@ export const addCanvasCopiedToClipboardListener = () => { moduleLog.error('Problem getting base layer blob'); dispatch( addToast({ - title: 'Problem Copying Canvas', - description: 'Unable to export base layer', + title: t('toast.problemCopyingCanvas'), + description: t('toast.problemCopyingCanvasDesc'), status: 'error', }) ); @@ -32,7 +33,7 @@ export const addCanvasCopiedToClipboardListener = () => { dispatch( addToast({ - title: 'Canvas Copied to Clipboard', + title: t('toast.canvasCopiedClipboard'), status: 'success', }) ); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasDownloadedAsImage.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasDownloadedAsImage.ts index b101d00541..23faf4a356 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasDownloadedAsImage.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasDownloadedAsImage.ts @@ -4,6 +4,7 @@ import { $logger } from 'app/logging/logger'; import { downloadBlob } from 'features/canvas/util/downloadBlob'; import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob'; import { addToast } from 'features/system/store/systemSlice'; +import { t } from 'i18next'; export const addCanvasDownloadedAsImageListener = () => { startAppListening({ @@ -20,8 +21,8 @@ export const addCanvasDownloadedAsImageListener = () => { moduleLog.error('Problem getting base layer blob'); dispatch( addToast({ - title: 'Problem Downloading Canvas', - description: 'Unable to export base layer', + title: t('toast.problemDownloadingCanvas'), + description: t('toast.problemDownloadingCanvasDesc'), status: 'error', }) ); @@ -29,7 +30,9 @@ export const addCanvasDownloadedAsImageListener = () => { } downloadBlob(blob, 'canvas.png'); - dispatch(addToast({ title: 'Canvas Downloaded', status: 'success' })); + dispatch( + addToast({ title: t('toast.canvasDownloaded'), status: 'success' }) + ); }, }); }; diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasImageToControlNet.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasImageToControlNet.ts index fb411a6e25..5181df134f 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasImageToControlNet.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasImageToControlNet.ts @@ -5,6 +5,7 @@ import { controlNetImageChanged } from 'features/controlNet/store/controlNetSlic import { addToast } from 'features/system/store/systemSlice'; import { imagesApi } from 'services/api/endpoints/images'; import { startAppListening } from '..'; +import { t } from 'i18next'; export const addCanvasImageToControlNetListener = () => { startAppListening({ @@ -19,8 +20,8 @@ export const addCanvasImageToControlNetListener = () => { log.error('Problem getting base layer blob'); dispatch( addToast({ - title: 'Problem Saving Canvas', - description: 'Unable to export base layer', + title: t('toast.problemSavingCanvas'), + description: t('toast.problemSavingCanvasDesc'), status: 'error', }) ); @@ -40,7 +41,7 @@ export const addCanvasImageToControlNetListener = () => { crop_visible: true, postUploadAction: { type: 'TOAST', - toastOptions: { title: 'Canvas Sent to ControlNet & Assets' }, + toastOptions: { title: t('toast.canvasSentControlnetAssets') }, }, }) ).unwrap(); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskSavedToGallery.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskSavedToGallery.ts index e701b93352..f814d94f3a 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskSavedToGallery.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskSavedToGallery.ts @@ -4,6 +4,7 @@ import { getCanvasData } from 'features/canvas/util/getCanvasData'; import { addToast } from 'features/system/store/systemSlice'; import { imagesApi } from 'services/api/endpoints/images'; import { startAppListening } from '..'; +import { t } from 'i18next'; export const addCanvasMaskSavedToGalleryListener = () => { startAppListening({ @@ -30,8 +31,8 @@ export const addCanvasMaskSavedToGalleryListener = () => { log.error('Problem getting mask layer blob'); dispatch( addToast({ - title: 'Problem Saving Mask', - description: 'Unable to export mask', + title: t('toast.problemSavingMask'), + description: t('toast.problemSavingMaskDesc'), status: 'error', }) ); @@ -51,7 +52,7 @@ export const addCanvasMaskSavedToGalleryListener = () => { crop_visible: true, postUploadAction: { type: 'TOAST', - toastOptions: { title: 'Mask Saved to Assets' }, + toastOptions: { title: t('toast.maskSavedAssets') }, }, }) ); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskToControlNet.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskToControlNet.ts index 6c97259f02..671c7f63e4 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskToControlNet.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMaskToControlNet.ts @@ -5,6 +5,7 @@ import { controlNetImageChanged } from 'features/controlNet/store/controlNetSlic import { addToast } from 'features/system/store/systemSlice'; import { imagesApi } from 'services/api/endpoints/images'; import { startAppListening } from '..'; +import { t } from 'i18next'; export const addCanvasMaskToControlNetListener = () => { startAppListening({ @@ -31,8 +32,8 @@ export const addCanvasMaskToControlNetListener = () => { log.error('Problem getting mask layer blob'); dispatch( addToast({ - title: 'Problem Importing Mask', - description: 'Unable to export mask', + title: t('toast.problemImportingMask'), + description: t('toast.problemImportingMaskDesc'), status: 'error', }) ); @@ -52,7 +53,7 @@ export const addCanvasMaskToControlNetListener = () => { crop_visible: true, postUploadAction: { type: 'TOAST', - toastOptions: { title: 'Mask Sent to ControlNet & Assets' }, + toastOptions: { title: t('toast.maskSentControlnetAssets') }, }, }) ).unwrap(); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts index 21c506242d..62f7b60036 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasMerged.ts @@ -6,6 +6,7 @@ import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider'; import { addToast } from 'features/system/store/systemSlice'; import { imagesApi } from 'services/api/endpoints/images'; import { startAppListening } from '..'; +import { t } from 'i18next'; export const addCanvasMergedListener = () => { startAppListening({ @@ -20,8 +21,8 @@ export const addCanvasMergedListener = () => { moduleLog.error('Problem getting base layer blob'); dispatch( addToast({ - title: 'Problem Merging Canvas', - description: 'Unable to export base layer', + title: t('toast.problemMergingCanvas'), + description: t('toast.problemMergingCanvasDesc'), status: 'error', }) ); @@ -34,8 +35,8 @@ export const addCanvasMergedListener = () => { moduleLog.error('Problem getting canvas base layer'); dispatch( addToast({ - title: 'Problem Merging Canvas', - description: 'Unable to export base layer', + title: t('toast.problemMergingCanvas'), + description: t('toast.problemMergingCanvasDesc'), status: 'error', }) ); @@ -55,7 +56,7 @@ export const addCanvasMergedListener = () => { is_intermediate: true, postUploadAction: { type: 'TOAST', - toastOptions: { title: 'Canvas Merged' }, + toastOptions: { title: t('toast.canvasMerged') }, }, }) ).unwrap(); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSavedToGallery.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSavedToGallery.ts index dbadb72a52..0bb8ad8550 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSavedToGallery.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSavedToGallery.ts @@ -4,6 +4,7 @@ import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob'; import { addToast } from 'features/system/store/systemSlice'; import { imagesApi } from 'services/api/endpoints/images'; import { startAppListening } from '..'; +import { t } from 'i18next'; export const addCanvasSavedToGalleryListener = () => { startAppListening({ @@ -18,8 +19,8 @@ export const addCanvasSavedToGalleryListener = () => { log.error('Problem getting base layer blob'); dispatch( addToast({ - title: 'Problem Saving Canvas', - description: 'Unable to export base layer', + title: t('toast.problemSavingCanvas'), + description: t('toast.problemSavingCanvasDesc'), status: 'error', }) ); @@ -39,7 +40,7 @@ export const addCanvasSavedToGalleryListener = () => { crop_visible: true, postUploadAction: { type: 'TOAST', - toastOptions: { title: 'Canvas Saved to Gallery' }, + toastOptions: { title: t('toast.canvasSavedGallery') }, }, }) ); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts index 0c55908748..2cc406469b 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts @@ -9,9 +9,10 @@ import { omit } from 'lodash-es'; import { boardsApi } from 'services/api/endpoints/boards'; import { startAppListening } from '..'; import { imagesApi } from '../../../../../services/api/endpoints/images'; +import { t } from 'i18next'; const DEFAULT_UPLOADED_TOAST: UseToastOptions = { - title: 'Image Uploaded', + title: t('toast.imageUploaded'), status: 'success', }; @@ -57,8 +58,8 @@ export const addImageUploadedFulfilledListener = () => { // Fall back to just the board id if we can't find the board for some reason const board = data?.find((b) => b.board_id === autoAddBoardId); const description = board - ? `Added to board ${board.board_name}` - : `Added to board ${autoAddBoardId}`; + ? `${t('toast.addedToBoard')} ${board.board_name}` + : `${t('toast.addedToBoard')} ${autoAddBoardId}`; dispatch( addToast({ @@ -75,7 +76,7 @@ export const addImageUploadedFulfilledListener = () => { dispatch( addToast({ ...DEFAULT_UPLOADED_TOAST, - description: 'Set as canvas initial image', + description: t('toast.setCanvasInitialImage'), }) ); return; @@ -92,7 +93,7 @@ export const addImageUploadedFulfilledListener = () => { dispatch( addToast({ ...DEFAULT_UPLOADED_TOAST, - description: 'Set as control image', + description: t('toast.setControlImage'), }) ); return; @@ -103,7 +104,7 @@ export const addImageUploadedFulfilledListener = () => { dispatch( addToast({ ...DEFAULT_UPLOADED_TOAST, - description: 'Set as initial image', + description: t('toast.setInitialImage'), }) ); return; @@ -117,7 +118,7 @@ export const addImageUploadedFulfilledListener = () => { dispatch( addToast({ ...DEFAULT_UPLOADED_TOAST, - description: `Set as node field ${fieldName}`, + description: `${t('toast.setNodeField')} ${fieldName}`, }) ); return; @@ -140,7 +141,7 @@ export const addImageUploadedRejectedListener = () => { log.error({ ...sanitizedData }, 'Image upload failed'); dispatch( addToast({ - title: 'Image Upload Failed', + title: t('toast.imageUploadFailed'), description: action.error.message, status: 'error', }) diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts index 240890f043..eb25b22293 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts @@ -14,6 +14,7 @@ import { addToast } from 'features/system/store/systemSlice'; import { makeToast } from 'features/system/util/makeToast'; import { forEach } from 'lodash-es'; import { startAppListening } from '..'; +import { t } from 'i18next'; export const addModelSelectedListener = () => { startAppListening({ @@ -67,7 +68,9 @@ export const addModelSelectedListener = () => { dispatch( addToast( makeToast({ - title: `Base model changed, cleared ${modelsCleared} incompatible submodel${ + title: `${t( + 'toast.baseModelChangedCleared' + )} ${modelsCleared} ${t('toast.incompatibleSubmodel')}${ modelsCleared === 1 ? '' : 's' }`, status: 'warning', diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved.ts index b14e18ea63..c00cf78beb 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved.ts @@ -2,6 +2,7 @@ import { stagingAreaImageSaved } from 'features/canvas/store/actions'; import { addToast } from 'features/system/store/systemSlice'; import { imagesApi } from 'services/api/endpoints/images'; import { startAppListening } from '..'; +import { t } from 'i18next'; export const addStagingAreaImageSavedListener = () => { startAppListening({ @@ -28,11 +29,11 @@ export const addStagingAreaImageSavedListener = () => { }) ); } - dispatch(addToast({ title: 'Image Saved', status: 'success' })); + dispatch(addToast({ title: t('toast.imageSaved'), status: 'success' })); } catch (error) { dispatch( addToast({ - title: 'Image Saving Failed', + title: t('toast.imageSavingFailed'), description: (error as Error)?.message, status: 'error', }) diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoaded.ts index c447720941..de697a70e5 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoaded.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoaded.ts @@ -7,6 +7,7 @@ import { addToast } from 'features/system/store/systemSlice'; import { makeToast } from 'features/system/util/makeToast'; import { setActiveTab } from 'features/ui/store/uiSlice'; import { startAppListening } from '..'; +import { t } from 'i18next'; export const addWorkflowLoadedListener = () => { startAppListening({ @@ -27,7 +28,7 @@ export const addWorkflowLoadedListener = () => { dispatch( addToast( makeToast({ - title: 'Workflow Loaded', + title: t('toast.workflowLoaded'), status: 'success', }) ) @@ -36,7 +37,7 @@ export const addWorkflowLoadedListener = () => { dispatch( addToast( makeToast({ - title: 'Workflow Loaded with Warnings', + title: t('toast.loadedWithWarnings'), status: 'warning', }) ) diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index 11b74cd002..0ab10db159 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -1,5 +1,5 @@ import { FieldType, FieldUIConfig } from './types'; -import i18n from 'i18next'; +import { t } from 'i18next'; export const HANDLE_TOOLTIP_OPEN_DELAY = 500; export const COLOR_TOKEN_VALUE = 500; @@ -103,73 +103,73 @@ export const isPolymorphicItemType = ( export const FIELDS: Record = { boolean: { color: 'green.500', - description: i18n.t('nodes.booleanDescription'), - title: i18n.t('nodes.boolean'), + description: t('nodes.booleanDescription'), + title: t('nodes.boolean'), }, BooleanCollection: { color: 'green.500', - description: i18n.t('nodes.booleanCollectionDescription'), - title: i18n.t('nodes.booleanCollection'), + description: t('nodes.booleanCollectionDescription'), + title: t('nodes.booleanCollection'), }, BooleanPolymorphic: { color: 'green.500', - description: i18n.t('nodes.booleanPolymorphicDescription'), - title: i18n.t('nodes.booleanPolymorphic'), + description: t('nodes.booleanPolymorphicDescription'), + title: t('nodes.booleanPolymorphic'), }, ClipField: { color: 'green.500', - description: i18n.t('nodes.clipFieldDescription'), - title: i18n.t('nodes.clipField'), + description: t('nodes.clipFieldDescription'), + title: t('nodes.clipField'), }, Collection: { color: 'base.500', - description: i18n.t('nodes.collectionDescription'), - title: i18n.t('nodes.collection'), + description: t('nodes.collectionDescription'), + title: t('nodes.collection'), }, CollectionItem: { color: 'base.500', - description: i18n.t('nodes.collectionItemDescription'), - title: i18n.t('nodes.collectionItem'), + description: t('nodes.collectionItemDescription'), + title: t('nodes.collectionItem'), }, ColorCollection: { color: 'pink.300', - description: i18n.t('nodes.colorCollectionDescription'), - title: i18n.t('nodes.colorCollection'), + description: t('nodes.colorCollectionDescription'), + title: t('nodes.colorCollection'), }, ColorField: { color: 'pink.300', - description: i18n.t('nodes.colorFieldDescription'), - title: i18n.t('nodes.colorField'), + description: t('nodes.colorFieldDescription'), + title: t('nodes.colorField'), }, ColorPolymorphic: { color: 'pink.300', - description: i18n.t('nodes.colorPolymorphicDescription'), - title: i18n.t('nodes.colorPolymorphic'), + description: t('nodes.colorPolymorphicDescription'), + title: t('nodes.colorPolymorphic'), }, ConditioningCollection: { color: 'cyan.500', - description: i18n.t('nodes.conditioningCollectionDescription'), - title: i18n.t('nodes.conditioningCollection'), + description: t('nodes.conditioningCollectionDescription'), + title: t('nodes.conditioningCollection'), }, ConditioningField: { color: 'cyan.500', - description: i18n.t('nodes.conditioningFieldDescription'), - title: i18n.t('nodes.conditioningField'), + description: t('nodes.conditioningFieldDescription'), + title: t('nodes.conditioningField'), }, ConditioningPolymorphic: { color: 'cyan.500', - description: i18n.t('nodes.conditioningPolymorphicDescription'), - title: i18n.t('nodes.conditioningPolymorphic'), + description: t('nodes.conditioningPolymorphicDescription'), + title: t('nodes.conditioningPolymorphic'), }, ControlCollection: { color: 'teal.500', - description: i18n.t('nodes.controlCollectionDescription'), - title: i18n.t('nodes.controlCollection'), + description: t('nodes.controlCollectionDescription'), + title: t('nodes.controlCollection'), }, ControlField: { color: 'teal.500', - description: i18n.t('nodes.controlFieldDescription'), - title: i18n.t('nodes.controlField'), + description: t('nodes.controlFieldDescription'), + title: t('nodes.controlField'), }, ControlNetModelField: { color: 'teal.500', @@ -183,132 +183,132 @@ export const FIELDS: Record = { }, DenoiseMaskField: { color: 'blue.300', - description: i18n.t('nodes.denoiseMaskFieldDescription'), - title: i18n.t('nodes.denoiseMaskField'), + description: t('nodes.denoiseMaskFieldDescription'), + title: t('nodes.denoiseMaskField'), }, enum: { color: 'blue.500', - description: i18n.t('nodes.enumDescription'), - title: i18n.t('nodes.enum'), + description: t('nodes.enumDescription'), + title: t('nodes.enum'), }, float: { color: 'orange.500', - description: i18n.t('nodes.floatDescription'), - title: i18n.t('nodes.float'), + description: t('nodes.floatDescription'), + title: t('nodes.float'), }, FloatCollection: { color: 'orange.500', - description: i18n.t('nodes.floatCollectionDescription'), - title: i18n.t('nodes.floatCollection'), + description: t('nodes.floatCollectionDescription'), + title: t('nodes.floatCollection'), }, FloatPolymorphic: { color: 'orange.500', - description: i18n.t('nodes.floatPolymorphicDescription'), - title: i18n.t('nodes.floatPolymorphic'), + description: t('nodes.floatPolymorphicDescription'), + title: t('nodes.floatPolymorphic'), }, ImageCollection: { color: 'purple.500', - description: i18n.t('nodes.imageCollectionDescription'), - title: i18n.t('nodes.imageCollection'), + description: t('nodes.imageCollectionDescription'), + title: t('nodes.imageCollection'), }, ImageField: { color: 'purple.500', - description: i18n.t('nodes.imageFieldDescription'), - title: i18n.t('nodes.imageField'), + description: t('nodes.imageFieldDescription'), + title: t('nodes.imageField'), }, ImagePolymorphic: { color: 'purple.500', - description: i18n.t('nodes.imagePolymorphicDescription'), - title: i18n.t('nodes.imagePolymorphic'), + description: t('nodes.imagePolymorphicDescription'), + title: t('nodes.imagePolymorphic'), }, integer: { color: 'red.500', - description: i18n.t('nodes.integerDescription'), - title: i18n.t('nodes.integer'), + description: t('nodes.integerDescription'), + title: t('nodes.integer'), }, IntegerCollection: { color: 'red.500', - description: i18n.t('nodes.integerCollectionDescription'), - title: i18n.t('nodes.integerCollection'), + description: t('nodes.integerCollectionDescription'), + title: t('nodes.integerCollection'), }, IntegerPolymorphic: { color: 'red.500', - description: i18n.t('nodes.integerPolymorphicDescription'), - title: i18n.t('nodes.integerPolymorphic'), + description: t('nodes.integerPolymorphicDescription'), + title: t('nodes.integerPolymorphic'), }, LatentsCollection: { color: 'pink.500', - description: i18n.t('nodes.latentsCollectionDescription'), - title: i18n.t('nodes.latentsCollection'), + description: t('nodes.latentsCollectionDescription'), + title: t('nodes.latentsCollection'), }, LatentsField: { color: 'pink.500', - description: i18n.t('nodes.latentsFieldDescription'), - title: i18n.t('nodes.latentsField'), + description: t('nodes.latentsFieldDescription'), + title: t('nodes.latentsField'), }, LatentsPolymorphic: { color: 'pink.500', - description: i18n.t('nodes.latentsPolymorphicDescription'), - title: i18n.t('nodes.latentsPolymorphic'), + description: t('nodes.latentsPolymorphicDescription'), + title: t('nodes.latentsPolymorphic'), }, LoRAModelField: { color: 'teal.500', - description: i18n.t('nodes.loRAModelFieldDescription'), - title: i18n.t('nodes.loRAModelField'), + description: t('nodes.loRAModelFieldDescription'), + title: t('nodes.loRAModelField'), }, MainModelField: { color: 'teal.500', - description: i18n.t('nodes.mainModelFieldDescription'), - title: i18n.t('nodes.mainModelField'), + description: t('nodes.mainModelFieldDescription'), + title: t('nodes.mainModelField'), }, ONNXModelField: { color: 'teal.500', - description: i18n.t('nodes.oNNXModelFieldDescription'), - title: i18n.t('nodes.oNNXModelField'), + description: t('nodes.oNNXModelFieldDescription'), + title: t('nodes.oNNXModelField'), }, Scheduler: { color: 'base.500', - description: i18n.t('nodes.schedulerDescription'), - title: i18n.t('nodes.scheduler'), + description: t('nodes.schedulerDescription'), + title: t('nodes.scheduler'), }, SDXLMainModelField: { color: 'teal.500', - description: i18n.t('nodes.sDXLMainModelFieldDescription'), - title: i18n.t('nodes.sDXLMainModelField'), + description: t('nodes.sDXLMainModelFieldDescription'), + title: t('nodes.sDXLMainModelField'), }, SDXLRefinerModelField: { color: 'teal.500', - description: i18n.t('nodes.sDXLRefinerModelFieldDescription'), - title: i18n.t('nodes.sDXLRefinerModelField'), + description: t('nodes.sDXLRefinerModelFieldDescription'), + title: t('nodes.sDXLRefinerModelField'), }, string: { color: 'yellow.500', - description: i18n.t('nodes.stringDescription'), - title: i18n.t('nodes.string'), + description: t('nodes.stringDescription'), + title: t('nodes.string'), }, StringCollection: { color: 'yellow.500', - description: i18n.t('nodes.stringCollectionDescription'), - title: i18n.t('nodes.stringCollection'), + description: t('nodes.stringCollectionDescription'), + title: t('nodes.stringCollection'), }, StringPolymorphic: { color: 'yellow.500', - description: i18n.t('nodes.stringPolymorphicDescription'), - title: i18n.t('nodes.stringPolymorphic'), + description: t('nodes.stringPolymorphicDescription'), + title: t('nodes.stringPolymorphic'), }, UNetField: { color: 'red.500', - description: i18n.t('nodes.uNetFieldDescription'), - title: i18n.t('nodes.uNetField'), + description: t('nodes.uNetFieldDescription'), + title: t('nodes.uNetField'), }, VaeField: { color: 'blue.500', - description: i18n.t('nodes.vaeFieldDescription'), - title: i18n.t('nodes.vaeField'), + description: t('nodes.vaeFieldDescription'), + title: t('nodes.vaeField'), }, VaeModelField: { color: 'teal.500', - description: i18n.t('nodes.vaeModelFieldDescription'), - title: i18n.t('nodes.vaeModelField'), + description: t('nodes.vaeModelFieldDescription'), + title: t('nodes.vaeModelField'), }, }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts index bfed5f417a..9e21a292b8 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts @@ -9,7 +9,6 @@ import { buildCanvasSDXLInpaintGraph } from './buildCanvasSDXLInpaintGraph'; import { buildCanvasSDXLOutpaintGraph } from './buildCanvasSDXLOutpaintGraph'; import { buildCanvasSDXLTextToImageGraph } from './buildCanvasSDXLTextToImageGraph'; import { buildCanvasTextToImageGraph } from './buildCanvasTextToImageGraph'; -import i18n from 'i18next'; export const buildCanvasGraph = ( state: RootState, @@ -30,7 +29,7 @@ export const buildCanvasGraph = ( } } else if (generationMode === 'img2img') { if (!canvasInitImage) { - throw new Error(i18n.t('nodes.missingCanvaInitImage')); + throw new Error('Missing canvas init image'); } if ( state.generation.model && @@ -42,7 +41,7 @@ export const buildCanvasGraph = ( } } else if (generationMode === 'inpaint') { if (!canvasInitImage || !canvasMaskImage) { - throw new Error(i18n.t('nodes.missingCanvaInitMaskImages')); + throw new Error('Missing canvas init and mask images'); } if ( state.generation.model && @@ -58,7 +57,7 @@ export const buildCanvasGraph = ( } } else { if (!canvasInitImage) { - throw new Error(i18n.t('nodes.missingCanvaInitImage')); + throw new Error('Missing canvas init image'); } if ( state.generation.model && @@ -75,4 +74,4 @@ export const buildCanvasGraph = ( } return graph; -}; +}; \ No newline at end of file diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts index b27ffe7149..e750b40220 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasImageToImageGraph.ts @@ -25,7 +25,6 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from './constants'; -import i18n from 'i18next'; /** * Builds the Canvas tab's Image to Image graph. @@ -67,8 +66,8 @@ export const buildCanvasImageToImageGraph = ( ); if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } let modelLoaderNodeId = MAIN_MODEL_LOADER; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts index 3a0db8c55a..bfedc03de4 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasInpaintGraph.ts @@ -44,7 +44,6 @@ import { RANGE_OF_SIZE, SEAMLESS, } from './constants'; -import i18n from 'i18next'; /** * Builds the Canvas tab's Inpaint graph. @@ -80,8 +79,8 @@ export const buildCanvasInpaintGraph = ( } = state.generation; if (!model) { - log.error(i18n.t('nodes.noImageFoundState')); - throw new Error(i18n.t('nodes.noImageFoundState')); + log.error('No Image found in state'); + throw new Error('No Image found in state'); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts index 2222fcbfe8..add94e4b57 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts @@ -46,7 +46,6 @@ import { RANGE_OF_SIZE, SEAMLESS, } from './constants'; -import i18n from 'i18next'; /** * Builds the Canvas tab's Outpaint graph. @@ -84,8 +83,8 @@ export const buildCanvasOutpaintGraph = ( } = state.generation; if (!model) { - log.error(i18n.t('nodes.noImageFoundState')); - throw new Error(i18n.t('nodes.noImageFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } // The bounding box determines width and height, not the width and height params @@ -851,4 +850,4 @@ export const buildCanvasOutpaintGraph = ( } return graph; -}; +}; \ No newline at end of file diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts index 6beb4c725c..2a677a8775 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts @@ -27,7 +27,6 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; -import i18n from 'i18next'; /** * Builds the Canvas tab's Image to Image graph. @@ -75,8 +74,8 @@ export const buildCanvasSDXLImageToImageGraph = ( ); if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } // Model Loader ID diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts index 6b63ec4e44..baa1c0155f 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLInpaintGraph.ts @@ -46,7 +46,6 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; -import i18n from 'i18next'; /** * Builds the Canvas tab's Inpaint graph. @@ -87,8 +86,8 @@ export const buildCanvasSDXLInpaintGraph = ( } = state.sdxl; if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts index c1105c0ecd..3f8fffb70a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLOutpaintGraph.ts @@ -48,7 +48,6 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; -import i18n from 'i18next'; /** * Builds the Canvas tab's Outpaint graph. @@ -91,8 +90,8 @@ export const buildCanvasSDXLOutpaintGraph = ( } = state.sdxl; if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } // The bounding box determines width and height, not the width and height params diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts index 07f9b8f573..6d787987ef 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts @@ -29,7 +29,6 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; -import i18n from 'i18next'; /** * Builds the Canvas tab's Text to Image graph. @@ -72,8 +71,8 @@ export const buildCanvasSDXLTextToImageGraph = ( state.sdxl; if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } const use_cpu = shouldUseNoiseSettings diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts index ae06a27a3e..094a7b02cc 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasTextToImageGraph.ts @@ -27,7 +27,6 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from './constants'; -import i18n from 'i18next'; /** * Builds the Canvas tab's Text to Image graph. @@ -67,8 +66,8 @@ export const buildCanvasTextToImageGraph = ( ); if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } const use_cpu = shouldUseNoiseSettings diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts index b032e6d9f7..ee1526c20d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts @@ -27,7 +27,6 @@ import { RESIZE, SEAMLESS, } from './constants'; -import i18n from 'i18next'; /** * Builds the Image to Image tab graph. @@ -76,13 +75,13 @@ export const buildLinearImageToImageGraph = ( */ if (!initialImage) { - log.error(i18n.t('nodes.noImageFoundState')); - throw new Error(i18n.t('nodes.noImageFoundState')); + log.error('No initial image found in state'); + throw new Error('No initial image found in state'); } if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } const fp32 = vaePrecision === 'fp32'; @@ -377,4 +376,4 @@ export const buildLinearImageToImageGraph = ( } return graph; -}; +}; \ No newline at end of file diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts index 7dd4aaf301..9d39aa2147 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts @@ -29,7 +29,6 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; -import i18n from 'i18next'; /** * Builds the Image to Image tab graph. @@ -76,13 +75,13 @@ export const buildLinearSDXLImageToImageGraph = ( */ if (!initialImage) { - log.error(i18n.t('nodes.noImageFoundState')); - throw new Error(i18n.t('nodes.noImageFoundState')); + log.error('No initial image found in state'); + throw new Error('No initial image found in state'); } if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } const fp32 = vaePrecision === 'fp32'; @@ -400,4 +399,4 @@ export const buildLinearSDXLImageToImageGraph = ( } return graph; -}; +}; \ No newline at end of file diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts index 86ea08b41c..9590e77f89 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts @@ -23,7 +23,6 @@ import { SEAMLESS, } from './constants'; import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt'; -import i18n from 'i18next'; export const buildLinearSDXLTextToImageGraph = ( state: RootState @@ -59,8 +58,8 @@ export const buildLinearSDXLTextToImageGraph = ( : initialGenerationState.shouldUseCpuNoise; if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } const fp32 = vaePrecision === 'fp32'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts index 6ca16b0ae0..5c534fff21 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearTextToImageGraph.ts @@ -26,7 +26,6 @@ import { SEAMLESS, TEXT_TO_IMAGE_GRAPH, } from './constants'; -import i18n from 'i18next'; export const buildLinearTextToImageGraph = ( state: RootState @@ -54,8 +53,8 @@ export const buildLinearTextToImageGraph = ( : initialGenerationState.shouldUseCpuNoise; if (!model) { - log.error(i18n.t('nodes.noModelFoundState')); - throw new Error(i18n.t('nodes.noModelFoundState')); + log.error('No model found in state'); + throw new Error('No model found in state'); } const fp32 = vaePrecision === 'fp32'; From 368bd6f7784a8c52ddd95274c71640fdb513b2cf Mon Sep 17 00:00:00 2001 From: mickr777 Date: Fri, 15 Sep 2023 14:04:28 +1000 Subject: [PATCH 09/12] Prettier Fixes --- .../src/features/nodes/util/graphBuilders/buildCanvasGraph.ts | 2 +- .../nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts | 2 +- .../nodes/util/graphBuilders/buildLinearImageToImageGraph.ts | 2 +- .../util/graphBuilders/buildLinearSDXLImageToImageGraph.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts index 9e21a292b8..d268a3990d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasGraph.ts @@ -74,4 +74,4 @@ export const buildCanvasGraph = ( } return graph; -}; \ No newline at end of file +}; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts index add94e4b57..71d3492bdc 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasOutpaintGraph.ts @@ -850,4 +850,4 @@ export const buildCanvasOutpaintGraph = ( } return graph; -}; \ No newline at end of file +}; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts index ee1526c20d..dc9a34c67e 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearImageToImageGraph.ts @@ -376,4 +376,4 @@ export const buildLinearImageToImageGraph = ( } return graph; -}; \ No newline at end of file +}; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts index 9d39aa2147..757a3976bb 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts @@ -399,4 +399,4 @@ export const buildLinearSDXLImageToImageGraph = ( } return graph; -}; \ No newline at end of file +}; From 54dc912c839684fa02ede0208193ae50bf6fd54a Mon Sep 17 00:00:00 2001 From: mickr777 Date: Fri, 15 Sep 2023 14:13:54 +1000 Subject: [PATCH 10/12] Revert some test Changes --- .../getMetadataAndWorkflowFromImageBlob.ts | 5 ++-- .../src/features/nodes/util/parseSchema.ts | 26 ++++++++----------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts index 6f850e7d29..b46a701757 100644 --- a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts +++ b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts @@ -7,7 +7,6 @@ import { zWorkflow, } from 'features/nodes/types/types'; import { get } from 'lodash-es'; -import i18n from 'i18next'; export const getMetadataAndWorkflowFromImageBlob = async ( image: Blob @@ -24,7 +23,7 @@ export const getMetadataAndWorkflowFromImageBlob = async ( } else { logger('system').error( { error: parseify(metadataResult.error) }, - i18n.t('nodes.problemReadingMetadata') + 'Problem reading metadata from image' ); } } @@ -37,7 +36,7 @@ export const getMetadataAndWorkflowFromImageBlob = async ( } else { logger('system').error( { error: parseify(workflowResult.error) }, - i18n.t('nodes.problemReadingWorkflow') + 'Problem reading workflow from image' ); } } diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index 55ca593827..8615a12c46 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -15,7 +15,6 @@ import { isInvocationSchemaObject, } from '../types/types'; import { buildInputFieldTemplate, getFieldType } from './fieldTemplateBuilders'; -import i18n from 'i18next'; const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'metadata']; const RESERVED_OUTPUT_FIELD_NAMES = ['type']; @@ -98,7 +97,7 @@ export const parseSchema = ( if (isReservedInputField(type, propertyName)) { logger('nodes').trace( { node: type, fieldName: propertyName, field: parseify(property) }, - i18n.t('nodes.skippedReservedInput') + 'Skipped reserved input field' ); return inputsAccumulator; } @@ -106,7 +105,7 @@ export const parseSchema = ( if (!isInvocationFieldSchema(property)) { logger('nodes').warn( { node: type, propertyName, property: parseify(property) }, - i18n.t('nodes.unhandledInputProperty') + 'Unhandled input property' ); return inputsAccumulator; } @@ -121,7 +120,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - i18n.t('nodes.skippingUnknownInputType') + 'Skipping unknown input field type' ); return inputsAccumulator; } @@ -134,7 +133,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - i18n.t('nodes.skippingReservedFieldType') + 'Skipping reserved field type' ); return inputsAccumulator; } @@ -154,7 +153,7 @@ export const parseSchema = ( fieldType, field: parseify(property), }, - i18n.t('nodes.skippingInputNoTemplate') + 'Skipping input field with no template' ); return inputsAccumulator; } @@ -170,24 +169,21 @@ export const parseSchema = ( if (!outputSchemaName) { logger('nodes').warn( { outputRefObject: parseify(schema.output) }, - i18n.t('nodes.noOutputSchemaName') + 'No output schema name found in ref object' ); return invocationsAccumulator; } const outputSchema = openAPI.components?.schemas?.[outputSchemaName]; if (!outputSchema) { - logger('nodes').warn( - { outputSchemaName }, - i18n.t('nodes.outputSchemaNotFound') - ); + logger('nodes').warn({ outputSchemaName }, 'Output schema not found'); return invocationsAccumulator; } if (!isInvocationOutputSchemaObject(outputSchema)) { logger('nodes').error( { outputSchema: parseify(outputSchema) }, - i18n.t('nodes.invalidOutputSchema') + 'Invalid output schema' ); return invocationsAccumulator; } @@ -200,7 +196,7 @@ export const parseSchema = ( if (!isAllowedOutputField(type, propertyName)) { logger('nodes').trace( { type, propertyName, property: parseify(property) }, - i18n.t('nodes.skippedReservedOutput') + 'Skipped reserved output field' ); return outputsAccumulator; } @@ -208,7 +204,7 @@ export const parseSchema = ( if (!isInvocationFieldSchema(property)) { logger('nodes').warn( { type, propertyName, property: parseify(property) }, - i18n.t('nodes.unhandledOutputProperty') + 'Unhandled output property' ); return outputsAccumulator; } @@ -218,7 +214,7 @@ export const parseSchema = ( if (!isFieldType(fieldType)) { logger('nodes').warn( { fieldName: propertyName, fieldType, field: parseify(property) }, - i18n.t('nodes.skippingUnknownOutputType') + 'Skipping unknown output field type' ); return outputsAccumulator; } From ff3150a818245c6dc83ba742045f18d5242a7c0d Mon Sep 17 00:00:00 2001 From: Sergey Borisov Date: Wed, 13 Sep 2023 21:37:08 +0300 Subject: [PATCH 11/12] Update lora hotfix to new diffusers version(scale argument added) --- invokeai/backend/util/hotfixes.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/invokeai/backend/util/hotfixes.py b/invokeai/backend/util/hotfixes.py index 983d0b7601..852d640161 100644 --- a/invokeai/backend/util/hotfixes.py +++ b/invokeai/backend/util/hotfixes.py @@ -772,11 +772,13 @@ diffusers.models.controlnet.ControlNetModel = ControlNetModel # NOTE: with this patch, torch.compile crashes on 2.0 torch(already fixed in nightly) # https://github.com/huggingface/diffusers/pull/4315 # https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/lora.py#L96C18-L96C18 -def new_LoRACompatibleConv_forward(self, x): +def new_LoRACompatibleConv_forward(self, hidden_states, scale: float = 1.0): if self.lora_layer is None: - return super(diffusers.models.lora.LoRACompatibleConv, self).forward(x) + return super(diffusers.models.lora.LoRACompatibleConv, self).forward(hidden_states) else: - return super(diffusers.models.lora.LoRACompatibleConv, self).forward(x) + self.lora_layer(x) + return super(diffusers.models.lora.LoRACompatibleConv, self).forward(hidden_states) + ( + scale * self.lora_layer(hidden_states) + ) diffusers.models.lora.LoRACompatibleConv.forward = new_LoRACompatibleConv_forward From b75c56768d9b81a362c51abb32f84e947d89f9eb Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Fri, 15 Sep 2023 13:52:11 -0400 Subject: [PATCH 12/12] Unmasked default --- .../web/src/features/parameters/store/generationSlice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index 50d9894b27..dc79281a06 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -80,7 +80,7 @@ export const initialGenerationState: GenerationState = { scheduler: 'euler', maskBlur: 16, maskBlurMethod: 'box', - canvasCoherenceMode: 'edge', + canvasCoherenceMode: 'unmasked', canvasCoherenceSteps: 20, canvasCoherenceStrength: 0.3, seed: 0,