From e287df1320b14079af2171b6093dbc365257a135 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 19 Oct 2022 21:34:40 +0530 Subject: [PATCH] Allow loading UI plugins from a /plugins/ URL path, which loads files ending with .plugin.js inside the plugins/ui folder --- ui/index.html | 1 + ui/media/js/main.js | 52 +------------------------------------ ui/media/js/plugins.js | 58 ++++++++++-------------------------------- ui/server.py | 17 ++++++++++++- 4 files changed, 31 insertions(+), 97 deletions(-) diff --git a/ui/index.html b/ui/index.html index 07a1876c..0fcf28ca 100644 --- a/ui/index.html +++ b/ui/index.html @@ -266,6 +266,7 @@ async function init() { await getAppConfig() await getModels() await initSettings() + await loadUIPlugins() setInterval(healthCheck, HEALTH_PING_INTERVAL * 1000) healthCheck() diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 609e3cbe..cb76fb35 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -369,7 +369,7 @@ function showImages(reqBody, res, outputContainer, livePreview) { let buttons = [ { text: 'Use as Input', on_click: onUseAsInputClick }, { text: 'Download', on_click: onDownloadImageClick }, - { text: 'Make Similar Images', on_click: onMakeSimilarClick }, + { text: 'Make Similar Images', on_click: onMakeSimilarClick } ] // include the plugins @@ -423,56 +423,6 @@ function onDownloadImageClick(req, img) { imgDownload.click() } -function getStartNewTaskHandler(mode) { - return function(reqBody, img) { - if (!isServerAvailable()) { - alert('The server is not available.') - return - } - const newTaskRequest = getCurrentUserRequest() - switch (mode) { - case 'img2img': - case 'img2img_X2': - newTaskRequest.reqBody = Object.assign({}, reqBody, { - num_outputs: 1, - use_cpu: useCPUField.checked, - }) - if (!newTaskRequest.reqBody.init_image || mode === 'img2img_X2') { - newTaskRequest.reqBody.sampler = 'ddim' - newTaskRequest.reqBody.prompt_strength = '0.5' - newTaskRequest.reqBody.init_image = img.src - delete newTaskRequest.reqBody.mask - } else { - newTaskRequest.reqBody.seed = 1 + newTaskRequest.reqBody.seed - } - if (mode === 'img2img_X2') { - newTaskRequest.reqBody.width = reqBody.width * 2 - newTaskRequest.reqBody.height = reqBody.height * 2 - newTaskRequest.reqBody.num_inference_steps = Math.min(100, reqBody.num_inference_steps * 2) - if (useUpscalingField.checked) { - newTaskRequest.reqBody.use_upscale = upscaleModelField.value - } else { - delete newTaskRequest.reqBody.use_upscale - } - } - break - case 'upscale': - newTaskRequest.reqBody = Object.assign({}, reqBody, { - num_outputs: 1, - //use_face_correction: 'GFPGANv1.3', - use_upscale: upscaleModelField.value, - }) - break - default: - throw new Error("Unknown upscale mode: " + mode) - } - newTaskRequest.seed = newTaskRequest.reqBody.seed - newTaskRequest.numOutputsTotal = 1 - newTaskRequest.batchCount = 1 - createTask(newTaskRequest) - } -} - function onMakeSimilarClick(req, img) { let newTaskRequest = getCurrentUserRequest() diff --git a/ui/media/js/plugins.js b/ui/media/js/plugins.js index bbbfe333..dce65e09 100644 --- a/ui/media/js/plugins.js +++ b/ui/media/js/plugins.js @@ -27,53 +27,21 @@ const PLUGINS = { IMAGE_INFO_BUTTONS: [] } +async function loadUIPlugins() { + try { + let res = await fetch('/get/ui_plugins') + if (res.status === 200) { + res = await res.json() + res.forEach(pluginPath => { + let script = document.createElement('script') + script.src = pluginPath -PLUGINS['IMAGE_INFO_BUTTONS'].push({ text: 'Double Size', on_click: getStartNewTaskHandler('img2img_X2') }) -PLUGINS['IMAGE_INFO_BUTTONS'].push({ text: 'Redo', on_click: getStartNewTaskHandler('img2img') }) -PLUGINS['IMAGE_INFO_BUTTONS'].push({ text: 'Upscale', on_click: getStartNewTaskHandler('upscale'), filter: (req, img) => !req.use_upscale }) + console.log('loading plugin', pluginPath) -function getStartNewTaskHandler(mode) { - return function(reqBody, img) { - const newTaskRequest = getCurrentUserRequest() - switch (mode) { - case 'img2img': - case 'img2img_X2': - newTaskRequest.reqBody = Object.assign({}, reqBody, { - num_outputs: 1, - use_cpu: useCPUField.checked, - }) - if (!newTaskRequest.reqBody.init_image || mode === 'img2img_X2') { - newTaskRequest.reqBody.sampler = 'ddim' - newTaskRequest.reqBody.prompt_strength = '0.5' - newTaskRequest.reqBody.init_image = img.src - delete newTaskRequest.reqBody.mask - } else { - newTaskRequest.reqBody.seed = 1 + newTaskRequest.reqBody.seed - } - if (mode === 'img2img_X2') { - newTaskRequest.reqBody.width = reqBody.width * 2 - newTaskRequest.reqBody.height = reqBody.height * 2 - newTaskRequest.reqBody.num_inference_steps = Math.min(100, reqBody.num_inference_steps * 2) - if (useUpscalingField.checked) { - newTaskRequest.reqBody.use_upscale = upscaleModelField.value - } else { - delete newTaskRequest.reqBody.use_upscale - } - } - break - case 'upscale': - newTaskRequest.reqBody = Object.assign({}, reqBody, { - num_outputs: 1, - //use_face_correction: 'GFPGANv1.3', - use_upscale: upscaleModelField.value, - }) - break - default: - throw new Error("Unknown upscale mode: " + mode) + document.head.appendChild(script) + }) } - newTaskRequest.seed = newTaskRequest.reqBody.seed - newTaskRequest.numOutputsTotal = 1 - newTaskRequest.batchCount = 1 - createTask(newTaskRequest) + } catch (e) { + console.log('error fetching plugin paths', e) } } diff --git a/ui/server.py b/ui/server.py index 48b364f1..61bc7f4d 100644 --- a/ui/server.py +++ b/ui/server.py @@ -12,6 +12,7 @@ sys.path.append(os.path.dirname(SD_UI_DIR)) CONFIG_DIR = os.path.abspath(os.path.join(SD_UI_DIR, '..', 'scripts')) MODELS_DIR = os.path.abspath(os.path.join(SD_DIR, '..', 'models')) +UI_PLUGINS_DIR = os.path.abspath(os.path.join(SD_DIR, '..', 'plugins', 'ui')) OUTPUT_DIRNAME = "Stable Diffusion UI" # in the user's home folder TASK_TTL = 15 * 60 # Discard last session's task timeout @@ -31,11 +32,15 @@ app = FastAPI() modifiers_cache = None outpath = os.path.join(os.path.expanduser("~"), OUTPUT_DIRNAME) +os.makedirs(UI_PLUGINS_DIR, exist_ok=True) + # don't show access log entries for URLs that start with the given prefix ACCESS_LOG_SUPPRESS_PATH_PREFIXES = ['/ping', '/image', '/modifier-thumbnails'] NOCACHE_HEADERS={"Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0"} -app.mount('/media', StaticFiles(directory=os.path.join(SD_UI_DIR, 'media/')), name="media") + +app.mount('/media', StaticFiles(directory=os.path.join(SD_UI_DIR, 'media')), name="media") +app.mount('/plugins', StaticFiles(directory=UI_PLUGINS_DIR), name="plugins") class SetAppConfigRequest(BaseModel): update_branch: str = "main" @@ -251,6 +256,15 @@ def getModels(): return models +def getUIPlugins(): + plugins = [] + + for file in os.listdir(UI_PLUGINS_DIR): + if file.endswith('.plugin.js'): + plugins.append(f'/plugins/{file}') + + return plugins + @app.get('/get/{key:path}') def read_web_data(key:str=None): if not key: # /get without parameters, stable-diffusion easter egg. @@ -264,6 +278,7 @@ def read_web_data(key:str=None): return JSONResponse(getModels(), headers=NOCACHE_HEADERS) elif key == 'modifiers': return FileResponse(os.path.join(SD_UI_DIR, 'modifiers.json'), headers=NOCACHE_HEADERS) elif key == 'output_dir': return JSONResponse({ 'output_dir': outpath }, headers=NOCACHE_HEADERS) + elif key == 'ui_plugins': return JSONResponse(getUIPlugins(), headers=NOCACHE_HEADERS) else: raise HTTPException(status_code=404, detail=f'Request for unknown {key}') # HTTP404 Not Found