mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2025-08-15 02:39:13 +02:00
Compare commits
143 Commits
Author | SHA1 | Date | |
---|---|---|---|
dfb26ed781 | |||
547febafba | |||
85eaa305cc | |||
25272ce083 | |||
212fa77b47 | |||
e77629c525 | |||
097780be26 | |||
6489cd785d | |||
a4e651e27e | |||
bedf176e62 | |||
398a0509d7 | |||
52cc99bf1f | |||
824e057d7b | |||
9bd4b3a6d0 | |||
307b00cc05 | |||
8a98df4673 | |||
45a14a9be9 | |||
e419276e34 | |||
0a92b7b1d5 | |||
f110168366 | |||
ce24a05909 | |||
45facf64e5 | |||
e999832c26 | |||
4c8d5a7077 | |||
81643cb3af | |||
7a9bc883df | |||
6280a80129 | |||
a33908b6de | |||
0ea5620413 | |||
e23eb1fea8 | |||
41f2c82eaf | |||
91e3bfe58f | |||
83d5519a31 | |||
cc2666b9d6 | |||
954493fef5 | |||
967c3681cd | |||
87c9df5c0d | |||
62136768d2 | |||
b71b7804fc | |||
e8b7751374 | |||
54d4433141 | |||
14dbebbc35 | |||
d6a02a31a7 | |||
86e2ac40ae | |||
a12ed7533b | |||
9fb0ee2d1b | |||
6311b80474 | |||
c13d1093ee | |||
dd7deeba53 | |||
338aef3e95 | |||
134c98ccb5 | |||
d12877987f | |||
676316e5e4 | |||
52761ad88c | |||
f5e489ba87 | |||
982af1fff3 | |||
1cff398c20 | |||
a6271d2c4e | |||
60f8cc6883 | |||
ffb8feba6b | |||
4aca3c4639 | |||
120f9e567c | |||
c0492511df | |||
1075a5ed93 | |||
58d3507155 | |||
ae0c9b6a6b | |||
ad1374af1d | |||
8436e8a71e | |||
ea07483465 | |||
51f857c3f3 | |||
74c0ca0902 | |||
ad5641fa3e | |||
b0294f8cbd | |||
5d4498ff85 | |||
d52fb15746 | |||
ee6be74e72 | |||
4cbc86f945 | |||
3a5e0cb2d2 | |||
7916b8d26a | |||
a0842b4659 | |||
14ee87ca80 | |||
cec1d7d6c9 | |||
9aeae4d16e | |||
9c1b741d89 | |||
c71a74f857 | |||
524612cee5 | |||
11e47b3871 | |||
4a1b2be45c | |||
d641aa2f6e | |||
237c7a5348 | |||
19f37907d9 | |||
b8706da990 | |||
b458d57355 | |||
a5962dae33 | |||
670768e5b3 | |||
f02b915cd0 | |||
71bbbeb936 | |||
e084b78b53 | |||
013860e3c0 | |||
7a118eeb15 | |||
df408b25e5 | |||
536082c1a6 | |||
b986ca3059 | |||
4bf9e577b9 | |||
a7c12e61d8 | |||
847d27bffb | |||
781e812f22 | |||
e49b5e0e6b | |||
8f1c1b128e | |||
04cbb052d7 | |||
16f0950ebd | |||
e959a3d7ab | |||
fc9941abaa | |||
f177011395 | |||
80e47be5a5 | |||
9a9f6e3559 | |||
1a6e0234b3 | |||
56bea46e3a | |||
a09441b2c8 | |||
105994d96d | |||
d641647b1e | |||
672574d278 | |||
f1ded17399 | |||
d254e3e2fd | |||
ab5450bb27 | |||
a2e9e5eb57 | |||
8965f11ab4 | |||
1dd5644e7a | |||
37f813506e | |||
a5d5ed90e6 | |||
3792a1bc0d | |||
fbafa56ecb | |||
2f910c69b8 | |||
bf06cc48bb | |||
3ef67ebc73 | |||
0c4318fb31 | |||
c55ced93db | |||
807d940001 | |||
8c27fa136c | |||
8e7a6077e5 | |||
53a79c1a81 | |||
e9f54c8bae | |||
c978863e5f |
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@ installer.tar
|
||||
dist
|
||||
.idea/*
|
||||
node_modules/*
|
||||
.tmp1
|
||||
.tmp2
|
||||
|
12
CHANGES.md
12
CHANGES.md
@ -17,6 +17,18 @@
|
||||
- **Major rewrite of the code** - We've switched to using diffusers under-the-hood, which allows us to release new features faster, and focus on making the UI and installer even easier to use.
|
||||
|
||||
### Detailed changelog
|
||||
* 3.0.7 - 11 Dec 2023 - Setting to enable/disable VAE tiling (in the Image Settings panel). Sometimes VAE tiling reduces the quality of the image, so this setting will help control that.
|
||||
* 3.0.6 - 18 Sep 2023 - Add thumbnails to embeddings from the UI, using the new `Upload Thumbnail` button in the Embeddings popup. Thanks @JeLuf.
|
||||
* 3.0.6 - 15 Sep 2023 - Fix broken embeddings dialog when LoRA information couldn't be fetched.
|
||||
* 3.0.6 - 14 Sep 2023 - UI for adding notes to LoRA files (to help you remember which prompts to use). Also added a button to automatically fetch prompts from Civitai for a LoRA file, using the `Import from Civitai` button. Thanks @JeLuf.
|
||||
* 3.0.5 - 2 Sep 2023 - Support SDXL ControlNets.
|
||||
* 3.0.4 - 1 Sep 2023 - Fix incorrect metadata generated for embeddings, when the exact word doesn't match the case, or is part of a larger word.
|
||||
* 3.0.4 - 1 Sep 2023 - Simplify the installation for AMD users on Linux. Thanks @JeLuf.
|
||||
* 3.0.4 - 1 Sep 2023 - Allow using a different folder for models. This is useful if you want to share a models folder across different software, or on a different drive. You can change this path in the Settings tab.
|
||||
* 3.0.3 - 31 Aug 2023 - Auto-save images to disk (if enabled by the user) when upscaling/fixing using the buttons on the image.
|
||||
* 3.0.3 - 30 Aug 2023 - Allow loading NovelAI-based custom models.
|
||||
* 3.0.3 - 30 Aug 2023 - Fix broken VAE tiling. This allows you to create larger images with lesser VRAM usage.
|
||||
* 3.0.3 - 30 Aug 2023 - Allow blocking NSFW images using a server-side config. This prevents the browser from generating NSFW images or changing the config. Open `config.yaml` in a text editor (e.g. Notepad), and add `block_nsfw: true` at the end, and save the file.
|
||||
* 3.0.2 - 29 Aug 2023 - Fixed incorrect matching of embeddings from prompts.
|
||||
* 3.0.2 - 24 Aug 2023 - Fix broken seamless tiling.
|
||||
* 3.0.2 - 23 Aug 2023 - Fix styling on mobile devices.
|
||||
|
@ -47,3 +47,5 @@ Build the Windows installer using Windows, and the Linux installer using Linux.
|
||||
|
||||
1. Run `build.bat` or `./build.sh` depending on whether you're in Windows or Linux.
|
||||
2. Make a new GitHub release and upload the Windows and Linux installer builds created inside the `dist` folder.
|
||||
|
||||
For NSIS (on Windows), you need to have these plugins in the `nsis/Plugins` folder: `amd64-unicode`, `x86-ansi`, `x86-unicode`
|
||||
|
BIN
NSIS/astro.bmp
BIN
NSIS/astro.bmp
Binary file not shown.
Before Width: | Height: | Size: 288 KiB |
@ -1 +0,0 @@
|
||||
!define EXISTING_INSTALLATION_DIR "D:\path\to\installed\easy-diffusion"
|
BIN
NSIS/sd.ico
BIN
NSIS/sd.ico
Binary file not shown.
Before Width: | Height: | Size: 200 KiB |
@ -7,9 +7,9 @@ RequestExecutionLevel user
|
||||
!AddPluginDir /amd64-unicode "."
|
||||
; HM NIS Edit Wizard helper defines
|
||||
!define PRODUCT_NAME "Easy Diffusion"
|
||||
!define PRODUCT_VERSION "2.5"
|
||||
!define PRODUCT_VERSION "3.0"
|
||||
!define PRODUCT_PUBLISHER "cmdr2 and contributors"
|
||||
!define PRODUCT_WEB_SITE "https://stable-diffusion-ui.github.io"
|
||||
!define PRODUCT_WEB_SITE "https://easydiffusion.github.io"
|
||||
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Easy Diffusion\App Paths\installer.exe"
|
||||
|
||||
; MUI 1.67 compatible ------
|
||||
@ -165,9 +165,9 @@ FunctionEnd
|
||||
; MUI Settings
|
||||
;---------------------------------------------------------------------------------------------------------
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_ICON "cyborg_flower_girl.ico"
|
||||
!define MUI_ICON "${EXISTING_INSTALLATION_DIR}\installer_files\cyborg_flower_girl.ico"
|
||||
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "cyborg_flower_girl.bmp"
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "${EXISTING_INSTALLATION_DIR}\installer_files\cyborg_flower_girl.bmp"
|
||||
|
||||
; Welcome page
|
||||
!define MUI_WELCOMEPAGE_TEXT "This installer will guide you through the installation of Easy Diffusion.$\n$\n\
|
||||
@ -176,8 +176,8 @@ Click Next to continue."
|
||||
Page custom MediaPackDialog
|
||||
|
||||
; License page
|
||||
!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
|
||||
!insertmacro MUI_PAGE_LICENSE "..\CreativeML Open RAIL-M License"
|
||||
!insertmacro MUI_PAGE_LICENSE "${EXISTING_INSTALLATION_DIR}\LICENSE"
|
||||
!insertmacro MUI_PAGE_LICENSE "${EXISTING_INSTALLATION_DIR}\CreativeML Open RAIL-M License"
|
||||
; Directory page
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE "DirectoryLeave"
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
@ -210,29 +210,33 @@ ShowInstDetails show
|
||||
; List of files to be installed
|
||||
Section "MainSection" SEC01
|
||||
SetOutPath "$INSTDIR"
|
||||
File "..\CreativeML Open RAIL-M License"
|
||||
File "..\How to install and run.txt"
|
||||
File "..\LICENSE"
|
||||
File "..\scripts\Start Stable Diffusion UI.cmd"
|
||||
File "${EXISTING_INSTALLATION_DIR}\CreativeML Open RAIL-M License"
|
||||
File "${EXISTING_INSTALLATION_DIR}\How to install and run.txt"
|
||||
File "${EXISTING_INSTALLATION_DIR}\LICENSE"
|
||||
File "${EXISTING_INSTALLATION_DIR}\Start Stable Diffusion UI.cmd"
|
||||
File /r "${EXISTING_INSTALLATION_DIR}\installer_files"
|
||||
File /r "${EXISTING_INSTALLATION_DIR}\profile"
|
||||
File /r "${EXISTING_INSTALLATION_DIR}\sd-ui-files"
|
||||
SetOutPath "$INSTDIR\installer_files"
|
||||
File "cyborg_flower_girl.ico"
|
||||
|
||||
SetOutPath "$INSTDIR\scripts"
|
||||
File "${EXISTING_INSTALLATION_DIR}\scripts\install_status.txt"
|
||||
File "..\scripts\on_env_start.bat"
|
||||
File "${EXISTING_INSTALLATION_DIR}\scripts\on_env_start.bat"
|
||||
File "C:\windows\system32\curl.exe"
|
||||
CreateDirectory "$INSTDIR\models"
|
||||
File "${EXISTING_INSTALLATION_DIR}\scripts\config.yaml.sample"
|
||||
|
||||
CreateDirectory "$INSTDIR\models\stable-diffusion"
|
||||
CreateDirectory "$INSTDIR\models\gfpgan"
|
||||
CreateDirectory "$INSTDIR\models\realesrgan"
|
||||
CreateDirectory "$INSTDIR\models\vae"
|
||||
|
||||
CreateDirectory "$INSTDIR\profile\.cache\huggingface\hub"
|
||||
SetOutPath "$INSTDIR\profile\.cache\huggingface\hub"
|
||||
File /r /x pytorch_model.bin "${EXISTING_INSTALLATION_DIR}\profile\.cache\huggingface\hub\models--openai--clip-vit-large-patch14"
|
||||
|
||||
CreateDirectory "$SMPROGRAMS\Easy Diffusion"
|
||||
CreateShortCut "$SMPROGRAMS\Easy Diffusion\Easy Diffusion.lnk" "$INSTDIR\Start Stable Diffusion UI.cmd" "" "$INSTDIR\installer_files\cyborg_flower_girl.ico"
|
||||
|
||||
DetailPrint 'Downloading the Stable Diffusion 1.4 model...'
|
||||
NScurl::http get "https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt" "$INSTDIR\models\stable-diffusion\sd-v1-4.ckpt" /CANCEL /INSIST /END
|
||||
DetailPrint 'Downloading the Stable Diffusion 1.5 model...'
|
||||
NScurl::http get "https://github.com/easydiffusion/sdkit-test-data/releases/download/assets/sd-v1-5.safetensors" "$INSTDIR\models\stable-diffusion\sd-v1-5.safetensors" /CANCEL /INSIST /END
|
||||
|
||||
DetailPrint 'Downloading the GFPGAN model...'
|
||||
NScurl::http get "https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/GFPGANv1.4.pth" "$INSTDIR\models\gfpgan\GFPGANv1.4.pth" /CANCEL /INSIST /END
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
Does not require technical knowledge, does not require pre-installed software. 1-click install, powerful features, friendly community.
|
||||
|
||||
[Installation guide](#installation) | [Troubleshooting guide](https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting) | <sub>[](https://discord.com/invite/u9yhsFmEkB)</sub> <sup>(for support queries, and development discussions)</sup>
|
||||
️🔥🎉 **New!** Support for SDXL, ControlNet, multiple LoRA files, embeddings (and a lot more) have been added!
|
||||
|
||||
[Installation guide](#installation) | [Troubleshooting guide](https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting) | [User guide](https://github.com/easydiffusion/easydiffusion/wiki) | <sub>[](https://discord.com/invite/u9yhsFmEkB)</sub> <sup>(for support queries, and development discussions)</sup>
|
||||
|
||||
---
|
||||

|
||||
@ -102,7 +104,7 @@ Just delete the `EasyDiffusion` folder to uninstall all the downloaded packages.
|
||||
- **Auto scan for malicious models**: Uses picklescan to prevent malicious models.
|
||||
- **Safetensors support**: Support loading models in the safetensor format, for improved safety.
|
||||
- **Auto-updater**: Gets you the latest improvements and bug-fixes to a rapidly evolving project.
|
||||
- **Developer Console**: A developer-mode for those who want to modify their Stable Diffusion code, and edit the conda environment.
|
||||
- **Developer Console**: A developer-mode for those who want to modify their Stable Diffusion code, modify packages, and edit the conda environment.
|
||||
|
||||
**(and a lot more)**
|
||||
|
||||
|
94
build.bat
94
build.bat
@ -1,48 +1,78 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
@echo "Hi there, what you are running is meant for the developers of this project, not for users." & echo.
|
||||
@echo "If you only want to use the Stable Diffusion UI, you've downloaded the wrong file."
|
||||
@echo "If you only want to use Easy Diffusion, you've downloaded the wrong file."
|
||||
@echo "Please download and follow the instructions at https://github.com/easydiffusion/easydiffusion#installation" & echo.
|
||||
@echo "If you are actually a developer of this project, please type Y and press enter" & echo.
|
||||
|
||||
set /p answer=Are you a developer of this project (Y/N)?
|
||||
if /i "%answer:~,1%" NEQ "Y" exit /b
|
||||
|
||||
mkdir dist\win\stable-diffusion-ui\scripts
|
||||
@REM mkdir dist\linux-mac\stable-diffusion-ui\scripts
|
||||
@rem verify dependencies
|
||||
call makensis /VERSION >.tmp1 2>.tmp2
|
||||
if "!ERRORLEVEL!" NEQ "0" (
|
||||
echo makensis.exe not found! Download it from https://sourceforge.net/projects/nsisbi/files/ and set it on the PATH variable.
|
||||
pause
|
||||
exit
|
||||
)
|
||||
|
||||
@rem copy the installer files for Windows
|
||||
set /p OUT_DIR=Output folder path (will create the installer files inside this, e.g. F:\EasyDiffusion):
|
||||
|
||||
copy scripts\on_env_start.bat dist\win\stable-diffusion-ui\scripts\
|
||||
copy scripts\bootstrap.bat dist\win\stable-diffusion-ui\scripts\
|
||||
copy scripts\config.yaml.sample dist\win\stable-diffusion-ui\scripts\config.yaml
|
||||
copy "scripts\Start Stable Diffusion UI.cmd" dist\win\stable-diffusion-ui\
|
||||
copy LICENSE dist\win\stable-diffusion-ui\
|
||||
copy "CreativeML Open RAIL-M License" dist\win\stable-diffusion-ui\
|
||||
copy "How to install and run.txt" dist\win\stable-diffusion-ui\
|
||||
echo. > dist\win\stable-diffusion-ui\scripts\install_status.txt
|
||||
mkdir "%OUT_DIR%\scripts"
|
||||
mkdir "%OUT_DIR%\installer_files"
|
||||
|
||||
@rem copy the installer files for Linux and Mac
|
||||
set BASE_DIR=%cd%
|
||||
|
||||
@REM copy scripts\on_env_start.sh dist\linux-mac\stable-diffusion-ui\scripts\
|
||||
@REM copy scripts\bootstrap.sh dist\linux-mac\stable-diffusion-ui\scripts\
|
||||
@REM copy scripts\start.sh dist\linux-mac\stable-diffusion-ui\
|
||||
@REM copy LICENSE dist\linux-mac\stable-diffusion-ui\
|
||||
@REM copy "CreativeML Open RAIL-M License" dist\linux-mac\stable-diffusion-ui\
|
||||
@REM copy "How to install and run.txt" dist\linux-mac\stable-diffusion-ui\
|
||||
@REM echo. > dist\linux-mac\stable-diffusion-ui\scripts\install_status.txt
|
||||
@rem STEP 1: copy the installer files for Windows
|
||||
|
||||
@rem make the zip
|
||||
|
||||
cd dist\win
|
||||
call powershell Compress-Archive -Path stable-diffusion-ui -DestinationPath ..\stable-diffusion-ui-windows.zip
|
||||
cd ..\..
|
||||
|
||||
@REM cd dist\linux-mac
|
||||
@REM call powershell Compress-Archive -Path stable-diffusion-ui -DestinationPath ..\stable-diffusion-ui-linux.zip
|
||||
@REM call powershell Compress-Archive -Path stable-diffusion-ui -DestinationPath ..\stable-diffusion-ui-mac.zip
|
||||
@REM cd ..\..
|
||||
|
||||
echo "Build ready. Upload the zip files inside the 'dist' folder."
|
||||
copy "%BASE_DIR%\scripts\on_env_start.bat" "%OUT_DIR%\scripts\"
|
||||
copy "%BASE_DIR%\scripts\config.yaml.sample" "%OUT_DIR%\scripts\config.yaml.sample"
|
||||
copy "%BASE_DIR%\scripts\Start Stable Diffusion UI.cmd" "%OUT_DIR%\"
|
||||
copy "%BASE_DIR%\LICENSE" "%OUT_DIR%\"
|
||||
copy "%BASE_DIR%\CreativeML Open RAIL-M License" "%OUT_DIR%\"
|
||||
copy "%BASE_DIR%\How to install and run.txt" "%OUT_DIR%\"
|
||||
copy "%BASE_DIR%\NSIS\cyborg_flower_girl.ico" "%OUT_DIR%\installer_files\"
|
||||
copy "%BASE_DIR%\NSIS\cyborg_flower_girl.bmp" "%OUT_DIR%\installer_files\"
|
||||
echo. > "%OUT_DIR%\scripts\install_status.txt"
|
||||
|
||||
echo ----
|
||||
echo Basic files ready. Verify the files in %OUT_DIR%, then press Enter to initialize the environment, or close to quit.
|
||||
echo ----
|
||||
pause
|
||||
|
||||
@rem STEP 2: Initialize the environment with git, python and conda
|
||||
|
||||
cd /d "%OUT_DIR%\"
|
||||
call "%BASE_DIR%\scripts\bootstrap.bat"
|
||||
|
||||
echo ----
|
||||
echo Environment ready. Verify the environment, then press Enter to download the necessary packages, or close to quit.
|
||||
echo ----
|
||||
pause
|
||||
|
||||
@rem STEP 3: Download the packages and create a working installation
|
||||
|
||||
cd /d "%OUT_DIR%\"
|
||||
start "Install Easy Diffusion" /D "%OUT_DIR%" "Start Stable Diffusion UI.cmd"
|
||||
|
||||
echo ----
|
||||
echo Installation in progress (in a new window). Once complete, verify the installation, then press Enter to create an installer from these files, or close to quit.
|
||||
echo ----
|
||||
pause
|
||||
|
||||
@rem STEP 4: Build the installer from a working installation
|
||||
|
||||
cd /d "%OUT_DIR%\"
|
||||
|
||||
echo ^^!define EXISTING_INSTALLATION_DIR "%OUT_DIR%" > nsisconf.nsh
|
||||
call makensis /NOCD /V4 "%BASE_DIR%\NSIS\sdui.nsi"
|
||||
|
||||
echo ----
|
||||
if "!ERRORLEVEL!" EQU "0" (
|
||||
echo Installer built successfully at %OUT_DIR%
|
||||
) else (
|
||||
echo Installer failed to build at %OUT_DIR%
|
||||
)
|
||||
echo ----
|
||||
pause
|
46
build.sh
46
build.sh
@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "Hi there, what you are running is meant for the developers of this project, not for users.\n\n"
|
||||
printf "If you only want to use the Stable Diffusion UI, you've downloaded the wrong file.\n"
|
||||
printf "If you only want to use Easy Diffusion, you've downloaded the wrong file.\n"
|
||||
printf "Please download and follow the instructions at https://github.com/easydiffusion/easydiffusion#installation \n\n"
|
||||
printf "If you are actually a developer of this project, please type Y and press enter\n\n"
|
||||
|
||||
@ -11,40 +11,30 @@ case $yn in
|
||||
* ) exit;;
|
||||
esac
|
||||
|
||||
# mkdir -p dist/win/stable-diffusion-ui/scripts
|
||||
mkdir -p dist/linux-mac/stable-diffusion-ui/scripts
|
||||
|
||||
# copy the installer files for Windows
|
||||
|
||||
# cp scripts/on_env_start.bat dist/win/stable-diffusion-ui/scripts/
|
||||
# cp scripts/bootstrap.bat dist/win/stable-diffusion-ui/scripts/
|
||||
# cp "scripts/Start Stable Diffusion UI.cmd" dist/win/stable-diffusion-ui/
|
||||
# cp LICENSE dist/win/stable-diffusion-ui/
|
||||
# cp "CreativeML Open RAIL-M License" dist/win/stable-diffusion-ui/
|
||||
# cp "How to install and run.txt" dist/win/stable-diffusion-ui/
|
||||
# echo "" > dist/win/stable-diffusion-ui/scripts/install_status.txt
|
||||
mkdir -p dist/linux-mac/easy-diffusion/scripts
|
||||
|
||||
# copy the installer files for Linux and Mac
|
||||
|
||||
cp scripts/on_env_start.sh dist/linux-mac/stable-diffusion-ui/scripts/
|
||||
cp scripts/bootstrap.sh dist/linux-mac/stable-diffusion-ui/scripts/
|
||||
cp scripts/functions.sh dist/linux-mac/stable-diffusion-ui/scripts/
|
||||
cp scripts/config.yaml.sample dist/linux-mac/stable-diffusion-ui/scripts/config.yaml
|
||||
cp scripts/start.sh dist/linux-mac/stable-diffusion-ui/
|
||||
cp LICENSE dist/linux-mac/stable-diffusion-ui/
|
||||
cp "CreativeML Open RAIL-M License" dist/linux-mac/stable-diffusion-ui/
|
||||
cp "How to install and run.txt" dist/linux-mac/stable-diffusion-ui/
|
||||
echo "" > dist/linux-mac/stable-diffusion-ui/scripts/install_status.txt
|
||||
cp scripts/on_env_start.sh dist/linux-mac/easy-diffusion/scripts/
|
||||
cp scripts/bootstrap.sh dist/linux-mac/easy-diffusion/scripts/
|
||||
cp scripts/functions.sh dist/linux-mac/easy-diffusion/scripts/
|
||||
cp scripts/config.yaml.sample dist/linux-mac/easy-diffusion/scripts/config.yaml.sample
|
||||
cp scripts/start.sh dist/linux-mac/easy-diffusion/
|
||||
cp LICENSE dist/linux-mac/easy-diffusion/
|
||||
cp "CreativeML Open RAIL-M License" dist/linux-mac/easy-diffusion/
|
||||
cp "How to install and run.txt" dist/linux-mac/easy-diffusion/
|
||||
echo "" > dist/linux-mac/easy-diffusion/scripts/install_status.txt
|
||||
|
||||
# set the permissions
|
||||
chmod u+x dist/linux-mac/easy-diffusion/scripts/on_env_start.sh
|
||||
chmod u+x dist/linux-mac/easy-diffusion/scripts/bootstrap.sh
|
||||
chmod u+x dist/linux-mac/easy-diffusion/start.sh
|
||||
|
||||
# make the zip
|
||||
|
||||
# cd dist/win
|
||||
# zip -r ../stable-diffusion-ui-windows.zip stable-diffusion-ui
|
||||
# cd ../..
|
||||
|
||||
cd dist/linux-mac
|
||||
zip -r ../stable-diffusion-ui-linux.zip stable-diffusion-ui
|
||||
zip -r ../stable-diffusion-ui-mac.zip stable-diffusion-ui
|
||||
zip -r ../Easy-Diffusion-Linux.zip easy-diffusion
|
||||
zip -r ../Easy-Diffusion-Mac.zip easy-diffusion
|
||||
cd ../..
|
||||
|
||||
echo "Build ready. Upload the zip files inside the 'dist' folder."
|
||||
|
BIN
patch.patch
BIN
patch.patch
Binary file not shown.
@ -15,7 +15,7 @@ if exist "on_sd_start.bat" (
|
||||
echo download. This will not work.
|
||||
echo.
|
||||
echo Recommended: Please close this window and download the installer from
|
||||
echo https://stable-diffusion-ui.github.io/docs/installation/
|
||||
echo https://easydiffusion.github.io/docs/installation/
|
||||
echo.
|
||||
echo ================================================================================
|
||||
echo.
|
||||
@ -39,6 +39,7 @@ call where conda
|
||||
call conda --version
|
||||
echo .
|
||||
echo COMSPEC=%COMSPEC%
|
||||
wmic path win32_VideoController get name,AdapterRAM,DriverDate,DriverVersion
|
||||
|
||||
@rem Download the rest of the installer and UI
|
||||
call scripts\on_env_start.bat
|
||||
|
@ -14,6 +14,8 @@ set LEGACY_INSTALL_ENV_DIR=%cd%\installer
|
||||
set MICROMAMBA_DOWNLOAD_URL=https://github.com/easydiffusion/easydiffusion/releases/download/v1.1/micromamba.exe
|
||||
set umamba_exists=F
|
||||
|
||||
set PYTHONHOME=
|
||||
|
||||
set OLD_APPDATA=%APPDATA%
|
||||
set OLD_USERPROFILE=%USERPROFILE%
|
||||
set APPDATA=%cd%\installer_files\appdata
|
||||
@ -22,15 +24,12 @@ set USERPROFILE=%cd%\profile
|
||||
@rem figure out whether git and conda needs to be installed
|
||||
if exist "%INSTALL_ENV_DIR%" set PATH=%INSTALL_ENV_DIR%;%INSTALL_ENV_DIR%\Library\bin;%INSTALL_ENV_DIR%\Scripts;%INSTALL_ENV_DIR%\Library\usr\bin;%PATH%
|
||||
|
||||
set PACKAGES_TO_INSTALL=
|
||||
set PACKAGES_TO_INSTALL=git python=3.8.5
|
||||
|
||||
if not exist "%LEGACY_INSTALL_ENV_DIR%\etc\profile.d\conda.sh" (
|
||||
if not exist "%INSTALL_ENV_DIR%\etc\profile.d\conda.sh" set PACKAGES_TO_INSTALL=%PACKAGES_TO_INSTALL% conda python=3.8.5
|
||||
if not exist "%INSTALL_ENV_DIR%\etc\profile.d\conda.sh" set PACKAGES_TO_INSTALL=%PACKAGES_TO_INSTALL% conda
|
||||
)
|
||||
|
||||
call git --version >.tmp1 2>.tmp2
|
||||
if "!ERRORLEVEL!" NEQ "0" set PACKAGES_TO_INSTALL=%PACKAGES_TO_INSTALL% git
|
||||
|
||||
call "%MAMBA_ROOT_PREFIX%\micromamba.exe" --version >.tmp1 2>.tmp2
|
||||
if "!ERRORLEVEL!" EQU "0" set umamba_exists=T
|
||||
|
||||
|
@ -8,18 +8,21 @@ a custom index URL depending on the platform.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import os, sys
|
||||
from importlib.metadata import version as pkg_version
|
||||
import platform
|
||||
import traceback
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from pprint import pprint
|
||||
|
||||
os_name = platform.system()
|
||||
|
||||
modules_to_check = {
|
||||
"torch": ("1.11.0", "1.13.1", "2.0.0"),
|
||||
"torchvision": ("0.12.0", "0.14.1", "0.15.1"),
|
||||
"sdkit": "2.0.3",
|
||||
"stable-diffusion-sdkit": "2.1.4",
|
||||
"torch": ("1.11.0", "1.13.1", "2.0.0", "2.0.1"),
|
||||
"torchvision": ("0.12.0", "0.14.1", "0.15.1", "0.15.2"),
|
||||
"sdkit": "2.0.15",
|
||||
"stable-diffusion-sdkit": "2.1.5",
|
||||
"rich": "12.6.0",
|
||||
"uvicorn": "0.19.0",
|
||||
"fastapi": "0.85.1",
|
||||
@ -48,9 +51,20 @@ def install(module_name: str, module_version: str):
|
||||
module_version, index_url = apply_torch_install_overrides(module_version)
|
||||
|
||||
if is_amd_on_linux(): # hack until AMD works properly on torch 2.0 (avoids black images on some cards)
|
||||
amd_gpus = setup_amd_environment()
|
||||
if module_name == "torch":
|
||||
if "Navi 3" in amd_gpus:
|
||||
# No AMD 7x00 support in rocm 5.2, needs nightly 5.5. build
|
||||
module_version = "2.1.0.dev-20230614+rocm5.5"
|
||||
index_url = "https://download.pytorch.org/whl/nightly/rocm5.5"
|
||||
else:
|
||||
module_version = "1.13.1+rocm5.2"
|
||||
elif module_name == "torchvision":
|
||||
if "Navi 3" in amd_gpus:
|
||||
# No AMD 7x00 support in rocm 5.2, needs nightly 5.5. build
|
||||
module_version = "0.16.0.dev-20230614+rocm5.5"
|
||||
index_url = "https://download.pytorch.org/whl/nightly/rocm5.5"
|
||||
else:
|
||||
module_version = "0.14.1+rocm5.2"
|
||||
elif os_name == "Darwin":
|
||||
if module_name == "torch":
|
||||
@ -69,9 +83,9 @@ def install(module_name: str, module_version: str):
|
||||
os.system(install_cmd)
|
||||
|
||||
|
||||
def init():
|
||||
def update_modules():
|
||||
for module_name, allowed_versions in modules_to_check.items():
|
||||
if os.path.exists(f"../src/{module_name}"):
|
||||
if os.path.exists(f"src/{module_name}"):
|
||||
print(f"Skipping {module_name} update, since it's in developer/editable mode")
|
||||
continue
|
||||
|
||||
@ -94,6 +108,10 @@ def init():
|
||||
except:
|
||||
traceback.print_exc()
|
||||
fail(module_name)
|
||||
else:
|
||||
if version(module_name) != latest_version:
|
||||
print(f"WARNING! Tried to install {module_name}=={latest_version}, but the version is still {version(module_name)}!")
|
||||
|
||||
|
||||
if module_name in modules_to_log:
|
||||
print(f"{module_name}: {version(module_name)}")
|
||||
@ -159,7 +177,930 @@ Thanks!"""
|
||||
)
|
||||
exit(1)
|
||||
|
||||
### Launcher
|
||||
|
||||
### start
|
||||
def get_config():
|
||||
config_directory = os.path.dirname(__file__) # this will be "scripts"
|
||||
config_yaml = os.path.join(config_directory, "..", "config.yaml")
|
||||
config_json = os.path.join(config_directory, "config.json")
|
||||
|
||||
init()
|
||||
config = None
|
||||
|
||||
# migrate the old config yaml location
|
||||
config_legacy_yaml = os.path.join(config_directory, "config.yaml")
|
||||
if os.path.isfile(config_legacy_yaml):
|
||||
shutil.move(config_legacy_yaml, config_yaml)
|
||||
|
||||
if os.path.isfile(config_yaml):
|
||||
from ruamel.yaml import YAML
|
||||
yaml = YAML(typ='safe')
|
||||
with open(config_yaml, 'r') as configfile:
|
||||
try:
|
||||
config = yaml.load(configfile)
|
||||
except Exception as e:
|
||||
print(e, file=sys.stderr)
|
||||
elif os.path.isfile(config_json):
|
||||
import json
|
||||
with open(config_json, 'r') as configfile:
|
||||
try:
|
||||
config = json.load(configfile)
|
||||
except Exception as e:
|
||||
print(e, file=sys.stderr)
|
||||
|
||||
if config is None:
|
||||
config = {}
|
||||
return config
|
||||
|
||||
|
||||
def setup_amd_environment():
|
||||
if not os.access("/dev/kfd", os.W_OK):
|
||||
print(
|
||||
"#########################################################################\n"
|
||||
+ "# EasyDiffusion has no write access to /dev/kfd. #\n"
|
||||
+ "#########################################################################\n"
|
||||
+ "\n"
|
||||
+ "Without this, the ROCm driver will probably not be able to initialize the GPU and EasyDiffusion will use the CPU for rendering.\n"
|
||||
+ "\n"
|
||||
+ "Follow the instructions on this site to configure the access:\n"
|
||||
+ "https://github.com/easydiffusion/easydiffusion/wiki/AMD-on-Linux#access-permissions\n"
|
||||
+ "\n"
|
||||
)
|
||||
|
||||
gpus = list(filter(lambda x: ("amdgpu" in x), open("/proc/bus/pci/devices", "r").readlines()))
|
||||
gpus = [ x.split("\t")[1].upper() for x in gpus ]
|
||||
gpus = [ AMD_PCI_IDs[x] for x in gpus if x in AMD_PCI_IDs ]
|
||||
i=0
|
||||
supported_gpus=[]
|
||||
for gpu in gpus:
|
||||
print(f"Found AMD GPU {gpu}.")
|
||||
if gpu.startswith("Navi 1"):
|
||||
print("--- Applying Navi 1 settings")
|
||||
os.environ["HSA_OVERRIDE_GFX_VERSION"]="10.3.0"
|
||||
os.environ["FORCE_FULL_PRECISION"]="yes"
|
||||
os.environ["HIP_VISIBLE_DEVICES"]=str(i)
|
||||
supported_gpus.append("Navi 1")
|
||||
elif gpu.startswith("Navi 2"):
|
||||
print("--- Applying Navi 2 settings")
|
||||
os.environ["HSA_OVERRIDE_GFX_VERSION"]="10.3.0"
|
||||
os.environ["HIP_VISIBLE_DEVICES"]=str(i)
|
||||
supported_gpus.append("Navi 2")
|
||||
elif gpu.startswith("Navi 3"):
|
||||
print("--- Applying Navi 3 settings")
|
||||
os.environ["HSA_OVERRIDE_GFX_VERSION"]="11.0.0"
|
||||
os.environ["HIP_VISIBLE_DEVICES"]=str(i)
|
||||
supported_gpus.append("Navi 3")
|
||||
else:
|
||||
print("--- This GPU is probably not supported by ROCm\n")
|
||||
i+=1
|
||||
return supported_gpus
|
||||
|
||||
|
||||
def launch_uvicorn():
|
||||
config = get_config()
|
||||
|
||||
pprint(config)
|
||||
|
||||
with open("scripts/install_status.txt","a") as f:
|
||||
f.write("sd_weights_downloaded\n")
|
||||
f.write("sd_install_complete\n")
|
||||
|
||||
print("\n\nEasy Diffusion installation complete, starting the server!\n\n")
|
||||
|
||||
os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
|
||||
if os_name == "Windows":
|
||||
os.environ["PYTHONPATH"] = str(Path( os.environ["INSTALL_ENV_DIR"], "lib", "site-packages"))
|
||||
else:
|
||||
os.environ["PYTHONPATH"] = str(Path( os.environ["INSTALL_ENV_DIR"], "lib", "python3.8", "site-packages"))
|
||||
os.environ["SD_UI_PATH"] = str(Path(Path.cwd(), "ui"))
|
||||
|
||||
print(f"PYTHONPATH={os.environ['PYTHONPATH']}")
|
||||
print(f"Python: {shutil.which('python')}")
|
||||
print(f"Version: {platform. python_version()}")
|
||||
|
||||
bind_ip = "127.0.0.1"
|
||||
listen_port = 9000
|
||||
if "net" in config:
|
||||
print("Checking network settings")
|
||||
if "listen_port" in config["net"]:
|
||||
listen_port = config["net"]["listen_port"]
|
||||
print("Set listen port to ", listen_port)
|
||||
if "listen_to_network" in config["net"] and config["net"]["listen_to_network"] == True:
|
||||
if "bind_ip" in config["net"]:
|
||||
bind_ip = config["net"]["bind_ip"]
|
||||
else:
|
||||
bind_ip = "0.0.0.0"
|
||||
print("Set bind_ip to ", bind_ip)
|
||||
|
||||
os.chdir("stable-diffusion")
|
||||
|
||||
if is_amd_on_linux():
|
||||
setup_amd_environment()
|
||||
|
||||
print("\nLaunching uvicorn\n")
|
||||
os.system(f'python -m uvicorn main:server_api --app-dir "{os.environ["SD_UI_PATH"]}" --port {listen_port} --host {bind_ip} --log-level error')
|
||||
|
||||
### Start
|
||||
|
||||
# This list would probably be a good candidate for an import, but since PYTHONPATH and other settings
|
||||
# have not been initialized yet, I keep the list here for the moment -- JeLuF
|
||||
AMD_PCI_IDs = {
|
||||
"1002AC0C": "Theater 506A USB",
|
||||
"1002AC0D": "Theater 506A USB",
|
||||
"1002AC0E": "Theater 506A External USB",
|
||||
"1002AC0F": "Theater 506A External USB",
|
||||
"1002AC12": "Theater HD T507 (DVB-T) TV tuner/capture device",
|
||||
"1002AC02": "TV Wonder HD 600 PCIe",
|
||||
"1002AC03": "Theater 506 PCIe",
|
||||
"1002AC04": "Theater 506 USB",
|
||||
"1002AC05": "Theater 506 USB",
|
||||
"1002AC06": "Theater 506 External USB",
|
||||
"1002AC07": "Theater 506 External USB",
|
||||
"1002AC08": "Theater 506A World-Wide Analog Decoder + Demodulator",
|
||||
"1002AC09": "Theater 506A World-Wide Analog Decoder + Demodulator",
|
||||
"1002AC0A": "Theater 506A PCIe",
|
||||
"1002AC0B": "Theater 506A PCIe",
|
||||
"1002AC00": "Theater 506 World-Wide Analog Decoder",
|
||||
"1002AC01": "Theater 506 World-Wide Analog Decoder",
|
||||
"1002999D": "Richland [Radeon HD 8550D]",
|
||||
"100299A0": "Trinity 2 [Radeon HD 7520G]",
|
||||
"100299A2": "Trinity 2 [Radeon HD 7420G]",
|
||||
"100299A4": "Trinity 2 [Radeon HD 7400G]",
|
||||
"10029996": "Richland [Radeon HD 8470D]",
|
||||
"10029997": "Richland [Radeon HD 8350G]",
|
||||
"10029998": "Richland [Radeon HD 8370D]",
|
||||
"10029999": "Richland [Radeon HD 8510G]",
|
||||
"1002999A": "Richland [Radeon HD 8410G]",
|
||||
"1002999B": "Richland [Radeon HD 8310G]",
|
||||
"1002999C": "Richland [Radeon HD 8650D]",
|
||||
"10029925": "Kingston/Clayton/Jupiter/Gladius/Montego HDMI Controller",
|
||||
"10029926": "Jupiter",
|
||||
"10029990": "Trinity 2 [Radeon HD 7520G]",
|
||||
"10029991": "Trinity 2 [Radeon HD 7540D]",
|
||||
"10029992": "Trinity 2 [Radeon HD 7420G]",
|
||||
"10029993": "Trinity 2 [Radeon HD 7480D]",
|
||||
"10029994": "Trinity 2 [Radeon HD 7400G]",
|
||||
"10029995": "Richland [Radeon HD 8450G]",
|
||||
"10029917": "Trinity [Radeon HD 7620G]",
|
||||
"10029918": "Trinity [Radeon HD 7600G]",
|
||||
"10029919": "Trinity [Radeon HD 7500G]",
|
||||
"1002991E": "Bishop [Xbox One S APU]",
|
||||
"10029920": "Liverpool [Playstation 4 APU]",
|
||||
"10029922": "Starshp",
|
||||
"10029923": "Starsha2 [Kingston/Clayton]",
|
||||
"10029924": "Gladius",
|
||||
"10029909": "Trinity [Radeon HD 7500G]",
|
||||
"1002990A": "Trinity [Radeon HD 7500G]",
|
||||
"1002990B": "Richland [Radeon HD 8650G]",
|
||||
"1002990C": "Richland [Radeon HD 8670D]",
|
||||
"1002990D": "Richland [Radeon HD 8550G]",
|
||||
"1002990E": "Richland [Radeon HD 8570D]",
|
||||
"1002990F": "Richland [Radeon HD 8610G]",
|
||||
"10029910": "Trinity [Radeon HD 7660G]",
|
||||
"10029913": "Trinity [Radeon HD 7640G]",
|
||||
"10029901": "Trinity [Radeon HD 7660D]",
|
||||
"10029903": "Trinity [Radeon HD 7640G]",
|
||||
"10029904": "Trinity [Radeon HD 7560D]",
|
||||
"10029905": "Trinity GL [FirePro A300]",
|
||||
"10029906": "Trinity GL [FirePro A320]",
|
||||
"10029907": "Trinity [Radeon HD 7620G]",
|
||||
"10029908": "Trinity [Radeon HD 7600G]",
|
||||
"1002985F": "Mullins",
|
||||
"10029874": "Wani [Radeon R5/R6/R7 Graphics]",
|
||||
"10029890": "Amur",
|
||||
"100298C0": "Nolan",
|
||||
"100298E4": "Stoney [Radeon R2/R3/R4/R5 Graphics]",
|
||||
"10029900": "Trinity [Radeon HD 7660G]",
|
||||
"10029858": "Mullins",
|
||||
"10029859": "Mullins",
|
||||
"1002985A": "Mullins",
|
||||
"1002985B": "Mullins",
|
||||
"1002985C": "Mullins",
|
||||
"1002985D": "Mullins",
|
||||
"1002985E": "Mullins",
|
||||
"10029852": "Mullins [Radeon R2 Graphics]",
|
||||
"10029853": "Mullins [Radeon R2 Graphics]",
|
||||
"10029854": "Mullins [Radeon R3E Graphics]",
|
||||
"10029855": "Mullins [Radeon R6 Graphics]",
|
||||
"10029856": "Mullins [Radeon R1E/R2E Graphics]",
|
||||
"10029857": "Mullins [Radeon APU XX-2200M with R2 Graphics]",
|
||||
"10029836": "Kabini [Radeon HD 8280 / R3 Series]",
|
||||
"10029837": "Kabini [Radeon HD 8280E]",
|
||||
"10029838": "Kabini [Radeon HD 8240 / R3 Series]",
|
||||
"10029839": "Kabini [Radeon HD 8180]",
|
||||
"1002983D": "Temash [Radeon HD 8250/8280G]",
|
||||
"10029850": "Mullins [Radeon R3 Graphics]",
|
||||
"10029851": "Mullins [Radeon R4/R5 Graphics]",
|
||||
"10029808": "Wrestler [Radeon HD 7340]",
|
||||
"10029809": "Wrestler [Radeon HD 7310]",
|
||||
"1002980A": "Wrestler [Radeon HD 7290]",
|
||||
"10029830": "Kabini [Radeon HD 8400 / R3 Series]",
|
||||
"10029831": "Kabini [Radeon HD 8400E]",
|
||||
"10029832": "Kabini [Radeon HD 8330]",
|
||||
"10029833": "Kabini [Radeon HD 8330E]",
|
||||
"10029834": "Kabini [Radeon HD 8210]",
|
||||
"10029835": "Kabini [Radeon HD 8310E]",
|
||||
"10029714": "RS880 [Radeon HD 4290]",
|
||||
"10029715": "RS880 [Radeon HD 4250]",
|
||||
"10029802": "Wrestler [Radeon HD 6310]",
|
||||
"10029803": "Wrestler [Radeon HD 6310]",
|
||||
"10029804": "Wrestler [Radeon HD 6250]",
|
||||
"10029805": "Wrestler [Radeon HD 6250]",
|
||||
"10029806": "Wrestler [Radeon HD 6320]",
|
||||
"10029807": "Wrestler [Radeon HD 6290]",
|
||||
"1002964B": "Sumo",
|
||||
"1002964C": "Sumo",
|
||||
"1002964E": "Sumo",
|
||||
"1002964F": "Sumo",
|
||||
"10029710": "RS880 [Radeon HD 4200]",
|
||||
"10029712": "RS880M [Mobility Radeon HD 4225/4250]",
|
||||
"10029713": "RS880M [Mobility Radeon HD 4100]",
|
||||
"10029643": "SuperSumo [Radeon HD 6380G]",
|
||||
"10029644": "SuperSumo [Radeon HD 6410D]",
|
||||
"10029645": "SuperSumo [Radeon HD 6410D]",
|
||||
"10029647": "Sumo [Radeon HD 6520G]",
|
||||
"10029648": "Sumo [Radeon HD 6480G]",
|
||||
"10029649": "SuperSumo [Radeon HD 6480G]",
|
||||
"1002964A": "Sumo [Radeon HD 6530D]",
|
||||
"10029642": "SuperSumo [Radeon HD 6370D]",
|
||||
"10029615": "RS780E [Radeon HD 3200]",
|
||||
"10029610": "RS780 [Radeon HD 3200]",
|
||||
"10029611": "RS780C [Radeon 3100]",
|
||||
"10029612": "RS780M [Mobility Radeon HD 3200]",
|
||||
"10029613": "RS780MC [Mobility Radeon HD 3100]",
|
||||
"10029614": "RS780D [Radeon HD 3300]",
|
||||
"10029616": "RS780L [Radeon 3000]",
|
||||
"10029640": "Sumo [Radeon HD 6550D]",
|
||||
"10029641": "Sumo [Radeon HD 6620G]",
|
||||
"100295C4": "RV620/M82 [Mobility Radeon HD 3450/3470]",
|
||||
"100295C5": "RV620 LE [Radeon HD 3450]",
|
||||
"100295C6": "RV620 LE [Radeon HD 3450 AGP]",
|
||||
"100295C9": "RV620 LE [Radeon HD 3450 PCI]",
|
||||
"100295CC": "RV620 GL [FirePro V3700]",
|
||||
"100295CD": "RV620 GL [FirePro 2450]",
|
||||
"100295CF": "RV620 GL [FirePro 2260]",
|
||||
"10029591": "RV635/M86 [Mobility Radeon HD 3650]",
|
||||
"10029593": "RV635/M86 [Mobility Radeon HD 3670]",
|
||||
"10029595": "RV635/M86 GL [Mobility FireGL V5700]",
|
||||
"10029596": "RV635 PRO [Radeon HD 3650 AGP]",
|
||||
"10029597": "RV635 PRO [Radeon HD 3650 AGP]",
|
||||
"10029598": "RV635 [Radeon HD 3650/3750/4570/4580]",
|
||||
"10029599": "RV635 PRO [Radeon HD 3650 AGP]",
|
||||
"100295C0": "RV620 PRO [Radeon HD 3470]",
|
||||
"100295C2": "RV620/M82 [Mobility Radeon HD 3410/3430]",
|
||||
"10029586": "RV630 XT [Radeon HD 2600 XT AGP]",
|
||||
"10029587": "RV630 PRO [Radeon HD 2600 PRO AGP]",
|
||||
"10029588": "RV630 XT [Radeon HD 2600 XT]",
|
||||
"10029589": "RV630 PRO [Radeon HD 2600 PRO]",
|
||||
"1002958A": "RV630 [Radeon HD 2600 X2]",
|
||||
"1002958B": "RV630/M76 [Mobility Radeon HD 2600 XT]",
|
||||
"1002958C": "RV630 GL [FireGL V5600]",
|
||||
"1002958D": "RV630 GL [FireGL V3600]",
|
||||
"1002954F": "RV710 [Radeon HD 4350/4550]",
|
||||
"10029552": "RV710/M92 [Mobility Radeon HD 4330/4350/4550]",
|
||||
"10029553": "RV710/M92 [Mobility Radeon HD 4530/4570/5145/530v/540v/545v]",
|
||||
"10029555": "RV711/M93 [Mobility Radeon HD 4350/4550/530v/540v/545v / FirePro RG220]",
|
||||
"10029557": "RV711/M93 GL [FirePro RG220]",
|
||||
"1002955F": "RV710/M92 [Mobility Radeon HD 4330]",
|
||||
"10029580": "RV630 [Radeon HD 2600 PRO]",
|
||||
"10029581": "RV630/M76 [Mobility Radeon HD 2600]",
|
||||
"10029583": "RV630/M76 [Mobility Radeon HD 2600 XT/2700]",
|
||||
"1002950F": "R680 [Radeon HD 3870 X2]",
|
||||
"10029511": "RV670 GL [FireGL V7700]",
|
||||
"10029513": "RV670 [Radeon HD 3850 X2]",
|
||||
"10029515": "RV670 PRO [Radeon HD 3850 AGP]",
|
||||
"10029519": "RV670 GL [FireStream 9170]",
|
||||
"10029540": "RV710 [Radeon HD 4550]",
|
||||
"10029500": "RV670 [Radeon HD 3850 X2]",
|
||||
"10029501": "RV670 [Radeon HD 3870]",
|
||||
"10029504": "RV670/M88 [Mobility Radeon HD 3850]",
|
||||
"10029505": "RV670 [Radeon HD 3690/3850]",
|
||||
"10029506": "RV670/M88 [Mobility Radeon HD 3850 X2]",
|
||||
"10029507": "RV670 [Radeon HD 3830]",
|
||||
"10029508": "RV670/M88-XT [Mobility Radeon HD 3870]",
|
||||
"10029509": "RV670/M88 [Mobility Radeon HD 3870 X2]",
|
||||
"100294C1": "RV610 [Radeon HD 2400 PRO/XT]",
|
||||
"100294C3": "RV610 [Radeon HD 2400 PRO]",
|
||||
"100294C4": "RV610 LE [Radeon HD 2400 PRO AGP]",
|
||||
"100294C5": "RV610 [Radeon HD 2400 LE]",
|
||||
"100294C7": "RV610 [Radeon HD 2350]",
|
||||
"100294C8": "RV610/M74 [Mobility Radeon HD 2400 XT]",
|
||||
"100294C9": "RV610/M72-S [Mobility Radeon HD 2400]",
|
||||
"100294CB": "RV610 [Radeon E2400]",
|
||||
"100294CC": "RV610 LE [Radeon HD 2400 PRO PCI]",
|
||||
"10029498": "RV730 PRO [Radeon HD 4650]",
|
||||
"1002949C": "RV730 GL [FirePro V7750]",
|
||||
"1002949E": "RV730 GL [FirePro V5700]",
|
||||
"1002949F": "RV730 GL [FirePro V3750]",
|
||||
"100294A0": "RV740/M97 [Mobility Radeon HD 4830]",
|
||||
"100294A1": "RV740/M97-XT [Mobility Radeon HD 4860]",
|
||||
"100294A3": "RV740/M97 GL [FirePro M7740]",
|
||||
"100294B3": "RV740 PRO [Radeon HD 4770]",
|
||||
"100294B4": "RV740 PRO [Radeon HD 4750]",
|
||||
"10029462": "RV790 [Radeon HD 4860]",
|
||||
"1002946A": "RV770 GL [FirePro M7750]",
|
||||
"10029480": "RV730/M96 [Mobility Radeon HD 4650/5165]",
|
||||
"10029488": "RV730/M96-XT [Mobility Radeon HD 4670]",
|
||||
"10029489": "RV730/M96 GL [Mobility FireGL V5725]",
|
||||
"10029490": "RV730 XT [Radeon HD 4670]",
|
||||
"10029491": "RV730/M96-CSP [Radeon E4690]",
|
||||
"10029495": "RV730 [Radeon HD 4600 AGP Series]",
|
||||
"1002944A": "RV770/M98L [Mobility Radeon HD 4850]",
|
||||
"1002944B": "RV770/M98 [Mobility Radeon HD 4850 X2]",
|
||||
"1002944C": "RV770 LE [Radeon HD 4830]",
|
||||
"1002944E": "RV770 CE [Radeon HD 4710]",
|
||||
"10029450": "RV770 GL [FireStream 9270]",
|
||||
"10029452": "RV770 GL [FireStream 9250]",
|
||||
"10029456": "RV770 GL [FirePro V8700]",
|
||||
"1002945A": "RV770/M98-XT [Mobility Radeon HD 4870]",
|
||||
"10029460": "RV790 [Radeon HD 4890]",
|
||||
"1002940A": "R600 GL [FireGL V8650]",
|
||||
"1002940B": "R600 GL [FireGL V8600]",
|
||||
"1002940F": "R600 GL [FireGL V7600]",
|
||||
"10029440": "RV770 [Radeon HD 4870]",
|
||||
"10029441": "R700 [Radeon HD 4870 X2]",
|
||||
"10029442": "RV770 [Radeon HD 4850]",
|
||||
"10029443": "R700 [Radeon HD 4850 X2]",
|
||||
"10029444": "RV770 GL [FirePro V8750]",
|
||||
"10029446": "RV770 GL [FirePro V7760]",
|
||||
"1002793F": "RS690M [Radeon Xpress 1200/1250/1270] (Secondary)",
|
||||
"10027941": "RS600 [Radeon Xpress 1250]",
|
||||
"10027942": "RS600M [Radeon Xpress 1250]",
|
||||
"1002796E": "RS740 [Radeon 2100]",
|
||||
"10029400": "R600 [Radeon HD 2900 PRO/XT]",
|
||||
"10029401": "R600 [Radeon HD 2900 XT]",
|
||||
"10029403": "R600 [Radeon HD 2900 PRO]",
|
||||
"10029405": "R600 [Radeon HD 2900 GT]",
|
||||
"1002791E": "RS690 [Radeon X1200]",
|
||||
"1002791F": "RS690M [Radeon Xpress 1200/1250/1270]",
|
||||
"10027835": "RS350M [Mobility Radeon 9000 IGP]",
|
||||
"10027448": "Navi 31 [Radeon Pro W7900]",
|
||||
"1002744C": "Navi 31 [Radeon RX 7900 XT/7900 XTX]",
|
||||
"1002745E": "Navi 31 [Radeon Pro W7800]",
|
||||
"10027480": "Navi 33 [Radeon RX 7700S/7600S/7600M XT]",
|
||||
"10027483": "Navi 33 [Radeon RX 7600M/7600M XT]",
|
||||
"10027489": "Navi 33",
|
||||
"10027834": "RS350 [Radeon 9100 PRO/XT IGP]",
|
||||
"10027446": "Navi 31 USB",
|
||||
"1002743F": "Navi 24 [Radeon RX 6400/6500 XT/6500M]",
|
||||
"10027421": "Navi 24 [Radeon PRO W6500M]",
|
||||
"10027422": "Navi 24 [Radeon PRO W6400]",
|
||||
"10027423": "Navi 24 [Radeon PRO W6300/W6300M]",
|
||||
"10027424": "Navi 24 [Radeon RX 6300]",
|
||||
"100273F0": "Navi 33 [Radeon RX 7600M XT]",
|
||||
"100273EF": "Navi 23 [Radeon RX 6650 XT / 6700S / 6800S]",
|
||||
"100273E1": "Navi 23 WKS-XM [Radeon PRO W6600M]",
|
||||
"100273FF": "Navi 23 [Radeon RX 6600/6600 XT/6600M]",
|
||||
"100273E3": "Navi 23 WKS-XL [Radeon PRO W6600]",
|
||||
"100273E4": "Navi 23 USB",
|
||||
"10027408": "Aldebaran/MI200 [Instinct MI250X]",
|
||||
"1002740C": "Aldebaran/MI200 [Instinct MI250X/MI250]",
|
||||
"1002740F": "Aldebaran/MI200 [Instinct MI210]",
|
||||
"100273CE": "Navi 22-XL SRIOV MxGPU",
|
||||
"100273AF": "Navi 21 [Radeon RX 6900 XT]",
|
||||
"100273BF": "Navi 21 [Radeon RX 6800/6800 XT / 6900 XT]",
|
||||
"100273C4": "Navi 22 USB",
|
||||
"100273C3": "Navi 22",
|
||||
"100273E0": "Navi 23",
|
||||
"100273DF": "Navi 22 [Radeon RX 6700/6700 XT/6750 XT / 6800M/6850M XT]",
|
||||
"100273A5": "Navi 21 [Radeon RX 6950 XT]",
|
||||
"100273AE": "Navi 21 [Radeon Pro V620 MxGPU]",
|
||||
"100273A2": "Navi 21 Pro-XTA [Radeon Pro W6900X]",
|
||||
"100273A3": "Navi 21 GL-XL [Radeon PRO W6800]",
|
||||
"100273A4": "Navi 21 USB",
|
||||
"100273AB": "Navi 21 Pro-XLA [Radeon Pro W6800X/Radeon Pro W6800X Duo]",
|
||||
"1002734F": "Navi 14 [Radeon Pro W5300M]",
|
||||
"10027360": "Navi 12 [Radeon Pro 5600M/V520/BC-160]",
|
||||
"100273A1": "Navi 21 [Radeon Pro V620]",
|
||||
"10027362": "Navi 12 [Radeon Pro V520/V540]",
|
||||
"10027388": "Arcturus GL-XL",
|
||||
"1002738C": "Arcturus GL-XL [Instinct MI100]",
|
||||
"1002738E": "Arcturus GL-XL [Instinct MI100]",
|
||||
"10027319": "Navi 10 [Radeon Pro 5700 XT]",
|
||||
"1002731B": "Navi 10 [Radeon Pro 5700]",
|
||||
"1002731F": "Navi 10 [Radeon RX 5600 OEM/5600 XT / 5700/5700 XT]",
|
||||
"10027340": "Navi 14 [Radeon RX 5500/5500M / Pro 5500M]",
|
||||
"10027341": "Navi 14 [Radeon Pro W5500]",
|
||||
"10027347": "Navi 14 [Radeon Pro W5500M]",
|
||||
"1002731E": "TDC-150",
|
||||
"100272A0": "RV570 [Radeon X1950 PRO] (Secondary)",
|
||||
"100272A8": "RV570 [Radeon X1950 GT] (Secondary)",
|
||||
"100272B1": "RV560 [Radeon X1650 XT] (Secondary)",
|
||||
"100272B3": "RV560 [Radeon X1650 GT] (Secondary)",
|
||||
"10027300": "Fiji [Radeon R9 FURY / NANO Series]",
|
||||
"10027310": "Navi 10 [Radeon Pro W5700X]",
|
||||
"10027312": "Navi 10 [Radeon Pro W5700]",
|
||||
"10027314": "Navi 10 USB",
|
||||
"1002724E": "R580 GL [FireGL V7350]",
|
||||
"10027269": "R580 [Radeon X1900 XT] (Secondary)",
|
||||
"1002726B": "R580 [Radeon X1900 GT] (Secondary)",
|
||||
"1002726E": "R580 [AMD Stream Processor] (Secondary)",
|
||||
"10027280": "RV570 [Radeon X1950 PRO]",
|
||||
"10027288": "RV570 [Radeon X1950 GT]",
|
||||
"10027291": "RV560 [Radeon X1650 XT]",
|
||||
"10027293": "RV560 [Radeon X1650 GT]",
|
||||
"100271F2": "RV530 GL [FireGL V3400] (Secondary)",
|
||||
"10027210": "RV550/M71 [Mobility Radeon HD 2300]",
|
||||
"10027211": "RV550/M71 [Mobility Radeon X2300 HD]",
|
||||
"10027240": "R580+ [Radeon X1950 XTX]",
|
||||
"10027244": "R580+ [Radeon X1950 XT]",
|
||||
"10027248": "R580 [Radeon X1950]",
|
||||
"10027249": "R580 [Radeon X1900 XT]",
|
||||
"1002724B": "R580 [Radeon X1900 GT]",
|
||||
"100271D6": "RV530/M66-XT [Mobility Radeon X1700]",
|
||||
"100271DE": "RV530/M66 [Mobility Radeon X1700/X2500]",
|
||||
"100271E0": "RV530 [Radeon X1600] (Secondary)",
|
||||
"100271E1": "RV535 [Radeon X1650 PRO] (Secondary)",
|
||||
"100271E2": "RV530 [Radeon X1600] (Secondary)",
|
||||
"100271E6": "RV530 [Radeon X1650] (Secondary)",
|
||||
"100271E7": "RV535 [Radeon X1650 PRO] (Secondary)",
|
||||
"100271C4": "RV530/M56 GL [Mobility FireGL V5200]",
|
||||
"100271C5": "RV530/M56-P [Mobility Radeon X1600]",
|
||||
"100271C6": "RV530LE [Radeon X1600/X1650 PRO]",
|
||||
"100271C7": "RV535 [Radeon X1650 PRO]",
|
||||
"100271CE": "RV530 [Radeon X1300 XT/X1600 PRO]",
|
||||
"100271D2": "RV530 GL [FireGL V3400]",
|
||||
"100271D4": "RV530/M66 GL [Mobility FireGL V5250]",
|
||||
"100271D5": "RV530/M66-P [Mobility Radeon X1700]",
|
||||
"100271A7": "RV516 [Radeon X1300/X1550 Series] (Secondary)",
|
||||
"100271BB": "RV516 GL [FireMV 2250] (Secondary)",
|
||||
"100271C0": "RV530 [Radeon X1600 XT/X1650 GTO]",
|
||||
"100271C1": "RV535 [Radeon X1650 PRO]",
|
||||
"100271C2": "RV530 [Radeon X1600 PRO]",
|
||||
"100271C3": "RV530 [Radeon X1600 PRO]",
|
||||
"1002718D": "RV516/M64-CSP128 [Mobility Radeon X1450]",
|
||||
"10027193": "RV516 [Radeon X1550 Series]",
|
||||
"10027196": "RV516/M62-S [Mobility Radeon X1350]",
|
||||
"1002719B": "RV516 GL [FireMV 2250]",
|
||||
"1002719F": "RV516 [Radeon X1550 Series]",
|
||||
"100271A0": "RV516 [Radeon X1300/X1550 Series] (Secondary)",
|
||||
"100271A1": "RV516 [Radeon X1600/X1650 Series] (Secondary)",
|
||||
"100271A3": "RV516 [Radeon X1300/X1550 Series] (Secondary)",
|
||||
"10027186": "RV516/M64 [Mobility Radeon X1450]",
|
||||
"10027187": "RV516 [Radeon X1300/X1550 Series]",
|
||||
"10027188": "RV516/M64-S [Mobility Radeon X2300]",
|
||||
"1002718A": "RV516/M64 [Mobility Radeon X2300]",
|
||||
"1002718B": "RV516/M62 [Mobility Radeon X1350]",
|
||||
"1002718C": "RV516/M62-CSP64 [Mobility Radeon X1350]",
|
||||
"10027162": "RV515 PRO [Radeon X1300/X1550 Series] (Secondary)",
|
||||
"10027163": "RV505 [Radeon X1550 Series] (Secondary)",
|
||||
"10027166": "RV515 [Radeon X1300/X1550 Series] (Secondary)",
|
||||
"10027167": "RV515 [Radeon X1550 64-bit] (Secondary)",
|
||||
"10027172": "RV515 GL [FireGL V3300] (Secondary)",
|
||||
"10027173": "RV515 GL [FireGL V3350] (Secondary)",
|
||||
"10027181": "RV516 [Radeon X1600/X1650 Series]",
|
||||
"10027183": "RV516 [Radeon X1300/X1550 Series]",
|
||||
"10027145": "RV515/M54 [Mobility Radeon X1400]",
|
||||
"10027146": "RV515 [Radeon X1300/X1550]",
|
||||
"10027147": "RV505 [Radeon X1550 64-bit]",
|
||||
"10027149": "RV515/M52 [Mobility Radeon X1300]",
|
||||
"1002714A": "RV515/M52 [Mobility Radeon X1300]",
|
||||
"10027152": "RV515 GL [FireGL V3300]",
|
||||
"10027153": "RV515 GL [FireGL V3350]",
|
||||
"1002715F": "RV505 CE [Radeon X1550 64-bit]",
|
||||
"10027120": "R520 [Radeon X1800] (Secondary)",
|
||||
"10027124": "R520 GL [FireGL V7200] (Secondary)",
|
||||
"10027129": "R520 [Radeon X1800] (Secondary)",
|
||||
"1002712E": "R520 GL [FireGL V7300] (Secondary)",
|
||||
"1002712F": "R520 GL [FireGL V7350] (Secondary)",
|
||||
"10027140": "RV515 [Radeon X1300/X1550/X1600 Series]",
|
||||
"10027142": "RV515 PRO [Radeon X1300/X1550 Series]",
|
||||
"10027143": "RV505 [Radeon X1300/X1550 Series]",
|
||||
"10027102": "R520/M58 [Mobility Radeon X1800]",
|
||||
"10027104": "R520 GL [FireGL V7200 / Barco MXTR-5100]",
|
||||
"10027109": "R520 [Radeon X1800 XL]",
|
||||
"1002710A": "R520 [Radeon X1800 GTO]",
|
||||
"1002710B": "R520 [Radeon X1800 GTO]",
|
||||
"1002710E": "R520 GL [FireGL V7300]",
|
||||
"1002710F": "R520 GL [FireGL V7350]",
|
||||
"100269A1": "Vega 12",
|
||||
"100269A2": "Vega 12",
|
||||
"100269A3": "Vega 12",
|
||||
"100269AF": "Vega 12 [Radeon Pro Vega 20]",
|
||||
"10026FDF": "Polaris 20 XL [Radeon RX 580 2048SP]",
|
||||
"10027100": "R520 [Radeon X1800 XT]",
|
||||
"10027101": "R520/M58 [Mobility Radeon X1800 XT]",
|
||||
"10026980": "Polaris12",
|
||||
"10026981": "Lexa XT [Radeon PRO WX 3200]",
|
||||
"10026985": "Lexa XT [Radeon PRO WX 3100]",
|
||||
"10026986": "Polaris12",
|
||||
"10026987": "Lexa [Radeon 540X/550X/630 / RX 640 / E9171 MCM]",
|
||||
"10026995": "Lexa XT [Radeon PRO WX 2100]",
|
||||
"1002699F": "Lexa PRO [Radeon 540/540X/550/550X / RX 540X/550/550X]",
|
||||
"100269A0": "Vega 12",
|
||||
"1002698F": "Lexa XT [Radeon PRO WX 3100 / Barco MXRT 4700]",
|
||||
"1002692F": "Tonga XTV GL [FirePro S7150V]",
|
||||
"10026938": "Tonga XT / Amethyst XT [Radeon R9 380X / R9 M295X]",
|
||||
"10026939": "Tonga PRO [Radeon R9 285/380]",
|
||||
"1002694C": "Polaris 22 XT [Radeon RX Vega M GH]",
|
||||
"1002694E": "Polaris 22 XL [Radeon RX Vega M GL]",
|
||||
"1002694F": "Polaris 22 MGL XL [Radeon Pro WX Vega M GL]",
|
||||
"10026930": "Tonga PRO [Radeon R9 380 4GB]",
|
||||
"1002693B": "Tonga PRO GL [FirePro W7100 / Barco MXRT-7600]",
|
||||
"100268FE": "Cedar LE",
|
||||
"10026900": "Topaz XT [Radeon R7 M260/M265 / M340/M360 / M440/M445 / 530/535 / 620/625 Mobile]",
|
||||
"10026901": "Topaz PRO [Radeon R5 M255]",
|
||||
"10026907": "Meso XT [Radeon R5 M315]",
|
||||
"10026920": "Amethyst [Radeon R9 M395/ M395X Mac Edition]",
|
||||
"10026921": "Amethyst XT [Radeon R9 M295X / M390X]",
|
||||
"10026929": "Tonga XT GL [FirePro S7150]",
|
||||
"1002692B": "Tonga PRO GL [FirePro W7100]",
|
||||
"100268FA": "Cedar [Radeon HD 7350/8350 / R5 220]",
|
||||
"100268E4": "Robson CE [Radeon HD 6370M/7370M]",
|
||||
"100268E5": "Robson LE [Radeon HD 6330M]",
|
||||
"100268E8": "Cedar",
|
||||
"100268E9": "Cedar [ATI FirePro (FireGL) Graphics Adapter]",
|
||||
"100268F1": "Cedar GL [FirePro 2460]",
|
||||
"100268F2": "Cedar GL [FirePro 2270]",
|
||||
"100268F8": "Cedar [Radeon HD 7300 Series]",
|
||||
"100268F9": "Cedar [Radeon HD 5000/6000/7350/8350 Series]",
|
||||
"100268C8": "Redwood XT GL [FirePro V4800]",
|
||||
"100268C9": "Redwood PRO GL [FirePro V3800]",
|
||||
"100268D8": "Redwood XT [Radeon HD 5670/5690/5730]",
|
||||
"100268D9": "Redwood PRO [Radeon HD 5550/5570/5630/6510/6610/7570]",
|
||||
"100268DA": "Redwood LE [Radeon HD 5550/5570/5630/6390/6490/7570]",
|
||||
"100268DE": "Redwood",
|
||||
"100268E0": "Park [Mobility Radeon HD 5430/5450/5470]",
|
||||
"100268E1": "Park [Mobility Radeon HD 5430]",
|
||||
"100268A9": "Juniper XT [FirePro V5800]",
|
||||
"100268B8": "Juniper XT [Radeon HD 5770]",
|
||||
"100268B9": "Juniper LE [Radeon HD 5670 640SP Edition]",
|
||||
"100268BA": "Juniper XT [Radeon HD 6770]",
|
||||
"100268BE": "Juniper PRO [Radeon HD 5750]",
|
||||
"100268BF": "Juniper PRO [Radeon HD 6750]",
|
||||
"100268C0": "Madison [Mobility Radeon HD 5730 / 6570M]",
|
||||
"100268C1": "Madison [Mobility Radeon HD 5650/5750 / 6530M/6550M]",
|
||||
"100268C7": "Pinewood [Mobility Radeon HD 5570/6550A]",
|
||||
"10026898": "Cypress XT [Radeon HD 5870]",
|
||||
"10026899": "Cypress PRO [Radeon HD 5850]",
|
||||
"1002689B": "Cypress PRO [Radeon HD 6800 Series]",
|
||||
"1002689C": "Hemlock [Radeon HD 5970]",
|
||||
"1002689D": "Hemlock [Radeon HD 5970]",
|
||||
"1002689E": "Cypress LE [Radeon HD 5830]",
|
||||
"100268A0": "Broadway XT [Mobility Radeon HD 5870]",
|
||||
"100268A1": "Broadway PRO [Mobility Radeon HD 5850]",
|
||||
"100268A8": "Granville [Radeon HD 6850M/6870M]",
|
||||
"1002686D": "Vega 10 GLXTA",
|
||||
"1002686E": "Vega 10 GLXLA",
|
||||
"1002687F": "Vega 10 XL/XT [Radeon RX Vega 56/64]",
|
||||
"10026880": "Lexington [Radeon HD 6550M]",
|
||||
"10026888": "Cypress XT [FirePro V8800]",
|
||||
"10026889": "Cypress PRO [FirePro V7800]",
|
||||
"1002688A": "Cypress XT [FirePro V9800]",
|
||||
"1002688C": "Cypress XT GL [FireStream 9370]",
|
||||
"1002688D": "Cypress PRO GL [FireStream 9350]",
|
||||
"10026869": "Vega 10 XGA [Radeon Pro Vega 48]",
|
||||
"1002686A": "Vega 10 LEA",
|
||||
"1002686B": "Vega 10 XTXA [Radeon Pro Vega 64X]",
|
||||
"10026862": "Vega 10 XT [Radeon PRO SSG]",
|
||||
"10026863": "Vega 10 XTX [Radeon Vega Frontier Edition]",
|
||||
"10026864": "Vega 10 [Radeon Pro V340/Instinct MI25x2]",
|
||||
"10026867": "Vega 10 XL [Radeon Pro Vega 56]",
|
||||
"10026868": "Vega 10 [Radeon PRO WX 8100/8200]",
|
||||
"1002686C": "Vega 10 [Instinct MI25 MxGPU/MI25x2 MxGPU/V340 MxGPU/V340L MxGPU]",
|
||||
"1002683F": "Cape Verde PRO [Radeon HD 7750/8740 / R7 250E]",
|
||||
"10026840": "Thames [Radeon HD 7500M/7600M Series]",
|
||||
"10026841": "Thames [Radeon HD 7550M/7570M/7650M]",
|
||||
"10026842": "Thames LE [Radeon HD 7000M Series]",
|
||||
"10026843": "Thames [Radeon HD 7670M]",
|
||||
"10026860": "Vega 10 [Instinct MI25/MI25x2/V340/V320]",
|
||||
"10026861": "Vega 10 XT [Radeon PRO WX 9100]",
|
||||
"10026828": "Cape Verde PRO [FirePro W600]",
|
||||
"10026829": "Cape Verde",
|
||||
"1002682A": "Venus PRO",
|
||||
"1002682B": "Cape Verde PRO / Venus LE / Tropo PRO-L [Radeon HD 8830M / R7 250 / R7 M465X]",
|
||||
"1002682C": "Cape Verde GL [FirePro W4100]",
|
||||
"1002682D": "Chelsea XT GL [FirePro M4000]",
|
||||
"1002682F": "Chelsea LP [Radeon HD 7730M]",
|
||||
"10026835": "Cape Verde PRX [Radeon R9 255 OEM]",
|
||||
"10026837": "Cape Verde LE [Radeon HD 7730/8730]",
|
||||
"1002683D": "Cape Verde XT [Radeon HD 7770/8760 / R7 250X]",
|
||||
"10026820": "Venus XTX [Radeon HD 8890M / R9 M275X/M375X]",
|
||||
"10026821": "Venus XT [Radeon HD 8870M / R9 M270X/M370X]",
|
||||
"10026822": "Venus PRO [Radeon E8860]",
|
||||
"10026823": "Venus PRO [Radeon HD 8850M / R9 M265X]",
|
||||
"10026825": "Heathrow XT [Radeon HD 7870M]",
|
||||
"10026826": "Chelsea LP [Radeon HD 7700M Series]",
|
||||
"10026827": "Heathrow PRO [Radeon HD 7850M/8850M]",
|
||||
"10026808": "Pitcairn XT GL [FirePro W7000]",
|
||||
"10026809": "Pitcairn LE GL [FirePro W5000]",
|
||||
"10026810": "Curacao XT / Trinidad XT [Radeon R7 370 / R9 270X/370X]",
|
||||
"10026811": "Curacao PRO [Radeon R7 370 / R9 270/370 OEM]",
|
||||
"10026816": "Pitcairn",
|
||||
"10026817": "Pitcairn",
|
||||
"10026818": "Pitcairn XT [Radeon HD 7870 GHz Edition]",
|
||||
"10026819": "Pitcairn PRO [Radeon HD 7850 / R7 265 / R9 270 1024SP]",
|
||||
"100267EB": "Baffin [Radeon Pro V5300X]",
|
||||
"100267EF": "Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X]",
|
||||
"100267FF": "Baffin [Radeon RX 550 640SP / RX 560/560X]",
|
||||
"10026800": "Wimbledon XT [Radeon HD 7970M]",
|
||||
"10026801": "Neptune XT [Radeon HD 8970M]",
|
||||
"10026802": "Wimbledon",
|
||||
"10026806": "Neptune",
|
||||
"100267DF": "Ellesmere [Radeon RX 470/480/570/570X/580/580X/590]",
|
||||
"100267E0": "Baffin [Radeon Pro WX 4170]",
|
||||
"100267E1": "Baffin [Polaris11]",
|
||||
"100267E3": "Baffin [Radeon Pro WX 4100]",
|
||||
"100267E8": "Baffin [Radeon Pro WX 4130/4150]",
|
||||
"100267E9": "Baffin [Polaris11]",
|
||||
"100267D7": "Ellesmere [Radeon Pro WX 5100 / Barco MXRT-6700]",
|
||||
"100267C7": "Ellesmere [Radeon Pro WX 5100]",
|
||||
"100267CA": "Ellesmere [Polaris10]",
|
||||
"100267CC": "Ellesmere [Polaris10]",
|
||||
"100267CF": "Ellesmere [Polaris10]",
|
||||
"100267D0": "Ellesmere [Radeon Pro V7300X / V7350x2]",
|
||||
"100267D4": "Ellesmere [Radeon Pro WX 7100 / Barco MXRT-8700]",
|
||||
"100267B9": "Vesuvius [Radeon R9 295X2]",
|
||||
"100267BE": "Hawaii LE",
|
||||
"100267C0": "Ellesmere [Radeon Pro WX 7100 Mobile]",
|
||||
"100267C2": "Ellesmere [Radeon Pro V7300X / V7350x2]",
|
||||
"100267C4": "Ellesmere [Radeon Pro WX 7100]",
|
||||
"100267B8": "Hawaii XT [Radeon R9 290X Engineering Sample]",
|
||||
"100267A2": "Hawaii GL",
|
||||
"100267A8": "Hawaii",
|
||||
"100267A9": "Hawaii",
|
||||
"100267AA": "Hawaii",
|
||||
"100267B0": "Hawaii XT / Grenada XT [Radeon R9 290X/390X]",
|
||||
"100267B1": "Hawaii PRO [Radeon R9 290/390]",
|
||||
"1002679A": "Tahiti PRO [Radeon HD 7950/8950 OEM / R9 280]",
|
||||
"1002679B": "Malta [Radeon HD 7990/8990 OEM]",
|
||||
"1002679E": "Tahiti LE [Radeon HD 7870 XT]",
|
||||
"1002679F": "Tahiti",
|
||||
"100267A0": "Hawaii XT GL [FirePro W9100]",
|
||||
"100267A1": "Hawaii PRO GL [FirePro W8100]",
|
||||
"10026780": "Tahiti XT GL [FirePro W9000]",
|
||||
"10026784": "Tahiti [FirePro Series Graphics Adapter]",
|
||||
"10026788": "Tahiti [FirePro Series Graphics Adapter]",
|
||||
"1002678A": "Tahiti PRO GL [FirePro Series]",
|
||||
"10026798": "Tahiti XT [Radeon HD 7970/8970 OEM / R9 280X]",
|
||||
"10026770": "Caicos [Radeon HD 6450A/7450A]",
|
||||
"10026771": "Caicos XTX [Radeon HD 8490 / R5 235X OEM]",
|
||||
"10026772": "Caicos [Radeon HD 7450A]",
|
||||
"10026778": "Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM]",
|
||||
"10026779": "Caicos [Radeon HD 6450/7450/8450 / R5 230 OEM]",
|
||||
"1002677B": "Caicos PRO [Radeon HD 7450]",
|
||||
"10026761": "Seymour LP [Radeon HD 6430M]",
|
||||
"10026763": "Seymour [Radeon E6460]",
|
||||
"10026764": "Seymour [Radeon HD 6400M Series]",
|
||||
"10026765": "Seymour [Radeon HD 6400M Series]",
|
||||
"10026766": "Caicos",
|
||||
"10026767": "Caicos",
|
||||
"10026768": "Caicos",
|
||||
"10026759": "Turks PRO [Radeon HD 6570/7570/8550 / R5 230]",
|
||||
"1002675B": "Turks [Radeon HD 7600 Series]",
|
||||
"1002675D": "Turks PRO [Radeon HD 7570]",
|
||||
"1002675F": "Turks LE [Radeon HD 5570/6510/7510/8510]",
|
||||
"10026760": "Seymour [Radeon HD 6400M/7400M Series]",
|
||||
"10026743": "Whistler [Radeon E6760]",
|
||||
"10026749": "Turks GL [FirePro V4900]",
|
||||
"1002674A": "Turks GL [FirePro V3900]",
|
||||
"10026750": "Onega [Radeon HD 6650A/7650A]",
|
||||
"10026751": "Turks [Radeon HD 7650A/7670A]",
|
||||
"10026758": "Turks XT [Radeon HD 6670/7670]",
|
||||
"1002671F": "Cayman CE [Radeon HD 6930]",
|
||||
"10026720": "Blackcomb [Radeon HD 6970M/6990M]",
|
||||
"10026738": "Barts XT [Radeon HD 6870]",
|
||||
"10026739": "Barts PRO [Radeon HD 6850]",
|
||||
"1002673E": "Barts LE [Radeon HD 6790]",
|
||||
"10026740": "Whistler [Radeon HD 6730M/6770M/7690M XT]",
|
||||
"10026741": "Whistler [Radeon HD 6630M/6650M/6750M/7670M/7690M]",
|
||||
"10026742": "Whistler LE [Radeon HD 6610M/7610M]",
|
||||
"10026707": "Cayman LE GL [FirePro V5900]",
|
||||
"10026718": "Cayman XT [Radeon HD 6970]",
|
||||
"10026719": "Cayman PRO [Radeon HD 6950]",
|
||||
"1002671C": "Antilles [Radeon HD 6990]",
|
||||
"1002671D": "Antilles [Radeon HD 6990]",
|
||||
"100266A2": "Vega 20",
|
||||
"100266A3": "Vega 20 [Radeon Pro Vega II/Radeon Pro Vega II Duo]",
|
||||
"100266A7": "Vega 20 [Radeon Pro Vega 20]",
|
||||
"100266AF": "Vega 20 [Radeon VII]",
|
||||
"10026704": "Cayman PRO GL [FirePro V7900]",
|
||||
"10026665": "Jet PRO [Radeon R5 M230 / R7 M260DX / Radeon 520/610 Mobile]",
|
||||
"10026667": "Jet ULT [Radeon R5 M230]",
|
||||
"1002666F": "Sun LE [Radeon HD 8550M / R5 M230]",
|
||||
"100266A0": "Vega 20 [Radeon Pro/Radeon Instinct]",
|
||||
"100266A1": "Vega 20 [Radeon Pro VII/Radeon Instinct MI50 32GB]",
|
||||
"10026658": "Bonaire XTX [Radeon R7 260X/360]",
|
||||
"1002665C": "Bonaire XT [Radeon HD 7790/8770 / R7 360 / R9 260/360 OEM]",
|
||||
"1002665D": "Bonaire [Radeon R7 200 Series]",
|
||||
"1002665F": "Tobago PRO [Radeon R7 360 / R9 360 OEM]",
|
||||
"10026660": "Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330 / M430 / Radeon 520 Mobile]",
|
||||
"10026663": "Sun PRO [Radeon HD 8570A/8570M]",
|
||||
"10026664": "Jet XT [Radeon R5 M240]",
|
||||
"10026631": "Oland",
|
||||
"10026640": "Saturn XT [FirePro M6100]",
|
||||
"10026641": "Saturn PRO [Radeon HD 8930M]",
|
||||
"10026646": "Bonaire XT [Radeon R9 M280X / FirePro W6150M]",
|
||||
"10026647": "Saturn PRO/XT [Radeon R9 M270X/M280X]",
|
||||
"10026649": "Bonaire [FirePro W5100]",
|
||||
"10026650": "Bonaire",
|
||||
"10026651": "Bonaire",
|
||||
"1002664D": "Bonaire [FirePro W5100 / Barco MXRT-5600]",
|
||||
"10026606": "Mars XTX [Radeon HD 8790M]",
|
||||
"10026607": "Mars LE [Radeon HD 8530M / R5 M240]",
|
||||
"10026608": "Oland GL [FirePro W2100]",
|
||||
"10026610": "Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM]",
|
||||
"10026611": "Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM]",
|
||||
"10026613": "Oland PRO [Radeon R7 240/340 / Radeon 520]",
|
||||
"10026617": "Oland LE [Radeon R7 240]",
|
||||
"10026609": "Oland GL [FirePro W2100 / Barco MXRT 2600]",
|
||||
"10025E4F": "RV410 [Radeon X700]",
|
||||
"10025E6B": "RV410 [Radeon X700 PRO] (Secondary)",
|
||||
"10025E6D": "RV410 [Radeon X700] (Secondary)",
|
||||
"10025F57": "R423 [Radeon X800 XT]",
|
||||
"10026600": "Mars [Radeon HD 8670A/8670M/8750M / R7 M370]",
|
||||
"10026601": "Mars [Radeon HD 8730M]",
|
||||
"10026604": "Opal XT [Radeon R7 M265/M365X/M465]",
|
||||
"10026605": "Opal PRO [Radeon R7 M260X]",
|
||||
"10025D72": "R480 [Radeon X850 XT] (Secondary)",
|
||||
"10025D77": "R423 [Radeon X800 XT] (Secondary)",
|
||||
"10025E48": "RV410 GL [FireGL V5000]",
|
||||
"10025E49": "RV410 [Radeon X700 Series]",
|
||||
"10025E4A": "RV410 [Radeon X700 XT]",
|
||||
"10025E4B": "RV410 [Radeon X700 PRO]",
|
||||
"10025E4C": "RV410 [Radeon X700 SE]",
|
||||
"10025E4D": "RV410 [Radeon X700]",
|
||||
"10025D4D": "R480 [Radeon X850 XT Platinum Edition]",
|
||||
"10025D4E": "R480 [Radeon X850 SE]",
|
||||
"10025D4F": "R480 [Radeon X800 GTO]",
|
||||
"10025D50": "R480 GL [FireGL V7200]",
|
||||
"10025D52": "R480 [Radeon X850 XT]",
|
||||
"10025D57": "R423 [Radeon X800 XT]",
|
||||
"10025D6D": "R480 [Radeon X850 XT Platinum Edition] (Secondary)",
|
||||
"10025D6F": "R480 [Radeon X800 GTO] (Secondary)",
|
||||
"10025B73": "RV370 [Radeon X300/X550/X1050 Series] (Secondary)",
|
||||
"10025B74": "RV370 GL [FireGL V3100] (Secondary)",
|
||||
"10025B75": "RV370 GL [FireMV 2200] (Secondary)",
|
||||
"10025C61": "RV280/M9+ [Mobility Radeon 9200 AGP]",
|
||||
"10025C63": "RV280/M9+ [Mobility Radeon 9200 AGP]",
|
||||
"10025D44": "RV280 [Radeon 9200 SE] (Secondary)",
|
||||
"10025D45": "RV280 GL [FireMV 2200 PCI] (Secondary)",
|
||||
"10025D48": "R423/M28 [Mobility Radeon X800 XT]",
|
||||
"10025D49": "R423/M28 GL [Mobility FireGL V5100]",
|
||||
"10025D4A": "R423/M28 [Mobility Radeon X800]",
|
||||
"10025A62": "RC410M [Mobility Radeon Xpress 200M]",
|
||||
"10025B60": "RV370 [Radeon X300]",
|
||||
"10025B62": "RV370 [Radeon X600/X600 SE]",
|
||||
"10025B63": "RV370 [Radeon X300/X550/X1050 Series]",
|
||||
"10025B64": "RV370 GL [FireGL V3100]",
|
||||
"10025B65": "RV370 GL [FireMV 2200]",
|
||||
"10025B66": "RV370X",
|
||||
"10025B70": "RV370 [Radeon X300 SE]",
|
||||
"10025B72": "RV380 [Radeon X300/X550/X1050 Series] (Secondary)",
|
||||
"10025A36": "RC4xx/RS4xx PCI Express Port 1",
|
||||
"10025A37": "RC4xx/RS4xx PCI Express Port 2",
|
||||
"10025A38": "RC4xx/RS4xx PCI Express Port 3",
|
||||
"10025A39": "RC4xx/RS4xx PCI Express Port 4",
|
||||
"10025A41": "RS400 [Radeon Xpress 200]",
|
||||
"10025A42": "RS400M [Radeon Xpress 200M]",
|
||||
"10025A61": "RC410 [Radeon Xpress 200/1100]",
|
||||
"10025A23": "RD890S/RD990 I/O Memory Management Unit (IOMMU)",
|
||||
"10025A34": "RS4xx PCI Express Port [ext gfx]",
|
||||
"10025965": "RV280 GL [FireMV 2200 PCI]",
|
||||
"10025974": "RS482/RS485 [Radeon Xpress 1100/1150]",
|
||||
"10025975": "RS482M [Mobility Radeon Xpress 200]",
|
||||
"10025960": "RV280 [Radeon 9200 PRO / 9250]",
|
||||
"10025961": "RV280 [Radeon 9200]",
|
||||
"10025962": "RV280 [Radeon 9200]",
|
||||
"10025964": "RV280 [Radeon 9200 SE]",
|
||||
"10025940": "RV280 [Radeon 9200 PRO] (Secondary)",
|
||||
"10025941": "RV280 [Radeon 9200] (Secondary)",
|
||||
"10025944": "RV280 [Radeon 9200 SE PCI]",
|
||||
"10025954": "RS480 [Radeon Xpress 200 Series]",
|
||||
"10025955": "RS480M [Mobility Radeon Xpress 200]",
|
||||
"10025834": "RS300 [Radeon 9100 IGP]",
|
||||
"10025835": "RS300M [Mobility Radeon 9100 IGP]",
|
||||
"10025854": "RS480 [Radeon Xpress 200 Series] (Secondary)",
|
||||
"10025874": "RS480 [Radeon Xpress 1150] (Secondary)",
|
||||
"1002564B": "RV410/M26 GL [Mobility FireGL V5000]",
|
||||
"1002564F": "RV410/M26 [Mobility Radeon X700 XL]",
|
||||
"10025652": "RV410/M26 [Mobility Radeon X700]",
|
||||
"10025653": "RV410/M26 [Mobility Radeon X700]",
|
||||
"10025654": "Mach64 VT [Video Xpression]",
|
||||
"10025655": "264VT3 [Mach64 VT3]",
|
||||
"10025656": "Mach64 VT4 [Video Xpression+]",
|
||||
"10025657": "RV410 [Radeon X550 XTX / X700]",
|
||||
"1002554E": "R430 [All-In-Wonder X800 GT]",
|
||||
"1002554F": "R430 [Radeon X800]",
|
||||
"10025550": "R423 GL [FireGL V7100]",
|
||||
"10025551": "R423 GL [FireGL V5100]",
|
||||
"10025569": "R423 [Radeon X800 PRO] (Secondary)",
|
||||
"1002556B": "R423 [Radeon X800 GT] (Secondary)",
|
||||
"1002556D": "R480 [Radeon X800 GTO2/XL] (Secondary)",
|
||||
"1002556F": "R430 [Radeon X800] (Secondary)",
|
||||
"10025571": "R423 GL [FireGL V5100] (Secondary)",
|
||||
"10025462": "RV380/M24C [Mobility Radeon X600 SE]",
|
||||
"10025464": "RV370/M22 GL [Mobility FireGL V3100]",
|
||||
"10025549": "R423 [Radeon X800 GTO]",
|
||||
"1002554A": "R423 [Radeon X800 XT Platinum Edition]",
|
||||
"1002554B": "R423 [Radeon X800 GT/SE]",
|
||||
"1002554D": "R480 [Radeon X800 GTO2/XL]",
|
||||
"1002524C": "Rage 128 VR AGP",
|
||||
"1002534D": "Rage 128 4X AGP 4x",
|
||||
"10025354": "Mach 64 VT",
|
||||
"10025446": "Rage 128 PRO Ultra AGP 4x",
|
||||
"10025452": "Rage 128 PRO Ultra4XL VR-R AGP",
|
||||
"10025460": "RV370/M22 [Mobility Radeon X300]",
|
||||
"10025461": "RV370/M22 [Mobility Radeon X300]",
|
||||
"1002514C": "R200 [Radeon 8500/8500 LE]",
|
||||
"1002514D": "R200 [Radeon 9100]",
|
||||
"10025157": "RV200 [Radeon 7500/7500 LE]",
|
||||
"10025159": "RV100 [Radeon 7000 / Radeon VE]",
|
||||
"1002515E": "ES1000",
|
||||
"10025245": "Rage 128 GL PCI",
|
||||
"10025246": "Rage 128 (Rage 4) series",
|
||||
"1002524B": "Rage 128 VR PCI",
|
||||
"10024E6A": "RV350 [Radeon 9800 XT] (Secondary)",
|
||||
"10024E71": "RV350/M10 [Mobility Radeon 9600] (Secondary)",
|
||||
"10024F72": "RV250 [Radeon 9000 Series]",
|
||||
"10024F73": "RV250 [Radeon 9000 Series] (Secondary)",
|
||||
"10025044": "All-In-Wonder 128 PCI",
|
||||
"10025046": "Rage 4 [Rage 128 PRO AGP 4X]",
|
||||
"10025050": "Rage 4 [Rage 128 PRO PCI / Xpert 128 PCI]",
|
||||
"10025052": "Rage 4 [Rage 128 PRO AGP 4X]",
|
||||
"10025144": "R100 [Radeon 7200 / All-In-Wonder Radeon]",
|
||||
"10025148": "R200 GL [FireGL 8800]",
|
||||
"10024E54": "RV350/M10 GL [Mobility FireGL T2]",
|
||||
"10024E56": "RV360/M12 [Mobility Radeon 9550]",
|
||||
"10024E64": "R300 [Radeon 9700 PRO] (Secondary)",
|
||||
"10024E65": "R300 [Radeon 9500 PRO] (Secondary)",
|
||||
"10024E66": "RV350 [Radeon 9600] (Secondary)",
|
||||
"10024E67": "R300 GL [FireGL X1] (Secondary)",
|
||||
"10024E68": "R350 [Radeon 9800 PRO] (Secondary)",
|
||||
"10024E69": "R350 [Radeon 9800] (Secondary)",
|
||||
"10024E48": "R350 [Radeon 9800 Series]",
|
||||
"10024E49": "R350 [Radeon 9800]",
|
||||
"10024E4A": "R360 [Radeon 9800 XXL/XT]",
|
||||
"10024E4B": "R350 GL [FireGL X2 AGP Pro]",
|
||||
"10024E50": "RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700]",
|
||||
"10024E51": "RV350 [Radeon 9550/9600/X1050 Series]",
|
||||
"10024E52": "RV350/M10 [Mobility Radeon 9500/9700 SE]",
|
||||
"10024C66": "RV250/M9 GL [Mobility FireGL 9000/Radeon 9000]",
|
||||
"10024C6E": "RV250/M9 [Mobility Radeon 9000] (Secondary)",
|
||||
"10024D46": "Rage Mobility 128 AGP 4X/Mobility M4",
|
||||
"10024D52": "Theater 550 PRO PCI [ATI TV Wonder 550]",
|
||||
"10024D53": "Theater 550 PRO PCIe",
|
||||
"10024E44": "R300 [Radeon 9700/9700 PRO]",
|
||||
"10024E45": "R300 [Radeon 9500 PRO/9700]",
|
||||
"10024E46": "R300 [Radeon 9600 TX]",
|
||||
"10024E47": "R300 GL [FireGL X1]",
|
||||
"10024C4E": "Rage Mobility L AGP 2x",
|
||||
"10024C46": "Rage Mobility 128 AGP 2X/Mobility M3",
|
||||
"10024C47": "3D Rage IIC PCI / Mobility Radeon 7500/7500C",
|
||||
"10024C49": "3D Rage LT PRO PCI",
|
||||
"10024C4D": "Rage Mobility AGP 2x Series",
|
||||
"10024C50": "Rage 3 LT [3D Rage LT PRO PCI]",
|
||||
"10024C52": "M1 [Rage Mobility-M1 PCI]",
|
||||
"10024C54": "264LT [Mach64 LT]",
|
||||
"10024C57": "RV200/M7 [Mobility Radeon 7500]",
|
||||
"10024C58": "RV200/M7 GL [Mobility FireGL 7800]",
|
||||
"10024C59": "RV100/M6 [Rage/Radeon Mobility Series]",
|
||||
"10024A6A": "R420 [Radeon X800] (Secondary)",
|
||||
"10024A6B": "R420 [Radeon X800 XT AGP] (Secondary)",
|
||||
"10024A70": "R420 [Radeon X800 XT Platinum Edition AGP] (Secondary)",
|
||||
"10024A74": "R420 [Radeon X800 VE] (Secondary)",
|
||||
"10024B49": "R481 [Radeon X850 XT AGP]",
|
||||
"10024B4B": "R481 [Radeon X850 PRO AGP]",
|
||||
"10024B4C": "R481 [Radeon X850 XT Platinum Edition AGP]",
|
||||
"10024B69": "R481 [Radeon X850 XT AGP] (Secondary)",
|
||||
"10024B6B": "R481 [Radeon X850 PRO AGP] (Secondary)",
|
||||
"10024B6C": "R481 [Radeon X850 XT Platinum Edition AGP] (Secondary)",
|
||||
"10024C42": "Mach64 LT [3D Rage LT PRO AGP]",
|
||||
"1002496E": "RV250 [Radeon 9000] (Secondary)",
|
||||
"10024A49": "R420 [Radeon X800 PRO/GTO AGP]",
|
||||
"10024A4A": "R420 [Radeon X800 GT AGP]",
|
||||
"10024A4B": "R420 [Radeon X800 AGP Series]",
|
||||
"10024A4D": "R420 GL [FireGL X3-256]",
|
||||
"10024A4E": "RV420/M18 [Mobility Radeon 9800]",
|
||||
"10024A4F": "R420 [Radeon X850 AGP]",
|
||||
"10024A50": "R420 [Radeon X800 XT Platinum Edition AGP]",
|
||||
"10024A54": "R420 [Radeon X800 VE AGP]",
|
||||
"10024A69": "R420 [Radeon X800 PRO/GTO] (Secondary)",
|
||||
"10024966": "RV250 [Radeon 9000 Series]",
|
||||
"10024753": "Rage XC",
|
||||
"10024754": "Mach64 GT/GT-B [3D Rage I/II]",
|
||||
"10024755": "Mach64 GT-B [3D Rage II+ DVD]",
|
||||
"10024756": "Rage 2 [3D Rage IIC PCI]",
|
||||
"10024757": "Rage 2 [3D Rage IIC AGP]",
|
||||
"10024758": "Mach64 GX [WinTurbo]",
|
||||
"10024759": "Rage 3 [3D Rage IIC PCI]",
|
||||
"1002475A": "3D Rage IIC AGP",
|
||||
"10024654": "Mach64 VT",
|
||||
"10024742": "Rage 3 [3D Rage PRO AGP 2X]",
|
||||
"10024744": "Rage 3 [3D Rage PRO AGP 1X]",
|
||||
"10024749": "3D Rage PRO PCI",
|
||||
"1002474D": "Rage XL AGP 2X",
|
||||
"1002474E": "Rage XC AGP",
|
||||
"1002474F": "Rage XL",
|
||||
"10024750": "3D Rage Pro PCI",
|
||||
"10024752": "Rage 3 [Rage XL PCI]",
|
||||
"10024437": "RS250 [Mobility Radeon 7000 IGP]",
|
||||
"10024554": "210888ET [Mach64 ET]",
|
||||
"10024630": "XENOS Parent Die (XBOX 360)",
|
||||
"10024631": "XENOS Daughter Die (XBOX 360)",
|
||||
}
|
||||
|
||||
|
||||
update_modules()
|
||||
|
||||
if len(sys.argv) > 1 and sys.argv[1]=="--launch-uvicorn":
|
||||
launch_uvicorn()
|
||||
|
@ -34,6 +34,7 @@ call conda activate
|
||||
|
||||
@REM remove the old version of the dev console script, if it's still present
|
||||
if exist "Open Developer Console.cmd" del "Open Developer Console.cmd"
|
||||
if exist "ui\plugins\ui\merge.plugin.js" del "ui\plugins\ui\merge.plugin.js"
|
||||
|
||||
@rem create the stable-diffusion folder, to work with legacy installations
|
||||
if not exist "stable-diffusion" mkdir stable-diffusion
|
||||
@ -52,73 +53,24 @@ if exist ldm rename ldm ldm-old
|
||||
if not exist "%INSTALL_ENV_DIR%\DLLs\libssl-1_1-x64.dll" copy "%INSTALL_ENV_DIR%\Library\bin\libssl-1_1-x64.dll" "%INSTALL_ENV_DIR%\DLLs\"
|
||||
if not exist "%INSTALL_ENV_DIR%\DLLs\libcrypto-1_1-x64.dll" copy "%INSTALL_ENV_DIR%\Library\bin\libcrypto-1_1-x64.dll" "%INSTALL_ENV_DIR%\DLLs\"
|
||||
|
||||
cd ..
|
||||
|
||||
@rem set any overrides
|
||||
set HF_HUB_DISABLE_SYMLINKS_WARNING=true
|
||||
|
||||
@rem install or upgrade the required modules
|
||||
set PATH=C:\Windows\System32;%PATH%
|
||||
|
||||
@REM prevent from using packages from the user's home directory, to avoid conflicts
|
||||
set PYTHONNOUSERSITE=1
|
||||
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
||||
|
||||
@rem Download the required packages
|
||||
call python ..\scripts\check_modules.py
|
||||
if "%ERRORLEVEL%" NEQ "0" (
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
call WHERE uvicorn > .tmp
|
||||
@>nul findstr /m "uvicorn" .tmp
|
||||
@if "%ERRORLEVEL%" NEQ "0" (
|
||||
@echo. & echo "UI packages not found! Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/easydiffusion/easydiffusion/issues" & echo "Thanks!" & echo.
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
@>nul findstr /m "conda_sd_ui_deps_installed" ..\scripts\install_status.txt
|
||||
@if "%ERRORLEVEL%" NEQ "0" (
|
||||
@echo conda_sd_ui_deps_installed >> ..\scripts\install_status.txt
|
||||
)
|
||||
|
||||
@>nul findstr /m "sd_install_complete" ..\scripts\install_status.txt
|
||||
@if "%ERRORLEVEL%" NEQ "0" (
|
||||
@echo sd_weights_downloaded >> ..\scripts\install_status.txt
|
||||
@echo sd_install_complete >> ..\scripts\install_status.txt
|
||||
)
|
||||
|
||||
@echo. & echo "Easy Diffusion installation complete! Starting the server!" & echo.
|
||||
|
||||
@set SD_DIR=%cd%
|
||||
|
||||
set PYTHONPATH=%INSTALL_ENV_DIR%\lib\site-packages
|
||||
echo PYTHONPATH=%PYTHONPATH%
|
||||
|
||||
@rem Download the required packages
|
||||
call where python
|
||||
call python --version
|
||||
|
||||
@cd ..
|
||||
@set SD_UI_PATH=%cd%\ui
|
||||
call python scripts\check_modules.py --launch-uvicorn
|
||||
pause
|
||||
exit /b
|
||||
|
||||
@FOR /F "tokens=* USEBACKQ" %%F IN (`python scripts\get_config.py --default=9000 net listen_port`) DO (
|
||||
@SET ED_BIND_PORT=%%F
|
||||
)
|
||||
|
||||
@FOR /F "tokens=* USEBACKQ" %%F IN (`python scripts\get_config.py --default=False net listen_to_network`) DO (
|
||||
if "%%F" EQU "True" (
|
||||
@FOR /F "tokens=* USEBACKQ" %%G IN (`python scripts\get_config.py --default=0.0.0.0 net bind_ip`) DO (
|
||||
@SET ED_BIND_IP=%%G
|
||||
)
|
||||
) else (
|
||||
@SET ED_BIND_IP=127.0.0.1
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@cd stable-diffusion
|
||||
|
||||
@rem set any overrides
|
||||
set HF_HUB_DISABLE_SYMLINKS_WARNING=true
|
||||
|
||||
@python -m uvicorn main:server_api --app-dir "%SD_UI_PATH%" --port %ED_BIND_PORT% --host %ED_BIND_IP% --log-level error
|
||||
|
||||
|
||||
@pause
|
||||
|
@ -7,6 +7,7 @@ cp sd-ui-files/scripts/check_modules.py scripts/
|
||||
cp sd-ui-files/scripts/get_config.py scripts/
|
||||
cp sd-ui-files/scripts/config.yaml.sample scripts/
|
||||
|
||||
|
||||
source ./scripts/functions.sh
|
||||
|
||||
# activate the installer env
|
||||
@ -20,6 +21,10 @@ if [ -e "open_dev_console.sh" ]; then
|
||||
rm "open_dev_console.sh"
|
||||
fi
|
||||
|
||||
if [ -e "ui/plugins/ui/merge.plugin.js" ]; then
|
||||
rm "ui/plugins/ui/merge.plugin.js"
|
||||
fi
|
||||
|
||||
# set the correct installer path (current vs legacy)
|
||||
if [ -e "installer_files/env" ]; then
|
||||
export INSTALL_ENV_DIR="$(pwd)/installer_files/env"
|
||||
@ -41,45 +46,8 @@ fi
|
||||
if [ -e "src" ]; then mv src src-old; fi
|
||||
if [ -e "ldm" ]; then mv ldm ldm-old; fi
|
||||
|
||||
# Download the required packages
|
||||
if ! python ../scripts/check_modules.py; then
|
||||
read -p "Press any key to continue"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v uvicorn &> /dev/null; then
|
||||
fail "UI packages not found!"
|
||||
fi
|
||||
|
||||
if [ `grep -c sd_install_complete ../scripts/install_status.txt` -gt "0" ]; then
|
||||
echo sd_weights_downloaded >> ../scripts/install_status.txt
|
||||
echo sd_install_complete >> ../scripts/install_status.txt
|
||||
fi
|
||||
|
||||
printf "\n\nEasy Diffusion installation complete, starting the server!\n\n"
|
||||
|
||||
SD_PATH=`pwd`
|
||||
|
||||
export PYTORCH_ENABLE_MPS_FALLBACK=1
|
||||
export PYTHONPATH="$INSTALL_ENV_DIR/lib/python3.8/site-packages"
|
||||
echo "PYTHONPATH=$PYTHONPATH"
|
||||
|
||||
which python
|
||||
python --version
|
||||
|
||||
cd ..
|
||||
export SD_UI_PATH=`pwd`/ui
|
||||
export ED_BIND_PORT="$( python scripts/get_config.py --default=9000 net listen_port )"
|
||||
case "$( python scripts/get_config.py --default=False net listen_to_network )" in
|
||||
"True")
|
||||
export ED_BIND_IP=$( python scripts/get_config.py --default=0.0.0.0 net bind_ip)
|
||||
;;
|
||||
"False")
|
||||
export ED_BIND_IP=127.0.0.1
|
||||
;;
|
||||
esac
|
||||
cd stable-diffusion
|
||||
|
||||
uvicorn main:server_api --app-dir "$SD_UI_PATH" --port "$ED_BIND_PORT" --host "$ED_BIND_IP" --log-level error
|
||||
# Download the required packages
|
||||
python scripts/check_modules.py --launch-uvicorn
|
||||
|
||||
read -p "Press any key to continue"
|
||||
|
@ -11,7 +11,7 @@ if [ -f "on_sd_start.bat" ]; then
|
||||
echo download. This will not work.
|
||||
echo
|
||||
echo Recommended: Please close this window and download the installer from
|
||||
echo https://stable-diffusion-ui.github.io/docs/installation/
|
||||
echo https://easydiffusion.github.io/docs/installation/
|
||||
echo
|
||||
echo ================================================================================
|
||||
echo
|
||||
|
@ -37,7 +37,6 @@ ROOT_DIR = os.path.abspath(os.path.join(SD_DIR, ".."))
|
||||
SD_UI_DIR = os.getenv("SD_UI_PATH", None)
|
||||
|
||||
CONFIG_DIR = os.path.abspath(os.path.join(SD_UI_DIR, "..", "scripts"))
|
||||
MODELS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "models"))
|
||||
BUCKET_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "bucket"))
|
||||
|
||||
USER_PLUGINS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "plugins"))
|
||||
@ -61,7 +60,7 @@ APP_CONFIG_DEFAULTS = {
|
||||
"ui": {
|
||||
"open_browser_on_start": True,
|
||||
},
|
||||
"test_diffusers": True,
|
||||
"use_v3_engine": True,
|
||||
}
|
||||
|
||||
IMAGE_EXTENSIONS = [
|
||||
@ -92,14 +91,23 @@ CUSTOM_MODIFIERS_LANDSCAPE_EXTENSIONS = [
|
||||
"-landscape",
|
||||
]
|
||||
|
||||
MODELS_DIR = os.path.abspath(os.path.join(SD_DIR, "..", "models"))
|
||||
|
||||
|
||||
def init():
|
||||
global MODELS_DIR
|
||||
|
||||
os.makedirs(USER_UI_PLUGINS_DIR, exist_ok=True)
|
||||
os.makedirs(USER_SERVER_PLUGINS_DIR, exist_ok=True)
|
||||
|
||||
# https://pytorch.org/docs/stable/storage.html
|
||||
warnings.filterwarnings("ignore", category=UserWarning, message="TypedStorage is deprecated")
|
||||
|
||||
config = getConfig()
|
||||
config_models_dir = config.get("models_dir", None)
|
||||
if (config_models_dir is not None and config_models_dir != ""):
|
||||
MODELS_DIR = config_models_dir
|
||||
|
||||
|
||||
def init_render_threads():
|
||||
load_server_plugins()
|
||||
@ -116,9 +124,9 @@ def getConfig(default_val=APP_CONFIG_DEFAULTS):
|
||||
shutil.move(config_legacy_yaml, config_yaml_path)
|
||||
|
||||
def set_config_on_startup(config: dict):
|
||||
if getConfig.__test_diffusers_on_startup is None:
|
||||
getConfig.__test_diffusers_on_startup = config.get("test_diffusers", True)
|
||||
config["config_on_startup"] = {"test_diffusers": getConfig.__test_diffusers_on_startup}
|
||||
if getConfig.__use_v3_engine_on_startup is None:
|
||||
getConfig.__use_v3_engine_on_startup = config.get("use_v3_engine", True)
|
||||
config["config_on_startup"] = {"use_v3_engine": getConfig.__use_v3_engine_on_startup}
|
||||
|
||||
if os.path.isfile(config_yaml_path):
|
||||
try:
|
||||
@ -166,12 +174,15 @@ def getConfig(default_val=APP_CONFIG_DEFAULTS):
|
||||
return default_val
|
||||
|
||||
|
||||
getConfig.__test_diffusers_on_startup = None
|
||||
getConfig.__use_v3_engine_on_startup = None
|
||||
|
||||
|
||||
def setConfig(config):
|
||||
global MODELS_DIR
|
||||
|
||||
try: # config.yaml
|
||||
config_yaml_path = os.path.join(CONFIG_DIR, "..", "config.yaml")
|
||||
config_yaml_path = os.path.abspath(config_yaml_path)
|
||||
yaml = YAML()
|
||||
|
||||
if not hasattr(config, "_yaml_comment"):
|
||||
@ -205,6 +216,9 @@ def setConfig(config):
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
|
||||
if config.get("models_dir"):
|
||||
MODELS_DIR = config["models_dir"]
|
||||
|
||||
|
||||
def save_to_config(ckpt_model_name, vae_model_name, hypernetwork_model_name, vram_usage_level):
|
||||
config = getConfig()
|
||||
|
@ -55,8 +55,13 @@ def init():
|
||||
return bucketfiles
|
||||
|
||||
else:
|
||||
bucket_id = crud.get_bucket_by_path(db, path).id
|
||||
bucket = crud.get_bucket_by_path(db, path)
|
||||
if bucket == None:
|
||||
raise HTTPException(status_code=404, detail="Bucket not found")
|
||||
bucket_id = bucket.id
|
||||
bucketfile = db.query(models.BucketFile).filter(models.BucketFile.bucket_id == bucket_id, models.BucketFile.filename == filename).first()
|
||||
if bucketfile == None:
|
||||
raise HTTPException(status_code=404, detail="File not found")
|
||||
|
||||
suffix = get_suffix_from_filename(filename)
|
||||
|
||||
|
@ -37,7 +37,7 @@ MODEL_EXTENSIONS = {
|
||||
}
|
||||
DEFAULT_MODELS = {
|
||||
"stable-diffusion": [
|
||||
{"file_name": "sd-v1-4.ckpt", "model_id": "1.4"},
|
||||
{"file_name": "sd-v1-5.safetensors", "model_id": "1.5-pruned-emaonly-fp16"},
|
||||
],
|
||||
"gfpgan": [
|
||||
{"file_name": "GFPGANv1.4.pth", "model_id": "1.4"},
|
||||
@ -193,9 +193,9 @@ def resolve_model_paths(models_data: ModelsData):
|
||||
skip_models = cn_filters + ["latent_upscaler", "nsfw_checker"]
|
||||
if model_type in skip_models: # doesn't use model paths
|
||||
continue
|
||||
if model_type == "codeformer":
|
||||
if model_type == "codeformer" and model_paths[model_type]:
|
||||
download_if_necessary("codeformer", "codeformer.pth", "codeformer-0.1.0")
|
||||
elif model_type == "controlnet":
|
||||
elif model_type == "controlnet" and model_paths[model_type]:
|
||||
model_id = model_paths[model_type]
|
||||
model_info = get_model_info_from_db(model_type=model_type, model_id=model_id)
|
||||
if model_info:
|
||||
@ -261,7 +261,24 @@ def make_model_folders():
|
||||
for model_type in KNOWN_MODEL_TYPES:
|
||||
model_dir_path = os.path.join(app.MODELS_DIR, model_type)
|
||||
|
||||
try:
|
||||
os.makedirs(model_dir_path, exist_ok=True)
|
||||
except Exception as e:
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
|
||||
Console().print(
|
||||
Panel(
|
||||
"\n"
|
||||
+ f"Error while creating the models directory: '{model_dir_path}'\n"
|
||||
+ f"Error: {e}\n\n"
|
||||
+ f"[white]Check the 'models_dir:' line in the file '{os.path.join(app.ROOT_DIR, 'config.yaml')}'.[/white]\n",
|
||||
title="Fatal Error starting Easy Diffusion",
|
||||
style="bold yellow on red",
|
||||
)
|
||||
)
|
||||
input("Press Enter to terminate...")
|
||||
exit(1)
|
||||
|
||||
help_file_name = f"Place your {model_type} model files here.txt"
|
||||
help_file_contents = f'Supported extensions: {" or ".join(MODEL_EXTENSIONS.get(model_type))}'
|
||||
@ -305,7 +322,7 @@ def is_malicious_model(file_path):
|
||||
def getModels(scan_for_malicious: bool = True):
|
||||
models = {
|
||||
"options": {
|
||||
"stable-diffusion": [{"sd-v1-4": "SD 1.4"}],
|
||||
"stable-diffusion": [],
|
||||
"vae": [],
|
||||
"hypernetwork": [],
|
||||
"lora": [],
|
||||
|
@ -12,9 +12,9 @@ from easydiffusion import app
|
||||
manifest = {
|
||||
"tensorrt": {
|
||||
"install": [
|
||||
"nvidia-cudnn --pre --extra-index-url=https://pypi.nvidia.com --trusted-host pypi.nvidia.com",
|
||||
"tensorrt-libs --pre --extra-index-url=https://pypi.nvidia.com --trusted-host pypi.nvidia.com",
|
||||
"tensorrt --pre --extra-index-url=https://pypi.nvidia.com --trusted-host pypi.nvidia.com",
|
||||
"wheel",
|
||||
"nvidia-cudnn-cu11==8.9.4.25",
|
||||
"tensorrt==9.0.0.post11.dev1 --pre --extra-index-url=https://pypi.nvidia.com --trusted-host pypi.nvidia.com",
|
||||
],
|
||||
"uninstall": ["tensorrt"],
|
||||
# TODO also uninstall tensorrt-libs and nvidia-cudnn, but do it upon restarting (avoid 'file in use' error)
|
||||
|
@ -30,7 +30,7 @@ def init(device):
|
||||
from easydiffusion import app
|
||||
|
||||
app_config = app.getConfig()
|
||||
context.test_diffusers = app_config.get("test_diffusers", True)
|
||||
context.test_diffusers = app_config.get("use_v3_engine", True)
|
||||
|
||||
log.info("Device usage during initialization:")
|
||||
get_device_usage(device, log_info=True, process_usage_only=False)
|
||||
|
@ -15,8 +15,10 @@ from easydiffusion.types import (
|
||||
FilterImageRequest,
|
||||
MergeRequest,
|
||||
TaskData,
|
||||
RenderTaskData,
|
||||
ModelsData,
|
||||
OutputFormatData,
|
||||
SaveToDiskData,
|
||||
convert_legacy_render_req_to_new,
|
||||
)
|
||||
from easydiffusion.utils import log
|
||||
@ -36,6 +38,7 @@ NOCACHE_HEADERS = {
|
||||
"Pragma": "no-cache",
|
||||
"Expires": "0",
|
||||
}
|
||||
PROTECTED_CONFIG_KEYS = ("block_nsfw",) # can't change these via the HTTP API
|
||||
|
||||
|
||||
class NoCacheStaticFiles(StaticFiles):
|
||||
@ -63,7 +66,8 @@ class SetAppConfigRequest(BaseModel, extra=Extra.allow):
|
||||
ui_open_browser_on_start: bool = None
|
||||
listen_to_network: bool = None
|
||||
listen_port: int = None
|
||||
test_diffusers: bool = True
|
||||
use_v3_engine: bool = True
|
||||
models_dir: str = None
|
||||
|
||||
|
||||
def init():
|
||||
@ -172,10 +176,11 @@ def set_app_config_internal(req: SetAppConfigRequest):
|
||||
config["net"] = {}
|
||||
config["net"]["listen_port"] = int(req.listen_port)
|
||||
|
||||
config["test_diffusers"] = req.test_diffusers
|
||||
config["use_v3_engine"] = req.use_v3_engine
|
||||
config["models_dir"] = req.models_dir
|
||||
|
||||
for property, property_value in req.dict().items():
|
||||
if property_value is not None and property not in req.__fields__:
|
||||
if property_value is not None and property not in req.__fields__ and property not in PROTECTED_CONFIG_KEYS:
|
||||
config[property] = property_value
|
||||
|
||||
try:
|
||||
@ -204,7 +209,12 @@ def read_web_data_internal(key: str = None, **kwargs):
|
||||
if not key: # /get without parameters, stable-diffusion easter egg.
|
||||
raise HTTPException(status_code=418, detail="StableDiffusion is drawing a teapot!") # HTTP418 I'm a teapot
|
||||
elif key == "app_config":
|
||||
return JSONResponse(app.getConfig(), headers=NOCACHE_HEADERS)
|
||||
config = app.getConfig()
|
||||
|
||||
if "models_dir" not in config:
|
||||
config["models_dir"] = app.MODELS_DIR
|
||||
|
||||
return JSONResponse(config, headers=NOCACHE_HEADERS)
|
||||
elif key == "system_info":
|
||||
config = app.getConfig()
|
||||
|
||||
@ -215,6 +225,7 @@ def read_web_data_internal(key: str = None, **kwargs):
|
||||
"hosts": app.getIPConfig(),
|
||||
"default_output_dir": output_dir,
|
||||
"enforce_output_dir": ("force_save_path" in config),
|
||||
"enforce_output_metadata": ("force_save_metadata" in config),
|
||||
}
|
||||
system_info["devices"]["config"] = config.get("render_devices", "auto")
|
||||
return JSONResponse(system_info, headers=NOCACHE_HEADERS)
|
||||
@ -261,14 +272,15 @@ def render_internal(req: dict):
|
||||
|
||||
# separate out the request data into rendering and task-specific data
|
||||
render_req: GenerateImageRequest = GenerateImageRequest.parse_obj(req)
|
||||
task_data: TaskData = TaskData.parse_obj(req)
|
||||
task_data: RenderTaskData = RenderTaskData.parse_obj(req)
|
||||
models_data: ModelsData = ModelsData.parse_obj(req)
|
||||
output_format: OutputFormatData = OutputFormatData.parse_obj(req)
|
||||
save_data: SaveToDiskData = SaveToDiskData.parse_obj(req)
|
||||
|
||||
# Overwrite user specified save path
|
||||
config = app.getConfig()
|
||||
if "force_save_path" in config:
|
||||
task_data.save_to_disk_path = config["force_save_path"]
|
||||
save_data.save_to_disk_path = config["force_save_path"]
|
||||
|
||||
render_req.init_image_mask = req.get("mask") # hack: will rename this in the HTTP API in a future revision
|
||||
|
||||
@ -280,7 +292,7 @@ def render_internal(req: dict):
|
||||
)
|
||||
|
||||
# enqueue the task
|
||||
task = RenderTask(render_req, task_data, models_data, output_format)
|
||||
task = RenderTask(render_req, task_data, models_data, output_format, save_data)
|
||||
return enqueue_task(task)
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
@ -291,13 +303,14 @@ def render_internal(req: dict):
|
||||
|
||||
def filter_internal(req: dict):
|
||||
try:
|
||||
session_id = req.get("session_id", "session")
|
||||
filter_req: FilterImageRequest = FilterImageRequest.parse_obj(req)
|
||||
task_data: TaskData = TaskData.parse_obj(req)
|
||||
models_data: ModelsData = ModelsData.parse_obj(req)
|
||||
output_format: OutputFormatData = OutputFormatData.parse_obj(req)
|
||||
save_data: SaveToDiskData = SaveToDiskData.parse_obj(req)
|
||||
|
||||
# enqueue the task
|
||||
task = FilterTask(filter_req, session_id, models_data, output_format)
|
||||
task = FilterTask(filter_req, task_data, models_data, output_format, save_data)
|
||||
return enqueue_task(task)
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
@ -456,8 +469,8 @@ def modify_package_internal(package_name: str, req: dict):
|
||||
log.error(traceback.format_exc())
|
||||
return HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
def get_sha256_internal(obj_path):
|
||||
import hashlib
|
||||
from easydiffusion.utils import sha256sum
|
||||
|
||||
path = obj_path.split("/")
|
||||
@ -477,4 +490,3 @@ def get_sha256_internal(obj_path):
|
||||
log.error(str(e))
|
||||
log.error(traceback.format_exc())
|
||||
return HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
@ -1,12 +1,25 @@
|
||||
import os
|
||||
import json
|
||||
import pprint
|
||||
import time
|
||||
|
||||
from numpy import base_repr
|
||||
|
||||
from sdkit.filter import apply_filters
|
||||
from sdkit.models import load_model
|
||||
from sdkit.utils import img_to_base64_str, get_image, log
|
||||
from sdkit.utils import img_to_base64_str, get_image, log, save_images
|
||||
|
||||
from easydiffusion import model_manager, runtime
|
||||
from easydiffusion.types import FilterImageRequest, FilterImageResponse, ModelsData, OutputFormatData
|
||||
from easydiffusion.types import (
|
||||
FilterImageRequest,
|
||||
FilterImageResponse,
|
||||
ModelsData,
|
||||
OutputFormatData,
|
||||
SaveToDiskData,
|
||||
TaskData,
|
||||
GenerateImageRequest,
|
||||
)
|
||||
from easydiffusion.utils.save_utils import format_folder_name
|
||||
|
||||
from .task import Task
|
||||
|
||||
@ -15,13 +28,22 @@ class FilterTask(Task):
|
||||
"For applying filters to input images"
|
||||
|
||||
def __init__(
|
||||
self, req: FilterImageRequest, session_id: str, models_data: ModelsData, output_format: OutputFormatData
|
||||
self,
|
||||
req: FilterImageRequest,
|
||||
task_data: TaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
):
|
||||
super().__init__(session_id)
|
||||
super().__init__(task_data.session_id)
|
||||
|
||||
task_data.request_id = self.id
|
||||
|
||||
self.request = req
|
||||
self.task_data = task_data
|
||||
self.models_data = models_data
|
||||
self.output_format = output_format
|
||||
self.save_data = save_data
|
||||
|
||||
# convert to multi-filter format, if necessary
|
||||
if isinstance(req.filter, str):
|
||||
@ -34,13 +56,15 @@ class FilterTask(Task):
|
||||
def run(self):
|
||||
"Runs the image filtering task on the assigned thread"
|
||||
|
||||
from easydiffusion import app
|
||||
|
||||
context = runtime.context
|
||||
|
||||
model_manager.resolve_model_paths(self.models_data)
|
||||
model_manager.reload_models_if_necessary(context, self.models_data)
|
||||
model_manager.fail_if_models_did_not_load(context)
|
||||
|
||||
print_task_info(self.request, self.models_data, self.output_format)
|
||||
print_task_info(self.request, self.models_data, self.output_format, self.save_data)
|
||||
|
||||
if isinstance(self.request.image, list):
|
||||
images = [get_image(img) for img in self.request.image]
|
||||
@ -50,6 +74,26 @@ class FilterTask(Task):
|
||||
images = filter_images(context, images, self.request.filter, self.request.filter_params)
|
||||
|
||||
output_format = self.output_format
|
||||
|
||||
if self.save_data.save_to_disk_path is not None:
|
||||
app_config = app.getConfig()
|
||||
folder_format = app_config.get("folder_format", "$id")
|
||||
|
||||
dummy_req = GenerateImageRequest()
|
||||
img_id = base_repr(int(time.time() * 10000), 36)[-7:] # Base 36 conversion, 0-9, A-Z
|
||||
|
||||
save_dir_path = os.path.join(
|
||||
self.save_data.save_to_disk_path, format_folder_name(folder_format, dummy_req, self.task_data)
|
||||
)
|
||||
save_images(
|
||||
images,
|
||||
save_dir_path,
|
||||
file_name=img_id,
|
||||
output_format=output_format.output_format,
|
||||
output_quality=output_format.output_quality,
|
||||
output_lossless=output_format.output_lossless,
|
||||
)
|
||||
|
||||
images = [
|
||||
img_to_base64_str(
|
||||
img, output_format.output_format, output_format.output_quality, output_format.output_lossless
|
||||
@ -60,6 +104,7 @@ class FilterTask(Task):
|
||||
res = FilterImageResponse(self.request, self.models_data, images=images)
|
||||
res = res.json()
|
||||
self.buffer_queue.put(json.dumps(res))
|
||||
|
||||
log.info("Filter task completed")
|
||||
|
||||
self.response = res
|
||||
@ -105,11 +150,15 @@ def after_filter(context, filter_name, filter_params, previous_state):
|
||||
load_model(context, "realesrgan")
|
||||
|
||||
|
||||
def print_task_info(req: FilterImageRequest, models_data: ModelsData, output_format: OutputFormatData):
|
||||
def print_task_info(
|
||||
req: FilterImageRequest, models_data: ModelsData, output_format: OutputFormatData, save_data: SaveToDiskData
|
||||
):
|
||||
req_str = pprint.pformat({"filter": req.filter, "filter_params": req.filter_params}).replace("[", "\[")
|
||||
models_data = pprint.pformat(models_data.dict()).replace("[", "\[")
|
||||
output_format = pprint.pformat(output_format.dict()).replace("[", "\[")
|
||||
save_data = pprint.pformat(save_data.dict()).replace("[", "\[")
|
||||
|
||||
log.info(f"request: {req_str}")
|
||||
log.info(f"models data: {models_data}")
|
||||
log.info(f"output format: {output_format}")
|
||||
log.info(f"save data: {save_data}")
|
||||
|
@ -4,9 +4,9 @@ import queue
|
||||
import time
|
||||
|
||||
from easydiffusion import model_manager, runtime
|
||||
from easydiffusion.types import GenerateImageRequest, ModelsData, OutputFormatData
|
||||
from easydiffusion.types import GenerateImageRequest, ModelsData, OutputFormatData, SaveToDiskData
|
||||
from easydiffusion.types import Image as ResponseImage
|
||||
from easydiffusion.types import GenerateImageResponse, TaskData, UserInitiatedStop
|
||||
from easydiffusion.types import GenerateImageResponse, RenderTaskData, UserInitiatedStop
|
||||
from easydiffusion.utils import get_printable_request, log, save_images_to_disk
|
||||
from sdkit.generate import generate_images
|
||||
from sdkit.utils import (
|
||||
@ -28,23 +28,38 @@ class RenderTask(Task):
|
||||
"For image generation"
|
||||
|
||||
def __init__(
|
||||
self, req: GenerateImageRequest, task_data: TaskData, models_data: ModelsData, output_format: OutputFormatData
|
||||
self,
|
||||
req: GenerateImageRequest,
|
||||
task_data: RenderTaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
):
|
||||
super().__init__(task_data.session_id)
|
||||
|
||||
task_data.request_id = self.id
|
||||
self.render_request: GenerateImageRequest = req # Initial Request
|
||||
self.task_data: TaskData = task_data
|
||||
|
||||
self.render_request = req # Initial Request
|
||||
self.task_data = task_data
|
||||
self.models_data = models_data
|
||||
self.output_format = output_format
|
||||
self.save_data = save_data
|
||||
|
||||
self.temp_images: list = [None] * req.num_outputs * (1 if task_data.show_only_filtered_image else 2)
|
||||
|
||||
def run(self):
|
||||
"Runs the image generation task on the assigned thread"
|
||||
|
||||
from easydiffusion import task_manager
|
||||
from easydiffusion import task_manager, app
|
||||
|
||||
context = runtime.context
|
||||
config = app.getConfig()
|
||||
|
||||
if config.get("block_nsfw", False): # override if set on the server
|
||||
self.task_data.block_nsfw = True
|
||||
if "nsfw_checker" not in self.task_data.filters:
|
||||
self.task_data.filters.append("nsfw_checker")
|
||||
self.models_data.model_paths["nsfw_checker"] = "nsfw_checker"
|
||||
|
||||
def step_callback():
|
||||
task_manager.keep_task_alive(self)
|
||||
@ -80,6 +95,7 @@ class RenderTask(Task):
|
||||
self.task_data,
|
||||
self.models_data,
|
||||
self.output_format,
|
||||
self.save_data,
|
||||
self.buffer_queue,
|
||||
self.temp_images,
|
||||
step_callback,
|
||||
@ -122,22 +138,23 @@ class RenderTask(Task):
|
||||
def make_images(
|
||||
context,
|
||||
req: GenerateImageRequest,
|
||||
task_data: TaskData,
|
||||
task_data: RenderTaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
data_queue: queue.Queue,
|
||||
task_temp_images: list,
|
||||
step_callback,
|
||||
):
|
||||
context.stop_processing = False
|
||||
print_task_info(req, task_data, models_data, output_format)
|
||||
print_task_info(req, task_data, models_data, output_format, save_data)
|
||||
|
||||
images, seeds = make_images_internal(
|
||||
context, req, task_data, models_data, output_format, data_queue, task_temp_images, step_callback
|
||||
context, req, task_data, models_data, output_format, save_data, data_queue, task_temp_images, step_callback
|
||||
)
|
||||
|
||||
res = GenerateImageResponse(
|
||||
req, task_data, models_data, output_format, images=construct_response(images, seeds, output_format)
|
||||
req, task_data, models_data, output_format, save_data, images=construct_response(images, seeds, output_format)
|
||||
)
|
||||
res = res.json()
|
||||
data_queue.put(json.dumps(res))
|
||||
@ -147,25 +164,32 @@ def make_images(
|
||||
|
||||
|
||||
def print_task_info(
|
||||
req: GenerateImageRequest, task_data: TaskData, models_data: ModelsData, output_format: OutputFormatData
|
||||
req: GenerateImageRequest,
|
||||
task_data: RenderTaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
):
|
||||
req_str = pprint.pformat(get_printable_request(req, task_data, output_format)).replace("[", "\[")
|
||||
req_str = pprint.pformat(get_printable_request(req, task_data, models_data, output_format, save_data)).replace("[", "\[")
|
||||
task_str = pprint.pformat(task_data.dict()).replace("[", "\[")
|
||||
models_data = pprint.pformat(models_data.dict()).replace("[", "\[")
|
||||
output_format = pprint.pformat(output_format.dict()).replace("[", "\[")
|
||||
save_data = pprint.pformat(save_data.dict()).replace("[", "\[")
|
||||
|
||||
log.info(f"request: {req_str}")
|
||||
log.info(f"task data: {task_str}")
|
||||
# log.info(f"models data: {models_data}")
|
||||
log.info(f"output format: {output_format}")
|
||||
log.info(f"save data: {save_data}")
|
||||
|
||||
|
||||
def make_images_internal(
|
||||
context,
|
||||
req: GenerateImageRequest,
|
||||
task_data: TaskData,
|
||||
task_data: RenderTaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
data_queue: queue.Queue,
|
||||
task_temp_images: list,
|
||||
step_callback,
|
||||
@ -187,8 +211,8 @@ def make_images_internal(
|
||||
filters, filter_params = task_data.filters, task_data.filter_params
|
||||
filtered_images = filter_images(context, images, filters, filter_params) if not user_stopped else images
|
||||
|
||||
if task_data.save_to_disk_path is not None:
|
||||
save_images_to_disk(images, filtered_images, req, task_data, output_format)
|
||||
if save_data.save_to_disk_path is not None:
|
||||
save_images_to_disk(images, filtered_images, req, task_data, models_data, output_format, save_data)
|
||||
|
||||
seeds = [*range(req.seed, req.seed + len(images))]
|
||||
if task_data.show_only_filtered_image or filtered_images is images:
|
||||
@ -200,7 +224,7 @@ def make_images_internal(
|
||||
def generate_images_internal(
|
||||
context,
|
||||
req: GenerateImageRequest,
|
||||
task_data: TaskData,
|
||||
task_data: RenderTaskData,
|
||||
models_data: ModelsData,
|
||||
data_queue: queue.Queue,
|
||||
task_temp_images: list,
|
||||
@ -254,6 +278,13 @@ def generate_images_internal(
|
||||
setattr(pipe.unet, "_allocate_trt_buffers_backup", pipe.unet._allocate_trt_buffers)
|
||||
delattr(pipe.unet, "_allocate_trt_buffers")
|
||||
|
||||
if task_data.enable_vae_tiling:
|
||||
if hasattr(pipe, "enable_vae_tiling"):
|
||||
pipe.enable_vae_tiling()
|
||||
else:
|
||||
if hasattr(pipe, "disable_vae_tiling"):
|
||||
pipe.disable_vae_tiling()
|
||||
|
||||
images = generate_images(context, callback=callback, **req.dict())
|
||||
user_stopped = False
|
||||
except UserInitiatedStop:
|
||||
@ -291,7 +322,7 @@ def construct_response(images: list, seeds: list, output_format: OutputFormatDat
|
||||
def make_step_callback(
|
||||
context,
|
||||
req: GenerateImageRequest,
|
||||
task_data: TaskData,
|
||||
task_data: RenderTaskData,
|
||||
data_queue: queue.Queue,
|
||||
task_temp_images: list,
|
||||
step_callback,
|
||||
|
@ -26,7 +26,7 @@ class GenerateImageRequest(BaseModel):
|
||||
sampler_name: str = None # "ddim", "plms", "heun", "euler", "euler_a", "dpm2", "dpm2_a", "lms"
|
||||
hypernetwork_strength: float = 0
|
||||
lora_alpha: Union[float, List[float]] = 0
|
||||
tiling: str = "none" # "none", "x", "y", "xy"
|
||||
tiling: str = None # None, "x", "y", "xy"
|
||||
|
||||
|
||||
class FilterImageRequest(BaseModel):
|
||||
@ -58,10 +58,17 @@ class OutputFormatData(BaseModel):
|
||||
output_lossless: bool = False
|
||||
|
||||
|
||||
class SaveToDiskData(BaseModel):
|
||||
save_to_disk_path: str = None
|
||||
metadata_output_format: str = "txt" # or "json"
|
||||
|
||||
|
||||
class TaskData(BaseModel):
|
||||
request_id: str = None
|
||||
session_id: str = "session"
|
||||
save_to_disk_path: str = None
|
||||
|
||||
|
||||
class RenderTaskData(TaskData):
|
||||
vram_usage_level: str = "balanced" # or "low" or "medium"
|
||||
|
||||
use_face_correction: Union[str, List[str]] = None # or "GFPGANv1.3"
|
||||
@ -77,10 +84,10 @@ class TaskData(BaseModel):
|
||||
filters: List[str] = []
|
||||
filter_params: Dict[str, Dict[str, Any]] = {}
|
||||
control_filter_to_apply: Union[str, List[str]] = None
|
||||
enable_vae_tiling: bool = True
|
||||
|
||||
show_only_filtered_image: bool = False
|
||||
block_nsfw: bool = False
|
||||
metadata_output_format: str = "txt" # or "json"
|
||||
stream_image_progress: bool = False
|
||||
stream_image_progress_interval: int = 5
|
||||
clip_skip: bool = False
|
||||
@ -126,12 +133,14 @@ class GenerateImageResponse:
|
||||
task_data: TaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
images: list,
|
||||
):
|
||||
self.render_request = render_request
|
||||
self.task_data = task_data
|
||||
self.models_data = models_data
|
||||
self.output_format = output_format
|
||||
self.save_data = save_data
|
||||
self.images = images
|
||||
|
||||
def json(self):
|
||||
@ -141,6 +150,7 @@ class GenerateImageResponse:
|
||||
|
||||
task_data = self.task_data.dict()
|
||||
task_data.update(self.output_format.dict())
|
||||
task_data.update(self.save_data.dict())
|
||||
|
||||
res = {
|
||||
"status": "succeeded",
|
||||
|
@ -1,4 +1,5 @@
|
||||
import logging
|
||||
import hashlib
|
||||
|
||||
log = logging.getLogger("easydiffusion")
|
||||
|
||||
|
@ -7,7 +7,14 @@ from datetime import datetime
|
||||
from functools import reduce
|
||||
|
||||
from easydiffusion import app
|
||||
from easydiffusion.types import GenerateImageRequest, TaskData, OutputFormatData
|
||||
from easydiffusion.types import (
|
||||
GenerateImageRequest,
|
||||
TaskData,
|
||||
RenderTaskData,
|
||||
OutputFormatData,
|
||||
SaveToDiskData,
|
||||
ModelsData,
|
||||
)
|
||||
from numpy import base_repr
|
||||
from sdkit.utils import save_dicts, save_images
|
||||
from sdkit.models.model_loader.embeddings import get_embedding_token
|
||||
@ -95,7 +102,7 @@ def format_folder_name(format: str, req: GenerateImageRequest, task_data: TaskDa
|
||||
def format_file_name(
|
||||
format: str,
|
||||
req: GenerateImageRequest,
|
||||
task_data: TaskData,
|
||||
task_data: RenderTaskData,
|
||||
now: float,
|
||||
batch_file_number: int,
|
||||
folder_img_number: ImageNumber,
|
||||
@ -118,13 +125,19 @@ def format_file_name(
|
||||
|
||||
|
||||
def save_images_to_disk(
|
||||
images: list, filtered_images: list, req: GenerateImageRequest, task_data: TaskData, output_format: OutputFormatData
|
||||
images: list,
|
||||
filtered_images: list,
|
||||
req: GenerateImageRequest,
|
||||
task_data: RenderTaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
):
|
||||
now = time.time()
|
||||
app_config = app.getConfig()
|
||||
folder_format = app_config.get("folder_format", "$id")
|
||||
save_dir_path = os.path.join(task_data.save_to_disk_path, format_folder_name(folder_format, req, task_data))
|
||||
metadata_entries = get_metadata_entries_for_request(req, task_data, output_format)
|
||||
save_dir_path = os.path.join(save_data.save_to_disk_path, format_folder_name(folder_format, req, task_data))
|
||||
metadata_entries = get_metadata_entries_for_request(req, task_data, models_data, output_format, save_data)
|
||||
file_number = calculate_img_number(save_dir_path, task_data)
|
||||
make_filename = make_filename_callback(
|
||||
app_config.get("filename_format", "$p_$tsb64"),
|
||||
@ -143,8 +156,8 @@ def save_images_to_disk(
|
||||
output_quality=output_format.output_quality,
|
||||
output_lossless=output_format.output_lossless,
|
||||
)
|
||||
if task_data.metadata_output_format:
|
||||
for metadata_output_format in task_data.metadata_output_format.split(","):
|
||||
if save_data.metadata_output_format:
|
||||
for metadata_output_format in save_data.metadata_output_format.split(","):
|
||||
if metadata_output_format.lower() in ["json", "txt", "embed"]:
|
||||
save_dicts(
|
||||
metadata_entries,
|
||||
@ -179,8 +192,8 @@ def save_images_to_disk(
|
||||
output_quality=output_format.output_quality,
|
||||
output_lossless=output_format.output_lossless,
|
||||
)
|
||||
if task_data.metadata_output_format:
|
||||
for metadata_output_format in task_data.metadata_output_format.split(","):
|
||||
if save_data.metadata_output_format:
|
||||
for metadata_output_format in save_data.metadata_output_format.split(","):
|
||||
if metadata_output_format.lower() in ["json", "txt", "embed"]:
|
||||
save_dicts(
|
||||
metadata_entries,
|
||||
@ -191,11 +204,17 @@ def save_images_to_disk(
|
||||
)
|
||||
|
||||
|
||||
def get_metadata_entries_for_request(req: GenerateImageRequest, task_data: TaskData, output_format: OutputFormatData):
|
||||
metadata = get_printable_request(req, task_data, output_format)
|
||||
def get_metadata_entries_for_request(
|
||||
req: GenerateImageRequest,
|
||||
task_data: RenderTaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
):
|
||||
metadata = get_printable_request(req, task_data, models_data, output_format, save_data)
|
||||
|
||||
# if text, format it in the text format expected by the UI
|
||||
is_txt_format = task_data.metadata_output_format and "txt" in task_data.metadata_output_format.lower().split(",")
|
||||
is_txt_format = save_data.metadata_output_format and "txt" in save_data.metadata_output_format.lower().split(",")
|
||||
if is_txt_format:
|
||||
|
||||
def format_value(value):
|
||||
@ -214,13 +233,20 @@ def get_metadata_entries_for_request(req: GenerateImageRequest, task_data: TaskD
|
||||
return entries
|
||||
|
||||
|
||||
def get_printable_request(req: GenerateImageRequest, task_data: TaskData, output_format: OutputFormatData):
|
||||
def get_printable_request(
|
||||
req: GenerateImageRequest,
|
||||
task_data: RenderTaskData,
|
||||
models_data: ModelsData,
|
||||
output_format: OutputFormatData,
|
||||
save_data: SaveToDiskData,
|
||||
):
|
||||
req_metadata = req.dict()
|
||||
task_data_metadata = task_data.dict()
|
||||
task_data_metadata.update(output_format.dict())
|
||||
task_data_metadata.update(save_data.dict())
|
||||
|
||||
app_config = app.getConfig()
|
||||
using_diffusers = app_config.get("test_diffusers", True)
|
||||
using_diffusers = app_config.get("use_v3_engine", True)
|
||||
|
||||
# Save the metadata in the order defined in TASK_TEXT_MAPPING
|
||||
metadata = {}
|
||||
@ -230,25 +256,11 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData, output
|
||||
elif key in task_data_metadata:
|
||||
metadata[key] = task_data_metadata[key]
|
||||
|
||||
if key == "use_embeddings_model" and using_diffusers:
|
||||
embeddings_extensions = {".pt", ".bin", ".safetensors"}
|
||||
if key == "use_embeddings_model" and task_data_metadata[key] and using_diffusers:
|
||||
embeddings_used = models_data.model_paths["embeddings"]
|
||||
embeddings_used = embeddings_used if isinstance(embeddings_used, list) else [embeddings_used]
|
||||
|
||||
def scan_directory(directory_path: str):
|
||||
used_embeddings = []
|
||||
for entry in os.scandir(directory_path):
|
||||
if entry.is_file():
|
||||
# Check if the filename has the right extension
|
||||
if not any(map(lambda ext: entry.name.endswith(ext), embeddings_extensions)):
|
||||
continue
|
||||
embedding_name_regex = regex.compile(r"(^|[\s,])" + regex.escape(get_embedding_token(entry.name)) + r"([+-]*$|[\s,]|[+-]+[\s,])")
|
||||
if embedding_name_regex.search(req.prompt) or embedding_name_regex.search(req.negative_prompt):
|
||||
used_embeddings.append(entry.path)
|
||||
elif entry.is_dir():
|
||||
used_embeddings.extend(scan_directory(entry.path))
|
||||
return used_embeddings
|
||||
|
||||
used_embeddings = scan_directory(os.path.join(app.MODELS_DIR, "embeddings"))
|
||||
metadata["use_embeddings_model"] = used_embeddings if len(used_embeddings) > 0 else None
|
||||
metadata["use_embeddings_model"] = embeddings_used if len(embeddings_used) > 0 else None
|
||||
|
||||
# Clean up the metadata
|
||||
if req.init_image is None and "prompt_strength" in metadata:
|
||||
@ -269,7 +281,17 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData, output
|
||||
del metadata[key]
|
||||
else:
|
||||
for key in (
|
||||
x for x in ["use_lora_model", "lora_alpha", "clip_skip", "tiling", "latent_upscaler_steps", "use_controlnet_model", "control_filter_to_apply"] if x in metadata
|
||||
x
|
||||
for x in [
|
||||
"use_lora_model",
|
||||
"lora_alpha",
|
||||
"clip_skip",
|
||||
"tiling",
|
||||
"latent_upscaler_steps",
|
||||
"use_controlnet_model",
|
||||
"control_filter_to_apply",
|
||||
]
|
||||
if x in metadata
|
||||
):
|
||||
del metadata[key]
|
||||
|
||||
@ -279,7 +301,7 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData, output
|
||||
def make_filename_callback(
|
||||
filename_format: str,
|
||||
req: GenerateImageRequest,
|
||||
task_data: TaskData,
|
||||
task_data: RenderTaskData,
|
||||
folder_img_number: int,
|
||||
suffix=None,
|
||||
now=None,
|
||||
@ -296,7 +318,7 @@ def make_filename_callback(
|
||||
return make_filename
|
||||
|
||||
|
||||
def _calculate_img_number(save_dir_path: str, task_data: TaskData):
|
||||
def _calculate_img_number(save_dir_path: str, task_data: RenderTaskData):
|
||||
def get_highest_img_number(accumulator: int, file: os.DirEntry) -> int:
|
||||
if not file.is_file:
|
||||
return accumulator
|
||||
@ -340,5 +362,5 @@ def _calculate_img_number(save_dir_path: str, task_data: TaskData):
|
||||
_calculate_img_number.session_img_numbers = {}
|
||||
|
||||
|
||||
def calculate_img_number(save_dir_path: str, task_data: TaskData):
|
||||
def calculate_img_number(save_dir_path: str, task_data: RenderTaskData):
|
||||
return ImageNumber(lambda: _calculate_img_number(save_dir_path, task_data))
|
||||
|
@ -35,7 +35,7 @@
|
||||
<h1>
|
||||
<img id="logo_img" src="/media/images/icon-512x512.png" >
|
||||
Easy Diffusion
|
||||
<small><span id="version">v3.0.2</span> <span id="updateBranchLabel"></span></small>
|
||||
<small><span id="version">v3.0.7</span> <span id="updateBranchLabel"></span></small>
|
||||
</h1>
|
||||
</div>
|
||||
<div id="server-status">
|
||||
@ -155,11 +155,11 @@
|
||||
<div id="editor-settings-entries" class="collapsible-content">
|
||||
<div><table>
|
||||
<tr><b class="settings-subheader">Image Settings</b></tr>
|
||||
<tr class="pl-5"><td><label for="seed">Seed:</label></td><td><input id="seed" name="seed" size="10" value="0" onkeypress="preventNonNumericalInput(event)"> <input id="random_seed" name="random_seed" type="checkbox" checked><label for="random_seed">Random</label></td></tr>
|
||||
<tr class="pl-5"><td><label for="seed">Seed:</label></td><td><input id="seed" name="seed" size="10" value="0" onkeypress="preventNonNumericalInput(event)" inputmode="numeric"> <input id="random_seed" name="random_seed" type="checkbox" checked><label for="random_seed">Random</label></td></tr>
|
||||
<tr class="pl-5"><td><label for="num_outputs_total">Number of Images:</label></td>
|
||||
<td><input id="num_outputs_total" name="num_outputs_total" value="1" type="number" value="1" min="1" step="1" onkeypres"="preventNonNumericalInput(event)">
|
||||
<td><input id="num_outputs_total" name="num_outputs_total" value="1" type="number" value="1" min="1" step="1" onkeypres"="preventNonNumericalInput(event)" inputmode="numeric">
|
||||
<label><small>(total)</small></label>
|
||||
<input id="num_outputs_parallel" name="num_outputs_parallel" value="1" type="number" value="1" min="1" step="1" onkeypress="preventNonNumericalInput(event)">
|
||||
<input id="num_outputs_parallel" name="num_outputs_parallel" value="1" type="number" value="1" min="1" step="1" onkeypress="preventNonNumericalInput(event)" inputmode="numeric">
|
||||
<label id="num_outputs_parallel_label" for="num_outputs_parallel"><small>(in parallel)</small></label></td>
|
||||
</tr>
|
||||
<tr class="pl-5"><td><label for="stable_diffusion_model">Model:</label></td><td class="model-input">
|
||||
@ -266,7 +266,7 @@
|
||||
<option value="unipc_tu_2" class="k_diffusion-only">UniPC TU 2</option>
|
||||
<option value="unipc_tq" class="k_diffusion-only">UniPC TQ</option>
|
||||
</select>
|
||||
<a href="https://github.com/easydiffusion/easydiffusion/wiki/How-to-Use#samplers" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about samplers</span></i></a>
|
||||
<a href="https://github.com/easydiffusion/easydiffusion/wiki/Samplers" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about samplers</span></i></a>
|
||||
</td></tr>
|
||||
<tr class="pl-5"><td><label>Image Size: </label></td><td id="image-size-options">
|
||||
<select id="width" name="width" value="512">
|
||||
@ -291,7 +291,9 @@
|
||||
<option value="2048">2048</option>
|
||||
</select>
|
||||
<label id="widthLabel" for="width"><small><span>(width)</span></small></label>
|
||||
<div class="tooltip-container">
|
||||
<span id="swap-width-height" class="clickable smallButton" style="margin-left: 2px; margin-right:2px;"><i class="fa-solid fa-right-left"><span class="simple-tooltip top-left"> Swap width and height </span></i></span>
|
||||
</div>
|
||||
<select id="height" name="height" value="512">
|
||||
<option value="128">128</option>
|
||||
<option value="192">192</option>
|
||||
@ -318,9 +320,9 @@
|
||||
<span id="recent-resolutions-button" class="clickable"><i class="fa-solid fa-sliders"><span class="simple-tooltip top-left"> Advanced sizes </span></i></span>
|
||||
<div id="recent-resolutions-popup" class="displayNone">
|
||||
<small>Custom size:</small><br>
|
||||
<input id="custom-width" name="custom-width" type="number" min="128" value="512" onkeypress="preventNonNumericalInput(event)">
|
||||
<input id="custom-width" name="custom-width" type="number" min="128" value="512" onkeypress="preventNonNumericalInput(event)" inputmode="numeric">
|
||||
×
|
||||
<input id="custom-height" name="custom-height" type="number" min="128" value="512" onkeypress="preventNonNumericalInput(event)"><br>
|
||||
<input id="custom-height" name="custom-height" type="number" min="128" value="512" onkeypress="preventNonNumericalInput(event)" inputmode="numeric"><br>
|
||||
<small>Resize:</small><br>
|
||||
<input id="resize-slider" name="resize-slider" class="editor-slider" value="1" type="range" min="0.4" max="2" step="0.005" style="width:100%;"><br>
|
||||
<div id="enlarge-buttons"><button data-factor="0.5" class="tertiaryButton smallButton">×0.5</button> <button data-factor="1.2" class="tertiaryButton smallButton">×1.2</button> <button data-factor="1.5" class="tertiaryButton smallButton">×1.5</button> <button data-factor="2" class="tertiaryButton smallButton">×2</button> <button data-factor="3" class="tertiaryButton smallButton">×3</button></div>
|
||||
@ -342,9 +344,9 @@
|
||||
</div>
|
||||
<div id="small_image_warning" class="displayNone">Small image sizes can cause bad image quality</div>
|
||||
</td></tr>
|
||||
<tr class="pl-5"><td><label for="num_inference_steps">Inference Steps:</label></td><td> <input id="num_inference_steps" name="num_inference_steps" type="number" min="1" step="1" style="width: 42pt" value="25" onkeypress="preventNonNumericalInput(event)"></td></tr>
|
||||
<tr class="pl-5"><td><label for="guidance_scale_slider">Guidance Scale:</label></td><td> <input id="guidance_scale_slider" name="guidance_scale_slider" class="editor-slider" value="75" type="range" min="11" max="500"> <input id="guidance_scale" name="guidance_scale" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)"></td></tr>
|
||||
<tr id="prompt_strength_container" class="pl-5"><td><label for="prompt_strength_slider">Prompt Strength:</label></td><td> <input id="prompt_strength_slider" name="prompt_strength_slider" class="editor-slider" value="80" type="range" min="0" max="99"> <input id="prompt_strength" name="prompt_strength" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)"><br/></td></tr>
|
||||
<tr class="pl-5"><td><label for="num_inference_steps">Inference Steps:</label></td><td> <input id="num_inference_steps" name="num_inference_steps" type="number" min="1" step="1" style="width: 42pt" value="25" onkeypress="preventNonNumericalInput(event)" inputmode="numeric"></td></tr>
|
||||
<tr class="pl-5"><td><label for="guidance_scale_slider">Guidance Scale:</label></td><td> <input id="guidance_scale_slider" name="guidance_scale_slider" class="editor-slider" value="75" type="range" min="11" max="500"> <input id="guidance_scale" name="guidance_scale" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)" inputmode="decimal"></td></tr>
|
||||
<tr id="prompt_strength_container" class="pl-5"><td><label for="prompt_strength_slider">Prompt Strength:</label></td><td> <input id="prompt_strength_slider" name="prompt_strength_slider" class="editor-slider" value="80" type="range" min="0" max="99"> <input id="prompt_strength" name="prompt_strength" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)" inputmode="decimal"><br/></td></tr>
|
||||
<tr id="lora_model_container" class="pl-5">
|
||||
<td>
|
||||
<label for="lora_model">LoRA:</label>
|
||||
@ -358,7 +360,7 @@
|
||||
</td></tr>
|
||||
<tr id="hypernetwork_strength_container" class="pl-5">
|
||||
<td><label for="hypernetwork_strength_slider">Hypernetwork Strength:</label></td>
|
||||
<td> <input id="hypernetwork_strength_slider" name="hypernetwork_strength_slider" class="editor-slider" value="100" type="range" min="0" max="100"> <input id="hypernetwork_strength" name="hypernetwork_strength" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)"><br/></td>
|
||||
<td> <input id="hypernetwork_strength_slider" name="hypernetwork_strength_slider" class="editor-slider" value="100" type="range" min="0" max="100"> <input id="hypernetwork_strength" name="hypernetwork_strength" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)" inputmode="decimal"><br/></td>
|
||||
</tr>
|
||||
<tr id="tiling_container" class="pl-5">
|
||||
<td><label for="tiling">Seamless Tiling:</label></td>
|
||||
@ -383,8 +385,15 @@
|
||||
</span>
|
||||
</td></tr>
|
||||
<tr class="pl-5" id="output_quality_row"><td><label for="output_quality">Image Quality:</label></td><td>
|
||||
<input id="output_quality_slider" name="output_quality" class="editor-slider" value="75" type="range" min="10" max="95"> <input id="output_quality" name="output_quality" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)">
|
||||
<input id="output_quality_slider" name="output_quality" class="editor-slider" value="75" type="range" min="10" max="95"> <input id="output_quality" name="output_quality" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)" inputmode="numeric">
|
||||
</td></tr>
|
||||
<tr class="pl-5">
|
||||
<td><label for="tiling">Enable VAE Tiling:</label></td>
|
||||
<td class="diffusers-restart-needed">
|
||||
<input id="enable_vae_tiling" name="enable_vae_tiling" type="checkbox" checked>
|
||||
<label><small>Optimizes memory for larger images</small></label>
|
||||
</td>
|
||||
</tr>
|
||||
</table></div>
|
||||
|
||||
<div><ul>
|
||||
@ -393,7 +402,7 @@
|
||||
<li class="pl-5" id="use_face_correction_container">
|
||||
<input id="use_face_correction" name="use_face_correction" type="checkbox"> <label for="use_face_correction">Fix incorrect faces and eyes</label> <div style="display:inline-block;"><input id="gfpgan_model" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" /></div>
|
||||
<table id="codeformer_settings" class="displayNone sub-settings">
|
||||
<tr class="pl-5"><td><label for="codeformer_fidelity_slider">Strength:</label></td><td><input id="codeformer_fidelity_slider" name="codeformer_fidelity_slider" class="editor-slider" value="5" type="range" min="0" max="10"> <input id="codeformer_fidelity" name="codeformer_fidelity" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)"></td></tr>
|
||||
<tr class="pl-5"><td><label for="codeformer_fidelity_slider">Strength:</label></td><td><input id="codeformer_fidelity_slider" name="codeformer_fidelity_slider" class="editor-slider" value="5" type="range" min="0" max="10"> <input id="codeformer_fidelity" name="codeformer_fidelity" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)" inputmode="decimal"></td></tr>
|
||||
<tr class="pl-5"><td><label for="codeformer_upscale_faces">Upscale Faces:</label></td><td><input id="codeformer_upscale_faces" name="codeformer_upscale_faces" type="checkbox" checked> <label><small>(improves the resolution of faces)</small></label></td></tr>
|
||||
</table>
|
||||
</li>
|
||||
@ -410,7 +419,7 @@
|
||||
<option value="latent_upscaler">Latent Upscaler 2x</option>
|
||||
</select>
|
||||
<table id="latent_upscaler_settings" class="displayNone sub-settings">
|
||||
<tr class="pl-5"><td><label for="latent_upscaler_steps_slider">Upscaling Steps:</label></td><td><input id="latent_upscaler_steps_slider" name="latent_upscaler_steps_slider" class="editor-slider" value="10" type="range" min="1" max="50"> <input id="latent_upscaler_steps" name="latent_upscaler_steps" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)"></td></tr>
|
||||
<tr class="pl-5"><td><label for="latent_upscaler_steps_slider">Upscaling Steps:</label></td><td><input id="latent_upscaler_steps_slider" name="latent_upscaler_steps_slider" class="editor-slider" value="10" type="range" min="1" max="50"> <input id="latent_upscaler_steps" name="latent_upscaler_steps" size="4" pattern="^[0-9\.]+$" onkeypress="preventNonNumericalInput(event)" inputmode="numeric"></td></tr>
|
||||
</table>
|
||||
</li>
|
||||
<li class="pl-5"><input id="show_only_filtered_image" name="show_only_filtered_image" type="checkbox" checked> <label for="show_only_filtered_image">Show only the corrected/upscaled image</label></li>
|
||||
@ -455,14 +464,14 @@
|
||||
<div class="dropdown-content">
|
||||
<div class="dropdown-item">
|
||||
<input id="thumbnail_size" name="thumbnail_size" class="editor-slider" type="range" value="70" min="5" max="200" oninput="sliderUpdate(event)">
|
||||
<input id="thumbnail_size-input" name="thumbnail_size-input" size="3" value="70" pattern="^[0-9.]+$" onkeypress="preventNonNumericalInput(event)" oninput="sliderUpdate(event)"> %
|
||||
<input id="thumbnail_size-input" name="thumbnail_size-input" size="3" value="70" pattern="^[0-9.]+$" onkeypress="preventNonNumericalInput(event)" oninput="sliderUpdate(event)" inputmode="numeric"> %
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix" style="clear: both;"></div>
|
||||
</div>
|
||||
<div id="supportBanner" class="displayNone">
|
||||
If you found this project useful and want to help keep it alive, please consider <a href="https://ko-fi.com/easydiffusion" target="_blank">buying me a coffee</a> or <a href="https://www.patreon.com/EasyDiffusion" target="_blank">supporting me on Patreon</a> to help cover the cost of development and maintenance! Or even better, <a href="https://cmdr2.itch.io/easydiffusion" target="_blank">purchasing it at the full price</a>. Thank you for your support!
|
||||
If you found this project useful and want to help keep it alive, please consider <a href="https://ko-fi.com/easydiffusion" target="_blank">buying me a coffee</a> to help cover the cost of development and maintenance! Thanks for your support!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -508,29 +517,45 @@
|
||||
<div class="float-container">
|
||||
<div class="float-child">
|
||||
<h1>Help</h1>
|
||||
<ul id="help-links">
|
||||
<li><span class="help-section">Using the software</span>
|
||||
<div id="help-links">
|
||||
<h4><span class="help-section"><b>Basics</b></span></h4>
|
||||
<ul>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/How-To-Use" target="_blank"><i class="fa-solid fa-book fa-fw"></i> How to use</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/UI-Overview" target="_blank"><i class="fa-solid fa-list fa-fw"></i> UI Overview</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Writing-Prompts" target="_blank"><i class="fa-solid fa-pen-to-square fa-fw"></i> Writing prompts</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Inpainting" target="_blank"><i class="fa-solid fa-paintbrush fa-fw"></i> Inpainting</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Run-on-Multiple-GPUs" target="_blank"><i class="fa-solid fa-paintbrush fa-fw"></i> Run on Multiple GPUs</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/How-To-Use" target="_blank">How to use</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Writing-Prompts" target="_blank">Writing prompts</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Image-Modifiers" target="_blank">Image Modifiers</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Inpainting" target="_blank">Inpainting</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Samplers" target="_blank">Samplers</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/UI-Overview" target="_blank">Summary of every UI option</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting" target="_blank">Common error messages (and solutions)</a></li>
|
||||
</ul>
|
||||
|
||||
<li><span class="help-section">Installation</span>
|
||||
<h4><span class="help-section"><b>Intermediate</b></span></h4>
|
||||
<ul>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting" target="_blank"><i class="fa-solid fa-circle-question fa-fw"></i> Troubleshooting</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Custom-Models" target="_blank">Custom Models</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Prompt-Syntax" target="_blank">Prompt Syntax (weights, emphasis etc)</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/UI-Plugins" target="_blank">UI Plugins</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Embeddings" target="_blank">Embeddings</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/LoRA" target="_blank">LoRA</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/SDXL" target="_blank">SDXL</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/ControlNet" target="_blank">ControlNet</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Seamless-Tiling" target="_blank">Seamless Tiling</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/xFormers" target="_blank">xFormers</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/The-beta-channel" target="_blank">The beta channel</a></li>
|
||||
</ul>
|
||||
|
||||
<li><span class="help-section">Downloadable Content</span>
|
||||
<h4><span class="help-section"><b>Advanced topics</b></span></h4>
|
||||
<ul>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Custom-Models" target="_blank"><i class="fa-solid fa-images fa-fw"></i> Custom Models</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/UI-Plugins" target="_blank"><i class="fa-solid fa-puzzle-piece fa-fw"></i> UI Plugins</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/VAE-Variational-Auto-Encoder" target="_blank"><i class="fa-solid fa-hand-sparkles fa-fw"></i> VAE Variational Auto Encoder</a>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Run-on-Multiple-GPUs" target="_blank">Run on Multiple GPUs</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Model-Merging" target="_blank">Model Merging</a></li>
|
||||
<li> <a href="https://github.com/easydiffusion/easydiffusion/wiki/Custom-Modifiers" target="_blank">Custom Modifiers</a></li>
|
||||
</ul>
|
||||
|
||||
<h4><span class="help-section"><b>Misc</b></span></h4>
|
||||
<ul>
|
||||
<li> <a href="https://theally.notion.site/The-Definitive-Stable-Diffusion-Glossary-1d1e6d15059c41e6a6b4306b4ecd9df9" target="_blank">Glossary of Stable Diffusion related terms</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="float-child">
|
||||
<h1>Community</h1>
|
||||
@ -712,7 +737,7 @@
|
||||
<span class="embeddings-action-text">Expand Categories</span>
|
||||
</button>
|
||||
<i class="fa-solid fa-magnifying-glass"></i>
|
||||
<input id="embeddings-search-box" type="text" spellcheck="false" autocomplete="off" placeholder="Search...">
|
||||
<input id="embeddings-search-box" type="text" spellcheck="false" autocomplete="off" placeholder="Search..." inputmode="search">
|
||||
<label for="embedding-card-size-selector"><small>Thumbnail Size:</small></label>
|
||||
<select id="embedding-card-size-selector" name="embedding-card-size-selector">
|
||||
<option value="-2">0</option>
|
||||
@ -798,6 +823,7 @@
|
||||
<p>This license of this software forbids you from sharing any content that violates any laws, produce any harm to a person, disseminate any personal information that would be meant for harm, <br/>spread misinformation and target vulnerable groups. For the full list of restrictions please read <a href="https://github.com/easydiffusion/easydiffusion/blob/main/LICENSE" target="_blank">the license</a>.</p>
|
||||
<p>By using this software, you consent to the terms and conditions of the license.</p>
|
||||
</div>
|
||||
<input id="test_diffusers" type="checkbox" style="display: none" checked />
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -609,11 +609,18 @@ div.img-preview img {
|
||||
margin: auto;
|
||||
padding: 0px;
|
||||
}
|
||||
#help-links ul {
|
||||
list-style-type: disc;
|
||||
padding-left: 12pt;
|
||||
}
|
||||
#help-links li {
|
||||
padding-bottom: 12pt;
|
||||
padding-bottom: 6pt;
|
||||
display: block;
|
||||
font-size: 10pt;
|
||||
}
|
||||
#help-links ul li {
|
||||
display: list-item;
|
||||
}
|
||||
#help-links li .fa-fw {
|
||||
padding-right: 2pt;
|
||||
}
|
||||
@ -1207,6 +1214,12 @@ input::file-selector-button {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-container {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.simple-tooltip.right {
|
||||
right: 0px;
|
||||
top: 50%;
|
||||
|
@ -56,6 +56,7 @@ const SETTINGS_IDS_LIST = [
|
||||
"extract_lora_from_prompt",
|
||||
"embedding-card-size-selector",
|
||||
"lora_model",
|
||||
"enable_vae_tiling",
|
||||
]
|
||||
|
||||
const IGNORE_BY_DEFAULT = ["prompt"]
|
||||
|
@ -268,7 +268,11 @@ const TASK_MAPPING = {
|
||||
tiling: {
|
||||
name: "Tiling",
|
||||
setUI: (val) => {
|
||||
if (val === null || val === "None") {
|
||||
tilingField.value = "none"
|
||||
} else {
|
||||
tilingField.value = val
|
||||
}
|
||||
},
|
||||
readUI: () => tilingField.value,
|
||||
parse: (val) => val,
|
||||
@ -583,6 +587,7 @@ const TASK_TEXT_MAPPING = {
|
||||
lora_alpha: "LoRA Strength",
|
||||
use_controlnet_model: "ControlNet model",
|
||||
control_filter_to_apply: "ControlNet Filter",
|
||||
tiling: "Seamless Tiling",
|
||||
}
|
||||
function parseTaskFromText(str) {
|
||||
const taskReqBody = {}
|
||||
|
@ -22,7 +22,8 @@ const taskConfigSetup = {
|
||||
},
|
||||
tiling: {
|
||||
label: "Tiling",
|
||||
visible: ({ reqBody }) => reqBody?.tiling != "none",
|
||||
visible: ({ reqBody }) =>
|
||||
reqBody?.tiling != "none" && reqBody?.tiling !== null && reqBody?.tiling !== undefined,
|
||||
value: ({ reqBody }) => reqBody?.tiling,
|
||||
},
|
||||
use_vae_model: {
|
||||
@ -128,6 +129,7 @@ let hypernetworkStrengthField = document.querySelector("#hypernetwork_strength")
|
||||
let outputFormatField = document.querySelector("#output_format")
|
||||
let outputLosslessField = document.querySelector("#output_lossless")
|
||||
let outputLosslessContainer = document.querySelector("#output_lossless_container")
|
||||
let enableVAETilingField = document.querySelector("#enable_vae_tiling")
|
||||
let blockNSFWField = document.querySelector("#block_nsfw")
|
||||
let showOnlyFilteredImageField = document.querySelector("#show_only_filtered_image")
|
||||
let updateBranchLabel = document.querySelector("#updateBranchLabel")
|
||||
@ -513,7 +515,7 @@ function showImages(reqBody, res, outputContainer, livePreview) {
|
||||
{
|
||||
text: "Use as Thumbnail",
|
||||
on_click: onUseAsThumbnailClick,
|
||||
filter: (req, img) => "use_embeddings_model" in req,
|
||||
filter: (req, img) => "use_embeddings_model" in req || "use_lora_model" in req
|
||||
},
|
||||
]
|
||||
|
||||
@ -680,7 +682,7 @@ function getAllModelNames(type) {
|
||||
|
||||
// gets a flattened list of all models of a certain type. e.g. "path/subpath/modelname"
|
||||
// use the filter to search for all models having a certain name.
|
||||
function getAllModelPathes(type,filter="") {
|
||||
function getAllModelPathes(type, filter = "") {
|
||||
function f(tree, prefix) {
|
||||
if (tree == undefined) {
|
||||
return []
|
||||
@ -690,7 +692,7 @@ function getAllModelPathes(type,filter="") {
|
||||
if (typeof e == "object") {
|
||||
result = result.concat(f(e[1], prefix + e[0] + "/"))
|
||||
} else {
|
||||
if (filter=="" || e==filter) {
|
||||
if (filter == "" || e == filter) {
|
||||
result.push(prefix + e)
|
||||
}
|
||||
}
|
||||
@ -700,7 +702,6 @@ function getAllModelPathes(type,filter="") {
|
||||
return f(modelsOptions[type], "")
|
||||
}
|
||||
|
||||
|
||||
function onUseAsThumbnailClick(req, img) {
|
||||
let scale = 1
|
||||
let targetWidth = img.naturalWidth
|
||||
@ -748,16 +749,14 @@ function onUseAsThumbnailClick(req, img) {
|
||||
onUseAsThumbnailClick.croppr.setImage(img.src)
|
||||
}
|
||||
|
||||
useAsThumbSelect.innerHTML=""
|
||||
|
||||
if ("use_embeddings_model" in req) {
|
||||
let embeddings = req.use_embeddings_model.map((e) => e.split("/").pop())
|
||||
let LORA = []
|
||||
|
||||
if ("use_lora_model" in req) {
|
||||
LORA = req.use_lora_model
|
||||
}
|
||||
|
||||
let optgroup = document.createElement("optgroup")
|
||||
optgroup.label = "Embeddings"
|
||||
optgroup.replaceChildren(
|
||||
let embOptions = document.createElement("optgroup")
|
||||
embOptions.label = "Embeddings"
|
||||
embOptions.replaceChildren(
|
||||
...embeddings.map((e) => {
|
||||
let option = document.createElement("option")
|
||||
option.innerText = e
|
||||
@ -765,8 +764,30 @@ function onUseAsThumbnailClick(req, img) {
|
||||
return option
|
||||
})
|
||||
)
|
||||
useAsThumbSelect.appendChild(embOptions)
|
||||
}
|
||||
|
||||
|
||||
if ("use_lora_model" in req) {
|
||||
let LORA = req.use_lora_model
|
||||
if (typeof LORA == "string") {
|
||||
LORA = [LORA]
|
||||
}
|
||||
LORA = LORA.map((e) => e.split("/").pop())
|
||||
|
||||
let loraOptions = document.createElement("optgroup")
|
||||
loraOptions.label = "LORA"
|
||||
loraOptions.replaceChildren(
|
||||
...LORA.map((e) => {
|
||||
let option = document.createElement("option")
|
||||
option.innerText = e
|
||||
option.dataset["type"] = "lora"
|
||||
return option
|
||||
})
|
||||
)
|
||||
useAsThumbSelect.appendChild(loraOptions)
|
||||
}
|
||||
|
||||
useAsThumbSelect.replaceChildren(optgroup)
|
||||
useAsThumbDialog.showModal()
|
||||
onUseAsThumbnailClick.scale = scale
|
||||
}
|
||||
@ -782,6 +803,50 @@ useAsThumbCancelBtn.addEventListener("click", () => {
|
||||
useAsThumbDialog.close()
|
||||
})
|
||||
|
||||
const Bucket = {
|
||||
upload(path, blob) {
|
||||
const formData = new FormData()
|
||||
formData.append("file", blob)
|
||||
return fetch(`bucket/${path}`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
})
|
||||
},
|
||||
|
||||
getImageAsDataURL(path) {
|
||||
return fetch(`bucket/${path}`)
|
||||
.then((response) => {
|
||||
if (response.status == 200) {
|
||||
return response.blob()
|
||||
} else {
|
||||
throw new Error("Bucket error")
|
||||
}
|
||||
})
|
||||
.then((blob) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => resolve(reader.result)
|
||||
reader.onerror = reject
|
||||
reader.readAsDataURL(blob)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
getList(path) {
|
||||
return fetch(`bucket/${path}`)
|
||||
.then((response) => (response.status == 200 ? response.json() : []))
|
||||
},
|
||||
|
||||
store(path, data) {
|
||||
return Bucket.upload(`${path}.json`, JSON.stringify(data))
|
||||
},
|
||||
|
||||
retrieve(path) {
|
||||
return fetch(`bucket/${path}.json`)
|
||||
.then((response) => (response.status == 200 ? response.json() : null))
|
||||
},
|
||||
}
|
||||
|
||||
useAsThumbSaveBtn.addEventListener("click", (e) => {
|
||||
let scale = 1 / onUseAsThumbnailClick.scale
|
||||
let crop = onUseAsThumbnailClick.croppr.getValue()
|
||||
@ -793,22 +858,18 @@ useAsThumbSaveBtn.addEventListener("click", (e) => {
|
||||
.then((thumb) => fetch(thumb))
|
||||
.then((response) => response.blob())
|
||||
.then(async function(blob) {
|
||||
const formData = new FormData()
|
||||
formData.append("file", blob)
|
||||
let options = useAsThumbSelect.selectedOptions
|
||||
let promises = []
|
||||
for (let embedding of options) {
|
||||
promises.push(
|
||||
fetch(`bucket/${profileName}/${embedding.dataset["type"]}/${embedding.value}.png`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
})
|
||||
Bucket.upload(`${profileName}/${embedding.dataset["type"]}/${embedding.value}.png`, blob)
|
||||
)
|
||||
}
|
||||
return Promise.all(promises)
|
||||
})
|
||||
.then(() => {
|
||||
useAsThumbDialog.close()
|
||||
document.dispatchEvent(new CustomEvent("saveThumb", { detail: useAsThumbSelect.selectedOptions }))
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
@ -852,6 +913,10 @@ function applyInlineFilter(filterName, path, filterParams, img, statusText, tool
|
||||
}
|
||||
filterReq.model_paths[filterName] = path
|
||||
|
||||
if (saveToDiskField.checked && diskPathField.value.trim() !== "") {
|
||||
filterReq.save_to_disk_path = diskPathField.value.trim()
|
||||
}
|
||||
|
||||
tools.spinnerStatus.innerText = statusText
|
||||
tools.spinner.classList.remove("displayNone")
|
||||
|
||||
@ -1237,7 +1302,6 @@ function getCurrentUserRequest() {
|
||||
//render_device: undefined, // Set device affinity. Prefer this device, but wont activate.
|
||||
use_stable_diffusion_model: stableDiffusionModelField.value,
|
||||
clip_skip: clipSkipField.checked,
|
||||
tiling: tilingField.value,
|
||||
use_vae_model: vaeModelField.value,
|
||||
stream_progress_updates: true,
|
||||
stream_image_progress: numOutputsTotal > 50 ? false : streamImageProgressField.checked,
|
||||
@ -1302,6 +1366,11 @@ function getCurrentUserRequest() {
|
||||
newTask.reqBody.use_lora_model = modelNames
|
||||
newTask.reqBody.lora_alpha = modelStrengths
|
||||
}
|
||||
|
||||
if (tilingField.value !== "none") {
|
||||
newTask.reqBody.tiling = tilingField.value
|
||||
}
|
||||
newTask.reqBody.enable_vae_tiling = enableVAETilingField.checked
|
||||
}
|
||||
if (testDiffusers.checked && document.getElementById("toggle-tensorrt-install").innerHTML == "Uninstall") {
|
||||
// TRT is installed
|
||||
@ -1338,7 +1407,7 @@ function setEmbeddings(task) {
|
||||
let prompt = task.reqBody.prompt
|
||||
let negativePrompt = task.reqBody.negative_prompt
|
||||
let overallPrompt = (prompt + " " + negativePrompt).toLowerCase()
|
||||
overallPrompt = overallPrompt.replaceAll(/[^a-z0-9\.]/g, " ") // only allow alpha-numeric and dots
|
||||
overallPrompt = overallPrompt.replaceAll(/[^a-z0-9\-_\.]/g, " ") // only allow alpha-numeric, dots and hyphens
|
||||
overallPrompt = overallPrompt.split(" ")
|
||||
|
||||
let embeddingsTree = modelsOptions["embeddings"]
|
||||
@ -1562,7 +1631,7 @@ function updateInitialText() {
|
||||
|
||||
const countBeforeBanner = localStorage.getItem("countBeforeBanner") || 1
|
||||
if (countBeforeBanner <= 0) {
|
||||
// supportBanner.classList.remove("displayNone")
|
||||
supportBanner.classList.remove("displayNone")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2355,20 +2424,10 @@ function loadThumbnailImageFromFile() {
|
||||
}
|
||||
|
||||
function updateEmbeddingsList(filter = "") {
|
||||
function html(model, iconlist = [], prefix = "", filter = "") {
|
||||
function html(model, iconMap = {}, prefix = "", filter = "") {
|
||||
filter = filter.toLowerCase()
|
||||
let toplevel = document.createElement("div")
|
||||
let folders = document.createElement("div")
|
||||
let embIcon = Object.assign(
|
||||
{},
|
||||
...iconlist.map((x) => ({
|
||||
[x
|
||||
.toLowerCase()
|
||||
.split(".")
|
||||
.slice(0, -1)
|
||||
.join(".")]: x,
|
||||
}))
|
||||
)
|
||||
|
||||
let profileName = profileNameField.value
|
||||
model?.forEach((m) => {
|
||||
@ -2376,13 +2435,9 @@ function updateEmbeddingsList(filter = "") {
|
||||
let token = m.toLowerCase()
|
||||
if (token.search(filter) != -1) {
|
||||
let button
|
||||
// if (iconlist.length==0) {
|
||||
// button = document.createElement("button")
|
||||
// button.innerText = m
|
||||
// } else {
|
||||
let img = "/media/images/noimg.png"
|
||||
if (token in embIcon) {
|
||||
img = `/bucket/${profileName}/embeddings/${embIcon[token]}`
|
||||
if (token in iconMap) {
|
||||
img = `/bucket/${profileName}/${iconMap[token]}`
|
||||
}
|
||||
button = createModifierCard(m, [img, img], true)
|
||||
// }
|
||||
@ -2391,7 +2446,7 @@ function updateEmbeddingsList(filter = "") {
|
||||
toplevel.appendChild(button)
|
||||
}
|
||||
} else {
|
||||
let subdir = html(m[1], iconlist, prefix + m[0] + "/", filter)
|
||||
let subdir = html(m[1], iconMap, prefix + m[0] + "/", filter)
|
||||
if (typeof subdir == "object") {
|
||||
let div1 = document.createElement("div")
|
||||
let div2 = document.createElement("div")
|
||||
@ -2450,11 +2505,44 @@ function updateEmbeddingsList(filter = "") {
|
||||
</div>
|
||||
`
|
||||
|
||||
let loraTokens = []
|
||||
let profileName = profileNameField.value
|
||||
fetch(`/bucket/${profileName}/embeddings/`)
|
||||
.then((response) => (response.status == 200 ? response.json() : []))
|
||||
.then(async function(iconlist) {
|
||||
embeddingsList.replaceChildren(html(modelsOptions.embeddings, iconlist, "", filter))
|
||||
let iconMap = {}
|
||||
|
||||
Bucket.getList(`${profileName}/embeddings/`)
|
||||
.then((icons) => {
|
||||
iconMap = Object.assign(
|
||||
{},
|
||||
...icons.map((x) => ({
|
||||
[x
|
||||
.toLowerCase()
|
||||
.split(".")
|
||||
.slice(0, -1)
|
||||
.join(".")]: `embeddings/${x}`,
|
||||
}))
|
||||
)
|
||||
|
||||
return Bucket.getList(`${profileName}/lora/`)
|
||||
})
|
||||
.then(async function (icons) {
|
||||
for (let lora of loraModelField.value.modelNames) {
|
||||
let keywords = await getLoraKeywords(lora)
|
||||
loraTokens = loraTokens.concat(keywords)
|
||||
let loraname = lora.split("/").pop()
|
||||
|
||||
if (icons.includes(`${loraname}.png`)) {
|
||||
keywords.forEach((kw) => {
|
||||
iconMap[kw.toLowerCase()] = `lora/${loraname}.png`
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let tokenList = [...modelsOptions.embeddings]
|
||||
if (loraTokens.length != 0) {
|
||||
tokenList.unshift(['LORA Keywords', loraTokens])
|
||||
}
|
||||
embeddingsList.replaceChildren(html(tokenList, iconMap, "", filter))
|
||||
createCollapsibles(embeddingsList)
|
||||
if (filter != "") {
|
||||
embeddingsExpandAll()
|
||||
|
@ -97,6 +97,17 @@ var PARAMETERS = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "models_dir",
|
||||
type: ParameterType.custom,
|
||||
icon: "fa-folder-tree",
|
||||
label: "Models Folder",
|
||||
note: "Path to the 'models' folder. Please save and refresh the page after changing this.",
|
||||
saveInAppConfig: true,
|
||||
render: (parameter) => {
|
||||
return `<input id="${parameter.id}" name="${parameter.id}" size="30">`
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "block_nsfw",
|
||||
type: ParameterType.checkbox,
|
||||
@ -238,7 +249,7 @@ var PARAMETERS = [
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
id: "test_diffusers",
|
||||
id: "use_v3_engine",
|
||||
type: ParameterType.checkbox,
|
||||
label: "Use the new v3 engine (diffusers)",
|
||||
note:
|
||||
@ -420,8 +431,9 @@ let listenPortField = document.querySelector("#listen_port")
|
||||
let useBetaChannelField = document.querySelector("#use_beta_channel")
|
||||
let uiOpenBrowserOnStartField = document.querySelector("#ui_open_browser_on_start")
|
||||
let confirmDangerousActionsField = document.querySelector("#confirm_dangerous_actions")
|
||||
let testDiffusers = document.querySelector("#test_diffusers")
|
||||
let testDiffusers = document.querySelector("#use_v3_engine")
|
||||
let profileNameField = document.querySelector("#profileName")
|
||||
let modelsDirField = document.querySelector("#models_dir")
|
||||
|
||||
let saveSettingsBtn = document.querySelector("#save-system-settings-btn")
|
||||
|
||||
@ -463,15 +475,17 @@ async function getAppConfig() {
|
||||
if (config.net && config.net.listen_port !== undefined) {
|
||||
listenPortField.value = config.net.listen_port
|
||||
}
|
||||
modelsDirField.value = config.models_dir
|
||||
|
||||
let testDiffusersEnabled = true
|
||||
if (config.test_diffusers === false) {
|
||||
if (config.use_v3_engine === false) {
|
||||
testDiffusersEnabled = false
|
||||
}
|
||||
testDiffusers.checked = testDiffusersEnabled
|
||||
document.querySelector("#test_diffusers").checked = testDiffusers.checked // don't break plugins
|
||||
|
||||
if (config.config_on_startup) {
|
||||
if (config.config_on_startup?.test_diffusers) {
|
||||
if (config.config_on_startup?.use_v3_engine) {
|
||||
document.body.classList.add("diffusers-enabled-on-startup")
|
||||
document.body.classList.remove("diffusers-disabled-on-startup")
|
||||
} else {
|
||||
@ -511,6 +525,10 @@ async function getAppConfig() {
|
||||
customHeightField.step = IMAGE_STEP_SIZE
|
||||
}
|
||||
|
||||
if (config.force_save_metadata) {
|
||||
metadataOutputFormatField.value = config.force_save_metadata
|
||||
}
|
||||
|
||||
console.log("get config status response", config)
|
||||
|
||||
return config
|
||||
@ -722,10 +740,13 @@ async function getSystemInfo() {
|
||||
force = res["enforce_output_dir"]
|
||||
if (force == true) {
|
||||
saveToDiskField.checked = true
|
||||
metadataOutputFormatField.disabled = false
|
||||
metadataOutputFormatField.disabled = res["enforce_output_metadata"]
|
||||
diskPathField.disabled = true
|
||||
}
|
||||
saveToDiskField.disabled = force
|
||||
diskPathField.disabled = force
|
||||
} else {
|
||||
diskPathField.disabled = !saveToDiskField.checked
|
||||
metadataOutputFormatField.disabled = !saveToDiskField.checked
|
||||
}
|
||||
setDiskPath(res["default_output_dir"], force)
|
||||
} catch (e) {
|
||||
|
@ -1,454 +0,0 @@
|
||||
;(function() {
|
||||
"use strict"
|
||||
|
||||
///////////////////// Function section
|
||||
function smoothstep(x) {
|
||||
return x * x * (3 - 2 * x)
|
||||
}
|
||||
|
||||
function smootherstep(x) {
|
||||
return x * x * x * (x * (x * 6 - 15) + 10)
|
||||
}
|
||||
|
||||
function smootheststep(x) {
|
||||
let y = -20 * Math.pow(x, 7)
|
||||
y += 70 * Math.pow(x, 6)
|
||||
y -= 84 * Math.pow(x, 5)
|
||||
y += 35 * Math.pow(x, 4)
|
||||
return y
|
||||
}
|
||||
function getCurrentTime() {
|
||||
const now = new Date()
|
||||
let hours = now.getHours()
|
||||
let minutes = now.getMinutes()
|
||||
let seconds = now.getSeconds()
|
||||
|
||||
hours = hours < 10 ? `0${hours}` : hours
|
||||
minutes = minutes < 10 ? `0${minutes}` : minutes
|
||||
seconds = seconds < 10 ? `0${seconds}` : seconds
|
||||
|
||||
return `${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
|
||||
function addLogMessage(message) {
|
||||
const logContainer = document.getElementById("merge-log")
|
||||
logContainer.innerHTML += `<i>${getCurrentTime()}</i> ${message}<br>`
|
||||
|
||||
// Scroll to the bottom of the log
|
||||
logContainer.scrollTop = logContainer.scrollHeight
|
||||
|
||||
document.querySelector("#merge-log-container").style.display = "block"
|
||||
}
|
||||
|
||||
function addLogSeparator() {
|
||||
const logContainer = document.getElementById("merge-log")
|
||||
logContainer.innerHTML += "<hr>"
|
||||
|
||||
logContainer.scrollTop = logContainer.scrollHeight
|
||||
}
|
||||
|
||||
function drawDiagram(fn) {
|
||||
const SIZE = 300
|
||||
const canvas = document.getElementById("merge-canvas")
|
||||
canvas.height = canvas.width = SIZE
|
||||
const ctx = canvas.getContext("2d")
|
||||
|
||||
// Draw coordinate system
|
||||
ctx.scale(1, -1)
|
||||
ctx.translate(0, -canvas.height)
|
||||
ctx.lineWidth = 1
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.strokeStyle = "white"
|
||||
ctx.moveTo(0, 0)
|
||||
ctx.lineTo(0, SIZE)
|
||||
ctx.lineTo(SIZE, SIZE)
|
||||
ctx.lineTo(SIZE, 0)
|
||||
ctx.lineTo(0, 0)
|
||||
ctx.lineTo(SIZE, SIZE)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.setLineDash([1, 2])
|
||||
const n = SIZE / 10
|
||||
for (let i = n; i < SIZE; i += n) {
|
||||
ctx.moveTo(0, i)
|
||||
ctx.lineTo(SIZE, i)
|
||||
ctx.moveTo(i, 0)
|
||||
ctx.lineTo(i, SIZE)
|
||||
}
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.setLineDash([])
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = "black"
|
||||
ctx.lineWidth = 3
|
||||
// Plot function
|
||||
const numSamples = 20
|
||||
for (let i = 0; i <= numSamples; i++) {
|
||||
const x = i / numSamples
|
||||
const y = fn(x)
|
||||
|
||||
const canvasX = x * SIZE
|
||||
const canvasY = y * SIZE
|
||||
|
||||
if (i === 0) {
|
||||
ctx.moveTo(canvasX, canvasY)
|
||||
} else {
|
||||
ctx.lineTo(canvasX, canvasY)
|
||||
}
|
||||
}
|
||||
ctx.stroke()
|
||||
// Plot alpha values (yellow boxes)
|
||||
let start = parseFloat(document.querySelector("#merge-start").value)
|
||||
let step = parseFloat(document.querySelector("#merge-step").value)
|
||||
let iterations = document.querySelector("#merge-count").value >> 0
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = "yellow"
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const alpha = (start + i * step) / 100
|
||||
const x = alpha * SIZE
|
||||
const y = fn(alpha) * SIZE
|
||||
if (x <= SIZE) {
|
||||
ctx.rect(x - 3, y - 3, 6, 6)
|
||||
ctx.fill()
|
||||
} else {
|
||||
ctx.strokeStyle = "red"
|
||||
ctx.moveTo(0, 0)
|
||||
ctx.lineTo(0, SIZE)
|
||||
ctx.lineTo(SIZE, SIZE)
|
||||
ctx.lineTo(SIZE, 0)
|
||||
ctx.lineTo(0, 0)
|
||||
ctx.lineTo(SIZE, SIZE)
|
||||
ctx.stroke()
|
||||
addLogMessage("<i>Warning: maximum ratio is ≥ 100%</i>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateChart() {
|
||||
let fn = (x) => x
|
||||
switch (document.querySelector("#merge-interpolation").value) {
|
||||
case "SmoothStep":
|
||||
fn = smoothstep
|
||||
break
|
||||
case "SmootherStep":
|
||||
fn = smootherstep
|
||||
break
|
||||
case "SmoothestStep":
|
||||
fn = smootheststep
|
||||
break
|
||||
}
|
||||
drawDiagram(fn)
|
||||
}
|
||||
createTab({
|
||||
id: "merge",
|
||||
icon: "fa-code-merge",
|
||||
label: "Merge models",
|
||||
css: `
|
||||
#tab-content-merge .tab-content-inner {
|
||||
max-width: 100%;
|
||||
padding: 10pt;
|
||||
}
|
||||
.merge-container {
|
||||
margin-left: 15%;
|
||||
margin-right: 15%;
|
||||
text-align: left;
|
||||
display: inline-grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: auto auto auto;
|
||||
gap: 0px 0px;
|
||||
grid-auto-flow: row;
|
||||
grid-template-areas:
|
||||
"merge-input merge-config"
|
||||
"merge-buttons merge-buttons";
|
||||
}
|
||||
.merge-container p {
|
||||
margin-top: 3pt;
|
||||
margin-bottom: 3pt;
|
||||
}
|
||||
.merge-config .tab-content {
|
||||
background: var(--background-color1);
|
||||
border-radius: 3pt;
|
||||
}
|
||||
.merge-config .tab-content-inner {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.merge-input {
|
||||
grid-area: merge-input;
|
||||
padding-left:1em;
|
||||
}
|
||||
.merge-config {
|
||||
grid-area: merge-config;
|
||||
padding:1em;
|
||||
}
|
||||
.merge-config input {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.merge-config select {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.merge-buttons {
|
||||
grid-area: merge-buttons;
|
||||
padding:1em;
|
||||
text-align: center;
|
||||
}
|
||||
#merge-button {
|
||||
padding: 8px;
|
||||
width:20em;
|
||||
}
|
||||
div#merge-log {
|
||||
height:150px;
|
||||
overflow-x:hidden;
|
||||
overflow-y:scroll;
|
||||
background:var(--background-color1);
|
||||
border-radius: 3pt;
|
||||
}
|
||||
div#merge-log i {
|
||||
color: hsl(var(--accent-hue), 100%, calc(2*var(--accent-lightness)));
|
||||
font-family: monospace;
|
||||
}
|
||||
.disabled {
|
||||
background: var(--background-color4);
|
||||
color: var(--text-color);
|
||||
}
|
||||
#merge-type-tabs {
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
#merge-log-container {
|
||||
display: none;
|
||||
}
|
||||
.merge-container #merge-warning {
|
||||
color: rgb(153, 153, 153);
|
||||
}`,
|
||||
content: `
|
||||
<div class="merge-container panel-box">
|
||||
<div class="merge-input">
|
||||
<p><label for="#mergeModelA">Select Model A:</label></p>
|
||||
<input id="mergeModelA" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
|
||||
<p><label for="#mergeModelB">Select Model B:</label></p>
|
||||
<input id="mergeModelB" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
|
||||
<br/><br/>
|
||||
<p id="merge-warning"><small><b>Important:</b> Please merge models of similar type.<br/>For e.g. <code>SD 1.4</code> models with only <code>SD 1.4/1.5</code> models,<br/><code>SD 2.0</code> with <code>SD 2.0</code>-type, and <code>SD 2.1</code> with <code>SD 2.1</code>-type models.</small></p>
|
||||
<br/>
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="#merge-filename">Output file name:</label></td>
|
||||
<td><input id="merge-filename" size=24> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Base name of the output file.<br>Mix ratio and file suffix will be appended to this.</span></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="#merge-fp">Output precision:</label></td>
|
||||
<td><select id="merge-fp">
|
||||
<option value="fp16">fp16 (smaller file size)</option>
|
||||
<option value="fp32">fp32 (larger file size)</option>
|
||||
</select>
|
||||
<i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Image generation uses fp16, so it's a good choice.<br>Use fp32 if you want to use the result models for more mixes</span></i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="#merge-format">Output file format:</label></td>
|
||||
<td><select id="merge-format">
|
||||
<option value="safetensors">Safetensors (recommended)</option>
|
||||
<option value="ckpt">CKPT/Pickle (legacy format)</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<div id="merge-log-container">
|
||||
<p><label for="#merge-log">Log messages:</label></p>
|
||||
<div id="merge-log"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="merge-config">
|
||||
<div class="tab-container">
|
||||
<span id="tab-merge-opts-single" class="tab active">
|
||||
<span>Make a single file</small></span>
|
||||
</span>
|
||||
<span id="tab-merge-opts-batch" class="tab">
|
||||
<span>Make multiple variations</small></span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div id="tab-content-merge-opts-single" class="tab-content active">
|
||||
<div class="tab-content-inner">
|
||||
<small>Saves a single merged model file, at the specified merge ratio.</small><br/><br/>
|
||||
<label for="#single-merge-ratio-slider">Merge ratio:</label>
|
||||
<input id="single-merge-ratio-slider" name="single-merge-ratio-slider" class="editor-slider" value="50" type="range" min="1" max="1000">
|
||||
<input id="single-merge-ratio" size=2 value="5">%
|
||||
<i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Model A's contribution to the mix. The rest will be from Model B.</span></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-content-merge-opts-batch" class="tab-content">
|
||||
<div class="tab-content-inner">
|
||||
<small>Saves multiple variations of the model, at different merge ratios.<br/>Each variation will be saved as a separate file.</small><br/><br/>
|
||||
<table>
|
||||
<tr><td><label for="#merge-count">Number of variations:</label></td>
|
||||
<td> <input id="merge-count" size=2 value="5"></td>
|
||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Number of models to create</span></i></td></tr>
|
||||
<tr><td><label for="#merge-start">Starting merge ratio:</label></td>
|
||||
<td> <input id="merge-start" size=2 value="5">%</td>
|
||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Smallest share of model A in the mix</span></i></td></tr>
|
||||
<tr><td><label for="#merge-step">Increment each step:</label></td>
|
||||
<td> <input id="merge-step" size=2 value="10">%</td>
|
||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Share of model A added into the mix per step</span></i></td></tr>
|
||||
<tr><td><label for="#merge-interpolation">Interpolation model:</label></td>
|
||||
<td> <select id="merge-interpolation">
|
||||
<option>Exact</option>
|
||||
<option>SmoothStep</option>
|
||||
<option>SmootherStep</option>
|
||||
<option>SmoothestStep</option>
|
||||
</select></td>
|
||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Sigmoid function to be applied to the model share before mixing</span></i></td></tr>
|
||||
</table>
|
||||
<br/>
|
||||
<small>Preview of variation ratios:</small><br/>
|
||||
<canvas id="merge-canvas" width="400" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="merge-buttons">
|
||||
<button id="merge-button" class="primaryButton">Merge models</button>
|
||||
</div>
|
||||
</div>`,
|
||||
onOpen: ({ firstOpen }) => {
|
||||
if (!firstOpen) {
|
||||
return
|
||||
}
|
||||
|
||||
const tabSettingsSingle = document.querySelector("#tab-merge-opts-single")
|
||||
const tabSettingsBatch = document.querySelector("#tab-merge-opts-batch")
|
||||
linkTabContents(tabSettingsSingle)
|
||||
linkTabContents(tabSettingsBatch)
|
||||
|
||||
console.log("Activate")
|
||||
let mergeModelAField = new ModelDropdown(document.querySelector("#mergeModelA"), "stable-diffusion")
|
||||
let mergeModelBField = new ModelDropdown(document.querySelector("#mergeModelB"), "stable-diffusion")
|
||||
updateChart()
|
||||
|
||||
// slider
|
||||
const singleMergeRatioField = document.querySelector("#single-merge-ratio")
|
||||
const singleMergeRatioSlider = document.querySelector("#single-merge-ratio-slider")
|
||||
|
||||
function updateSingleMergeRatio() {
|
||||
singleMergeRatioField.value = singleMergeRatioSlider.value / 10
|
||||
singleMergeRatioField.dispatchEvent(new Event("change"))
|
||||
}
|
||||
|
||||
function updateSingleMergeRatioSlider() {
|
||||
if (singleMergeRatioField.value < 0) {
|
||||
singleMergeRatioField.value = 0
|
||||
} else if (singleMergeRatioField.value > 100) {
|
||||
singleMergeRatioField.value = 100
|
||||
}
|
||||
|
||||
singleMergeRatioSlider.value = singleMergeRatioField.value * 10
|
||||
singleMergeRatioSlider.dispatchEvent(new Event("change"))
|
||||
}
|
||||
|
||||
singleMergeRatioSlider.addEventListener("input", updateSingleMergeRatio)
|
||||
singleMergeRatioField.addEventListener("input", updateSingleMergeRatioSlider)
|
||||
updateSingleMergeRatio()
|
||||
|
||||
document.querySelector(".merge-config").addEventListener("change", updateChart)
|
||||
|
||||
document.querySelector("#merge-button").addEventListener("click", async function(e) {
|
||||
// Build request template
|
||||
let model0 = mergeModelAField.value
|
||||
let model1 = mergeModelBField.value
|
||||
let request = { model0: model0, model1: model1 }
|
||||
request["use_fp16"] = document.querySelector("#merge-fp").value == "fp16"
|
||||
let iterations = document.querySelector("#merge-count").value >> 0
|
||||
let start = parseFloat(document.querySelector("#merge-start").value)
|
||||
let step = parseFloat(document.querySelector("#merge-step").value)
|
||||
|
||||
if (isTabActive(tabSettingsSingle)) {
|
||||
start = parseFloat(singleMergeRatioField.value)
|
||||
step = 0
|
||||
iterations = 1
|
||||
addLogMessage(`merge ratio = ${start}%`)
|
||||
} else {
|
||||
addLogMessage(`start = ${start}%`)
|
||||
addLogMessage(`step = ${step}%`)
|
||||
}
|
||||
|
||||
if (start + (iterations - 1) * step >= 100) {
|
||||
addLogMessage("<i>Aborting: maximum ratio is ≥ 100%</i>")
|
||||
addLogMessage("Reduce the number of variations or the step size")
|
||||
addLogSeparator()
|
||||
document.querySelector("#merge-count").focus()
|
||||
return
|
||||
}
|
||||
|
||||
if (document.querySelector("#merge-filename").value == "") {
|
||||
addLogMessage("<i>Aborting: No output file name specified</i>")
|
||||
addLogSeparator()
|
||||
document.querySelector("#merge-filename").focus()
|
||||
return
|
||||
}
|
||||
|
||||
// Disable merge button
|
||||
e.target.disabled = true
|
||||
e.target.classList.add("disabled")
|
||||
let cursor = $("body").css("cursor")
|
||||
let label = document.querySelector("#merge-button").innerHTML
|
||||
$("body").css("cursor", "progress")
|
||||
document.querySelector("#merge-button").innerHTML = "Merging models ..."
|
||||
|
||||
addLogMessage("Merging models")
|
||||
addLogMessage("Model A: " + model0)
|
||||
addLogMessage("Model B: " + model1)
|
||||
|
||||
// Batch main loop
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
let alpha = (start + i * step) / 100
|
||||
|
||||
if (isTabActive(tabSettingsBatch)) {
|
||||
switch (document.querySelector("#merge-interpolation").value) {
|
||||
case "SmoothStep":
|
||||
alpha = smoothstep(alpha)
|
||||
break
|
||||
case "SmootherStep":
|
||||
alpha = smootherstep(alpha)
|
||||
break
|
||||
case "SmoothestStep":
|
||||
alpha = smootheststep(alpha)
|
||||
break
|
||||
}
|
||||
}
|
||||
addLogMessage(`merging batch job ${i + 1}/${iterations}, alpha = ${alpha.toFixed(5)}...`)
|
||||
|
||||
request["out_path"] = document.querySelector("#merge-filename").value
|
||||
request["out_path"] += "-" + alpha.toFixed(5) + "." + document.querySelector("#merge-format").value
|
||||
addLogMessage(` filename: ${request["out_path"]}`)
|
||||
|
||||
// sdkit documentation: "ratio - the ratio of the second model. 1 means only the second model will be used."
|
||||
request["ratio"] = 1-alpha
|
||||
let res = await fetch("/model/merge", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(request),
|
||||
})
|
||||
const data = await res.json()
|
||||
addLogMessage(JSON.stringify(data))
|
||||
}
|
||||
addLogMessage(
|
||||
"<b>Done.</b> The models have been saved to your <tt>models/stable-diffusion</tt> folder."
|
||||
)
|
||||
addLogSeparator()
|
||||
// Re-enable merge button
|
||||
$("body").css("cursor", cursor)
|
||||
document.querySelector("#merge-button").innerHTML = label
|
||||
e.target.disabled = false
|
||||
e.target.classList.remove("disabled")
|
||||
|
||||
// Update model list
|
||||
stableDiffusionModelField.innerHTML = ""
|
||||
vaeModelField.innerHTML = ""
|
||||
hypernetworkModelField.innerHTML = ""
|
||||
await getModels()
|
||||
})
|
||||
},
|
||||
})
|
||||
})()
|
770
ui/plugins/ui/model-tools.plugin.js
Normal file
770
ui/plugins/ui/model-tools.plugin.js
Normal file
@ -0,0 +1,770 @@
|
||||
;(function() {
|
||||
"use strict"
|
||||
|
||||
let mergeCSS = `
|
||||
/*********** Main tab ***********/
|
||||
.tab-centered {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#model-tool-tab-content {
|
||||
background-color: var(--background-color3);
|
||||
}
|
||||
|
||||
#model-tool-tab-content .tab-content-inner {
|
||||
text-align: initial;
|
||||
}
|
||||
|
||||
#model-tool-tab-bar .tab {
|
||||
margin-bottom: 0px;
|
||||
border-top-left-radius: var(--input-border-radius);
|
||||
background-color: var(--background-color3);
|
||||
padding: 6px 6px 0.8em 6px;
|
||||
}
|
||||
#tab-content-merge .tab-content-inner {
|
||||
max-width: 100%;
|
||||
padding: 10pt;
|
||||
}
|
||||
|
||||
/*********** Merge UI ***********/
|
||||
.merge-model-container {
|
||||
margin-left: 15%;
|
||||
margin-right: 15%;
|
||||
text-align: left;
|
||||
display: inline-grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: auto auto auto;
|
||||
gap: 0px 0px;
|
||||
grid-auto-flow: row;
|
||||
grid-template-areas:
|
||||
"merge-input merge-config"
|
||||
"merge-buttons merge-buttons";
|
||||
}
|
||||
.merge-model-container p {
|
||||
margin-top: 3pt;
|
||||
margin-bottom: 3pt;
|
||||
}
|
||||
.merge-config .tab-content {
|
||||
background: var(--background-color1);
|
||||
border-radius: 3pt;
|
||||
}
|
||||
.merge-config .tab-content-inner {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.merge-input {
|
||||
grid-area: merge-input;
|
||||
padding-left:1em;
|
||||
}
|
||||
.merge-config {
|
||||
grid-area: merge-config;
|
||||
padding:1em;
|
||||
}
|
||||
.merge-config input {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.merge-config select {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.merge-buttons {
|
||||
grid-area: merge-buttons;
|
||||
padding:1em;
|
||||
text-align: center;
|
||||
}
|
||||
#merge-button {
|
||||
padding: 8px;
|
||||
width:20em;
|
||||
}
|
||||
div#merge-log {
|
||||
height:150px;
|
||||
overflow-x:hidden;
|
||||
overflow-y:scroll;
|
||||
background:var(--background-color1);
|
||||
border-radius: 3pt;
|
||||
}
|
||||
div#merge-log i {
|
||||
color: hsl(var(--accent-hue), 100%, calc(2*var(--accent-lightness)));
|
||||
font-family: monospace;
|
||||
}
|
||||
.disabled {
|
||||
background: var(--background-color4);
|
||||
color: var(--text-color);
|
||||
}
|
||||
#merge-type-tabs {
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
#merge-log-container {
|
||||
display: none;
|
||||
}
|
||||
.merge-model-container #merge-warning {
|
||||
color: var(--small-label-color);
|
||||
}
|
||||
|
||||
/*********** LORA UI ***********/
|
||||
.lora-manager-grid {
|
||||
display: grid;
|
||||
gap: 0px 8px;
|
||||
grid-auto-flow: row;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1501px) {
|
||||
.lora-manager-grid textarea {
|
||||
height:350px;
|
||||
}
|
||||
|
||||
.lora-manager-grid {
|
||||
grid-template-columns: auto 1fr 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-areas:
|
||||
"selector selector selector"
|
||||
"thumbnail keywords notes";
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1001px) and (max-width: 1500px) {
|
||||
.lora-manager-grid textarea {
|
||||
height:250px;
|
||||
}
|
||||
|
||||
.lora-manager-grid {
|
||||
grid-template-columns: auto auto;
|
||||
grid-template-rows: auto auto auto;
|
||||
grid-template-areas:
|
||||
"selector selector"
|
||||
"thumbnail keywords"
|
||||
"thumbnail notes";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
.lora-manager-grid textarea {
|
||||
height:200px;
|
||||
}
|
||||
|
||||
.lora-manager-grid {
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto auto auto auto;
|
||||
grid-template-areas:
|
||||
"selector"
|
||||
"keywords"
|
||||
"thumbnail"
|
||||
"notes";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.lora-manager-grid-selector {
|
||||
grid-area: selector;
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.lora-manager-grid-thumbnail {
|
||||
grid-area: thumbnail;
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
.lora-manager-grid-keywords {
|
||||
grid-area: keywords;
|
||||
}
|
||||
|
||||
.lora-manager-grid-notes {
|
||||
grid-area: notes;
|
||||
}
|
||||
|
||||
.lora-manager-grid p {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
|
||||
`
|
||||
|
||||
let mergeUI = `
|
||||
<div class="merge-model-container panel-box">
|
||||
<div class="merge-input">
|
||||
<p><label for="#mergeModelA">Select Model A:</label></p>
|
||||
<input id="mergeModelA" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
|
||||
<p><label for="#mergeModelB">Select Model B:</label></p>
|
||||
<input id="mergeModelB" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
|
||||
<br/><br/>
|
||||
<p id="merge-warning"><small><b>Important:</b> Please merge models of similar type.<br/>For e.g. <code>SD 1.4</code> models with only <code>SD 1.4/1.5</code> models,<br/><code>SD 2.0</code> with <code>SD 2.0</code>-type, and <code>SD 2.1</code> with <code>SD 2.1</code>-type models.</small></p>
|
||||
<br/>
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="#merge-filename">Output file name:</label></td>
|
||||
<td><input id="merge-filename" size=24> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Base name of the output file.<br>Mix ratio and file suffix will be appended to this.</span></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="#merge-fp">Output precision:</label></td>
|
||||
<td><select id="merge-fp">
|
||||
<option value="fp16">fp16 (smaller file size)</option>
|
||||
<option value="fp32">fp32 (larger file size)</option>
|
||||
</select>
|
||||
<i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Image generation uses fp16, so it's a good choice.<br>Use fp32 if you want to use the result models for more mixes</span></i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="#merge-format">Output file format:</label></td>
|
||||
<td><select id="merge-format">
|
||||
<option value="safetensors">Safetensors (recommended)</option>
|
||||
<option value="ckpt">CKPT/Pickle (legacy format)</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<div id="merge-log-container">
|
||||
<p><label for="#merge-log">Log messages:</label></p>
|
||||
<div id="merge-log"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="merge-config">
|
||||
<div class="tab-container">
|
||||
<span id="tab-merge-opts-single" class="tab active">
|
||||
<span>Make a single file</small></span>
|
||||
</span>
|
||||
<span id="tab-merge-opts-batch" class="tab">
|
||||
<span>Make multiple variations</small></span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div id="tab-content-merge-opts-single" class="tab-content active">
|
||||
<div class="tab-content-inner">
|
||||
<small>Saves a single merged model file, at the specified merge ratio.</small><br/><br/>
|
||||
<label for="#single-merge-ratio-slider">Merge ratio:</label>
|
||||
<input id="single-merge-ratio-slider" name="single-merge-ratio-slider" class="editor-slider" value="50" type="range" min="1" max="1000">
|
||||
<input id="single-merge-ratio" size=2 value="5">%
|
||||
<i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Model A's contribution to the mix. The rest will be from Model B.</span></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-content-merge-opts-batch" class="tab-content">
|
||||
<div class="tab-content-inner">
|
||||
<small>Saves multiple variations of the model, at different merge ratios.<br/>Each variation will be saved as a separate file.</small><br/><br/>
|
||||
<table>
|
||||
<tr><td><label for="#merge-count">Number of variations:</label></td>
|
||||
<td> <input id="merge-count" size=2 value="5"></td>
|
||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Number of models to create</span></i></td></tr>
|
||||
<tr><td><label for="#merge-start">Starting merge ratio:</label></td>
|
||||
<td> <input id="merge-start" size=2 value="5">%</td>
|
||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Smallest share of model A in the mix</span></i></td></tr>
|
||||
<tr><td><label for="#merge-step">Increment each step:</label></td>
|
||||
<td> <input id="merge-step" size=2 value="10">%</td>
|
||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Share of model A added into the mix per step</span></i></td></tr>
|
||||
<tr><td><label for="#merge-interpolation">Interpolation model:</label></td>
|
||||
<td> <select id="merge-interpolation">
|
||||
<option>Exact</option>
|
||||
<option>SmoothStep</option>
|
||||
<option>SmootherStep</option>
|
||||
<option>SmoothestStep</option>
|
||||
</select></td>
|
||||
<td> <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Sigmoid function to be applied to the model share before mixing</span></i></td></tr>
|
||||
</table>
|
||||
<br/>
|
||||
<small>Preview of variation ratios:</small><br/>
|
||||
<canvas id="merge-canvas" width="400" height="400"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="merge-buttons">
|
||||
<button id="merge-button" class="primaryButton">Merge models</button>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
|
||||
let loraUI=`
|
||||
<div class="panel-box lora-manager-grid">
|
||||
<div class="lora-manager-grid-selector">
|
||||
<label for="#loraModel">Select Lora:</label>
|
||||
<input id="loraModel" type="text" spellcheck="false" autocomplete="off" class="model-filter" data-path="" />
|
||||
</div>
|
||||
<div class="lora-manager-grid-thumbnail">
|
||||
<p style="height:2em;">Thumbnail:</p>
|
||||
<div style="position:relative; height:256px; width:256px;background-color:#222;border-radius:1em;margin-bottom:1em;">
|
||||
<i id="lora-manager-image-placeholder" class="fa-regular fa-image" style="font-size:500%;color:#555;position:absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);"></i>
|
||||
<img id="lora-manager-image" class="displayNone" style="border-radius:6px;max-height:256px;max-width:256px;"/>
|
||||
</div>
|
||||
<div style="text-align:center;">
|
||||
<button class="tertiaryButton" id="lora-manager-upload-button"><i class="fa-solid fa-upload"></i> Upload new thumbnail</button>
|
||||
<input id="lora-manager-upload-input" name="lora-manager-upload-input" type="file" class="displayNone">
|
||||
<!-- button class="tertiaryButton"><i class="fa-solid fa-trash-can"></i> Remove</button -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="lora-manager-grid-keywords">
|
||||
<p style="height:2em;">Keywords:
|
||||
<span style="float:right;margin-bottom:4px;"><button id="lora-keyword-from-civitai" class="tertiaryButton smallButton">Import from Civitai</button></span></p>
|
||||
<textarea style="width:100%;resize:vertical;" id="lora-manager-keywords" placeholder="Put LORA specific keywords here..."></textarea>
|
||||
<p style="color:var(--small-label-color);">
|
||||
<b>LORA model keywords</b> can be used via the <code>+ Embeddings</code> button. They get added to the embedding
|
||||
keyword menu when the LORA has been selected in the image settings.
|
||||
</p>
|
||||
</div>
|
||||
<div class="lora-manager-grid-notes">
|
||||
<p style="height:2em;">Notes:</p>
|
||||
<textarea style="width:100%;resize:vertical;" id="lora-manager-notes" placeholder="Place for things you want to remember..."></textarea>
|
||||
<p id="civitai-section" class="displayNone">
|
||||
<b>Civitai model page:</b>
|
||||
<a id="civitai-model-page" target="_blank"></a>
|
||||
</p>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
let tabHTML=`
|
||||
<div id="model-tool-tab-bar" class="tab-container tab-centered">
|
||||
<span id="tab-model-loraUI" class="tab active">
|
||||
<span><i class="fa-solid fa-key"></i> Lora Keywords</small></span>
|
||||
</span>
|
||||
<span id="tab-model-mergeUI" class="tab">
|
||||
<span><i class="fa-solid fa-code-merge"></i> Merge Models</small></span>
|
||||
</span>
|
||||
</div>
|
||||
<div id="model-tool-tab-content" class="panel-box">
|
||||
<div id="tab-content-model-loraUI" class="tab-content active">
|
||||
<div class="tab-content-inner">
|
||||
${loraUI}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-content-model-mergeUI" class="tab-content">
|
||||
<div class="tab-content-inner">
|
||||
${mergeUI}
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
|
||||
///////////////////// Function section
|
||||
function smoothstep(x) {
|
||||
return x * x * (3 - 2 * x)
|
||||
}
|
||||
|
||||
function smootherstep(x) {
|
||||
return x * x * x * (x * (x * 6 - 15) + 10)
|
||||
}
|
||||
|
||||
function smootheststep(x) {
|
||||
let y = -20 * Math.pow(x, 7)
|
||||
y += 70 * Math.pow(x, 6)
|
||||
y -= 84 * Math.pow(x, 5)
|
||||
y += 35 * Math.pow(x, 4)
|
||||
return y
|
||||
}
|
||||
function getCurrentTime() {
|
||||
const now = new Date()
|
||||
let hours = now.getHours()
|
||||
let minutes = now.getMinutes()
|
||||
let seconds = now.getSeconds()
|
||||
|
||||
hours = hours < 10 ? `0${hours}` : hours
|
||||
minutes = minutes < 10 ? `0${minutes}` : minutes
|
||||
seconds = seconds < 10 ? `0${seconds}` : seconds
|
||||
|
||||
return `${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
|
||||
function addLogMessage(message) {
|
||||
const logContainer = document.getElementById("merge-log")
|
||||
logContainer.innerHTML += `<i>${getCurrentTime()}</i> ${message}<br>`
|
||||
|
||||
// Scroll to the bottom of the log
|
||||
logContainer.scrollTop = logContainer.scrollHeight
|
||||
|
||||
document.querySelector("#merge-log-container").style.display = "block"
|
||||
}
|
||||
|
||||
function addLogSeparator() {
|
||||
const logContainer = document.getElementById("merge-log")
|
||||
logContainer.innerHTML += "<hr>"
|
||||
|
||||
logContainer.scrollTop = logContainer.scrollHeight
|
||||
}
|
||||
|
||||
function drawDiagram(fn) {
|
||||
const SIZE = 300
|
||||
const canvas = document.getElementById("merge-canvas")
|
||||
canvas.height = canvas.width = SIZE
|
||||
const ctx = canvas.getContext("2d")
|
||||
|
||||
// Draw coordinate system
|
||||
ctx.scale(1, -1)
|
||||
ctx.translate(0, -canvas.height)
|
||||
ctx.lineWidth = 1
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.strokeStyle = "white"
|
||||
ctx.moveTo(0, 0)
|
||||
ctx.lineTo(0, SIZE)
|
||||
ctx.lineTo(SIZE, SIZE)
|
||||
ctx.lineTo(SIZE, 0)
|
||||
ctx.lineTo(0, 0)
|
||||
ctx.lineTo(SIZE, SIZE)
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.setLineDash([1, 2])
|
||||
const n = SIZE / 10
|
||||
for (let i = n; i < SIZE; i += n) {
|
||||
ctx.moveTo(0, i)
|
||||
ctx.lineTo(SIZE, i)
|
||||
ctx.moveTo(i, 0)
|
||||
ctx.lineTo(i, SIZE)
|
||||
}
|
||||
ctx.stroke()
|
||||
ctx.beginPath()
|
||||
ctx.setLineDash([])
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = "black"
|
||||
ctx.lineWidth = 3
|
||||
// Plot function
|
||||
const numSamples = 20
|
||||
for (let i = 0; i <= numSamples; i++) {
|
||||
const x = i / numSamples
|
||||
const y = fn(x)
|
||||
|
||||
const canvasX = x * SIZE
|
||||
const canvasY = y * SIZE
|
||||
|
||||
if (i === 0) {
|
||||
ctx.moveTo(canvasX, canvasY)
|
||||
} else {
|
||||
ctx.lineTo(canvasX, canvasY)
|
||||
}
|
||||
}
|
||||
ctx.stroke()
|
||||
// Plot alpha values (yellow boxes)
|
||||
let start = parseFloat(document.querySelector("#merge-start").value)
|
||||
let step = parseFloat(document.querySelector("#merge-step").value)
|
||||
let iterations = document.querySelector("#merge-count").value >> 0
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = "yellow"
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const alpha = (start + i * step) / 100
|
||||
const x = alpha * SIZE
|
||||
const y = fn(alpha) * SIZE
|
||||
if (x <= SIZE) {
|
||||
ctx.rect(x - 3, y - 3, 6, 6)
|
||||
ctx.fill()
|
||||
} else {
|
||||
ctx.strokeStyle = "red"
|
||||
ctx.moveTo(0, 0)
|
||||
ctx.lineTo(0, SIZE)
|
||||
ctx.lineTo(SIZE, SIZE)
|
||||
ctx.lineTo(SIZE, 0)
|
||||
ctx.lineTo(0, 0)
|
||||
ctx.lineTo(SIZE, SIZE)
|
||||
ctx.stroke()
|
||||
addLogMessage("<i>Warning: maximum ratio is ≥ 100%</i>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateChart() {
|
||||
let fn = (x) => x
|
||||
switch (document.querySelector("#merge-interpolation").value) {
|
||||
case "SmoothStep":
|
||||
fn = smoothstep
|
||||
break
|
||||
case "SmootherStep":
|
||||
fn = smootherstep
|
||||
break
|
||||
case "SmoothestStep":
|
||||
fn = smootheststep
|
||||
break
|
||||
}
|
||||
drawDiagram(fn)
|
||||
}
|
||||
|
||||
function initMergeUI() {
|
||||
const tabSettingsSingle = document.querySelector("#tab-merge-opts-single")
|
||||
const tabSettingsBatch = document.querySelector("#tab-merge-opts-batch")
|
||||
linkTabContents(tabSettingsSingle)
|
||||
linkTabContents(tabSettingsBatch)
|
||||
|
||||
let mergeModelAField = new ModelDropdown(document.querySelector("#mergeModelA"), "stable-diffusion")
|
||||
let mergeModelBField = new ModelDropdown(document.querySelector("#mergeModelB"), "stable-diffusion")
|
||||
updateChart()
|
||||
|
||||
// slider
|
||||
const singleMergeRatioField = document.querySelector("#single-merge-ratio")
|
||||
const singleMergeRatioSlider = document.querySelector("#single-merge-ratio-slider")
|
||||
|
||||
function updateSingleMergeRatio() {
|
||||
singleMergeRatioField.value = singleMergeRatioSlider.value / 10
|
||||
singleMergeRatioField.dispatchEvent(new Event("change"))
|
||||
}
|
||||
|
||||
function updateSingleMergeRatioSlider() {
|
||||
if (singleMergeRatioField.value < 0) {
|
||||
singleMergeRatioField.value = 0
|
||||
} else if (singleMergeRatioField.value > 100) {
|
||||
singleMergeRatioField.value = 100
|
||||
}
|
||||
|
||||
singleMergeRatioSlider.value = singleMergeRatioField.value * 10
|
||||
singleMergeRatioSlider.dispatchEvent(new Event("change"))
|
||||
}
|
||||
|
||||
singleMergeRatioSlider.addEventListener("input", updateSingleMergeRatio)
|
||||
singleMergeRatioField.addEventListener("input", updateSingleMergeRatioSlider)
|
||||
updateSingleMergeRatio()
|
||||
|
||||
document.querySelector(".merge-config").addEventListener("change", updateChart)
|
||||
|
||||
document.querySelector("#merge-button").addEventListener("click", async function(e) {
|
||||
// Build request template
|
||||
let model0 = mergeModelAField.value
|
||||
let model1 = mergeModelBField.value
|
||||
let request = { model0: model0, model1: model1 }
|
||||
request["use_fp16"] = document.querySelector("#merge-fp").value == "fp16"
|
||||
let iterations = document.querySelector("#merge-count").value >> 0
|
||||
let start = parseFloat(document.querySelector("#merge-start").value)
|
||||
let step = parseFloat(document.querySelector("#merge-step").value)
|
||||
|
||||
if (isTabActive(tabSettingsSingle)) {
|
||||
start = parseFloat(singleMergeRatioField.value)
|
||||
step = 0
|
||||
iterations = 1
|
||||
addLogMessage(`merge ratio = ${start}%`)
|
||||
} else {
|
||||
addLogMessage(`start = ${start}%`)
|
||||
addLogMessage(`step = ${step}%`)
|
||||
}
|
||||
|
||||
if (start + (iterations - 1) * step >= 100) {
|
||||
addLogMessage("<i>Aborting: maximum ratio is ≥ 100%</i>")
|
||||
addLogMessage("Reduce the number of variations or the step size")
|
||||
addLogSeparator()
|
||||
document.querySelector("#merge-count").focus()
|
||||
return
|
||||
}
|
||||
|
||||
if (document.querySelector("#merge-filename").value == "") {
|
||||
addLogMessage("<i>Aborting: No output file name specified</i>")
|
||||
addLogSeparator()
|
||||
document.querySelector("#merge-filename").focus()
|
||||
return
|
||||
}
|
||||
|
||||
// Disable merge button
|
||||
e.target.disabled = true
|
||||
e.target.classList.add("disabled")
|
||||
let cursor = $("body").css("cursor")
|
||||
let label = document.querySelector("#merge-button").innerHTML
|
||||
$("body").css("cursor", "progress")
|
||||
document.querySelector("#merge-button").innerHTML = "Merging models ..."
|
||||
|
||||
addLogMessage("Merging models")
|
||||
addLogMessage("Model A: " + model0)
|
||||
addLogMessage("Model B: " + model1)
|
||||
|
||||
// Batch main loop
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
let alpha = (start + i * step) / 100
|
||||
|
||||
if (isTabActive(tabSettingsBatch)) {
|
||||
switch (document.querySelector("#merge-interpolation").value) {
|
||||
case "SmoothStep":
|
||||
alpha = smoothstep(alpha)
|
||||
break
|
||||
case "SmootherStep":
|
||||
alpha = smootherstep(alpha)
|
||||
break
|
||||
case "SmoothestStep":
|
||||
alpha = smootheststep(alpha)
|
||||
break
|
||||
}
|
||||
}
|
||||
addLogMessage(`merging batch job ${i + 1}/${iterations}, alpha = ${alpha.toFixed(5)}...`)
|
||||
|
||||
request["out_path"] = document.querySelector("#merge-filename").value
|
||||
request["out_path"] += "-" + alpha.toFixed(5) + "." + document.querySelector("#merge-format").value
|
||||
addLogMessage(` filename: ${request["out_path"]}`)
|
||||
|
||||
// sdkit documentation: "ratio - the ratio of the second model. 1 means only the second model will be used."
|
||||
request["ratio"] = 1-alpha
|
||||
let res = await fetch("/model/merge", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(request),
|
||||
})
|
||||
const data = await res.json()
|
||||
addLogMessage(JSON.stringify(data))
|
||||
}
|
||||
addLogMessage(
|
||||
"<b>Done.</b> The models have been saved to your <tt>models/stable-diffusion</tt> folder."
|
||||
)
|
||||
addLogSeparator()
|
||||
// Re-enable merge button
|
||||
$("body").css("cursor", cursor)
|
||||
document.querySelector("#merge-button").innerHTML = label
|
||||
e.target.disabled = false
|
||||
e.target.classList.remove("disabled")
|
||||
|
||||
// Update model list
|
||||
stableDiffusionModelField.innerHTML = ""
|
||||
vaeModelField.innerHTML = ""
|
||||
hypernetworkModelField.innerHTML = ""
|
||||
await getModels()
|
||||
})
|
||||
}
|
||||
|
||||
const LoraUI = {
|
||||
modelField: undefined,
|
||||
keywordsField: undefined,
|
||||
notesField: undefined,
|
||||
civitaiImportBtn: undefined,
|
||||
civitaiSecion: undefined,
|
||||
civitaiAnchor: undefined,
|
||||
image: undefined,
|
||||
imagePlaceholder: undefined,
|
||||
|
||||
init() {
|
||||
LoraUI.modelField = new ModelDropdown(document.querySelector("#loraModel"), "lora", "None")
|
||||
LoraUI.keywordsField = document.querySelector("#lora-manager-keywords")
|
||||
LoraUI.notesField = document.querySelector("#lora-manager-notes")
|
||||
LoraUI.civitaiImportBtn = document.querySelector("#lora-keyword-from-civitai")
|
||||
LoraUI.civitaiSection = document.querySelector("#civitai-section")
|
||||
LoraUI.civitaiAnchor = document.querySelector("#civitai-model-page")
|
||||
LoraUI.image = document.querySelector("#lora-manager-image")
|
||||
LoraUI.imagePlaceholder = document.querySelector("#lora-manager-image-placeholder")
|
||||
LoraUI.uploadBtn = document.querySelector("#lora-manager-upload-button")
|
||||
LoraUI.uploadInput = document.querySelector("#lora-manager-upload-input")
|
||||
|
||||
LoraUI.modelField.addEventListener("change", LoraUI.updateFields)
|
||||
LoraUI.keywordsField.addEventListener("focusout", LoraUI.saveInfos)
|
||||
LoraUI.notesField.addEventListener("focusout", LoraUI.saveInfos)
|
||||
LoraUI.civitaiImportBtn.addEventListener("click", LoraUI.importFromCivitai)
|
||||
|
||||
LoraUI.uploadBtn.addEventListener("click", (e) => LoraUI.uploadInput.click())
|
||||
LoraUI.uploadInput.addEventListener("change", LoraUI.uploadLoraThumb)
|
||||
|
||||
document.addEventListener("saveThumb", LoraUI.updateFields)
|
||||
|
||||
LoraUI.updateFields()
|
||||
},
|
||||
|
||||
uploadLoraThumb(e) {
|
||||
console.log(e)
|
||||
if (LoraUI.uploadInput.files.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let reader = new FileReader()
|
||||
let file = LoraUI.uploadInput.files[0]
|
||||
|
||||
reader.addEventListener("load", (event) => {
|
||||
let img = document.createElement("img")
|
||||
img.src = reader.result
|
||||
onUseAsThumbnailClick(
|
||||
{
|
||||
use_lora_model: LoraUI.modelField.value,
|
||||
},
|
||||
img
|
||||
)
|
||||
})
|
||||
|
||||
if (file) {
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
},
|
||||
|
||||
updateFields() {
|
||||
document.getElementById("civitai-section").classList.add("displayNone")
|
||||
Bucket.retrieve(`modelinfo/lora/${LoraUI.modelField.value}`)
|
||||
.then((info) => {
|
||||
if (info == null) {
|
||||
LoraUI.keywordsField.value = ""
|
||||
LoraUI.notesField.value = ""
|
||||
LoraUI.hideCivitaiLink()
|
||||
} else {
|
||||
LoraUI.keywordsField.value = info.keywords.join("\n")
|
||||
LoraUI.notesField.value = info.notes
|
||||
if ("civitai" in info && info["civitai"] != null) {
|
||||
LoraUI.showCivitaiLink(info.civitai)
|
||||
} else {
|
||||
LoraUI.hideCivitaiLink()
|
||||
}
|
||||
}
|
||||
})
|
||||
Bucket.getImageAsDataURL(`${profileNameField.value}/lora/${LoraUI.modelField.value}.png`)
|
||||
.then((data) => {
|
||||
LoraUI.image.src=data
|
||||
LoraUI.image.classList.remove("displayNone")
|
||||
LoraUI.imagePlaceholder.classList.add("displayNone")
|
||||
})
|
||||
.catch((error) => {
|
||||
LoraUI.image.classList.add("displayNone")
|
||||
LoraUI.imagePlaceholder.classList.remove("displayNone")
|
||||
})
|
||||
},
|
||||
|
||||
saveInfos() {
|
||||
let info = {
|
||||
keywords: LoraUI.keywordsField.value
|
||||
.split("\n")
|
||||
.filter((x) => (x != "")),
|
||||
notes: LoraUI.notesField.value,
|
||||
civitai: LoraUI.civitaiSection.checkVisibility() ? LoraUI.civitaiAnchor.href : null,
|
||||
}
|
||||
Bucket.store(`modelinfo/lora/${LoraUI.modelField.value}`, info)
|
||||
},
|
||||
|
||||
importFromCivitai() {
|
||||
document.body.style["cursor"] = "progress"
|
||||
fetch("/sha256/lora/"+LoraUI.modelField.value)
|
||||
.then((result) => result.json())
|
||||
.then((json) => fetch("https://civitai.com/api/v1/model-versions/by-hash/" + json.digest))
|
||||
.then((result) => result.json())
|
||||
.then((json) => {
|
||||
document.body.style["cursor"] = "default"
|
||||
if (json == null) {
|
||||
return
|
||||
}
|
||||
if ("trainedWords" in json) {
|
||||
LoraUI.keywordsField.value = json["trainedWords"].join("\n")
|
||||
} else {
|
||||
showToast("No keyword info found.")
|
||||
}
|
||||
if ("modelId" in json) {
|
||||
LoraUI.showCivitaiLink("https://civitai.com/models/" + json.modelId)
|
||||
} else {
|
||||
LoraUI.hideCivitaiLink()
|
||||
}
|
||||
|
||||
LoraUI.saveInfos()
|
||||
})
|
||||
},
|
||||
|
||||
showCivitaiLink(href) {
|
||||
LoraUI.civitaiSection.classList.remove("displayNone")
|
||||
LoraUI.civitaiAnchor.href = href
|
||||
LoraUI.civitaiAnchor.innerHTML = LoraUI.civitaiAnchor.href
|
||||
},
|
||||
|
||||
hideCivitaiLink() {
|
||||
LoraUI.civitaiSection.classList.add("displayNone")
|
||||
}
|
||||
}
|
||||
|
||||
createTab({
|
||||
id: "merge",
|
||||
icon: "fa-toolbox",
|
||||
label: "Model tools",
|
||||
css: mergeCSS,
|
||||
content: tabHTML,
|
||||
onOpen: ({ firstOpen }) => {
|
||||
if (!firstOpen) {
|
||||
return
|
||||
}
|
||||
initMergeUI()
|
||||
LoraUI.init()
|
||||
const tabMergeUI = document.querySelector("#tab-model-mergeUI")
|
||||
const tabLoraUI = document.querySelector("#tab-model-loraUI")
|
||||
linkTabContents(tabMergeUI)
|
||||
linkTabContents(tabLoraUI)
|
||||
},
|
||||
})
|
||||
})()
|
||||
async function getLoraKeywords(model) {
|
||||
return Bucket.retrieve(`modelinfo/lora/${model}`)
|
||||
.then((info) => info ? info.keywords : [])
|
||||
}
|
Reference in New Issue
Block a user