├── .github └── workflows │ ├── publish.yml │ ├── publish_docs_to_wiki │ ├── wiki-sync-action.yml │ └── wiki_action_2 ├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE.md ├── README.md ├── build-script ├── pack-ccx.mjs └── webpack.config.js ├── deprecated-do-not-use-start_server.bat ├── deprecated-do-not-use-start_server.sh ├── deprecated-do-not-use-start_server_MacOS.sh ├── deprecated-do-not-use-update_plugin.bat ├── deprecated-do-not-use-update_plugin.sh ├── dialog_box.js ├── docs ├── Generate txt2img.gif ├── History.gif ├── Home.md ├── Pasted image 20230131191554.png ├── Pasted image 20230131192430.png ├── Pasted image 20230131195947.png ├── Pasted image 20230131200253.png ├── Pasted image 20230131201122.png ├── Pasted image 20230131202243.png ├── Pasted image 20230131202255.png ├── Pasted image 20230131202517.png ├── Pasted image 20230131202539.png ├── Pasted image 20230131202558.png ├── Pasted image 20230131202638.png ├── Pasted image 20230201161508.png ├── Pasted image 20230201161702.png ├── Pasted image 20230201161716.png ├── Pasted image 20230201161938.png ├── Pasted image 20230201163236.png ├── Pasted image 20230203191656.png ├── Viewer Tutorial.gif ├── become_backer.svg ├── heal_brush.gif ├── img2img.gif ├── inpainting.gif ├── outpainting.gif ├── profile_image │ ├── A934E4F0-7778-47E9-A395-531BFF2E61F1_1_105_c.jpeg │ └── no_profile.png ├── prompt_shortcut.gif └── prompt_shortcut_file.gif ├── enum.js ├── helper.js ├── i18n └── zh_CN │ ├── ps-plugin.json │ └── sd-official.json ├── icon ├── accept_all.png ├── accept_all.svg ├── accept_selected.png ├── accept_selected.svg ├── camera_icon.png ├── camera_icon.svg ├── chain_black.svg ├── chain_white.svg ├── discard_all.png ├── discard_all.svg ├── discard_all_border.png ├── discard_selected.png ├── discard_selected.svg ├── discard_selected_border.png ├── ftcopy.svg ├── image-search.svg ├── layer_to_selection.svg ├── move_to_canvas.svg ├── panel@1x.png ├── panel@2x.png ├── pen.svg ├── plugin@1x.png ├── plugin@2x.png ├── preview.svg ├── reselect-area.svg ├── reset_settings.png ├── reset_settings.svg ├── reset_settings2.png ├── search.svg ├── search_button.svg ├── selection-area_2.svg └── writing-icon.svg ├── index.html ├── index.js ├── install.py ├── jimp └── browser │ └── lib │ └── jimp.min.js ├── manifest.json ├── output_image.png ├── package-lock.json ├── package.json ├── presets ├── ctrlnet_inpaint.json ├── ctrlnet_inpaint_tile.json ├── ctrlnet_outpaint.json ├── default.json ├── img2img.json ├── inpaint.json └── outpaint.json ├── psapi.js ├── requirements.txt ├── scripts ├── main.py └── test.py ├── sdapi_py_re.js ├── selection.js ├── server └── python_server │ ├── global_state.py │ ├── img2imgapi.py │ ├── init_images │ └── .gitignore │ ├── metadata_to_json.py │ ├── output │ └── .gitignore │ ├── prompt_shortcut - Copy.json │ ├── prompt_shortcut.py │ ├── search.py │ ├── serverHelper.py │ └── serverMain.py ├── thumbnail.js ├── typescripts ├── @types │ ├── changedpi.d.ts │ ├── custom.d.ts │ ├── sdapi_py_re.d.ts │ └── uxp.d.ts ├── after_detailer │ ├── after_detailer.tsx │ ├── config.ts │ └── style │ │ └── after_detailer.css ├── comfyui │ ├── comfyapi.ts │ ├── comfyui.tsx │ ├── img2img_api.json │ ├── img2img_workflow.json │ ├── inpaint_api.json │ ├── inpaint_workflow.json │ ├── main_ui.tsx │ ├── native_workflows │ │ ├── IPAdapter_simple_api.json │ │ ├── IPAdapter_weighted_api.json │ │ ├── animatediff_lcm_api.json │ │ ├── animatediff_simple_api.json │ │ ├── real_time_lcm_img2img_api.json │ │ ├── real_time_lcm_sketching_api.json │ │ ├── real_time_lcm_txt2img_api.json │ │ ├── sdxl_turbo_txt2img_api.json │ │ └── zoom_out_api.json │ ├── txt2img_api.json │ ├── txt2img_workflow.json │ └── util.ts ├── controlnet │ ├── ControlNetTab.tsx │ ├── ControlNetUnit.tsx │ ├── entry.ts │ ├── main.tsx │ ├── store.ts │ └── util.tsx ├── entry.ts ├── extra_page │ └── extra_page.tsx ├── globalstore.ts ├── history │ └── history.tsx ├── image_search │ └── image_search.tsx ├── lexical │ └── lexical.tsx ├── locale │ ├── locale-for-old-html.ts │ └── locale.ts ├── main │ └── astore.ts ├── multiTextarea.tsx ├── one_button_prompt │ └── one_button_prompt.tsx ├── preset │ ├── preset.tsx │ └── shared_ui_preset.ts ├── sam │ └── sam.tsx ├── sd_tab │ ├── sd_tab.tsx │ └── util.ts ├── session │ ├── generate.tsx │ ├── modes.ts │ ├── progress.ts │ ├── session.ts │ ├── session_store.ts │ └── style │ │ └── generate.css ├── settings │ ├── settings.tsx │ └── vae.tsx ├── stores.ts ├── tool_bar │ ├── style │ │ └── tool_bar.css │ └── tool_bar.tsx ├── tsconfig.json ├── ultimate_sd_upscaler │ ├── config.ts │ ├── scripts.tsx │ └── ultimate_sd_upscaler.tsx ├── util │ ├── collapsible.tsx │ ├── elements.tsx │ ├── errorBoundary.tsx │ ├── grid.tsx │ ├── logger.ts │ ├── oldSystem.tsx │ └── ts │ │ ├── api.ts │ │ ├── document.ts │ │ ├── enum.ts │ │ ├── general.ts │ │ ├── io.ts │ │ ├── layer.ts │ │ ├── sdapi.ts │ │ ├── selection.ts │ │ └── ui_ts.ts └── viewer │ ├── preview.tsx │ ├── style │ └── preview.css │ ├── viewer.tsx │ └── viewer_util.ts └── utility ├── api.js ├── dummy.js ├── general.js ├── html_manip.js ├── io.js ├── layer.js ├── notification.js ├── online_data.json ├── presets └── controlnet_preset.js ├── sampler.js ├── sd_scripts └── horde.js ├── sdapi ├── config.js ├── horde_native.js ├── options.js ├── prompt_shortcut.js └── python_replacement.js ├── session.js ├── tab ├── image_search_tab.js └── settings.js └── tips.js /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish ccx and make tag 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tag_name: 7 | description: 'tag name' 8 | required: true 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | 17 | - name: Create Release Asset 18 | shell: bash 19 | run: | 20 | cd $GITHUB_WORKSPACE 21 | npm i 22 | npm run publish 23 | node build-script/pack-ccx.mjs --version ${{ github.event.inputs.tag_name }} 24 | 25 | - name: Create Release 26 | id: create_release 27 | uses: actions/create-release@v1 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | with: 31 | tag_name: v${{ github.event.inputs.tag_name }} 32 | release_name: v${{ github.event.inputs.tag_name }} 33 | draft: true 34 | prerelease: false 35 | 36 | - name: Upload ZIP 37 | uses: actions/upload-release-asset@v1 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | with: 41 | upload_url: ${{ steps.create_release.outputs.upload_url }} 42 | asset_path: ./Auto.Photoshop.SD.plugin_v${{ github.event.inputs.tag_name }}.zip 43 | asset_name: Auto.Photoshop.SD.plugin_v${{ github.event.inputs.tag_name }}.zip 44 | asset_content_type: application/zip 45 | 46 | - name: Upload CCX 47 | uses: actions/upload-release-asset@v1 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | with: 51 | upload_url: ${{ steps.create_release.outputs.upload_url }} 52 | asset_path: ./Auto.Photoshop.SD.plugin_v${{ github.event.inputs.tag_name }}.ccx 53 | asset_name: Auto.Photoshop.SD.plugin_v${{ github.event.inputs.tag_name }}.ccx 54 | asset_content_type: application/zip -------------------------------------------------------------------------------- /.github/workflows/publish_docs_to_wiki: -------------------------------------------------------------------------------- 1 | name: Publish docs to Wiki 2 | 3 | # Trigger this action only if there are changes pushed to the docs/** directory under the main branch 4 | on: 5 | push: 6 | branches: 7 | - main # This can be changed to any branch of your preference 8 | 9 | env: 10 | USER_TOKEN: ${{ secrets.WIKI_ACTION_TOKEN }} # This is the repository secret 11 | USER_NAME: AbdullahAlfaraj # Enter the username of your (bot) account 12 | USER_EMAIL: 7842232+AbdullahAlfaraj@users.noreply.github.com # Enter the e-mail of your (bot) account 13 | OWNER: ${{ github.event.repository.owner.name }} # This is the repository owner 14 | REPOSITORY_NAME: ${{ github.event.repository.name }} # This is the repository name 15 | 16 | jobs: 17 | publish_docs_to_wiki: 18 | name: Publish docs to Wiki 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v2 23 | 24 | # 1. Create folder named `tmp_wiki` 25 | # 2. Initialize Git 26 | # 3. Pull old Wiki content 27 | - name: Pull content from wiki 28 | run: | 29 | mkdir tmp_wiki 30 | cd tmp_wiki 31 | git init 32 | git config user.name $USER_NAME 33 | git config user.email $USER_EMAIL 34 | git pull https://$USER_TOKEN@github.com/$OWNER/$REPOSITORY_NAME.wiki.git 35 | # 4. Synchronize differences between `docs` & `tmp_wiki` 36 | # 5. Push new Wiki content 37 | - name: Push content to wiki 38 | run: | 39 | rsync -av --delete docs/ tmp_wiki/ --exclude .git 40 | cd tmp_wiki 41 | git add . 42 | git commit -m "Update Wiki content" 43 | git push -f --set-upstream https://$USER_TOKEN@github.com/$OWNER/$REPOSITORY_NAME.wiki.git master 44 | -------------------------------------------------------------------------------- /.github/workflows/wiki-sync-action.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request: 6 | branches: 7 | - master 8 | name: Wiki Sync 9 | jobs: 10 | update-wiki: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # - name: wiki-safe 14 | # run: | 15 | # git config --global --add safe.directory /wiki 16 | - uses: actions/checkout@master 17 | - name: Sync Wiki 18 | # uses: joeizzard/action-wiki-sync@master 19 | uses: AbdullahAlfaraj/ghaction-wiki-sync@master 20 | 21 | 22 | with: 23 | username: AbdullahAlfaraj 24 | access_token: ${{ secrets.WIKI_ACTION_TOKEN }} 25 | wiki_folder: docs 26 | commit_username: 'AbdullahAlfaraj ' 27 | commit_email: '7842232+AbdullahAlfaraj@users.noreply.github.com' 28 | commit_message: 'action: wiki sync' 29 | 30 | -------------------------------------------------------------------------------- /.github/workflows/wiki_action_2: -------------------------------------------------------------------------------- 1 | name: Deploy Wiki 2 | 3 | on: 4 | push: 5 | branches: 6 | # And only on master branch 7 | - master 8 | 9 | jobs: 10 | deploy-wiki: 11 | runs-on: ubuntu-latest 12 | steps: 13 | 14 | - name: Push Wiki Changes 15 | uses: Andrew-Chen-Wang/github-wiki-action@v3 16 | env: 17 | # Make sure you have that / at the end. We use rsync 18 | # WIKI_DIR's default is wiki/ 19 | WIKI_DIR: docs/ 20 | GH_TOKEN: ${{ secrets.WIKI_ACTION_TOKEN }} 21 | GH_MAIL: 7842232+AbdullahAlfaraj@users.noreply.github.com 22 | GH_NAME: ${{ github.repository_owner }} 23 | EXCLUDED_FILES: "a/ b.md" 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | env 3 | /server_env 4 | /tmp 5 | /outputs 6 | /log 7 | /.idea 8 | /.vscode 9 | /.git 10 | /.github 11 | test.bat 12 | server/python_server/output/* 13 | server/python_server/init_images/* 14 | node_modules/ 15 | server/python_server/prompt_shortcut.json 16 | experimental/ 17 | start_server.sh 18 | start_server.bat 19 | *.ccx 20 | *.zip 21 | expanded_mask.png 22 | original_mask.png 23 | /config 24 | 25 | /jimp/* 26 | !/jimp/browser/ 27 | /jimp/browser/examples 28 | /jimp/browser/*.md 29 | /jimp/browser/*.editorconfig 30 | /jimp/browser/lib/jimp.js 31 | 32 | 33 | # comments when packaging (include in the package,uxp packager will use .gitignore to ignore files): 34 | */dist/*LICENSE.txt 35 | */dist/*.bundle.js 36 | typescripts/dist 37 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | server/python_server/output/* 2 | *.md 3 | manifest.json 4 | jimp/** 5 | server_env/** 6 | .github\workflows\wiki-sync-action.yml 7 | **/dist 8 | .github\workflows\wiki-sync-action.yml 9 | tsconfig.json -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 4, 4 | "semi": false, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Abdullah Alfaraj 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build-script/pack-ccx.mjs: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk' 2 | import { program } from 'commander' 3 | import { createWriteStream, readFileSync, statSync, writeFileSync } from 'fs' 4 | import { globSync } from 'glob' 5 | import { dirname, join, relative } from 'path' 6 | import { fileURLToPath } from 'url' 7 | import yazl from 'yazl' 8 | 9 | const __dirname = dirname(fileURLToPath(import.meta.url)) 10 | const basePath = join(__dirname, '..') 11 | 12 | program.requiredOption('--version ', 'the target platform').parse() 13 | 14 | const version = program.opts().version 15 | if (!version.match(/\d+\.\d+\.\d+/)) 16 | throw new Error(`invalid version format: ${version}`) 17 | 18 | console.log(chalk.cyan("rewriting manifest.json's version field to " + version)) 19 | const manifest = JSON.parse(readFileSync(`${basePath}/manifest.json`, 'utf-8')) 20 | manifest.version = version 21 | writeFileSync(`${basePath}/manifest.json`, JSON.stringify(manifest)) 22 | 23 | console.log(chalk.cyan("rewriting package.json's version field to " + version)) 24 | const packageJSON = JSON.parse( 25 | readFileSync(`${basePath}/package.json`, 'utf-8') 26 | ) 27 | packageJSON.version = version 28 | writeFileSync(`${basePath}/package.json`, JSON.stringify(packageJSON)) 29 | 30 | console.log(chalk.cyan('packaging .ccx')) 31 | const zipList = [ 32 | './manifest.json', 33 | './i18n/**/*', 34 | './icon/**/*', 35 | './jimp/**/*', 36 | './scripts/**/*', 37 | './typescripts/dist/**/*', 38 | './utility/**/*', 39 | './server/**/*', 40 | './*.js', 41 | './package.json', 42 | './tsconfig.json', 43 | './*.html', 44 | './*.py', 45 | './*.txt', 46 | './*.md', 47 | './*.png', 48 | './presets/**/*', 49 | './typescripts/comfyui/**/*.json', 50 | ] 51 | 52 | const zipfile = new yazl.ZipFile() 53 | 54 | zipList.forEach((globber) => { 55 | globSync(join(basePath, globber).replace(/\\/g, '/')).forEach( 56 | (filepath) => { 57 | if (statSync(filepath).isDirectory()) return 58 | 59 | const rpath = relative(basePath, filepath) 60 | zipfile.addFile(filepath, rpath) 61 | } 62 | ) 63 | }) 64 | 65 | zipfile.outputStream.pipe( 66 | createWriteStream( 67 | join(basePath, `Auto.Photoshop.SD.plugin_v${version}.ccx`) 68 | ) 69 | ) 70 | zipfile.outputStream.pipe( 71 | createWriteStream( 72 | join(basePath, `Auto.Photoshop.SD.plugin_v${version}.zip`) 73 | ) 74 | ) 75 | 76 | zipfile.end() 77 | -------------------------------------------------------------------------------- /build-script/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | // const CleanWebpackPlugin = require('clean-webpack-plugin') 3 | const CopyPlugin = require('copy-webpack-plugin') 4 | 5 | module.exports = { 6 | entry: { 7 | bundle: path.resolve(__dirname, '../typescripts/entry.ts'), 8 | }, 9 | output: { 10 | path: path.resolve(__dirname, '../typescripts/dist'), 11 | filename: '[name].js', 12 | libraryTarget: 'commonjs2', 13 | }, 14 | mode: 'development', 15 | // mode: 'production', 16 | 17 | devtool: false, 18 | 19 | externals: { 20 | uxp: 'commonjs2 uxp', 21 | photoshop: 'commonjs2 photoshop', 22 | os: 'commonjs2 os', 23 | fs: 'commonjs2 fs', 24 | }, 25 | resolve: { 26 | extensions: ['.tsx', '.ts', '.js', '.jsx'], 27 | 28 | fallback: { 29 | util: require.resolve('util/'), 30 | }, 31 | }, 32 | module: { 33 | rules: [ 34 | { 35 | test: /\.tsx?$/, 36 | loader: 'ts-loader', 37 | exclude: /node_modules/, 38 | options: { 39 | configFile: path.resolve(__dirname, '../typescripts/tsconfig.json'), 40 | }, 41 | }, 42 | { 43 | test: /\.jsx?$/, 44 | exclude: /node_modules/, 45 | loader: 'babel-loader', 46 | options: { 47 | plugins: [ 48 | '@babel/transform-react-jsx', 49 | '@babel/proposal-object-rest-spread', 50 | '@babel/plugin-syntax-class-properties', 51 | ], 52 | }, 53 | }, 54 | { 55 | test: /\.png$/, 56 | exclude: /node_modules/, 57 | loader: 'file-loader', 58 | }, 59 | { 60 | test: /\.css$/, 61 | use: ['style-loader', 'css-loader'], 62 | }, 63 | { 64 | test: /\.svg$/, 65 | use: ['@svgr/webpack', 'url-loader'], 66 | }, 67 | ], 68 | }, 69 | plugins: [ 70 | //new CleanWebpackPlugin(), 71 | // new CopyPlugin(['plugin'], { 72 | // copyUnmodified: true, 73 | // }), 74 | ], 75 | } 76 | -------------------------------------------------------------------------------- /deprecated-do-not-use-start_server.bat: -------------------------------------------------------------------------------- 1 | @REM @echo off 2 | git pull 3 | 4 | set SD_URL=http://127.0.0.1:7860 5 | 6 | echo does server_env\ exist 7 | if exist server_env\ ( 8 | echo Yes 9 | goto :activate_server_env 10 | ) else ( 11 | echo No 12 | goto :create_server_env 13 | ) 14 | 15 | :create_server_env 16 | python -m venv server_env 17 | 18 | 19 | 20 | 21 | @REM pause 22 | 23 | 24 | :activate_server_env 25 | 26 | ::run a server 27 | echo my_path: %~dp0 28 | @REM set current_dir= 29 | set VENV_DIR=%~dp0server_env 30 | @REM cd ./server_env/Scripts/ 31 | set PYTHON="%VENV_DIR%\Scripts\Python.exe" 32 | %PYTHON% -m pip install -r requirements.txt 33 | 34 | cd ./server/python_server 35 | echo python path: %PYTHON% 36 | dir 37 | echo %PYTHON% uvicorn serverMain:app --reload 38 | %PYTHON% -m uvicorn serverMain:app --reload 39 | pause 40 | @REM exit /b 41 | @REM %PYTHON% uvicorn serverMain:app --reload 42 | pause 43 | 44 | @REM %PYTHON% img2imgapi.py 45 | @REM activate 46 | @REM echo server_env %PYTHON% 47 | @REM cd ./server/python_server 48 | @REM %PYTHON% img2imgapi.py 49 | @REM uvicorn serverMain:app --reload 50 | @REM dir . 51 | @REM call webui.bat 52 | -------------------------------------------------------------------------------- /deprecated-do-not-use-start_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | git pull 3 | # Set the desired remote host where the "<>" is 4 | export SD_URL=http://127.0.0.1:7860 5 | 6 | # Check python was installed 7 | if ! hash python; then 8 | echo "Python is not installed" 9 | exit 1 10 | fi 11 | 12 | # Check the default python version 13 | orig_ver=$(python -V 2>&1) 14 | major_version=$(echo "$orig_ver" | sed 's/[^0-9]*\([0-9]*\)\..*/\1/') 15 | minor_subversion=$(echo "$orig_ver" | sed -E 's/^[^.]*\.([^.]*).*$/\1/') 16 | if [[ "$major_version" -ge "3" ]] && [[ "$minor_subversion" -ge "7" ]] # Because of uvicorn==0.20.0 in requirements 17 | then 18 | echo "You have valid version of $orig_ver" 19 | else 20 | echo "Your version $orig_ver not valid, should be >=3.7" 21 | exit 1 22 | fi 23 | 24 | 25 | # Check if the desired environment exists 26 | if [ ! -d "server_env" ]; then 27 | # Create the environment if it doesn't exist 28 | python -m venv server_env 29 | source ./server_env/bin/activate 30 | python -m pip install -r requirements.txt 31 | else 32 | source ./server_env/bin/activate 33 | fi 34 | 35 | cd ./server/python_server 36 | python -m uvicorn serverMain:app --reload 37 | -------------------------------------------------------------------------------- /deprecated-do-not-use-start_server_MacOS.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | git pull 3 | # Set the desired remote host where the "<>" is 4 | export SD_URL=http://127.0.0.1:7860 5 | 6 | # Check if the desired environment exists 7 | if [ ! -d "server_env" ]; then 8 | # Create the environment if it doesn't exist 9 | python3 -m venv server_env 10 | source ./server_env/bin/activate 11 | python3 -m pip install -r requirements.txt 12 | else 13 | source ./server_env/bin/activate 14 | fi 15 | 16 | cd ./server/python_server 17 | python3 -m uvicorn serverMain:app --reload 18 | -------------------------------------------------------------------------------- /deprecated-do-not-use-update_plugin.bat: -------------------------------------------------------------------------------- 1 | git pull -------------------------------------------------------------------------------- /deprecated-do-not-use-update_plugin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | git pull -------------------------------------------------------------------------------- /dialog_box.js: -------------------------------------------------------------------------------- 1 | async function prompt( 2 | heading, 3 | body, 4 | buttons = ['Cancel', 'Ok'], 5 | options = { title: heading, size: { width: 360, height: 280 } } 6 | ) { 7 | const [dlgEl, formEl, headingEl, dividerEl, bodyEl, footerEl] = [ 8 | 'dialog', 9 | 'form', 10 | 'sp-heading', 11 | 'sp-divider', 12 | 'sp-body', 13 | 'footer', 14 | ].map((tag) => document.createElement(tag)) 15 | ;[headingEl, dividerEl, bodyEl, footerEl].forEach((el) => { 16 | el.style.margin = '6px' 17 | el.style.width = 'calc(100% - 12px)' 18 | }) 19 | 20 | formEl.setAttribute('method', 'dialog') 21 | formEl.addEventListener('submit', () => dlgEl.close()) 22 | 23 | footerEl.style.marginTop = '26px' 24 | 25 | dividerEl.setAttribute('size', 'large') 26 | 27 | headingEl.textContent = heading 28 | 29 | bodyEl.textContent = body 30 | 31 | buttons.forEach((btnText, idx) => { 32 | const btnEl = document.createElement('sp-button') 33 | btnEl.setAttribute( 34 | 'variant', 35 | idx === buttons.length - 1 ? btnText.variant || 'cta' : 'secondary' 36 | ) 37 | if (idx === buttons.length - 1) 38 | btnEl.setAttribute('autofocus', 'autofocus') 39 | if (idx < buttons.length - 1) btnEl.setAttribute('quiet') 40 | btnEl.textContent = btnText.text || btnText 41 | btnEl.style.marginLeft = '12px' 42 | btnEl.addEventListener('click', () => 43 | dlgEl.close(btnText.text || btnText) 44 | ) 45 | footerEl.appendChild(btnEl) 46 | }) 47 | ;[headingEl, dividerEl, bodyEl, footerEl].forEach((el) => 48 | formEl.appendChild(el) 49 | ) 50 | dlgEl.appendChild(formEl) 51 | document.body.appendChild(dlgEl) 52 | 53 | return dlgEl.uxpShowModal(options) 54 | } 55 | 56 | // const r1 = await prompt( 57 | // 'Upload Large File', 58 | // 'This is a large file (over 100MB) -- it may take a few moments to upload.', 59 | // ['Skip', 'Upload'] 60 | // ) 61 | // if ((r1 || 'Upload') !== 'Upload') { 62 | // /* cancelled or No */ 63 | // } else { 64 | // /* Yes */ 65 | // } 66 | 67 | // const r2 = await prompt( 68 | // 'Delete File', 69 | // 'Are you sure you wish to delete this file? This action cannot be undone.', 70 | // ['Cancel', { variant: 'warning', text: 'Delete' }] 71 | // ) 72 | // if (r2 !== 'Delete') { 73 | // /* nope, don't do it! */ 74 | // } else { 75 | // /* Do the delete */ 76 | // } 77 | 78 | module.exports = { prompt } 79 | -------------------------------------------------------------------------------- /docs/Generate txt2img.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Generate txt2img.gif -------------------------------------------------------------------------------- /docs/History.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/History.gif -------------------------------------------------------------------------------- /docs/Pasted image 20230131191554.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131191554.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131192430.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131192430.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131195947.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131195947.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131200253.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131200253.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131201122.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131201122.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131202243.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131202243.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131202255.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131202255.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131202517.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131202517.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131202539.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131202539.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131202558.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131202558.png -------------------------------------------------------------------------------- /docs/Pasted image 20230131202638.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230131202638.png -------------------------------------------------------------------------------- /docs/Pasted image 20230201161508.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230201161508.png -------------------------------------------------------------------------------- /docs/Pasted image 20230201161702.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230201161702.png -------------------------------------------------------------------------------- /docs/Pasted image 20230201161716.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230201161716.png -------------------------------------------------------------------------------- /docs/Pasted image 20230201161938.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230201161938.png -------------------------------------------------------------------------------- /docs/Pasted image 20230201163236.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230201163236.png -------------------------------------------------------------------------------- /docs/Pasted image 20230203191656.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Pasted image 20230203191656.png -------------------------------------------------------------------------------- /docs/Viewer Tutorial.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/Viewer Tutorial.gif -------------------------------------------------------------------------------- /docs/heal_brush.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/heal_brush.gif -------------------------------------------------------------------------------- /docs/img2img.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/img2img.gif -------------------------------------------------------------------------------- /docs/inpainting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/inpainting.gif -------------------------------------------------------------------------------- /docs/outpainting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/outpainting.gif -------------------------------------------------------------------------------- /docs/profile_image/A934E4F0-7778-47E9-A395-531BFF2E61F1_1_105_c.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/profile_image/A934E4F0-7778-47E9-A395-531BFF2E61F1_1_105_c.jpeg -------------------------------------------------------------------------------- /docs/profile_image/no_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/profile_image/no_profile.png -------------------------------------------------------------------------------- /docs/prompt_shortcut.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/prompt_shortcut.gif -------------------------------------------------------------------------------- /docs/prompt_shortcut_file.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/docs/prompt_shortcut_file.gif -------------------------------------------------------------------------------- /enum.js: -------------------------------------------------------------------------------- 1 | const clickTypeEnum = { 2 | Click: 'click', 3 | ShiftClick: 'shift_click', 4 | AltClick: 'alt_click', 5 | SecondClick: 'second_click', //when we click a thumbnail that is active/ has orange border 6 | } 7 | const generationModeEnum = { 8 | Txt2Img: 'txt2img', 9 | Img2Img: 'img2img', 10 | Inpaint: 'inpaint', 11 | Outpaint: 'outpaint', 12 | Upscale: 'upscale', 13 | } 14 | 15 | const AutomaticStatusEnum = { 16 | NoApi: 'no_api', 17 | Offline: 'offline', 18 | RunningNoApi: 'running_no_api', 19 | RunningWithApi: 'running_with_api', 20 | AutoPhotoshopSDExtensionMissing: 'auto_photoshop_sd_missing', 21 | } 22 | 23 | const ViewerObjectTypeEnum = { 24 | OutputImage: 'output_image', 25 | InitImage: 'init_image', 26 | MaskImage: 'mask_image', 27 | } 28 | 29 | const RequestStateEnum = { 30 | Generating: 'generating', // in the generation process 31 | Interrupted: 'interrupted', // canceled/ interrupted 32 | Finished: 'finished', // finished generating 33 | } 34 | 35 | const BackgroundHistoryEnum = { 36 | CorrectBackground: 'correct_background', 37 | NoBackground: 'no_background', 38 | } 39 | 40 | module.exports = { 41 | clickTypeEnum, 42 | generationModeEnum, 43 | AutomaticStatusEnum, 44 | ViewerObjectTypeEnum, 45 | RequestStateEnum, 46 | 47 | BackgroundHistoryEnum, 48 | } 49 | -------------------------------------------------------------------------------- /helper.js: -------------------------------------------------------------------------------- 1 | const { unselectActiveLayers } = require('./psapi') 2 | 3 | const app = window.require('photoshop').app 4 | 5 | function getActiveLayer() { 6 | let activeLayers = app.activeDocument.activeLayers 7 | // console.dir(getSize()) 8 | for (const layer of activeLayers) { 9 | console.dir({ layer }) 10 | const name = layer.name 11 | console.dir({ name }) 12 | let layer_size = getLayerSize(layer) 13 | console.dir({ layer_size }) 14 | } 15 | 16 | return activeLayers[0] 17 | } 18 | 19 | function getSize() { 20 | let doc = app.activeDocument 21 | return { height: doc.height, width: doc.width } 22 | } 23 | 24 | const { batchPlay } = require('photoshop').action 25 | const { executeAsModal } = require('photoshop').core 26 | 27 | async function reselectBatchPlay(selectionInfo) { 28 | const result = await batchPlay( 29 | [ 30 | { 31 | _obj: 'set', 32 | _target: [ 33 | { 34 | _ref: 'channel', 35 | _property: 'selection', 36 | }, 37 | ], 38 | to: { 39 | _obj: 'rectangle', 40 | top: { 41 | _unit: 'pixelsUnit', 42 | _value: selectionInfo.top, 43 | }, 44 | left: { 45 | _unit: 'pixelsUnit', 46 | _value: selectionInfo.left, 47 | }, 48 | bottom: { 49 | _unit: 'pixelsUnit', 50 | _value: selectionInfo.bottom, 51 | }, 52 | right: { 53 | _unit: 'pixelsUnit', 54 | _value: selectionInfo.right, 55 | }, 56 | }, 57 | _options: { 58 | dialogOptions: 'dontDisplay', 59 | }, 60 | }, 61 | ], 62 | { 63 | synchronousExecution: true, 64 | modalBehavior: 'execute', 65 | } 66 | ) 67 | } 68 | 69 | async function reselect(selectionInfo) { 70 | await executeAsModal( 71 | async () => { 72 | reselectBatchPlay(selectionInfo) 73 | }, 74 | { commandName: 'reselect' } 75 | ) 76 | } 77 | 78 | //unselect the rectangular marquee selection area 79 | async function unSelect() { 80 | const batchPlay = require('photoshop').action.batchPlay 81 | 82 | const result = await batchPlay( 83 | [ 84 | { 85 | _obj: 'set', 86 | _target: [ 87 | { 88 | _ref: 'channel', 89 | _property: 'selection', 90 | }, 91 | ], 92 | to: { 93 | _enum: 'ordinal', 94 | _value: 'none', 95 | }, 96 | _options: { 97 | dialogOptions: 'dontDisplay', 98 | }, 99 | }, 100 | ], 101 | { 102 | synchronousExecution: true, 103 | modalBehavior: 'execute', 104 | } 105 | ) 106 | 107 | return result 108 | } 109 | 110 | /** 111 | * Convert 1d index to 2d array 112 | * @param {number} index sequential index 113 | * @param {number} width width of 2d array 114 | * @returns {number[]} [x,y] 115 | */ 116 | function indexToXY(index, width) { 117 | return [index % width, Math.floor(index / width)] 118 | } 119 | 120 | module.exports = {} 121 | -------------------------------------------------------------------------------- /icon/accept_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/accept_all.png -------------------------------------------------------------------------------- /icon/accept_all.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /icon/accept_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/accept_selected.png -------------------------------------------------------------------------------- /icon/accept_selected.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /icon/camera_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/camera_icon.png -------------------------------------------------------------------------------- /icon/camera_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /icon/chain_black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /icon/chain_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /icon/discard_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/discard_all.png -------------------------------------------------------------------------------- /icon/discard_all.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /icon/discard_all_border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/discard_all_border.png -------------------------------------------------------------------------------- /icon/discard_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/discard_selected.png -------------------------------------------------------------------------------- /icon/discard_selected.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /icon/discard_selected_border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/discard_selected_border.png -------------------------------------------------------------------------------- /icon/ftcopy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | 38 | 48 | 58 | 65 | 67 | 69 | 71 | image/svg+xml 74 | 77 | 80 | 82 | 85 | Openclipart 88 | 90 | 92 | ftcopy 95 | 2011-01-31T02:01:26 98 | Originally uploaded by Danny Allen for OCAL 0.18 this icon is part of the flat theme 101 | https://openclipart.org/detail/112297/ftcopy-by-anonymous 104 | 106 | 108 | Anonymous 111 | 113 | 115 | 117 | 119 | flat 122 | icon 125 | theme 128 | 130 | 132 | 134 | 137 | 140 | 143 | 146 | 148 | 150 | 152 | 154 | -------------------------------------------------------------------------------- /icon/image-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /icon/layer_to_selection.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /icon/move_to_canvas.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 22 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /icon/panel@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/panel@1x.png -------------------------------------------------------------------------------- /icon/panel@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/panel@2x.png -------------------------------------------------------------------------------- /icon/pen.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /icon/plugin@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/plugin@1x.png -------------------------------------------------------------------------------- /icon/plugin@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/plugin@2x.png -------------------------------------------------------------------------------- /icon/preview.svg: -------------------------------------------------------------------------------- 1 | 16 | 21 | 26 | 31 | 40 | 45 | 50 | 55 | 56 | -------------------------------------------------------------------------------- /icon/reselect-area.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 12 | 13 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /icon/reset_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/reset_settings.png -------------------------------------------------------------------------------- /icon/reset_settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /icon/reset_settings2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/icon/reset_settings2.png -------------------------------------------------------------------------------- /icon/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /icon/search_button.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /icon/selection-area_2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 12 | 13 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /icon/writing-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /install.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | from launch import git, run 4 | import launch 5 | import sys 6 | 7 | # launch.run(f'git pull', f"updating auto-photoshop plugin", 8 | # f"Couldn't update auto-photoshop plugin") 9 | 10 | 11 | REPO_LOCATION = Path(__file__).parent 12 | # auto_update = os.environ.get("AUTO_UPDATE", "True").lower() in {"true", "yes"} 13 | auto_update = True 14 | extension_branch = "master" 15 | # extension_branch = "horde_native" 16 | # extension_branch = "auto_extension_ccx_1_1_7" 17 | 18 | if auto_update: 19 | print("[Auto-Photoshop-SD] Attempting auto-update...") 20 | 21 | try: 22 | checkout_result = run( 23 | f'"{git}" -C "{REPO_LOCATION}" checkout {extension_branch}', 24 | "[Auto-Photoshop-SD] switch branch to extension branch.", 25 | ) 26 | print("checkout_result:", checkout_result) 27 | 28 | branch_result = run( 29 | f'"{git}" -C "{REPO_LOCATION}" branch', 30 | "[Auto-Photoshop-SD] Current Branch.", 31 | ) 32 | print("branch_result:", branch_result) 33 | 34 | fetch_result = run( 35 | f'"{git}" -C "{REPO_LOCATION}" fetch', "[Auto-Photoshop-SD] Fetch upstream." 36 | ) 37 | print("fetch_result:", fetch_result) 38 | 39 | pull_result = run( 40 | f'"{git}" -C "{REPO_LOCATION}" pull', "[Auto-Photoshop-SD] Pull upstream." 41 | ) 42 | print("pull_result:", pull_result) 43 | 44 | except Exception as e: 45 | print("[Auto-Photoshop-SD] Auto-update failed:") 46 | print(e) 47 | print("[Auto-Photoshop-SD] Ensure git was used to install extension.") 48 | 49 | 50 | # print("Auto-Photoshop-SD plugin is installing") 51 | import pkg_resources 52 | 53 | 54 | def install_or_update_package(package_name, package_version): 55 | if not launch.is_installed(package_name): 56 | launch.run_pip( 57 | f"install {package_name}=={package_version}", 58 | "requirements for Auto-Photoshop Image Search", 59 | ) 60 | else: # it's installed but we need to check for update 61 | version = pkg_resources.get_distribution(package_name).version 62 | if version != package_version: 63 | print( 64 | f"{package_name} version: {version} will update to version: {package_version}" 65 | ) 66 | launch.run_pip( 67 | f"install {package_name}=={package_version}", 68 | "update requirements for Auto-Photoshop Image Search", 69 | ) 70 | 71 | 72 | # Now we can use this function to install or update the packages 73 | install_or_update_package("duckduckgo_search", "3.9.9") 74 | install_or_update_package("httpx", "0.24.1") 75 | -------------------------------------------------------------------------------- /output_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/6f6d4907adf0b6a6e562d084238f02ed6b7503c1/output_image.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto-photoshop-stable-diffusion-plugin", 3 | "version": "1.3.3", 4 | "description": "A user-friendly plug-in that makes it easy to generate stable diffusion images inside Photoshop using Automatic1111-sd-webui as a backend.", 5 | "author": "Adobe Inc", 6 | "license": "Apache-2.0", 7 | "dependencies": { 8 | "@types/photoshop": "^24.5.1", 9 | "@types/react": "^18.2.6", 10 | "@types/react-dom": "^18.2.4", 11 | "changedpi": "^1.0.4", 12 | "fastify": "^4.10.2", 13 | "jimp": "^0.16.2", 14 | "madge": "^6.0.0", 15 | "md5": "^2.3.0", 16 | "mobx": "^6.9.0", 17 | "mobx-react": "^7.6.0", 18 | "react": "^18.2.0", 19 | "react-dom": "^18.2.0", 20 | "util": "^0.12.5" 21 | }, 22 | "main": "index.js", 23 | "directories": { 24 | "test": "test" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "^7.21.8", 28 | "@babel/plugin-proposal-object-rest-spread": "^7.20.7", 29 | "@babel/plugin-syntax-class-properties": "^7.12.13", 30 | "@babel/plugin-transform-react-jsx": "^7.21.5", 31 | "@svgr/webpack": "^8.0.1", 32 | "babel-loader": "^9.1.2", 33 | "chalk": "^5.3.0", 34 | "clean-webpack-plugin": "^4.0.0", 35 | "commander": "^11.0.0", 36 | "copy-webpack-plugin": "^11.0.0", 37 | "css-loader": "^6.7.3", 38 | "file-loader": "^6.2.0", 39 | "glob": "^10.3.4", 40 | "nodemon": "^2.0.22", 41 | "prettier": "2.8.3", 42 | "style-loader": "^3.3.2", 43 | "terser-webpack-plugin": "^3.0.8", 44 | "ts-loader": "^9.4.2", 45 | "typescript": "^5.0.4", 46 | "url-loader": "^4.1.1", 47 | "webpack": "^5.82.1", 48 | "webpack-cli": "^5.1.1", 49 | "yazl": "^2.5.1" 50 | }, 51 | "scripts": { 52 | "test": "echo \"Error: no test specified\" && exit 1", 53 | "watch": "npx webpack --config ./build-script/webpack.config.js --watch --devtool eval-source-map", 54 | "build": "npx webpack --config ./build-script/webpack.config.js", 55 | "publish": "npx webpack --config ./build-script/webpack.config.js --mode production", 56 | "format": "npx prettier -w typescripts" 57 | }, 58 | "repository": { 59 | "type": "git", 60 | "url": "git+https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin.git" 61 | }, 62 | "keywords": [], 63 | "bugs": { 64 | "url": "https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/issues" 65 | }, 66 | "homepage": "https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin#readme" 67 | } 68 | -------------------------------------------------------------------------------- /presets/ctrlnet_inpaint.json: -------------------------------------------------------------------------------- 1 | { 2 | "sd_tab_preset": { 3 | "is_lasso_mode": false, 4 | "mode": "inpaint", 5 | "rb_mode": "inpaint", 6 | "batch_size": 1, 7 | "batch_count": 1, 8 | "ratio": 1, 9 | "cfg": 7, 10 | "b_width_height_link": true, 11 | "denoising_strength": 1, 12 | "hr_denoising_strength": 0.7, 13 | "inpaint_full_res": false, 14 | "enable_hr": false, 15 | "image_cfg_scale": 1.5, 16 | "mask_blur": 0, 17 | "mask_expansion": 0, 18 | "inpaint_full_res_padding": 0, 19 | "hr_scale": 2, 20 | "hr_resize_x": 512, 21 | "hr_resize_y": 512, 22 | "hr_second_pass_steps": 0, 23 | "restore_faces": false, 24 | "inpainting_fill": 2, 25 | "hr_upscaler": "", 26 | "selection_mode": "ratio" 27 | }, 28 | "controlnet_tab_preset": [ 29 | { 30 | "enabled": true, 31 | "module": "inpaint_global_harmonious", 32 | "model": "control_v11p_sd15_inpaint [ebff9138]", 33 | "weight": 1, 34 | "resize_mode": "Scale to Fit (Inner Fit)", 35 | "lowvram": true, 36 | "processor_res": 512, 37 | "threshold_a": 0, 38 | "threshold_b": 0, 39 | "guidance_start": 0, 40 | "guidance_end": 1, 41 | "guessmode": false, 42 | "control_mode": "ControlNet is more important", 43 | "pixel_perfect": true, 44 | "auto_image": true, 45 | "filter_keyword": "Inpaint" 46 | }, 47 | {}, 48 | {}, 49 | {}, 50 | {}, 51 | {}, 52 | {} 53 | ] 54 | } -------------------------------------------------------------------------------- /presets/ctrlnet_inpaint_tile.json: -------------------------------------------------------------------------------- 1 | { 2 | "sd_tab_preset": { 3 | "is_lasso_mode": false, 4 | "mode": "inpaint", 5 | "rb_mode": "inpaint", 6 | "batch_size": 1, 7 | "batch_count": 1, 8 | "ratio": 1, 9 | "b_width_height_link": true, 10 | "denoising_strength": 1, 11 | "hr_denoising_strength": 0.7, 12 | "inpaint_full_res": false, 13 | "enable_hr": false, 14 | "image_cfg_scale": 1.5, 15 | "mask_blur": 0, 16 | "mask_expansion": 0, 17 | "inpaint_full_res_padding": 0, 18 | "hr_scale": 2, 19 | "hr_resize_x": 512, 20 | "hr_resize_y": 512, 21 | "hr_second_pass_steps": 0, 22 | "restore_faces": false, 23 | "inpainting_fill": 2, 24 | "hr_upscaler": "", 25 | "selection_mode": "ratio" 26 | }, 27 | "controlnet_tab_preset": [ 28 | { 29 | "enabled": true, 30 | "module": "inpaint_global_harmonious", 31 | "model": "control_v11p_sd15_inpaint [ebff9138]", 32 | "weight": 1, 33 | "resize_mode": "Scale to Fit (Inner Fit)", 34 | "lowvram": true, 35 | "processor_res": 512, 36 | "threshold_a": 0, 37 | "threshold_b": 0, 38 | "guidance_start": 0, 39 | "guidance_end": 1, 40 | "guessmode": false, 41 | "control_mode": "ControlNet is more important", 42 | "pixel_perfect": true, 43 | "auto_image": true, 44 | "filter_keyword": "Inpaint" 45 | }, 46 | { 47 | "enabled": true, 48 | "module": "tile_resample", 49 | "model": "control_v11f1e_sd15_tile [a371b31b]", 50 | "weight": 0.4, 51 | "resize_mode": "Scale to Fit (Inner Fit)", 52 | "lowvram": true, 53 | "processor_res": 512, 54 | "threshold_a": 1, 55 | "threshold_b": 0, 56 | "guidance_start": 0, 57 | "guidance_end": 1, 58 | "guessmode": false, 59 | "control_mode": "Balanced", 60 | "pixel_perfect": true, 61 | "auto_image": true, 62 | "filter_keyword": "Tile" 63 | }, 64 | {}, 65 | {}, 66 | {}, 67 | {}, 68 | {} 69 | ] 70 | } -------------------------------------------------------------------------------- /presets/ctrlnet_outpaint.json: -------------------------------------------------------------------------------- 1 | { 2 | "sd_tab_preset": { 3 | "is_lasso_mode": false, 4 | "mode": "outpaint", 5 | "rb_mode": "outpaint", 6 | "batch_size": 1, 7 | "batch_count": 1, 8 | "ratio": 1, 9 | "cfg": 7, 10 | "b_width_height_link": true, 11 | "denoising_strength": 1, 12 | "hr_denoising_strength": 0.7, 13 | "inpaint_full_res": false, 14 | "enable_hr": false, 15 | "image_cfg_scale": 1.5, 16 | "mask_blur": 0, 17 | "mask_expansion": 10, 18 | "inpaint_full_res_padding": 0, 19 | "hr_scale": 2, 20 | "hr_resize_x": 512, 21 | "hr_resize_y": 512, 22 | "hr_second_pass_steps": 0, 23 | "restore_faces": false, 24 | "inpainting_fill": 3, 25 | "hr_upscaler": "", 26 | "selection_mode": "ratio" 27 | }, 28 | "controlnet_tab_preset": [ 29 | { 30 | "enabled": true, 31 | "module": "inpaint_global_harmonious", 32 | "model": "control_v11p_sd15_inpaint [ebff9138]", 33 | "weight": 1, 34 | "resize_mode": "Scale to Fit (Inner Fit)", 35 | "lowvram": true, 36 | "processor_res": 512, 37 | "threshold_a": 0, 38 | "threshold_b": 0, 39 | "guidance_start": 0, 40 | "guidance_end": 1, 41 | "guessmode": false, 42 | "control_mode": "ControlNet is more important", 43 | "pixel_perfect": true, 44 | "auto_image": true, 45 | "filter_keyword": "Inpaint" 46 | }, 47 | {}, 48 | {}, 49 | {}, 50 | {}, 51 | {}, 52 | {} 53 | ] 54 | } -------------------------------------------------------------------------------- /presets/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "sd_tab_preset": { 3 | "is_lasso_mode": false, 4 | "mode": "txt2img", 5 | "rb_mode": "txt2img", 6 | "batch_size": 1, 7 | "batch_count": 1, 8 | "steps": 20, 9 | "width": 512, 10 | "height": 512, 11 | "ratio": 1, 12 | "cfg": 7, 13 | "b_width_height_link": true, 14 | "denoising_strength": 0.7, 15 | "hr_denoising_strength": 0.7, 16 | "inpaint_full_res": false, 17 | "enable_hr": false, 18 | "sampler_name": "Euler a", 19 | "image_cfg_scale": 1.5, 20 | "seed": "-1", 21 | "mask_blur": 0, 22 | "mask_expansion": 0, 23 | "inpaint_full_res_padding": 0, 24 | "hr_scale": 2, 25 | "hr_resize_x": 512, 26 | "hr_resize_y": 512, 27 | "hr_second_pass_steps": 0, 28 | "restore_faces": false, 29 | "inpainting_fill": 0, 30 | "hr_upscaler": "", 31 | "selection_mode": "ratio" 32 | }, 33 | "controlnet_tab_preset": [ 34 | {}, 35 | {}, 36 | {}, 37 | {}, 38 | {}, 39 | {}, 40 | {} 41 | ] 42 | } -------------------------------------------------------------------------------- /presets/img2img.json: -------------------------------------------------------------------------------- 1 | { 2 | "sd_tab_preset": { 3 | "is_lasso_mode": false, 4 | "mode": "img2img", 5 | "rb_mode": "img2img", 6 | "batch_size": 1, 7 | "batch_count": 1, 8 | "steps": 20, 9 | 10 | "ratio": 1, 11 | "cfg": 7, 12 | "b_width_height_link": true, 13 | "denoising_strength": 0.6, 14 | "hr_denoising_strength": 0.7, 15 | "inpaint_full_res": false, 16 | "enable_hr": false, 17 | "image_cfg_scale": 1.5, 18 | "mask_blur": 0, 19 | "mask_expansion": 10, 20 | "inpaint_full_res_padding": 0, 21 | "hr_scale": 2, 22 | "hr_resize_x": 512, 23 | "hr_resize_y": 512, 24 | "hr_second_pass_steps": 0, 25 | "restore_faces": false, 26 | "inpainting_fill": 2, 27 | "hr_upscaler": "", 28 | "selection_mode": "ratio" 29 | }, 30 | "controlnet_tab_preset": [{}, {}, {}, {}, {}, {}, {}] 31 | } 32 | -------------------------------------------------------------------------------- /presets/inpaint.json: -------------------------------------------------------------------------------- 1 | { 2 | "sd_tab_preset": { 3 | "is_lasso_mode": false, 4 | "mode": "inpaint", 5 | "rb_mode": "inpaint", 6 | "batch_size": 1, 7 | "batch_count": 1, 8 | "steps": 20, 9 | "ratio": 1, 10 | "cfg": 7, 11 | "b_width_height_link": true, 12 | "denoising_strength": 0.7, 13 | "hr_denoising_strength": 0.7, 14 | "inpaint_full_res": false, 15 | "enable_hr": false, 16 | "image_cfg_scale": 1.5, 17 | "mask_blur": 0, 18 | "mask_expansion": 0, 19 | "inpaint_full_res_padding": 0, 20 | "hr_scale": 2, 21 | "hr_resize_x": 512, 22 | "hr_resize_y": 512, 23 | "hr_second_pass_steps": 0, 24 | "restore_faces": false, 25 | "inpainting_fill": 1, 26 | "hr_upscaler": "", 27 | "selection_mode": "ratio" 28 | }, 29 | "controlnet_tab_preset": [{}, {}, {}, {}, {}, {}, {}] 30 | } 31 | -------------------------------------------------------------------------------- /presets/outpaint.json: -------------------------------------------------------------------------------- 1 | { 2 | "sd_tab_preset": { 3 | "is_lasso_mode": false, 4 | "mode": "outpaint", 5 | "rb_mode": "outpaint", 6 | "batch_size": 1, 7 | "batch_count": 1, 8 | "steps": 20, 9 | "ratio": 1, 10 | "cfg": 7, 11 | "b_width_height_link": true, 12 | "denoising_strength": 0.92, 13 | "hr_denoising_strength": 0.7, 14 | "inpaint_full_res": false, 15 | "enable_hr": false, 16 | "image_cfg_scale": 1.5, 17 | "mask_blur": 0, 18 | "mask_expansion": 10, 19 | "inpaint_full_res_padding": 0, 20 | "hr_scale": 2, 21 | "hr_resize_x": 512, 22 | "hr_resize_y": 512, 23 | "hr_second_pass_steps": 0, 24 | "restore_faces": false, 25 | "inpainting_fill": 2, 26 | "hr_upscaler": "", 27 | "selection_mode": "ratio" 28 | }, 29 | "controlnet_tab_preset": [] 30 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.2 2 | asyncio==3.4.3 3 | certifi==2022.12.7 4 | charset-normalizer==2.1.1 5 | click==8.1.7 6 | fastapi==0.88.0 7 | h11==0.14.0 8 | httpcore==0.16.3 9 | httptools==0.5.0 10 | httpx==0.25.1 11 | idna==3.4 12 | Pillow==9.3.0 13 | pydantic==1.10.2 14 | python-dotenv==0.21.0 15 | PyYAML==6.0 16 | requests==2.28.1 17 | rfc3986==1.5.0 18 | sniffio==1.3.0 19 | starlette==0.22.0 20 | typing_extensions==4.4.0 21 | urllib3==1.26.13 22 | uvicorn==0.20.0 23 | # uvloop==0.17.0 24 | watchfiles==0.18.1 25 | websockets==10.4 26 | duckduckgo_search==3.9.9 27 | -------------------------------------------------------------------------------- /scripts/main.py: -------------------------------------------------------------------------------- 1 | from modules import scripts, processing, shared, images, devices, ui, lowvram 2 | import gradio 3 | import requests 4 | import time 5 | import PIL.Image 6 | import base64 7 | import io 8 | import os.path 9 | import numpy 10 | import itertools 11 | import gradio as gr 12 | import torch 13 | from fastapi import FastAPI 14 | from fastapi import APIRouter, Request 15 | from fastapi.responses import StreamingResponse 16 | from modules import script_callbacks, scripts, shared 17 | 18 | 19 | import sys 20 | python_server_dir = 'server/python_server' 21 | extension_dir = scripts.basedir() 22 | python_server_full_path = os.path.join(extension_dir,python_server_dir) 23 | print("python_server_full_path: ",python_server_full_path) 24 | sys.path.insert(0, python_server_full_path) 25 | import search 26 | import img2imgapi 27 | import serverMain 28 | 29 | router = APIRouter() 30 | 31 | # @router.get("/config") 32 | # async def get_state(): 33 | # print("hello get /config auto-photoshop-sd") 34 | # res = "hello get /config auto-photoshop-sd" 35 | # return {"res": res} 36 | 37 | @router.post('/search/image/') 38 | async def searchImage(request:Request): 39 | try: 40 | json = await request.json() 41 | except: 42 | json = {} 43 | 44 | 45 | try: 46 | keywords = json.get('keywords','cute cats') 47 | images = await search.imageSearch(keywords) 48 | print(images) 49 | 50 | 51 | return {"images":images} 52 | except: 53 | print("keywords",keywords) 54 | # print(f'{request}') 55 | return {"error": "error message: can't preform an image search"} 56 | 57 | 58 | @router.post('/mask/expansion/') 59 | async def maskExpansionHandler(request:Request): 60 | try: 61 | json = await request.json() 62 | except: 63 | json = {} 64 | 65 | # print("mask expansion json :",json) 66 | try: 67 | # keywords = json.get('keywords','cute dogs') 68 | base64_mask_image = json['mask'] 69 | mask_expansion = json['mask_expansion'] 70 | blur = json['blur'] 71 | #convert base64 to img 72 | 73 | await img2imgapi.base64ToPng(base64_mask_image,"original_mask.png")#save a copy of the mask 74 | 75 | mask_image = img2imgapi.b64_2_img(base64_mask_image) 76 | 77 | expanded_mask_img = img2imgapi.maskExpansion(mask_image,mask_expansion,blur) 78 | base64_expanded_mask_image = img2imgapi.img_2_b64(expanded_mask_img) 79 | await img2imgapi.base64ToPng(base64_expanded_mask_image,"expanded_mask.png")#save a copy of the mask 80 | 81 | 82 | return {"mask":base64_expanded_mask_image} 83 | 84 | except: 85 | # print("request",request) 86 | raise Exception(f"couldn't preform mask expansion",json) 87 | # return response 88 | return {"error": "error message: can't preform an mask expansion"} 89 | 90 | 91 | 92 | def on_app_started(demo: gr.Blocks, app: FastAPI): 93 | # print("hello on_app_started auto-photoshop-plugin") 94 | 95 | if shared.cmd_opts.api: 96 | app.include_router(serverMain.router, prefix="/sdapi/auto-photoshop-sd", tags=['Auto Photoshop SD Plugin API']) 97 | # app.include_router(router, prefix="/sdapi/auto-photoshop-sd", tags=['Auto Photoshop SD Plugin API']) 98 | 99 | 100 | else: 101 | print("COMMANDLINE_ARGS does not contain --api, API won't be mounted.") 102 | 103 | # logger.warning("COMMANDLINE_ARGS does not contain --api, API won't be mounted.") 104 | # if you wanted to do anything massive to the UI, you could modify demo, but why? 105 | 106 | script_callbacks.on_app_started(on_app_started) -------------------------------------------------------------------------------- /scripts/test.py: -------------------------------------------------------------------------------- 1 | # import sys 2 | # sys.path.insert(0, 'server/python_server') 3 | # import search 4 | 5 | # print("hello test.py") -------------------------------------------------------------------------------- /server/python_server/global_state.py: -------------------------------------------------------------------------------- 1 | #code copied from controlnet repo global_state.py 2 | 3 | 4 | preprocessor_filters = { 5 | "All": "none", 6 | "Canny": "canny", 7 | "Depth": "depth_midas", 8 | "Normal": "normal_bae", 9 | "OpenPose": "openpose_full", 10 | "MLSD": "mlsd", 11 | "Lineart": "lineart_standard (from white bg & black line)", 12 | "SoftEdge": "softedge_pidinet", 13 | "Scribble": "scribble_pidinet", 14 | "Seg": "seg_ofade20k", 15 | "Shuffle": "shuffle", 16 | "Tile": "tile_resample", 17 | "Inpaint": "inpaint_only", 18 | "IP2P": "none", 19 | "Reference": "reference_only", 20 | "T2IA": "none", 21 | } 22 | 23 | cn_preprocessor_modules = ["none", 24 | "canny", 25 | "depth", 26 | "depth_leres", 27 | "depth_leres++", 28 | "hed", 29 | "hed_safe", 30 | "mediapipe_face", 31 | "mlsd", 32 | "normal_map", 33 | "openpose", 34 | "openpose_hand", 35 | "openpose_face", 36 | "openpose_faceonly", 37 | "openpose_full", 38 | "clip_vision", 39 | "color", 40 | "pidinet", 41 | "pidinet_safe", 42 | "pidinet_sketch", 43 | "pidinet_scribble", 44 | "scribble_xdog", 45 | "scribble_hed", 46 | "segmentation", 47 | "threshold", 48 | "depth_zoe", 49 | "normal_bae", 50 | "oneformer_coco", 51 | "oneformer_ade20k", 52 | "lineart", 53 | "lineart_coarse", 54 | "lineart_anime", 55 | "lineart_standard", 56 | "shuffle", 57 | "tile_resample", 58 | "invert", 59 | "lineart_anime_denoise", 60 | "reference_only", 61 | "reference_adain", 62 | "reference_adain+attn", 63 | "inpaint", 64 | "inpaint_only", 65 | "inpaint_only+lama", 66 | "tile_colorfix", 67 | "tile_colorfix+sharp", 68 | ] 69 | 70 | preprocessor_aliases = { 71 | "invert": "invert (from white bg & black line)", 72 | "lineart_standard": "lineart_standard (from white bg & black line)", 73 | "lineart": "lineart_realistic", 74 | "color": "t2ia_color_grid", 75 | "clip_vision": "t2ia_style_clipvision", 76 | "pidinet_sketch": "t2ia_sketch_pidi", 77 | "depth": "depth_midas", 78 | "normal_map": "normal_midas", 79 | "hed": "softedge_hed", 80 | "hed_safe": "softedge_hedsafe", 81 | "pidinet": "softedge_pidinet", 82 | "pidinet_safe": "softedge_pidisafe", 83 | "segmentation": "seg_ufade20k", 84 | "oneformer_coco": "seg_ofcoco", 85 | "oneformer_ade20k": "seg_ofade20k", 86 | "pidinet_scribble": "scribble_pidinet", 87 | "inpaint": "inpaint_global_harmonious", 88 | } 89 | 90 | def filter_selected_helper(k,preprocessor_list,model_list): 91 | if 'None' not in model_list: 92 | model_list = ['None'] + model_list 93 | ui_preprocessor_keys = ['none', preprocessor_aliases['invert']] 94 | 95 | 96 | ui_preprocessor_keys += sorted([preprocessor_aliases.get(k, k) 97 | for k in preprocessor_list 98 | if preprocessor_aliases.get(k, k) not in ui_preprocessor_keys]) 99 | 100 | 101 | preprocessor_list = ui_preprocessor_keys 102 | # print("preprocessor_list sorted: ",preprocessor_list) 103 | model_list = list(model_list) 104 | # print("list(model_list): ",model_list) 105 | 106 | # print("k:",k,k.lower()) 107 | 108 | 109 | default_option = preprocessor_filters[k] 110 | pattern = k.lower() 111 | # model_list = list(cn_models.keys()) 112 | if pattern == "all": 113 | return [ 114 | preprocessor_list, 115 | model_list, 116 | 'none', #default option 117 | "None" #default model 118 | ] 119 | filtered_preprocessor_list = [ 120 | x 121 | for x in preprocessor_list 122 | if pattern in x.lower() or x.lower() == "none" 123 | ] 124 | if pattern in ["canny", "lineart", "scribble", "mlsd"]: 125 | filtered_preprocessor_list += [ 126 | x for x in preprocessor_list if "invert" in x.lower() 127 | ] 128 | 129 | ##Debug start 130 | # for model in model_list: 131 | # print("model: ",model) 132 | # if pattern in model.lower(): 133 | # print('add to filtered') 134 | # print("pattern:",pattern, "in model.lower():",model.lower()) 135 | # else: 136 | # print("pattern:",pattern, "not in model.lower():",model.lower()) 137 | ##Debug end 138 | 139 | filtered_model_list = [ 140 | x for x in model_list if pattern in x.lower() or x.lower() == "none" 141 | ] 142 | if default_option not in filtered_preprocessor_list: 143 | default_option = filtered_preprocessor_list[0] 144 | if len(filtered_model_list) == 1: 145 | default_model = "None" 146 | filtered_model_list = model_list 147 | else: 148 | default_model = filtered_model_list[1] 149 | for x in filtered_model_list: 150 | if "11" in x.split("[")[0]: 151 | default_model = x 152 | break 153 | 154 | return [filtered_preprocessor_list,filtered_model_list, default_option,default_model] 155 | -------------------------------------------------------------------------------- /server/python_server/init_images/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /server/python_server/metadata_to_json.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | from PIL import Image 4 | import json 5 | 6 | import serverHelper 7 | # metadata_str = 'cute cat\nSteps: 20, Sampler: Euler a, CFG scale: 7.0, Seed: 2253354038, Size: 512x512, Model hash: 3e16efc8, Seed resize from: -1x-1, Denoising strength: 0, Conditional mask weight: 1.0' 8 | def convertMetadataToJson(metadata_str): 9 | print(metadata_str) 10 | last_new_line_index = metadata_str.rindex('\n') 11 | prompt = metadata_str[:last_new_line_index] 12 | other_settings = metadata_str[last_new_line_index+1:] 13 | 14 | print("prompt:", prompt) 15 | print("other_settings:", other_settings) 16 | sub_settings = other_settings.split(",") 17 | print("sub_settings: ",sub_settings) 18 | 19 | settings_dict = {} 20 | settings_dict['prompt'] = prompt 21 | 22 | for setting in sub_settings: 23 | [key,value]= setting.split(":") 24 | key = key.lstrip(' ') 25 | value = value.lstrip(' ') 26 | settings_dict[key] = value 27 | import json 28 | settings_json = json.dumps(settings_dict) 29 | print("settings_dict: ",settings_dict) 30 | print("settings_json ",settings_json) 31 | return settings_json 32 | 33 | 34 | 35 | 36 | def getMetadataFromPng(image_path): 37 | # image_path = "./output/5c42fd2a-6708-45e2-b282-2e9f3894368e/output- 1672476035.4888158.png" 38 | # image_path = "C:/Users/abdul/Desktop/auto-photoshop/Auto-Photoshop-StableDiffusion-Plugin/server/python_server/output/5c42fd2a-6708-45e2-b282-2e9f3894368e/output- 1672476035.4888158.png" 39 | im = Image.open(image_path) 40 | # im.load() # Needed only for .png EXIF data (see citation above) 41 | # print(im.info['parameters']) 42 | metadata_string = im.info['parameters'] 43 | metadata_json_string = convertMetadataToJson(metadata_string) 44 | metadata_dict = json.loads(metadata_json_string) 45 | print("metadata_dict: ", metadata_dict) 46 | # print(im.info['meta_to_read']) 47 | return metadata_dict 48 | 49 | 50 | def createMetadataJsonFileIfNotExist(image_path): 51 | 52 | # image_name = os.path.splitext(image_path) 53 | image_name = Path(image_path).stem 54 | # parent_dir_path = Path(image_path) 55 | # parent_dir_path = image_path.split(image_name)[0] 56 | # os.path.join() 57 | head = os.path.split(image_path)[0] 58 | json_file_tail = f'{image_name}.json' 59 | json_full_path = os.path.join(head,json_file_tail) 60 | print("image_name: ",image_name) 61 | print("json_full_path: ",json_full_path) 62 | isExist = os.path.exists(json_full_path) 63 | if(isExist): 64 | #read metadata from json 65 | metadata_dict = serverHelper.readJson(json_full_path) 66 | 67 | else: 68 | #read metadata from image 69 | #save the metadata to a json file 70 | metadata_dict = getMetadataFromPng(image_path) 71 | serverHelper.writeJson(json_full_path,metadata_dict) 72 | return metadata_dict 73 | 74 | 75 | if __name__ == "__main__": 76 | image_path = "C:/Users/abdul/Desktop/auto-photoshop/Auto-Photoshop-StableDiffusion-Plugin/server/python_server/output/5c42fd2a-6708-45e2-b282-2e9f3894368e/output- 1672476035.4888158.png" 77 | # getMetadataFromPng(image_path) 78 | createMetadataJsonFileIfNotExist(image_path) 79 | -------------------------------------------------------------------------------- /server/python_server/output/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /server/python_server/prompt_shortcut - Copy.json: -------------------------------------------------------------------------------- 1 | { 2 | "painterly_style_1": "A full portrait of a beautiful post apocalyptic offworld arctic explorer, intricate, elegant, highly detailed, digital painting, artstation, concept art, smooth, sharp focus, illustration", 3 | "ugly": " ((((ugly)))), (((duplicate))), ((morbid)), ((mutilated)), out of frame, extra fingers, mutated hands, ((poorly drawn hands)), ((poorly drawn face)), (((mutation))), (((deformed))), ((ugly)), blurry, ((bad anatomy)), (((bad proportions))), ((extra limbs)), cloned face, (((disfigured))), out of frame, ugly, extra limbs, (bad anatomy), gross proportions, (malformed limbs), ((missing arms)), ((missing legs)), (((extra arms))), (((extra legs))), mutated hands, (fused fingers), (too many fingers), (((long neck)))", 4 | "art_style": "(SPACE1999:1.0),(dreamlikeart style:1.0), ( redshift style:1.0), (analog style:1.2), (studio_ghibli_anime_style style:0.7), (copeseethemald style:0.8)", 5 | "woman_style": "woman, 1girls, solo, detailed face, lips, realistic pupils, closeup, centered, standing, centered, skin pores, subsurface scattering, detailed skin", 6 | "environment_style": "detailed background, items, realistic proportions, blushing, masterpiece, best quality, realistic, hyperrealistic, sharp focus, absurdres, good anatomy", 7 | "uniform_style": "space uniform, red, smooth, black belt, black boots", 8 | "man_style": "man, solo, detailed face, lips, realistic pupils, closeup, centered, standing, centered, skin pores, subsurface scattering, detailed skin", 9 | "neg_person": "(glossy:1.0), freckles, nipples, small waist, lowres, large head, long neck, blurry, bad anatomy, bad hands, extra limbs, extra hands, mutated hands, mutated fingers, missing hand, missing finger, text, error, missing fingers, extra digit, fewer digits,", 10 | "neg_general": "cropped, worst quality, low quality, normal quality, jpeg artifacts, text, signature, watermark, artist name, logo,", 11 | "nova_green": "[Julianne Hough:Jaime King:0.5]" 12 | } -------------------------------------------------------------------------------- /server/python_server/prompt_shortcut.py: -------------------------------------------------------------------------------- 1 | import re 2 | import json 3 | prompt_shortcut_dict ={} 4 | 5 | 6 | def readToJson(): 7 | return load() 8 | 9 | def writeToJson(file_name,data_dict): 10 | with open(file_name, "w") as outfile: 11 | json.dump(data_dict, outfile,indent=4) 12 | 13 | 14 | def load(): 15 | global prompt_shortcut_dict 16 | try: 17 | with open('prompt_shortcut.json') as f_obj: 18 | data = json.load(f_obj) 19 | prompt_shortcut_dict = data 20 | print(data) 21 | except IOError: 22 | print("prompt_shortcut.json is not found") 23 | return prompt_shortcut_dict 24 | def find_words_inside_braces(string): 25 | result = "" 26 | pattern ="\{(.*?)\}" 27 | keywords = [] 28 | for match in re.findall(pattern, string): 29 | keywords.append(match) 30 | result += match 31 | return keywords 32 | 33 | # text = "a beautiful girl holding a cute cat {style_1} on sunny day" 34 | # text = "a beautiful girl holding a cute cat { style_1 } on sunny day" 35 | text = "a beautiful girl{ }, {char1}, {painterly_style} holding a cute cat { style_1 } on sunny day" 36 | # text = "a beautiful girl {char1 } holding a cute cat on sunny day" 37 | 38 | 39 | 40 | def replaceShortcut(text,prompt_shortcut_dict): 41 | raw_keywords = find_words_inside_braces(text) 42 | strip_keywords = list(map(lambda s: s.strip(),raw_keywords)) 43 | 44 | original_substrings = list(map(lambda s: '{'+s+'}',raw_keywords)) 45 | 46 | print("raw_keywords: ", raw_keywords) 47 | print("strip_keywords: ", strip_keywords) 48 | print("original_substrings: ",original_substrings) 49 | # print ("text:",text) 50 | 51 | for i, word in enumerate(strip_keywords): 52 | # word = word.strip() 53 | print("word: ",word) 54 | if len(word) > 0 and word in prompt_shortcut_dict: 55 | prompt = prompt_shortcut_dict[word] 56 | print("prompt: ",prompt) 57 | text = text.replace(original_substrings[i],prompt) 58 | # else: 59 | # text = text.replace(word,word.strip()) 60 | print ("final text: ",text) 61 | return text -------------------------------------------------------------------------------- /server/python_server/search.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | try: 4 | from duckduckgo_search import AsyncDDGS 5 | except ImportError: 6 | raise ImportError( 7 | "duckduckgo_search is required to image search. Please install it with `pip install --upgrade duckduckgo_search`." 8 | ) 9 | 10 | 11 | async def imageSearch(keywords="cute cats"): 12 | async with AsyncDDGS() as ddgs: 13 | return [ 14 | x async for x in ddgs.images(keywords, safesearch="off", max_results=50) 15 | ] 16 | 17 | 18 | async def main(): 19 | result = await imageSearch() 20 | print("result: ", result) 21 | # result = await imageSearch2() 22 | # print(result) 23 | 24 | 25 | if __name__ == "__main__": 26 | asyncio.run(main()) 27 | -------------------------------------------------------------------------------- /server/python_server/serverHelper.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | import datetime 4 | import uuid 5 | import json 6 | 7 | # this function should be used whenever we need to write to json file 8 | def writeJson(file_name,data_dict): 9 | with open(file_name, 'w', encoding='utf-8') as outfile: 10 | json.dump(data_dict, outfile, ensure_ascii=False, indent=4) 11 | 12 | 13 | 14 | 15 | # this function should be used whenever we need to read from json file 16 | def readJson(file_name): 17 | data_dict = {} 18 | try: 19 | with open(file_name) as f_obj: 20 | data_dict = json.load(f_obj) 21 | 22 | print("readJson: data_dict: ", data_dict) 23 | except IOError: 24 | print(f"{file_name} is not found") 25 | return data_dict 26 | 27 | def createFolder(fullpath): 28 | print("fullpath:",fullpath) 29 | 30 | if not os.path.exists(fullpath): 31 | os.mkdir(fullpath) 32 | #create string dir path name based on the current time 33 | def makeDirPathName(): 34 | # dirName = f'{time.time()}' 35 | currentDirPath = os.getcwd() 36 | now = datetime.datetime.now() 37 | daily_folder = now.strftime("%Y-%m-%d") 38 | output_path = os.path.join(currentDirPath,"output") 39 | fullpath = os.path.join(output_path,daily_folder) 40 | # fullpath = os.path.join(currentDirPath,dirName) 41 | return fullpath,daily_folder 42 | 43 | #create string dir path name based on the uniqueDocumentId 44 | def getUniqueDocumentDirPathName(uniqueDocumentId): 45 | 46 | currentDirPath = os.getcwd() 47 | output_path = os.path.join(currentDirPath,"output") 48 | fullpath = os.path.join(output_path,uniqueDocumentId) 49 | 50 | return fullpath,uniqueDocumentId 51 | 52 | def makeUniqueID(): 53 | myuuid = uuid.uuid4() 54 | print('Your UUID is: ' + str(myuuid)) 55 | return myuuid 56 | 57 | 58 | if __name__ == "__main__": 59 | # currentDirPath = os.getcwd() 60 | # dirName = f'{time.time()}' 61 | # fullpath = os.path.join(currentDirPath,dirName) 62 | # createFolder(fullpath) 63 | id = makeUniqueID() 64 | print("id: ",id) -------------------------------------------------------------------------------- /thumbnail.js: -------------------------------------------------------------------------------- 1 | class Thumbnail { 2 | static wrapImgInContainer(img, container_style_class) { 3 | const container = document.createElement('div') 4 | container.className = container_style_class 5 | container.appendChild(img) 6 | return container 7 | } 8 | 9 | static addSPButtonToContainer( 10 | container, 11 | button_id, 12 | title, 13 | callbackFunction, 14 | param1 15 | ) { 16 | const elem = document.getElementById(button_id) 17 | const clone = elem.cloneNode(true) 18 | const button = clone 19 | button.style.display = null 20 | button.removeAttribute('id') 21 | button.setAttribute('title', title) 22 | 23 | // Create button element 24 | button.className = 'thumbnail-image-button' 25 | if (callbackFunction.constructor.name === 'AsyncFunction') { 26 | button.addEventListener( 27 | 'click', 28 | async () => await callbackFunction(param1) 29 | ) 30 | } else { 31 | button.addEventListener('click', () => callbackFunction(param1)) 32 | } 33 | 34 | container.appendChild(button) 35 | } 36 | } 37 | 38 | module.exports = { 39 | Thumbnail, 40 | } 41 | -------------------------------------------------------------------------------- /typescripts/@types/changedpi.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'changedpi' 2 | -------------------------------------------------------------------------------- /typescripts/@types/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | import React = require('react') 3 | export const ReactComponent: React.FunctionComponent< 4 | React.SVGProps 5 | > 6 | const src: string 7 | export default src 8 | } 9 | -------------------------------------------------------------------------------- /typescripts/@types/sdapi_py_re.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'sdapi_py_re' { 2 | const exports: any 3 | export = exports 4 | } 5 | -------------------------------------------------------------------------------- /typescripts/@types/uxp.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'uxp' { 2 | // Add type declarations for the uxp module here 3 | export const storage: any 4 | export const versions: any 5 | export const host: any 6 | } 7 | -------------------------------------------------------------------------------- /typescripts/after_detailer/style/after_detailer.css: -------------------------------------------------------------------------------- 1 | /* Style the button that is used to open and close the collapsible content */ 2 | .collapsible { 3 | background-color: #2d2d2d; 4 | 5 | cursor: pointer; 6 | padding: 3px; 7 | 8 | border: none; 9 | text-align: left; 10 | outline: none; 11 | font-size: 15px; 12 | font-weight: 500; 13 | color: #eaeaea; 14 | 15 | display: flex; 16 | justify-content: space-between; 17 | width: 100%; 18 | } 19 | 20 | /* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */ 21 | .collapsible-active, 22 | .collapsible:hover { 23 | background-color: #1f1f1f; 24 | } 25 | 26 | .triangle { 27 | background-color: transparent; 28 | } 29 | 30 | .truncate { 31 | white-space: nowrap; 32 | overflow: hidden; 33 | text-overflow: ellipsis; 34 | } 35 | 36 | .minimal-checkbox { 37 | margin: 0; 38 | padding: 0; 39 | border: none; 40 | } 41 | -------------------------------------------------------------------------------- /typescripts/comfyui/native_workflows/IPAdapter_simple_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "8": { 3 | "inputs": { 4 | "samples": [ 5 | "50", 6 | 0 7 | ], 8 | "vae": [ 9 | "32", 10 | 0 11 | ] 12 | }, 13 | "class_type": "VAEDecode" 14 | }, 15 | "14": { 16 | "inputs": { 17 | "ckpt_name": "dreamshaper_8.safetensors" 18 | }, 19 | "class_type": "CheckpointLoaderSimple" 20 | }, 21 | "32": { 22 | "inputs": { 23 | "vae_name": "vae-ft-mse-840000-ema-pruned.safetensors" 24 | }, 25 | "class_type": "VAELoader" 26 | }, 27 | "50": { 28 | "inputs": { 29 | "add_noise": "enable", 30 | "noise_seed": 538408362410054, 31 | "steps": 30, 32 | "cfg": 7, 33 | "sampler_name": "dpmpp_2m", 34 | "scheduler": "karras", 35 | "start_at_step": 0, 36 | "end_at_step": 10000, 37 | "return_with_leftover_noise": "disable", 38 | "model": [ 39 | "210", 40 | 0 41 | ], 42 | "positive": [ 43 | "211", 44 | 0 45 | ], 46 | "negative": [ 47 | "212", 48 | 0 49 | ], 50 | "latent_image": [ 51 | "95", 52 | 0 53 | ] 54 | }, 55 | "class_type": "KSamplerAdvanced" 56 | }, 57 | "95": { 58 | "inputs": { 59 | "width": 512, 60 | "height": 512, 61 | "batch_size": 1 62 | }, 63 | "class_type": "EmptyLatentImage" 64 | }, 65 | "192": { 66 | "inputs": { 67 | "images": [ 68 | "8", 69 | 0 70 | ] 71 | }, 72 | "class_type": "PreviewImage" 73 | }, 74 | "204": { 75 | "inputs": { 76 | "weight": 0.5, 77 | "noise": 0.33, 78 | "weight_type": "original", 79 | "start_at": 0, 80 | "end_at": 1, 81 | "ipadapter": [ 82 | "205", 83 | 0 84 | ], 85 | "clip_vision": [ 86 | "206", 87 | 0 88 | ], 89 | "image": [ 90 | "207", 91 | 0 92 | ], 93 | "model": [ 94 | "14", 95 | 0 96 | ] 97 | }, 98 | "class_type": "IPAdapterApply" 99 | }, 100 | "205": { 101 | "inputs": { 102 | "ipadapter_file": "ip-adapter-plus_sd15.bin" 103 | }, 104 | "class_type": "IPAdapterModelLoader" 105 | }, 106 | "206": { 107 | "inputs": { 108 | "clip_name": "model.safetensors" 109 | }, 110 | "class_type": "CLIPVisionLoader" 111 | }, 112 | "207": { 113 | "inputs": { 114 | "interpolation": "LANCZOS", 115 | "crop_position": "top", 116 | "sharpening": 0.15, 117 | "image": [ 118 | "209", 119 | 0 120 | ] 121 | }, 122 | "class_type": "PrepImageForClipVision" 123 | }, 124 | "209": { 125 | "inputs": { 126 | "image": "ComfyUI_temp_cqoqp_00001_ (1).png", 127 | "choose file to upload": "image" 128 | }, 129 | "class_type": "LoadImage" 130 | }, 131 | "210": { 132 | "inputs": { 133 | "block_number": 3, 134 | "downscale_factor": 1.5, 135 | "start_percent": 0, 136 | "end_percent": 0.45, 137 | "downscale_after_skip": true, 138 | "downscale_method": "bicubic", 139 | "upscale_method": "bicubic", 140 | "model": [ 141 | "204", 142 | 0 143 | ] 144 | }, 145 | "class_type": "PatchModelAddDownscale" 146 | }, 147 | "211": { 148 | "inputs": { 149 | "text": "", 150 | "clip": [ 151 | "14", 152 | 1 153 | ] 154 | }, 155 | "class_type": "CLIPTextEncode" 156 | }, 157 | "212": { 158 | "inputs": { 159 | "text": "blurry, low quality", 160 | "clip": [ 161 | "14", 162 | 1 163 | ] 164 | }, 165 | "class_type": "CLIPTextEncode" 166 | } 167 | } -------------------------------------------------------------------------------- /typescripts/comfyui/native_workflows/IPAdapter_weighted_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": { 3 | "inputs": { 4 | "ckpt_name": "dreamshaper_8.safetensors" 5 | }, 6 | "class_type": "CheckpointLoaderSimple" 7 | }, 8 | "2": { 9 | "inputs": { 10 | "vae_name": "vae-ft-mse-840000-ema-pruned.safetensors" 11 | }, 12 | "class_type": "VAELoader" 13 | }, 14 | "3": { 15 | "inputs": { 16 | "ipadapter_file": "ip-adapter-plus_sd15.bin" 17 | }, 18 | "class_type": "IPAdapterModelLoader" 19 | }, 20 | "4": { 21 | "inputs": { 22 | "clip_name": "model.safetensors" 23 | }, 24 | "class_type": "CLIPVisionLoader" 25 | }, 26 | "6": { 27 | "inputs": { 28 | "image": "ComfyUI_temp_cqoqp_00001_ (1).png", 29 | "choose file to upload": "image" 30 | }, 31 | "class_type": "LoadImage" 32 | }, 33 | "7": { 34 | "inputs": { 35 | "text": "beautiful renaissance girl, detailed", 36 | "clip": [ 37 | "1", 38 | 1 39 | ] 40 | }, 41 | "class_type": "CLIPTextEncode" 42 | }, 43 | "8": { 44 | "inputs": { 45 | "text": "blurry, horror", 46 | "clip": [ 47 | "1", 48 | 1 49 | ] 50 | }, 51 | "class_type": "CLIPTextEncode" 52 | }, 53 | "9": { 54 | "inputs": { 55 | "seed": 857545940756658, 56 | "steps": 35, 57 | "cfg": 5, 58 | "sampler_name": "ddim", 59 | "scheduler": "ddim_uniform", 60 | "denoise": 1, 61 | "model": [ 62 | "13", 63 | 0 64 | ], 65 | "positive": [ 66 | "7", 67 | 0 68 | ], 69 | "negative": [ 70 | "8", 71 | 0 72 | ], 73 | "latent_image": [ 74 | "10", 75 | 0 76 | ] 77 | }, 78 | "class_type": "KSampler" 79 | }, 80 | "10": { 81 | "inputs": { 82 | "width": 512, 83 | "height": 512, 84 | "batch_size": 4 85 | }, 86 | "class_type": "EmptyLatentImage" 87 | }, 88 | "11": { 89 | "inputs": { 90 | "samples": [ 91 | "9", 92 | 0 93 | ], 94 | "vae": [ 95 | "2", 96 | 0 97 | ] 98 | }, 99 | "class_type": "VAEDecode" 100 | }, 101 | "12": { 102 | "inputs": { 103 | "filename_prefix": "IPAdapter", 104 | "images": [ 105 | "11", 106 | 0 107 | ] 108 | }, 109 | "class_type": "SaveImage" 110 | }, 111 | "13": { 112 | "inputs": { 113 | "weight": 1, 114 | "weight_type": "original", 115 | "start_at": 0, 116 | "end_at": 1, 117 | "ipadapter": [ 118 | "3", 119 | 0 120 | ], 121 | "embeds": [ 122 | "14", 123 | 0 124 | ], 125 | "model": [ 126 | "1", 127 | 0 128 | ] 129 | }, 130 | "class_type": "IPAdapterApplyEncoded" 131 | }, 132 | "14": { 133 | "inputs": { 134 | "ipadapter_plus": true, 135 | "noise": 0.31, 136 | "weight_1": [ 137 | "16", 138 | 0 139 | ], 140 | "weight_2": [ 141 | "17", 142 | 0 143 | ], 144 | "weight_3": 1, 145 | "weight_4": 1, 146 | "clip_vision": [ 147 | "4", 148 | 0 149 | ], 150 | "image_1": [ 151 | "15", 152 | 0 153 | ], 154 | "image_2": [ 155 | "6", 156 | 0 157 | ] 158 | }, 159 | "class_type": "IPAdapterEncoder" 160 | }, 161 | "15": { 162 | "inputs": { 163 | "image": "animation-deku-my-hero-academia.jpg", 164 | "choose file to upload": "image" 165 | }, 166 | "class_type": "LoadImage" 167 | }, 168 | "16": { 169 | "inputs": { 170 | "Value": 1 171 | }, 172 | "class_type": "Float" 173 | }, 174 | "17": { 175 | "inputs": { 176 | "Value": 0.38 177 | }, 178 | "class_type": "Float" 179 | } 180 | } -------------------------------------------------------------------------------- /typescripts/comfyui/native_workflows/animatediff_lcm_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "2": { 3 | "inputs": { 4 | "vae_name": "vae-ft-mse-840000-ema-pruned.safetensors" 5 | }, 6 | "class_type": "VAELoader" 7 | }, 8 | "4": { 9 | "inputs": { 10 | "stop_at_clip_layer": -1, 11 | "clip": [ 12 | "32", 13 | 1 14 | ] 15 | }, 16 | "class_type": "CLIPSetLastLayer" 17 | }, 18 | "6": { 19 | "inputs": { 20 | "text": "embedding:BadDream, ", 21 | "clip": [ 22 | "4", 23 | 0 24 | ] 25 | }, 26 | "class_type": "CLIPTextEncode" 27 | }, 28 | "7": { 29 | "inputs": { 30 | "seed": 888888891, 31 | "steps": 8, 32 | "cfg": 1.5, 33 | "sampler_name": "lcm", 34 | "scheduler": "sgm_uniform", 35 | "denoise": 1, 36 | "model": [ 37 | "36", 38 | 0 39 | ], 40 | "positive": [ 41 | "38", 42 | 0 43 | ], 44 | "negative": [ 45 | "6", 46 | 0 47 | ], 48 | "latent_image": [ 49 | "9", 50 | 0 51 | ] 52 | }, 53 | "class_type": "KSampler" 54 | }, 55 | "9": { 56 | "inputs": { 57 | "width": 512, 58 | "height": 512, 59 | "batch_size": 110 60 | }, 61 | "class_type": "EmptyLatentImage" 62 | }, 63 | "10": { 64 | "inputs": { 65 | "samples": [ 66 | "7", 67 | 0 68 | ], 69 | "vae": [ 70 | "2", 71 | 0 72 | ] 73 | }, 74 | "class_type": "VAEDecode" 75 | }, 76 | "32": { 77 | "inputs": { 78 | "ckpt_name": "dreamshaper_8.safetensors" 79 | }, 80 | "class_type": "CheckpointLoaderSimple" 81 | }, 82 | "33": { 83 | "inputs": { 84 | "context_length": 16, 85 | "context_stride": 1, 86 | "context_overlap": 4, 87 | "context_schedule": "uniform", 88 | "closed_loop": false 89 | }, 90 | "class_type": "ADE_AnimateDiffUniformContextOptions" 91 | }, 92 | "36": { 93 | "inputs": { 94 | "model_name": "mm_sd_v15_v2.ckpt", 95 | "beta_schedule": "sqrt_linear (AnimateDiff)", 96 | "motion_scale": 1, 97 | "apply_v2_models_properly": false, 98 | "model": [ 99 | "42", 100 | 0 101 | ], 102 | "context_options": [ 103 | "33", 104 | 0 105 | ] 106 | }, 107 | "class_type": "ADE_AnimateDiffLoaderWithContext" 108 | }, 109 | "37": { 110 | "inputs": { 111 | "frame_rate": 8, 112 | "loop_count": 0, 113 | "filename_prefix": "aaa_readme", 114 | "format": "image/gif", 115 | "pingpong": false, 116 | "save_image": true, 117 | "crf": 20, 118 | "save_metadata": true, 119 | "videopreview": { 120 | "hidden": false, 121 | "paused": false, 122 | "params": { 123 | "filename": "aaa_readme_00024.gif", 124 | "subfolder": "", 125 | "type": "output", 126 | "format": "image/gif" 127 | } 128 | }, 129 | "images": [ 130 | "10", 131 | 0 132 | ] 133 | }, 134 | "class_type": "VHS_VideoCombine" 135 | }, 136 | "38": { 137 | "inputs": { 138 | "text": "\"0\" : \"Spring, flowers, smile\",\n\"20\" : \"Spring, flowers, smile\",\n\"30\" : \"Summer, sun, happy, windy\",\n\"50\" : \"Summer, sun, happy, windy\",\n\"60\" : \"Autumn, yellow leaves, laugh\",\n\"80\" : \"Autumn, yellow leaves, laugh\",\n\"90\" : \"Winter, wind, snow, smile, seductive\",\n\"110\" : \"Winter, wind snow, smile, seductive\"", 139 | "max_frames": 110, 140 | "print_output": false, 141 | "pre_text": "25 year old woman, t-shirt", 142 | "app_text": "", 143 | "start_frame": 0, 144 | "pw_a": 0, 145 | "pw_b": 0, 146 | "pw_c": 0, 147 | "pw_d": 0, 148 | "clip": [ 149 | "4", 150 | 0 151 | ] 152 | }, 153 | "class_type": "BatchPromptSchedule" 154 | }, 155 | "41": { 156 | "inputs": { 157 | "lora_name": "lcm_lora_sd15.safetensors", 158 | "strength_model": 1, 159 | "strength_clip": 1, 160 | "model": [ 161 | "32", 162 | 0 163 | ], 164 | "clip": [ 165 | "32", 166 | 1 167 | ] 168 | }, 169 | "class_type": "LoraLoader" 170 | }, 171 | "42": { 172 | "inputs": { 173 | "sampling": "lcm", 174 | "zsnr": false, 175 | "model": [ 176 | "41", 177 | 0 178 | ] 179 | }, 180 | "class_type": "ModelSamplingDiscrete" 181 | } 182 | } -------------------------------------------------------------------------------- /typescripts/comfyui/native_workflows/animatediff_simple_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "2": { 3 | "inputs": { 4 | "vae_name": "vae-ft-mse-840000-ema-pruned.safetensors" 5 | }, 6 | "class_type": "VAELoader" 7 | }, 8 | "3": { 9 | "inputs": { 10 | "text": "girl astronaut walking on the moon. ", 11 | "clip": [ 12 | "4", 13 | 0 14 | ] 15 | }, 16 | "class_type": "CLIPTextEncode" 17 | }, 18 | "4": { 19 | "inputs": { 20 | "stop_at_clip_layer": -2, 21 | "clip": [ 22 | "32", 23 | 1 24 | ] 25 | }, 26 | "class_type": "CLIPSetLastLayer" 27 | }, 28 | "6": { 29 | "inputs": { 30 | "text": "(worst quality, low quality: 1.4)", 31 | "clip": [ 32 | "4", 33 | 0 34 | ] 35 | }, 36 | "class_type": "CLIPTextEncode" 37 | }, 38 | "7": { 39 | "inputs": { 40 | "seed": 888888889, 41 | "steps": 20, 42 | "cfg": 8, 43 | "sampler_name": "euler", 44 | "scheduler": "normal", 45 | "denoise": 1, 46 | "model": [ 47 | "27", 48 | 0 49 | ], 50 | "positive": [ 51 | "3", 52 | 0 53 | ], 54 | "negative": [ 55 | "6", 56 | 0 57 | ], 58 | "latent_image": [ 59 | "9", 60 | 0 61 | ] 62 | }, 63 | "class_type": "KSampler" 64 | }, 65 | "9": { 66 | "inputs": { 67 | "width": 512, 68 | "height": 512, 69 | "batch_size": 16 70 | }, 71 | "class_type": "EmptyLatentImage" 72 | }, 73 | "10": { 74 | "inputs": { 75 | "samples": [ 76 | "7", 77 | 0 78 | ], 79 | "vae": [ 80 | "2", 81 | 0 82 | ] 83 | }, 84 | "class_type": "VAEDecode" 85 | }, 86 | "27": { 87 | "inputs": { 88 | "model_name": "mm_sd_v14.ckpt", 89 | "beta_schedule": "sqrt_linear (AnimateDiff)", 90 | "motion_scale": 1, 91 | "apply_v2_models_properly": false, 92 | "model": [ 93 | "32", 94 | 0 95 | ] 96 | }, 97 | "class_type": "ADE_AnimateDiffLoaderWithContext" 98 | }, 99 | "32": { 100 | "inputs": { 101 | "ckpt_name": "cardosAnime_v20.safetensors" 102 | }, 103 | "class_type": "CheckpointLoaderSimple" 104 | }, 105 | "35": { 106 | "inputs": { 107 | "frame_rate": 8, 108 | "loop_count": 0, 109 | "filename_prefix": "aaa_readme", 110 | "format": "image/gif", 111 | "pingpong": false, 112 | "save_image": true, 113 | "crf": 20, 114 | "save_metadata": false, 115 | "videopreview": { 116 | "hidden": false, 117 | "paused": false, 118 | "params": { 119 | "filename": "aaa_readme_00022.gif", 120 | "subfolder": "", 121 | "type": "output", 122 | "format": "image/gif" 123 | } 124 | }, 125 | "images": [ 126 | "10", 127 | 0 128 | ] 129 | }, 130 | "class_type": "VHS_VideoCombine" 131 | }, 132 | "37": { 133 | "inputs": { 134 | "images": [ 135 | "10", 136 | 0 137 | ] 138 | }, 139 | "class_type": "PreviewImage" 140 | } 141 | } -------------------------------------------------------------------------------- /typescripts/comfyui/native_workflows/real_time_lcm_img2img_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "6": { 3 | "inputs": { 4 | "text": "cute girl", 5 | "clip": [ 6 | "38", 7 | 1 8 | ] 9 | }, 10 | "class_type": "CLIPTextEncode" 11 | }, 12 | "20": { 13 | "inputs": { 14 | "ckpt_name": "aniverse_v15Pruned.safetensors" 15 | }, 16 | "class_type": "CheckpointLoaderSimple" 17 | }, 18 | "30": { 19 | "inputs": { 20 | "seed": 951163705423093, 21 | "steps": 4, 22 | "cfg": 1, 23 | "sampler_name": "lcm", 24 | "scheduler": "sgm_uniform", 25 | "denoise": 0.5, 26 | "model": [ 27 | "38", 28 | 0 29 | ], 30 | "positive": [ 31 | "6", 32 | 0 33 | ], 34 | "negative": [ 35 | "36", 36 | 0 37 | ], 38 | "latent_image": [ 39 | "40", 40 | 0 41 | ] 42 | }, 43 | "class_type": "KSampler" 44 | }, 45 | "31": { 46 | "inputs": { 47 | "samples": [ 48 | "30", 49 | 0 50 | ], 51 | "vae": [ 52 | "20", 53 | 2 54 | ] 55 | }, 56 | "class_type": "VAEDecode" 57 | }, 58 | "32": { 59 | "inputs": { 60 | "images": [ 61 | "31", 62 | 0 63 | ] 64 | }, 65 | "class_type": "PreviewImage" 66 | }, 67 | "36": { 68 | "inputs": { 69 | "text": "", 70 | "clip": [ 71 | "20", 72 | 1 73 | ] 74 | }, 75 | "class_type": "CLIPTextEncode" 76 | }, 77 | "38": { 78 | "inputs": { 79 | "lora_name": "lcm_lora_sd15.safetensors", 80 | "strength_model": 1, 81 | "strength_clip": 1, 82 | "model": [ 83 | "20", 84 | 0 85 | ], 86 | "clip": [ 87 | "20", 88 | 1 89 | ] 90 | }, 91 | "class_type": "Load Lora" 92 | }, 93 | "39": { 94 | "inputs": { 95 | "image": "output_image.png.png", 96 | "upload": "image" 97 | }, 98 | "class_type": "LoadImage" 99 | }, 100 | "40": { 101 | "inputs": { 102 | "pixels": [ 103 | "41", 104 | 0 105 | ], 106 | "vae": [ 107 | "20", 108 | 2 109 | ] 110 | }, 111 | "class_type": "VAEEncode" 112 | }, 113 | "41": { 114 | "inputs": { 115 | "side_length": 512, 116 | "side": "Longest", 117 | "upscale_method": "nearest-exact", 118 | "crop": "disabled", 119 | "image": [ 120 | "39", 121 | 0 122 | ] 123 | }, 124 | "class_type": "Image scale to side" 125 | } 126 | } -------------------------------------------------------------------------------- /typescripts/comfyui/native_workflows/real_time_lcm_sketching_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "6": { 3 | "inputs": { 4 | "text": "", 5 | "clip": [ 6 | "38", 7 | 1 8 | ] 9 | }, 10 | "class_type": "CLIPTextEncode" 11 | }, 12 | "20": { 13 | "inputs": { 14 | "ckpt_name": "aniverse_v15Pruned.safetensors" 15 | }, 16 | "class_type": "CheckpointLoaderSimple" 17 | }, 18 | "30": { 19 | "inputs": { 20 | "seed": [ 21 | "70", 22 | 0 23 | ], 24 | "steps": 4, 25 | "cfg": 1, 26 | "sampler_name": "lcm", 27 | "scheduler": "sgm_uniform", 28 | "denoise": 1, 29 | "model": [ 30 | "38", 31 | 0 32 | ], 33 | "positive": [ 34 | "74", 35 | 1 36 | ], 37 | "negative": [ 38 | "74", 39 | 2 40 | ], 41 | "latent_image": [ 42 | "46", 43 | 0 44 | ] 45 | }, 46 | "class_type": "KSampler" 47 | }, 48 | "31": { 49 | "inputs": { 50 | "samples": [ 51 | "30", 52 | 0 53 | ], 54 | "vae": [ 55 | "20", 56 | 2 57 | ] 58 | }, 59 | "class_type": "VAEDecode" 60 | }, 61 | "32": { 62 | "inputs": { 63 | "images": [ 64 | "31", 65 | 0 66 | ] 67 | }, 68 | "class_type": "PreviewImage" 69 | }, 70 | "36": { 71 | "inputs": { 72 | "text": "(nsfw:1.2), (nude:1.2)", 73 | "clip": [ 74 | "20", 75 | 1 76 | ] 77 | }, 78 | "class_type": "CLIPTextEncode" 79 | }, 80 | "38": { 81 | "inputs": { 82 | "lora_name": "lcm_lora_sd15.safetensors", 83 | "strength_model": 1, 84 | "strength_clip": 1, 85 | "model": [ 86 | "20", 87 | 0 88 | ], 89 | "clip": [ 90 | "20", 91 | 1 92 | ] 93 | }, 94 | "class_type": "Load Lora" 95 | }, 96 | "46": { 97 | "inputs": { 98 | "width": [ 99 | "51", 100 | 0 101 | ], 102 | "height": [ 103 | "51", 104 | 1 105 | ], 106 | "batch_size": 1 107 | }, 108 | "class_type": "EmptyLatentImage" 109 | }, 110 | "47": { 111 | "inputs": { 112 | "image": "pasted/image (14).png", 113 | "upload": "image" 114 | }, 115 | "class_type": "LoadImage" 116 | }, 117 | "51": { 118 | "inputs": { 119 | "image": [ 120 | "53", 121 | 0 122 | ] 123 | }, 124 | "class_type": "Get image size" 125 | }, 126 | "53": { 127 | "inputs": { 128 | "side_length": [ 129 | "57", 130 | 0 131 | ], 132 | "side": "Longest", 133 | "upscale_method": "nearest-exact", 134 | "crop": "disabled", 135 | "image": [ 136 | "73", 137 | 0 138 | ] 139 | }, 140 | "class_type": "Image scale to side" 141 | }, 142 | "57": { 143 | "inputs": { 144 | "Value": 512 145 | }, 146 | "class_type": "Integer" 147 | }, 148 | "59": { 149 | "inputs": { 150 | "seed": [ 151 | "70", 152 | 0 153 | ], 154 | "steps": 8, 155 | "cfg": 1, 156 | "sampler_name": "lcm", 157 | "scheduler": "sgm_uniform", 158 | "denoise": 0.5, 159 | "model": [ 160 | "38", 161 | 0 162 | ], 163 | "positive": [ 164 | "6", 165 | 0 166 | ], 167 | "negative": [ 168 | "36", 169 | 0 170 | ], 171 | "latent_image": [ 172 | "65", 173 | 0 174 | ] 175 | }, 176 | "class_type": "KSampler" 177 | }, 178 | "63": { 179 | "inputs": { 180 | "samples": [ 181 | "59", 182 | 0 183 | ], 184 | "vae": [ 185 | "20", 186 | 2 187 | ] 188 | }, 189 | "class_type": "VAEDecode" 190 | }, 191 | "64": { 192 | "inputs": { 193 | "images": [ 194 | "63", 195 | 0 196 | ] 197 | }, 198 | "class_type": "PreviewImage" 199 | }, 200 | "65": { 201 | "inputs": { 202 | "upscale_method": "nearest-exact", 203 | "scale_by": 1.5, 204 | "samples": [ 205 | "30", 206 | 0 207 | ] 208 | }, 209 | "class_type": "LatentUpscaleBy" 210 | }, 211 | "70": { 212 | "inputs": { 213 | "seed": 412914567948332 214 | }, 215 | "class_type": "APS_Seed" 216 | }, 217 | "73": { 218 | "inputs": { 219 | "image": [ 220 | "47", 221 | 0 222 | ] 223 | }, 224 | "class_type": "ImageInvert" 225 | }, 226 | "74": { 227 | "inputs": { 228 | "preprocessor_name": "ScribblePreprocessor", 229 | "control_net_name": "control_lora_rank128_v11p_sd15_scribble_fp16.safetensors", 230 | "strength": 1, 231 | "start_percent": 0, 232 | "end_percent": 1, 233 | "resolution": [ 234 | "57", 235 | 0 236 | ], 237 | "threshold_a": 0, 238 | "threshold_b": 0, 239 | "positive": [ 240 | "6", 241 | 0 242 | ], 243 | "negative": [ 244 | "36", 245 | 0 246 | ], 247 | "image": [ 248 | "53", 249 | 0 250 | ] 251 | }, 252 | "class_type": "ControlnetUnit" 253 | }, 254 | "75": { 255 | "inputs": { 256 | "images": [ 257 | "74", 258 | 0 259 | ] 260 | }, 261 | "class_type": "PreviewImage" 262 | } 263 | } -------------------------------------------------------------------------------- /typescripts/comfyui/native_workflows/real_time_lcm_txt2img_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "6": { 3 | "inputs": { 4 | "text": "cute girl", 5 | "clip": [ 6 | "38", 7 | 1 8 | ] 9 | }, 10 | "class_type": "CLIPTextEncode" 11 | }, 12 | "20": { 13 | "inputs": { 14 | "ckpt_name": "aniverse_v15Pruned.safetensors" 15 | }, 16 | "class_type": "CheckpointLoaderSimple" 17 | }, 18 | "30": { 19 | "inputs": { 20 | "seed": 951163705423093, 21 | "steps": 4, 22 | "cfg": 1, 23 | "sampler_name": "lcm", 24 | "scheduler": "sgm_uniform", 25 | "denoise": 1, 26 | "model": [ 27 | "38", 28 | 0 29 | ], 30 | "positive": [ 31 | "6", 32 | 0 33 | ], 34 | "negative": [ 35 | "36", 36 | 0 37 | ], 38 | "latent_image": [ 39 | "37", 40 | 0 41 | ] 42 | }, 43 | "class_type": "KSampler" 44 | }, 45 | "31": { 46 | "inputs": { 47 | "samples": [ 48 | "30", 49 | 0 50 | ], 51 | "vae": [ 52 | "20", 53 | 2 54 | ] 55 | }, 56 | "class_type": "VAEDecode" 57 | }, 58 | "32": { 59 | "inputs": { 60 | "images": [ 61 | "31", 62 | 0 63 | ] 64 | }, 65 | "class_type": "PreviewImage" 66 | }, 67 | "36": { 68 | "inputs": { 69 | "text": "", 70 | "clip": [ 71 | "20", 72 | 1 73 | ] 74 | }, 75 | "class_type": "CLIPTextEncode" 76 | }, 77 | "37": { 78 | "inputs": { 79 | "width": 512, 80 | "height": 512, 81 | "batch_size": 1 82 | }, 83 | "class_type": "EmptyLatentImage" 84 | }, 85 | "38": { 86 | "inputs": { 87 | "lora_name": "lcm_lora_sd15.safetensors", 88 | "strength_model": 1, 89 | "strength_clip": 1, 90 | "model": [ 91 | "20", 92 | 0 93 | ], 94 | "clip": [ 95 | "20", 96 | 1 97 | ] 98 | }, 99 | "class_type": "Load Lora" 100 | } 101 | } -------------------------------------------------------------------------------- /typescripts/comfyui/native_workflows/sdxl_turbo_txt2img_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "5": { 3 | "inputs": { 4 | "width": 512, 5 | "height": 512, 6 | "batch_size": 1 7 | }, 8 | "class_type": "EmptyLatentImage" 9 | }, 10 | "6": { 11 | "inputs": { 12 | "text": "beautiful landscape scenery glass bottle with a galaxy inside cute fennec fox snow HDR sunset", 13 | "clip": [ 14 | "20", 15 | 1 16 | ] 17 | }, 18 | "class_type": "CLIPTextEncode" 19 | }, 20 | "7": { 21 | "inputs": { 22 | "text": "text, watermark", 23 | "clip": [ 24 | "20", 25 | 1 26 | ] 27 | }, 28 | "class_type": "CLIPTextEncode" 29 | }, 30 | "8": { 31 | "inputs": { 32 | "samples": [ 33 | "13", 34 | 0 35 | ], 36 | "vae": [ 37 | "20", 38 | 2 39 | ] 40 | }, 41 | "class_type": "VAEDecode" 42 | }, 43 | "13": { 44 | "inputs": { 45 | "add_noise": true, 46 | "noise_seed": 0, 47 | "cfg": 1, 48 | "model": [ 49 | "20", 50 | 0 51 | ], 52 | "positive": [ 53 | "6", 54 | 0 55 | ], 56 | "negative": [ 57 | "7", 58 | 0 59 | ], 60 | "sampler": [ 61 | "14", 62 | 0 63 | ], 64 | "sigmas": [ 65 | "22", 66 | 0 67 | ], 68 | "latent_image": [ 69 | "5", 70 | 0 71 | ] 72 | }, 73 | "class_type": "SamplerCustom" 74 | }, 75 | "14": { 76 | "inputs": { 77 | "sampler_name": "euler_ancestral" 78 | }, 79 | "class_type": "KSamplerSelect" 80 | }, 81 | "20": { 82 | "inputs": { 83 | "ckpt_name": "sd_xl_turbo_1.0_fp16.safetensors" 84 | }, 85 | "class_type": "CheckpointLoaderSimple" 86 | }, 87 | "22": { 88 | "inputs": { 89 | "steps": 1, 90 | "model": [ 91 | "20", 92 | 0 93 | ] 94 | }, 95 | "class_type": "SDTurboScheduler" 96 | }, 97 | "25": { 98 | "inputs": { 99 | "images": [ 100 | "8", 101 | 0 102 | ] 103 | }, 104 | "class_type": "PreviewImage" 105 | } 106 | } -------------------------------------------------------------------------------- /typescripts/controlnet/main.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom/client' 2 | import React from 'react' 3 | import ControlNetTab from './ControlNetTab' 4 | import store from './store' 5 | import { versionCompare } from './util' 6 | import { Collapsible } from '../util/collapsible' 7 | import Locale from '../locale/locale' 8 | import { ErrorBoundary } from '../util/errorBoundary' 9 | 10 | const elem = document.getElementById('sp-control_net-tab-page') 11 | const elem2 = document.getElementById('sp-control_net-tab-page2') 12 | 13 | if (elem) { 14 | const root = ReactDOM.createRoot(elem) 15 | root.render( 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | if (elem2) { 23 | const root = ReactDOM.createRoot(elem2) 24 | root.render( 25 | // 26 | 27 |
33 | 37 |
41 | 42 |
43 |
44 |
45 |
46 | //
47 | ) 48 | } 49 | function scrollToEnabledControlNetUnit() {} 50 | 51 | // const button = document.getElementById('scrollToControlNetUnitContainer')! 52 | // const button_root = ReactDOM.createRoot(button) 53 | 54 | // button_root.render() 55 | 56 | export { versionCompare } 57 | -------------------------------------------------------------------------------- /typescripts/controlnet/store.ts: -------------------------------------------------------------------------------- 1 | import { observable, reaction } from 'mobx' 2 | import { SelectionInfoType } from '../util/ts/enum' 3 | type ResizeMode = 'Just Resize' | 'Crop and Resize' | 'Resize and Fill' 4 | export const controlnetModes = [ 5 | 'Balanced', 6 | 'My prompt is more important', 7 | 'ControlNet is more important', 8 | ] as const 9 | export type ControlnetMode = (typeof controlnetModes)[number] 10 | export const DefaultControlNetUnitData = { 11 | enabled: false, 12 | input_image: '', 13 | mask: '', 14 | detect_map: '', 15 | module: '', 16 | model: '', 17 | weight: 1.0, 18 | resize_mode: 'Crop and Resize' as ResizeMode, 19 | lowvram: true, 20 | processor_res: 512, 21 | threshold_a: 0, 22 | threshold_b: 0, 23 | 24 | guidance_start: 0, 25 | guidance_end: 1, 26 | guessmode: false, 27 | 28 | control_mode: 'Balanced' as ControlnetMode, 29 | pixel_perfect: true, 30 | auto_image: true, 31 | } 32 | 33 | export const DefaultPresetControlNetUnitData = { 34 | enabled: false, 35 | // input_image: '', 36 | // mask: '', 37 | // detect_map: '', 38 | module: 'none', 39 | model: 'None', 40 | filter_keyword: 'All', 41 | weight: 1.0, 42 | 43 | resize_mode: 'Crop and Resize' as ResizeMode, 44 | 45 | lowvram: true, 46 | 47 | processor_res: 512, 48 | threshold_a: 0, 49 | threshold_b: 0, 50 | 51 | guidance_start: 0, 52 | guidance_end: 1, 53 | guessmode: false, 54 | 55 | control_mode: 'Balanced' as ControlnetMode, 56 | pixel_perfect: true, 57 | auto_image: true, 58 | } 59 | 60 | export interface controlNetUnitData { 61 | enabled: boolean 62 | input_image: string 63 | mask: string 64 | detect_map: string 65 | module_list: string[] 66 | model_list: string[] 67 | module: string 68 | model: string 69 | filter_keyword: string 70 | weight: number 71 | resize_mode: ResizeMode 72 | lowvram: boolean 73 | processor_res: number 74 | threshold_a: number 75 | threshold_b: number 76 | 77 | guidance_start: number 78 | guidance_end: number 79 | guessmode: boolean 80 | 81 | control_mode: ControlnetMode 82 | pixel_perfect: boolean 83 | auto_image: boolean // sync CtrlNet image with sd input image 84 | selection_info: SelectionInfoType 85 | } 86 | interface ControlNetMobxStore { 87 | disableControlNetTab: boolean 88 | maxControlNet: number 89 | controlnetApiVersion: number 90 | 91 | supportedModels: string[] 92 | supportedPreprocessors: string[] 93 | filterKeywords: string[] 94 | preprocessorDetail: { [key: string]: any } 95 | 96 | controlNetUnitData: controlNetUnitData[] 97 | } 98 | 99 | var ControlNetStore = observable({ 100 | disableControlNetTab: false, 101 | maxControlNet: 0, 102 | controlnetApiVersion: 1, 103 | 104 | supportedModels: [], 105 | supportedPreprocessors: [], 106 | filterKeywords: [], 107 | preprocessorDetail: {}, 108 | 109 | controlNetUnitData: [], 110 | }) 111 | 112 | reaction( 113 | () => { 114 | return ControlNetStore.controlNetUnitData.map((data) => data.module) 115 | }, 116 | (module_, index) => { 117 | ControlNetStore.controlNetUnitData.forEach((data, index) => { 118 | const pd = ControlNetStore.preprocessorDetail[module_[index]] || {} 119 | const pSlider = pd.sliders || [] 120 | data.processor_res = pSlider[0]?.value || 512 121 | data.threshold_a = pSlider[1]?.value || 0 122 | data.threshold_b = pSlider[2]?.value || 0 123 | }) 124 | } 125 | ) 126 | reaction( 127 | () => ControlNetStore.maxControlNet, 128 | (maxControlNet) => { 129 | ControlNetStore.controlNetUnitData = Array(maxControlNet) 130 | .fill(0) 131 | .map((v, index) => { 132 | return ( 133 | ControlNetStore.controlNetUnitData[index] || 134 | DefaultControlNetUnitData 135 | ) 136 | }) 137 | } 138 | ) 139 | 140 | reaction( 141 | () => { 142 | return ControlNetStore.controlNetUnitData.map( 143 | (data) => data.filter_keyword 144 | ) 145 | }, 146 | (filter_keyword_, index) => { 147 | ControlNetStore.controlNetUnitData.forEach((data, index) => { 148 | if (filter_keyword_[index] === 'none') { 149 | data.module_list = ControlNetStore.supportedPreprocessors 150 | data.model_list = ['None'].concat( 151 | ControlNetStore.supportedModels 152 | ) 153 | } 154 | }) 155 | } 156 | ) 157 | 158 | export default ControlNetStore 159 | -------------------------------------------------------------------------------- /typescripts/controlnet/util.tsx: -------------------------------------------------------------------------------- 1 | export function mapRange( 2 | x: number, 3 | in_min: number, 4 | in_max: number, 5 | out_min: number, 6 | out_max: number, 7 | step: number 8 | ) { 9 | return ( 10 | Math.round( 11 | (((x - in_min) * (out_max - out_min)) / (in_max - in_min) + 12 | out_min) / 13 | step 14 | ) * step 15 | ) 16 | } 17 | 18 | export function versionCompare(to: string, from: string) { 19 | const vTo = to.split('.') 20 | const vFrom = from.split('.') 21 | 22 | for (let i = 0; i < Math.max(vTo.length, vFrom.length); i++) { 23 | const vFromI = +(vFrom[i] || 0) 24 | const vToI = +(vTo[i] || 0) 25 | if (isNaN(vFromI) || isNaN(vToI)) { 26 | throw new Error(`invalid version ${vTo} or ${vFrom} `) 27 | } 28 | 29 | if (vFromI > vToI) { 30 | return -1 31 | } else if (vFromI < vToI) { 32 | return 1 33 | } 34 | } 35 | return 0 36 | } 37 | -------------------------------------------------------------------------------- /typescripts/entry.ts: -------------------------------------------------------------------------------- 1 | import { configure } from 'mobx' 2 | configure({ 3 | enforceActions: 'never', // disable mobx warning temporarily 4 | }) 5 | export * as control_net from './controlnet/entry' 6 | export * as after_detailer_script from './after_detailer/after_detailer' 7 | export * as ultimate_sd_upscaler from './ultimate_sd_upscaler/ultimate_sd_upscaler' 8 | export * as scripts from './ultimate_sd_upscaler/scripts' 9 | 10 | export * as controlnet_main from './controlnet/main' 11 | export * as logger from './util/logger' 12 | export * as image_search from './image_search/image_search' 13 | export * as history from './history/history' 14 | export * as viewer from './viewer/viewer' 15 | export { default as viewer_util } from './viewer/viewer_util' 16 | export * as session_ts from './session/session' 17 | export { store as session_store } from './session/session_store' 18 | export { store as sd_tab_store } from './sd_tab/util' 19 | 20 | export * as progress from './session/progress' 21 | export * as preview from './viewer/preview' 22 | export * as generate from './session/generate' 23 | export * as sd_tab_ts from './sd_tab/sd_tab' 24 | export * as sd_tab_util from './sd_tab/util' 25 | export * as sam from './sam/sam' 26 | export * as settings_tab_ts from './settings/settings' 27 | export * as one_button_prompt from './one_button_prompt/one_button_prompt' 28 | export * as enum_ts from './util/ts/enum' 29 | export * as multiPrompts from './multiTextarea' 30 | export * as preset from './preset/preset' 31 | export * as preset_util from './preset/shared_ui_preset' 32 | export * as ui_ts from './util/ts/ui_ts' 33 | export * as io_ts from './util/ts/io' 34 | export * as tool_bar from './tool_bar/tool_bar' 35 | export * as extra_page from './extra_page/extra_page' 36 | export * as selection_ts from './util/ts/selection' 37 | export * as stores from './stores' 38 | 39 | export { default as lexica } from './lexical/lexical' 40 | export * as api_ts from './util/ts/api' 41 | export * as comfyui from './comfyui/comfyui' 42 | export { toJS } from 'mobx' 43 | export { default as node_fs } from 'fs' 44 | export { default as comfyui_util } from './comfyui/util' 45 | export { default as comfyui_main_ui } from './comfyui/main_ui' 46 | 47 | export { default as comfyapi } from './comfyui/comfyapi' 48 | -------------------------------------------------------------------------------- /typescripts/globalstore.ts: -------------------------------------------------------------------------------- 1 | import { observable } from 'mobx' 2 | import { host } from 'uxp' 3 | 4 | interface GlobalStore { 5 | Locale: 'zh_CN' | 'en_US' 6 | } 7 | 8 | const initialLocale = 9 | localStorage.getItem('last_selected_locale') || host.uiLocale 10 | var globalStore = observable({ 11 | Locale: initialLocale == 'zh_CN' ? initialLocale : 'en_US', 12 | }) 13 | 14 | export default globalStore 15 | -------------------------------------------------------------------------------- /typescripts/image_search/image_search.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import { observer } from 'mobx-react' 4 | import { AStore } from '../main/astore' 5 | import { Grid } from '../util/grid' 6 | import { MoveToCanvasSvg } from '../util/elements' 7 | import { io } from '../util/oldSystem' 8 | import { ErrorBoundary } from '../util/errorBoundary' 9 | import { urlToCanvas } from '../util/ts/general' 10 | 11 | export const store = new AStore({ 12 | images: [], 13 | thumbnails: [], 14 | refresh: false, 15 | width: 50, 16 | height: 50, 17 | }) 18 | 19 | const ImageSearch = observer(() => { 20 | console.log('rendered') 21 | return ( 22 |
23 | ) => { 27 | const new_value = event.target.value 28 | store.updateProperty('height', new_value) 29 | store.updateProperty('width', new_value) 30 | }} 31 | show-value="true" 32 | > 33 | Image Size: 34 | 35 | { 44 | urlToCanvas( 45 | store.data.images[index], 46 | 'search_image_temp.png' 47 | ) 48 | }, 49 | title: 'Copy Image to Canvas', 50 | }, 51 | ]} 52 | > 53 |
54 | ) 55 | }) 56 | 57 | const gridContainerNode = document.getElementById( 58 | 'divImageSearchImagesContainer' 59 | // 'search_second_panel' 60 | )! 61 | const gridRoot = ReactDOM.createRoot(gridContainerNode) 62 | 63 | let images: string[] = [] 64 | gridRoot.render( 65 | // 66 | 67 | 68 | 69 | // 70 | ) 71 | -------------------------------------------------------------------------------- /typescripts/locale/locale-for-old-html.ts: -------------------------------------------------------------------------------- 1 | import { reaction } from 'mobx' 2 | import globalStore from '../globalstore' 3 | import Locale from './locale' 4 | 5 | const elemSelectorForLocale = { 6 | // tab bar 7 | '#sp-stable-diffusion-ui-tab sp-label': 'Stable Diffusion', 8 | '#sp-viewer-tab sp-label': 'Viewer', 9 | '#sp-control_net-tab sp-label': 'ControlNet', 10 | // '#sp-history-tab sp-label': 'History', 11 | // '#sp-lexica-tab sp-label': 'Lexica', 12 | '#sp-image_search-tab sp-label': 'Image Search', 13 | '#sp-prompts-library-tab sp-label': 'Prompts library', 14 | '#sp-horde-tab sp-label': 'Horde', 15 | '#sp-extras-tab sp-label': 'Extras', 16 | '#sp-presets-tab sp-label': 'Presets', 17 | '#sp-settings-tab sp-label': 'Settings', 18 | 19 | // viewer tab 20 | '#rgSubTab .rbSubTab': 'Viewer', 21 | '#rbHistoryTab': 'History', 22 | '#rbImageSearch': 'Image Search', 23 | '#rbPromptsLibrary': 'Prompts Library', 24 | '#rbLexica': 'Lexica', 25 | '#viewerSubTab .flexContainer sp-label': 26 | 'View your generated images on the canvas', 27 | // '#btnSetMaskViewer': 'Set Mask', 28 | // '#btnSetInitImageViewer': 'Set Init Image', 29 | '#btnInterruptViewer': 'Interrupt', 30 | // '#btnSelectionArea': 'Selection Area', 31 | 32 | // extra tab 33 | // '#slThumbnailSize sp-label': 'Thumbnail Size', 34 | '#chSquareThumbnail': 'Square 1:1', 35 | '#btnGenerateUpscale': 'Generate upscale', 36 | '#btnInterruptUpscale': 'Interrupt', 37 | '#progressContainerUpscale sp-label': 'No work in progress', 38 | '#slUpscaler2Visibility .title': 'Upscaler 2 visibility', 39 | '#slGFPGANVisibility .title': 'GFPGAN visibility', 40 | '#slCodeFormerVisibility .title': 'CodeFormer visibility', 41 | '#slCodeFormerWeight .title': 'CodeFormer weight', 42 | 43 | // sd tab 44 | '#pViewerProgressBar .lProgressLabel': 'Progress...', 45 | '#btnRefreshModels': 'Refresh', 46 | '#btnUpdate': 'Update', 47 | '#chUsePromptShortcut': 'prompt shortcut', 48 | '#btnInterrupt': 'Interrupt', 49 | '#bSetInitImage': 'Image', 50 | '#bSetInitImageMask': 'Mask', 51 | '#batchNumberSdUiTabContainer sp-label': 'Batch Size', 52 | '#batchCountSdUiTabContainer sp-label': 'Batch count', 53 | '#rbSelectionModeLabel': 'Selection Mode', 54 | '#selectionModeGroup [value=ratio]': 'ratio', 55 | '#selectionModeGroup [value=precise]': 'precise', 56 | '#selectionModeGroup [value=ignore]': 'ignore', 57 | '#slCfgScale .title': 'CFG Scale', 58 | '#slImageCfgScale .title': 'Image CFG Scale', 59 | '#slMaskBlur sp-label': 'Mask blur', 60 | '#slMaskExpansion sp-label': 'Mask Expansion', 61 | '#slInpaintingMaskWeight .title': 'Inpainting conditioning mask strength', 62 | '#slInpainting_fill .title': 'Masked content', 63 | '#slInpainting_fill [value=0]': 'fill', 64 | '#slInpainting_fill [value=1]': 'original', 65 | '#slInpainting_fill [value=2]': 'latent noise', 66 | '#slInpainting_fill [value=3]': 'latent nothing', 67 | '#chInpaintFullRes': 'Inpaint at Full Res', 68 | '#chRestoreFaces': 'Restore Faces', 69 | '#chHiResFixs': 'Highres. fix', 70 | '#HiResDiv .title': 'Upscaler', 71 | '#HiResStep': 'Hires steps', 72 | '#hrScaleSlider .title': 'Hires Scale', 73 | '#hrDenoisingStrength .title': 'High Res Denoising Strength', 74 | '#hrWidth': 'Hi Res Output Width', 75 | '#hrHeight': 'Hi Res Output Height', 76 | '#lNameInpaintPdding': 'Inpaint Padding', 77 | '#btnRandomSeed': 'Random', 78 | '#btnLastSeed': 'Last', 79 | '#sampler_group sp-label': 'Sampling method', 80 | '#sdLabelSeed': 'Seed', 81 | '#collapsible': 'Show Samplers', 82 | '#slHeight .title': 'Height', 83 | '#slWidth .title': 'Width', 84 | '#sdLabelSampleStep': 'Sampling Steps', 85 | } 86 | 87 | function renderLocale(locale: string) { 88 | Object.keys(elemSelectorForLocale).forEach((selector) => { 89 | const elem = document.querySelector(selector) 90 | if (elem) { 91 | // @ts-ignore 92 | elem.innerHTML = Locale(elemSelectorForLocale[selector]) 93 | } 94 | }) 95 | } 96 | 97 | reaction(() => globalStore.Locale, renderLocale) 98 | renderLocale(globalStore.Locale) 99 | -------------------------------------------------------------------------------- /typescripts/locale/locale.ts: -------------------------------------------------------------------------------- 1 | import globalStore from '../globalstore' 2 | import type zhHans from '../../i18n/zh_CN/sd-official.json' 3 | import type zhHansForPSPlugin from '../../i18n/zh_CN/ps-plugin.json' 4 | import { lstatSync, readFileSync } from 'fs' 5 | 6 | const localeFileCache: any = {} 7 | 8 | function isExists(path: string): boolean { 9 | try { 10 | lstatSync(path) 11 | // console.log(path, 'exists') 12 | return true 13 | } catch (e) { 14 | // console.log(path, 'not exists') 15 | return false 16 | } 17 | } 18 | 19 | export default function Locale( 20 | key: keyof typeof zhHans | keyof typeof zhHansForPSPlugin | any 21 | ): string { 22 | const locale = globalStore.Locale 23 | 24 | const sdOfficialJSONPath = `plugin:/i18n/${locale}/sd-official.json` 25 | let sdOfficialTranslate = localeFileCache[sdOfficialJSONPath] 26 | if (!localeFileCache[sdOfficialJSONPath] && isExists(sdOfficialJSONPath)) { 27 | console.log('readFile') 28 | sdOfficialTranslate = JSON.parse( 29 | readFileSync(sdOfficialJSONPath, 'utf-8') 30 | ) 31 | localeFileCache[sdOfficialJSONPath] = sdOfficialTranslate 32 | } 33 | 34 | const psPluginJSONPath = `plugin:/i18n/${locale}/ps-plugin.json` 35 | let psPluginTranslate = localeFileCache[psPluginJSONPath] 36 | if (!localeFileCache[psPluginJSONPath] && isExists(psPluginJSONPath)) { 37 | console.log('readFile') 38 | psPluginTranslate = JSON.parse(readFileSync(psPluginJSONPath, 'utf-8')) 39 | localeFileCache[psPluginJSONPath] = psPluginTranslate 40 | } 41 | 42 | let res = '' 43 | //@ts-ignore 44 | if (sdOfficialTranslate && key in sdOfficialTranslate) 45 | res = sdOfficialTranslate[key] 46 | //@ts-ignore 47 | if (psPluginTranslate && key in psPluginTranslate) 48 | res = psPluginTranslate[key] 49 | 50 | res = res || key 51 | return res 52 | } 53 | -------------------------------------------------------------------------------- /typescripts/main/astore.ts: -------------------------------------------------------------------------------- 1 | import { makeAutoObservable, reaction, toJS } from 'mobx' 2 | export { toJS } from 'mobx' 3 | // import { Provider, inject, observer } from 'mobx-react' 4 | interface AStoreData { 5 | [key: string]: any 6 | } 7 | export class AStore { 8 | data: T 9 | 10 | constructor(data: T) { 11 | this.data = data 12 | 13 | makeAutoObservable(this) 14 | } 15 | 16 | updateProperty(key: keyof T, value: any) { 17 | this.data[key] = value 18 | } 19 | updatePropertyArray(key: keyof T, value: any) { 20 | this.data[key] = this.data[key].concat(value) 21 | } 22 | updatePropertyArrayRemove(key: keyof T, valueToRemove: any) { 23 | this.data[key] = this.data[key].filter( 24 | (item: any) => item !== valueToRemove 25 | ) 26 | } 27 | 28 | toJsFunc() { 29 | return toJS(this) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /typescripts/preset/shared_ui_preset.ts: -------------------------------------------------------------------------------- 1 | import { AStore } from '../main/astore' 2 | import { html_manip, io } from '../util/oldSystem' 3 | import { PresetTypeEnum } from '../util/ts/enum' 4 | // import { getNativeSDPresets } from '../util/ts/ui_ts' 5 | 6 | export async function getLoadedPresets(ui_settings_obj: any) { 7 | let customPresets 8 | 9 | customPresets = await mapCustomPresetsToLoaders(ui_settings_obj) 10 | console.log('customPresets: ', customPresets) 11 | let loadedPresets = { 12 | // ...getNativeSDPresets(), 13 | ...customPresets, 14 | } 15 | return loadedPresets 16 | } 17 | export const store = new AStore({ 18 | preset_name: '', 19 | custom_presets: [] as any, 20 | selected_preset_name: '', 21 | 22 | sd_presets: [], 23 | sd_native_presets: [], 24 | 25 | selected_sd_preset_name: '', // the selected sd preset in sd tab 26 | selected_sd_preset: {}, // the selected sd preset settings 27 | }) 28 | 29 | export const preset_tab_store = new AStore({ 30 | new_preset_name: '', //for the textfield field and label 31 | new_preset: {} as any, // settings of the current preset tab preset 32 | selected_preset_name: '', // name of the selected in the menu 33 | selected_preset: {}, //settings of the selected preset in the menu 34 | }) 35 | export async function getCustomPresetEntries(preset_folder_name: string) { 36 | const custom_preset_entry = await io.IOFolder.getCustomPresetFolder( 37 | preset_folder_name 38 | ) 39 | 40 | const custom_preset_entries = await io.IOJson.getJsonEntries( 41 | custom_preset_entry 42 | ) 43 | 44 | return custom_preset_entries 45 | } 46 | export async function loadPresetSettingsFromFile(preset_file_name: string) { 47 | const custom_preset_entry = await io.IOFolder.getCustomPresetFolder( 48 | 'custom_preset' 49 | ) 50 | let preset_settings = {} 51 | try { 52 | preset_settings = await io.IOJson.loadJsonFromFile( 53 | custom_preset_entry, 54 | preset_file_name 55 | ) 56 | } catch (e) { 57 | console.warn(e) 58 | } 59 | return preset_settings 60 | } 61 | 62 | export async function getAllCustomPresetsSettings() { 63 | const custom_preset_entries = await getCustomPresetEntries('custom_preset') 64 | let custom_presets: any = {} 65 | for (const entry of custom_preset_entries) { 66 | const preset_name: string = entry.name.split('.json')[0] 67 | let preset_settings = await loadPresetSettingsFromFile(entry.name) 68 | 69 | custom_presets[preset_name] = preset_settings 70 | } 71 | return custom_presets 72 | } 73 | 74 | const updatePresetMenuEvent = new CustomEvent('updatePresetMenuEvent', { 75 | detail: {}, 76 | bubbles: true, 77 | cancelable: true, 78 | composed: false, 79 | }) 80 | 81 | export function loadPreset(ui_settings: any, preset: any) { 82 | console.log('preset:', preset) 83 | ui_settings.autoFillInSettings(preset) 84 | } 85 | export function loadCustomPreset( 86 | ui_settings_obj: any, 87 | custom_preset_settings: any 88 | ) { 89 | loadPreset(ui_settings_obj, custom_preset_settings) 90 | } 91 | export async function mapCustomPresetsToLoaders(ui_settings_obj: any) { 92 | const name_to_settings_obj = await getAllCustomPresetsSettings() 93 | const preset_name_to_loader_obj: any = {} 94 | for (const [preset_name, preset_settings] of Object.entries( 95 | name_to_settings_obj 96 | )) { 97 | preset_name_to_loader_obj[preset_name] = () => { 98 | loadCustomPreset(ui_settings_obj, preset_settings) 99 | } 100 | } 101 | return preset_name_to_loader_obj 102 | } 103 | 104 | export function getCustomPresetsNames(custom_presets: any) { 105 | let presets_names: any = [] 106 | if (custom_presets) { 107 | presets_names = Object.keys(custom_presets) 108 | } 109 | return presets_names 110 | } 111 | 112 | export function onLoadControlnetPreset() {} 113 | export function onLoadSDPreset() {} 114 | 115 | //sd preset = {preset_name: settings_json} 116 | //sd_preset_loader(sd_preset) 117 | 118 | //controlnet_preset = {preset_name: settings_json} 119 | 120 | export { updatePresetMenuEvent } 121 | -------------------------------------------------------------------------------- /typescripts/session/session_store.ts: -------------------------------------------------------------------------------- 1 | import { AStore } from '../main/astore' 2 | import { 3 | GenerationModeEnum, 4 | ScriptMode, 5 | SelectionInfoType, 6 | } from '../util/ts/enum' 7 | 8 | interface AStoreUISettings { 9 | batch_size: number 10 | // add other properties here as needed 11 | } 12 | 13 | interface AStoreData { 14 | // other properties... 15 | 16 | init_image: string 17 | active_mask: string // this is the mask that is been used in the current generation 18 | mask: string // the user inputted mask, also can be the mask generated by photoshop dependant on the generation mode 19 | expanded_mask: string // mask after expanded 20 | monoMask: string //monochrome mask, no gradation 21 | preprocessed_mask: string // 22 | sd_mask: string // mask send to sd as payload[mask] 23 | mode: GenerationModeEnum 24 | rb_mode: ScriptMode 25 | 26 | ui_settings: AStoreUISettings 27 | selectionInfo: SelectionInfoType | undefined //the session selection info 28 | current_selection_info: SelectionInfoType | undefined // any new selection, could be undefined too 29 | can_generate: boolean // is generation currently in progress 30 | can_generate_more: boolean // 31 | is_active: boolean // is session active 32 | is_interrupted: boolean // did we interrupt the generation 33 | generation_number: number // generation number per session, 0 mean first generation 34 | controlnet_input_image: string // the controlnet the image that will controlnet load 35 | 36 | //plugin related state: 37 | auto_photoshop_sd_extension_status: boolean 38 | 39 | doc_uuid: string 40 | current_session_id: number 41 | last_seed: string 42 | } 43 | 44 | export const store = new AStore({ 45 | // activeBase64InitImage: '', 46 | // activeBase64Mask: '', 47 | init_image: '', 48 | active_mask: '', // this is the mask that is been used in the current generation 49 | mask: '', // the user inputted mask, also can be the mask generated by photoshop dependant on the generation mode 50 | expanded_mask: '', // mask after expanded 51 | monoMask: '', //monochrome mask, no gradation 52 | preprocessed_mask: '', // 53 | sd_mask: '', // mask send to sd as payload[mask] 54 | mode: GenerationModeEnum.Txt2Img, 55 | rb_mode: ScriptMode.Txt2Img, 56 | ui_settings: { batch_size: 1 }, 57 | selectionInfo: undefined, //the session selection info 58 | current_selection_info: undefined, // any new selection, could be undefined too 59 | can_generate: true, // is generation currently in progress 60 | can_generate_more: false, // 61 | is_active: false, // is session active 62 | is_interrupted: false, // did we interrupt the generation 63 | generation_number: 0, // generation number per session, 0 mean first generation 64 | controlnet_input_image: '', // the controlnet the image that will controlnet load 65 | 66 | //plugin related state: 67 | auto_photoshop_sd_extension_status: true, 68 | doc_uuid: '', 69 | current_session_id: 0, 70 | last_seed: '-1', 71 | }) 72 | -------------------------------------------------------------------------------- /typescripts/session/style/generate.css: -------------------------------------------------------------------------------- 1 | .generateButtonMargin { 2 | margin-top: 1px; 3 | margin-bottom: 3px; 4 | display: inline-block; 5 | } 6 | 7 | .generateColor { 8 | background-color: #ff595e; 9 | } 10 | 11 | .generateMoreColor { 12 | background-color: #6db579; 13 | } 14 | -------------------------------------------------------------------------------- /typescripts/settings/vae.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import { observer } from 'mobx-react' 4 | import { AStore } from '../main/astore' 5 | import { SpMenu } from '../util/elements' 6 | 7 | import { api, python_replacement } from '../util/oldSystem' 8 | const { getExtensionUrl } = python_replacement 9 | import '../locale/locale-for-old-html' 10 | import { ErrorBoundary } from '../util/errorBoundary' 11 | 12 | declare let g_sd_url: string 13 | 14 | export const store = new AStore({ 15 | vae_model_list: [] as string[], 16 | current_vae: '' as string, 17 | }) 18 | 19 | @observer 20 | export class VAEComponent extends React.Component<{ 21 | // store: AStore 22 | }> { 23 | componentDidMount(): void {} 24 | changeVAEModel(vae_model: string) { 25 | try { 26 | const full_url = `${g_sd_url}/sdapi/v1/options` 27 | api.requestPost(full_url, { sd_vae: vae_model }) 28 | } catch (e) { 29 | console.warn('changeVAEModel: vae_model: ', vae_model, e) 30 | } 31 | } 32 | handleRefresh() { 33 | populateVAE() 34 | } 35 | render(): React.ReactNode { 36 | return ( 37 |
38 | { 48 | // script_store.setSelectedScript(value.item) 49 | console.log('onChange value: ', value) 50 | this.changeVAEModel(value.item) 51 | }} 52 | > 53 | 58 |
59 | ) 60 | } 61 | } 62 | const vaeContainerNode = document.getElementById('settingsVAEContainer')! 63 | const vaeRoot = ReactDOM.createRoot(vaeContainerNode) 64 | 65 | async function requestGetVAE() { 66 | const full_url = `${g_sd_url}/sdapi/v1/options` 67 | 68 | const options = await api.requestGet(full_url) 69 | return options?.sd_vae 70 | } 71 | export async function populateVAE() { 72 | try { 73 | const extension_url = getExtensionUrl() 74 | 75 | const full_url = `${extension_url}/vae/list` 76 | const vae_models = (await api.requestGet(full_url)) || [] 77 | 78 | console.log('populateVAE vae_models: ', vae_models) 79 | store.updateProperty('vae_model_list', vae_models) 80 | 81 | const current_vae = await requestGetVAE() 82 | if (current_vae && vae_models.includes(current_vae)) { 83 | store.updateProperty('current_vae', current_vae) 84 | } 85 | } catch (e) { 86 | console.warn('populateVAE():', e) 87 | } 88 | } 89 | 90 | vaeRoot.render( 91 | // 92 | 93 | 94 | 95 | // 96 | ) 97 | 98 | export default { 99 | store, 100 | populateVAE, 101 | } 102 | -------------------------------------------------------------------------------- /typescripts/stores.ts: -------------------------------------------------------------------------------- 1 | export { store as session_store } from './session/session_store' 2 | export { store as sd_tab_store } from './sd_tab/util' 3 | export { mask_store } from './viewer/viewer_util' 4 | -------------------------------------------------------------------------------- /typescripts/tool_bar/style/tool_bar.css: -------------------------------------------------------------------------------- 1 | /* styles.css */ 2 | #_tool_bar_container button:not(:last-child) { 3 | margin-bottom: 3px; 4 | } 5 | -------------------------------------------------------------------------------- /typescripts/ultimate_sd_upscaler/config.ts: -------------------------------------------------------------------------------- 1 | export let ui_config = { 2 | tile_width: { 3 | minimum: 0, 4 | maximum: 2048, 5 | step: 64, 6 | label: 'Tile width', 7 | value: 512, 8 | }, 9 | tile_height: { 10 | minimum: 0, 11 | maximum: 2048, 12 | step: 64, 13 | label: 'Tile height', 14 | value: 0, 15 | }, 16 | mask_blur: { 17 | minimum: 0, 18 | maximum: 64, 19 | step: 1, 20 | label: 'Mask blur', 21 | value: 8, 22 | }, 23 | padding: { minimum: 0, maximum: 128, step: 1, label: 'Padding', value: 32 }, 24 | 25 | seams_fix_denoise: { 26 | label: 'Denoise', 27 | minimum: 0, 28 | maximum: 1, 29 | step: 0.01, 30 | value: 0.35, 31 | visible: false, 32 | interactive: true, 33 | }, 34 | 35 | seams_fix_width: { 36 | label: 'Width', 37 | minimum: 0, 38 | maximum: 128, 39 | step: 1, 40 | value: 64, 41 | visible: false, 42 | interactive: true, 43 | }, 44 | seams_fix_mask_blur: { 45 | label: 'Mask blur', 46 | minimum: 0, 47 | maximum: 64, 48 | step: 1, 49 | value: 4, 50 | visible: false, 51 | interactive: true, 52 | }, 53 | seams_fix_padding: { 54 | label: 'Padding', 55 | minimum: 0, 56 | maximum: 128, 57 | step: 1, 58 | value: 16, 59 | visible: false, 60 | interactive: true, 61 | }, 62 | redraw_mode: { 63 | label: 'Type', 64 | choices: ['Linear', 'Chess', 'None'], 65 | type: 'index', 66 | value: 0, 67 | }, 68 | save_upscaled_image: { 69 | label: 'Upscaled', 70 | value: true, 71 | }, 72 | save_seams_fix_image: { 73 | label: 'Seams fix', 74 | value: false, 75 | }, 76 | 77 | seams_fix_type: { 78 | label: 'Type', 79 | choices: [ 80 | 'None', 81 | 'Band pass', 82 | 'Half tile offset pass', 83 | 'Half tile offset pass + intersections', 84 | ], 85 | type: 'index', 86 | value: 3, 87 | }, 88 | 89 | target_size_type: { 90 | label: 'Target size type', 91 | choices: [ 92 | 'From img2img2 settings', 93 | 'Custom size', 94 | 'Scale from image size', 95 | ], 96 | type: 'index', 97 | value: 2, 98 | }, 99 | 100 | custom_width: { 101 | label: 'Custom width', 102 | minimum: 64, 103 | maximum: 8192, 104 | step: 64, 105 | value: 2048, 106 | visible: false, 107 | interactive: true, 108 | }, 109 | custom_height: { 110 | label: 'Custom height', 111 | minimum: 64, 112 | maximum: 8192, 113 | step: 64, 114 | value: 2048, 115 | visible: false, 116 | interactive: true, 117 | }, 118 | custom_scale: { 119 | label: 'Scale', 120 | minimum: 1, 121 | maximum: 16, 122 | step: 0.01, 123 | value: 2, 124 | visible: false, 125 | interactive: true, 126 | }, 127 | 128 | upscaler_index: { 129 | label: 'Upscaler', 130 | choices: [], 131 | type: 'index', 132 | value: 0, 133 | }, 134 | } 135 | -------------------------------------------------------------------------------- /typescripts/util/collapsible.tsx: -------------------------------------------------------------------------------- 1 | import React, { CSSProperties, ComponentType } from 'react' 2 | // import ReactDOM from 'react-dom' 3 | 4 | import { useState, ReactNode } from 'react' 5 | import Locale from '../locale/locale' 6 | interface CollapsibleProps { 7 | label: string 8 | labelStyle?: React.CSSProperties 9 | containerStyle?: React.CSSProperties 10 | defaultIsOpen?: boolean 11 | checked?: boolean 12 | checkboxCallback?: (checked: boolean) => void 13 | children: ReactNode 14 | } 15 | 16 | export function Collapsible({ 17 | label, 18 | labelStyle, 19 | containerStyle, 20 | defaultIsOpen = false, 21 | checkboxCallback, 22 | checked, 23 | children, 24 | }: CollapsibleProps) { 25 | const [isOpen, setIsOpen] = useState(defaultIsOpen) 26 | 27 | const handleToggle = () => { 28 | setIsOpen(!isOpen) 29 | } 30 | 31 | return ( 32 | /*useObserver(()=>*/
33 |
38 | 39 | {label} 40 | 41 | 42 | 46 | {checkboxCallback && checked !== void 0 ? ( 47 | { 51 | event.stopPropagation() 52 | }} 53 | onChange={(event: any) => { 54 | checkboxCallback(event.target.checked) 55 | }} 56 | checked={checked} 57 | /> 58 | ) : ( 59 | void 0 60 | )} 61 | 62 | {isOpen ? '∨' : '<'} 63 | 64 |
65 | {/* {isOpen &&
{children}
} */} 66 |
{children}
67 |
68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /typescripts/util/errorBoundary.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component, ErrorInfo, ReactNode } from 'react' 2 | import { refreshUI } from '../sd_tab/util' 3 | 4 | interface Props { 5 | children: ReactNode 6 | } 7 | 8 | interface State { 9 | hasError: boolean 10 | key: number 11 | } 12 | interface State { 13 | hasError: boolean 14 | key: number 15 | } 16 | 17 | export class ErrorBoundary extends Component { 18 | public state: State = { 19 | hasError: false, 20 | key: 0, 21 | } 22 | 23 | public static getDerivedStateFromError(_: Error): Partial { 24 | // When an error occurs, we update state so the next render will show the fallback UI. 25 | return { hasError: true } 26 | } 27 | 28 | public componentDidCatch(error: Error, errorInfo: ErrorInfo) { 29 | console.error('Uncaught error:', error, errorInfo) 30 | } 31 | 32 | handleRefresh = () => { 33 | this.setState((prevState) => ({ 34 | hasError: false, // reset the error state 35 | key: prevState.key + 1, // increment key to remount children 36 | })) 37 | // await refreshUI() 38 | } 39 | 40 | public render() { 41 | if (this.state.hasError) { 42 | return ( 43 |
44 |

Sorry.. there was an error

45 | 46 |
47 | ) 48 | } 49 | 50 | // The key prop causes a remount of children when it changes 51 | return
{this.props.children}
52 | } 53 | } 54 | -------------------------------------------------------------------------------- /typescripts/util/logger.ts: -------------------------------------------------------------------------------- 1 | import { format } from 'util' 2 | export function formateLog(data: any, ...optional_param: any[]) { 3 | const formattedOutput = format(data, ...optional_param) 4 | return formattedOutput 5 | } 6 | -------------------------------------------------------------------------------- /typescripts/util/oldSystem.tsx: -------------------------------------------------------------------------------- 1 | import type Jimp from 'jimp' 2 | 3 | //@ts-ignore 4 | const req = window['require'] 5 | 6 | // because we use window['require'], so the base path of this require function is the root path of plugin. 7 | const selection = req('./selection') 8 | const note = req('./utility/notification') 9 | const controlnet_preset = req('./utility/presets/controlnet_preset') 10 | 11 | const Enum = req('./enum') 12 | const api = req('./utility/api') 13 | const python_replacement = req('./utility/sdapi/python_replacement') 14 | const sdapi = req('./sdapi_py_re') 15 | const html_manip = req('./utility/html_manip') 16 | const psapi = req('./psapi') 17 | const general = req('./utility/general') 18 | const io = req('./utility/io') 19 | const settings_tab = req('./utility/tab/settings') 20 | const layer_util = req('./utility/layer') 21 | const session = req('./utility/session') 22 | const dialog_box = req('./dialog_box') 23 | const sampler_data = req('./utility/sampler') 24 | 25 | const thumbnail = req('./thumbnail') 26 | interface _Jimp extends Jimp {} 27 | const _Jimp: typeof Jimp = (window as any)['Jimp'] 28 | 29 | export { 30 | selection, 31 | note, 32 | controlnet_preset, 33 | Enum, 34 | api, 35 | python_replacement, 36 | sdapi, 37 | html_manip, 38 | psapi, 39 | general, 40 | io, 41 | settings_tab, 42 | layer_util, 43 | session, 44 | dialog_box, 45 | sampler_data, 46 | thumbnail, 47 | _Jimp as Jimp, 48 | } 49 | -------------------------------------------------------------------------------- /typescripts/util/ts/enum.ts: -------------------------------------------------------------------------------- 1 | export enum GenerationModeEnum { 2 | Txt2Img = 'txt2img', 3 | Img2Img = 'img2img', 4 | Inpaint = 'inpaint', 5 | Outpaint = 'outpaint', 6 | Upscale = 'upscale', 7 | LassoInpaint = 'lasso_inpaint', 8 | LassoOutpaint = 'lasso_outpaint', 9 | } 10 | 11 | export enum ScriptMode { 12 | Txt2Img = 'txt2img', 13 | Img2Img = 'img2img', 14 | Inpaint = 'inpaint', 15 | Outpaint = 'outpaint', 16 | } 17 | 18 | export enum MaskModeEnum { 19 | Transparent = 'transparent', 20 | Borders = 'border', 21 | Corners = 'corner', 22 | } 23 | 24 | export interface SelectionInfoType { 25 | left: number 26 | right: number 27 | top: number 28 | bottom: number 29 | width: number 30 | height: number 31 | } 32 | 33 | export enum PresetTypeEnum { 34 | SDPreset = 'sd_preset', 35 | ControlNetPreset = 'controlnet_preset', 36 | } 37 | -------------------------------------------------------------------------------- /typescripts/util/ts/layer.ts: -------------------------------------------------------------------------------- 1 | import { app, core, action } from 'photoshop' 2 | import { layer_util, psapi } from '../oldSystem' 3 | // import { settings_tab_ts } from '../../entry' 4 | import * as settings_tab_ts from '../../settings/settings' 5 | const executeAsModal = core.executeAsModal 6 | const { batchPlay } = action 7 | 8 | export interface RectArea { 9 | top: number 10 | left: number 11 | height: number 12 | width: number 13 | } 14 | 15 | async function transformBatchPlay( 16 | centerX: number, 17 | centerY: number, 18 | scaleRatioX: number, 19 | scaleRatioY: number, 20 | translateX: number, 21 | translateY: number 22 | ) { 23 | const setInterpolationMethodDesc = { 24 | _obj: 'set', 25 | _target: [ 26 | { 27 | _ref: 'property', 28 | _property: 'generalPreferences', 29 | }, 30 | { 31 | _ref: 'application', 32 | _enum: 'ordinal', 33 | _value: 'targetEnum', 34 | }, 35 | ], 36 | to: { 37 | _obj: 'generalPreferences', 38 | interpolationMethod: { 39 | _enum: 'interpolationType', 40 | // _value: 'bilinear', 41 | _value: settings_tab_ts.store.data.scale_interpolation_method 42 | .photoshop, 43 | }, 44 | }, 45 | _isCommand: true, 46 | } 47 | 48 | let imageSizeDescriptor = { 49 | _obj: 'transform', 50 | _target: [ 51 | { 52 | _ref: 'layer', 53 | _enum: 'ordinal', 54 | _value: 'targetEnum', 55 | }, 56 | ], 57 | freeTransformCenterState: { 58 | _enum: 'quadCenterState', 59 | _value: 'QCSIndependent', 60 | }, 61 | position: { 62 | _obj: 'paint', 63 | horizontal: { _unit: 'pixelsUnit', _value: centerX }, 64 | vertical: { _unit: 'pixelsUnit', _value: centerY }, 65 | }, 66 | offset: { 67 | _obj: 'offset', 68 | horizontal: { 69 | _unit: 'pixelsUnit', 70 | _value: translateX, 71 | }, 72 | vertical: { 73 | _unit: 'pixelsUnit', 74 | _value: translateY, 75 | }, 76 | }, 77 | width: { 78 | _unit: 'percentUnit', 79 | _value: scaleRatioX, 80 | }, 81 | height: { 82 | _unit: 'percentUnit', 83 | _value: scaleRatioY, 84 | }, 85 | linked: true, 86 | interfaceIconFrameDimmed: { 87 | _enum: 'interpolationType', 88 | // _value: 'bilinear', 89 | _value: settings_tab_ts.store.data.scale_interpolation_method 90 | .photoshop, 91 | }, 92 | _isCommand: true, 93 | } 94 | return batchPlay([setInterpolationMethodDesc, imageSizeDescriptor], { 95 | synchronousExecution: true, 96 | modalBehavior: 'execute', 97 | }) 98 | } 99 | 100 | export async function transformCurrentLayerTo( 101 | toRect: RectArea, 102 | fromRect: RectArea 103 | ) { 104 | const selection_info = await psapi.getSelectionInfoExe() 105 | await psapi.unSelectMarqueeExe() 106 | 107 | const scale_x_ratio = (toRect.width / fromRect.width) * 100 108 | const scale_y_ratio = (toRect.height / fromRect.height) * 100 109 | 110 | const top_dist = toRect.top - fromRect.top 111 | const left_dist = toRect.left - fromRect.left 112 | console.log( 113 | 'transformCurrentLayer', 114 | top_dist, 115 | left_dist, 116 | scale_x_ratio, 117 | scale_y_ratio 118 | ) 119 | 120 | await executeAsModal( 121 | () => 122 | transformBatchPlay( 123 | fromRect.left, 124 | fromRect.top, 125 | scale_x_ratio, 126 | scale_y_ratio, 127 | left_dist, 128 | top_dist 129 | ), 130 | { commandName: 'transform' } 131 | ) 132 | 133 | await psapi.reSelectMarqueeExe(selection_info) 134 | } 135 | 136 | export async function SetLayerColor() { 137 | let result 138 | 139 | let command = [ 140 | { 141 | _obj: 'set', 142 | _target: [ 143 | { _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' }, 144 | ], 145 | to: { _obj: 'layer', color: { _enum: 'color', _value: 'red' } }, 146 | }, 147 | ] 148 | result = await batchPlay(command, { 149 | synchronousExecution: true, 150 | modalBehavior: 'execute', 151 | }) 152 | } 153 | -------------------------------------------------------------------------------- /typescripts/util/ts/sdapi.ts: -------------------------------------------------------------------------------- 1 | declare let g_version: any 2 | declare let g_sd_url: any 3 | 4 | export async function getVersionRequest() { 5 | console.log('requestGetSamplers: ') 6 | const current_version = g_version 7 | 8 | return current_version 9 | } 10 | export async function requestGetSamplers() { 11 | let json = null 12 | try { 13 | console.log('requestGetSamplers: ') 14 | 15 | const full_url = `${g_sd_url}/sdapi/v1/samplers` 16 | let request = await fetch(full_url) 17 | json = await request.json() 18 | // console.log('samplers json:', json) 19 | } catch (e) { 20 | console.warn(e) 21 | } 22 | return json 23 | } 24 | 25 | export async function requestGetUpscalers() { 26 | console.log('requestGetUpscalers: ') 27 | let json = [] 28 | const full_url = `${g_sd_url}/sdapi/v1/upscalers` 29 | try { 30 | let request = await fetch(full_url) 31 | json = await request.json() 32 | console.log('upscalers json:') 33 | console.dir(json) 34 | } catch (e) { 35 | console.warn(`issues requesting from ${full_url}`, e) 36 | } 37 | return json 38 | } 39 | 40 | export async function setInpaintMaskWeight(value: number) { 41 | const full_url = `${g_sd_url}/sdapi/v1/options` 42 | try { 43 | const payload = { 44 | inpainting_mask_weight: value, 45 | } 46 | await fetch(full_url, { 47 | method: 'POST', 48 | headers: { 49 | Accept: 'application/json', 50 | 'Content-Type': 'application/json', 51 | }, 52 | body: JSON.stringify(payload), 53 | }) 54 | } catch (e) { 55 | console.warn(e) 56 | } 57 | } 58 | 59 | export async function requestGetModels() { 60 | console.log('requestGetModels: ') 61 | let json = [] 62 | const full_url = `${g_sd_url}/sdapi/v1/sd-models` 63 | try { 64 | let res = await fetch(full_url) 65 | if (res.status == 200) { 66 | json = await res.json() 67 | } 68 | console.log('models json:') 69 | console.dir(json) 70 | } catch (e) { 71 | console.warn(`issues requesting from ${full_url}`, e) 72 | } 73 | return json 74 | } 75 | 76 | export async function requestSwapModel(model_title: string) { 77 | console.log('requestSwapModel: ') 78 | 79 | const full_url = `${g_sd_url}/sdapi/v1/options` 80 | const payload = { 81 | sd_model_checkpoint: model_title, 82 | } 83 | let request = await fetch(full_url, { 84 | method: 'POST', 85 | headers: { 86 | Accept: 'application/json', 87 | 'Content-Type': 'application/json', 88 | }, 89 | body: JSON.stringify(payload), 90 | }) 91 | 92 | let json = await request.json() 93 | 94 | console.log('models json:') 95 | console.dir(json) 96 | 97 | return json 98 | } 99 | -------------------------------------------------------------------------------- /typescripts/viewer/preview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | 4 | import { Collapsible } from '../util/collapsible' 5 | import { observer } from 'mobx-react' 6 | import { AStore } from '../main/astore' 7 | // import { progress } from '../entry' 8 | import * as progress from '../session/progress' 9 | 10 | import './style/preview.css' 11 | import { reaction } from 'mobx' 12 | import Locale from '../locale/locale' 13 | import { ErrorBoundary } from '../util/errorBoundary' 14 | export const store = new AStore({ 15 | // image: '', 16 | // progress_value: 0, 17 | }) 18 | // update all progress bar when progress store progress_value update 19 | reaction( 20 | () => { 21 | return progress.store.data.progress_value 22 | }, 23 | (value: number) => { 24 | document.querySelectorAll('.pProgressBars').forEach((progress: any) => { 25 | progress.value = value?.toFixed(2) 26 | }) 27 | } 28 | ) 29 | const Previewer = observer(() => { 30 | const renderImage = () => { 31 | let preview_img_html 32 | if (progress.store.data.progress_image) { 33 | preview_img_html = ( 34 | 41 | ) 42 | } 43 | return ( 44 |
50 | 55 | {progress.store.data.progress_image ? preview_img_html : void 0} 56 |
57 | ) 58 | } 59 | return
{renderImage()}
60 | }) 61 | 62 | const containers = document.querySelectorAll('.previewContainer') 63 | 64 | const PreviewerContainer = observer(() => { 65 | return ( 66 |
67 | 79 | 80 | 81 |
82 | ) 83 | }) 84 | containers.forEach((container) => { 85 | const root = ReactDOM.createRoot(container) 86 | 87 | root.render( 88 | // 89 | 90 | 91 | 92 | // 93 | ) 94 | }) 95 | -------------------------------------------------------------------------------- /typescripts/viewer/style/preview.css: -------------------------------------------------------------------------------- 1 | .preview_progress_bar { 2 | border-left: 2px solid #3e3e3e; 3 | border-right: 2px solid #3e3e3e; 4 | margin: 0; 5 | width: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /typescripts/viewer/viewer_util.ts: -------------------------------------------------------------------------------- 1 | import { AStore } from '../main/astore' 2 | import { io } from '../util/oldSystem' 3 | 4 | export enum ClickTypeEnum { 5 | Click = 'click', 6 | ShiftClick = 'shift_click', 7 | AltClick = 'alt_click', 8 | SecondClick = 'second_click', //when we click a thumbnail that is active/ has orange border 9 | } 10 | 11 | export enum OutputImageStateEnum { 12 | Add = 'add', 13 | remove = 'remove', 14 | } 15 | export enum ClassNameEnum { 16 | Green = 'viewerImgSelected', 17 | Orange = 'viewerImgActive', 18 | None = '', 19 | } 20 | interface AStoreData { 21 | images: string[] 22 | thumbnails: string[] 23 | metadata: any[] // metadata for each image 24 | width: number 25 | height: number 26 | 27 | prev_layer: any 28 | clicked_index: number | undefined 29 | 30 | permanent_indices: number[] 31 | 32 | prev_index: number 33 | is_stored: boolean[] 34 | layers: any[] 35 | class_name: ClassNameEnum[] 36 | can_click: boolean 37 | auto_mask: boolean 38 | } 39 | export const store = new AStore({ 40 | images: [], 41 | thumbnails: [], 42 | metadata: [], // metadata for each image 43 | width: 50, 44 | height: 50, 45 | 46 | prev_layer: null, 47 | clicked_index: undefined, 48 | 49 | permanent_indices: [], 50 | 51 | prev_index: -1, 52 | 53 | is_stored: [], 54 | layers: [], 55 | class_name: [], 56 | can_click: true, 57 | auto_mask: true, 58 | }) 59 | export const init_store = new AStore({ 60 | images: [], 61 | thumbnails: [], 62 | 63 | width: 50, 64 | height: 50, 65 | 66 | prev_layer: null, 67 | clicked_index: null, 68 | 69 | permanent_indices: [], 70 | 71 | prev_index: -1, 72 | output_image_obj_list: [], 73 | is_stored: [], 74 | layers: [], 75 | class_name: [], 76 | can_click: true, 77 | }) 78 | export const mask_store = new AStore({ 79 | images: [], 80 | thumbnails: [], 81 | output_images_masks: [] as string[], 82 | 83 | width: 50, 84 | height: 50, 85 | expand_by: 0, 86 | prev_layer: null, 87 | clicked_index: null, 88 | 89 | permanent_indices: [], 90 | 91 | prev_index: -1, 92 | output_image_obj_list: [], 93 | is_stored: [], 94 | layers: [], 95 | class_name: [], 96 | can_click: true, 97 | }) 98 | 99 | interface AStoreDataWithImagesAndThumbnails { 100 | images: string[] 101 | thumbnails: string[] 102 | } 103 | 104 | export async function updateViewerStoreImageAndThumbnail< 105 | T extends AStoreDataWithImagesAndThumbnails 106 | >(store: AStore, images: string[]) { 107 | try { 108 | if (typeof images === 'undefined' || !images) { 109 | return null 110 | } 111 | store.data.images = images 112 | const thumbnail_list = [] 113 | for (const base64 of images) { 114 | const thumbnail = await io.createThumbnail(base64, 300) 115 | thumbnail_list.push(thumbnail) 116 | } 117 | 118 | store.data.thumbnails = thumbnail_list 119 | } catch (e) { 120 | console.warn(e) 121 | console.warn('images: ', images) 122 | } 123 | } 124 | 125 | export const resetViewer = () => { 126 | store.updateProperty('images', []) 127 | store.data.thumbnails = [] 128 | store.data.prev_index = -1 129 | store.data.is_stored = [] 130 | store.data.layers = [] 131 | store.data.class_name = [] 132 | store.data.can_click = true 133 | 134 | mask_store.data.images = [] 135 | mask_store.data.thumbnails = [] 136 | init_store.data.images = [] 137 | init_store.data.thumbnails = [] 138 | } 139 | 140 | export default { 141 | store, 142 | init_store, 143 | mask_store, 144 | } 145 | -------------------------------------------------------------------------------- /utility/api.js: -------------------------------------------------------------------------------- 1 | //deprecated file don't use 2 | 3 | console.warn('api.js is deprecated, use typescript/util/ts/api.ts') 4 | 5 | async function requestGet(url) { 6 | let json = null 7 | 8 | const full_url = url 9 | try { 10 | let request = await fetch(full_url) 11 | if (request.status === 404) { 12 | return null 13 | } 14 | 15 | json = await request.json() 16 | 17 | // console.log('json: ', json) 18 | } catch (e) { 19 | console.warn(`issues requesting from ${full_url}`, e) 20 | } 21 | return json 22 | } 23 | async function requestPost(url, payload) { 24 | let json = null 25 | 26 | const full_url = url 27 | try { 28 | let request = await fetch(full_url, { 29 | method: 'POST', 30 | headers: { 31 | Accept: 'application/json', 32 | 'Content-Type': 'application/json', 33 | }, 34 | body: JSON.stringify(payload), 35 | }) 36 | 37 | if (request.status === 404) { 38 | return null 39 | } 40 | 41 | json = await request.json() 42 | 43 | // console.log('json: ', json) 44 | } catch (e) { 45 | console.warn(`issues requesting from ${full_url}`, e) 46 | } 47 | return json 48 | } 49 | async function requestFormDataPost(url, payload) { 50 | try { 51 | var myHeaders = new Headers() 52 | myHeaders.append('Cookie', 'PHPSESSID=n70fa2vmvm6tfmktf4jmstmd1i') 53 | 54 | var formdata = new FormData() 55 | 56 | for ([key, value] of Object.entries(payload)) { 57 | formdata.append(key, value) 58 | } 59 | // formdata.append( 60 | // 'source', 61 | // 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=' 62 | // ) 63 | // formdata.append('key', '6d207e02198a847aa98d0a2a901485a5') 64 | 65 | var requestOptions = { 66 | method: 'POST', 67 | headers: myHeaders, 68 | body: formdata, 69 | redirect: 'follow', 70 | } 71 | 72 | const response = await fetch(url, requestOptions) 73 | const result_json = response.json() 74 | return result_json 75 | } catch (e) { 76 | console.warn(e) 77 | } 78 | } 79 | 80 | module.exports = { 81 | requestGet, 82 | requestPost, 83 | requestFormDataPost, 84 | } 85 | -------------------------------------------------------------------------------- /utility/general.js: -------------------------------------------------------------------------------- 1 | const { requestGet } = require('./api') 2 | 3 | function newOutputImageName(format = 'png') { 4 | const random_id = Math.floor(Math.random() * 100000000000 + 1) // Date.now() doesn't have enough resolution to avoid duplicate 5 | const image_name = `output- ${Date.now()}-${random_id}.${format}` 6 | console.log('generated image name:', image_name) 7 | return image_name 8 | } 9 | 10 | function makeImagePath(format = 'png') { 11 | const image_name = newOutputImageName(format) 12 | const image_path = `${uniqueDocumentId}/${image_name}` 13 | return image_path 14 | } 15 | function convertImageNameToPng(image_name) { 16 | const image_png_name = image_name.split('.')[0] + '.png' 17 | return image_png_name 18 | } 19 | function fixNativePath(native_path) { 20 | const fixed_native_path = native_path.replaceAll('\\', '/') 21 | 22 | return fixed_native_path 23 | } 24 | function base64ToBase64Url(base64_image) { 25 | return 'data:image/png;base64,' + base64_image 26 | } 27 | function base64UrlToBase64(base64_url) { 28 | const base64_image = base64_url.replace('data:image/png;base64,', '') 29 | return base64_image 30 | } 31 | const timer = (ms) => new Promise((res) => setTimeout(res, ms)) //Todo: move this line to it's own utilit function 32 | 33 | function mapRange(x, in_min, in_max, out_min, out_max) { 34 | return ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min 35 | } 36 | 37 | function compareVersions(version_1, version_2) { 38 | //remove the first character v 39 | version_1 = version_1.slice(1) 40 | const increments_1 = version_1.split('.').map((sn) => parseInt(sn)) 41 | 42 | version_2 = version_2.slice(1) 43 | const increments_2 = version_2.split('.').map((sn) => parseInt(sn)) 44 | 45 | let b_older = false // true if version_1 is < than version_2, false if version_1 >= older 46 | for (let i = 0; i < increments_1.length; ++i) { 47 | if (increments_1[i] < increments_2[i]) { 48 | b_older = true 49 | break 50 | } 51 | } 52 | return b_older 53 | } 54 | async function requestOnlineData() { 55 | const { requestGet } = require('./api') 56 | const online_data = await requestGet(g_online_data_url) 57 | return online_data 58 | } 59 | function nearestMultiple(input, multiple) { 60 | //use the following formula for finding the upper value instead of the lower. 61 | //( ( x - 1 ) | ( m - 1 ) ) + 1 62 | const nearest_multiple = input - (input % multiple) 63 | return nearest_multiple 64 | } 65 | 66 | function sudoTimer(progress_text = 'Loading ControlNet...') { 67 | //sudo timer that will count to 100 and update the progress bar. 68 | //use it for controlNet since block api progress call 69 | let current_time = 0 70 | let max_time = 100 71 | var timerId = setInterval(countdown, 1000) 72 | 73 | function countdown() { 74 | if (current_time > max_time) { 75 | clearTimeout(timerId) 76 | // doSomething() 77 | // html_manip.updateProgressBarsHtml(0) 78 | } else { 79 | html_manip.updateProgressBarsHtml(current_time, progress_text) 80 | console.log(current_time + ' seconds remaining') 81 | current_time++ 82 | } 83 | } 84 | return timerId 85 | } 86 | function countNewLines(string) { 87 | const count = (string.match(/[\n\r]/g) || []).length 88 | // console.log(count) 89 | return count 90 | } 91 | module.exports = { 92 | newOutputImageName, 93 | makeImagePath, 94 | convertImageNameToPng, 95 | fixNativePath, 96 | base64ToBase64Url, 97 | base64UrlToBase64, 98 | timer, 99 | 100 | mapRange, 101 | compareVersions, 102 | requestOnlineData, 103 | nearestMultiple, 104 | sudoTimer, 105 | countNewLines, 106 | } 107 | -------------------------------------------------------------------------------- /utility/notification.js: -------------------------------------------------------------------------------- 1 | const dialog_box = require('../dialog_box') 2 | const psapi = require('../psapi') 3 | const { createBackgroundLayer } = require('./layer') 4 | class Notification { 5 | static {} 6 | static async webuiIsOffline() { 7 | const r1 = await dialog_box.prompt( 8 | 'Automatic1111 is Offline', 9 | 'make sure Automatic1111 is running in the background', 10 | ['Cancel', 'OK'] 11 | ) 12 | 13 | try { 14 | if (r1 === 'Cancel') { 15 | /* cancelled or No */ 16 | console.log('cancel') 17 | } else if (r1 === 'OK') { 18 | console.log('ok') 19 | } 20 | } catch (e) { 21 | console.warn(e) 22 | } 23 | } 24 | static async webuiAPIMissing() { 25 | const r1 = await dialog_box.prompt( 26 | "The Plugin can't communicate with Automatic1111", 27 | 'Automatic1111 is running, but you forgot to add --api flag to the webui command flags', 28 | ['Cancel', 'OK'] 29 | ) 30 | 31 | try { 32 | if (r1 === 'Cancel') { 33 | /* cancelled or No */ 34 | console.log('cancel') 35 | } else if (r1 === 'OK') { 36 | console.log('ok') 37 | } 38 | } catch (e) { 39 | console.warn(e) 40 | } 41 | } 42 | static async backgroundLayerIsMissing() { 43 | const r1 = await dialog_box.prompt( 44 | 'You need a white background layer present in your document', 45 | '', 46 | ['Cancel', 'Create'] 47 | ) 48 | 49 | try { 50 | if (r1 === 'Cancel') { 51 | /* cancelled or No */ 52 | console.log('cancel') 53 | return false 54 | } else if (r1 === 'Create') { 55 | //store the selection area and then unselected 56 | const selectionInfo = await psapi.getSelectionInfoExe() 57 | await psapi.unSelectMarqueeExe() 58 | const active_layers = app.activeDocument.activeLayers 59 | 60 | //create a background layer with no selection active 61 | await createBackgroundLayer() 62 | console.log('create background layer') 63 | //reselect the selection area if it exist 64 | 65 | await psapi.reSelectMarqueeExe(selectionInfo) 66 | await psapi.selectLayersExe(active_layers) 67 | return true 68 | } 69 | } catch (e) { 70 | console.warn(e) 71 | } 72 | return false 73 | } 74 | static async inactiveSelectionArea( 75 | is_active_session, 76 | button_label = 'Continue Session' 77 | ) { 78 | let buttons = ['Cancel', 'Rectangular Marquee'] 79 | if (is_active_session) { 80 | buttons.push(button_label) 81 | } 82 | const r1 = await dialog_box.prompt( 83 | 'Please Select a Rectangular Area', 84 | 'You Forgot to select a Rectangular Area', 85 | buttons 86 | ) 87 | if (r1 === 'Cancel') { 88 | /* cancelled or No */ 89 | console.log('cancel') 90 | return false 91 | } else if (r1 === 'Rectangular Marquee') { 92 | console.log('Rectangular Marquee') 93 | psapi.selectMarqueeRectangularToolExe() 94 | return false // should this be false?! what does true and false means in this context?! Yes: it should be false since boolean value represent wither we have an active selection area or not 95 | } else if (r1 === button_label) { 96 | await selection_ts.activateSessionSelectionArea() 97 | return true 98 | } 99 | return false 100 | } 101 | } 102 | 103 | module.exports = { 104 | Notification, 105 | } 106 | -------------------------------------------------------------------------------- /utility/online_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "new_version": "v1.4.1", 3 | "update_message": "Your version is outdated.Please visit our Github page and download the one click installer / .ccx file.\nRun the .ccx file and it will automatically update the current version of your plug in. No data will be lost." 4 | } 5 | -------------------------------------------------------------------------------- /utility/sampler.js: -------------------------------------------------------------------------------- 1 | samplers = [ 2 | { 3 | name: 'Euler a', 4 | aliases: ['k_euler_a', 'k_euler_ancestral'], 5 | options: {}, 6 | }, 7 | { 8 | name: 'Euler', 9 | aliases: ['k_euler'], 10 | options: {}, 11 | }, 12 | { 13 | name: 'LMS', 14 | aliases: ['k_lms'], 15 | options: {}, 16 | }, 17 | { 18 | name: 'Heun', 19 | aliases: ['k_heun'], 20 | options: {}, 21 | }, 22 | { 23 | name: 'DPM2', 24 | aliases: ['k_dpm_2'], 25 | options: { 26 | discard_next_to_last_sigma: 'True', 27 | }, 28 | }, 29 | { 30 | name: 'DPM2 a', 31 | aliases: ['k_dpm_2_a'], 32 | options: { 33 | discard_next_to_last_sigma: 'True', 34 | }, 35 | }, 36 | { 37 | name: 'DPM++ 2S a', 38 | aliases: ['k_dpmpp_2s_a'], 39 | options: {}, 40 | }, 41 | { 42 | name: 'DPM++ 2M', 43 | aliases: ['k_dpmpp_2m'], 44 | options: {}, 45 | }, 46 | { 47 | name: 'DPM++ SDE', 48 | aliases: ['k_dpmpp_sde'], 49 | options: {}, 50 | }, 51 | { 52 | name: 'DPM fast', 53 | aliases: ['k_dpm_fast'], 54 | options: {}, 55 | }, 56 | { 57 | name: 'DPM adaptive', 58 | aliases: ['k_dpm_ad'], 59 | options: {}, 60 | }, 61 | { 62 | name: 'LMS Karras', 63 | aliases: ['k_lms_ka'], 64 | options: { 65 | scheduler: 'karras', 66 | }, 67 | }, 68 | { 69 | name: 'DPM2 Karras', 70 | aliases: ['k_dpm_2_ka'], 71 | options: { 72 | scheduler: 'karras', 73 | discard_next_to_last_sigma: 'True', 74 | }, 75 | }, 76 | { 77 | name: 'DPM2 a Karras', 78 | aliases: ['k_dpm_2_a_ka'], 79 | options: { 80 | scheduler: 'karras', 81 | discard_next_to_last_sigma: 'True', 82 | }, 83 | }, 84 | { 85 | name: 'DPM++ 2S a Karras', 86 | aliases: ['k_dpmpp_2s_a_ka'], 87 | options: { 88 | scheduler: 'karras', 89 | }, 90 | }, 91 | { 92 | name: 'DPM++ 2M Karras', 93 | aliases: ['k_dpmpp_2m_ka'], 94 | options: { 95 | scheduler: 'karras', 96 | }, 97 | }, 98 | { 99 | name: 'DPM++ SDE Karras', 100 | aliases: ['k_dpmpp_sde_ka'], 101 | options: { 102 | scheduler: 'karras', 103 | }, 104 | }, 105 | { 106 | name: 'DDIM', 107 | aliases: [], 108 | options: {}, 109 | }, 110 | { 111 | name: 'PLMS', 112 | aliases: [], 113 | options: {}, 114 | }, 115 | ] 116 | 117 | module.exports = { samplers } 118 | -------------------------------------------------------------------------------- /utility/sd_scripts/horde.js: -------------------------------------------------------------------------------- 1 | async function requestModelsHorde() { 2 | //get the models list from url 3 | // https://stablehorde.net/api/v2/status/models 4 | 5 | console.log('requestModelsHorde: ') 6 | 7 | const full_url = 'https://stablehorde.net/api/v2/status/models' 8 | let request = await fetch(full_url) 9 | let json = await request.json() 10 | console.log('hordes models json:') 11 | console.dir(json) 12 | 13 | return json 14 | } 15 | 16 | function addHordeModelMenuItem(model_title, model_name) { 17 | // console.log(model_title,model_name) 18 | const menu_item_element = document.createElement('sp-menu-item') 19 | menu_item_element.className = 'mModelMenuItemHorde' 20 | menu_item_element.innerHTML = model_title 21 | 22 | menu_item_element.dataset.name = model_name 23 | return menu_item_element 24 | } 25 | 26 | async function refreshModelsHorde() { 27 | try { 28 | let g_models_horde = await requestModelsHorde() 29 | // const models_menu_element = document.getElementById('mModelsMenu') 30 | // models_menu_element.value = "" 31 | //(optional): sort the models 32 | 33 | g_models_horde.sort(function (a, b) { 34 | return b.count - a.count 35 | }) 36 | // g_models_horde = g_models_horde.sort( compareModelCounts ); 37 | document.getElementById('mModelsMenuHorde').innerHTML = '' 38 | let model_item_random = addHordeModelMenuItem('Random', 'Random') 39 | // model_item_random.selected = true 40 | document 41 | .getElementById('mModelsMenuHorde') 42 | .appendChild(model_item_random) 43 | for (let model of g_models_horde) { 44 | // console.log(model.name, model.count) //Log 45 | const model_html_tile = `${model.name}: ${model.count}` 46 | const model_item_element = addHordeModelMenuItem( 47 | model_html_tile, 48 | model.name 49 | ) 50 | if (model.name === 'stable_diffusion') { 51 | // TODO: refactor this code outside the for loop 52 | // maybe call it in an init function 53 | //selection the stable diffusion model by default 54 | model_item_element.selected = true 55 | } 56 | document 57 | .getElementById('mModelsMenuHorde') 58 | .appendChild(model_item_element) 59 | } 60 | } catch (e) { 61 | console.warn(e) 62 | } 63 | } 64 | function getModelHorde() { 65 | return [...document.getElementsByClassName('mModelMenuItemHorde')].filter( 66 | (e) => e.selected == true 67 | )[0].dataset.name 68 | } 69 | 70 | function getScriptArgs() { 71 | const model = getModelHorde() 72 | const b_nsfw = document.getElementById('chUseNSFW').checked 73 | const b_shared_laion = document.getElementById('chUseSharedLaion').checked 74 | 75 | let seed_variation = document.getElementById('slSeedVariation').value 76 | seed_variation = parseInt(seed_variation) 77 | const script_args_json = { 78 | model: model, 79 | nsfw: b_nsfw, 80 | shared_laion: b_shared_laion, 81 | seed_variation: seed_variation, 82 | post_processing_1: 'None', 83 | post_processing_2: 'None', 84 | post_processing_3: 'None', 85 | } 86 | const script_args = Object.values(script_args_json) 87 | return script_args 88 | } 89 | 90 | document 91 | .getElementById('btnRefreshModelsHorde') 92 | .addEventListener('click', async () => { 93 | await refreshModelsHorde() 94 | }) 95 | 96 | const script_name = 'Run on Stable Horde' 97 | 98 | refreshModelsHorde() //refresh the model when importing the script 99 | 100 | module.exports = { 101 | requestModelsHorde, 102 | refreshModelsHorde, 103 | getModelHorde, 104 | 105 | getScriptArgs, 106 | script_name, 107 | } 108 | -------------------------------------------------------------------------------- /utility/sdapi/config.js: -------------------------------------------------------------------------------- 1 | class SdConfig { 2 | constructor() { 3 | this.config //store sd options 4 | } 5 | 6 | async getConfig() { 7 | try { 8 | this.config = await sdapi.requestGetConfig() 9 | return this.config 10 | } catch (e) { 11 | console.warn(e) 12 | } 13 | } 14 | getUpscalerModels() { 15 | try { 16 | // const upscaler_comp = this.config.components.filter(comp =>comp.props.elem_id === "txt2img_hr_upscaler")[0] 17 | let upscaler_comp 18 | // console.log('this.config: ', this.config) 19 | for (let comp of this.config.components) { 20 | if (comp?.props?.elem_id) { 21 | const elem_id = comp?.props?.elem_id 22 | if (elem_id === 'txt2img_hr_upscaler') { 23 | console.log('elem_id: ', elem_id) 24 | upscaler_comp = comp 25 | break 26 | } 27 | } 28 | } 29 | console.log('upscaler_comp: ', upscaler_comp) 30 | const upscalers = upscaler_comp.props.choices 31 | 32 | return upscalers 33 | } catch (e) { 34 | console.warn(e) 35 | } 36 | } 37 | 38 | getControlNetMaxModelsNum() { 39 | try { 40 | let max_models_num = 0 41 | for (let comp of this.config.components) { 42 | if (comp?.props?.elem_id) { 43 | const elem_id = comp?.props?.elem_id 44 | if (elem_id === 'setting_control_net_max_models_num') { 45 | console.log( 46 | 'setting_control_net_max_models_num: ', 47 | comp?.props?.value 48 | ) 49 | max_models_num = comp?.props?.value 50 | break 51 | } 52 | } 53 | } 54 | console.log('max_models_num: ', max_models_num) 55 | return max_models_num 56 | } catch (e) { 57 | console.warn(e) 58 | return 1 // default max number is one 59 | } 60 | } 61 | 62 | getControlNetPreprocessors() { 63 | try { 64 | let max_models_num 65 | let choices 66 | for (let comp of this.config.components) { 67 | const label = comp?.props?.label 68 | if (label === 'Preprocessor') { 69 | choices = comp?.props?.choices 70 | break 71 | } 72 | } 73 | console.log('Preprocessor list: ', choices) 74 | return choices 75 | } catch (e) { 76 | console.warn(e) 77 | } 78 | } 79 | } 80 | 81 | module.exports = { 82 | SdConfig, 83 | } 84 | -------------------------------------------------------------------------------- /utility/sdapi/options.js: -------------------------------------------------------------------------------- 1 | class SdOptions { 2 | constructor() { 3 | // this.status = false // true if we have a valid copy of sd options, false otherwise 4 | this.options //store sd options 5 | } 6 | 7 | async getOptions() { 8 | try { 9 | // if (this.status) { 10 | // return this.options 11 | // } else { 12 | // this.options = await sdapi.requestGetOptions() 13 | // if (this.options) { 14 | // this.status = true 15 | // } 16 | // } 17 | this.options = await sdapi.requestGetOptions() 18 | return this.options 19 | } catch (e) { 20 | console.warn(e) 21 | } 22 | } 23 | getCurrentModel() { 24 | const current_model = this.options?.sd_model_checkpoint 25 | return current_model 26 | } 27 | getInpaintingMaskWeight() { 28 | const inpainting_mask_weight = this.options?.inpainting_mask_weight 29 | return inpainting_mask_weight 30 | } 31 | } 32 | // const sd_options = new SdOptions() 33 | // sd_options.option?.sd_model_checkpoint 34 | 35 | module.exports = { 36 | SdOptions, 37 | } 38 | -------------------------------------------------------------------------------- /utility/sdapi/prompt_shortcut.js: -------------------------------------------------------------------------------- 1 | function find_words_inside_braces(string) { 2 | const re = /\{(.*?)\}/g 3 | let keywords = string.match(re) 4 | // console.log('keywords: ', keywords) 5 | if (!keywords) { 6 | //avoid null keywords 7 | keywords = [] 8 | } 9 | return keywords 10 | } 11 | 12 | function replaceShortcut(text, prompt_shortcut_json) { 13 | const original_keywords = find_words_inside_braces(text) 14 | const strip_keywords = original_keywords.map((s) => { 15 | let content = s.slice(1, -1) //remove '{' and '}' 16 | content = content.trim() //remove any space in the beginning and end of content 17 | return content 18 | }) 19 | 20 | let i = 0 21 | for (const word of strip_keywords) { 22 | if (word.length > 0 && prompt_shortcut_json.hasOwnProperty(word)) { 23 | const prompt = prompt_shortcut_json[word] 24 | // console.log('prompt: ', prompt) 25 | text = text.replace(original_keywords[i], prompt) 26 | } 27 | } 28 | // console.log('final text: ', text) 29 | return text 30 | } 31 | module.exports = { 32 | find_words_inside_braces, 33 | replaceShortcut, 34 | } 35 | -------------------------------------------------------------------------------- /utility/tab/image_search_tab.js: -------------------------------------------------------------------------------- 1 | const sdapi = require('../../sdapi_py_re') 2 | const { image_search } = require('../../typescripts/dist/bundle') 3 | 4 | const storage = require('uxp').storage 5 | const fs = storage.localFileSystem 6 | 7 | //REFACTOR: move to events.js 8 | document 9 | .getElementById('btnImageSearch') 10 | .addEventListener('click', async function () { 11 | try { 12 | const keywords = document.getElementById('imageSearchField').value 13 | const image_search_objs = await sdapi.imageSearch(keywords) 14 | 15 | const thumbnails = image_search_objs.map((obj) => obj.thumbnail) 16 | const src_list = image_search_objs.map((obj) => obj.image) 17 | image_search.store.updateProperty('thumbnails', thumbnails) 18 | image_search.store.updateProperty('images', src_list) 19 | } catch (e) { 20 | console.warn(`imageSearch warning: ${e}`) 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /utility/tab/settings.js: -------------------------------------------------------------------------------- 1 | const io = require('../io') 2 | 3 | function setUseSharpMask() { 4 | console.warn('setUseSharpMask is not setup') 5 | } 6 | 7 | document.getElementById('btnGetDocPath').addEventListener('click', async () => { 8 | const docPath = await io.IOFolder.getDocumentFolderNativePath() 9 | document.getElementById('tiDocPath').value = docPath 10 | 11 | const uuid = await getUniqueDocumentId() 12 | doc_entry = await io.IOFolder.getDocFolder(uuid) 13 | await shell.openPath(doc_entry.nativePath) 14 | }) 15 | 16 | document.getElementById('btnSdUrl').addEventListener('click', async () => { 17 | //change the sdUrl in server in proxy server 18 | // console.log('you clicked btnSdUrl') 19 | let new_sd_url = document.getElementById('tiSdUrl').value 20 | changeSdUrl(new_sd_url) 21 | }) 22 | 23 | function getSdUrlHtml() { 24 | let sd_url = document.getElementById('tiSdUrl').value 25 | return sd_url 26 | } 27 | function setSdUrlHtml(sd_url) { 28 | document.getElementById('tiSdUrl').value = sd_url 29 | } 30 | async function changeSdUrl(sd_url) { 31 | sd_url = sd_url.trim() 32 | console.log('sd_url.trim(): ', sd_url) 33 | 34 | if (sd_url.length > 0) { 35 | //check if the last character of the url has "/" or '\' and remove it 36 | 37 | last_index = sd_url.length - 1 38 | 39 | if (sd_url[last_index] === '/' || sd_url[last_index] === '\\') { 40 | sd_url = sd_url.slice(0, -1) 41 | } 42 | 43 | //submit the change 44 | await sdapi.changeSdUrl(sd_url) 45 | } 46 | } 47 | 48 | async function saveSettings() { 49 | const settings_tab_settings = { 50 | use_sharp_mask: settings_tab_ts.store.data.use_sharp_mask, 51 | extension_type: settings_tab_ts.store.data.extension_type, 52 | sd_url: getSdUrlHtml(), 53 | } 54 | 55 | const folder = await io.IOFolder.getSettingsFolder() 56 | await io.IOJson.saveJsonToFile( 57 | settings_tab_settings, 58 | folder, 59 | 'settings_tab.json' 60 | ) 61 | } 62 | async function loadSettings() { 63 | try { 64 | const folder = await io.IOFolder.getSettingsFolder() 65 | let settings_tab_settings = await io.IOJson.loadJsonFromFile( 66 | folder, 67 | 'settings_tab.json' 68 | ) 69 | setSdUrlHtml(settings_tab_settings['sd_url']) 70 | await changeSdUrl(settings_tab_settings['sd_url']) 71 | } catch (e) { 72 | console.warn(e) 73 | } 74 | } 75 | 76 | function getUseOriginalPrompt() { 77 | const b_use_original_prompt = document.getElementById( 78 | 'chUseOriginalPrompt' 79 | ).checked 80 | return b_use_original_prompt 81 | } 82 | 83 | document 84 | .getElementById('btnSaveSettingsTabs') 85 | .addEventListener('click', async () => { 86 | await saveSettings() 87 | }) 88 | 89 | module.exports = { 90 | setUseSharpMask, 91 | 92 | getSdUrlHtml, 93 | setSdUrlHtml, 94 | changeSdUrl, 95 | loadSettings, 96 | saveSettings, 97 | 98 | getUseOriginalPrompt, 99 | } 100 | -------------------------------------------------------------------------------- /utility/tips.js: -------------------------------------------------------------------------------- 1 | //tips that will display when you hover over a html element 2 | const tips_json = { 3 | snapshot: '', 4 | txt2img: 'use this mode to generate images from text only', 5 | img2img: 'use this mode to generate variation of an image', 6 | inpaint: 7 | 'use this mode to generate variation of a small area of an image, while keeping the rest of the image intact', 8 | outpaint: 9 | 'use this mode to (1) fill any missing area of an image,(2) expand an image', 10 | generate: 'create', 11 | discardAll: 'Delete all generated images from the canvas', 12 | acceptAll: 'Keep all generated images on the canvas', 13 | acceptSelected: 'Keep only the highlighted images', 14 | discardSelected: 'Delete only the highlighted images', 15 | modelMenu: 'select a model', 16 | refresh: 'Refresh the plugin, only fixes minor issues.', 17 | prompt_shortcut: 'use {keyword} form the prompts library', 18 | inpaint: 'use when you need to modify an already existing part of an image', 19 | img2img: 'use this mode when you want to generate variation of an image', 20 | txt2img: 'use this mode to generate images based on text only', 21 | batchNumber: 22 | 'the number of images to generate at once.The larger the number more VRAM stable diffusion will use.', 23 | steps: 'how long should stable diffusion take to generate an image', 24 | selection_mode_ratio: 25 | 'will auto fill the width and height slider to the same ratio as the selection area', 26 | selection_mode_precise: 27 | 'auto fill width and height slider to the size as the selection area', 28 | selection_mode_ignore: 29 | 'you will have to fill the width and height slider manually', 30 | cfg_scale: 'larger value will put more emphasis on the prompt', 31 | preset_menu: 32 | 'auto fill the plugin with smart settings, to speed up your working process.', 33 | width: 'the generated image width', 34 | height: 'the generated image height', 35 | mask_expansion: 36 | "the larger the value the more the mask will expand, '0' means use precise masking, use in combination with the mask blur", 37 | mask_content_fill: '', 38 | } 39 | 40 | module.exports = { tips_json } 41 | --------------------------------------------------------------------------------