mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
[WebUI] Implement a "Cancel after current iteration" Button (#2642)
## What was the problem/requirement? (What/Why) Frequently, I wish to cancel the processing of images, but also want the current image to finalize before I do. To work around this, I need to wait until the current one finishes before pressing the cancel. ## What was the solution? (How) * Implemented a button that allows to "Cancel after current iteration," which stores a state in the UI that will attempt to cancel the processing after the current image finishes * If the button is pressed again, while it is spinning and before the next iteration happens, this will stop the scheduling of the cancel, and behave as if the button was never pressed. ### Minor * Added `.yarn` to `.gitignore` as this was an output folder produced from following Frontend's README ### Revision 2 #### Major * Changed from a standalone button to a context menu next to the original cancel button. Pressing the context menu will give the drop-down option to select which type of cancel method the user prefers, and they can press that button for canceling in the specified type * Moved states to system state for cross-screen and toggled cancel types management * Added in distribution for the target yarn version (allowing any version of yarn to compile successfully), and updated the README to ensure `--immutable` is passed for onboarding developers #### Minor * Updated `.gitignore` to ignore specific yarn folders, as specified by their team - https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored ## How were these changes tested? * `yarn dev` => Server started successfully * Manual testing on the development server to ensure the button behaved as expected * `yarn run build` => Success ### Artifacts #### Revision 1 * Video showing the UI changes in action https://user-images.githubusercontent.com/89283782/218347722-3a15ce61-2d8c-4c38-b681-e7a3e79dd595.mov * Images showing the basic UI changes ![image](https://user-images.githubusercontent.com/89283782/218347124-4afbb699-2abc-4e71-a794-b04f7179cfe2.png) ![image](https://user-images.githubusercontent.com/89283782/218347826-443db351-7a3a-4111-80af-56d56a81f07b.png) #### Revision 2 * Video showing the UI changes in action https://user-images.githubusercontent.com/89283782/219901217-048d2912-9b61-4415-85fd-9e8fedb00c79.mov * Images showing the basic UI changes (Default state) ![image](https://user-images.githubusercontent.com/89283782/219901228-918b263a-dc75-4e5d-8897-5fc62c71a790.png) (Drop-down context menu active) ![image](https://user-images.githubusercontent.com/89283782/219901241-021be07a-b768-40a2-988f-eb59be4a962d.png) (Scheduled cancel selected and running) ![image](https://user-images.githubusercontent.com/89283782/219901243-59a9c61a-71a7-44b3-adab-7aa4c9ee1f8e.png) (Scheduled cancel started) ![image](https://user-images.githubusercontent.com/89283782/219901266-b4c0adc1-d791-4989-9351-075758e06534.png) ## Notes * Using `SystemState`'s `currentStatus` variable, when the value is `common:statusIterationComplete` is an alternative to this approach (and would be more optimal as it should prevent the next iteration from even starting), but since the names are within the translations, rather than an enum or other type, this method of tracking the current iteration was used instead. * `isLoading` on `IAIIconButton` caused the Icon Button to also be disabled, so the current solution works around that with conditionally rendering the icon of the button instead of passing that value. * I don't have context on the development expectation for `dist` folder interactions (and couldn't find any documentation outside of the `.gitignore` mentioning that the folder should remain. Let me know if they need to be modified a certain way.
This commit is contained in:
commit
16c24ec367
11
invokeai/frontend/.gitignore
vendored
11
invokeai/frontend/.gitignore
vendored
@ -25,4 +25,13 @@ dist-ssr
|
||||
*.sw?
|
||||
|
||||
# build stats
|
||||
stats.html
|
||||
stats.html
|
||||
|
||||
# Yarn - https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
193957
invokeai/frontend/.yarn/releases/yarn-1.22.19.cjs
vendored
Normal file
193957
invokeai/frontend/.yarn/releases/yarn-1.22.19.cjs
vendored
Normal file
File diff suppressed because one or more lines are too long
5
invokeai/frontend/.yarnrc
Normal file
5
invokeai/frontend/.yarnrc
Normal file
@ -0,0 +1,5 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
yarn-path ".yarn/releases/yarn-1.22.19.cjs"
|
1
invokeai/frontend/.yarnrc.yml
Normal file
1
invokeai/frontend/.yarnrc.yml
Normal file
@ -0,0 +1 @@
|
||||
yarnPath: .yarn/releases/yarn-1.22.19.cjs
|
@ -7,7 +7,7 @@ The UI is in `invokeai/frontend`.
|
||||
Install [node](https://nodejs.org/en/download/) (includes npm) and
|
||||
[yarn](https://yarnpkg.com/getting-started/install).
|
||||
|
||||
From `invokeai/frontend/` run `yarn install` to get everything set up.
|
||||
From `invokeai/frontend/` run `yarn install --immutable` to get everything set up.
|
||||
|
||||
## Dev
|
||||
|
||||
|
638
invokeai/frontend/dist/assets/index-1e76002e.js
vendored
638
invokeai/frontend/dist/assets/index-1e76002e.js
vendored
File diff suppressed because one or more lines are too long
638
invokeai/frontend/dist/assets/index-c55cecd9.js
vendored
Normal file
638
invokeai/frontend/dist/assets/index-c55cecd9.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
invokeai/frontend/dist/index.html
vendored
2
invokeai/frontend/dist/index.html
vendored
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||
<link rel="shortcut icon" type="icon" href="./assets/favicon-0d253ced.ico" />
|
||||
<script type="module" crossorigin src="./assets/index-1e76002e.js"></script>
|
||||
<script type="module" crossorigin src="./assets/index-c55cecd9.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index-14cb2922.css">
|
||||
</head>
|
||||
|
||||
|
6
invokeai/frontend/dist/locales/ar.json
vendored
6
invokeai/frontend/dist/locales/ar.json
vendored
@ -66,7 +66,7 @@
|
||||
"hotkeys": {
|
||||
"keyboardShortcuts": "مفاتيح الأزرار المختصرة",
|
||||
"appHotkeys": "مفاتيح التطبيق",
|
||||
"GeneralHotkeys": "مفاتيح عامة",
|
||||
"generalHotkeys": "مفاتيح عامة",
|
||||
"galleryHotkeys": "مفاتيح المعرض",
|
||||
"unifiedCanvasHotkeys": "مفاتيح اللوحةالموحدة ",
|
||||
"invoke": {
|
||||
@ -452,10 +452,10 @@
|
||||
"seed": "يؤثر قيمة البذور على الضوضاء الأولي الذي يتم تكوين الصورة منه. يمكنك استخدام البذور الخاصة بالصور السابقة. 'عتبة الضوضاء' يتم استخدامها لتخفيف العناصر الخللية في قيم CFG العالية (جرب مدى 0-10), و Perlin لإضافة ضوضاء Perlin أثناء الإنتاج: كلا منهما يعملان على إضافة التنوع إلى النتائج الخاصة بك.",
|
||||
"variations": "جرب التغيير مع قيمة بين 0.1 و 1.0 لتغيير النتائج لبذور معينة. التغييرات المثيرة للاهتمام للبذور تكون بين 0.1 و 0.3.",
|
||||
"upscale": "استخدم إي إس آر جان لتكبير الصورة على الفور بعد الإنتاج.",
|
||||
"face Correction": "تصحيح الوجه باستخدام جي إف بي جان أو كود فورمر: يكتشف الخوارزمية الوجوه في الصورة وتصحح أي عيوب. قيمة عالية ستغير الصورة أكثر، مما يؤدي إلى وجوه أكثر جمالا. كود فورمر بدقة أعلى يحتفظ بالصورة الأصلية على حساب تصحيح وجه أكثر قوة.",
|
||||
"faceCorrection": "تصحيح الوجه باستخدام جي إف بي جان أو كود فورمر: يكتشف الخوارزمية الوجوه في الصورة وتصحح أي عيوب. قيمة عالية ستغير الصورة أكثر، مما يؤدي إلى وجوه أكثر جمالا. كود فورمر بدقة أعلى يحتفظ بالصورة الأصلية على حساب تصحيح وجه أكثر قوة.",
|
||||
"imageToImage": "تحميل صورة إلى صورة أي صورة كأولية، والتي يتم استخدامها لإنشاء صورة جديدة مع التشعيب. كلما كانت القيمة أعلى، كلما تغيرت نتيجة الصورة. من الممكن أن تكون القيم بين 0.0 و 1.0، وتوصي النطاق الموصى به هو .25-.75",
|
||||
"boundingBox": "مربع الحدود هو نفس الإعدادات العرض والارتفاع لنص إلى صورة أو صورة إلى صورة. فقط المنطقة في المربع سيتم معالجتها.",
|
||||
"seam Correction": "يتحكم بالتعامل مع الخطوط المرئية التي تحدث بين الصور المولدة في سطح اللوحة.",
|
||||
"seamCorrection": "يتحكم بالتعامل مع الخطوط المرئية التي تحدث بين الصور المولدة في سطح اللوحة.",
|
||||
"infillAndScaling": "إدارة أساليب التعبئة (المستخدمة على المناطق المخفية أو الممحوة في سطح اللوحة) والزيادة في الحجم (مفيدة لحجوزات الإطارات الصغيرة)."
|
||||
}
|
||||
},
|
||||
|
17
invokeai/frontend/dist/locales/en.json
vendored
17
invokeai/frontend/dist/locales/en.json
vendored
@ -390,7 +390,10 @@
|
||||
"modelMergeHeaderHelp1": "You can merge upto three different models to create a blend that suits your needs.",
|
||||
"modelMergeHeaderHelp2": "Only Diffusers are available for merging. If you want to merge a checkpoint model, please convert it to Diffusers first.",
|
||||
"modelMergeAlphaHelp": "Alpha controls blend strength for the models. Lower alpha values lead to lower influence of the second model.",
|
||||
"modelMergeInterpAddDifferenceHelp": "In this mode, Model 3 is first subtracted from Model 2. The resulting version is blended with Model 1 with the alpha rate set above."
|
||||
"modelMergeInterpAddDifferenceHelp": "In this mode, Model 3 is first subtracted from Model 2. The resulting version is blended with Model 1 with the alpha rate set above.",
|
||||
"inverseSigmoid": "Inverse Sigmoid",
|
||||
"sigmoid": "Sigmoid",
|
||||
"weightedSum": "Weighted Sum"
|
||||
},
|
||||
"parameters": {
|
||||
"general": "General",
|
||||
@ -401,6 +404,7 @@
|
||||
"height": "Height",
|
||||
"sampler": "Sampler",
|
||||
"seed": "Seed",
|
||||
"imageToImage": "Image to Image",
|
||||
"randomizeSeed": "Randomize Seed",
|
||||
"shuffle": "Shuffle",
|
||||
"noiseThreshold": "Noise Threshold",
|
||||
@ -438,7 +442,12 @@
|
||||
"img2imgStrength": "Image To Image Strength",
|
||||
"toggleLoopback": "Toggle Loopback",
|
||||
"invoke": "Invoke",
|
||||
"cancel": "Cancel",
|
||||
"cancel": {
|
||||
"immediate": "Cancel immediately",
|
||||
"schedule": "Cancel after current iteration",
|
||||
"isScheduled": "Canceling",
|
||||
"setType": "Set cancel type"
|
||||
},
|
||||
"promptPlaceholder": "Type prompt here. [negative tokens], (upweight)++, (downweight)--, swap and blend are available (see docs)",
|
||||
"negativePrompts": "Negative Prompts",
|
||||
"sendTo": "Send to",
|
||||
@ -465,8 +474,8 @@
|
||||
"confirmOnDelete": "Confirm On Delete",
|
||||
"displayHelpIcons": "Display Help Icons",
|
||||
"useCanvasBeta": "Use Canvas Beta Layout",
|
||||
"useSlidersForAll": "Use Sliders For All Options",
|
||||
"enableImageDebugging": "Enable Image Debugging",
|
||||
"useSlidersForAll": "Use Sliders For All Options",
|
||||
"resetWebUI": "Reset Web UI",
|
||||
"resetWebUIDesc1": "Resetting the web UI only resets the browser's local cache of your images and remembered settings. It does not delete any images from disk.",
|
||||
"resetWebUIDesc2": "If images aren't showing up in the gallery or something else isn't working, please try resetting before submitting an issue on GitHub.",
|
||||
@ -508,7 +517,7 @@
|
||||
"feature": {
|
||||
"prompt": "This is the prompt field. Prompt includes generation objects and stylistic terms. You can add weight (token importance) in the prompt as well, but CLI commands and parameters will not work.",
|
||||
"gallery": "Gallery displays generations from the outputs folder as they're created. Settings are stored within files and accesed by context menu.",
|
||||
"other": "These options will enable alternative processing modes for Invoke. 'Seamless tiling' will create repeating patterns in the output. 'High resolution' is generation in two steps with img2img: use this setting when you want a larger and more coherent image without artifacts. It will take longer that usual txt2img.",
|
||||
"other": "These options will enable alternative processing modes for Invoke. 'Seamless tiling' will create repeating patterns in the output. 'High resolution' is generation in two steps with img2img: use this setting when you want a larger and more coherent image without artifacts. It will take longer than usual txt2img.",
|
||||
"seed": "Seed value affects the initial noise from which the image is formed. You can use the already existing seeds from previous images. 'Noise Threshold' is used to mitigate artifacts at high CFG values (try the 0-10 range), and Perlin to add Perlin noise during generation: both serve to add variation to your outputs.",
|
||||
"variations": "Try a variation with a value between 0.1 and 1.0 to change the result for a given seed. Interesting variations of the seed are between 0.1 and 0.3.",
|
||||
"upscale": "Use ESRGAN to enlarge the image immediately after generation.",
|
||||
|
2
invokeai/frontend/dist/locales/fr.json
vendored
2
invokeai/frontend/dist/locales/fr.json
vendored
@ -66,7 +66,7 @@
|
||||
"hotkeys": {
|
||||
"keyboardShortcuts": "Raccourcis clavier",
|
||||
"appHotkeys": "Raccourcis de l'application",
|
||||
"GeneralHotkeys": "Raccourcis généraux",
|
||||
"generalHotkeys": "Raccourcis généraux",
|
||||
"galleryHotkeys": "Raccourcis de la galerie",
|
||||
"unifiedCanvasHotkeys": "Raccourcis du Canvas unifié",
|
||||
"invoke": {
|
||||
|
84
invokeai/frontend/dist/locales/it.json
vendored
84
invokeai/frontend/dist/locales/it.json
vendored
@ -15,11 +15,11 @@
|
||||
"langItalian": "Italiano",
|
||||
"nodesDesc": "Attualmente è in fase di sviluppo un sistema basato su nodi per la generazione di immagini. Resta sintonizzato per gli aggiornamenti su questa fantastica funzionalità.",
|
||||
"postProcessing": "Post-elaborazione",
|
||||
"postProcessDesc1": "Invoke AI offre un'ampia varietà di funzionalità di post-elaborazione. Ampiamento Immagine e Restaura i Volti sono già disponibili nell'interfaccia Web. È possibile accedervi dal menu 'Opzioni avanzate' delle schede 'Testo a Immagine' e 'Immagine a Immagine'. È inoltre possibile elaborare le immagini direttamente, utilizzando i pulsanti di azione dell'immagine sopra la visualizzazione dell'immagine corrente o nel visualizzatore.",
|
||||
"postProcessDesc1": "Invoke AI offre un'ampia varietà di funzionalità di post-elaborazione. Ampliamento Immagine e Restaura Volti sono già disponibili nell'interfaccia Web. È possibile accedervi dal menu 'Opzioni avanzate' delle schede 'Testo a Immagine' e 'Immagine a Immagine'. È inoltre possibile elaborare le immagini direttamente, utilizzando i pulsanti di azione dell'immagine sopra la visualizzazione dell'immagine corrente o nel visualizzatore.",
|
||||
"postProcessDesc2": "Presto verrà rilasciata un'interfaccia utente dedicata per facilitare flussi di lavoro di post-elaborazione più avanzati.",
|
||||
"postProcessDesc3": "L'interfaccia da riga di comando di 'Invoke AI' offre varie altre funzionalità tra cui Embiggen.",
|
||||
"training": "Addestramento",
|
||||
"trainingDesc1": "Un flusso di lavoro dedicato per addestrare i tuoi incorporamenti e checkpoint utilizzando Inversione Testuale e Dreambooth dall'interfaccia web.",
|
||||
"trainingDesc1": "Un flusso di lavoro dedicato per addestrare i tuoi Incorporamenti e Checkpoint utilizzando Inversione Testuale e Dreambooth dall'interfaccia web.",
|
||||
"trainingDesc2": "InvokeAI supporta già l'addestramento di incorporamenti personalizzati utilizzando l'inversione testuale utilizzando lo script principale.",
|
||||
"upload": "Caricamento",
|
||||
"close": "Chiudi",
|
||||
@ -45,7 +45,25 @@
|
||||
"statusUpscaling": "Ampliamento",
|
||||
"statusUpscalingESRGAN": "Ampliamento (ESRGAN)",
|
||||
"statusLoadingModel": "Caricamento del modello",
|
||||
"statusModelChanged": "Modello cambiato"
|
||||
"statusModelChanged": "Modello cambiato",
|
||||
"githubLabel": "GitHub",
|
||||
"discordLabel": "Discord",
|
||||
"langArabic": "Arabo",
|
||||
"langEnglish": "Inglese",
|
||||
"langFrench": "Francese",
|
||||
"langGerman": "Tedesco",
|
||||
"langJapanese": "Giapponese",
|
||||
"langPolish": "Polacco",
|
||||
"langBrPortuguese": "Portoghese Basiliano",
|
||||
"langRussian": "Russo",
|
||||
"langUkranian": "Ucraino",
|
||||
"langSpanish": "Spagnolo",
|
||||
"statusMergingModels": "Fusione Modelli",
|
||||
"statusMergedModels": "Modelli fusi",
|
||||
"langSimplifiedChinese": "Cinese semplificato",
|
||||
"langDutch": "Olandese",
|
||||
"statusModelConverted": "Modello Convertito",
|
||||
"statusConvertingModel": "Conversione Modello"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Generazioni",
|
||||
@ -70,7 +88,7 @@
|
||||
"galleryHotkeys": "Tasti di scelta rapida della galleria",
|
||||
"unifiedCanvasHotkeys": "Tasti di scelta rapida Tela Unificata",
|
||||
"invoke": {
|
||||
"title": "Invoca",
|
||||
"title": "Invoke",
|
||||
"desc": "Genera un'immagine"
|
||||
},
|
||||
"cancel": {
|
||||
@ -335,7 +353,47 @@
|
||||
"formMessageDiffusersModelLocation": "Ubicazione modelli diffusori",
|
||||
"formMessageDiffusersModelLocationDesc": "Inseriscine almeno uno.",
|
||||
"formMessageDiffusersVAELocation": "Ubicazione file VAE",
|
||||
"formMessageDiffusersVAELocationDesc": "Se non fornito, InvokeAI cercherà il file VAE all'interno dell'ubicazione del modello sopra indicata."
|
||||
"formMessageDiffusersVAELocationDesc": "Se non fornito, InvokeAI cercherà il file VAE all'interno dell'ubicazione del modello sopra indicata.",
|
||||
"convert": "Converti",
|
||||
"convertToDiffusers": "Converti in Diffusori",
|
||||
"convertToDiffusersHelpText2": "Questo processo sostituirà la voce in Gestione Modelli con la versione Diffusori dello stesso modello.",
|
||||
"convertToDiffusersHelpText4": "Questo è un processo una tantum. Potrebbero essere necessari circa 30-60 secondi a seconda delle specifiche del tuo computer.",
|
||||
"convertToDiffusersHelpText5": "Assicurati di avere spazio su disco sufficiente. I modelli generalmente variano tra 4 GB e 7 GB di dimensioni.",
|
||||
"convertToDiffusersHelpText6": "Vuoi convertire questo modello?",
|
||||
"convertToDiffusersSaveLocation": "Ubicazione salvataggio",
|
||||
"v2": "v2",
|
||||
"inpainting": "v1 Inpainting",
|
||||
"customConfig": "Configurazione personalizzata",
|
||||
"statusConverting": "Conversione in corso",
|
||||
"modelConverted": "Modello convertito",
|
||||
"sameFolder": "Stessa cartella",
|
||||
"invokeRoot": "Cartella InvokeAI",
|
||||
"merge": "Fondere",
|
||||
"modelsMerged": "Modelli fusi",
|
||||
"mergeModels": "Fondi Modelli",
|
||||
"modelOne": "Modello 1",
|
||||
"modelTwo": "Modello 2",
|
||||
"mergedModelName": "Nome del modello fuso",
|
||||
"alpha": "Alpha",
|
||||
"interpolationType": "Tipo di interpolazione",
|
||||
"mergedModelCustomSaveLocation": "Percorso personalizzato",
|
||||
"invokeAIFolder": "Cartella Invoke AI",
|
||||
"ignoreMismatch": "Ignora le discrepanze tra i modelli selezionati",
|
||||
"modelMergeHeaderHelp2": "Solo i diffusori sono disponibili per l'unione. Se desideri unire un modello Checkpoint, convertilo prima in Diffusori.",
|
||||
"modelMergeInterpAddDifferenceHelp": "In questa modalità, il Modello 3 viene prima sottratto dal Modello 2. La versione risultante viene unita al Modello 1 con il tasso Alpha impostato sopra.",
|
||||
"mergedModelSaveLocation": "Ubicazione salvataggio",
|
||||
"convertToDiffusersHelpText1": "Questo modello verrà convertito nel formato 🧨 Diffusore.",
|
||||
"custom": "Personalizzata",
|
||||
"convertToDiffusersHelpText3": "Il tuo file checkpoint sul disco NON verrà comunque cancellato o modificato. Se lo desideri, puoi aggiungerlo di nuovo in Gestione Modelli.",
|
||||
"v1": "v1",
|
||||
"pathToCustomConfig": "Percorso alla configurazione personalizzata",
|
||||
"modelThree": "Modello 3",
|
||||
"modelMergeHeaderHelp1": "Puoi unire fino a tre diversi modelli per creare una miscela adatta alle tue esigenze.",
|
||||
"modelMergeAlphaHelp": "Il valore Alpha controlla la forza di miscelazione dei modelli. Valori Alpha più bassi attenuano l'influenza del secondo modello.",
|
||||
"customSaveLocation": "Ubicazione salvataggio personalizzata",
|
||||
"weightedSum": "Somma pesata",
|
||||
"sigmoid": "Sigmoide",
|
||||
"inverseSigmoid": "Sigmoide inverso"
|
||||
},
|
||||
"parameters": {
|
||||
"images": "Immagini",
|
||||
@ -352,7 +410,7 @@
|
||||
"variations": "Variazioni",
|
||||
"variationAmount": "Quantità di variazione",
|
||||
"seedWeights": "Pesi dei semi",
|
||||
"faceRestoration": "Restaura volti",
|
||||
"faceRestoration": "Restauro volti",
|
||||
"restoreFaces": "Restaura volti",
|
||||
"type": "Tipo",
|
||||
"strength": "Forza",
|
||||
@ -396,7 +454,12 @@
|
||||
"info": "Informazioni",
|
||||
"deleteImage": "Elimina immagine",
|
||||
"initialImage": "Immagine iniziale",
|
||||
"showOptionsPanel": "Mostra pannello opzioni"
|
||||
"showOptionsPanel": "Mostra pannello opzioni",
|
||||
"general": "Generale",
|
||||
"denoisingStrength": "Forza riduzione rumore",
|
||||
"copyImage": "Copia immagine",
|
||||
"hiresStrength": "Forza Alta Risoluzione",
|
||||
"negativePrompts": "Prompt Negativi"
|
||||
},
|
||||
"settings": {
|
||||
"models": "Modelli",
|
||||
@ -409,7 +472,8 @@
|
||||
"resetWebUI": "Reimposta l'interfaccia utente Web",
|
||||
"resetWebUIDesc1": "Il ripristino dell'interfaccia utente Web reimposta solo la cache locale del browser delle immagini e le impostazioni memorizzate. Non cancella alcuna immagine dal disco.",
|
||||
"resetWebUIDesc2": "Se le immagini non vengono visualizzate nella galleria o qualcos'altro non funziona, prova a reimpostare prima di segnalare un problema su GitHub.",
|
||||
"resetComplete": "L'interfaccia utente Web è stata reimpostata. Aggiorna la pagina per ricaricarla."
|
||||
"resetComplete": "L'interfaccia utente Web è stata reimpostata. Aggiorna la pagina per ricaricarla.",
|
||||
"useSlidersForAll": "Usa i cursori per tutte le opzioni"
|
||||
},
|
||||
"toast": {
|
||||
"tempFoldersEmptied": "Cartella temporanea svuotata",
|
||||
@ -447,7 +511,7 @@
|
||||
"feature": {
|
||||
"prompt": "Questo è il campo del prompt. Il prompt include oggetti di generazione e termini stilistici. Puoi anche aggiungere il peso (importanza del token) nel prompt, ma i comandi e i parametri dell'interfaccia a linea di comando non funzioneranno.",
|
||||
"gallery": "Galleria visualizza le generazioni dalla cartella degli output man mano che vengono create. Le impostazioni sono memorizzate all'interno di file e accessibili dal menu contestuale.",
|
||||
"other": "Queste opzioni abiliteranno modalità di elaborazione alternative per Invoke. 'Piastrella senza cuciture' creerà modelli ripetuti nell'output. 'Ottimizzzazione Alta risoluzione' è la generazione in due passaggi con 'Immagine a Immagine': usa questa impostazione quando vuoi un'immagine più grande e più coerente senza artefatti. Ci vorrà più tempo del solito 'Testo a Immagine'.",
|
||||
"other": "Queste opzioni abiliteranno modalità di elaborazione alternative per Invoke. 'Piastrella senza cuciture' creerà modelli ripetuti nell'output. 'Ottimizzazione Alta risoluzione' è la generazione in due passaggi con 'Immagine a Immagine': usa questa impostazione quando vuoi un'immagine più grande e più coerente senza artefatti. Ci vorrà più tempo del solito 'Testo a Immagine'.",
|
||||
"seed": "Il valore del Seme influenza il rumore iniziale da cui è formata l'immagine. Puoi usare i semi già esistenti dalle immagini precedenti. 'Soglia del rumore' viene utilizzato per mitigare gli artefatti a valori CFG elevati (provare l'intervallo 0-10) e Perlin per aggiungere il rumore Perlin durante la generazione: entrambi servono per aggiungere variazioni ai risultati.",
|
||||
"variations": "Prova una variazione con un valore compreso tra 0.1 e 1.0 per modificare il risultato per un dato seme. Variazioni interessanti del seme sono comprese tra 0.1 e 0.3.",
|
||||
"upscale": "Utilizza ESRGAN per ingrandire l'immagine subito dopo la generazione.",
|
||||
@ -515,6 +579,6 @@
|
||||
"betaClear": "Svuota",
|
||||
"betaDarkenOutside": "Oscura all'esterno",
|
||||
"betaLimitToBox": "Limita al rettangolo",
|
||||
"betaPreserveMasked": "Conserva quanto mascheato"
|
||||
"betaPreserveMasked": "Conserva quanto mascherato"
|
||||
}
|
||||
}
|
||||
|
8
invokeai/frontend/dist/locales/ru.json
vendored
8
invokeai/frontend/dist/locales/ru.json
vendored
@ -160,7 +160,7 @@
|
||||
"title": "Увеличить размер миниатюр галереи",
|
||||
"desc": "Увеличивает размер миниатюр галереи"
|
||||
},
|
||||
"reduceGalleryThumbSize": {
|
||||
"decreaseGalleryThumbSize": {
|
||||
"title": "Уменьшает размер миниатюр галереи",
|
||||
"desc": "Уменьшает размер миниатюр галереи"
|
||||
},
|
||||
@ -172,7 +172,7 @@
|
||||
"title": "Выбрать ластик",
|
||||
"desc": "Выбирает ластик для холста"
|
||||
},
|
||||
"reduceBrushSize": {
|
||||
"decreaseBrushSize": {
|
||||
"title": "Уменьшить размер кисти",
|
||||
"desc": "Уменьшает размер кисти/ластика холста"
|
||||
},
|
||||
@ -180,7 +180,7 @@
|
||||
"title": "Увеличить размер кисти",
|
||||
"desc": "Увеличивает размер кисти/ластика холста"
|
||||
},
|
||||
"reduceBrushOpacity": {
|
||||
"decreaseBrushOpacity": {
|
||||
"title": "Уменьшить непрозрачность кисти",
|
||||
"desc": "Уменьшает непрозрачность кисти холста"
|
||||
},
|
||||
@ -494,7 +494,7 @@
|
||||
"cursorPosition": "Положение курсора",
|
||||
"previous": "Предыдущее",
|
||||
"next": "Следующее",
|
||||
"принять": "Принять",
|
||||
"accept": "Принять",
|
||||
"showHide": "Показать/Скрыть",
|
||||
"discardAll": "Отменить все",
|
||||
"betaClear": "Очистить",
|
||||
|
9
invokeai/frontend/dist/locales/uk.json
vendored
9
invokeai/frontend/dist/locales/uk.json
vendored
@ -160,7 +160,7 @@
|
||||
"title": "Збільшити розмір мініатюр галереї",
|
||||
"desc": "Збільшує розмір мініатюр галереї"
|
||||
},
|
||||
"reduceGalleryThumbSize": {
|
||||
"decreaseGalleryThumbSize": {
|
||||
"title": "Зменшує розмір мініатюр галереї",
|
||||
"desc": "Зменшує розмір мініатюр галереї"
|
||||
},
|
||||
@ -172,7 +172,7 @@
|
||||
"title": "Вибрати ластик",
|
||||
"desc": "Вибирає ластик для полотна"
|
||||
},
|
||||
"reduceBrushSize": {
|
||||
"decreaseBrushSize": {
|
||||
"title": "Зменшити розмір пензля",
|
||||
"desc": "Зменшує розмір пензля/ластика полотна"
|
||||
},
|
||||
@ -180,7 +180,7 @@
|
||||
"title": "Збільшити розмір пензля",
|
||||
"desc": "Збільшує розмір пензля/ластика полотна"
|
||||
},
|
||||
"reduceBrushOpacity": {
|
||||
"decreaseBrushOpacity": {
|
||||
"title": "Зменшити непрозорість пензля",
|
||||
"desc": "Зменшує непрозорість пензля полотна"
|
||||
},
|
||||
@ -354,7 +354,6 @@
|
||||
"seamBlur": "Розмиття шву",
|
||||
"seamStrength": "Сила шву",
|
||||
"seamSteps": "Кроки шву",
|
||||
"inpaintReplace": "Inpaint-заміна",
|
||||
"scaleBeforeProcessing": "Масштабувати",
|
||||
"scaledWidth": "Масштаб Ш",
|
||||
"scaledHeight": "Масштаб В",
|
||||
@ -495,7 +494,7 @@
|
||||
"cursorPosition": "Розташування курсора",
|
||||
"previous": "Попереднє",
|
||||
"next": "Наступне",
|
||||
"принять": "Приняти",
|
||||
"accept": "Приняти",
|
||||
"showHide": "Показати/Сховати",
|
||||
"discardAll": "Відмінити все",
|
||||
"betaClear": "Очистити",
|
||||
|
@ -442,7 +442,12 @@
|
||||
"img2imgStrength": "Image To Image Strength",
|
||||
"toggleLoopback": "Toggle Loopback",
|
||||
"invoke": "Invoke",
|
||||
"cancel": "Cancel",
|
||||
"cancel": {
|
||||
"immediate": "Cancel immediately",
|
||||
"schedule": "Cancel after current iteration",
|
||||
"isScheduled": "Canceling",
|
||||
"setType": "Set cancel type"
|
||||
},
|
||||
"promptPlaceholder": "Type prompt here. [negative tokens], (upweight)++, (downweight)--, swap and blend are available (see docs)",
|
||||
"negativePrompts": "Negative Prompts",
|
||||
"sendTo": "Send to",
|
||||
|
@ -48,6 +48,7 @@ const systemBlacklist = [
|
||||
'totalIterations',
|
||||
'totalSteps',
|
||||
'openModel',
|
||||
'cancelOptions.cancelAfter',
|
||||
].map((blacklistItem) => `system.${blacklistItem}`);
|
||||
|
||||
const galleryBlacklist = [
|
||||
|
102
invokeai/frontend/src/common/components/IAISimpleMenu.tsx
Normal file
102
invokeai/frontend/src/common/components/IAISimpleMenu.tsx
Normal file
@ -0,0 +1,102 @@
|
||||
import {
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
type MenuProps,
|
||||
type MenuButtonProps,
|
||||
type MenuListProps,
|
||||
type MenuItemProps,
|
||||
} from '@chakra-ui/react';
|
||||
import { MouseEventHandler, ReactNode } from 'react';
|
||||
import { MdArrowDropDown, MdArrowDropUp } from 'react-icons/md';
|
||||
import IAIButton from './IAIButton';
|
||||
import IAIIconButton from './IAIIconButton';
|
||||
|
||||
interface IAIMenuItem {
|
||||
item: ReactNode | string;
|
||||
onClick: MouseEventHandler<HTMLButtonElement> | undefined;
|
||||
}
|
||||
|
||||
interface IAIMenuProps {
|
||||
menuType?: 'icon' | 'regular';
|
||||
buttonText?: string;
|
||||
iconTooltip?: string;
|
||||
menuItems: IAIMenuItem[];
|
||||
menuProps?: MenuProps;
|
||||
menuButtonProps?: MenuButtonProps;
|
||||
menuListProps?: MenuListProps;
|
||||
menuItemProps?: MenuItemProps;
|
||||
}
|
||||
|
||||
export default function IAISimpleMenu(props: IAIMenuProps) {
|
||||
const {
|
||||
menuType = 'icon',
|
||||
iconTooltip,
|
||||
buttonText,
|
||||
menuItems,
|
||||
menuProps,
|
||||
menuButtonProps,
|
||||
menuListProps,
|
||||
menuItemProps,
|
||||
} = props;
|
||||
|
||||
const renderMenuItems = () => {
|
||||
const menuItemsToRender: ReactNode[] = [];
|
||||
menuItems.forEach((menuItem, index) => {
|
||||
menuItemsToRender.push(
|
||||
<MenuItem
|
||||
key={index}
|
||||
onClick={menuItem.onClick}
|
||||
fontSize="0.9rem"
|
||||
color="var(--text-color-secondary)"
|
||||
backgroundColor="var(--background-color-secondary)"
|
||||
_focus={{
|
||||
color: 'var(--text-color)',
|
||||
backgroundColor: 'var(--border-color)',
|
||||
}}
|
||||
{...menuItemProps}
|
||||
>
|
||||
{menuItem.item}
|
||||
</MenuItem>
|
||||
);
|
||||
});
|
||||
return menuItemsToRender;
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu {...menuProps}>
|
||||
{({ isOpen }) => (
|
||||
<>
|
||||
<MenuButton
|
||||
as={menuType === 'icon' ? IAIIconButton : IAIButton}
|
||||
tooltip={iconTooltip}
|
||||
icon={isOpen ? <MdArrowDropUp /> : <MdArrowDropDown />}
|
||||
padding={menuType === 'regular' ? '0 0.5rem' : 0}
|
||||
backgroundColor="var(--btn-base-color)"
|
||||
_hover={{
|
||||
backgroundColor: 'var(--btn-base-color-hover)',
|
||||
}}
|
||||
minWidth="1rem"
|
||||
minHeight="1rem"
|
||||
fontSize="1.5rem"
|
||||
{...menuButtonProps}
|
||||
>
|
||||
{menuType === 'regular' && buttonText}
|
||||
</MenuButton>
|
||||
<MenuList
|
||||
zIndex={15}
|
||||
padding={0}
|
||||
borderRadius="0.5rem"
|
||||
backgroundColor="var(--background-color-secondary)"
|
||||
color="var(--text-color-secondary)"
|
||||
borderColor="var(--border-color)"
|
||||
{...menuListProps}
|
||||
>
|
||||
{renderMenuItems()}
|
||||
</MenuList>
|
||||
</>
|
||||
)}
|
||||
</Menu>
|
||||
);
|
||||
}
|
@ -5,12 +5,20 @@ import IAIIconButton, {
|
||||
IAIIconButtonProps,
|
||||
} from 'common/components/IAIIconButton';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import { SystemState } from 'features/system/store/systemSlice';
|
||||
import {
|
||||
SystemState,
|
||||
setCancelAfter,
|
||||
setCancelType,
|
||||
} from 'features/system/store/systemSlice';
|
||||
import { isEqual } from 'lodash';
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { ButtonSpinner, ButtonGroup } from '@chakra-ui/react';
|
||||
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MdCancel } from 'react-icons/md';
|
||||
import { MdCancel, MdCancelScheduleSend } from 'react-icons/md';
|
||||
|
||||
import IAISimpleMenu from 'common/components/IAISimpleMenu';
|
||||
|
||||
const cancelButtonSelector = createSelector(
|
||||
systemSelector,
|
||||
@ -19,6 +27,10 @@ const cancelButtonSelector = createSelector(
|
||||
isProcessing: system.isProcessing,
|
||||
isConnected: system.isConnected,
|
||||
isCancelable: system.isCancelable,
|
||||
currentIteration: system.currentIteration,
|
||||
totalIterations: system.totalIterations,
|
||||
cancelType: system.cancelOptions.cancelType,
|
||||
cancelAfter: system.cancelOptions.cancelAfter,
|
||||
};
|
||||
},
|
||||
{
|
||||
@ -31,14 +43,26 @@ const cancelButtonSelector = createSelector(
|
||||
export default function CancelButton(
|
||||
props: Omit<IAIIconButtonProps, 'aria-label'>
|
||||
) {
|
||||
const { ...rest } = props;
|
||||
const dispatch = useAppDispatch();
|
||||
const { isProcessing, isConnected, isCancelable } =
|
||||
useAppSelector(cancelButtonSelector);
|
||||
const handleClickCancel = () => dispatch(cancelProcessing());
|
||||
const { ...rest } = props;
|
||||
const {
|
||||
isProcessing,
|
||||
isConnected,
|
||||
isCancelable,
|
||||
currentIteration,
|
||||
totalIterations,
|
||||
cancelType,
|
||||
cancelAfter,
|
||||
} = useAppSelector(cancelButtonSelector);
|
||||
const handleClickCancel = useCallback(() => {
|
||||
dispatch(cancelProcessing());
|
||||
dispatch(setCancelAfter(null));
|
||||
}, [dispatch]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isCancelScheduled = cancelAfter === null ? false : true;
|
||||
|
||||
useHotkeys(
|
||||
'shift+x',
|
||||
() => {
|
||||
@ -49,15 +73,82 @@ export default function CancelButton(
|
||||
[isConnected, isProcessing, isCancelable]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (cancelAfter !== null && cancelAfter < currentIteration) {
|
||||
handleClickCancel();
|
||||
}
|
||||
}, [cancelAfter, currentIteration, handleClickCancel]);
|
||||
|
||||
const cancelMenuItems = [
|
||||
{
|
||||
item: t('parameters.cancel.immediate'),
|
||||
onClick: () => dispatch(setCancelType('immediate')),
|
||||
},
|
||||
{
|
||||
item: t('parameters.cancel.schedule'),
|
||||
onClick: () => dispatch(setCancelType('scheduled')),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<IAIIconButton
|
||||
icon={<MdCancel />}
|
||||
tooltip={t('parameters.cancel')}
|
||||
aria-label={t('parameters.cancel')}
|
||||
isDisabled={!isConnected || !isProcessing || !isCancelable}
|
||||
onClick={handleClickCancel}
|
||||
styleClass="cancel-btn"
|
||||
{...rest}
|
||||
/>
|
||||
<ButtonGroup isAttached variant="link">
|
||||
{cancelType === 'immediate' ? (
|
||||
<IAIIconButton
|
||||
icon={<MdCancel />}
|
||||
tooltip={t('parameters.cancel.immediate')}
|
||||
aria-label={t('parameters.cancel.immediate')}
|
||||
isDisabled={!isConnected || !isProcessing || !isCancelable}
|
||||
onClick={handleClickCancel}
|
||||
className="cancel-btn"
|
||||
{...rest}
|
||||
/>
|
||||
) : (
|
||||
<IAIIconButton
|
||||
icon={
|
||||
isCancelScheduled ? (
|
||||
<ButtonSpinner color="var(--text-color)" />
|
||||
) : (
|
||||
<MdCancelScheduleSend />
|
||||
)
|
||||
}
|
||||
tooltip={
|
||||
isCancelScheduled
|
||||
? t('parameters.cancel.isScheduled')
|
||||
: t('parameters.cancel.schedule')
|
||||
}
|
||||
aria-label={
|
||||
isCancelScheduled
|
||||
? t('parameters.cancel.isScheduled')
|
||||
: t('parameters.cancel.schedule')
|
||||
}
|
||||
isDisabled={
|
||||
!isConnected ||
|
||||
!isProcessing ||
|
||||
!isCancelable ||
|
||||
currentIteration === totalIterations
|
||||
}
|
||||
onClick={() => {
|
||||
// If a cancel request has already been made, and the user clicks again before the next iteration has been processed, stop the request.
|
||||
if (isCancelScheduled) dispatch(setCancelAfter(null));
|
||||
else dispatch(setCancelAfter(currentIteration));
|
||||
}}
|
||||
className="cancel-btn"
|
||||
{...rest}
|
||||
/>
|
||||
)}
|
||||
<IAISimpleMenu
|
||||
menuItems={cancelMenuItems}
|
||||
iconTooltip={t('parameters.cancel.setType')}
|
||||
menuButtonProps={{
|
||||
backgroundColor: 'var(--destructive-color)',
|
||||
color: 'var(--text-color)',
|
||||
minWidth: '1.5rem',
|
||||
minHeight: '1.5rem',
|
||||
_hover: {
|
||||
backgroundColor: 'var(--destructive-color-hover)',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
);
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ export type ReadinessPayload = {
|
||||
|
||||
export type InProgressImageType = 'none' | 'full-res' | 'latents';
|
||||
|
||||
export type CancelType = 'immediate' | 'scheduled';
|
||||
|
||||
export interface SystemState
|
||||
extends InvokeAI.SystemStatus,
|
||||
InvokeAI.SystemConfig {
|
||||
@ -50,6 +52,10 @@ export interface SystemState
|
||||
searchFolder: string | null;
|
||||
foundModels: InvokeAI.FoundModel[] | null;
|
||||
openModel: string | null;
|
||||
cancelOptions: {
|
||||
cancelType: CancelType;
|
||||
cancelAfter: number | null;
|
||||
};
|
||||
}
|
||||
|
||||
const initialSystemState: SystemState = {
|
||||
@ -88,6 +94,10 @@ const initialSystemState: SystemState = {
|
||||
searchFolder: null,
|
||||
foundModels: null,
|
||||
openModel: null,
|
||||
cancelOptions: {
|
||||
cancelType: 'immediate',
|
||||
cancelAfter: null,
|
||||
},
|
||||
};
|
||||
|
||||
export const systemSlice = createSlice({
|
||||
@ -255,6 +265,12 @@ export const systemSlice = createSlice({
|
||||
setOpenModel: (state, action: PayloadAction<string | null>) => {
|
||||
state.openModel = action.payload;
|
||||
},
|
||||
setCancelType: (state, action: PayloadAction<CancelType>) => {
|
||||
state.cancelOptions.cancelType = action.payload;
|
||||
},
|
||||
setCancelAfter: (state, action: PayloadAction<number | null>) => {
|
||||
state.cancelOptions.cancelAfter = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -288,6 +304,8 @@ export const {
|
||||
setSearchFolder,
|
||||
setFoundModels,
|
||||
setOpenModel,
|
||||
setCancelType,
|
||||
setCancelAfter,
|
||||
} = systemSlice.actions;
|
||||
|
||||
export default systemSlice.reducer;
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user