// ==UserScript== // @name SDAtom-WebUi-us // @namespace SDAtom-WebUi-us // @version 1.4.1 // @description Queue for AUTOMATIC1111 WebUi and an option to saving settings // @author Kryptortio // @homepage https://github.com/Kryptortio/SDAtom-WebUi-us // @match http://127.0.0.1:7860/* // @updateURL https://raw.githubusercontent.com/Kryptortio/SDAtom-WebUi-us/main/SDAtom-WebUi-us.user.js // @downloadURL https://raw.githubusercontent.com/Kryptortio/SDAtom-WebUi-us/main/SDAtom-WebUi-us.user.js // @grant none // ==/UserScript== (function() { 'use strict'; const c_scriptVersion = typeof GM_info == 'undefined' ? '1.3.2' : GM_info.script.version; const c_scriptHandeler = typeof GM_info == 'undefined' ? '(not user script)' : GM_info.scriptHandler; // ----------------------------------------------------------------------------- Config let conf = { shadowDOM:{sel:"gradio-app"}, commonData: { t2iContainer:{sel:"#tab_txt2img"}, i2iContainer:{sel:"#tab_img2img"}, extContainer:{sel:"#tab_extras"}, sdModelCheckpoint:{grad:"setting_sd_model_checkpoint"}, versionContainer:{sel:"#footer .versions"}, working:false, processing:false, waiting:false, }, t2i: { controls:{ tabButton: {sel:"#tabs > div:nth-child(1) > button:nth-child(1)"}, genrateButton: {sel:"#txt2img_generate"}, skipButton: {sel:"#txt2img_skip"}, }, prompt: {sel:"#txt2img_prompt textarea"}, negPrompt: {sel:"#txt2img_neg_prompt textarea"}, sample: {sel:"#txt2img_steps [id^=range_id]",sel2:"#txt2img_steps input"}, sampleMethod: {grad:"txt2img_sampling"}, width: {sel:"#txt2img_width [id^=range_id]",sel2:"#txt2img_width input"}, height: {sel:"#txt2img_height [id^=range_id]",sel2:"#txt2img_height input"}, restoreFace: {sel:"#txt2img_settings #setting_face_restoration input"}, tiling: {sel:"#txt2img_settings #setting_tiling input"}, highresFix: {sel:"#txt2img_hr"}, hrFixUpscaler: {grad:"txt2img_hr_upscaler"}, hrFixSteps: {sel:"#txt2img_hires_steps [id^=range_id]",sel2:"#txt2img_hires_steps input"}, hrFixdenoise: {sel:"#txt2img_denoising_strength [id^=range_id]",sel2:"#txt2img_denoising_strength input"}, hrFixUpscaleBy: {sel:"#txt2img_hr_scale [id^=range_id]",sel2:"#txt2img_hr_scale input"}, hrFixWidth: {sel:"#txt2img_hr_resize_x [id^=range_id]",sel2:"#txt2img_hr_resize_x input"}, hrFixHeight: {sel:"#txt2img_hr_resize_y [id^=range_id]",sel2:"#txt2img_hr_resize_y input"}, batchCount: {sel:"#txt2img_batch_count [id^=range_id]",sel2:"#txt2img_batch_count input"}, batchSize: {sel:"#txt2img_batch_size [id^=range_id]",sel2:"#txt2img_batch_size input"}, cfg: {sel:"#txt2img_cfg_scale [id^=range_id]",se2:"#txt2img_cfg_scale input"}, seed: {sel:"#txt2img_seed input"}, extra: {sel:"#txt2img_subseed_show input"}, varSeed: {sel:"#txt2img_subseed input"}, varStr: {sel:"#txt2img_subseed_strength [id^=range_id]",sel2:"#txt2img_subseed_strength input"}, varRSFWidth: {sel:"#txt2img_seed_resize_from_w [id^=range_id]",sel2:"#txt2img_seed_resize_from_w input"}, varRSFHeight: {sel:"#txt2img_seed_resize_from_h [id^=range_id]",sel2:"#txt2img_seed_resize_from_h input"}, script: {grad:"script_list",gradIndex:0}, scriptPromptMatrixPutVar: {sel:"#script_txt2img_prompt_matrix_put_at_start input"}, scriptPromptMatrixUseDiff: {sel:"#script_txt2img_prompt_matrix_different_seeds input"}, scriptXYZXtype:{grad:"script_txt2img_xyz_plot_x_type"}, scriptXYZXVals:{sel:"#script_txt2img_xyz_plot_x_values textarea"}, scriptXYZYtype:{grad:"script_txt2img_xyz_plot_y_type"}, scriptXYZYVals:{sel:"#script_txt2img_xyz_plot_y_values textarea"}, scriptXYZZtype:{grad:"script_txt2img_xyz_plot_z_type"}, scriptXYZZVals:{sel:"#script_txt2img_xyz_plot_z_values textarea"}, scriptXYZDrawLeg:{sel:"#script_txt2img_xyz_plot_draw_legend input"}, scriptXYZIncludeSubImg:{sel:"#script_txt2img_xyz_plot_include_lone_images input"}, scriptXYZIncludeSubGrid:{sel:"#script_txt2img_xyz_plot_include_sub_grids input"}, scriptXYZKeepMOne:{sel:"#script_txt2img_xyz_plot_no_fixed_seeds input"}, scriptXYZGridMargin: {sel:"#script_txt2img_xyz_plot_margin_size [id^=range_id]",sel2:"#script_txt2img_xyz_plot_margin_size input"}, }, i2i:{ controls:{ tabButton: {sel:"#tabs > div:nth-child(1) > button:nth-child(2)"}, genrateButton: {sel:"#img2img_generate"}, skipButton: {sel:"#img2img_skip"}, i2iMode:[ {name:"i2i", buttonSel:"#mode_img2img button:nth-child(1)", containerSel:"#img2img_img2img_tab"}, {name:"sketch", buttonSel:"#mode_img2img button:nth-child(2)", containerSel:"#img2img_img2img_sketch_tab"}, {name:"inpaint", buttonSel:"#mode_img2img button:nth-child(3)", containerSel:"#img2img_inpaint_tab"}, {name:"inpaintSketch", buttonSel:"#mode_img2img button:nth-child(4)", containerSel:"#img2img_inpaint_sketch_tab"}, {name:"inpaintUpload", buttonSel:"#mode_img2img button:nth-child(5)", containerSel:"#img2img_inpaint_upload_tab"}, {name:"batch", buttonSel:"#mode_img2img button:nth-child(6)", containerSel:"#img2img_batch_tab"}, ], }, prompt: {sel:"#img2img_prompt textarea"}, negPrompt: {sel:"#img2img_neg_prompt textarea"}, resizeMode: {sel:"#resize_mode"}, inpaintBlur: {sel:"#img2img_mask_blur [id^=range_id]",sel2:"#img2img_mask_blur"}, inpaintMaskMode: {sel:"#img2img_mask_mode"}, inpaintMaskContent: {sel:"#img2img_inpainting_fill"}, inpaintArea: {sel:"#img2img_inpaint_full_res"}, inpaintPadding: {sel:"#img2img_inpaint_full_res_padding [id^=range_id]",sel2:"#img2img_inpaint_full_res_padding"}, i2iBatchInputDir: {sel:"#img2img_batch_input_dir textarea"}, i2iBatchOutputDir: {sel:"#img2img_batch_output_dir textarea"}, i2iBatchMaskDir: {sel:"#img2img_batch_inpaint_mask_dir textarea"}, sample: {sel:"#img2img_steps [id^=range_id]",sel2:"#img2img_steps input"}, sampleMethod: {grad:"img2img_sampling"}, width: {sel:"#img2img_width [id^=range_id]",sel2:"#img2img_width input"}, height: {sel:"#img2img_height [id^=range_id]",sel2:"#img2img_height input"}, restoreFace: {sel:"#img2img_settings #setting_face_restoration input"}, tiling: {sel:"#img2img_settings #setting_tiling input"}, batchCount: {sel:"#img2img_batch_count [id^=range_id]",sel2:"#img2img_batch_count input"}, batchSize: {sel:"#img2img_batch_size [id^=range_id]",sel2:"#img2img_batch_size input"}, cfg: {sel:"#img2img_cfg_scale [id^=range_id]",se2:"#img2img_cfg_scale input"}, denoise: {sel:"#img2img_denoising_strength [id^=range_id]",se2:"#img2img_denoising_strength input"}, seed: {sel:"#img2img_seed input"}, extra: {sel:"#txt2img_subseed_show input"}, varSeed: {sel:"#img2img_subseed input"}, varStr: {sel:"#img2img_subseed_strength input",sel2:"#img2img_subseed_strength [id^=range_id]"}, varRSFWidth: {sel:"#img2img_seed_resize_from_w input",sel2:"#img2img_seed_resize_from_w [id^=range_id]"}, varRSFHeight: {sel:"#img2img_seed_resize_from_h input",sel2:"#img2img_seed_resize_from_h [id^=range_id]"}, script: {grad:"script_list",gradIndex:1}, scriptPromptMatrixPutVar: {sel:"#script_img2img_prompt_matrix_put_at_start input"}, scriptPromptMatrixUseDiff: {sel:"#script_img2img_prompt_matrix_different_seeds input"}, scriptXYZXtype:{grad:"script_img2img_xyz_plot_x_type"}, scriptXYZXVals:{sel:"#script_img2img_xyz_plot_x_values textarea"}, scriptXYZYtype:{grad:"script_img2img_xyz_plot_y_type"}, scriptXYZYVals:{sel:"#script_img2img_xyz_plot_y_values textarea"}, scriptXYZZtype:{grad:"script_img2img_xyz_plot_z_type"}, scriptXYZZVals:{sel:"#script_img2img_xyz_plot_z_values textarea"}, scriptXYZDrawLeg:{sel:"#script_img2img_xyz_plot_draw_legend input"}, scriptXYZIncludeSubImg:{sel:"#script_img2img_xyz_plot_include_lone_images input"}, scriptXYZIncludeSubGrid:{sel:"#script_img2img_xyz_plot_include_sub_grids input"}, scriptXYZKeepMOne:{sel:"#script_img2img_xyz_plot_no_fixed_seeds input"}, scriptXYZGridMargin: {sel:"#script_img2img_xyz_plot_margin_size [id^=range_id]",sel2:"#script_img2img_xyz_plot_margin_size input"}, scripti2iAltTestOverrideSampM:{sel:"#script_img2img_alternative_test_override_sampler input"}, scripti2iAltTestOverrideProm:{sel:"#script_img2img_alternative_test_override_prompt input"}, scripti2iAltTestOrigProm:{sel:"#script_img2img_alternative_test_original_prompt textarea"}, scripti2iAltTestOrigNProm:{sel:"#script_img2img_alternative_test_original_negative_prompt textarea"}, scripti2iAltTestOverrideSampS:{sel:"#script_img2img_alternative_test_override_steps input"}, scripti2iAltTestDecStep:{sel:"#script_img2img_alternative_test_st input",sel2:"#script_img2img_alternative_test_st [id^=range_id]"}, scripti2iAltTestOverrideDenoi:{sel:"#script_img2img_alternative_test_override_strength input"}, scripti2iAltTestDecCFG:{sel:"#script_img2img_alternative_test_cfg input",sel2:"#script_img2img_alternative_test_cfg [id^=range_id]"}, scripti2iAltTestRand:{sel:"#script_img2img_alternative_test_randomness input",sel2:"#script_img2img_alternative_test_randomness [id^=range_id]"}, scripti2iAltTestSigma:{sel:"#script_img2img_alternative_test_sigma_adjustment input"}, scriptLoopbackLoops:{sel:"#script_loopback_loops input",sel2:"#script_loopback_loops [id^=range_id]"}, scriptLoopbackDenoStr:{sel:"#script_loopback_final_denoising_strength input",sel2:"#script_loopback_final_denoising_strength [id^=range_id]"}, scriptLoopbackDenoStrCurve:{gradLab:"Denoising strength curve"}, scriptLoopbackAppend:{gradLab:"Append interrogated prompt at each iteration"}, scriptOutPMK2Pixels:{sel:"#script_outpainting_mk2_pixels input",sel2:"#script_outpainting_mk2_pixels [id^=range_id]"}, scriptOutPMK2MaskBlur:{sel:"#script_outpainting_mk2_mask_blur input",sel2:"#script_outpainting_mk2_mask_blur [id^=range_id]"}, scriptOutPMK2Left:{sel:"#script_outpainting_mk2_direction label:nth-child(1) input"}, scriptOutPMK2Right:{sel:"#script_outpainting_mk2_direction label:nth-child(2) input"}, scriptOutPMK2Up:{sel:"#script_outpainting_mk2_direction label:nth-child(3) input"}, scriptOutPMK2Down:{sel:"#script_outpainting_mk2_direction label:nth-child(4) input"}, scriptOutPMK2FallOff:{sel:"#script_outpainting_mk2_noise_q input",sel2:"#script_outpainting_mk2_noise_q [id^=range_id]"}, scriptOutPMK2ColorVar:{sel:"#script_outpainting_mk2_color_variation input",sel2:"#script_outpainting_mk2_color_variation [id^=range_id]"}, scriptPoorManPixels:{sel:"#script_poor_mans_outpainting_pixels input",sel2:"#script_poor_mans_outpainting_pixels [id^=range_id]"}, scriptPoorManMaskBlur:{sel:"#script_poor_mans_outpainting_mask_blur input",sel2:"#script_poor_mans_outpainting_mask_blur [id^=range_id]"}, scriptPoorManMaskCont:{sel:"#script_poor_mans_outpainting_inpainting_fill"}, scriptPoorManLeft:{sel:"#script_poor_mans_outpainting_direction label:nth-child(1) input"}, scriptPoorManRight:{sel:"#script_poor_mans_outpainting_direction label:nth-child(2) input"}, scriptPoorManUp:{sel:"#script_poor_mans_outpainting_direction label:nth-child(3) input"}, scriptPoorManDown:{sel:"#script_poor_mans_outpainting_direction label:nth-child(4) input"}, scriptSDUpTile:{sel:"#script_sd_upscale_overlap input",sel2:"#script_sd_upscale_overlap [id^=range_id]"}, scriptSDUpScale:{sel:"#script_sd_upscale_scale_factor input",sel2:"#script_sd_upscale_scale_factor [id^=range_id]"}, scriptSDUpUpcaler:{sel:"#script_sd_upscale_upscaler_index"}, }, ext:{ controls:{ tabButton: {sel:"#tabs > div:nth-child(1) > button:nth-child(3)"}, genrateButton: {sel:"#extras_generate"}, loadingElement:{sel:"#html_info_x_extras .wrap"}, extrasResizeMode:[ {name:"scaleBy",buttonSel:"#extras_resize_mode button:nth-child(1)",containerSel:"#extras_scale_by_tab"}, {name:"scaleTo",buttonSel:"#extras_resize_mode button:nth-child(2)",containerSel:"#extras_scale_to_tab"}, ], extrasMode:[ {name:"singleImg",buttonSel:"#mode_extras button:nth-child(1)",containerSel:"#extras_single_tab"}, {name:"batchProcess",buttonSel:"#mode_extras button:nth-child(2)",containerSel:"#extras_batch_process_tab"}, {name:"batchDir",buttonSel:"#mode_extras button:nth-child(3)",containerSel:"#extras_batch_directory_tab"}, ], }, scaleByResize:{sel:"#extras_upscaling_resize input",sel2:"#extras_upscaling_resize [id^=range_id]"}, scaleToWidth:{sel:"#extras_upscaling_resize_w input"}, scaleToHeight:{sel:"#extras_upscaling_resize_h input"}, scaleToCropToFit:{sel:"#extras_upscaling_crop input"}, batchDirInput:{sel:"#extras_batch_input_dir textarea"}, batchDirOutput:{sel:"#extras_batch_output_dir textarea"}, batchDirShowImg:{sel:"#extras_show_extras_results input"}, upscaler1:{grad:"extras_upscaler_1"}, upscaler2:{grad:"extras_upscaler_2"}, upscale2Vis:{sel:"#extras_upscaler_2_visibility input",sel2:"#extras_upscaler_2_visibility [id^=range_id]"}, GFPGANVis:{sel:"#extras_gfpgan_visibility input",sel2:"#extras_gfpgan_visibility [id^=range_id]"}, CodeFormVis:{sel:"#extras_codeformer_visibility input",sel2:"#extras_codeformer_visibility [id^=range_id]"}, CodeFormWeight:{sel:"#extras_codeformer_weight input",sel2:"#extras_codeformer_weight [id^=range_id]"}, }, extensions: { iBrowser: { name:"stable-diffusion-webui-images-browser", existCheck:{sel:"#tab_image_browser"}, guiElems: { iBrowserContainer:{sel:"#tab_image_browser"}, generationInfo: {sel: "#image_browser_tab_txt2img_image_browser_file_info textarea"}, txt2img:{sel:'#image_browser_tab_txt2img_image_browser_file_info textarea'}, img2img:{sel:'#image_browser_tab_img2img_image_browser_file_info textarea'}, txt2imgG:{sel:'#image_browser_tab_txt2img-grids_image_browser_file_info textarea'}, img2imgG:{sel:'#image_browser_tab_img2img-grids_image_browser_file_info textarea'}, extras:{sel:'#image_browser_tab_extras_image_browser_file_info textarea'}, favorites:{sel:'#image_browser_tab_favorites_image_browser_file_info textarea'}, }, ui:{}, text:{ queueVariationsButtonText:'Add 5 variations', queueHiResVersionButtonText:'Add HiRes version', }, functions: { getValueJSON: function () { awqLog('iBrowser.getValueJSON: parsing data'); let valueJSON = {type:'t2i'}; let currentTab = document.querySelector('#image_browser_tabs_container button.selected').innerHTML; currentTab = currentTab.replace(/\s/g,''); currentTab = currentTab.replace('-grids','G').toLowerCase(); let generationInfoValue = conf.extensions.iBrowser.guiElems[currentTab].el.value; //Used when loading prompt from image browser /* Kind of using the logic from generation_parameters_copypaste.py/parse_generation_parameters (but not really, because that doesn't account for Template/Negative Template) Structure <prompt> Negative prompt: <negative prompt> a1: b1, a2: b2, etc Template: <template> Negative Template: <negative template> <prompt>, <negative prompt>, <template> and <negative template> can all be multiline, or missing. Maybe assume that <prompt> is never missing? */ let lines = generationInfoValue.split(/\r?\n/); let whichLine=0; //0=prompt, 1=negPrompt, 2=template, 3=negTemplate, 4: dictionary valueJSON['prompt']=''; valueJSON['negPrompt']=''; for (let l of lines) { if (l.startsWith("Negative prompt: ")) { whichLine=1; l=l.substring(17); } else if (l.startsWith("Template: ")) { whichLine=2; l=l.substring(10); } else if (l.startsWith("Negative Template: ")) { whichLine=3; l=l.substring(19); } else if (l.startsWith("Steps: ")) { whichLine=4; } switch (whichLine) { case 0: valueJSON['prompt']+=l; break; case 1: valueJSON['negPrompt']+=l; break; case 2: //ignore template break; case 3: //ignore neg template break; case 4: for (let v of l.split(/, /)) { let kv=v.split(/: /); let key=kv[0]; switch (kv[0]){ case "Steps": valueJSON['sample']=kv[1]; break; case "Sampler": valueJSON['sampleMethod']=kv[1]; break; case "CFG scale": valueJSON['cfg']=kv[1]; break; case "Seed": valueJSON['seed']=kv[1]; break; case "Size": let wh=kv[1].split(/x/) valueJSON['width']=wh[0]; valueJSON['height']=wh[1]; break; case "Model": valueJSON['sdModelCheckpoint']=kv[1]; break; case "Denoising strength": valueJSON['hrFixdenoise']=kv[1]; break; case "Hires upscale": valueJSON['hrFixUpscaleBy']=kv[1]; valueJSON['highresFix']=true; break; case "Hires upscaler": valueJSON['hrFixUpscaler']=kv[1]; break; } } break; } // End of switch } // End of for return JSON.stringify(valueJSON); }, }, // End of functions }, // End of iBrowser }, ui:{}, scriptSettings: { defaultQuantity:{name:"Default queue quantity", description:"Default number of times to execute each queue item", type:"numeric",value:"1"}, rememberQueue:{name:"Remember queue", description:"Remember the queue if you reload the page", type:"boolean",value:true}, notificationSound:{name:"Notification sound", description:"Sound to be played when processing of queue items stops", type:"boolean",value:true}, extensionScript:{name:"Extension script(s)", description:"https://github.com/Kryptortio/SDAtom-WebUi-us#script-extensions", type:"text",value:""}, promptFilter:{name:"Prompt filter(s)", description:"https://github.com/Kryptortio/SDAtom-WebUi-us#prompt-filter", type:"text",value:""}, promptFilterNegative:{name:"Filter negative prompt", description:"Apply the prompt filter to the negative filter as well", type:"boolean",value:false}, autoscrollOutput:{name:"Autoscroll console", description:"Scroll console automatically when new lines appear", type:"boolean",value:true}, verboseLog:{name:"Verbose console", description:"Log as much as possible to the console", type:"boolean",value:false}, maxOutputLines:{name:"Max console lines", description:"The maximum number of lines that can be shown in the console box", type:"numeric",value:"500"}, overwriteQueueSettings1:{name:"Alt 1 overwrite", description:"Add settings you want to overwrite the current settings with when you click the Alt 1 button to add to queue (same format as in the queue)", type:"text",value:'{"width":"768","height":"768"}'}, overwriteQueueSettings2:{name:"Alt 2 overwrite", description:"Add settings you want to overwrite the current settings with when you click the Alt 2 button to add to queue (same format as in the queue)", type:"text",value:'{"width":"1024","height":"1024"}'}, overwriteQueueSettings3:{name:"Alt 3 overwrite", description:"Add settings you want to overwrite the current settings with when you click the Alt 3 button to add to queue (same format as in the queue)", type:"text",value:'{"sample":"20","sampleMethod":"Euler a","width":"512","height":"512","restoreFace": false,"tiling": false,"batchCount": "1","batchSize": "1","cfg": "7","seed": "-1","extra": false, "varSeed": "-1","varStr": "0"}'}, buttonOpacity:{name:"Button transparency", description:"Change how visible the floating buttons in the corner should be", type:"numeric",value:0.7}, }, savedSetting: JSON.parse(localStorage.awqSavedSetting || '{}'), currentQueue: JSON.parse(localStorage.awqCurrentQueue || '[]'), }; if(localStorage.hasOwnProperty("awqNotificationSound") && !localStorage.hasOwnProperty("awqScriptSettings")) { // Tmp settings migration awqLog('Copying settings from old storage'); if (localStorage.hasOwnProperty("awqNotificationSound")) conf.scriptSettings.notificationSound.value = localStorage.awqNotificationSound == 1 ? true : false; if (localStorage.hasOwnProperty("awqAutoscrollOutput")) conf.scriptSettings.autoscrollOutput.value = localStorage.awqAutoscrollOutput == 1 ? true : false; if (localStorage.hasOwnProperty("awqVerboseLog")) conf.scriptSettings.verboseLog.value = localStorage.awqVerboseLog == 1 ? true : false; if (localStorage.hasOwnProperty("awqMaxOutputLines")) conf.scriptSettings.maxOutputLines.value = localStorage.awqMaxOutputLines; if (localStorage.hasOwnProperty("awqPromptFilter")) conf.scriptSettings.promptFilter.value = localStorage.awqPromptFilter; if (localStorage.hasOwnProperty("awqExtensionScript")) conf.scriptSettings.extensionScript.value = localStorage.awqExtensionScript; } const c_emptyQueueString = 'Queue is empty'; const c_addToQueueButtonText = 'Add to queue'; const c_processButtonText = 'Process queue'; const c_defaultTextStoredSettings = "Stored settings"; const c_innerUIWidth = 'calc(100vw - 20px)'; const c_uiElemntHeight = '25px'; const c_uiElemntHeightSmall = '18px'; const c_audio_base64 = new Audio('data:audio/mpeg;base64,//PkZAAAAAGkAAAAAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//PkZAAAAAGkAAAAAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVR9DU02wxI2HBY0xzzTPHVjsaEggIYbBQymbZ5et+lSLLDAPL2LcegkDNlkiLYgIBgMoIRxodnFVNMu2pmYwSfDSC2CxTFDKowcoycCimGKGFhYRCx50EjDS05dCEXJaIRTRHMTQfkO/U/sjuSEa5wroVM0a2hmXr0oA7JasD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V///+YGDIYDB4HGBRAYjCABAQMAOrVXeNb/////QYBwSBIETHQhBgBRAMGgq1lV3jW13f//////ogl+UTWeJbqBIMiQBa6X2STL/Y1tdq75lrtXf///////44AURAYAVhE+lMmFrcRNYQqJhyhq4FhWjY1tdx/mWu475lrv//////////rTVMnql4XBZApWX+aWuRL1jSmZf5pbEEvXQWDS+Z+yzHfK2u1d8y12rtFKTRUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//PkZAAAAAGkAOAAAAAAA0gBwAAATEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV'); const c_defaultOtputConsoleText = "Here you will see some information about what the script is doing"; const c_defaultOtputConsoleTextHTML = `<span class="console-description" style="color:darkgray">${c_defaultOtputConsoleText}</span>`; const c_extraResizeModeScaleByType = 1; const c_extraResizeModeScaleToType = 2; const c_wait_tick_duration = 200; const c_any_value = '<ANY VALUE>'; // ----------------------------------------------------------------------------- Logging function preAwqLog(p_message) { console.log(`SDAtom-WebUi-us: ${p_message}`); } preAwqLog(`Running SDAtom-WebUi-us version ${c_scriptVersion} using ${c_scriptHandeler} with browser ${window.navigator.userAgent}`); function awqLog(p_message) { if(conf.scriptSettings.verboseLog.value) { awqLogPublishMsg(p_message, 'lightgray'); } } function awqLogPublishMsg(p_message, p_color) { if(!conf.ui.outputConsole) return; if(conf.ui.outputConsole.innerHTML.match('console-description')) { let ASDWUIVerText = '<span style="font-size: 0.9em;">' + conf.commonData.versionContainer.el.textContent + '</span>'; conf.ui.outputConsole.innerHTML = `* Running SDAtom-WebUi-us version ${c_scriptVersion} using ${c_scriptHandeler} with browser ${window.navigator.userAgent} stable-diffusion-webui version ${ASDWUIVerText}`; } let lines = conf.ui.outputConsole.querySelectorAll('div'); let line = document.createElement('div'); line.className = 'awq-console-line'; const timestamp = (new Date()).toLocaleTimeString([], {hour: '2-digit',minute: '2-digit',second: '2-digit', hour12: false}); line.innerHTML = '<span style="' + (p_color ? 'color:'+p_color : '') + '">' + timestamp + ': ' + p_message + '</span>'; conf.ui.outputConsole.appendChild(line); if(lines.length >= conf.scriptSettings.maxOutputLines.value) { lines[0].parentNode.removeChild(lines[0]); } if(conf.scriptSettings.autoscrollOutput.value) conf.ui.outputConsole.scrollTo(0, conf.ui.outputConsole.scrollHeight); } function awqLogPublishError(p_message) { awqLogPublishMsg(p_message, 'red') } window.addEventListener("error", (event) => { if(conf.scriptSettings.verboseLog.value) { awqLogPublishMsg( `Javascript error (can be caused by something other than this script): ${event.message} source:${event.filename} line:${event.lineno} col:${event.colno} Error:${event.error ? JSON.stringify(event.error) : '' }`, 'darkorange' ); } },true); window.addEventListener("unhandledrejection", (event) => { if(conf.scriptSettings.verboseLog.value) { awqLogPublishMsg( `Javascript promise error (can be caused by something other than this script): ${event.reason}`, 'darkorange' ); } },true); let oldWarn = window.console.warn,oldInfo = window.console.info,oldLog = window.console.log,oldError = window.console.error; window.console.warn = function(p_msg) { if(conf.scriptSettings.verboseLog.value) awqLogPublishMsg('log (warn) message (can be caused by something other than this script):' + p_msg +`<br>Call stack:<pre>${getCallStack()}</pre>`, 'lightgray'); oldWarn(p_msg); } window.console.info = function(p_msg) { if(conf.scriptSettings.verboseLog.value) awqLogPublishMsg('log (info) message (can be caused by something other than this script):' + p_msg +`<br>Call stack:<pre>${getCallStack()}</pre>`, 'lightgray'); oldInfo(p_msg); } window.console.log = function(p_msg) { if(conf.scriptSettings.verboseLog.value) awqLogPublishMsg('log (log) message (can be caused by something other than this script):' + p_msg +`<br>Call stack:<pre>${getCallStack()}</pre>`, 'lightgray'); oldLog(p_msg); } // ----------------------------------------------------------------------------- Wait for content to load let waitForLoadInterval = setInterval(initAWQ, c_wait_tick_duration); function initAWQ() { window.awqConf = conf; conf.shadowDOM.root = document.querySelector(conf.shadowDOM.sel); if(!conf.shadowDOM.root || !conf.shadowDOM.root.querySelector('#txt2img_prompt')) return; clearInterval(waitForLoadInterval); conf.commonData.versionContainer.el = conf.shadowDOM.root.querySelector('#footer .versions'); // Check for extensions for(let ext in conf.extensions) { if(!document.querySelector(conf.extensions[ext].existCheck.sel)) { preAwqLog(`Extension ${conf.extensions[ext].name} not found, disabling`); conf.extensions[ext] = false; } else { preAwqLog(`Extension ${conf.extensions[ext].name} found`); } } loadScriptSettings(); generateMainUI(); try { throw new Error(); } catch(e) { awqLog(`initAWQ: stack = ${e.stack.replace(/^(.*?)\binitAWQ/s,'')}`) } try { eval(conf.scriptSettings.extensionScript.value);} catch(e) { awqLogPublishMsg(`Failed to load extension script, error: <pre>${e.message} l:${e.lineNumber} c:${e.columnNumber}\n${e.stack}</pre>`,'darkorange')} function mapElementsToConf(p_object, p_info) { for (let prop in p_object) { if(p_object[prop].sel) { p_object[prop].el = conf.shadowDOM.root.querySelector(p_object[prop].sel); if(!p_object[prop].el) awqLogPublishError(`Failed to find the ${p_info} ${prop}`); } if(p_object[prop].sel2) { p_object[prop].el2 = conf.shadowDOM.root.querySelector(p_object[prop].sel2); if(!p_object[prop].el2) awqLogPublishError(`Failed to find the secondary ${p_info} ${prop}`); } if(p_object[prop].grad) { let gradIndex = p_object[prop].gradIndex ? p_object[prop].gradIndex : 0; p_object[prop].gradEl = findGradioComponentState(p_object[prop].grad)[gradIndex]; if(!p_object[prop].gradEl) awqLogPublishError(`Failed to find the gradio element ${p_info} ${prop}`); } if(p_object[prop].gradLab) { p_object[prop].gradEl = findGradioComponentStateByLabel(p_object[prop].gradLab)[0]; if(!p_object[prop].gradEl) awqLogPublishError(`Failed to find the gradio element ${p_info} ${prop}`); } } } mapElementsToConf(conf.commonData, 'main object'); mapElementsToConf(conf.t2i, 't2i object'); mapElementsToConf(conf.t2i.controls, 't2i control'); mapElementsToConf(conf.i2i, 'i2i object'); mapElementsToConf(conf.i2i.controls, 'i2i control'); mapElementsToConf(conf.ext, 'ext object'); mapElementsToConf(conf.ext.controls, 'ext control'); if(conf.extensions.iBrowser) waitForElm(conf.extensions.iBrowser.guiElems.txt2img.sel).then(function() {mapElementsToConf(conf.extensions.iBrowser.guiElems, 'iBrowser objects')}); setInterval(updateStatus, c_wait_tick_duration); } function appendAddToQueueButton(container, top, innerHTML, onclick, title, right) { let button = document.createElement('button'); button.innerHTML = innerHTML; button.style.height = c_uiElemntHeight; button.style.color = 'black'; button.style.position = 'fixed'; button.style.top = top + 'px'; button.style.right = right ? right + 'px' : 0; button.style.opacity = conf.scriptSettings.buttonOpacity.value; button.onclick = onclick; button.style.cursor = "pointer"; button.title = title; button.style.display = 'none'; button.classList.add('awq-hover-button'); container.appendChild(button); return button; } function generateMainUI() { let awqCSSElem = document.createElement('style'); awqCSSElem.innerHTML = ` #AWQ-container { background:var(--background-fill-primary); } #AWQ-container button { border:var(--button-border-width) solid var(--button-secondary-border-color); background:var(--button-secondary-background-fill); color:var(--button-secondary-text-color); } #AWQ-container input, #AWQ-container select, #AWQ-container .awq-console-line, #awq-script-settings-popup input, #awq-script-settings-popup textarea { box-shadow: var(--input-shadow); border: var(--input-border-width) solid var(--input-border-color); border-radius: var(--input-radius); background: var(--input-background-fill); color: var(--body-text-color); } #AWQ-container input.completed-queue-item { background:var(--button-secondary-background-fill); color:var(--button-secondary-text-color); } #AWQ-container .awq-console-line { border-radius: unset; } #awq-script-settings-popup { background:var(--background-fill-primary); } #awq-script-settings-popup label, #awq-script-settings-popup span { color: var(--block-title-text-color); } `; document.head.appendChild(awqCSSElem); let container = document.createElement('div'); container.id = 'AWQ-container'; container.className = document.querySelector('gradio-app > div').classList.contains('dark') ? 'dark' : ''; container.style.width = c_innerUIWidth; container.style.border = "1px solid white"; container.style.position = "relative"; container.style.zIndex = "2147483647"; document.body.appendChild(container); let addToQueueButton = appendAddToQueueButton(container, 0, c_addToQueueButtonText, appendQueueItem, "Add an item to the queue according to current tab and settings"); let addToQueueButtonA1 = appendAddToQueueButton(container, 25, 'A1', () => {appendQueueItem(null, null, null, JSON.parse(conf.scriptSettings.overwriteQueueSettings1.value)) }, "Add an item to the queue according to current tab and settings and overwrite with Alt 1",63); let addToQueueButtonA2 = appendAddToQueueButton(container, 25, 'A2', () => {appendQueueItem(null, null, null, JSON.parse(conf.scriptSettings.overwriteQueueSettings2.value)) }, "Add an item to the queue according to current tab and settings and overwrite with Alt 2",32); let addToQueueButtonA3 = appendAddToQueueButton(container, 25, 'A3', () => {appendQueueItem(null, null, null, JSON.parse(conf.scriptSettings.overwriteQueueSettings3.value)) }, "Add an item to the queue according to current tab and settings and overwrite with Alt 3",1); let unsupportedButton = appendAddToQueueButton(container, 0, 'Tab not supported', function(){}, "Not supported"); unsupportedButton.disabled = true; unsupportedButton.innerHTML = 'Tab not supported'; unsupportedButton.style.cursor = 'not-allowed'; let defaultQueueQuantity = document.createElement('input'); defaultQueueQuantity.placeholder = 'Def #'; defaultQueueQuantity.style.height = c_uiElemntHeightSmall; defaultQueueQuantity.style.width = '50px'; defaultQueueQuantity.type = 'number'; defaultQueueQuantity.title = "How many items of each will be added to the queue (default is 1)"; defaultQueueQuantity.value = conf.scriptSettings.defaultQuantity.value; defaultQueueQuantity.onchange = function() {conf.scriptSettings.defaultQuantity.value = this.value;}; defaultQueueQuantity.onfocus = function() {this.select();}; container.appendChild(defaultQueueQuantity); let assignDefaultToAll = document.createElement('button'); assignDefaultToAll.innerHTML = ' ⤵'; assignDefaultToAll.style.cursor = "pointer"; assignDefaultToAll.title = "Assign the default value to all queue items"; assignDefaultToAll.style.height = c_uiElemntHeight; assignDefaultToAll.style.marginRight = '10px'; assignDefaultToAll.onclick = function() { if(conf.scriptSettings.defaultQuantity.value >= 0) { document.querySelectorAll('.AWQ-item-quantity').forEach((inp) => {inp.value = conf.scriptSettings.defaultQuantity.value}); updateQueueState(); } }; container.appendChild(assignDefaultToAll); let processButton = document.createElement('button'); processButton.innerHTML = c_processButtonText; processButton.style.height = c_uiElemntHeight; processButton.style.cursor = "pointer"; processButton.title = "Start processing the queue, click again to stop"; processButton.onclick = function() { toggleProcessButton(); } conf.ui.processButton = processButton; container.appendChild(processButton); let clearButton = document.createElement('button'); clearButton.innerHTML = "Clear queue"; clearButton.style.marginLeft = "5px"; clearButton.style.height = c_uiElemntHeight; clearButton.style.cursor = "pointer"; clearButton.title = "Empty the queue completely"; clearButton.onclick = function() { if(!confirm('Are you sure you want to remove everything in your queue?')) return; queueContainer.innerHTML = c_emptyQueueString; let oldQueueLength = conf.currentQueue.length; conf.currentQueue = []; updateQueueState(); awqLogPublishMsg(`Queue has been cleared, ${oldQueueLength} items removed`); } container.appendChild(clearButton); let scriptSettingsButton = document.createElement('button'); scriptSettingsButton.innerHTML = "Script settings"; scriptSettingsButton.style.float = 'right'; scriptSettingsButton.style.height = c_uiElemntHeight; scriptSettingsButton.style.cursor = "pointer"; scriptSettingsButton.title = "Open the settings popup for the script"; scriptSettingsButton.onclick = openScriptSettingsPopup; container.appendChild(scriptSettingsButton); let queueContainer = document.createElement('div'); queueContainer.style.width = c_innerUIWidth; queueContainer.style.border = "1px solid white"; queueContainer.style.color = "gray"; queueContainer.style.marginBottom = "5px"; queueContainer.innerHTML = c_emptyQueueString; container.appendChild(queueContainer); let clearSettingButton = document.createElement('button'); clearSettingButton.innerHTML = "❌"; clearSettingButton.style.height = c_uiElemntHeight; clearSettingButton.style.background = 'none'; clearSettingButton.onclick = function() {clearSetting(); } clearSettingButton.style.cursor = "pointer"; clearSettingButton.title = "Remove the currently selected setting"; container.appendChild(clearSettingButton); let settingsStorage = document.createElement('select'); settingsStorage.style.height = c_uiElemntHeight; settingsStorage.title = "List of stored settings (template of all settings)"; container.appendChild(settingsStorage); let editSettingButton = document.createElement('button'); editSettingButton.innerHTML = "✏️"; editSettingButton.style.height = c_uiElemntHeight; editSettingButton.onclick = function() {editSetting(); } editSettingButton.style.cursor = "pointer"; editSettingButton.title = "Edit the currently selected setting (a property can be removed to not change it when loading)"; container.appendChild(editSettingButton); let loadSettingButton = document.createElement('button'); loadSettingButton.innerHTML = "Load"; loadSettingButton.style.height = c_uiElemntHeight; loadSettingButton.onclick = function() {loadSetting(); } loadSettingButton.style.cursor = "pointer"; loadSettingButton.title = "Load the currently selected setting (replacing current settings)"; container.appendChild(loadSettingButton); let settingName =document.createElement('input'); settingName.placeholder = "Setting name"; settingName.style.height = c_uiElemntHeightSmall; settingName.title = "Name to use when saving a new setting (duplicates not allowed)"; settingName.onfocus = function() {this.select();}; container.appendChild(settingName); let saveSettingButton = document.createElement('button'); saveSettingButton.innerHTML = "Save"; saveSettingButton.style.height = c_uiElemntHeight; saveSettingButton.onclick = function() {saveSettings(); } saveSettingButton.style.cursor = "pointer"; saveSettingButton.title = "Save currently selected settings so that you can load them again later"; container.appendChild(saveSettingButton); let outputConsole = document.createElement('div'); outputConsole.title = c_defaultOtputConsoleText; outputConsole.innerHTML = c_defaultOtputConsoleTextHTML; outputConsole.style.width = 'calc(100vw - 50px)'; outputConsole.style.border = "1px solid black"; outputConsole.style.color = "gray"; outputConsole.style.padding = "2px"; outputConsole.style.marginTop = "5px"; outputConsole.style.marginBottom = "5px"; outputConsole.style.marginLeft = "15px"; outputConsole.style.marginRight = "15px"; outputConsole.style.height = (16*10)+"px"; outputConsole.style.overflow = "auto"; //outputConsole.style.backgroundColor = "white"; outputConsole.style.boxShadow = 'inset 0px 1px 4px #666'; container.appendChild(outputConsole); let outputConsoleClearButton = document.createElement('button'); outputConsoleClearButton.innerHTML = "Clear"; outputConsoleClearButton.style.height = c_uiElemntHeight; outputConsoleClearButton.onclick = function() {conf.ui.outputConsole.innerHTML = c_defaultOtputConsoleTextHTML; } outputConsoleClearButton.style.cursor = "pointer"; outputConsoleClearButton.style.marginLeft = "10px"; outputConsoleClearButton.title = "Clear the console above"; container.appendChild(outputConsoleClearButton); conf.ui.addToQueueButton = addToQueueButton; conf.ui.addToQueueButtonA1 = addToQueueButtonA1; conf.ui.addToQueueButtonA2 = addToQueueButtonA2; conf.ui.addToQueueButtonA3 = addToQueueButtonA3; conf.ui.unsupportedButton = unsupportedButton; conf.ui.queueContainer = queueContainer; conf.ui.clearButton = clearButton; conf.ui.loadSettingButton = loadSettingButton; conf.ui.settingName = settingName; conf.ui.settingsStorage = settingsStorage; conf.ui.defaultQueueQuantity = defaultQueueQuantity; conf.ui.outputConsole = outputConsole; document.querySelector('.gradio-container').style.overflow = 'visible'; // Fix so that a dropdown menu can overlap the queue refreshSettings(); if(conf.currentQueue.length > 0) { awqLog('Loaded saved queue:'+conf.currentQueue.length); for(let i = 0; i < conf.currentQueue.length; i++) { appendQueueItem(conf.currentQueue[i].quantity, conf.currentQueue[i].value, conf.currentQueue[i].type); } updateQueueState(); } awqLog('generateMainUI: Completed'); } function appendQueueItem(p_quantity, p_value, p_type, p_overwrite_data) { awqLog('appendQueueItem: quantity:' + p_quantity + ' type:' + p_type); let quantity = isNaN(p_quantity) || p_quantity == null ? (parseInt(conf.ui.defaultQueueQuantity.value) > 0 ? parseInt(conf.ui.defaultQueueQuantity.value) : 1) : p_quantity; let queueItem = document.createElement('div'); queueItem.style.width = c_innerUIWidth; let itemType =document.createElement('input'); itemType.classList = 'AWQ-item-type'; itemType.style.display = "50px"; itemType.style.height = c_uiElemntHeightSmall; itemType.style.width = "20px"; itemType.title = "This is the type/tab for the queue item"; itemType.disabled = true; let itemQuantity = document.createElement('input'); function updateItemQuantityBG() { if(itemQuantity.value.length == 0) { itemQuantity.style.color = 'red'; } else if(itemQuantity.value < 1) { itemQuantity.style.color = 'rgb(0, 225, 0)'; itemQuantity.classList.add('completed-queue-item') } else if(itemQuantity.value > 0) { itemQuantity.style.color = 'white'; itemQuantity.classList.remove('completed-queue-item')} } itemQuantity.classList = 'AWQ-item-quantity'; itemQuantity.value = quantity; itemQuantity.style.width = "50px"; itemQuantity.type = 'number'; itemQuantity.style.height = c_uiElemntHeightSmall; itemQuantity.onchange = function() { updateItemQuantityBG(); updateQueueState(); }; updateItemQuantityBG(); itemQuantity.onfocus = function() {this.select();}; itemQuantity.title = "This is how many times this item should be executed"; let itemJSON =document.createElement('input'); itemJSON.classList = 'AWQ-item-JSON'; itemJSON.value = p_value || getValueJSON(p_type); if(p_overwrite_data) { awqLog(`appendQueueItem: Adding to queue with Overwriting: ${JSON.stringify(p_overwrite_data)}`); let jsonData = JSON.parse(itemJSON.value); for(let setKey in p_overwrite_data) { jsonData[setKey] = p_overwrite_data[setKey]; } itemJSON.value = JSON.stringify(jsonData); } itemJSON.style.width = "calc(100vw - 290px)"; itemJSON.style.height = "18px"; itemJSON.onchange = function() { updateQueueState(); // Update itemType if needed let newType = itemJSON.value.match(/"type":"([^"]+)"/); newType = newType ? newType[1] : null; if(newType != itemType.value) itemType.value = newType; } itemJSON.title = "This is a JSON string with all the settings to be used for this item. Can be changed while processing the queue but will fail if you enter invalid values."; let JSONType = itemJSON.value.match(/"type":"([^"]+)"/); JSONType = JSONType ? JSONType[1] : conf.commonData.activeType; itemType.value = p_type || JSONType; let removeItem =document.createElement('button'); removeItem.innerHTML = '❌'; removeItem.style.height = c_uiElemntHeight; removeItem.style.background = 'none'; removeItem.style.cursor = "pointer"; removeItem.title = "Remove this item from the queue"; removeItem.onclick = function() { this.parentNode.parentNode.removeChild(this.parentNode); updateQueueState(); awqLogPublishMsg(`Removed queue item`); }; let moveItemUp =document.createElement('button'); moveItemUp.innerHTML = '⇧'; moveItemUp.style.height = c_uiElemntHeight; moveItemUp.style.cursor = "pointer"; moveItemUp.title = "Move this item up in the queue"; moveItemUp.onclick = function() { let tar = this.parentNode; if(tar.previousSibling) { tar.parentNode.insertBefore(tar, tar.previousSibling); awqLogPublishMsg(`Rearranged queue`); updateQueueState(); } }; let moveItemDown =document.createElement('button'); moveItemDown.innerHTML = '⇩'; moveItemDown.style.height = c_uiElemntHeight; moveItemDown.style.cursor = "pointer"; moveItemDown.title = "Move this item down in the queue"; moveItemDown.onclick = function() { let tar = this.parentNode; if(tar.nextSibling) { tar.parentNode.insertBefore(tar.nextSibling, tar); awqLogPublishMsg(`Rearranged queue`); updateQueueState(); } }; let moveItemBottom =document.createElement('button'); moveItemBottom.innerHTML = '⤓'; moveItemBottom.style.height = c_uiElemntHeight; moveItemBottom.style.cursor = "pointer"; moveItemBottom.title = "Move this item to the bottom of the queue"; moveItemBottom.onclick = function() { let tar = this.parentNode; if(tar.parentNode.lastChild !== tar) { tar.parentNode.appendChild(tar); updateQueueState(); } }; let moveItemTop =document.createElement('button'); moveItemTop.innerHTML = '⤒'; moveItemTop.style.height = c_uiElemntHeight; moveItemTop.style.cursor = "pointer"; moveItemTop.title = "Move this item to the top of the queue"; moveItemTop.onclick = function() { let tar = this.parentNode; let parentFirstChild = tar.parentNode.firstChild; if(parentFirstChild && parentFirstChild !== tar) { tar.parentNode.insertBefore(tar, parentFirstChild); awqLogPublishMsg(`Rearranged queue`); updateQueueState(); } }; let loadItem =document.createElement('button'); loadItem.innerHTML = 'Load'; loadItem.style.height = c_uiElemntHeight; loadItem.style.cursor = "pointer"; loadItem.title = "Load the settings from this item"; loadItem.onclick = async function() { let itemRow = this.parentNode; await loadJson(itemRow.querySelector('.AWQ-item-JSON').value); }; queueItem.appendChild(removeItem); queueItem.appendChild(moveItemUp); queueItem.appendChild(moveItemDown); queueItem.appendChild(moveItemBottom); queueItem.appendChild(moveItemTop); queueItem.appendChild(loadItem); queueItem.appendChild(itemType); queueItem.appendChild(itemQuantity); queueItem.appendChild(itemJSON); if(conf.ui.queueContainer.innerHTML == c_emptyQueueString) conf.ui.queueContainer.innerHTML = ""; conf.ui.queueContainer.appendChild(queueItem); awqLogPublishMsg(`Added new ${itemType.value} queue item (${quantity}x)`); // Wait with updating state while loading a predefined queue if(isNaN(p_quantity)) updateQueueState(); } function saveScriptSettings() { awqLog('Saving script settings'); let scriptSettingsCopy = structuredClone(conf.scriptSettings); // Delete data that does not need to be saved for(let ssk in scriptSettingsCopy) { for(let ssk2 in scriptSettingsCopy[ssk]) { if(ssk2 != 'value') delete scriptSettingsCopy[ssk][ssk2]; } } conf.ui.defaultQueueQuantity.value = conf.scriptSettings.defaultQuantity.value; // Update beacuse this one is in two places localStorage.awqScriptSettings = JSON.stringify(scriptSettingsCopy); } function loadScriptSettings(p_scriptSettings) { if(!localStorage.hasOwnProperty("awqScriptSettings") || !isJsonString(localStorage.awqScriptSettings)) return; awqLog('Loding saved script settings'); let savedSettings = p_scriptSettings || JSON.parse(localStorage.awqScriptSettings); for(let ssk in conf.scriptSettings) { if(savedSettings.hasOwnProperty(ssk)) conf.scriptSettings[ssk].value = savedSettings[ssk].value; } } function openScriptSettingsPopup() { let dialog = document.createElement('span'); dialog.id = 'awq-script-settings-popup'; dialog.className = document.querySelector('gradio-app > div').classList.contains('dark') ? 'dark' : ''; dialog.style.minWidth = '90%'; dialog.style.minHeight = '90%'; dialog.style.marginLeft = '5%'; dialog.style.marginTop = '5%'; dialog.style.top = '0'; dialog.style.position = 'fixed'; dialog.style.zIndex = '1000'; dialog.style.borderRadius = '15px'; dialog.style.boxShadow = '3px 3px 100px black,3px 3px 500px black, 3px 3px 25px black, inset 0 0 10px black'; let titleText = document.createElement('span'); titleText.innerHTML = '<b>Script settings</b> - <i>hold your mouse over an item for a description</i>'; titleText.style.top = '5px'; titleText.style.left = '10px'; titleText.style.position = 'absolute'; let closeButton = document.createElement('span'); closeButton.style.position = 'absolute'; closeButton.style.top = '5px'; closeButton.style.right = '10px'; closeButton.style.textShadow = '#292929 2px 3px 5px'; closeButton.style.cursor = 'pointer'; closeButton.onclick = function() {document.body.removeChild(dialog); saveScriptSettings();}; closeButton.innerHTML = '⛌'; let dialogBody = document.createElement('span'); dialogBody.style.width = '90%'; dialogBody.style.height = '90%'; dialogBody.style.marginLeft = '5%'; dialogBody.style.marginTop = 'max(5%,45px)'; dialogBody.style.top = '0'; dialogBody.style.position = 'absolute'; dialogBody.style.overflow = 'auto'; dialogBody.style.display = 'grid'; dialogBody.style.gridAutoFlow = 'row'; dialogBody.style.gridTemplateColumns = 'repeat(auto-fit, minmax(200px, 1fr))'; dialog.appendChild(titleText); dialog.appendChild(closeButton); dialog.appendChild(dialogBody); // Create input for each script setting for(let ssKey in conf.scriptSettings) { let ssObj = conf.scriptSettings[ssKey]; let ssElem = document.createElement(ssObj.type == 'text' ? 'textarea' : 'input'); ssElem.id = 'awq-ss-'+ssKey; ssElem.placeholder = ssObj.name; ssElem.value = ssObj.value; ssElem.style.height = ssObj.type == 'text' ? '40px' : '20px'; ssElem.style.marginRight = '20px'; ssElem.onchange = function() { conf.scriptSettings[ssKey].value = ssObj.type == 'boolean' ? this.checked : this.value; saveScriptSettings(); }; if(ssObj.type == 'boolean') ssElem.type = 'checkbox'; if(ssObj.type == 'numeric') { ssElem.type = 'number' ; ssElem.inputmode = 'numeric'; ssElem.onkeypress = e => { if (e.key.match(/\D/g)) { e.preventDefault();} }; } if(ssObj.type == 'boolean') { ssElem.type = 'checkbox'; ssElem.checked = ssObj.value; } let cbLabel = document.createElement('label'); cbLabel.for = ssElem.id; cbLabel.innerHTML = ssObj.name; cbLabel.title = ssObj.description; let ssElemContainer = document.createElement('span'); ssElemContainer.appendChild(cbLabel); if(ssObj.description.match("http")) { let helpLink = document.createElement('a'); helpLink.innerHTML = '❓'; helpLink.target = '_blank'; helpLink.href = ssObj.description; helpLink.style.textDecoration = 'none'; ssElem.title = ssObj.name; ssElemContainer.appendChild(helpLink); } else { ssElem.title = ssObj.description; } ssElemContainer.appendChild(ssElem); dialogBody.appendChild(ssElemContainer); } let importExportButton = document.createElement('button'); importExportButton.innerHTML = "Import/export"; importExportButton.style.height = c_uiElemntHeight; importExportButton.style.cursor = "pointer"; importExportButton.title = "Import or export all the data for this script (to import add previoiusly exported data to the right, to export leave it empty). Importing data will reload the page!"; importExportButton.onclick = exportImport; let importExportData = document.createElement('input'); importExportData.id = 'import-export-data-input'; importExportData.placeholder = 'Import/export data'; importExportData.style.height = c_uiElemntHeightSmall; importExportData.style.width = '125px'; importExportData.title = "Exported data will be show here, add data here to import it. Importing data will reload the page!"; importExportData.onfocus = function() {this.select();}; let importExportContainer = document.createElement('span'); importExportContainer.appendChild(importExportButton); importExportContainer.appendChild(importExportData); dialogBody.appendChild(importExportContainer); // *** Search & Replace *** START // Add replace in queue function GUI let collectedAttributes = {}; let anyOption = document.createElement('option'); anyOption.value = c_any_value; conf.currentQueue.map(el => { // Fetch all attributes and values currently in queue let queueObject = JSON.parse(el.value); Object.keys(queueObject).forEach(function(key,index) { if(!collectedAttributes[key]) collectedAttributes[key] = {}; collectedAttributes[key][queueObject[key]] = ''; }); }); let componentOptions = []; window.gradio_config.components.forEach(el => { if(el.props && el.props.choices) { componentOptions.push(el.props.choices); } }); let replaceLabel = document.createElement('label'); replaceLabel.innerHTML = 'Search and replace'; replaceLabel.style.display = 'block'; replaceLabel.title = 'Here you can search for values in the queue and replace them with something else'; let replaceAttributeSelectorLabel = document.createElement('label'); replaceAttributeSelectorLabel.innerHTML = 'Attribute'; replaceAttributeSelectorLabel.title = 'Choose the attribute to replace inside of (<ANY_VALUE> to replace in any attribute)'; let replaceAttributeSelector = document.createElement('input'); replaceAttributeSelector.setAttribute('list','awq-replace-attrib-dataset'); replaceAttributeSelector.className = 'awq-right-align-placeholder'; replaceAttributeSelector.placeholder='▼'; replaceAttributeSelector.type = 'text'; replaceAttributeSelector.title = replaceAttributeSelectorLabel.title; replaceAttributeSelector.onfocus = function() {this.select();}; let replaceAttributeSelectorDataset = document.createElement('datalist'); replaceAttributeSelectorDataset.id = 'awq-replace-attrib-dataset'; replaceAttributeSelectorDataset.appendChild(anyOption); Object.keys(collectedAttributes).forEach(function(key,index) { // Add all attributes from queue let attribOption = document.createElement('option'); attribOption.value = key; replaceAttributeSelectorDataset.appendChild(attribOption); }); let replaceValueSelectorLabel = document.createElement('label'); replaceValueSelectorLabel.innerHTML = 'Old value'; replaceValueSelectorLabel.style.display = 'block'; replaceValueSelectorLabel.title = 'Find this value and replace it with the one below (<ANY_VALUE> to replace anything)'; let replaceValueSelector = document.createElement('input'); replaceValueSelector.setAttribute('list','awq-replace-value-dataset'); replaceValueSelector.className = 'awq-right-align-placeholder'; replaceValueSelector.placeholder='▼'; replaceValueSelector.type = 'text'; replaceValueSelector.title = replaceValueSelectorLabel.title; replaceValueSelector.onfocus = function() {this.select();}; let replaceValueSelectorDataset = document.createElement('datalist'); replaceValueSelectorDataset.id = 'awq-replace-value-dataset'; let replaceContainer = document.createElement('span'); let replaceNewValueSelectorLabel = document.createElement('label'); replaceNewValueSelectorLabel.innerHTML = 'New value'; replaceNewValueSelectorLabel.style.display = 'block'; let replaceNewValueSelector = document.createElement('input'); replaceNewValueSelector.setAttribute('list','awq-replace-new-value-dataset'); replaceNewValueSelector.className = 'awq-right-align-placeholder'; replaceNewValueSelector.placeholder='▼'; replaceNewValueSelector.type = 'text'; replaceNewValueSelector.title = 'The value to replace with'; replaceNewValueSelector.onfocus = function() {this.select();}; let replaceNewValueSelectorDataset = document.createElement('datalist'); replaceNewValueSelectorDataset.id = 'awq-replace-new-value-dataset'; let replaceButton = document.createElement('button'); replaceButton.innerHTML = "Replace"; replaceContainer.appendChild(replaceLabel); replaceContainer.appendChild(replaceAttributeSelectorLabel); replaceContainer.appendChild(replaceAttributeSelector); replaceContainer.appendChild(replaceAttributeSelectorDataset); replaceContainer.appendChild(replaceValueSelectorLabel); replaceContainer.appendChild(replaceValueSelector); replaceContainer.appendChild(replaceValueSelectorDataset); replaceContainer.appendChild(replaceNewValueSelectorLabel); replaceContainer.appendChild(replaceNewValueSelector); replaceContainer.appendChild(replaceNewValueSelectorDataset); replaceContainer.appendChild(replaceButton); dialogBody.appendChild(replaceContainer); function updateReplaceValueSelectorDataset() { let foundValues = collectedAttributes[replaceAttributeSelector.value]; replaceValueSelectorDataset.innerHTML = ''; replaceValueSelectorDataset.appendChild(anyOption.cloneNode()); if(foundValues) { replaceValueSelectorDataset.innerHTML = ''; replaceValueSelectorDataset.appendChild(anyOption.cloneNode()); Object.keys(foundValues).forEach(function(key,index) { // Add all possible values for currently selected attribute let valueOption = document.createElement('option'); valueOption.value = key; replaceValueSelectorDataset.appendChild(valueOption); }); } else { Object.keys(collectedAttributes).forEach(function(key,index) { let attrib = collectedAttributes[key]; Object.keys(attrib).forEach(function(innerKey,innerIndex) { let valueOption = document.createElement('option'); valueOption.value = innerKey; replaceValueSelectorDataset.appendChild(valueOption); }); }); } } function updateReplaceNewValueSelectorDataset() { let matchingValues = []; // Any components that has the option we are trying to replace? componentOptions.forEach(arr => { if(arr.includes(replaceValueSelector.value)) matchingValues.push(arr) }); // If not add all their options if(matchingValues.length == 0) { matchingValues = [...componentOptions]; } // Remove duplicates and replace dataset options replaceNewValueSelectorDataset.innerHTML = ''; [...new Set(matchingValues.flat())].forEach(el => { let valueOption = document.createElement('option'); valueOption.value = el; replaceNewValueSelectorDataset.appendChild(valueOption); }); } updateReplaceNewValueSelectorDataset(); replaceAttributeSelector.onchange = function() { updateReplaceValueSelectorDataset(); } replaceValueSelector.onchange = function() { updateReplaceNewValueSelectorDataset(); } updateReplaceValueSelectorDataset(); // Handle clicking the search and replace button replaceButton.onclick = function() { let attributeValue = replaceAttributeSelector.value let anyAttribute = attributeValue == c_any_value; let oldValue = replaceValueSelector.value; let anyOldValue = oldValue == c_any_value; let currentQueue = conf.currentQueue; let newValue = replaceNewValueSelector.value; Object.keys(currentQueue).forEach(function(key,index) { // Loop queue entries let queueElentry = JSON.parse(currentQueue[key].value); if(anyAttribute) { Object.keys(queueElentry).forEach(function(keyInner,indexInner) { // Loop queue entry attributes if(anyOldValue) { // Replace everything with the new value (why are you doing this?) if(newValue != queueElentry[keyInner]) awqLog(`replaceButton: updated queue item ${key} attribute ${keyInner} to ${newValue}`); queueElentry[keyInner] = newValue; } else { // Search and replace in all attributes let replacedValue = queueElentry[keyInner].replaceAll ? queueElentry[keyInner].replaceAll(oldValue,newValue) : queueElentry[keyInner]; if(replacedValue != queueElentry[keyInner]) awqLog(`replaceButton: updated queue item ${key} attribute ${keyInner} to ${replacedValue}`); queueElentry[keyInner] = replacedValue; } }); } else { if(anyOldValue) { // Replace all values for this attribute if(newValue != queueElentry[attributeValue]) awqLog(`replaceButton: updated queue item ${key} attribute ${attributeValue} to ${newValue}`); queueElentry[attributeValue] = newValue; } else { // Replace string in specific attribute let replacedValue = queueElentry[attributeValue].replaceAll(oldValue,newValue); if(replacedValue != queueElentry[attributeValue]) awqLog(`replaceButton: updated queue item ${key} attribute ${attributeValue} to ${replacedValue}`); queueElentry[attributeValue] = replacedValue; } } let newJson = JSON.stringify(queueElentry); currentQueue[key].value = JSON.stringify(queueElentry); }); // Update state let queueElems = conf.ui.queueContainer.querySelectorAll('.AWQ-item-JSON'); for(let i=0; i < currentQueue.length; i++) { queueElems[i].value = currentQueue[i].value; } updateQueueState(); } // *** Search & Replace *** STOP document.body.appendChild(dialog); // Customize behaviour of the opacity button to show immediate effect let opacityButton = document.getElementById('awq-ss-buttonOpacity'); opacityButton.type = 'range'; opacityButton.min = 0; opacityButton.max = 1; opacityButton.step = 0.1; opacityButton.onchange = function() { document.querySelectorAll('.awq-hover-button').forEach(function(elem) { conf.scriptSettings.buttonOpacity.value = opacityButton.value; elem.style.opacity = conf.scriptSettings.buttonOpacity.value; }); }; } function toggleProcessButton(p_set_processing) { awqLog('toggleProcessButton:' + p_set_processing); let pb = conf.ui.processButton; let undefinedInput = typeof p_set_processing == 'undefined'; if(undefinedInput) { toggleProcessButton(!conf.commonData.processing); } else if (p_set_processing) { awqLogPublishMsg('Processing <b>started</b>'); conf.commonData.processing = true; pb.style.background = 'green'; pb.innerHTML = '⏸︎ '; let cogElem = document.createElement('div') cogElem.innerHTML = '⚙️'; cogElem.style.display = 'inline-block'; pb.appendChild(cogElem); //cogElem.animate([{ transform: 'rotate(0)' },{transform: 'rotate(360deg)'}], {duration: 1000,iterations: Infinity}); executeAllNewTasks(); } else { awqLogPublishMsg('Processing <b>ended</b>'); conf.commonData.processing = false; conf.commonData.previousTaskStartTime = null; pb.style.background = null; pb.innerHTML = c_processButtonText; } } function updateQueueState() { let queueItems = conf.ui.queueContainer.getElementsByTagName('div'); awqLog('updateQueueState: old length:'+conf.currentQueue.length + ' new length:'+queueItems.length); let newArray = []; for(let i = 0; i < queueItems.length; i++) { let newRowObject = {}; newRowObject.rowid = i; newRowObject.type = queueItems[i].querySelector('.AWQ-item-type').value; newRowObject.quantity = queueItems[i].querySelector('.AWQ-item-quantity').value; newRowObject.value = queueItems[i].querySelector('.AWQ-item-JSON').value; newArray.push(newRowObject); } conf.currentQueue = newArray; if(conf.scriptSettings.rememberQueue.value) { awqLog('updateQueueState: Saving current queue state '+conf.currentQueue.length); localStorage.awqCurrentQueue = JSON.stringify(conf.currentQueue); } else { awqLog('updateQueueState: Cleared current queue state'); localStorage.removeItem("awqCurrentQueue"); } } let stuckProcessingCounter = 0; function updateStatus() { let previousType = conf.commonData.activeType; let previousWorking = conf.commonData.working; let workingOnI2I = conf.i2i.controls.skipButton.el.getAttribute('style') == 'display: block;'; let workingOnT2I = conf.t2i.controls.skipButton.el.getAttribute('style') == 'display: block;'; let workingOnExt = conf.ext.controls.loadingElement.el.innerHTML.length > 0; // Hide all buttons by default, and then show the right one conf.ui.addToQueueButton.style.display = 'none' conf.ui.addToQueueButtonA1.style.display = 'none' conf.ui.addToQueueButtonA2.style.display = 'none' conf.ui.addToQueueButtonA3.style.display = 'none' conf.ui.unsupportedButton.style.display = 'none' if(conf.commonData.i2iContainer.el.style.display !== 'none') { conf.commonData.activeType = 'i2i'; } else if(conf.commonData.t2iContainer.el.style.display !== 'none') { conf.commonData.activeType = 't2i'; } else if(conf.commonData.extContainer.el.style.display !== 'none') { conf.commonData.activeType = 'ext'; } else if(conf.extensions.iBrowser && conf.extensions.iBrowser.guiElems.iBrowserContainer.el.style.display !== 'none') { conf.commonData.activeType = 'iBrowser'; } else { conf.commonData.activeType = 'other'; conf.ui.unsupportedButton.style.display = 'block'; } if(conf.commonData.activeType != 'other') { conf.ui.addToQueueButton.style.display = 'block'; conf.ui.addToQueueButtonA1.style.display = 'block'; conf.ui.addToQueueButtonA2.style.display = 'block'; conf.ui.addToQueueButtonA3.style.display = 'block'; } let typeChanged = conf.commonData.activeType !== previousType ? true : false; let workingChanged = conf.commonData.working !== previousWorking ? true : false; if(typeChanged) awqLog('updateStatus: active type changed to:' + conf.commonData.activeType); if(workingChanged) awqLog('updateStatus: Work status changed to:' + conf.commonData.working); // If no work is being done for a while disable queue stuckProcessingCounter = !conf.commonData.waiting && !workingChanged && !conf.commonData.working && conf.commonData.processing ? stuckProcessingCounter + 1 : 0; if(stuckProcessingCounter > 30) { awqLog('updateStatus: stuck in processing queue status? Disabling queue processing'); toggleProcessButton(false); stuckProcessingCounter = 0; playWorkCompleteSound(); } } async function executeNewTask() { awqLog('executeNewTask: working='+conf.commonData.working + ' processing=' + conf.commonData.processing); if(conf.commonData.working) return; // Already working on task if(!conf.commonData.processing) return; // Not proicessing queue if(conf.commonData.previousTaskStartTime) { let timeSpent = Date.now() - conf.commonData.previousTaskStartTime; awqLogPublishMsg(`Completed work on queue item after ${Math.floor(timeSpent/1000/60)} minutes ${Math.round((timeSpent-Math.floor(timeSpent/60000)*60000)/1000)} seconds `); } let queueItems = conf.ui.queueContainer.getElementsByTagName('div'); for(let i = 0; i < queueItems.length; i++) { let itemQuantity = queueItems[i].querySelector('.AWQ-item-quantity'); let itemType = queueItems[i].querySelector('.AWQ-item-type').value; if(itemQuantity.value > 0) { awqLog('executeNewTask: found next work item with index ' + i + ', quantity ' + itemQuantity.value + ' and type ' + itemType); await loadJson(queueItems[i].querySelector('.AWQ-item-JSON').value); await clickStartButton(itemType); conf.commonData.working = true; itemQuantity.value = itemQuantity.value - 1; itemQuantity.onchange(); awqLogPublishMsg(`Started working on ${itemType} queue item ${i+1} (${itemQuantity.value} more to go) `); conf.commonData.previousTaskStartTime = Date.now(); await waitForTaskToComplete(itemType); return; } } conf.commonData.previousTaskStartTime = null; awqLog('executeNewTask: No more tasks found'); toggleProcessButton(false); // No more tasks to process playWorkCompleteSound(); } async function executeAllNewTasks() { while(conf.commonData.processing) { await executeNewTask(); } } function playWorkCompleteSound() { if(conf.scriptSettings.notificationSound.value) c_audio_base64.play();} function editSetting() { let settingStorage = conf.ui.settingsStorage; let settingIndex = settingStorage.selectedIndex; let settingOption = settingStorage.options[settingIndex]; let settingKey = settingOption.innerHTML; if(settingKey == c_defaultTextStoredSettings) return; awqLog('editSettings: index'+settingIndex); let editContainer = document.createElement('div'); editContainer.style.cssText = 'position: fixed;bottom: 0;left: 0;width: 100vw;height: 100vh;background:black;z-index: 9999;'; let txtInput = document.createElement('input'); txtInput.style.cssText = 'width: 100vw;height: 10vh;'; txtInput.title = "Name of the settins set (do not remove the prefix)"; editContainer.appendChild(txtInput); let txtArea = document.createElement('textarea'); txtArea.style.cssText = 'width: 100vw;height: 80vh;'; txtArea.title = 'The set of settings i JSON format (Edit the value inside the "" but leave structure intact, an entire propertey: "id":"value" can also be removed if you do not want this setting set to make any changes to that setting)'; editContainer.appendChild(txtArea); let editButton = document.createElement('button'); editButton.style.cssText = 'width: 50vw;height: 10vh;'; editButton.innerHTML = 'OK'; editButton.title = "Save changes"; editContainer.appendChild(editButton); let resetButton = document.createElement('button'); resetButton.style.cssText = 'width: 50vw;height: 10vh;'; resetButton.innerHTML = 'Reset'; resetButton.title = "Revert changes"; resetButton.onclick = function() { txtArea.value = conf.ui.settingsStorage.options[settingIndex].value; txtInput.value = conf.ui.settingsStorage.options[settingIndex].text; } editContainer.appendChild(resetButton); resetButton.onclick(); document.body.style.overflow = 'hidden'; document.body.appendChild(editContainer); editButton.onclick = function() { // Validate if(txtInput.value.length < 1) { alert('Name is missing'); return; } if(!isJsonString(txtArea.value)) { alert('Value is invalid JSON'); return; } if(!['t2i-','i2i-','ext-'].includes(txtInput.value.substr(0,4))) { alert('Name does not have valid prefix (t2i-, i2i-, ext-)'); return; } // Remove overlay document.body.style.overflow = 'scroll'; document.body.removeChild(editContainer); // Update data and refresh UI awqLog('editSettings: updating '+ settingKey + (settingKey == txtInput.value ? '' : ' to ' + txtInput.value)); delete conf.savedSetting[settingKey]; conf.savedSetting[txtInput.value] = txtArea.value; localStorage.awqSavedSetting = JSON.stringify(conf.savedSetting); refreshSettings(); // Select option again let optionToSelect = Array.from(settingStorage.options).find(item => item.text ===txtInput.value); optionToSelect.selected = true; }; } function saveSettings() { if(conf.ui.settingName.value.length < 1) {alert('Missing name'); return;} if(conf.savedSetting.hasOwnProperty(conf.ui.settingName.value)) {alert('Duplicate name'); return;} let settingSetName = conf.commonData.activeType + '-'+ conf.ui.settingName.value; conf.savedSetting[settingSetName] = getValueJSON(); localStorage.awqSavedSetting = JSON.stringify(conf.savedSetting); awqLogPublishMsg(`Saved new setting set ` + settingSetName); refreshSettings(); } function refreshSettings() { awqLog('refreshSettings: saved settings:'+Object.keys(conf.savedSetting).length); conf.ui.settingName.value = ""; conf.ui.settingsStorage.innerHTML = ""; for (let prop in conf.savedSetting) { let newOption = document.createElement('option'); newOption.innerHTML = prop; newOption.value = conf.savedSetting[prop] conf.ui.settingsStorage.appendChild(newOption); } if(Object.keys(conf.savedSetting).length < 1) { let blankOption = document.createElement('option'); blankOption.innerHTML = c_defaultTextStoredSettings; blankOption.value = ""; conf.ui.settingsStorage.appendChild(blankOption); } } async function loadSetting() { if(conf.ui.settingsStorage.value.length < 1) return; let itemName = conf.ui.settingsStorage.options[conf.ui.settingsStorage.selectedIndex].text; let itemType = itemName.split('-')[0]; awqLog('loadSetting: ' + itemName); await loadJson(conf.ui.settingsStorage.value); } function clearSetting() { let ss = conf.ui.settingsStorage; if(ss.value.length < 1) return; awqLogPublishMsg(`Removed setting ` + ss.options[ss.selectedIndex].innerHTML); delete conf.savedSetting[ss.options[ss.selectedIndex].innerHTML]; ss.removeChild(ss.options[ss.selectedIndex]); localStorage.awqSavedSetting = JSON.stringify(conf.savedSetting); if(ss.value.length < 1) refreshSettings(); } function clickStartButton(p_type) { const c_max_time_to_wait = 100; let targetButton = conf[conf.commonData.activeType].controls.genrateButton.el; awqLog(`clickStartButton: working ${conf.commonData.working} waiting ${conf.commonData.working} type ${p_type}`); if(conf.commonData.working || conf.commonData.waiting) return; targetButton.click(); conf.commonData.waiting = true; return new Promise(resolve => { let retryCount = 0; let waitForSwitchInterval = setInterval(function() { retryCount++; if(retryCount >= c_max_time_to_wait) { targetButton.click(); retryCount = 0; awqLog(`Work has not started after ${c_max_time_to_wait/10} seconds, clicked again`); } if(!webUICurrentyWorkingOn(p_type)) return; conf.commonData.waiting = false; awqLog('clickStartButton: work has started'); clearInterval(waitForSwitchInterval); resolve(); },c_wait_tick_duration); }); } function switchTabAndWait(p_type) { if(p_type == conf.commonData.activeType) return; awqLog('switchTabAndWait: ' + p_type); conf.shadowDOM.root.querySelector(conf[p_type].controls.tabButton.sel).click(); // Using .el doesn't work conf.commonData.waiting = true; return new Promise(resolve => { let startingTab = conf.commonData.activeType; let waitForSwitchInterval = setInterval(function() { if(conf.commonData.activeType !== p_type) return; conf.commonData.waiting = false; awqLogPublishMsg(`Switched active tab from ${startingTab} to ${conf.commonData.activeType}`); clearInterval(waitForSwitchInterval); resolve(); },c_wait_tick_duration); }); } function switchTabAndWaitUntilSwitched(p_targetTabName, p_tabConfig) { awqLog('switchTabAndWaitUntilSwitched: p_target=' + p_targetTabName + ' p_config=' + p_tabConfig); let targetTabConf = p_tabConfig.filter( (elem) => { return elem.name == p_targetTabName })[0]; function correctTabVisible() { return conf.shadowDOM.root.querySelector(targetTabConf.containerSel).style.display == 'none' ? false : true; } if(correctTabVisible()) return; conf.shadowDOM.root.querySelector(targetTabConf.buttonSel).click(); conf.commonData.waiting = true; return new Promise(resolve => { let waitForSwitchInterval = setInterval(function() { if(!correctTabVisible()) return; conf.commonData.waiting = false; awqLog('switchTabAndWaitUntilSwitched: switch complete'); clearInterval(waitForSwitchInterval); resolve(); },c_wait_tick_duration); }); } function forceGradioUIUpdate() { const someCheckboxInputSelector = '#txt2img_subseed_show input'; document.querySelector(someCheckboxInputSelector).click(); document.querySelector(someCheckboxInputSelector).click(); } function webUICurrentyWorkingOn(p_itemType) { if(p_itemType == 'i2i') { return conf.i2i.controls.skipButton.el.getAttribute('style') == 'display: block;'; } else if (p_itemType == 't2i') { return conf.t2i.controls.skipButton.el.getAttribute('style') == 'display: block;'; } else { return conf.ext.controls.loadingElement.el.innerHTML.length > 0; } } function waitForTaskToComplete(p_itemType) { awqLog(`waitForTaskToComplete: Waiting to complete work for ${p_itemType}`); conf.commonData.waiting = true; return new Promise(resolve => { let waitForCompleteInterval = setInterval(function() { if(webUICurrentyWorkingOn(p_itemType)) return; clearInterval(waitForCompleteInterval); awqLog(`Work is complete for ${p_itemType}`); conf.commonData.waiting = false; conf.commonData.working = false; resolve(); },c_wait_tick_duration); }); } function filterPrompt(p_prompt_text, p_neg) { let newPromptText = p_prompt_text; let promptFilter = conf.scriptSettings.promptFilter.value.length > 0 ? JSON.parse(conf.scriptSettings.promptFilter.value) : []; for(let i=0; i < promptFilter.length; i++) { if(!promptFilter[i].hasOwnProperty('pattern') || !promptFilter[i].hasOwnProperty('flags') || !promptFilter[i].hasOwnProperty('replace')) continue; let regEx = new RegExp(promptFilter[i].pattern, promptFilter[i].flags); let tmpNewPromptText = newPromptText.replace(regEx, promptFilter[i].replace); if(tmpNewPromptText !== newPromptText) { let changesCount = levenshteinDist(newPromptText, tmpNewPromptText); awqLogPublishMsg(`Filtered ${p_neg ? '(neg)' : ''}prompt with filter (${promptFilter[i].desc}), ${changesCount} char changes`); awqLog(`Filtered from:<pre>${newPromptText}</pre>to:<pre>${tmpNewPromptText}</pre>`); newPromptText = tmpNewPromptText; } } return newPromptText; } function exportImport() { let exportJSON = JSON.stringify({ savedSetting: conf.savedSetting, currentQueue: conf.currentQueue, scriptSettings: JSON.parse(localStorage.awqScriptSettings), // Use localstorage since it has filtered everything except values }); let exportImportInput = document.getElementById('import-export-data-input'); let importJSON = exportImportInput.value; if(importJSON.length < 1) { awqLogPublishMsg(`Exported script data`); exportImportInput.value = exportJSON; exportImportInput.focus(); exportImportInput.select(); return; } if(!isJsonString(importJSON)) { alert(`There is something wrong with the import data provided`); return; } else if(exportJSON == importJSON) { alert(`The input data is the same as the current script data`); } else { awqLog('Data has changed'); let parsedImportJSON = JSON.parse(importJSON); conf.savedSetting = parsedImportJSON.savedSetting; conf.currentQueue = parsedImportJSON.currentQueue; loadScriptSettings(parsedImportJSON.scriptSettings); // Load with loadScriptSettings to only replace values localStorage.awqScriptSettings = JSON.stringify(parsedImportJSON.scriptSettings); localStorage.awqSavedSetting = JSON.stringify(conf.savedSetting); localStorage.awqCurrentQueue = JSON.stringify(conf.currentQueue); location.reload(); } } function isJsonString(str) { try { JSON.parse(str); } catch (e) { return false; } return true; } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function stringDiffCount(p_str1, p_str2) { let count = 0; for(let i = 0; i < p_str1.length; i++){ if(p_str1[i] === p_str2[i]){ continue; }; count++; }; return count; }; function getCallStack() { try { throw new Error(); } catch (err) { return err.stack.replace(/^getCallStack.*\n/, ''); } } function levenshteinDist(s1, s2) { if (s1 === s2) { return 0; } else { var s1_len = s1.length, s2_len = s2.length; if (s1_len && s2_len) { var i1 = 0, i2 = 0, a, b, c, c2, row = []; while (i1 < s1_len) { row[i1] = ++i1; } while (i2 < s2_len) { c2 = s2.charCodeAt(i2); a = i2; ++i2; b = i2; for (i1 = 0; i1 < s1_len; ++i1) { c = a + (s1.charCodeAt(i1) === c2 ? 0 : 1); a = row[i1]; b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c); row[i1] = b; } } return b; } else { return s1_len + s2_len; } } }; function getValueJSON(p_type) { let type = p_type || conf.commonData.activeType; awqLog('getValueJSON: type=' + type); let valueJSON = {type:type}; if(type == 'ext') { // Needs special saving since it's not an input but a tab switch valueJSON.extrasMode = conf.ext.controls.extrasMode.filter((elem) => { return conf.shadowDOM.root.querySelector(elem.containerSel).style.display == 'none' ? false : true })[0].name; valueJSON.extrasResizeMode = conf.ext.controls.extrasResizeMode.filter((elem) => { return conf.shadowDOM.root.querySelector(elem.containerSel).style.display == 'none' ? false : true })[0].name; } else if(type == 'i2i') { // Needs special saving since it's not an input but a tab switch valueJSON.i2iMode = conf.i2i.controls.i2iMode.filter((elem) => { return conf.shadowDOM.root.querySelector(elem.containerSel).style.display == 'none' ? false : true })[0].name; } else if(type == 'iBrowser') { return conf.extensions.iBrowser.functions.getValueJSON(); } for (let prop in conf[type]) { if(prop !== 'controls') { try { if(conf[type][prop].gradEl) { valueJSON[prop] = getGradVal(conf[type][prop].gradEl); } else if(conf[type][prop].el.classList.contains('input-accordion')) { // "input-accordion" (checkbox alternative) valueJSON[prop] = conf[type][prop].el.classList.contains('input-accordion-open') ? true : false; } else if(conf[type][prop].el.type == 'fieldset') { // Radio buttons valueJSON[prop] = conf[type][prop].el.querySelector('input:checked').value; } else if(conf[type][prop].el.type == 'checkbox') { valueJSON[prop] = conf[type][prop].el.checked; } else { // Inputs, Textarea valueJSON[prop] = conf[type][prop].el.value; if(prop == 'prompt') valueJSON[prop] = filterPrompt(valueJSON[prop]); if(prop == 'negPrompt' && conf.scriptSettings.promptFilterNegative.value) valueJSON[prop] = filterPrompt(valueJSON[prop], true); } } catch(e) { awqLogPublishError(`Failed to retrieve settings for ${type} item ${prop} with error ${e.message}: <pre style="margin: 0;">${e.stack}</pre>`); } } } valueJSON.sdModelCheckpoint = getGradVal(conf.commonData.sdModelCheckpoint.gradEl); return JSON.stringify(valueJSON); } async function loadJson(p_json) { let inputJSONObject = JSON.parse(p_json); let type = inputJSONObject.type ? inputJSONObject.type : conf.commonData.activeType; let oldData = JSON.parse(getValueJSON(type)); let waitForThisContainer; awqLog('loadJson: ' + type); let currentModel = getGradVal(conf.commonData.sdModelCheckpoint.gradEl); if(currentModel == inputJSONObject.sdModelCheckpoint) { awqLog('loadJson: Correct model already loaded: ' + currentModel);// No action needed } else if(conf.commonData.sdModelCheckpoint.gradEl.props.choices.includes(inputJSONObject.sdModelCheckpoint)) { // Check if model exists awqLog('loadJson: Trying to load model: ' + inputJSONObject.sdModelCheckpoint); setGradVal(conf.commonData.sdModelCheckpoint.gradEl, inputJSONObject.sdModelCheckpoint); setCheckpointWithPost(inputJSONObject.sdModelCheckpoint); // Only setting gradio config no longer works? } else { awqLogPublishError(`Model ${inputJSONObject.sdModelCheckpoint} was not found, using current model ${currentModel}`); } if(conf.commonData.activeType != inputJSONObject.type) await switchTabAndWait(inputJSONObject.type); // Switch tab? if(inputJSONObject.extrasResizeMode) await switchTabAndWaitUntilSwitched(inputJSONObject.extrasResizeMode, conf.ext.controls.extrasResizeMode); // Needs special loading since it's not an input but a tab switch if(inputJSONObject.extrasMode) await switchTabAndWaitUntilSwitched(inputJSONObject.extrasMode, conf.ext.controls.extrasMode); // Needs special loading since it's not an input but a tab switch if(inputJSONObject.i2iMode) await switchTabAndWaitUntilSwitched(inputJSONObject.i2iMode, conf.i2i.controls.i2iMode); // Needs special loading since it's not an input but a tab switch let loadOutput = 'loadJson: loaded: '; for (let prop in inputJSONObject) { let triggerOnBaseElem = true; if(['type','extrasMode','extrasResizeMode','sdModelCheckpoint', 'i2iMode'].includes(prop)) continue; try { if(oldData[prop] != inputJSONObject[prop]) loadOutput += `${prop}:${oldData[prop]}-->${inputJSONObject[prop]} | `; if(conf[type][prop].el) { if(conf[type][prop].el.type == 'fieldset') { triggerOnBaseElem = false; // No need to trigger this on base element conf[type][prop].el.querySelector('[value="' + inputJSONObject[prop] + '"]').checked = true; triggerChange(conf[type][prop].el.querySelector('[value="' + inputJSONObject[prop] + '"]')); } else if(conf[type][prop].el.classList.contains('input-accordion')) { // "input-accordion" (checkbox alternative) let currentValue = conf[type][prop].el.classList.contains('input-accordion-open') ? true : false; if(inputJSONObject[prop] != currentValue) { conf[type][prop].el.querySelector('.label-wrap').click(); } } else if(conf[type][prop].el.type == 'select-one') { // Select if(conf[type][prop].el.checked == inputJSONObject[prop]) triggerOnBaseElem = false; // Not needed conf[type][prop].el.value = inputJSONObject[prop]; } else if(conf[type][prop].el.type == 'checkbox') { if(conf[type][prop].el.checked == inputJSONObject[prop]) triggerOnBaseElem = false; // Prevent checbox getting toggled conf[type][prop].el.checked = inputJSONObject[prop]; } else { // Input, Textarea if(conf[type][prop].el.value == inputJSONObject[prop]) triggerOnBaseElem = false; // Fixes svelte error conf[type][prop].el.value = inputJSONObject[prop]; } if(conf[type][prop].el2) { let triggerForSel2 = conf[type][prop].sel2.value != inputJSONObject[prop]; conf[type][prop].el2.value = inputJSONObject[prop]; if(triggerForSel2) triggerChange(conf[type][prop].el2); } } if(conf[type][prop].gradEl) { setGradVal(conf[type][prop].gradEl, inputJSONObject[prop]); triggerOnBaseElem = false; } if(triggerOnBaseElem) triggerChange(conf[type][prop].el); } catch(e) { awqLogPublishError(`Failed to load settings for ${type} item ${prop} with error ${e.message}: <pre style="margin: 0;">${e.stack}</pre>`); } } awqLog(loadOutput.replace(/\|\s$/, '')); forceGradioUIUpdate(); } function waitForElm(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } function setCheckpointWithPost(p_target_cp) { awqLog('setCheckpointWithPost: '+ p_target_cp); let targetCheckpoint = p_target_cp.replace('/','//').replace('\\','\\\\'); // Try to find fn_index for the switch checkpoint "function" let checkPointGradioElemId = conf.commonData.sdModelCheckpoint.gradEl.id; let fnIndex = window.gradio_config.dependencies.filter(comp => comp.inputs[0] == checkPointGradioElemId); fnIndex = fnIndex ? window.gradio_config.dependencies.indexOf(fnIndex[0]) : null; if(fnIndex) { awqLog('setCheckpointWithPost: found fn_index '+ fnIndex); } else { awqLogPublishError('setCheckpointWithPost: failed to find fn_index for model change'); return; } fetch("/run/predict", { method: "POST", headers: {"Content-Type": "application/json"}, redirect: "follow", body: `{"fn_index":${fnIndex},"data":["${targetCheckpoint}"],"event_data":null,"session_hash":"trlwn215an"}` }).then(response => { awqLog(`setCheckpointWithPost: repsonse: ${response.status}-${response.statusText}: ${JSON.stringify(response.json())}`); }).catch(error => { awqLog(`setCheckpointWithPost: error: ${JSON.stringify(error)}`); });; } function triggerChange(p_elem) { let evt = document.createEvent("HTMLEvents"); evt.initEvent("change", false, true); // Needed for script to update subsection p_elem.dispatchEvent(evt); evt = document.createEvent("HTMLEvents"); evt.initEvent("input", false, true); // Needded for webui to register changed settings p_elem.dispatchEvent(evt); } function findGradioComponentState(p_elem_id) { return window.gradio_config.components.filter(comp => comp.props.elem_id == p_elem_id); } function findGradioComponentStateByLabel(p_elem_label) { return window.gradio_config.components.filter(comp => comp.props.label == p_elem_label); } function getGradVal(p_grad_comp) { return p_grad_comp.props.value; } function setGradVal(p_grad_comp,p_val) { p_grad_comp.props.value = p_val; } })();