Compare commits
260 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d5eb396046 | |||
| 7d60076b8b | |||
| 77171923f8 | |||
| c4ffeb857e | |||
| e5381320b9 | |||
| 86a46e8189 | |||
| c2279da522 | |||
| dc2074c46d | |||
| 362675e75b | |||
| 6ab0b65ed1 | |||
| 3f763d41e8 | |||
| e3c849da06 | |||
| c0113872c5 | |||
| deeec0b343 | |||
| c7e810a985 | |||
| 7026b96476 | |||
| 56ef5e9d48 | |||
| 0eb5fde2fd | |||
| 0935d2c304 | |||
| b2f9709538 | |||
| 5cc7bf3876 | |||
| 416fbde726 | |||
| 1cc7c4bfb3 | |||
| 951842d785 | |||
| 591ad1dbc3 | |||
| fcfe5c179b | |||
| a0e979badb | |||
| 3aa9f01bdc | |||
| 4e5d2526cb | |||
| ab63054f95 | |||
| 0c71967a53 | |||
| b20cd352d9 | |||
| 3a4290f833 | |||
| df48222f3e | |||
| ee8e98711b | |||
| 87b50397a6 | |||
| e309583f29 | |||
| 7ce1f3a142 | |||
| db63cf7d24 | |||
| cdafbcaad2 | |||
| 34055f9d0c | |||
| 9b17416580 | |||
| 833b9b62b5 | |||
| 3b0be0f12f | |||
| 4083639c3c | |||
| 8a758383d2 | |||
| ad3b8a1c41 | |||
| 1b9ca01e4f | |||
| 30f4f25b2e | |||
| a69daae012 | |||
| 99aa702015 | |||
| d00f6dca28 | |||
| fdecf813b6 | |||
| 8e355fbd75 | |||
| 701feabf49 | |||
| d2878a8b0b | |||
| 663fb87976 | |||
| d9d94141dc | |||
| 813535d38b | |||
| afd0624587 | |||
| ab3d3528a1 | |||
| 0ad38a9b87 | |||
| cf1edc2b54 | |||
| 5b761b49ad | |||
| 102b6617da | |||
| 93015964c7 | |||
| 6fb2194d9c | |||
| 59544321aa | |||
| c485a7d12e | |||
| 413123f08a | |||
| 7d4d871d46 | |||
| 26d0d87f5b | |||
| d6478a60aa | |||
| ab57417175 | |||
| f8042cb323 | |||
| 924642331b | |||
| c9c457eda8 | |||
| 73c2a03d49 | |||
| 06af73bd1d | |||
| 9cebe308e9 | |||
| 558808c748 | |||
| c68aabc852 | |||
| 46ef185709 | |||
| 46375f0592 | |||
| 558baffa2c | |||
| 4ebed495ed | |||
| e6d41b54cd | |||
| e06c16e884 | |||
| 72bc69e741 | |||
| b33ffc11aa | |||
| 0a2c24003c | |||
| 9e58e11ad4 | |||
| 4c4d7dd01f | |||
| adb3f2bcdd | |||
| 8afabae67d | |||
| fccde0c1f7 | |||
| 3ca4655a18 | |||
| 349f893024 | |||
| 7b44b85730 | |||
| 329c8ab932 | |||
| 259768f27f | |||
| 741e8ecb7d | |||
| 63485b2c55 | |||
| e4726cccf9 | |||
| f11eec81e3 | |||
| 45881703c5 | |||
| 340fce2113 | |||
| 657404b75b | |||
| 35d1c94549 | |||
| 47033afa5c | |||
| de5bb4ca88 | |||
| ff7027ffc0 | |||
| 0c1c9e74cd | |||
| 022639a145 | |||
| 5e16914a4e | |||
| 8f3b02f095 | |||
| f593cbfec4 | |||
| a51721cb09 | |||
| ba05e32789 | |||
| 3e67017dfb | |||
| d7e3ea68b3 | |||
| bf0b083216 | |||
| 317d00b2a6 | |||
| 737a013377 | |||
| 78c1a74660 | |||
| bd9b3d15e8 | |||
| 5681bf8016 | |||
| 348c6022f3 | |||
| 76b1ad7daf | |||
| d39440bfb9 | |||
| 5ef669de08 | |||
| 20158d77d9 | |||
| e7965a5eb8 | |||
| 3bff988f1e | |||
| 41196ccbf7 | |||
| 541a3db05b | |||
| ae7291fb49 | |||
| d43333ff71 | |||
| 0cdbd90d6b | |||
| d0026da483 | |||
| 8d54739de5 | |||
| 135b61bc0b | |||
| 6adf2b71c2 | |||
| 87cca029d7 | |||
| ae0b2cc196 | |||
| 1ac11b3dae | |||
| 0ff8b8fb54 | |||
| c985d23c52 | |||
| 87a083d1b2 | |||
| 644b537014 | |||
| 67cd4ec0aa | |||
| 28b084ca25 | |||
| 503bd3fc0f | |||
| f874b1bcad | |||
| 9e7de49fc5 | |||
| 06bc1f4f67 | |||
| 338d0b6103 | |||
| 3989d7e88b | |||
| afea99a72b | |||
| 965c728914 | |||
| 46f3ee9594 | |||
| 323dcadea2 | |||
| 642faa1f65 | |||
| d156d5bffd | |||
| edf3ad5aed | |||
| 4aaae3dc65 | |||
| 9a4a1aac81 | |||
| ee373a737c | |||
| 9e248fb24e | |||
| 08603378e8 | |||
| 834f4c7cd3 | |||
| 549b475be9 | |||
| 7e5fcdaf69 | |||
| e3939f3339 | |||
| cb2a4f2424 | |||
| f564d8ed2c | |||
| ba7d0d225a | |||
| 04b90328c0 | |||
| a0af2852b6 | |||
| b6c1a1bbbf | |||
| 00e393ce10 | |||
| 84d41e49b3 | |||
| 0c9282b84d | |||
| 18ba89863d | |||
| 444f102964 | |||
| 9e8464db1e | |||
| 738e133b24 | |||
| 01a257eb07 | |||
| 6558716018 | |||
| 9c87ae0d9d | |||
| 7ab16e99ee | |||
| 8a7a4275a8 | |||
| 3269572753 | |||
| 5070ab8004 | |||
| 02e7824e6a | |||
| d83a1ba65b | |||
| 1bb21f3510 | |||
| 739686b1c5 | |||
| c0f9821c35 | |||
| cd48308a2a | |||
| 592b0dcfa7 | |||
| 20df81b0cc | |||
| 99acbd5ebe | |||
| d1c93c3822 | |||
| 9e14cac318 | |||
| f898833ea3 | |||
| f3d1631aab | |||
| 8632452627 | |||
| 86708463f1 | |||
| 66146ed72b | |||
| 2b8484a29d | |||
| 18e3e6d6ab | |||
| bfc5c08109 | |||
| ad266d795e | |||
| e422f19ee9 | |||
| d0d5075914 | |||
| 896fde789e | |||
| d63117ace5 | |||
| 66d7630705 | |||
| 63d3150dc4 | |||
| cb81087b59 | |||
| 6139b145f0 | |||
| f331821b27 | |||
| 5359dc0a10 | |||
| 7989765faa | |||
| 783a5754d5 | |||
| 897312de46 | |||
| 23c6b5f124 | |||
| c2463b5323 | |||
| ed2a05fc3f | |||
| e3174a1a42 | |||
| 07878c6ca8 | |||
| 5e30f737b0 | |||
| bd5c16e8da | |||
| f2c55523c0 | |||
| cb5f0823c6 | |||
| 9dd0c4add5 | |||
| 1b46863f24 | |||
| 3d83683a28 | |||
| b7f0e81562 | |||
| 9d8d279d0d | |||
| d888490f85 | |||
| 168eac319d | |||
| 73f69a7453 | |||
| ec54257cb2 | |||
| 72ee347eab | |||
| ac1abf3de6 | |||
| bb90b0ff42 | |||
| db56bdce33 | |||
| f3a1027869 | |||
| dd07b5193e | |||
| 3369fb27df | |||
| 4c6788644a | |||
| a6cedafb27 | |||
| e004384e46 | |||
| e835e61f3a | |||
| 4130e5db3d | |||
| c8c73eae59 | |||
| c39efa6ba6 | |||
| c9c8485bc1 |
@@ -74,6 +74,7 @@ module.exports = {
|
||||
create_submit_args: "readonly",
|
||||
restart_reload: "readonly",
|
||||
updateInput: "readonly",
|
||||
onEdit: "readonly",
|
||||
//extraNetworks.js
|
||||
requestGet: "readonly",
|
||||
popup: "readonly",
|
||||
|
||||
@@ -26,7 +26,7 @@ body:
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce the problem
|
||||
description: Please provide us with precise step by step information on how to reproduce the bug
|
||||
description: Please provide us with precise step by step instructions on how to reproduce the bug
|
||||
value: |
|
||||
1. Go to ....
|
||||
2. Press ....
|
||||
@@ -37,64 +37,14 @@ body:
|
||||
id: what-should
|
||||
attributes:
|
||||
label: What should have happened?
|
||||
description: Tell what you think the normal behavior should be
|
||||
description: Tell us what you think the normal behavior should be
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: commit
|
||||
- type: textarea
|
||||
id: sysinfo
|
||||
attributes:
|
||||
label: Version or Commit where the problem happens
|
||||
description: "Which webui version or commit are you running ? (Do not write *Latest Version/repo/commit*, as this means nothing and will have changed by the time we read your issue. Rather, copy the **Version: v1.2.3** link at the bottom of the UI, or from the cmd/terminal if you can't launch it.)"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: py-version
|
||||
attributes:
|
||||
label: What Python version are you running on ?
|
||||
multiple: false
|
||||
options:
|
||||
- Python 3.10.x
|
||||
- Python 3.11.x (above, no supported yet)
|
||||
- Python 3.9.x (below, no recommended)
|
||||
- type: dropdown
|
||||
id: platforms
|
||||
attributes:
|
||||
label: What platforms do you use to access the UI ?
|
||||
multiple: true
|
||||
options:
|
||||
- Windows
|
||||
- Linux
|
||||
- MacOS
|
||||
- iOS
|
||||
- Android
|
||||
- Other/Cloud
|
||||
- type: dropdown
|
||||
id: device
|
||||
attributes:
|
||||
label: What device are you running WebUI on?
|
||||
multiple: true
|
||||
options:
|
||||
- Nvidia GPUs (RTX 20 above)
|
||||
- Nvidia GPUs (GTX 16 below)
|
||||
- AMD GPUs (RX 6000 above)
|
||||
- AMD GPUs (RX 5000 below)
|
||||
- CPU
|
||||
- Other GPUs
|
||||
- type: dropdown
|
||||
id: cross_attention_opt
|
||||
attributes:
|
||||
label: Cross attention optimization
|
||||
description: What cross attention optimization are you using, Settings -> Optimizations -> Cross attention optimization
|
||||
multiple: false
|
||||
options:
|
||||
- Automatic
|
||||
- xformers
|
||||
- sdp-no-mem
|
||||
- sdp
|
||||
- Doggettx
|
||||
- V1
|
||||
- InvokeAI
|
||||
- "None "
|
||||
label: Sysinfo
|
||||
description: System info file, generated by WebUI. You can generate it in settings, on the Sysinfo page. Drag the file into the field to upload it. If you submit your report without including the sysinfo file, the report will be closed. If needed, review the report to make sure it includes no personal information you don't want to share. If you can't start WebUI, you can use --dump-sysinfo commandline argument to generate the file.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
@@ -108,21 +58,7 @@ body:
|
||||
- Brave
|
||||
- Apple Safari
|
||||
- Microsoft Edge
|
||||
- type: textarea
|
||||
id: cmdargs
|
||||
attributes:
|
||||
label: Command Line Arguments
|
||||
description: Are you using any launching parameters/command line arguments (modified webui-user .bat/.sh) ? If yes, please write them below. Write "No" otherwise.
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extensions
|
||||
attributes:
|
||||
label: List of extensions
|
||||
description: Are you using any extensions other than built-ins? If yes, provide a list, you can copy it at "Extensions" tab. Write "No" otherwise.
|
||||
validations:
|
||||
required: true
|
||||
- Other
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
|
||||
+18
-1
@@ -65,9 +65,12 @@
|
||||
* make progress bar work independently from live preview display which results in it being updated a lot more often
|
||||
* forbid Full live preview method for medvram and add a setting to undo the forbidding
|
||||
* make it possible to localize tooltips and placeholders
|
||||
* add option to align with sgm repo's sampling implementation ([#12818](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12818))
|
||||
* Restore faces and Tiling generation parameters have been moved to settings out of main UI
|
||||
* if you want to put them back into main UI, use `Options in main UI` setting on the UI page.
|
||||
|
||||
### Extensions and API:
|
||||
* gradio 3.41.0
|
||||
* gradio 3.41.2
|
||||
* also bump versions for packages: transformers, GitPython, accelerate, scikit-image, timm, tomesd
|
||||
* support tooltip kwarg for gradio elements: gr.Textbox(label='hello', tooltip='world')
|
||||
* properly clear the total console progressbar when using txt2img and img2img from API
|
||||
@@ -127,6 +130,20 @@
|
||||
* set devices.dtype_unet correctly
|
||||
* run RealESRGAN on GPU for non-CUDA devices ([#12737](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12737))
|
||||
* prevent extra network buttons being obscured by description for very small card sizes ([#12745](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12745))
|
||||
* fix error that causes some extra networks to be disabled if both <lora:> and <lyco:> are present in the prompt
|
||||
* fix defaults settings page breaking when any of main UI tabs are hidden
|
||||
* fix incorrect save/display of new values in Defaults page in settings
|
||||
* fix for Reload UI function: if you reload UI on one tab, other opened tabs will no longer stop working
|
||||
* fix an error that prevents VAE being reloaded after an option change if a VAE near the checkpoint exists ([#12797](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12737))
|
||||
* hide broken image crop tool ([#12792](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12737))
|
||||
* don't show hidden samplers in dropdown for XYZ script ([#12780](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12737))
|
||||
* fix style editing dialog breaking if it's opened in both img2img and txt2img tabs
|
||||
* fix a bug allowing users to bypass gradio and API authentication (reported by vysecurity)
|
||||
* fix notification not playing when built-in webui tab is inactive ([#12834](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12834))
|
||||
* honor `--skip-install` for extension installers ([#12832](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12832))
|
||||
* don't print blank stdout in extension installers ([#12833](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12832), [#12855](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12855))
|
||||
* do not change quicksettings dropdown option when value returned is `None` ([#12854](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12854))
|
||||
* get progressbar to display correctly in extensions tab
|
||||
|
||||
|
||||
## 1.5.2
|
||||
|
||||
@@ -88,7 +88,7 @@ A browser interface based on Gradio library for Stable Diffusion.
|
||||
- [Alt-Diffusion](https://arxiv.org/abs/2211.06679) support - see [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#alt-diffusion) for instructions
|
||||
- Now without any bad letters!
|
||||
- Load checkpoints in safetensors format
|
||||
- Eased resolution restriction: generated image's dimension must be a multiple of 8 rather than 64
|
||||
- Eased resolution restriction: generated image's dimensions must be a multiple of 8 rather than 64
|
||||
- Now with a license!
|
||||
- Reorder elements in the UI from settings screen
|
||||
|
||||
@@ -103,7 +103,7 @@ Alternatively, use online services (like Google Colab):
|
||||
- [List of Online Services](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Online-Services)
|
||||
|
||||
### Installation on Windows 10/11 with NVidia-GPUs using release package
|
||||
1. Download `sd.webui.zip` from [v1.0.0-pre](https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/tag/v1.0.0-pre) and extract it's contents.
|
||||
1. Download `sd.webui.zip` from [v1.0.0-pre](https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/tag/v1.0.0-pre) and extract its contents.
|
||||
2. Run `update.bat`.
|
||||
3. Run `run.bat`.
|
||||
> For more details see [Install-and-Run-on-NVidia-GPUs](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs)
|
||||
|
||||
@@ -418,6 +418,7 @@ def network_forward(module, input, original_forward):
|
||||
def network_reset_cached_weight(self: Union[torch.nn.Conv2d, torch.nn.Linear]):
|
||||
self.network_current_names = ()
|
||||
self.network_weights_backup = None
|
||||
self.network_bias_backup = None
|
||||
|
||||
|
||||
def network_Linear_forward(self, input):
|
||||
|
||||
@@ -70,6 +70,7 @@ class LoraUserMetadataEditor(ui_extra_networks_user_metadata.UserMetadataEditor)
|
||||
metadata = item.get("metadata") or {}
|
||||
|
||||
keys = {
|
||||
'ss_output_name': "Output name:",
|
||||
'ss_sd_model_name': "Model:",
|
||||
'ss_clip_skip': "Clip skip:",
|
||||
'ss_network_module': "Kohya module:",
|
||||
|
||||
@@ -385,6 +385,8 @@ onUiLoaded(async() => {
|
||||
targetElement.style.overflow = "hidden";
|
||||
}
|
||||
|
||||
targetElement.isZoomed = false;
|
||||
|
||||
fixCanvas();
|
||||
targetElement.style.transform = `scale(${elemData[elemId].zoomLevel}) translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px)`;
|
||||
|
||||
@@ -479,7 +481,7 @@ onUiLoaded(async() => {
|
||||
|
||||
// Update the zoom level and pan position of the target element based on the values of the zoomLevel, panX and panY variables
|
||||
function updateZoom(newZoomLevel, mouseX, mouseY) {
|
||||
newZoomLevel = Math.max(0.5, Math.min(newZoomLevel, 15));
|
||||
newZoomLevel = Math.max(0.1, Math.min(newZoomLevel, 15));
|
||||
|
||||
elemData[elemId].panX +=
|
||||
mouseX - (mouseX * newZoomLevel) / elemData[elemId].zoomLevel;
|
||||
@@ -520,6 +522,8 @@ onUiLoaded(async() => {
|
||||
zoomPosX - targetElement.getBoundingClientRect().left,
|
||||
zoomPosY - targetElement.getBoundingClientRect().top
|
||||
);
|
||||
|
||||
targetElement.isZoomed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,17 +600,16 @@ onUiLoaded(async() => {
|
||||
`${elemId} canvas[key="interface"]`
|
||||
);
|
||||
|
||||
if (isExtension) {
|
||||
targetElement.style.overflow = "visible";
|
||||
}
|
||||
|
||||
|
||||
if (!canvas) return;
|
||||
|
||||
if (canvas.offsetWidth > 862 || isExtension) {
|
||||
targetElement.style.width = (canvas.offsetWidth + 2) + "px";
|
||||
}
|
||||
|
||||
if (isExtension) {
|
||||
targetElement.style.overflow = "visible";
|
||||
}
|
||||
|
||||
if (fullScreenMode) {
|
||||
resetZoom();
|
||||
fullScreenMode = false;
|
||||
@@ -867,7 +870,40 @@ onUiLoaded(async() => {
|
||||
isMoving = false;
|
||||
};
|
||||
|
||||
// Checks for extension
|
||||
function checkForOutBox() {
|
||||
const parentElement = targetElement.closest('[id^="component-"]');
|
||||
if (parentElement.offsetWidth < targetElement.offsetWidth && !targetElement.isExpanded) {
|
||||
resetZoom();
|
||||
targetElement.isExpanded = true;
|
||||
}
|
||||
|
||||
if (parentElement.offsetWidth < targetElement.offsetWidth && elemData[elemId].zoomLevel == 1) {
|
||||
resetZoom();
|
||||
}
|
||||
|
||||
if (parentElement.offsetWidth < targetElement.offsetWidth && targetElement.offsetWidth * elemData[elemId].zoomLevel > parentElement.offsetWidth && elemData[elemId].zoomLevel < 1 && !targetElement.isZoomed) {
|
||||
resetZoom();
|
||||
}
|
||||
}
|
||||
|
||||
if (isExtension) {
|
||||
targetElement.addEventListener("mousemove", checkForOutBox);
|
||||
}
|
||||
|
||||
|
||||
window.addEventListener('resize', (e) => {
|
||||
resetZoom();
|
||||
|
||||
if (isExtension) {
|
||||
targetElement.isExpanded = false;
|
||||
targetElement.isZoomed = false;
|
||||
}
|
||||
});
|
||||
|
||||
gradioApp().addEventListener("mousemove", handleMoveByKey);
|
||||
|
||||
|
||||
}
|
||||
|
||||
applyZoomAndPan(elementIDs.sketch, false);
|
||||
|
||||
Vendored
+1
-1
@@ -119,7 +119,7 @@ window.addEventListener('paste', e => {
|
||||
}
|
||||
|
||||
const firstFreeImageField = visibleImageFields
|
||||
.filter(el => el.querySelector('input[type=file]'))?.[0];
|
||||
.filter(el => !el.querySelector('img'))?.[0];
|
||||
|
||||
dropReplaceImage(
|
||||
firstFreeImageField ?
|
||||
|
||||
@@ -18,22 +18,11 @@ function keyupEditAttention(event) {
|
||||
const before = text.substring(0, selectionStart);
|
||||
let beforeParen = before.lastIndexOf(OPEN);
|
||||
if (beforeParen == -1) return false;
|
||||
let beforeParenClose = before.lastIndexOf(CLOSE);
|
||||
while (beforeParenClose !== -1 && beforeParenClose > beforeParen) {
|
||||
beforeParen = before.lastIndexOf(OPEN, beforeParen - 1);
|
||||
beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1);
|
||||
}
|
||||
|
||||
// Find closing parenthesis around current cursor
|
||||
const after = text.substring(selectionStart);
|
||||
let afterParen = after.indexOf(CLOSE);
|
||||
if (afterParen == -1) return false;
|
||||
let afterParenOpen = after.indexOf(OPEN);
|
||||
while (afterParenOpen !== -1 && afterParen > afterParenOpen) {
|
||||
afterParen = after.indexOf(CLOSE, afterParen + 1);
|
||||
afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1);
|
||||
}
|
||||
if (beforeParen === -1 || afterParen === -1) return false;
|
||||
|
||||
// Set the selection to the text between the parenthesis
|
||||
const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen);
|
||||
@@ -46,9 +35,14 @@ function keyupEditAttention(event) {
|
||||
|
||||
function selectCurrentWord() {
|
||||
if (selectionStart !== selectionEnd) return false;
|
||||
const delimiters = opts.keyedit_delimiters + " \r\n\t";
|
||||
const whitespace_delimiters = {"Tab": "\t", "Carriage Return": "\r", "Line Feed": "\n"};
|
||||
let delimiters = opts.keyedit_delimiters;
|
||||
|
||||
// seek backward until to find beggining
|
||||
for (let i of opts.keyedit_delimiters_whitespace) {
|
||||
delimiters += whitespace_delimiters[i];
|
||||
}
|
||||
|
||||
// seek backward to find beginning
|
||||
while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) {
|
||||
selectionStart--;
|
||||
}
|
||||
@@ -92,7 +86,7 @@ function keyupEditAttention(event) {
|
||||
}
|
||||
|
||||
var end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;
|
||||
var weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end));
|
||||
var weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + end));
|
||||
if (isNaN(weight)) return;
|
||||
|
||||
weight += isPlus ? delta : -delta;
|
||||
|
||||
@@ -33,7 +33,7 @@ function extensions_check() {
|
||||
|
||||
|
||||
var id = randomId();
|
||||
requestProgress(id, gradioApp().getElementById('extensions_installed_top'), null, function() {
|
||||
requestProgress(id, gradioApp().getElementById('extensions_installed_html'), null, function() {
|
||||
|
||||
});
|
||||
|
||||
|
||||
+23
-11
@@ -140,14 +140,15 @@ function setupExtraNetworks() {
|
||||
|
||||
onUiLoaded(setupExtraNetworks);
|
||||
|
||||
var re_extranet = /<([^:]+:[^:]+):[\d.]+>(.*)/;
|
||||
var re_extranet_g = /\s+<([^:]+:[^:]+):[\d.]+>/g;
|
||||
var re_extranet = /<([^:^>]+:[^:]+):[\d.]+>(.*)/;
|
||||
var re_extranet_g = /<([^:^>]+:[^:]+):[\d.]+>/g;
|
||||
|
||||
function tryToRemoveExtraNetworkFromPrompt(textarea, text) {
|
||||
var m = text.match(re_extranet);
|
||||
var replaced = false;
|
||||
var newTextareaText;
|
||||
if (m) {
|
||||
var extraTextBeforeNet = opts.extra_networks_add_text_separator;
|
||||
var extraTextAfterNet = m[2];
|
||||
var partToSearch = m[1];
|
||||
var foundAtPosition = -1;
|
||||
@@ -161,8 +162,13 @@ function tryToRemoveExtraNetworkFromPrompt(textarea, text) {
|
||||
return found;
|
||||
});
|
||||
|
||||
if (foundAtPosition >= 0 && newTextareaText.substr(foundAtPosition, extraTextAfterNet.length) == extraTextAfterNet) {
|
||||
newTextareaText = newTextareaText.substr(0, foundAtPosition) + newTextareaText.substr(foundAtPosition + extraTextAfterNet.length);
|
||||
if (foundAtPosition >= 0) {
|
||||
if (newTextareaText.substr(foundAtPosition, extraTextAfterNet.length) == extraTextAfterNet) {
|
||||
newTextareaText = newTextareaText.substr(0, foundAtPosition) + newTextareaText.substr(foundAtPosition + extraTextAfterNet.length);
|
||||
}
|
||||
if (newTextareaText.substr(foundAtPosition - extraTextBeforeNet.length, extraTextBeforeNet.length) == extraTextBeforeNet) {
|
||||
newTextareaText = newTextareaText.substr(0, foundAtPosition - extraTextBeforeNet.length) + newTextareaText.substr(foundAtPosition);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newTextareaText = textarea.value.replaceAll(new RegExp(text, "g"), function(found) {
|
||||
@@ -216,27 +222,24 @@ function extraNetworksSearchButton(tabs_id, event) {
|
||||
|
||||
var globalPopup = null;
|
||||
var globalPopupInner = null;
|
||||
|
||||
function closePopup() {
|
||||
if (!globalPopup) return;
|
||||
|
||||
globalPopup.style.display = "none";
|
||||
}
|
||||
|
||||
function popup(contents) {
|
||||
if (!globalPopup) {
|
||||
globalPopup = document.createElement('div');
|
||||
globalPopup.onclick = closePopup;
|
||||
globalPopup.classList.add('global-popup');
|
||||
|
||||
var close = document.createElement('div');
|
||||
close.classList.add('global-popup-close');
|
||||
close.onclick = closePopup;
|
||||
close.addEventListener("click", closePopup);
|
||||
close.title = "Close";
|
||||
globalPopup.appendChild(close);
|
||||
|
||||
globalPopupInner = document.createElement('div');
|
||||
globalPopupInner.onclick = function(event) {
|
||||
event.stopPropagation(); return false;
|
||||
};
|
||||
globalPopupInner.classList.add('global-popup-inner');
|
||||
globalPopup.appendChild(globalPopupInner);
|
||||
|
||||
@@ -249,6 +252,15 @@ function popup(contents) {
|
||||
globalPopup.style.display = "flex";
|
||||
}
|
||||
|
||||
var storedPopupIds = {};
|
||||
function popupId(id) {
|
||||
if (!storedPopupIds[id]) {
|
||||
storedPopupIds[id] = gradioApp().getElementById(id);
|
||||
}
|
||||
|
||||
popup(storedPopupIds[id]);
|
||||
}
|
||||
|
||||
function extraNetworksShowMetadata(text) {
|
||||
var elem = document.createElement('pre');
|
||||
elem.classList.add('popup-metadata');
|
||||
@@ -326,7 +338,7 @@ function extraNetworksEditUserMetadata(event, tabname, extraPage, cardName) {
|
||||
function extraNetworksRefreshSingleCard(page, tabname, name) {
|
||||
requestGet("./sd_extra_networks/get-single-card", {page: page, tabname: tabname, name: name}, function(data) {
|
||||
if (data && data.html) {
|
||||
var card = gradioApp().querySelector('.card[data-name=' + JSON.stringify(name) + ']'); // likely using the wrong stringify function
|
||||
var card = gradioApp().querySelector(`#${tabname}_${page.replace(" ", "_")}_cards > .card[data-name="${name}"]`);
|
||||
|
||||
var newDiv = document.createElement('DIV');
|
||||
newDiv.innerHTML = data.html;
|
||||
|
||||
@@ -15,7 +15,7 @@ onAfterUiUpdate(function() {
|
||||
}
|
||||
}
|
||||
|
||||
const galleryPreviews = gradioApp().querySelectorAll('div[id^="tab_"][style*="display: block"] div[id$="_results"] .thumbnail-item > img');
|
||||
const galleryPreviews = gradioApp().querySelectorAll('div[id^="tab_"] div[id$="_results"] .thumbnail-item > img');
|
||||
|
||||
if (galleryPreviews == null) return;
|
||||
|
||||
|
||||
@@ -134,6 +134,8 @@
|
||||
|
||||
onUiLoaded(function() {
|
||||
for (var elem of gradioApp().querySelectorAll('.resize-handle-row')) {
|
||||
setupResizeHandle(elem);
|
||||
if (!elem.querySelector('.resize-handle')) {
|
||||
setupResizeHandle(elem);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
let settingsExcludeTabsFromShowAll = {
|
||||
settings_tab_defaults: 1,
|
||||
settings_tab_sysinfo: 1,
|
||||
settings_tab_actions: 1,
|
||||
settings_tab_licenses: 1,
|
||||
};
|
||||
|
||||
function settingsShowAllTabs() {
|
||||
gradioApp().querySelectorAll('#settings > div').forEach(function(elem) {
|
||||
if (settingsExcludeTabsFromShowAll[elem.id]) return;
|
||||
|
||||
elem.style.display = "block";
|
||||
});
|
||||
}
|
||||
|
||||
function settingsShowOneTab() {
|
||||
gradioApp().querySelector('#settings_show_one_page').click();
|
||||
}
|
||||
|
||||
onUiLoaded(function() {
|
||||
var edit = gradioApp().querySelector('#settings_search');
|
||||
var editTextarea = gradioApp().querySelector('#settings_search > label > input');
|
||||
var buttonShowAllPages = gradioApp().getElementById('settings_show_all_pages');
|
||||
var settings_tabs = gradioApp().querySelector('#settings div');
|
||||
|
||||
onEdit('settingsSearch', editTextarea, 250, function() {
|
||||
var searchText = (editTextarea.value || "").trim().toLowerCase();
|
||||
|
||||
gradioApp().querySelectorAll('#settings > div[id^=settings_] div[id^=column_settings_] > *').forEach(function(elem) {
|
||||
var visible = elem.textContent.trim().toLowerCase().indexOf(searchText) != -1;
|
||||
elem.style.display = visible ? "" : "none";
|
||||
});
|
||||
|
||||
if (searchText != "") {
|
||||
settingsShowAllTabs();
|
||||
} else {
|
||||
settingsShowOneTab();
|
||||
}
|
||||
});
|
||||
|
||||
settings_tabs.insertBefore(edit, settings_tabs.firstChild);
|
||||
settings_tabs.appendChild(buttonShowAllPages);
|
||||
|
||||
|
||||
buttonShowAllPages.addEventListener("click", settingsShowAllTabs);
|
||||
});
|
||||
@@ -1,10 +1,9 @@
|
||||
let promptTokenCountDebounceTime = 800;
|
||||
let promptTokenCountTimeouts = {};
|
||||
var promptTokenCountUpdateFunctions = {};
|
||||
let promptTokenCountUpdateFunctions = {};
|
||||
|
||||
function update_txt2img_tokens(...args) {
|
||||
// Called from Gradio
|
||||
update_token_counter("txt2img_token_button");
|
||||
update_token_counter("txt2img_negative_token_button");
|
||||
if (args.length == 2) {
|
||||
return args[0];
|
||||
}
|
||||
@@ -14,6 +13,7 @@ function update_txt2img_tokens(...args) {
|
||||
function update_img2img_tokens(...args) {
|
||||
// Called from Gradio
|
||||
update_token_counter("img2img_token_button");
|
||||
update_token_counter("img2img_negative_token_button");
|
||||
if (args.length == 2) {
|
||||
return args[0];
|
||||
}
|
||||
@@ -21,16 +21,7 @@ function update_img2img_tokens(...args) {
|
||||
}
|
||||
|
||||
function update_token_counter(button_id) {
|
||||
if (opts.disable_token_counters) {
|
||||
return;
|
||||
}
|
||||
if (promptTokenCountTimeouts[button_id]) {
|
||||
clearTimeout(promptTokenCountTimeouts[button_id]);
|
||||
}
|
||||
promptTokenCountTimeouts[button_id] = setTimeout(
|
||||
() => gradioApp().getElementById(button_id)?.click(),
|
||||
promptTokenCountDebounceTime,
|
||||
);
|
||||
promptTokenCountUpdateFunctions[button_id]?.();
|
||||
}
|
||||
|
||||
|
||||
@@ -69,10 +60,11 @@ function setupTokenCounting(id, id_counter, id_button) {
|
||||
prompt.parentElement.insertBefore(counter, prompt);
|
||||
prompt.parentElement.style.position = "relative";
|
||||
|
||||
promptTokenCountUpdateFunctions[id] = function() {
|
||||
update_token_counter(id_button);
|
||||
};
|
||||
textarea.addEventListener("input", promptTokenCountUpdateFunctions[id]);
|
||||
var func = onEdit(id, textarea, 800, function() {
|
||||
gradioApp().getElementById(id_button)?.click();
|
||||
});
|
||||
promptTokenCountUpdateFunctions[id] = func;
|
||||
promptTokenCountUpdateFunctions[id_button] = func;
|
||||
}
|
||||
|
||||
function setupTokenCounters() {
|
||||
|
||||
+17
-15
@@ -263,21 +263,6 @@ onAfterUiUpdate(function() {
|
||||
json_elem.parentElement.style.display = "none";
|
||||
|
||||
setupTokenCounters();
|
||||
|
||||
var show_all_pages = gradioApp().getElementById('settings_show_all_pages');
|
||||
var settings_tabs = gradioApp().querySelector('#settings div');
|
||||
if (show_all_pages && settings_tabs) {
|
||||
settings_tabs.appendChild(show_all_pages);
|
||||
show_all_pages.onclick = function() {
|
||||
gradioApp().querySelectorAll('#settings > div').forEach(function(elem) {
|
||||
if (elem.id == "settings_tab_licenses") {
|
||||
return;
|
||||
}
|
||||
|
||||
elem.style.display = "block";
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
onOptionsChanged(function() {
|
||||
@@ -366,3 +351,20 @@ function switchWidthHeight(tabname) {
|
||||
updateInput(height);
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
var onEditTimers = {};
|
||||
|
||||
// calls func after afterMs milliseconds has passed since the input elem has beed enited by user
|
||||
function onEdit(editId, elem, afterMs, func) {
|
||||
var edited = function() {
|
||||
var existingTimer = onEditTimers[editId];
|
||||
if (existingTimer) clearTimeout(existingTimer);
|
||||
|
||||
onEditTimers[editId] = setTimeout(func, afterMs);
|
||||
};
|
||||
|
||||
elem.addEventListener("input", edited);
|
||||
|
||||
return edited;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,13 @@ start = launch_utils.start
|
||||
|
||||
|
||||
def main():
|
||||
if args.dump_sysinfo:
|
||||
filename = launch_utils.dump_sysinfo()
|
||||
|
||||
print(f"Sysinfo saved as {filename}. Exiting...")
|
||||
|
||||
exit(0)
|
||||
|
||||
launch_utils.startup_timer.record("initial startup")
|
||||
|
||||
with launch_utils.startup_timer.subcategory("prepare environment"):
|
||||
|
||||
+36
-18
@@ -17,7 +17,7 @@ from fastapi.encoders import jsonable_encoder
|
||||
from secrets import compare_digest
|
||||
|
||||
import modules.shared as shared
|
||||
from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart, shared_items
|
||||
from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart, shared_items, script_callbacks, generation_parameters_copypaste
|
||||
from modules.api import models
|
||||
from modules.shared import opts
|
||||
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
|
||||
@@ -29,7 +29,7 @@ from modules.sd_models import unload_model_weights, reload_model_weights, checkp
|
||||
from modules.sd_models_config import find_checkpoint_config_near_filename
|
||||
from modules.realesrgan_model import get_realesrgan_models
|
||||
from modules import devices
|
||||
from typing import Dict, List, Any
|
||||
from typing import Any
|
||||
import piexif
|
||||
import piexif.helper
|
||||
from contextlib import closing
|
||||
@@ -221,15 +221,15 @@ class Api:
|
||||
self.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=models.OptionsModel)
|
||||
self.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"])
|
||||
self.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=models.FlagsModel)
|
||||
self.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=List[models.SamplerItem])
|
||||
self.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=List[models.UpscalerItem])
|
||||
self.add_api_route("/sdapi/v1/latent-upscale-modes", self.get_latent_upscale_modes, methods=["GET"], response_model=List[models.LatentUpscalerModeItem])
|
||||
self.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=List[models.SDModelItem])
|
||||
self.add_api_route("/sdapi/v1/sd-vae", self.get_sd_vaes, methods=["GET"], response_model=List[models.SDVaeItem])
|
||||
self.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=List[models.HypernetworkItem])
|
||||
self.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=List[models.FaceRestorerItem])
|
||||
self.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=List[models.RealesrganItem])
|
||||
self.add_api_route("/sdapi/v1/prompt-styles", self.get_prompt_styles, methods=["GET"], response_model=List[models.PromptStyleItem])
|
||||
self.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=list[models.SamplerItem])
|
||||
self.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=list[models.UpscalerItem])
|
||||
self.add_api_route("/sdapi/v1/latent-upscale-modes", self.get_latent_upscale_modes, methods=["GET"], response_model=list[models.LatentUpscalerModeItem])
|
||||
self.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=list[models.SDModelItem])
|
||||
self.add_api_route("/sdapi/v1/sd-vae", self.get_sd_vaes, methods=["GET"], response_model=list[models.SDVaeItem])
|
||||
self.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=list[models.HypernetworkItem])
|
||||
self.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=list[models.FaceRestorerItem])
|
||||
self.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=list[models.RealesrganItem])
|
||||
self.add_api_route("/sdapi/v1/prompt-styles", self.get_prompt_styles, methods=["GET"], response_model=list[models.PromptStyleItem])
|
||||
self.add_api_route("/sdapi/v1/embeddings", self.get_embeddings, methods=["GET"], response_model=models.EmbeddingsResponse)
|
||||
self.add_api_route("/sdapi/v1/refresh-checkpoints", self.refresh_checkpoints, methods=["POST"])
|
||||
self.add_api_route("/sdapi/v1/refresh-vae", self.refresh_vae, methods=["POST"])
|
||||
@@ -242,7 +242,8 @@ class Api:
|
||||
self.add_api_route("/sdapi/v1/unload-checkpoint", self.unloadapi, methods=["POST"])
|
||||
self.add_api_route("/sdapi/v1/reload-checkpoint", self.reloadapi, methods=["POST"])
|
||||
self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=models.ScriptsList)
|
||||
self.add_api_route("/sdapi/v1/script-info", self.get_script_info, methods=["GET"], response_model=List[models.ScriptInfo])
|
||||
self.add_api_route("/sdapi/v1/script-info", self.get_script_info, methods=["GET"], response_model=list[models.ScriptInfo])
|
||||
self.add_api_route("/sdapi/v1/extensions", self.get_extensions_list, methods=["GET"], response_model=list[models.ExtensionItem])
|
||||
|
||||
if shared.cmd_opts.api_server_stop:
|
||||
self.add_api_route("/sdapi/v1/server-kill", self.kill_webui, methods=["POST"])
|
||||
@@ -473,9 +474,6 @@ class Api:
|
||||
return models.ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1])
|
||||
|
||||
def pnginfoapi(self, req: models.PNGInfoRequest):
|
||||
if(not req.image.strip()):
|
||||
return models.PNGInfoResponse(info="")
|
||||
|
||||
image = decode_base64_to_image(req.image.strip())
|
||||
if image is None:
|
||||
return models.PNGInfoResponse(info="")
|
||||
@@ -484,9 +482,10 @@ class Api:
|
||||
if geninfo is None:
|
||||
geninfo = ""
|
||||
|
||||
items = {**{'parameters': geninfo}, **items}
|
||||
params = generation_parameters_copypaste.parse_generation_parameters(geninfo)
|
||||
script_callbacks.infotext_pasted_callback(geninfo, params)
|
||||
|
||||
return models.PNGInfoResponse(info=geninfo, items=items)
|
||||
return models.PNGInfoResponse(info=geninfo, items=items, parameters=params)
|
||||
|
||||
def progressapi(self, req: models.ProgressRequest = Depends()):
|
||||
# copy from check_progress_call of ui.py
|
||||
@@ -564,7 +563,7 @@ class Api:
|
||||
|
||||
return options
|
||||
|
||||
def set_config(self, req: Dict[str, Any]):
|
||||
def set_config(self, req: dict[str, Any]):
|
||||
checkpoint_name = req.get("sd_model_checkpoint", None)
|
||||
if checkpoint_name is not None and checkpoint_name not in checkpoint_aliases:
|
||||
raise RuntimeError(f"model {checkpoint_name!r} not found")
|
||||
@@ -770,6 +769,25 @@ class Api:
|
||||
cuda = {'error': f'{err}'}
|
||||
return models.MemoryResponse(ram=ram, cuda=cuda)
|
||||
|
||||
def get_extensions_list(self):
|
||||
from modules import extensions
|
||||
extensions.list_extensions()
|
||||
ext_list = []
|
||||
for ext in extensions.extensions:
|
||||
ext: extensions.Extension
|
||||
ext.read_info_from_repo()
|
||||
if ext.remote is not None:
|
||||
ext_list.append({
|
||||
"name": ext.name,
|
||||
"remote": ext.remote,
|
||||
"branch": ext.branch,
|
||||
"commit_hash":ext.commit_hash,
|
||||
"commit_date":ext.commit_date,
|
||||
"version":ext.version,
|
||||
"enabled":ext.enabled
|
||||
})
|
||||
return ext_list
|
||||
|
||||
def launch(self, server_name, port, root_path):
|
||||
self.app.include_router(self.router)
|
||||
uvicorn.run(self.app, host=server_name, port=port, timeout_keep_alive=shared.cmd_opts.timeout_keep_alive, root_path=root_path)
|
||||
|
||||
+22
-14
@@ -1,12 +1,10 @@
|
||||
import inspect
|
||||
|
||||
from pydantic import BaseModel, Field, create_model
|
||||
from typing import Any, Optional
|
||||
from typing_extensions import Literal
|
||||
from typing import Any, Optional, Literal
|
||||
from inflection import underscore
|
||||
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img
|
||||
from modules.shared import sd_upscalers, opts, parser
|
||||
from typing import Dict, List
|
||||
|
||||
API_NOT_ALLOWED = [
|
||||
"self",
|
||||
@@ -130,12 +128,12 @@ StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator(
|
||||
).generate_model()
|
||||
|
||||
class TextToImageResponse(BaseModel):
|
||||
images: List[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
|
||||
images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
|
||||
parameters: dict
|
||||
info: str
|
||||
|
||||
class ImageToImageResponse(BaseModel):
|
||||
images: List[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
|
||||
images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
|
||||
parameters: dict
|
||||
info: str
|
||||
|
||||
@@ -168,17 +166,18 @@ class FileData(BaseModel):
|
||||
name: str = Field(title="File name")
|
||||
|
||||
class ExtrasBatchImagesRequest(ExtrasBaseRequest):
|
||||
imageList: List[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings")
|
||||
imageList: list[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings")
|
||||
|
||||
class ExtrasBatchImagesResponse(ExtraBaseResponse):
|
||||
images: List[str] = Field(title="Images", description="The generated images in base64 format.")
|
||||
images: list[str] = Field(title="Images", description="The generated images in base64 format.")
|
||||
|
||||
class PNGInfoRequest(BaseModel):
|
||||
image: str = Field(title="Image", description="The base64 encoded PNG image")
|
||||
|
||||
class PNGInfoResponse(BaseModel):
|
||||
info: str = Field(title="Image info", description="A string with the parameters used to generate the image")
|
||||
items: dict = Field(title="Items", description="An object containing all the info the image had")
|
||||
items: dict = Field(title="Items", description="A dictionary containing all the other fields the image had")
|
||||
parameters: dict = Field(title="Parameters", description="A dictionary with parsed generation info fields")
|
||||
|
||||
class ProgressRequest(BaseModel):
|
||||
skip_current_image: bool = Field(default=False, title="Skip current image", description="Skip current image serialization")
|
||||
@@ -232,8 +231,8 @@ FlagsModel = create_model("Flags", **flags)
|
||||
|
||||
class SamplerItem(BaseModel):
|
||||
name: str = Field(title="Name")
|
||||
aliases: List[str] = Field(title="Aliases")
|
||||
options: Dict[str, str] = Field(title="Options")
|
||||
aliases: list[str] = Field(title="Aliases")
|
||||
options: dict[str, str] = Field(title="Options")
|
||||
|
||||
class UpscalerItem(BaseModel):
|
||||
name: str = Field(title="Name")
|
||||
@@ -284,8 +283,8 @@ class EmbeddingItem(BaseModel):
|
||||
vectors: int = Field(title="Vectors", description="The number of vectors in the embedding")
|
||||
|
||||
class EmbeddingsResponse(BaseModel):
|
||||
loaded: Dict[str, EmbeddingItem] = Field(title="Loaded", description="Embeddings loaded for the current model")
|
||||
skipped: Dict[str, EmbeddingItem] = Field(title="Skipped", description="Embeddings skipped for the current model (likely due to architecture incompatibility)")
|
||||
loaded: dict[str, EmbeddingItem] = Field(title="Loaded", description="Embeddings loaded for the current model")
|
||||
skipped: dict[str, EmbeddingItem] = Field(title="Skipped", description="Embeddings skipped for the current model (likely due to architecture incompatibility)")
|
||||
|
||||
class MemoryResponse(BaseModel):
|
||||
ram: dict = Field(title="RAM", description="System memory stats")
|
||||
@@ -303,11 +302,20 @@ class ScriptArg(BaseModel):
|
||||
minimum: Optional[Any] = Field(default=None, title="Minimum", description="Minimum allowed value for the argumentin UI")
|
||||
maximum: Optional[Any] = Field(default=None, title="Minimum", description="Maximum allowed value for the argumentin UI")
|
||||
step: Optional[Any] = Field(default=None, title="Minimum", description="Step for changing value of the argumentin UI")
|
||||
choices: Optional[List[str]] = Field(default=None, title="Choices", description="Possible values for the argument")
|
||||
choices: Optional[list[str]] = Field(default=None, title="Choices", description="Possible values for the argument")
|
||||
|
||||
|
||||
class ScriptInfo(BaseModel):
|
||||
name: str = Field(default=None, title="Name", description="Script name")
|
||||
is_alwayson: bool = Field(default=None, title="IsAlwayson", description="Flag specifying whether this script is an alwayson script")
|
||||
is_img2img: bool = Field(default=None, title="IsImg2img", description="Flag specifying whether this script is an img2img script")
|
||||
args: List[ScriptArg] = Field(title="Arguments", description="List of script's arguments")
|
||||
args: list[ScriptArg] = Field(title="Arguments", description="List of script's arguments")
|
||||
|
||||
class ExtensionItem(BaseModel):
|
||||
name: str = Field(title="Name", description="Extension name")
|
||||
remote: str = Field(title="Remote", description="Extension Repository URL")
|
||||
branch: str = Field(title="Branch", description="Extension Repository Branch")
|
||||
commit_hash: str = Field(title="Commit Hash", description="Extension Repository Commit Hash")
|
||||
version: str = Field(title="Version", description="Extension Version")
|
||||
commit_date: str = Field(title="Commit Date", description="Extension Repository Commit Date")
|
||||
enabled: bool = Field(title="Enabled", description="Flag specifying whether this extension is enabled")
|
||||
|
||||
+5
-3
@@ -16,6 +16,7 @@ parser.add_argument("--test-server", action='store_true', help="launch.py argume
|
||||
parser.add_argument("--log-startup", action='store_true', help="launch.py argument: print a detailed log of what's happening at startup")
|
||||
parser.add_argument("--skip-prepare-environment", action='store_true', help="launch.py argument: skip all environment preparation")
|
||||
parser.add_argument("--skip-install", action='store_true', help="launch.py argument: skip installation of packages")
|
||||
parser.add_argument("--dump-sysinfo", action='store_true', help="launch.py argument: dump limited sysinfo file (without information about extensions, options) to disk and quit")
|
||||
parser.add_argument("--loglevel", type=str, help="log level; one of: CRITICAL, ERROR, WARNING, INFO, DEBUG", default=None)
|
||||
parser.add_argument("--do-not-download-clip", action='store_true', help="do not download CLIP model even if it's not included in the checkpoint")
|
||||
parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="base path where all user data is stored")
|
||||
@@ -89,7 +90,7 @@ parser.add_argument("--autolaunch", action='store_true', help="open the webui UR
|
||||
parser.add_argument("--theme", type=str, help="launches the UI with light or dark theme", default=None)
|
||||
parser.add_argument("--use-textbox-seed", action='store_true', help="use textbox for seeds in UI (no up/down, but possible to input long seeds)", default=False)
|
||||
parser.add_argument("--disable-console-progressbars", action='store_true', help="do not output progressbars to console", default=False)
|
||||
parser.add_argument("--enable-console-prompts", action='store_true', help="print prompts to console when generating with txt2img and img2img", default=False)
|
||||
parser.add_argument("--enable-console-prompts", action='store_true', help="does not do anything", default=False) # Legacy compatibility, use as default value shared.opts.enable_console_prompts
|
||||
parser.add_argument('--vae-path', type=str, help='Checkpoint to use as VAE; setting this argument disables all settings related to VAE', default=None)
|
||||
parser.add_argument("--disable-safe-unpickle", action='store_true', help="disable checking pytorch models for malicious code", default=False)
|
||||
parser.add_argument("--api", action='store_true', help="use api=True to launch the API together with the webui (use --nowebui instead for only the API)")
|
||||
@@ -111,8 +112,9 @@ parser.add_argument("--skip-version-check", action='store_true', help="Do not ch
|
||||
parser.add_argument("--no-hashing", action='store_true', help="disable sha256 hashing of checkpoints to help loading performance", default=False)
|
||||
parser.add_argument("--no-download-sd-model", action='store_true', help="don't download SD1.5 model even if no model is found in --ckpt-dir", default=False)
|
||||
parser.add_argument('--subpath', type=str, help='customize the subpath for gradio, use with reverse proxy')
|
||||
parser.add_argument('--add-stop-route', action='store_true', help='add /_stop route to stop server')
|
||||
parser.add_argument('--add-stop-route', action='store_true', help='does not do anything')
|
||||
parser.add_argument('--api-server-stop', action='store_true', help='enable server stop/restart/kill via api')
|
||||
parser.add_argument('--timeout-keep-alive', type=int, default=30, help='set timeout_keep_alive for uvicorn')
|
||||
parser.add_argument("--disable-all-extensions", action='store_true', help="prevent all extensions from running regardless of any other settings", default=False)
|
||||
parser.add_argument("--disable-extra-extensions", action='store_true', help=" prevent all extensions except built-in from running regardless of any other settings", default=False)
|
||||
parser.add_argument("--disable-extra-extensions", action='store_true', help="prevent all extensions except built-in from running regardless of any other settings", default=False)
|
||||
parser.add_argument("--skip-load-model-at-start", action='store_true', help="if load a model at web start, only take effect when --nowebui", )
|
||||
|
||||
@@ -4,7 +4,6 @@ Supports saving and restoring webui and extensions from a known working set of c
|
||||
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import tqdm
|
||||
|
||||
from datetime import datetime
|
||||
@@ -38,7 +37,7 @@ def list_config_states():
|
||||
config_states = sorted(config_states, key=lambda cs: cs["created_at"], reverse=True)
|
||||
|
||||
for cs in config_states:
|
||||
timestamp = time.asctime(time.gmtime(cs["created_at"]))
|
||||
timestamp = datetime.fromtimestamp(cs["created_at"]).strftime('%Y-%m-%d %H:%M:%S')
|
||||
name = cs.get("name", "Config")
|
||||
full_name = f"{name}: {timestamp}"
|
||||
all_config_states[full_name] = cs
|
||||
|
||||
+2
-1
@@ -60,7 +60,8 @@ def enable_tf32():
|
||||
|
||||
# enabling benchmark option seems to enable a range of cards to do fp16 when they otherwise can't
|
||||
# see https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/4407
|
||||
if any(torch.cuda.get_device_capability(devid) == (7, 5) for devid in range(0, torch.cuda.device_count())):
|
||||
device_id = (int(shared.cmd_opts.device_id) if shared.cmd_opts.device_id is not None and shared.cmd_opts.device_id.isdigit() else 0) or torch.cuda.current_device()
|
||||
if torch.cuda.get_device_capability(device_id) == (7, 5) and torch.cuda.get_device_name(device_id).startswith("NVIDIA GeForce GTX 16"):
|
||||
torch.backends.cudnn.benchmark = True
|
||||
|
||||
torch.backends.cuda.matmul.allow_tf32 = True
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ def check_versions():
|
||||
|
||||
expected_torch_version = "2.0.0"
|
||||
expected_xformers_version = "0.0.20"
|
||||
expected_gradio_version = "3.41.0"
|
||||
expected_gradio_version = "3.41.2"
|
||||
|
||||
if version.parse(torch.__version__) < version.parse(expected_torch_version):
|
||||
print_error_explanation(f"""
|
||||
|
||||
+43
-17
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
|
||||
from modules import errors
|
||||
@@ -86,27 +87,55 @@ class ExtraNetwork:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def lookup_extra_networks(extra_network_data):
|
||||
"""returns a dict mapping ExtraNetwork objects to lists of arguments for those extra networks.
|
||||
|
||||
Example input:
|
||||
{
|
||||
'lora': [<modules.extra_networks.ExtraNetworkParams object at 0x0000020690D58310>],
|
||||
'lyco': [<modules.extra_networks.ExtraNetworkParams object at 0x0000020690D58F70>],
|
||||
'hypernet': [<modules.extra_networks.ExtraNetworkParams object at 0x0000020690D5A800>]
|
||||
}
|
||||
|
||||
Example output:
|
||||
|
||||
{
|
||||
<extra_networks_lora.ExtraNetworkLora object at 0x0000020581BEECE0>: [<modules.extra_networks.ExtraNetworkParams object at 0x0000020690D58310>, <modules.extra_networks.ExtraNetworkParams object at 0x0000020690D58F70>],
|
||||
<modules.extra_networks_hypernet.ExtraNetworkHypernet object at 0x0000020581BEEE60>: [<modules.extra_networks.ExtraNetworkParams object at 0x0000020690D5A800>]
|
||||
}
|
||||
"""
|
||||
|
||||
res = {}
|
||||
|
||||
for extra_network_name, extra_network_args in list(extra_network_data.items()):
|
||||
extra_network = extra_network_registry.get(extra_network_name, None)
|
||||
alias = extra_network_aliases.get(extra_network_name, None)
|
||||
|
||||
if alias is not None and extra_network is None:
|
||||
extra_network = alias
|
||||
|
||||
if extra_network is None:
|
||||
logging.info(f"Skipping unknown extra network: {extra_network_name}")
|
||||
continue
|
||||
|
||||
res.setdefault(extra_network, []).extend(extra_network_args)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def activate(p, extra_network_data):
|
||||
"""call activate for extra networks in extra_network_data in specified order, then call
|
||||
activate for all remaining registered networks with an empty argument list"""
|
||||
|
||||
activated = []
|
||||
|
||||
for extra_network_name, extra_network_args in extra_network_data.items():
|
||||
extra_network = extra_network_registry.get(extra_network_name, None)
|
||||
|
||||
if extra_network is None:
|
||||
extra_network = extra_network_aliases.get(extra_network_name, None)
|
||||
|
||||
if extra_network is None:
|
||||
print(f"Skipping unknown extra network: {extra_network_name}")
|
||||
continue
|
||||
for extra_network, extra_network_args in lookup_extra_networks(extra_network_data).items():
|
||||
|
||||
try:
|
||||
extra_network.activate(p, extra_network_args)
|
||||
activated.append(extra_network)
|
||||
except Exception as e:
|
||||
errors.display(e, f"activating extra network {extra_network_name} with arguments {extra_network_args}")
|
||||
errors.display(e, f"activating extra network {extra_network.name} with arguments {extra_network_args}")
|
||||
|
||||
for extra_network_name, extra_network in extra_network_registry.items():
|
||||
if extra_network in activated:
|
||||
@@ -125,19 +154,16 @@ def deactivate(p, extra_network_data):
|
||||
"""call deactivate for extra networks in extra_network_data in specified order, then call
|
||||
deactivate for all remaining registered networks"""
|
||||
|
||||
for extra_network_name in extra_network_data:
|
||||
extra_network = extra_network_registry.get(extra_network_name, None)
|
||||
if extra_network is None:
|
||||
continue
|
||||
data = lookup_extra_networks(extra_network_data)
|
||||
|
||||
for extra_network in data:
|
||||
try:
|
||||
extra_network.deactivate(p)
|
||||
except Exception as e:
|
||||
errors.display(e, f"deactivating extra network {extra_network_name}")
|
||||
errors.display(e, f"deactivating extra network {extra_network.name}")
|
||||
|
||||
for extra_network_name, extra_network in extra_network_registry.items():
|
||||
args = extra_network_data.get(extra_network_name, None)
|
||||
if args is not None:
|
||||
if extra_network in data:
|
||||
continue
|
||||
|
||||
try:
|
||||
|
||||
@@ -9,7 +9,7 @@ from modules.paths import data_path
|
||||
from modules import shared, ui_tempdir, script_callbacks, processing
|
||||
from PIL import Image
|
||||
|
||||
re_param_code = r'\s*([\w ]+):\s*("(?:\\"[^,]|\\"|\\|[^\"])+"|[^,]*)(?:,|$)'
|
||||
re_param_code = r'\s*(\w[\w \-/]+):\s*("(?:\\.|[^\\"])+"|[^,]*)(?:,|$)'
|
||||
re_param = re.compile(re_param_code)
|
||||
re_imagesize = re.compile(r"^(\d+)x(\d+)$")
|
||||
re_hypernet_hash = re.compile("\(([0-9a-f]+)\)$")
|
||||
@@ -32,6 +32,7 @@ class ParamBinding:
|
||||
|
||||
def reset():
|
||||
paste_fields.clear()
|
||||
registered_param_bindings.clear()
|
||||
|
||||
|
||||
def quote(text):
|
||||
|
||||
@@ -23,7 +23,7 @@ class Git(git.Git):
|
||||
)
|
||||
return self._parse_object_header(ret)
|
||||
|
||||
def stream_object_data(self, ref: str) -> tuple[str, str, int, "Git.CatFileContentStream"]:
|
||||
def stream_object_data(self, ref: str) -> tuple[str, str, int, Git.CatFileContentStream]:
|
||||
# Not really streaming, per se; this buffers the entire object in memory.
|
||||
# Shouldn't be a problem for our use case, since we're only using this for
|
||||
# object headers (commit objects).
|
||||
|
||||
@@ -468,7 +468,7 @@ def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None,
|
||||
shared.reload_hypernetworks()
|
||||
|
||||
|
||||
def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, use_weight, create_image_every, save_hypernetwork_every, template_filename, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height):
|
||||
def train_hypernetwork(id_task, hypernetwork_name: str, learn_rate: float, batch_size: int, gradient_step: int, data_root: str, log_directory: str, training_width: int, training_height: int, varsize: bool, steps: int, clip_grad_mode: str, clip_grad_value: float, shuffle_tags: bool, tag_drop_out: bool, latent_sampling_method: str, use_weight: bool, create_image_every: int, save_hypernetwork_every: int, template_filename: str, preview_from_txt2img: bool, preview_prompt: str, preview_negative_prompt: str, preview_steps: int, preview_sampler_name: str, preview_cfg_scale: float, preview_seed: int, preview_width: int, preview_height: int):
|
||||
from modules import images, processing
|
||||
|
||||
save_hypernetwork_every = save_hypernetwork_every or 0
|
||||
@@ -698,7 +698,7 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi
|
||||
p.prompt = preview_prompt
|
||||
p.negative_prompt = preview_negative_prompt
|
||||
p.steps = preview_steps
|
||||
p.sampler_name = sd_samplers.samplers[preview_sampler_index].name
|
||||
p.sampler_name = sd_samplers.samplers_map[preview_sampler_name.lower()]
|
||||
p.cfg_scale = preview_cfg_scale
|
||||
p.seed = preview_seed
|
||||
p.width = preview_width
|
||||
|
||||
+17
-2
@@ -561,6 +561,8 @@ def save_image_with_geninfo(image, geninfo, filename, extension=None, existing_p
|
||||
})
|
||||
|
||||
piexif.insert(exif_bytes, filename)
|
||||
elif extension.lower() == ".gif":
|
||||
image.save(filename, format=image_format, comment=geninfo)
|
||||
else:
|
||||
image.save(filename, format=image_format, quality=opts.jpeg_quality)
|
||||
|
||||
@@ -661,7 +663,13 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
|
||||
|
||||
save_image_with_geninfo(image_to_save, info, temp_file_path, extension, existing_pnginfo=params.pnginfo, pnginfo_section_name=pnginfo_section_name)
|
||||
|
||||
os.replace(temp_file_path, filename_without_extension + extension)
|
||||
filename = filename_without_extension + extension
|
||||
if shared.opts.save_images_replace_action != "Replace":
|
||||
n = 0
|
||||
while os.path.exists(filename):
|
||||
n += 1
|
||||
filename = f"{filename_without_extension}-{n}{extension}"
|
||||
os.replace(temp_file_path, filename)
|
||||
|
||||
fullfn_without_extension, extension = os.path.splitext(params.filename)
|
||||
if hasattr(os, 'statvfs'):
|
||||
@@ -718,7 +726,12 @@ def read_info_from_image(image: Image.Image) -> tuple[str | None, dict]:
|
||||
geninfo = items.pop('parameters', None)
|
||||
|
||||
if "exif" in items:
|
||||
exif = piexif.load(items["exif"])
|
||||
exif_data = items["exif"]
|
||||
try:
|
||||
exif = piexif.load(exif_data)
|
||||
except OSError:
|
||||
# memory / exif was not valid so piexif tried to read from a file
|
||||
exif = None
|
||||
exif_comment = (exif or {}).get("Exif", {}).get(piexif.ExifIFD.UserComment, b'')
|
||||
try:
|
||||
exif_comment = piexif.helper.UserComment.load(exif_comment)
|
||||
@@ -728,6 +741,8 @@ def read_info_from_image(image: Image.Image) -> tuple[str | None, dict]:
|
||||
if exif_comment:
|
||||
items['exif comment'] = exif_comment
|
||||
geninfo = exif_comment
|
||||
elif "comment" in items: # for gif
|
||||
geninfo = items["comment"].decode('utf8', errors="ignore")
|
||||
|
||||
for field in IGNORED_INFO_KEYS:
|
||||
items.pop(field, None)
|
||||
|
||||
+23
-9
@@ -10,6 +10,7 @@ from modules import images as imgutil
|
||||
from modules.generation_parameters_copypaste import create_override_settings_dict, parse_generation_parameters
|
||||
from modules.processing import Processed, StableDiffusionProcessingImg2Img, process_images
|
||||
from modules.shared import opts, state
|
||||
from modules.sd_models import get_closet_checkpoint_match
|
||||
import modules.shared as shared
|
||||
import modules.processing as processing
|
||||
from modules.ui import plaintext_to_html
|
||||
@@ -41,7 +42,8 @@ def process_batch(p, input_dir, output_dir, inpaint_mask_dir, args, to_scale=Fal
|
||||
cfg_scale = p.cfg_scale
|
||||
sampler_name = p.sampler_name
|
||||
steps = p.steps
|
||||
|
||||
override_settings = p.override_settings
|
||||
sd_model_checkpoint_override = get_closet_checkpoint_match(override_settings.get("sd_model_checkpoint", None))
|
||||
for i, image in enumerate(images):
|
||||
state.job = f"{i+1} out of {len(images)}"
|
||||
if state.skipped:
|
||||
@@ -104,15 +106,27 @@ def process_batch(p, input_dir, output_dir, inpaint_mask_dir, args, to_scale=Fal
|
||||
p.sampler_name = parsed_parameters.get("Sampler", sampler_name)
|
||||
p.steps = int(parsed_parameters.get("Steps", steps))
|
||||
|
||||
model_info = get_closet_checkpoint_match(parsed_parameters.get("Model hash", None))
|
||||
if model_info is not None:
|
||||
p.override_settings['sd_model_checkpoint'] = model_info.name
|
||||
elif sd_model_checkpoint_override:
|
||||
p.override_settings['sd_model_checkpoint'] = sd_model_checkpoint_override
|
||||
else:
|
||||
p.override_settings.pop("sd_model_checkpoint", None)
|
||||
|
||||
if output_dir:
|
||||
p.outpath_samples = output_dir
|
||||
p.override_settings['save_to_dirs'] = False
|
||||
p.override_settings['save_images_replace_action'] = "Add number suffix"
|
||||
if p.n_iter > 1 or p.batch_size > 1:
|
||||
p.override_settings['samples_filename_pattern'] = f'{image_path.stem}-[generation_number]'
|
||||
else:
|
||||
p.override_settings['samples_filename_pattern'] = f'{image_path.stem}'
|
||||
|
||||
proc = modules.scripts.scripts_img2img.run(p, *args)
|
||||
|
||||
if proc is None:
|
||||
if output_dir:
|
||||
p.outpath_samples = output_dir
|
||||
p.override_settings['save_to_dirs'] = False
|
||||
if p.n_iter > 1 or p.batch_size > 1:
|
||||
p.override_settings['samples_filename_pattern'] = f'{image_path.stem}-[generation_number]'
|
||||
else:
|
||||
p.override_settings['samples_filename_pattern'] = f'{image_path.stem}'
|
||||
p.override_settings.pop('save_images_replace_action', None)
|
||||
process_images(p)
|
||||
|
||||
|
||||
@@ -189,7 +203,7 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
|
||||
|
||||
p.user = request.username
|
||||
|
||||
if shared.cmd_opts.enable_console_prompts:
|
||||
if shared.opts.enable_console_prompts:
|
||||
print(f"\nimg2img: {prompt}", file=shared.progress_print_out)
|
||||
|
||||
if mask:
|
||||
|
||||
@@ -151,8 +151,8 @@ def initialize_rest(*, reload_script_modules=False):
|
||||
|
||||
from modules import devices
|
||||
devices.first_time_calculation()
|
||||
|
||||
Thread(target=load_model).start()
|
||||
if not shared.cmd_opts.skip_load_model_at_start:
|
||||
Thread(target=load_model).start()
|
||||
|
||||
from modules import shared_items
|
||||
shared_items.reload_hypernetworks()
|
||||
|
||||
+21
-15
@@ -64,7 +64,7 @@ Use --skip-python-version-check to suppress this warning.
|
||||
@lru_cache()
|
||||
def commit_hash():
|
||||
try:
|
||||
return subprocess.check_output([git, "rev-parse", "HEAD"], shell=False, encoding='utf8').strip()
|
||||
return subprocess.check_output([git, "-C", script_path, "rev-parse", "HEAD"], shell=False, encoding='utf8').strip()
|
||||
except Exception:
|
||||
return "<none>"
|
||||
|
||||
@@ -72,7 +72,7 @@ def commit_hash():
|
||||
@lru_cache()
|
||||
def git_tag():
|
||||
try:
|
||||
return subprocess.check_output([git, "describe", "--tags"], shell=False, encoding='utf8').strip()
|
||||
return subprocess.check_output([git, "-C", script_path, "describe", "--tags"], shell=False, encoding='utf8').strip()
|
||||
except Exception:
|
||||
try:
|
||||
|
||||
@@ -228,7 +228,9 @@ def run_extension_installer(extension_dir):
|
||||
env = os.environ.copy()
|
||||
env['PYTHONPATH'] = f"{os.path.abspath('.')}{os.pathsep}{env.get('PYTHONPATH', '')}"
|
||||
|
||||
print(run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env))
|
||||
stdout = run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env).strip()
|
||||
if stdout:
|
||||
print(stdout)
|
||||
except Exception as e:
|
||||
errors.report(str(e))
|
||||
|
||||
@@ -366,17 +368,7 @@ def prepare_environment():
|
||||
startup_timer.record("install open_clip")
|
||||
|
||||
if (not is_installed("xformers") or args.reinstall_xformers) and args.xformers:
|
||||
if platform.system() == "Windows":
|
||||
if platform.python_version().startswith("3.10"):
|
||||
run_pip(f"install -U -I --no-deps {xformers_package}", "xformers", live=True)
|
||||
else:
|
||||
print("Installation of xformers is not supported in this version of Python.")
|
||||
print("You can also check this and build manually: https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers#building-xformers-on-windows-by-duckness")
|
||||
if not is_installed("xformers"):
|
||||
exit(0)
|
||||
elif platform.system() == "Linux":
|
||||
run_pip(f"install -U -I --no-deps {xformers_package}", "xformers")
|
||||
|
||||
run_pip(f"install -U -I --no-deps {xformers_package}", "xformers")
|
||||
startup_timer.record("install xformers")
|
||||
|
||||
if not is_installed("ngrok") and args.ngrok:
|
||||
@@ -404,7 +396,8 @@ def prepare_environment():
|
||||
run_pip(f"install -r \"{requirements_file}\"", "requirements")
|
||||
startup_timer.record("install requirements")
|
||||
|
||||
run_extensions_installers(settings_file=args.ui_settings_file)
|
||||
if not args.skip_install:
|
||||
run_extensions_installers(settings_file=args.ui_settings_file)
|
||||
|
||||
if args.update_check:
|
||||
version_check(commit)
|
||||
@@ -441,3 +434,16 @@ def start():
|
||||
webui.api_only()
|
||||
else:
|
||||
webui.webui()
|
||||
|
||||
|
||||
def dump_sysinfo():
|
||||
from modules import sysinfo
|
||||
import datetime
|
||||
|
||||
text = sysinfo.get()
|
||||
filename = f"sysinfo-{datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.txt"
|
||||
|
||||
with open(filename, "w", encoding="utf8") as file:
|
||||
file.write(text)
|
||||
|
||||
return filename
|
||||
|
||||
+12
-9
@@ -14,21 +14,24 @@ def list_localizations(dirname):
|
||||
if ext.lower() != ".json":
|
||||
continue
|
||||
|
||||
localizations[fn] = os.path.join(dirname, file)
|
||||
localizations[fn] = [os.path.join(dirname, file)]
|
||||
|
||||
for file in scripts.list_scripts("localizations", ".json"):
|
||||
fn, ext = os.path.splitext(file.filename)
|
||||
localizations[fn] = file.path
|
||||
if fn not in localizations:
|
||||
localizations[fn] = []
|
||||
localizations[fn].append(file.path)
|
||||
|
||||
|
||||
def localization_js(current_localization_name: str) -> str:
|
||||
fn = localizations.get(current_localization_name, None)
|
||||
fns = localizations.get(current_localization_name, None)
|
||||
data = {}
|
||||
if fn is not None:
|
||||
try:
|
||||
with open(fn, "r", encoding="utf8") as file:
|
||||
data = json.load(file)
|
||||
except Exception:
|
||||
errors.report(f"Error loading localization from {fn}", exc_info=True)
|
||||
if fns is not None:
|
||||
for fn in fns:
|
||||
try:
|
||||
with open(fn, "r", encoding="utf8") as file:
|
||||
data.update(json.load(file))
|
||||
except Exception:
|
||||
errors.report(f"Error loading localization from {fn}", exc_info=True)
|
||||
|
||||
return f"window.localization = {json.dumps(data)}"
|
||||
|
||||
@@ -210,6 +210,8 @@ class Options:
|
||||
|
||||
def add_option(self, key, info):
|
||||
self.data_labels[key] = info
|
||||
if key not in self.data:
|
||||
self.data[key] = info.default
|
||||
|
||||
def reorder(self):
|
||||
"""reorder settings so that all items related to section always go together"""
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
import sys
|
||||
from modules.paths_internal import models_path, script_path, data_path, extensions_dir, extensions_builtin_dir # noqa: F401
|
||||
from modules.paths_internal import models_path, script_path, data_path, extensions_dir, extensions_builtin_dir, cwd # noqa: F401
|
||||
|
||||
import modules.safe # noqa: F401
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import shlex
|
||||
commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
|
||||
sys.argv += shlex.split(commandline_args)
|
||||
|
||||
cwd = os.getcwd()
|
||||
modules_path = os.path.dirname(os.path.realpath(__file__))
|
||||
script_path = os.path.dirname(modules_path)
|
||||
|
||||
|
||||
+13
-17
@@ -91,8 +91,8 @@ def create_binary_mask(image):
|
||||
def txt2img_image_conditioning(sd_model, x, width, height):
|
||||
if sd_model.model.conditioning_key in {'hybrid', 'concat'}: # Inpainting models
|
||||
|
||||
# The "masked-image" in this case will just be all zeros since the entire image is masked.
|
||||
image_conditioning = torch.zeros(x.shape[0], 3, height, width, device=x.device)
|
||||
# The "masked-image" in this case will just be all 0.5 since the entire image is masked.
|
||||
image_conditioning = torch.ones(x.shape[0], 3, height, width, device=x.device) * 0.5
|
||||
image_conditioning = images_tensor_to_samples(image_conditioning, approximation_indexes.get(opts.sd_vae_encode_method))
|
||||
|
||||
# Add the fake full 1s mask to the first dimension.
|
||||
@@ -142,7 +142,7 @@ class StableDiffusionProcessing:
|
||||
overlay_images: list = None
|
||||
eta: float = None
|
||||
do_not_reload_embeddings: bool = False
|
||||
denoising_strength: float = 0
|
||||
denoising_strength: float = None
|
||||
ddim_discretize: str = None
|
||||
s_min_uncond: float = None
|
||||
s_churn: float = None
|
||||
@@ -533,6 +533,7 @@ class Processed:
|
||||
self.all_seeds = all_seeds or p.all_seeds or [self.seed]
|
||||
self.all_subseeds = all_subseeds or p.all_subseeds or [self.subseed]
|
||||
self.infotexts = infotexts or [info]
|
||||
self.version = program_version()
|
||||
|
||||
def js(self):
|
||||
obj = {
|
||||
@@ -567,6 +568,7 @@ class Processed:
|
||||
"job_timestamp": self.job_timestamp,
|
||||
"clip_skip": self.clip_skip,
|
||||
"is_using_inpainting_conditioning": self.is_using_inpainting_conditioning,
|
||||
"version": self.version,
|
||||
}
|
||||
|
||||
return json.dumps(obj)
|
||||
@@ -689,7 +691,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter
|
||||
"Token merging ratio": None if token_merging_ratio == 0 else token_merging_ratio,
|
||||
"Token merging ratio hr": None if not enable_hr or token_merging_ratio_hr == 0 else token_merging_ratio_hr,
|
||||
"Init image hash": getattr(p, 'init_img_hash', None),
|
||||
"RNG": opts.randn_source if opts.randn_source != "GPU" and opts.randn_source != "NV" else None,
|
||||
"RNG": opts.randn_source if opts.randn_source != "GPU" else None,
|
||||
"NGMS": None if p.s_min_uncond == 0 else p.s_min_uncond,
|
||||
"Tiling": "True" if p.tiling else None,
|
||||
**p.extra_generation_params,
|
||||
@@ -709,7 +711,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
if p.scripts is not None:
|
||||
p.scripts.before_process(p)
|
||||
|
||||
stored_opts = {k: opts.data[k] for k in p.override_settings.keys()}
|
||||
stored_opts = {k: opts.data[k] for k in p.override_settings.keys() if k in opts.data}
|
||||
|
||||
try:
|
||||
# if no checkpoint override or the override checkpoint can't be found, remove override entry and load opts checkpoint
|
||||
@@ -1148,18 +1150,12 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
else:
|
||||
decoded_samples = None
|
||||
|
||||
current = shared.sd_model.sd_checkpoint_info
|
||||
try:
|
||||
if self.hr_checkpoint_info is not None:
|
||||
self.sampler = None
|
||||
sd_models.reload_model_weights(info=self.hr_checkpoint_info)
|
||||
devices.torch_gc()
|
||||
with sd_models.SkipWritingToConfig():
|
||||
sd_models.reload_model_weights(info=self.hr_checkpoint_info)
|
||||
|
||||
return self.sample_hr_pass(samples, decoded_samples, seeds, subseeds, subseed_strength, prompts)
|
||||
finally:
|
||||
self.sampler = None
|
||||
sd_models.reload_model_weights(info=current)
|
||||
devices.torch_gc()
|
||||
devices.torch_gc()
|
||||
|
||||
return self.sample_hr_pass(samples, decoded_samples, seeds, subseeds, subseed_strength, prompts)
|
||||
|
||||
def sample_hr_pass(self, samples, decoded_samples, seeds, subseeds, subseed_strength, prompts):
|
||||
if shared.state.interrupted:
|
||||
@@ -1321,7 +1317,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
if shared.opts.hires_fix_use_firstpass_conds:
|
||||
self.calculate_hr_conds()
|
||||
|
||||
elif lowvram.is_enabled(shared.sd_model): # if in lowvram mode, we need to calculate conds right away, before the cond NN is unloaded
|
||||
elif lowvram.is_enabled(shared.sd_model) and shared.sd_model.sd_checkpoint_info == sd_models.select_checkpoint(): # if in lowvram mode, we need to calculate conds right away, before the cond NN is unloaded
|
||||
with devices.autocast():
|
||||
extra_networks.activate(self, self.hr_extra_network_data)
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ class ScriptSeed(scripts.ScriptBuiltinUI):
|
||||
else:
|
||||
self.seed = gr.Number(label='Seed', value=-1, elem_id=self.elem_id("seed"), min_width=100, precision=0)
|
||||
|
||||
random_seed = ToolButton(ui.random_symbol, elem_id=self.elem_id("random_seed"), label='Random seed')
|
||||
reuse_seed = ToolButton(ui.reuse_symbol, elem_id=self.elem_id("reuse_seed"), label='Reuse seed')
|
||||
random_seed = ToolButton(ui.random_symbol, elem_id=self.elem_id("random_seed"), tooltip="Set seed to -1, which will cause a new random number to be used every time")
|
||||
reuse_seed = ToolButton(ui.reuse_symbol, elem_id=self.elem_id("reuse_seed"), tooltip="Reuse seed from last generation, mostly useful if it was randomized")
|
||||
|
||||
seed_checkbox = gr.Checkbox(label='Extra', elem_id=self.elem_id("subseed_show"), value=False)
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ from __future__ import annotations
|
||||
|
||||
import re
|
||||
from collections import namedtuple
|
||||
from typing import List
|
||||
import lark
|
||||
|
||||
# a prompt like this: "fantasy landscape with a [mountain:lake:0.25] and [an oak:a christmas tree:0.75][ in foreground::0.6][ in background:0.25] [shoddy:masterful:0.5]"
|
||||
@@ -240,14 +239,14 @@ def get_multicond_prompt_list(prompts: SdConditioning | list[str]):
|
||||
|
||||
class ComposableScheduledPromptConditioning:
|
||||
def __init__(self, schedules, weight=1.0):
|
||||
self.schedules: List[ScheduledPromptConditioning] = schedules
|
||||
self.schedules: list[ScheduledPromptConditioning] = schedules
|
||||
self.weight: float = weight
|
||||
|
||||
|
||||
class MulticondLearnedConditioning:
|
||||
def __init__(self, shape, batch):
|
||||
self.shape: tuple = shape # the shape field is needed to send this object to DDIM/PLMS
|
||||
self.batch: List[List[ComposableScheduledPromptConditioning]] = batch
|
||||
self.batch: list[list[ComposableScheduledPromptConditioning]] = batch
|
||||
|
||||
|
||||
def get_multicond_learned_conditioning(model, prompts, steps, hires_steps=None, use_old_scheduling=False) -> MulticondLearnedConditioning:
|
||||
@@ -278,7 +277,7 @@ class DictWithShape(dict):
|
||||
return self["crossattn"].shape
|
||||
|
||||
|
||||
def reconstruct_cond_batch(c: List[List[ScheduledPromptConditioning]], current_step):
|
||||
def reconstruct_cond_batch(c: list[list[ScheduledPromptConditioning]], current_step):
|
||||
param = c[0][0].cond
|
||||
is_dict = isinstance(param, dict)
|
||||
|
||||
|
||||
+3
-1
@@ -14,7 +14,9 @@ def is_restartable() -> bool:
|
||||
def restart_program() -> None:
|
||||
"""creates file tmp/restart and immediately stops the process, which webui.bat/webui.sh interpret as a command to start webui again"""
|
||||
|
||||
(Path(script_path) / "tmp" / "restart").touch()
|
||||
tmpdir = Path(script_path) / "tmp"
|
||||
tmpdir.mkdir(parents=True, exist_ok=True)
|
||||
(tmpdir / "restart").touch()
|
||||
|
||||
stop_program()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import inspect
|
||||
import os
|
||||
from collections import namedtuple
|
||||
from typing import Optional, Dict, Any
|
||||
from typing import Optional, Any
|
||||
|
||||
from fastapi import FastAPI
|
||||
from gradio import Blocks
|
||||
@@ -29,12 +29,15 @@ class ImageSaveParams:
|
||||
|
||||
|
||||
class ExtraNoiseParams:
|
||||
def __init__(self, noise, x):
|
||||
def __init__(self, noise, x, xi):
|
||||
self.noise = noise
|
||||
"""Random noise generated by the seed"""
|
||||
|
||||
self.x = x
|
||||
"""Latent image representation of the image"""
|
||||
"""Latent representation of the image"""
|
||||
|
||||
self.xi = xi
|
||||
"""Noisy latent representation of the image"""
|
||||
|
||||
|
||||
class CFGDenoiserParams:
|
||||
@@ -255,7 +258,7 @@ def image_grid_callback(params: ImageGridLoopParams):
|
||||
report_exception(c, 'image_grid')
|
||||
|
||||
|
||||
def infotext_pasted_callback(infotext: str, params: Dict[str, Any]):
|
||||
def infotext_pasted_callback(infotext: str, params: dict[str, Any]):
|
||||
for c in callback_map['callbacks_infotext_pasted']:
|
||||
try:
|
||||
c.callback(infotext, params)
|
||||
@@ -446,7 +449,7 @@ def on_infotext_pasted(callback):
|
||||
"""register a function to be called before applying an infotext.
|
||||
The callback is called with two arguments:
|
||||
- infotext: str - raw infotext.
|
||||
- result: Dict[str, any] - parsed infotext parameters.
|
||||
- result: dict[str, any] - parsed infotext parameters.
|
||||
"""
|
||||
add_callback(callback_map['callbacks_infotext_pasted'], callback)
|
||||
|
||||
|
||||
+5
-1
@@ -491,11 +491,15 @@ class ScriptRunner:
|
||||
|
||||
arg_info = api_models.ScriptArg(label=control.label or "")
|
||||
|
||||
for field in ("value", "minimum", "maximum", "step", "choices"):
|
||||
for field in ("value", "minimum", "maximum", "step"):
|
||||
v = getattr(control, field, None)
|
||||
if v is not None:
|
||||
setattr(arg_info, field, v)
|
||||
|
||||
choices = getattr(control, 'choices', None) # as of gradio 3.41, some items in choices are strings, and some are tuples where the first elem is the string
|
||||
if choices is not None:
|
||||
arg_info.choices = [x[0] if isinstance(x, tuple) else x for x in choices]
|
||||
|
||||
api_args.append(arg_info)
|
||||
|
||||
script.api_info = api_models.ScriptInfo(
|
||||
|
||||
+12
-5
@@ -2,7 +2,7 @@ import torch
|
||||
from torch.nn.functional import silu
|
||||
from types import MethodType
|
||||
|
||||
from modules import devices, sd_hijack_optimizations, shared, script_callbacks, errors, sd_unet
|
||||
from modules import devices, sd_hijack_optimizations, shared, script_callbacks, errors, sd_unet, patches
|
||||
from modules.hypernetworks import hypernetwork
|
||||
from modules.shared import cmd_opts
|
||||
from modules import sd_hijack_clip, sd_hijack_open_clip, sd_hijack_unet, sd_hijack_xlmr, xlmr
|
||||
@@ -10,6 +10,7 @@ from modules import sd_hijack_clip, sd_hijack_open_clip, sd_hijack_unet, sd_hija
|
||||
import ldm.modules.attention
|
||||
import ldm.modules.diffusionmodules.model
|
||||
import ldm.modules.diffusionmodules.openaimodel
|
||||
import ldm.models.diffusion.ddpm
|
||||
import ldm.models.diffusion.ddim
|
||||
import ldm.models.diffusion.plms
|
||||
import ldm.modules.encoders.modules
|
||||
@@ -37,6 +38,8 @@ ldm.models.diffusion.ddpm.print = shared.ldm_print
|
||||
optimizers = []
|
||||
current_optimizer: sd_hijack_optimizations.SdOptimization = None
|
||||
|
||||
ldm_original_forward = patches.patch(__file__, ldm.modules.diffusionmodules.openaimodel.UNetModel, "forward", sd_unet.UNetModel_forward)
|
||||
sgm_original_forward = patches.patch(__file__, sgm.modules.diffusionmodules.openaimodel.UNetModel, "forward", sd_unet.UNetModel_forward)
|
||||
|
||||
def list_optimizers():
|
||||
new_optimizers = script_callbacks.list_optimizers_callback()
|
||||
@@ -239,10 +242,13 @@ class StableDiffusionModelHijack:
|
||||
|
||||
self.layers = flatten(m)
|
||||
|
||||
if not hasattr(ldm.modules.diffusionmodules.openaimodel, 'copy_of_UNetModel_forward_for_webui'):
|
||||
ldm.modules.diffusionmodules.openaimodel.copy_of_UNetModel_forward_for_webui = ldm.modules.diffusionmodules.openaimodel.UNetModel.forward
|
||||
if isinstance(m, ldm.models.diffusion.ddpm.LatentDiffusion):
|
||||
sd_unet.original_forward = ldm_original_forward
|
||||
elif isinstance(m, sgm.models.diffusion.DiffusionEngine):
|
||||
sd_unet.original_forward = sgm_original_forward
|
||||
else:
|
||||
sd_unet.original_forward = None
|
||||
|
||||
ldm.modules.diffusionmodules.openaimodel.UNetModel.forward = sd_unet.UNetModel_forward
|
||||
|
||||
def undo_hijack(self, m):
|
||||
conditioner = getattr(m, 'conditioner', None)
|
||||
@@ -279,7 +285,8 @@ class StableDiffusionModelHijack:
|
||||
self.layers = None
|
||||
self.clip = None
|
||||
|
||||
ldm.modules.diffusionmodules.openaimodel.UNetModel.forward = ldm.modules.diffusionmodules.openaimodel.copy_of_UNetModel_forward_for_webui
|
||||
sd_unet.original_forward = None
|
||||
|
||||
|
||||
def apply_circular(self, enable):
|
||||
if self.circular_enabled == enable:
|
||||
|
||||
+46
-5
@@ -7,16 +7,17 @@ import threading
|
||||
import torch
|
||||
import re
|
||||
import safetensors.torch
|
||||
from omegaconf import OmegaConf
|
||||
from omegaconf import OmegaConf, ListConfig
|
||||
from os import mkdir
|
||||
from urllib import request
|
||||
import ldm.modules.midas as midas
|
||||
|
||||
from ldm.util import instantiate_from_config
|
||||
|
||||
from modules import paths, shared, modelloader, devices, script_callbacks, sd_vae, sd_disable_initialization, errors, hashes, sd_models_config, sd_unet, sd_models_xl, cache, extra_networks, processing, lowvram, sd_hijack
|
||||
from modules import paths, shared, modelloader, devices, script_callbacks, sd_vae, sd_disable_initialization, errors, hashes, sd_models_config, sd_unet, sd_models_xl, cache, extra_networks, processing, lowvram, sd_hijack, patches
|
||||
from modules.timer import Timer
|
||||
import tomesd
|
||||
import numpy as np
|
||||
|
||||
model_dir = "Stable-diffusion"
|
||||
model_path = os.path.abspath(os.path.join(paths.models_path, model_dir))
|
||||
@@ -27,15 +28,34 @@ checkpoint_alisases = checkpoint_aliases # for compatibility with old name
|
||||
checkpoints_loaded = collections.OrderedDict()
|
||||
|
||||
|
||||
def replace_key(d, key, new_key, value):
|
||||
keys = list(d.keys())
|
||||
|
||||
d[new_key] = value
|
||||
|
||||
if key not in keys:
|
||||
return d
|
||||
|
||||
index = keys.index(key)
|
||||
keys[index] = new_key
|
||||
|
||||
new_d = {k: d[k] for k in keys}
|
||||
|
||||
d.clear()
|
||||
d.update(new_d)
|
||||
return d
|
||||
|
||||
|
||||
class CheckpointInfo:
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
abspath = os.path.abspath(filename)
|
||||
abs_ckpt_dir = os.path.abspath(shared.cmd_opts.ckpt_dir) if shared.cmd_opts.ckpt_dir is not None else None
|
||||
|
||||
self.is_safetensors = os.path.splitext(filename)[1].lower() == ".safetensors"
|
||||
|
||||
if shared.cmd_opts.ckpt_dir is not None and abspath.startswith(shared.cmd_opts.ckpt_dir):
|
||||
name = abspath.replace(shared.cmd_opts.ckpt_dir, '')
|
||||
if abs_ckpt_dir and abspath.startswith(abs_ckpt_dir):
|
||||
name = abspath.replace(abs_ckpt_dir, '')
|
||||
elif abspath.startswith(model_path):
|
||||
name = abspath.replace(model_path, '')
|
||||
else:
|
||||
@@ -91,9 +111,11 @@ class CheckpointInfo:
|
||||
if self.shorthash not in self.ids:
|
||||
self.ids += [self.shorthash, self.sha256, f'{self.name} [{self.shorthash}]', f'{self.name_for_extra} [{self.shorthash}]']
|
||||
|
||||
checkpoints_list.pop(self.title, None)
|
||||
old_title = self.title
|
||||
self.title = f'{self.name} [{self.shorthash}]'
|
||||
self.short_title = f'{self.name_for_extra} [{self.shorthash}]'
|
||||
|
||||
replace_key(checkpoints_list, old_title, self.title, self)
|
||||
self.register()
|
||||
|
||||
return self.shorthash
|
||||
@@ -109,9 +131,12 @@ except Exception:
|
||||
|
||||
|
||||
def setup_model():
|
||||
"""called once at startup to do various one-time tasks related to SD models"""
|
||||
|
||||
os.makedirs(model_path, exist_ok=True)
|
||||
|
||||
enable_midas_autodownload()
|
||||
patch_given_betas()
|
||||
|
||||
|
||||
def checkpoint_tiles(use_short=False):
|
||||
@@ -289,6 +314,8 @@ def get_checkpoint_state_dict(checkpoint_info: CheckpointInfo, timer):
|
||||
if checkpoint_info in checkpoints_loaded:
|
||||
# use checkpoint cache
|
||||
print(f"Loading weights [{sd_model_hash}] from cache")
|
||||
# move to end as latest
|
||||
checkpoints_loaded.move_to_end(checkpoint_info)
|
||||
return checkpoints_loaded[checkpoint_info]
|
||||
|
||||
print(f"Loading weights [{sd_model_hash}] from {checkpoint_info.filename}")
|
||||
@@ -433,6 +460,20 @@ def enable_midas_autodownload():
|
||||
midas.api.load_model = load_model_wrapper
|
||||
|
||||
|
||||
def patch_given_betas():
|
||||
import ldm.models.diffusion.ddpm
|
||||
|
||||
def patched_register_schedule(*args, **kwargs):
|
||||
"""a modified version of register_schedule function that converts plain list from Omegaconf into numpy"""
|
||||
|
||||
if isinstance(args[1], ListConfig):
|
||||
args = (args[0], np.array(args[1]), *args[2:])
|
||||
|
||||
original_register_schedule(*args, **kwargs)
|
||||
|
||||
original_register_schedule = patches.patch(__name__, ldm.models.diffusion.ddpm.DDPM, 'register_schedule', patched_register_schedule)
|
||||
|
||||
|
||||
def repair_config(sd_config):
|
||||
|
||||
if not hasattr(sd_config.model.params, "use_ema"):
|
||||
|
||||
@@ -95,6 +95,8 @@ def images_tensor_to_samples(image, approximation=None, model=None):
|
||||
else:
|
||||
if model is None:
|
||||
model = shared.sd_model
|
||||
model.first_stage_model.to(devices.dtype_vae)
|
||||
|
||||
image = image.to(shared.device, dtype=devices.dtype_vae)
|
||||
image = image * 2 - 1
|
||||
if len(image) > 1:
|
||||
@@ -164,8 +166,17 @@ def apply_refiner(cfg_denoiser):
|
||||
if refiner_checkpoint_info is None or shared.sd_model.sd_checkpoint_info == refiner_checkpoint_info:
|
||||
return False
|
||||
|
||||
if getattr(cfg_denoiser.p, "enable_hr", False) and not cfg_denoiser.p.is_hr_pass:
|
||||
return False
|
||||
if getattr(cfg_denoiser.p, "enable_hr", False):
|
||||
is_second_pass = cfg_denoiser.p.is_hr_pass
|
||||
|
||||
if opts.hires_fix_refiner_pass == "first pass" and is_second_pass:
|
||||
return False
|
||||
|
||||
if opts.hires_fix_refiner_pass == "second pass" and not is_second_pass:
|
||||
return False
|
||||
|
||||
if opts.hires_fix_refiner_pass != "second pass":
|
||||
cfg_denoiser.p.extra_generation_params['Hires refiner'] = opts.hires_fix_refiner_pass
|
||||
|
||||
cfg_denoiser.p.extra_generation_params['Refiner'] = refiner_checkpoint_info.short_title
|
||||
cfg_denoiser.p.extra_generation_params['Refiner switch at'] = refiner_switch_at
|
||||
|
||||
@@ -148,7 +148,7 @@ class KDiffusionSampler(sd_samplers_common.Sampler):
|
||||
|
||||
if opts.img2img_extra_noise > 0:
|
||||
p.extra_generation_params["Extra noise"] = opts.img2img_extra_noise
|
||||
extra_noise_params = ExtraNoiseParams(noise, x)
|
||||
extra_noise_params = ExtraNoiseParams(noise, x, xi)
|
||||
extra_noise_callback(extra_noise_params)
|
||||
noise = extra_noise_params.noise
|
||||
xi += noise * opts.img2img_extra_noise
|
||||
@@ -197,7 +197,11 @@ class KDiffusionSampler(sd_samplers_common.Sampler):
|
||||
|
||||
sigmas = self.get_sigmas(p, steps)
|
||||
|
||||
x = x * sigmas[0]
|
||||
if opts.sgm_noise_multiplier:
|
||||
p.extra_generation_params["SGM noise multiplier"] = True
|
||||
x = x * torch.sqrt(1.0 + sigmas[0] ** 2.0)
|
||||
else:
|
||||
x = x * sigmas[0]
|
||||
|
||||
extra_params_kwargs = self.initialize(p)
|
||||
parameters = inspect.signature(self.func).parameters
|
||||
|
||||
@@ -107,7 +107,7 @@ class CompVisSampler(sd_samplers_common.Sampler):
|
||||
|
||||
if opts.img2img_extra_noise > 0:
|
||||
p.extra_generation_params["Extra noise"] = opts.img2img_extra_noise
|
||||
extra_noise_params = ExtraNoiseParams(noise, x)
|
||||
extra_noise_params = ExtraNoiseParams(noise, x, xi)
|
||||
extra_noise_callback(extra_noise_params)
|
||||
noise = extra_noise_params.noise
|
||||
xi += noise * opts.img2img_extra_noise * sqrt_alpha_cumprod
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import torch.nn
|
||||
import ldm.modules.diffusionmodules.openaimodel
|
||||
|
||||
from modules import script_callbacks, shared, devices
|
||||
|
||||
unet_options = []
|
||||
current_unet_option = None
|
||||
current_unet = None
|
||||
original_forward = None
|
||||
|
||||
|
||||
def list_unets():
|
||||
@@ -88,5 +88,5 @@ def UNetModel_forward(self, x, timesteps=None, context=None, *args, **kwargs):
|
||||
if current_unet is not None:
|
||||
return current_unet.forward(x, timesteps, context, *args, **kwargs)
|
||||
|
||||
return ldm.modules.diffusionmodules.openaimodel.copy_of_UNetModel_forward_for_webui(self, x, timesteps, context, *args, **kwargs)
|
||||
return original_forward(self, x, timesteps, context, *args, **kwargs)
|
||||
|
||||
|
||||
+1
-1
@@ -159,7 +159,7 @@ def resolve_vae_from_user_metadata(checkpoint_file) -> VaeResolution:
|
||||
|
||||
def resolve_vae_near_checkpoint(checkpoint_file) -> VaeResolution:
|
||||
vae_near_checkpoint = find_vae_near_checkpoint(checkpoint_file)
|
||||
if vae_near_checkpoint is not None and (not shared.opts.sd_vae_overrides_per_model_preferences or is_automatic):
|
||||
if vae_near_checkpoint is not None and (not shared.opts.sd_vae_overrides_per_model_preferences or is_automatic()):
|
||||
return VaeResolution(vae_near_checkpoint, 'found near the checkpoint')
|
||||
|
||||
return VaeResolution(resolved=False)
|
||||
|
||||
@@ -14,5 +14,5 @@ if os.environ.get('IGNORE_CMD_ARGS_ERRORS', None) is None:
|
||||
else:
|
||||
cmd_opts, _ = parser.parse_known_args()
|
||||
|
||||
|
||||
cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or cmd_opts.server_name) and not cmd_opts.enable_insecure_extension_access
|
||||
cmd_opts.webui_is_non_local = any([cmd_opts.share, cmd_opts.listen, cmd_opts.ngrok, cmd_opts.server_name])
|
||||
cmd_opts.disable_extension_access = cmd_opts.webui_is_non_local and not cmd_opts.enable_insecure_extension_access
|
||||
|
||||
@@ -44,9 +44,9 @@ def refresh_unet_list():
|
||||
modules.sd_unet.list_unets()
|
||||
|
||||
|
||||
def list_checkpoint_tiles():
|
||||
def list_checkpoint_tiles(use_short=False):
|
||||
import modules.sd_models
|
||||
return modules.sd_models.checkpoint_tiles()
|
||||
return modules.sd_models.checkpoint_tiles(use_short)
|
||||
|
||||
|
||||
def refresh_checkpoints():
|
||||
|
||||
@@ -26,7 +26,7 @@ options_templates.update(options_section(('saving-images', "Saving images/grids"
|
||||
"samples_format": OptionInfo('png', 'File format for images'),
|
||||
"samples_filename_pattern": OptionInfo("", "Images filename pattern", component_args=hide_dirs).link("wiki", "https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Images-Filename-Name-and-Subdirectory"),
|
||||
"save_images_add_number": OptionInfo(True, "Add number to filename when saving", component_args=hide_dirs),
|
||||
|
||||
"save_images_replace_action": OptionInfo("Replace", "Saving the image to an existing file", gr.Radio, {"choices": ["Replace", "Add number suffix"], **hide_dirs}),
|
||||
"grid_save": OptionInfo(True, "Always save all generated image grids"),
|
||||
"grid_format": OptionInfo('png', 'File format for grids'),
|
||||
"grid_extended_filename": OptionInfo(False, "Add extended info (seed, prompt) to filename when saving grid"),
|
||||
@@ -100,6 +100,7 @@ options_templates.update(options_section(('face-restoration', "Face restoration"
|
||||
|
||||
options_templates.update(options_section(('system', "System"), {
|
||||
"auto_launch_browser": OptionInfo("Local", "Automatically open webui in browser on startup", gr.Radio, lambda: {"choices": ["Disable", "Local", "Remote"]}),
|
||||
"enable_console_prompts": OptionInfo(shared.cmd_opts.enable_console_prompts, "Print prompts to console when generating with txt2img and img2img."),
|
||||
"show_warnings": OptionInfo(False, "Show warnings in console.").needs_reload_ui(),
|
||||
"show_gradio_deprecation_warnings": OptionInfo(True, "Show gradio deprecation warnings in console.").needs_reload_ui(),
|
||||
"memmon_poll_rate": OptionInfo(8, "VRAM usage polls per second during generation.", gr.Slider, {"minimum": 0, "maximum": 40, "step": 1}).info("0 = disable"),
|
||||
@@ -133,7 +134,7 @@ options_templates.update(options_section(('training', "Training"), {
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('sd', "Stable Diffusion"), {
|
||||
"sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": shared_items.list_checkpoint_tiles()}, refresh=shared_items.refresh_checkpoints, infotext='Model hash'),
|
||||
"sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": shared_items.list_checkpoint_tiles(shared.opts.sd_checkpoint_dropdown_use_short)}, refresh=shared_items.refresh_checkpoints, infotext='Model hash'),
|
||||
"sd_checkpoints_limit": OptionInfo(1, "Maximum number of checkpoints loaded at the same time", gr.Slider, {"minimum": 1, "maximum": 10, "step": 1}),
|
||||
"sd_checkpoints_keep_in_cpu": OptionInfo(True, "Only keep one model on device").info("will keep models other than the currently used one in RAM rather than VRAM"),
|
||||
"sd_checkpoint_cache": OptionInfo(0, "Checkpoints to cache in RAM", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}).info("obsolete; set to 0 and use the two settings above instead"),
|
||||
@@ -144,8 +145,9 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), {
|
||||
"comma_padding_backtrack": OptionInfo(20, "Prompt word wrap length limit", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1}).info("in tokens - for texts shorter than specified, if they don't fit into 75 token limit, move them to the next 75 token chunk"),
|
||||
"CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}, infotext="Clip skip").link("wiki", "https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#clip-skip").info("ignore last layers of CLIP network; 1 ignores none, 2 ignores one layer"),
|
||||
"upcast_attn": OptionInfo(False, "Upcast cross attention layer to float32"),
|
||||
"randn_source": OptionInfo("GPU", "Random number generator source.", gr.Radio, {"choices": ["GPU", "CPU", "NV"]}).info("changes seeds drastically; use CPU to produce the same picture across different videocard vendors; use NV to produce same picture as on NVidia videocards"),
|
||||
"randn_source": OptionInfo("GPU", "Random number generator source.", gr.Radio, {"choices": ["GPU", "CPU", "NV"]}, infotext="RNG").info("changes seeds drastically; use CPU to produce the same picture across different videocard vendors; use NV to produce same picture as on NVidia videocards"),
|
||||
"tiling": OptionInfo(False, "Tiling", infotext='Tiling').info("produce a tileable picture"),
|
||||
"hires_fix_refiner_pass": OptionInfo("second pass", "Hires fix: which pass to enable refiner for", gr.Radio, {"choices": ["first pass", "second pass", "both passes"]}, infotext="Hires refiner"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('sdxl', "Stable Diffusion XL"), {
|
||||
@@ -254,12 +256,14 @@ options_templates.update(options_section(('ui', "User interface"), {
|
||||
"dimensions_and_batch_together": OptionInfo(True, "Show Width/Height and Batch sliders in same row").needs_reload_ui(),
|
||||
"keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
|
||||
"keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing <extra networks:0.9>", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
|
||||
"keyedit_delimiters": OptionInfo(".,\\/!?%^*;:{}=`~()", "Ctrl+up/down word delimiters"),
|
||||
"keyedit_delimiters": OptionInfo(r".,\/!?%^*;:{}=`~() ", "Ctrl+up/down word delimiters"),
|
||||
"keyedit_delimiters_whitespace": OptionInfo(["Tab", "Carriage Return", "Line Feed"], "Ctrl+up/down whitespace delimiters", gr.CheckboxGroup, lambda: {"choices": ["Tab", "Carriage Return", "Line Feed"]}),
|
||||
"keyedit_move": OptionInfo(True, "Alt+left/right moves prompt elements"),
|
||||
"quicksettings_list": OptionInfo(["sd_model_checkpoint"], "Quicksettings list", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that appear at the top of page rather than in settings tab").needs_reload_ui(),
|
||||
"ui_tab_order": OptionInfo([], "UI tab order", ui_components.DropdownMulti, lambda: {"choices": list(shared.tab_names)}).needs_reload_ui(),
|
||||
"hidden_tabs": OptionInfo([], "Hidden UI tabs", ui_components.DropdownMulti, lambda: {"choices": list(shared.tab_names)}).needs_reload_ui(),
|
||||
"ui_reorder_list": OptionInfo([], "txt2img/img2img UI item order", ui_components.DropdownMulti, lambda: {"choices": list(shared_items.ui_reorder_categories())}).info("selected items appear first").needs_reload_ui(),
|
||||
"sd_checkpoint_dropdown_use_short": OptionInfo(False, "Checkpoint dropdown: use filenames without paths").info("models in subdirectories like photo/sd15.ckpt will be listed as just sd15.ckpt"),
|
||||
"hires_fix_show_sampler": OptionInfo(False, "Hires fix: show hires checkpoint and sampler selection").needs_reload_ui(),
|
||||
"hires_fix_show_prompts": OptionInfo(False, "Hires fix: show hires prompt and negative prompt").needs_reload_ui(),
|
||||
"disable_token_counters": OptionInfo(False, "Disable prompt token counters").needs_reload_ui(),
|
||||
@@ -304,11 +308,12 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters"
|
||||
's_tmax': OptionInfo(0.0, "sigma tmax", gr.Slider, {"minimum": 0.0, "maximum": 999.0, "step": 0.01}, infotext='Sigma tmax').info("0 = inf; end value of the sigma range; only applies to Euler, Heun, and DPM2"),
|
||||
's_noise': OptionInfo(1.0, "sigma noise", gr.Slider, {"minimum": 0.0, "maximum": 1.1, "step": 0.001}, infotext='Sigma noise').info('amount of additional noise to counteract loss of detail during sampling'),
|
||||
'k_sched_type': OptionInfo("Automatic", "Scheduler type", gr.Dropdown, {"choices": ["Automatic", "karras", "exponential", "polyexponential"]}, infotext='Schedule type').info("lets you override the noise schedule for k-diffusion samplers; choosing Automatic disables the three parameters below"),
|
||||
'sigma_min': OptionInfo(0.0, "sigma min", gr.Number, infotext='Schedule max sigma').info("0 = default (~0.03); minimum noise strength for k-diffusion noise scheduler"),
|
||||
'sigma_max': OptionInfo(0.0, "sigma max", gr.Number, infotext='Schedule min sigma').info("0 = default (~14.6); maximum noise strength for k-diffusion noise scheduler"),
|
||||
'sigma_min': OptionInfo(0.0, "sigma min", gr.Number, infotext='Schedule min sigma').info("0 = default (~0.03); minimum noise strength for k-diffusion noise scheduler"),
|
||||
'sigma_max': OptionInfo(0.0, "sigma max", gr.Number, infotext='Schedule max sigma').info("0 = default (~14.6); maximum noise strength for k-diffusion noise scheduler"),
|
||||
'rho': OptionInfo(0.0, "rho", gr.Number, infotext='Schedule rho').info("0 = default (7 for karras, 1 for polyexponential); higher values result in a steeper noise schedule (decreases faster)"),
|
||||
'eta_noise_seed_delta': OptionInfo(0, "Eta noise seed delta", gr.Number, {"precision": 0}, infotext='ENSD').info("ENSD; does not improve anything, just produces different results for ancestral samplers - only useful for reproducing images"),
|
||||
'always_discard_next_to_last_sigma': OptionInfo(False, "Always discard next-to-last sigma", infotext='Discard penultimate sigma').link("PR", "https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/6044"),
|
||||
'sgm_noise_multiplier': OptionInfo(False, "SGM noise multiplier", infotext='SGM noise multplier').link("PR", "https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12818").info("Match initial noise to official SDXL implementation - only useful for reproducing images"),
|
||||
'uni_pc_variant': OptionInfo("bh1", "UniPC variant", gr.Radio, {"choices": ["bh1", "bh2", "vary_coeff"]}, infotext='UniPC variant'),
|
||||
'uni_pc_skip_type': OptionInfo("time_uniform", "UniPC skip type", gr.Radio, {"choices": ["time_uniform", "time_quadratic", "logSNR"]}, infotext='UniPC skip type'),
|
||||
'uni_pc_order': OptionInfo(3, "UniPC order", gr.Slider, {"minimum": 1, "maximum": 50, "step": 1}, infotext='UniPC order').info("must be < sampling steps"),
|
||||
|
||||
@@ -103,6 +103,7 @@ class State:
|
||||
|
||||
def begin(self, job: str = "(unknown)"):
|
||||
self.sampling_step = 0
|
||||
self.time_start = time.time()
|
||||
self.job_count = -1
|
||||
self.processing_has_refined_job_count = False
|
||||
self.job_no = 0
|
||||
@@ -114,7 +115,6 @@ class State:
|
||||
self.skipped = False
|
||||
self.interrupted = False
|
||||
self.textinfo = None
|
||||
self.time_start = time.time()
|
||||
self.job = job
|
||||
devices.torch_gc()
|
||||
log.info("Starting job %s", job)
|
||||
|
||||
@@ -15,7 +15,7 @@ import torch
|
||||
from torch import Tensor
|
||||
from torch.utils.checkpoint import checkpoint
|
||||
import math
|
||||
from typing import Optional, NamedTuple, List
|
||||
from typing import Optional, NamedTuple
|
||||
|
||||
|
||||
def narrow_trunc(
|
||||
@@ -97,7 +97,7 @@ def _query_chunk_attention(
|
||||
)
|
||||
return summarize_chunk(query, key_chunk, value_chunk)
|
||||
|
||||
chunks: List[AttnChunk] = [
|
||||
chunks: list[AttnChunk] = [
|
||||
chunk_scanner(chunk) for chunk in torch.arange(0, k_tokens, kv_chunk_size)
|
||||
]
|
||||
acc_chunk = AttnChunk(*map(torch.stack, zip(*chunks)))
|
||||
|
||||
+17
-1
@@ -82,7 +82,7 @@ def get_dict():
|
||||
"Data path": paths_internal.data_path,
|
||||
"Extensions dir": paths_internal.extensions_dir,
|
||||
"Checksum": checksum_token,
|
||||
"Commandline": sys.argv,
|
||||
"Commandline": get_argv(),
|
||||
"Torch env info": get_torch_sysinfo(),
|
||||
"Exceptions": get_exceptions(),
|
||||
"CPU": {
|
||||
@@ -123,6 +123,22 @@ def get_environment():
|
||||
return {k: os.environ[k] for k in sorted(os.environ) if k in environment_whitelist}
|
||||
|
||||
|
||||
def get_argv():
|
||||
res = []
|
||||
|
||||
for v in sys.argv:
|
||||
if shared.cmd_opts.gradio_auth and shared.cmd_opts.gradio_auth == v:
|
||||
res.append("<hidden>")
|
||||
continue
|
||||
|
||||
if shared.cmd_opts.api_auth and shared.cmd_opts.api_auth == v:
|
||||
res.append("<hidden>")
|
||||
continue
|
||||
|
||||
res.append(v)
|
||||
|
||||
return res
|
||||
|
||||
re_newline = re.compile(r"\r*\n")
|
||||
|
||||
|
||||
|
||||
@@ -386,7 +386,7 @@ def validate_train_inputs(model_name, learn_rate, batch_size, gradient_step, dat
|
||||
assert log_directory, "Log directory is empty"
|
||||
|
||||
|
||||
def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, use_weight, create_image_every, save_embedding_every, template_filename, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height):
|
||||
def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, use_weight, create_image_every, save_embedding_every, template_filename, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_name, preview_cfg_scale, preview_seed, preview_width, preview_height):
|
||||
from modules import processing
|
||||
|
||||
save_embedding_every = save_embedding_every or 0
|
||||
@@ -590,7 +590,7 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
p.prompt = preview_prompt
|
||||
p.negative_prompt = preview_negative_prompt
|
||||
p.steps = preview_steps
|
||||
p.sampler_name = sd_samplers.samplers[preview_sampler_index].name
|
||||
p.sampler_name = sd_samplers.samplers_map[preview_sampler_name.lower()]
|
||||
p.cfg_scale = preview_cfg_scale
|
||||
p.seed = preview_seed
|
||||
p.width = preview_width
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ from contextlib import closing
|
||||
import modules.scripts
|
||||
from modules import processing
|
||||
from modules.generation_parameters_copypaste import create_override_settings_dict
|
||||
from modules.shared import opts, cmd_opts
|
||||
from modules.shared import opts
|
||||
import modules.shared as shared
|
||||
from modules.ui import plaintext_to_html
|
||||
import gradio as gr
|
||||
@@ -45,7 +45,7 @@ def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, step
|
||||
|
||||
p.user = request.username
|
||||
|
||||
if cmd_opts.enable_console_prompts:
|
||||
if shared.opts.enable_console_prompts:
|
||||
print(f"\ntxt2img: {prompt}", file=shared.progress_print_out)
|
||||
|
||||
with closing(p):
|
||||
|
||||
+23
-17
@@ -151,11 +151,15 @@ def connect_clear_prompt(button):
|
||||
)
|
||||
|
||||
|
||||
def update_token_counter(text, steps):
|
||||
def update_token_counter(text, steps, *, is_positive=True):
|
||||
try:
|
||||
text, _ = extra_networks.parse_prompt(text)
|
||||
|
||||
_, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
|
||||
if is_positive:
|
||||
_, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
|
||||
else:
|
||||
prompt_flat_list = [text]
|
||||
|
||||
prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
|
||||
|
||||
except Exception:
|
||||
@@ -169,6 +173,10 @@ def update_token_counter(text, steps):
|
||||
return f"<span class='gr-box gr-text-input'>{token_count}/{max_length}</span>"
|
||||
|
||||
|
||||
def update_negative_prompt_token_counter(text, steps):
|
||||
return update_token_counter(text, steps, is_positive=False)
|
||||
|
||||
|
||||
class Toprow:
|
||||
"""Creates a top row UI with prompts, generate button, styles, extra little buttons for things, and enables some functionality related to their operation"""
|
||||
|
||||
@@ -215,9 +223,10 @@ class Toprow:
|
||||
)
|
||||
|
||||
with gr.Row(elem_id=f"{id_part}_tools"):
|
||||
self.paste = ToolButton(value=paste_symbol, elem_id="paste")
|
||||
self.clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt")
|
||||
self.restore_progress_button = ToolButton(value=restore_progress_symbol, elem_id=f"{id_part}_restore_progress", visible=False)
|
||||
self.paste = ToolButton(value=paste_symbol, elem_id="paste", tooltip="Read generation parameters from prompt or last generation if prompt is empty into user interface.")
|
||||
self.clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt", tooltip="Clear prompt")
|
||||
self.apply_styles = ToolButton(value=ui_prompt_styles.styles_materialize_symbol, elem_id=f"{id_part}_style_apply", tooltip="Apply all selected styles to prompts.")
|
||||
self.restore_progress_button = ToolButton(value=restore_progress_symbol, elem_id=f"{id_part}_restore_progress", visible=False, tooltip="Restore progress")
|
||||
|
||||
self.token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_token_counter", elem_classes=["token-counter"])
|
||||
self.token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
|
||||
@@ -232,6 +241,7 @@ class Toprow:
|
||||
)
|
||||
|
||||
self.ui_styles = ui_prompt_styles.UiPromptStyles(id_part, self.prompt, self.negative_prompt)
|
||||
self.ui_styles.setup_apply_button(self.apply_styles)
|
||||
|
||||
self.prompt_img.change(
|
||||
fn=modules.images.image_data,
|
||||
@@ -348,7 +358,7 @@ def create_ui():
|
||||
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height")
|
||||
|
||||
with gr.Column(elem_id="txt2img_dimensions_row", scale=1, elem_classes="dimensions-tools"):
|
||||
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn", label="Switch dims")
|
||||
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn", tooltip="Switch width/height")
|
||||
|
||||
if opts.dimensions_and_batch_together:
|
||||
with gr.Column(elem_id="txt2img_column_batch"):
|
||||
@@ -533,7 +543,7 @@ def create_ui():
|
||||
]
|
||||
|
||||
toprow.token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[toprow.prompt, steps], outputs=[toprow.token_counter])
|
||||
toprow.negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[toprow.negative_prompt, steps], outputs=[toprow.negative_token_counter])
|
||||
toprow.negative_token_button.click(fn=wrap_queued_call(update_negative_prompt_token_counter), inputs=[toprow.negative_prompt, steps], outputs=[toprow.negative_token_counter])
|
||||
|
||||
extra_networks_ui = ui_extra_networks.create_ui(txt2img_interface, [txt2img_generation_tab], 'txt2img')
|
||||
ui_extra_networks.setup_ui(extra_networks_ui, txt2img_gallery)
|
||||
@@ -614,7 +624,7 @@ def create_ui():
|
||||
with gr.Accordion("PNG info", open=False):
|
||||
img2img_batch_use_png_info = gr.Checkbox(label="Append png info to prompts", **shared.hide_dirs, elem_id="img2img_batch_use_png_info")
|
||||
img2img_batch_png_info_dir = gr.Textbox(label="PNG info directory", **shared.hide_dirs, placeholder="Leave empty to use input directory", elem_id="img2img_batch_png_info_dir")
|
||||
img2img_batch_png_info_props = gr.CheckboxGroup(["Prompt", "Negative prompt", "Seed", "CFG scale", "Sampler", "Steps"], label="Parameters to take from png info", info="Prompts from png info will be appended to prompts set in ui.")
|
||||
img2img_batch_png_info_props = gr.CheckboxGroup(["Prompt", "Negative prompt", "Seed", "CFG scale", "Sampler", "Steps", "Model hash"], label="Parameters to take from png info", info="Prompts from png info will be appended to prompts set in ui.")
|
||||
|
||||
img2img_tabs = [tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch]
|
||||
|
||||
@@ -661,8 +671,8 @@ def create_ui():
|
||||
width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width")
|
||||
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height")
|
||||
with gr.Column(elem_id="img2img_dimensions_row", scale=1, elem_classes="dimensions-tools"):
|
||||
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
|
||||
detect_image_size_btn = ToolButton(value=detect_image_size_symbol, elem_id="img2img_detect_image_size_btn")
|
||||
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn", tooltip="Switch width/height")
|
||||
detect_image_size_btn = ToolButton(value=detect_image_size_symbol, elem_id="img2img_detect_image_size_btn", tooltip="Auto detect size from img2img")
|
||||
|
||||
with gr.Tab(label="Resize by", elem_id="img2img_tab_resize_by") as tab_scale_by:
|
||||
scale_by = gr.Slider(minimum=0.05, maximum=4.0, step=0.05, label="Scale", value=1.0, elem_id="img2img_scale")
|
||||
@@ -1279,11 +1289,8 @@ def create_ui():
|
||||
with gr.TabItem(label, id=ifid, elem_id=f"tab_{ifid}"):
|
||||
interface.render()
|
||||
|
||||
for interface, _label, ifid in interfaces:
|
||||
if ifid in ["extensions", "settings"]:
|
||||
continue
|
||||
|
||||
loadsave.add_block(interface, ifid)
|
||||
if ifid not in ["extensions", "settings"]:
|
||||
loadsave.add_block(interface, ifid)
|
||||
|
||||
loadsave.add_component(f"webui/Tabs@{tabs.elem_id}", tabs)
|
||||
|
||||
@@ -1341,7 +1348,6 @@ checkpoint: <a id="sd_checkpoint_hash">N/A</a>
|
||||
|
||||
def setup_ui_api(app):
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List
|
||||
|
||||
class QuicksettingsHint(BaseModel):
|
||||
name: str = Field(title="Name of the quicksettings field")
|
||||
@@ -1350,7 +1356,7 @@ def setup_ui_api(app):
|
||||
def quicksettings_hint():
|
||||
return [QuicksettingsHint(name=k, label=v.label) for k, v in opts.data_labels.items()]
|
||||
|
||||
app.add_api_route("/internal/quicksettings-hint", quicksettings_hint, methods=["GET"], response_model=List[QuicksettingsHint])
|
||||
app.add_api_route("/internal/quicksettings-hint", quicksettings_hint, methods=["GET"], response_model=list[QuicksettingsHint])
|
||||
|
||||
app.add_api_route("/internal/ping", lambda: {}, methods=["GET"])
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ def setup_dialog(button_show, dialog, *, button_close=None):
|
||||
fn=lambda: gr.update(visible=True),
|
||||
inputs=[],
|
||||
outputs=[dialog],
|
||||
).then(fn=None, _js="function(){ popup(gradioApp().getElementById('" + dialog.elem_id + "')); }")
|
||||
).then(fn=None, _js="function(){ popupId('" + dialog.elem_id + "'); }")
|
||||
|
||||
if button_close:
|
||||
button_close.click(fn=None, _js="closePopup")
|
||||
|
||||
@@ -2,7 +2,7 @@ import json
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import git
|
||||
|
||||
@@ -177,7 +177,7 @@ def extension_table():
|
||||
<td>{remote}</td>
|
||||
<td>{ext.branch}</td>
|
||||
<td>{version_link}</td>
|
||||
<td>{time.asctime(time.gmtime(ext.commit_date))}</td>
|
||||
<td>{datetime.fromtimestamp(ext.commit_date) if ext.commit_date else ""}</td>
|
||||
<td{' class="extension_status"' if ext.remote is not None else ''}>{ext_status}</td>
|
||||
</tr>
|
||||
"""
|
||||
@@ -197,7 +197,7 @@ def update_config_states_table(state_name):
|
||||
config_state = config_states.all_config_states[state_name]
|
||||
|
||||
config_name = config_state.get("name", "Config")
|
||||
created_date = time.asctime(time.gmtime(config_state["created_at"]))
|
||||
created_date = datetime.fromtimestamp(config_state["created_at"]).strftime('%Y-%m-%d %H:%M:%S')
|
||||
filepath = config_state.get("filepath", "<unknown>")
|
||||
|
||||
try:
|
||||
@@ -442,7 +442,7 @@ sort_ordering = [
|
||||
|
||||
def get_date(info: dict, key):
|
||||
try:
|
||||
return datetime.strptime(info.get(key), "%Y-%m-%dT%H:%M:%SZ").strftime("%Y-%m-%d")
|
||||
return datetime.strptime(info.get(key), "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc).astimezone().strftime("%Y-%m-%d")
|
||||
except (ValueError, TypeError):
|
||||
return ''
|
||||
|
||||
@@ -557,8 +557,12 @@ def create_ui():
|
||||
msg = '"--disable-extra-extensions" was used, remove it to load all extensions again'
|
||||
html = f'<span style="color: var(--primary-400);">{msg}</span>'
|
||||
|
||||
info = gr.HTML(html)
|
||||
extensions_table = gr.HTML('Loading...')
|
||||
with gr.Row():
|
||||
info = gr.HTML(html)
|
||||
|
||||
with gr.Row(elem_classes="progress-container"):
|
||||
extensions_table = gr.HTML('Loading...', elem_id="extensions_installed_html")
|
||||
|
||||
ui.load(fn=extension_table, inputs=[], outputs=[extensions_table])
|
||||
|
||||
apply.click(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import functools
|
||||
import os.path
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
@@ -15,6 +16,17 @@ from modules.ui_components import ToolButton
|
||||
extra_pages = []
|
||||
allowed_dirs = set()
|
||||
|
||||
default_allowed_preview_extensions = ["png", "jpg", "jpeg", "webp", "gif"]
|
||||
|
||||
|
||||
@functools.cache
|
||||
def allowed_preview_extensions_with_extra(extra_extensions=None):
|
||||
return set(default_allowed_preview_extensions) | set(extra_extensions or [])
|
||||
|
||||
|
||||
def allowed_preview_extensions():
|
||||
return allowed_preview_extensions_with_extra((shared.opts.samples_format, ))
|
||||
|
||||
|
||||
def register_page(page):
|
||||
"""registers extra networks page for the UI; recommend doing it in on_before_ui() callback for extensions"""
|
||||
@@ -33,9 +45,9 @@ def fetch_file(filename: str = ""):
|
||||
if not any(Path(x).absolute() in Path(filename).absolute().parents for x in allowed_dirs):
|
||||
raise ValueError(f"File cannot be fetched: {filename}. Must be in one of directories registered by extra pages.")
|
||||
|
||||
ext = os.path.splitext(filename)[1].lower()
|
||||
if ext not in (".png", ".jpg", ".jpeg", ".webp", ".gif"):
|
||||
raise ValueError(f"File cannot be fetched: {filename}. Only png, jpg, webp, and gif.")
|
||||
ext = os.path.splitext(filename)[1].lower()[1:]
|
||||
if ext not in allowed_preview_extensions():
|
||||
raise ValueError(f"File cannot be fetched: {filename}. Extensions allowed: {allowed_preview_extensions()}.")
|
||||
|
||||
# would profit from returning 304
|
||||
return FileResponse(filename, headers={"Accept-Ranges": "bytes"})
|
||||
@@ -213,9 +225,9 @@ class ExtraNetworksPage:
|
||||
metadata_button = ""
|
||||
metadata = item.get("metadata")
|
||||
if metadata:
|
||||
metadata_button = f"<div class='metadata-button card-button' title='Show internal metadata' onclick='extraNetworksRequestMetadata(event, {quote_js(self.name)}, {quote_js(item['name'])})'></div>"
|
||||
metadata_button = f"<div class='metadata-button card-button' title='Show internal metadata' onclick='extraNetworksRequestMetadata(event, {quote_js(self.name)}, {quote_js(html.escape(item['name']))})'></div>"
|
||||
|
||||
edit_button = f"<div class='edit-button card-button' title='Edit metadata' onclick='extraNetworksEditUserMetadata(event, {quote_js(tabname)}, {quote_js(self.id_page)}, {quote_js(item['name'])})'></div>"
|
||||
edit_button = f"<div class='edit-button card-button' title='Edit metadata' onclick='extraNetworksEditUserMetadata(event, {quote_js(tabname)}, {quote_js(self.id_page)}, {quote_js(html.escape(item['name']))})'></div>"
|
||||
|
||||
local_path = ""
|
||||
filename = item.get("filename", "")
|
||||
@@ -235,7 +247,7 @@ class ExtraNetworksPage:
|
||||
if search_only and shared.opts.extra_networks_hidden_models == "Never":
|
||||
return ""
|
||||
|
||||
sort_keys = " ".join([html.escape(f'data-sort-{k}={v}') for k, v in item.get("sort_keys", {}).items()]).strip()
|
||||
sort_keys = " ".join([f'data-sort-{k}="{html.escape(str(v))}"' for k, v in item.get("sort_keys", {}).items()]).strip()
|
||||
|
||||
args = {
|
||||
"background_image": background_image,
|
||||
@@ -273,11 +285,7 @@ class ExtraNetworksPage:
|
||||
Find a preview PNG for a given path (without extension) and call link_preview on it.
|
||||
"""
|
||||
|
||||
preview_extensions = ["png", "jpg", "jpeg", "webp"]
|
||||
if shared.opts.samples_format not in preview_extensions:
|
||||
preview_extensions.append(shared.opts.samples_format)
|
||||
|
||||
potential_files = sum([[path + "." + ext, path + ".preview." + ext] for ext in preview_extensions], [])
|
||||
potential_files = sum([[path + "." + ext, path + ".preview." + ext] for ext in allowed_preview_extensions()], [])
|
||||
|
||||
for file in potential_files:
|
||||
if os.path.isfile(file):
|
||||
@@ -374,7 +382,7 @@ def create_ui(interface: gr.Blocks, unrelated_tabs, tabname):
|
||||
|
||||
edit_search = gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", elem_classes="search", placeholder="Search...", visible=False, interactive=True)
|
||||
dropdown_sort = gr.Dropdown(choices=['Default Sort', 'Date Created', 'Date Modified', 'Name'], value='Default Sort', elem_id=tabname+"_extra_sort", elem_classes="sort", multiselect=False, visible=False, show_label=False, interactive=True, label=tabname+"_extra_sort_order")
|
||||
button_sortorder = ToolButton(switch_values_symbol, elem_id=tabname+"_extra_sortorder", elem_classes="sortorder", visible=False)
|
||||
button_sortorder = ToolButton(switch_values_symbol, elem_id=tabname+"_extra_sortorder", elem_classes="sortorder", visible=False, tooltip="Invert sort order")
|
||||
button_refresh = gr.Button('Refresh', elem_id=tabname+"_extra_refresh", visible=False)
|
||||
checkbox_show_dirs = gr.Checkbox(True, label='Show dirs', elem_id=tabname+"_extra_show_dirs", elem_classes="show-dirs", visible=False)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import os.path
|
||||
|
||||
import gradio as gr
|
||||
|
||||
from modules import generation_parameters_copypaste, images, sysinfo, errors
|
||||
from modules import generation_parameters_copypaste, images, sysinfo, errors, ui_extra_networks
|
||||
|
||||
|
||||
class UserMetadataEditor:
|
||||
@@ -89,6 +89,13 @@ class UserMetadataEditor:
|
||||
|
||||
return preview
|
||||
|
||||
def relative_path(self, path):
|
||||
for parent_path in self.page.allowed_directories_for_previews():
|
||||
if ui_extra_networks.path_is_parent(parent_path, path):
|
||||
return os.path.relpath(path, parent_path)
|
||||
|
||||
return os.path.basename(path)
|
||||
|
||||
def get_metadata_table(self, name):
|
||||
item = self.page.items.get(name, {})
|
||||
try:
|
||||
@@ -97,7 +104,7 @@ class UserMetadataEditor:
|
||||
|
||||
stats = os.stat(filename)
|
||||
params = [
|
||||
('Filename: ', os.path.basename(filename)),
|
||||
('Filename: ', self.relative_path(filename)),
|
||||
('File size: ', sysinfo.pretty_bytes(stats.st_size)),
|
||||
('Hash: ', shorthash),
|
||||
('Modified: ', datetime.datetime.fromtimestamp(stats.st_mtime).strftime('%Y-%m-%d %H:%M')),
|
||||
|
||||
@@ -2,12 +2,12 @@ import os
|
||||
import gradio as gr
|
||||
|
||||
from modules import localization, shared, scripts
|
||||
from modules.paths import script_path, data_path
|
||||
from modules.paths import script_path, data_path, cwd
|
||||
|
||||
|
||||
def webpath(fn):
|
||||
if fn.startswith(script_path):
|
||||
web_path = os.path.relpath(fn, script_path).replace('\\', '/')
|
||||
if fn.startswith(cwd):
|
||||
web_path = os.path.relpath(fn, cwd)
|
||||
else:
|
||||
web_path = os.path.abspath(fn)
|
||||
|
||||
|
||||
+26
-9
@@ -4,7 +4,11 @@ import os
|
||||
import gradio as gr
|
||||
|
||||
from modules import errors
|
||||
from modules.ui_components import ToolButton
|
||||
from modules.ui_components import ToolButton, InputAccordion
|
||||
|
||||
|
||||
def radio_choices(comp): # gradio 3.41 changes choices from list of values to list of pairs
|
||||
return [x[0] if isinstance(x, tuple) else x for x in getattr(comp, 'choices', [])]
|
||||
|
||||
|
||||
class UiLoadsave:
|
||||
@@ -37,20 +41,24 @@ class UiLoadsave:
|
||||
key = f"{path}/{field}"
|
||||
|
||||
if getattr(obj, 'custom_script_source', None) is not None:
|
||||
key = f"customscript/{obj.custom_script_source}/{key}"
|
||||
key = f"customscript/{obj.custom_script_source}/{key}"
|
||||
|
||||
if getattr(obj, 'do_not_save_to_config', False):
|
||||
return
|
||||
|
||||
saved_value = self.ui_settings.get(key, None)
|
||||
|
||||
if isinstance(obj, gr.Accordion) and isinstance(x, InputAccordion) and field == 'value':
|
||||
field = 'open'
|
||||
|
||||
if saved_value is None:
|
||||
self.ui_settings[key] = getattr(obj, field)
|
||||
elif condition and not condition(saved_value):
|
||||
pass
|
||||
else:
|
||||
if isinstance(x, gr.Textbox) and field == 'value': # due to an undesirable behavior of gr.Textbox, if you give it an int value instead of str, everything dies
|
||||
if isinstance(obj, gr.Textbox) and field == 'value': # due to an undesirable behavior of gr.Textbox, if you give it an int value instead of str, everything dies
|
||||
saved_value = str(saved_value)
|
||||
elif isinstance(x, gr.Number) and field == 'value':
|
||||
elif isinstance(obj, gr.Number) and field == 'value':
|
||||
try:
|
||||
saved_value = float(saved_value)
|
||||
except ValueError:
|
||||
@@ -61,7 +69,7 @@ class UiLoadsave:
|
||||
init_field(saved_value)
|
||||
|
||||
if field == 'value' and key not in self.component_mapping:
|
||||
self.component_mapping[key] = x
|
||||
self.component_mapping[key] = obj
|
||||
|
||||
if type(x) in [gr.Slider, gr.Radio, gr.Checkbox, gr.Textbox, gr.Number, gr.Dropdown, ToolButton, gr.Button] and x.visible:
|
||||
apply_field(x, 'visible')
|
||||
@@ -73,7 +81,7 @@ class UiLoadsave:
|
||||
apply_field(x, 'step')
|
||||
|
||||
if type(x) == gr.Radio:
|
||||
apply_field(x, 'value', lambda val: val in x.choices)
|
||||
apply_field(x, 'value', lambda val: val in radio_choices(x))
|
||||
|
||||
if type(x) == gr.Checkbox:
|
||||
apply_field(x, 'value')
|
||||
@@ -86,13 +94,20 @@ class UiLoadsave:
|
||||
|
||||
if type(x) == gr.Dropdown:
|
||||
def check_dropdown(val):
|
||||
choices = radio_choices(x)
|
||||
if getattr(x, 'multiselect', False):
|
||||
return all(value in x.choices for value in val)
|
||||
return all(value in choices for value in val)
|
||||
else:
|
||||
return val in x.choices
|
||||
return val in choices
|
||||
|
||||
apply_field(x, 'value', check_dropdown, getattr(x, 'init_field', None))
|
||||
|
||||
if type(x) == InputAccordion:
|
||||
if x.accordion.visible:
|
||||
apply_field(x.accordion, 'visible')
|
||||
apply_field(x, 'value')
|
||||
apply_field(x.accordion, 'value')
|
||||
|
||||
def check_tab_id(tab_id):
|
||||
tab_items = list(filter(lambda e: isinstance(e, gr.TabItem), x.children))
|
||||
if type(tab_id) == str:
|
||||
@@ -146,12 +161,14 @@ class UiLoadsave:
|
||||
for (path, component), new_value in zip(self.component_mapping.items(), values):
|
||||
old_value = current_ui_settings.get(path)
|
||||
|
||||
choices = getattr(component, 'choices', None)
|
||||
choices = radio_choices(component)
|
||||
if isinstance(new_value, int) and choices:
|
||||
if new_value >= len(choices):
|
||||
continue
|
||||
|
||||
new_value = choices[new_value]
|
||||
if isinstance(new_value, tuple):
|
||||
new_value = new_value[0]
|
||||
|
||||
if new_value == old_value:
|
||||
continue
|
||||
|
||||
@@ -4,6 +4,7 @@ from modules import shared, ui_common, ui_components, styles
|
||||
|
||||
styles_edit_symbol = '\U0001f58c\uFE0F' # 🖌️
|
||||
styles_materialize_symbol = '\U0001f4cb' # 📋
|
||||
styles_copy_symbol = '\U0001f4dd' # 📝
|
||||
|
||||
|
||||
def select_style(name):
|
||||
@@ -52,6 +53,8 @@ def refresh_styles():
|
||||
class UiPromptStyles:
|
||||
def __init__(self, tabname, main_ui_prompt, main_ui_negative_prompt):
|
||||
self.tabname = tabname
|
||||
self.main_ui_prompt = main_ui_prompt
|
||||
self.main_ui_negative_prompt = main_ui_negative_prompt
|
||||
|
||||
with gr.Row(elem_id=f"{tabname}_styles_row"):
|
||||
self.dropdown = gr.Dropdown(label="Styles", show_label=False, elem_id=f"{tabname}_styles", choices=list(shared.prompt_styles.styles), value=[], multiselect=True, tooltip="Styles")
|
||||
@@ -61,7 +64,8 @@ class UiPromptStyles:
|
||||
with gr.Row():
|
||||
self.selection = gr.Dropdown(label="Styles", elem_id=f"{tabname}_styles_edit_select", choices=list(shared.prompt_styles.styles), value=[], allow_custom_value=True, info="Styles allow you to add custom text to prompt. Use the {prompt} token in style text, and it will be replaced with user's prompt when applying style. Otherwise, style's text will be added to the end of the prompt.")
|
||||
ui_common.create_refresh_button([self.dropdown, self.selection], shared.prompt_styles.reload, lambda: {"choices": list(shared.prompt_styles.styles)}, f"refresh_{tabname}_styles")
|
||||
self.materialize = ui_components.ToolButton(value=styles_materialize_symbol, elem_id=f"{tabname}_style_apply", tooltip="Apply all selected styles from the style selction dropdown in main UI to the prompt.")
|
||||
self.materialize = ui_components.ToolButton(value=styles_materialize_symbol, elem_id=f"{tabname}_style_apply_dialog", tooltip="Apply all selected styles from the style selction dropdown in main UI to the prompt.")
|
||||
self.copy = ui_components.ToolButton(value=styles_copy_symbol, elem_id=f"{tabname}_style_copy", tooltip="Copy main UI prompt to style.")
|
||||
|
||||
with gr.Row():
|
||||
self.prompt = gr.Textbox(label="Prompt", show_label=True, elem_id=f"{tabname}_edit_style_prompt", lines=3)
|
||||
@@ -96,15 +100,21 @@ class UiPromptStyles:
|
||||
show_progress=False,
|
||||
).then(refresh_styles, outputs=[self.dropdown, self.selection], show_progress=False)
|
||||
|
||||
self.materialize.click(
|
||||
fn=materialize_styles,
|
||||
inputs=[main_ui_prompt, main_ui_negative_prompt, self.dropdown],
|
||||
outputs=[main_ui_prompt, main_ui_negative_prompt, self.dropdown],
|
||||
self.setup_apply_button(self.materialize)
|
||||
|
||||
self.copy.click(
|
||||
fn=lambda p, n: (p, n),
|
||||
inputs=[main_ui_prompt, main_ui_negative_prompt],
|
||||
outputs=[self.prompt, self.neg_prompt],
|
||||
show_progress=False,
|
||||
).then(fn=None, _js="function(){update_"+tabname+"_tokens(); closePopup();}", show_progress=False)
|
||||
)
|
||||
|
||||
ui_common.setup_dialog(button_show=edit_button, dialog=styles_dialog, button_close=self.close)
|
||||
|
||||
|
||||
|
||||
|
||||
def setup_apply_button(self, button):
|
||||
button.click(
|
||||
fn=materialize_styles,
|
||||
inputs=[self.main_ui_prompt, self.main_ui_negative_prompt, self.dropdown],
|
||||
outputs=[self.main_ui_prompt, self.main_ui_negative_prompt, self.dropdown],
|
||||
show_progress=False,
|
||||
).then(fn=None, _js="function(){update_"+self.tabname+"_tokens(); closePopup();}", show_progress=False)
|
||||
|
||||
+34
-3
@@ -5,6 +5,7 @@ from modules.call_queue import wrap_gradio_call
|
||||
from modules.shared import opts
|
||||
from modules.ui_components import FormRow
|
||||
from modules.ui_gradio_extensions import reload_javascript
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
|
||||
def get_value_for_setting(key):
|
||||
@@ -63,6 +64,9 @@ class UiSettings:
|
||||
quicksettings_list = None
|
||||
quicksettings_names = None
|
||||
text_settings = None
|
||||
show_all_pages = None
|
||||
show_one_page = None
|
||||
search_input = None
|
||||
|
||||
def run_settings(self, *args):
|
||||
changed = []
|
||||
@@ -87,7 +91,7 @@ class UiSettings:
|
||||
if not opts.same_type(value, opts.data_labels[key].default):
|
||||
return gr.update(visible=True), opts.dumpjson()
|
||||
|
||||
if not opts.set(key, value):
|
||||
if value is None or not opts.set(key, value):
|
||||
return gr.update(value=getattr(opts, key)), opts.dumpjson()
|
||||
|
||||
opts.save(shared.config_filename)
|
||||
@@ -135,7 +139,7 @@ class UiSettings:
|
||||
gr.Group()
|
||||
current_tab = gr.TabItem(elem_id=f"settings_{elem_id}", label=text)
|
||||
current_tab.__enter__()
|
||||
current_row = gr.Column(variant='compact')
|
||||
current_row = gr.Column(elem_id=f"column_settings_{elem_id}", variant='compact')
|
||||
current_row.__enter__()
|
||||
|
||||
previous_section = item.section
|
||||
@@ -175,11 +179,18 @@ class UiSettings:
|
||||
with gr.Row():
|
||||
unload_sd_model = gr.Button(value='Unload SD checkpoint to free VRAM', elem_id="sett_unload_sd_model")
|
||||
reload_sd_model = gr.Button(value='Reload the last SD checkpoint back into VRAM', elem_id="sett_reload_sd_model")
|
||||
with gr.Row():
|
||||
calculate_all_checkpoint_hash = gr.Button(value='Calculate hash for all checkpoint', elem_id="calculate_all_checkpoint_hash")
|
||||
calculate_all_checkpoint_hash_threads = gr.Number(value=1, label="Number of parallel calculations", elem_id="calculate_all_checkpoint_hash_threads", precision=0, minimum=1)
|
||||
|
||||
with gr.TabItem("Licenses", id="licenses", elem_id="settings_tab_licenses"):
|
||||
gr.HTML(shared.html("licenses.html"), elem_id="licenses")
|
||||
|
||||
gr.Button(value="Show all pages", elem_id="settings_show_all_pages")
|
||||
self.show_all_pages = gr.Button(value="Show all pages", elem_id="settings_show_all_pages")
|
||||
self.show_one_page = gr.Button(value="Show only one page", elem_id="settings_show_one_page", visible=False)
|
||||
self.show_one_page.click(lambda: None)
|
||||
|
||||
self.search_input = gr.Textbox(value="", elem_id="settings_search", max_lines=1, placeholder="Search...", show_label=False)
|
||||
|
||||
self.text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False)
|
||||
|
||||
@@ -241,6 +252,21 @@ class UiSettings:
|
||||
outputs=[sysinfo_check_output],
|
||||
)
|
||||
|
||||
def calculate_all_checkpoint_hash_fn(max_thread):
|
||||
checkpoints_list = sd_models.checkpoints_list.values()
|
||||
with ThreadPoolExecutor(max_workers=max_thread) as executor:
|
||||
futures = [executor.submit(checkpoint.calculate_shorthash) for checkpoint in checkpoints_list]
|
||||
completed = 0
|
||||
for _ in as_completed(futures):
|
||||
completed += 1
|
||||
print(f"{completed} / {len(checkpoints_list)} ")
|
||||
print("Finish calculating hash for all checkpoints")
|
||||
|
||||
calculate_all_checkpoint_hash.click(
|
||||
fn=calculate_all_checkpoint_hash_fn,
|
||||
inputs=[calculate_all_checkpoint_hash_threads],
|
||||
)
|
||||
|
||||
self.interface = settings_interface
|
||||
|
||||
def add_quicksettings(self):
|
||||
@@ -294,3 +320,8 @@ class UiSettings:
|
||||
outputs=[self.component_dict[k] for k in component_keys],
|
||||
queue=False,
|
||||
)
|
||||
|
||||
def search(self, text):
|
||||
print(text)
|
||||
|
||||
return [gr.update(visible=text in (comp.label or "")) for comp in self.components]
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ clean-fid
|
||||
einops
|
||||
fastapi>=0.90.1
|
||||
gfpgan
|
||||
gradio==3.41.0
|
||||
gradio==3.41.2
|
||||
inflection
|
||||
jsonmerge
|
||||
kornia
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
GitPython==3.1.32
|
||||
Pillow==9.5.0
|
||||
Pillow==10.0.1
|
||||
accelerate==0.21.0
|
||||
basicsr==1.4.2
|
||||
blendmodes==2022
|
||||
blendmodes==2023
|
||||
clean-fid==0.1.35
|
||||
einops==0.4.1
|
||||
fastapi==0.94.0
|
||||
gfpgan==1.3.8
|
||||
gradio==3.41.0
|
||||
gradio==3.41.2
|
||||
httpcore==0.15
|
||||
inflection==0.5.1
|
||||
jsonmerge==1.8.0
|
||||
@@ -27,5 +27,5 @@ timm==0.9.2
|
||||
tomesd==0.1.3
|
||||
torch
|
||||
torchdiffeq==0.2.3
|
||||
torchsde==0.2.5
|
||||
torchsde==0.2.6
|
||||
transformers==4.30.2
|
||||
|
||||
@@ -29,7 +29,7 @@ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing):
|
||||
upscaling_resize_w = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="extras_upscaling_resize_w")
|
||||
upscaling_resize_h = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="extras_upscaling_resize_h")
|
||||
with gr.Column(elem_id="upscaling_dimensions_row", scale=1, elem_classes="dimensions-tools"):
|
||||
upscaling_res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="upscaling_res_switch_btn")
|
||||
upscaling_res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="upscaling_res_switch_btn", tooltip="Switch width/height")
|
||||
upscaling_crop = gr.Checkbox(label='Crop to fit', value=True, elem_id="extras_upscaling_crop")
|
||||
|
||||
with FormRow():
|
||||
|
||||
@@ -5,11 +5,17 @@ import shlex
|
||||
import modules.scripts as scripts
|
||||
import gradio as gr
|
||||
|
||||
from modules import sd_samplers, errors
|
||||
from modules import sd_samplers, errors, sd_models
|
||||
from modules.processing import Processed, process_images
|
||||
from modules.shared import state
|
||||
|
||||
|
||||
def process_model_tag(tag):
|
||||
info = sd_models.get_closet_checkpoint_match(tag)
|
||||
assert info is not None, f'Unknown checkpoint: {tag}'
|
||||
return info.name
|
||||
|
||||
|
||||
def process_string_tag(tag):
|
||||
return tag
|
||||
|
||||
@@ -27,7 +33,7 @@ def process_boolean_tag(tag):
|
||||
|
||||
|
||||
prompt_tags = {
|
||||
"sd_model": None,
|
||||
"sd_model": process_model_tag,
|
||||
"outpath_samples": process_string_tag,
|
||||
"outpath_grids": process_string_tag,
|
||||
"prompt_for_display": process_string_tag,
|
||||
@@ -156,7 +162,10 @@ class Script(scripts.Script):
|
||||
|
||||
copy_p = copy.copy(p)
|
||||
for k, v in args.items():
|
||||
setattr(copy_p, k, v)
|
||||
if k == "sd_model":
|
||||
copy_p.override_settings['sd_model_checkpoint'] = v
|
||||
else:
|
||||
setattr(copy_p, k, v)
|
||||
|
||||
proc = process_images(copy_p)
|
||||
images += proc.images
|
||||
|
||||
+10
-4
@@ -205,13 +205,14 @@ def csv_string_to_list_strip(data_str):
|
||||
|
||||
|
||||
class AxisOption:
|
||||
def __init__(self, label, type, apply, format_value=format_value_add_label, confirm=None, cost=0.0, choices=None):
|
||||
def __init__(self, label, type, apply, format_value=format_value_add_label, confirm=None, cost=0.0, choices=None, prepare=None):
|
||||
self.label = label
|
||||
self.type = type
|
||||
self.apply = apply
|
||||
self.format_value = format_value
|
||||
self.confirm = confirm
|
||||
self.cost = cost
|
||||
self.prepare = prepare
|
||||
self.choices = choices
|
||||
|
||||
|
||||
@@ -238,9 +239,9 @@ axis_options = [
|
||||
AxisOptionImg2Img("Image CFG Scale", float, apply_field("image_cfg_scale")),
|
||||
AxisOption("Prompt S/R", str, apply_prompt, format_value=format_value),
|
||||
AxisOption("Prompt order", str_permutations, apply_order, format_value=format_value_join_list),
|
||||
AxisOptionTxt2Img("Sampler", str, apply_field("sampler_name"), format_value=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),
|
||||
AxisOptionTxt2Img("Hires sampler", str, apply_field("hr_sampler_name"), confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img]),
|
||||
AxisOptionImg2Img("Sampler", str, apply_field("sampler_name"), format_value=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img]),
|
||||
AxisOptionTxt2Img("Sampler", str, apply_field("sampler_name"), format_value=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers if x.name not in opts.hide_samplers]),
|
||||
AxisOptionTxt2Img("Hires sampler", str, apply_field("hr_sampler_name"), confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img if x.name not in opts.hide_samplers]),
|
||||
AxisOptionImg2Img("Sampler", str, apply_field("sampler_name"), format_value=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img if x.name not in opts.hide_samplers]),
|
||||
AxisOption("Checkpoint name", str, apply_checkpoint, format_value=format_remove_path, confirm=confirm_checkpoints, cost=1.0, choices=lambda: sorted(sd_models.checkpoints_list, key=str.casefold)),
|
||||
AxisOption("Negative Guidance minimum sigma", float, apply_field("s_min_uncond")),
|
||||
AxisOption("Sigma Churn", float, apply_field("s_churn")),
|
||||
@@ -265,6 +266,7 @@ axis_options = [
|
||||
AxisOption("Token merging ratio", float, apply_override('token_merging_ratio')),
|
||||
AxisOption("Token merging ratio high-res", float, apply_override('token_merging_ratio_hr')),
|
||||
AxisOption("Always discard next-to-last sigma", str, apply_override('always_discard_next_to_last_sigma', boolean=True), choices=boolean_choice(reverse=True)),
|
||||
AxisOption("SGM noise multiplier", str, apply_override('sgm_noise_multiplier', boolean=True), choices=boolean_choice(reverse=True)),
|
||||
AxisOption("Refiner checkpoint", str, apply_field('refiner_checkpoint'), format_value=format_remove_path, confirm=confirm_checkpoints_or_none, cost=1.0, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list, key=str.casefold)),
|
||||
AxisOption("Refiner switch at", float, apply_field('refiner_switch_at')),
|
||||
AxisOption("RNG source", str, apply_override("randn_source"), choices=lambda: ["GPU", "CPU", "NV"]),
|
||||
@@ -535,6 +537,8 @@ class Script(scripts.Script):
|
||||
|
||||
if opt.choices is not None and not csv_mode:
|
||||
valslist = vals_dropdown
|
||||
elif opt.prepare is not None:
|
||||
valslist = opt.prepare(vals)
|
||||
else:
|
||||
valslist = csv_string_to_list_strip(vals)
|
||||
|
||||
@@ -772,6 +776,8 @@ class Script(scripts.Script):
|
||||
# TODO: See previous comment about intentional data misalignment.
|
||||
adj_g = g-1 if g > 0 else g
|
||||
images.save_image(processed.images[g], p.outpath_grids, "xyz_grid", info=processed.infotexts[g], extension=opts.grid_format, prompt=processed.all_prompts[adj_g], seed=processed.all_seeds[adj_g], grid=True, p=processed)
|
||||
if not include_sub_grids: # if not include_sub_grids then skip saving after the first grid
|
||||
break
|
||||
|
||||
if not include_sub_grids:
|
||||
# Done with sub-grids, drop all related information:
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600&display=swap');
|
||||
|
||||
|
||||
/* temporary fix to hide gradio crop tool until it's fixed https://github.com/gradio-app/gradio/issues/3810 */
|
||||
|
||||
div.gradio-image button[aria-label="Edit"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* general gradio fixes */
|
||||
|
||||
:root, .dark{
|
||||
@@ -75,8 +83,10 @@ div.compact{
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.gradio-dropdown ul.options li.item {
|
||||
padding: 0.05em 0;
|
||||
@media (pointer:fine) {
|
||||
.gradio-dropdown ul.options li.item {
|
||||
padding: 0.05em 0;
|
||||
}
|
||||
}
|
||||
|
||||
.gradio-dropdown ul.options li.item.selected {
|
||||
@@ -413,6 +423,7 @@ div#extras_scale_to_tab div.form{
|
||||
#settings > div{
|
||||
border: none;
|
||||
margin-left: 10em;
|
||||
padding: 0 var(--spacing-xl);
|
||||
}
|
||||
|
||||
#settings > div.tab-nav{
|
||||
@@ -427,6 +438,7 @@ div#extras_scale_to_tab div.form{
|
||||
border: none;
|
||||
text-align: left;
|
||||
white-space: initial;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#settings_result{
|
||||
@@ -509,6 +521,11 @@ table.popup-table .link{
|
||||
background: #b4c0cc;
|
||||
border-radius: 3px !important;
|
||||
top: -20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.progress-container{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[id$=_results].mobile{
|
||||
@@ -568,7 +585,6 @@ table.popup-table .link{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(20, 20, 20, 0.95);
|
||||
}
|
||||
|
||||
.global-popup *{
|
||||
@@ -577,9 +593,6 @@ table.popup-table .link{
|
||||
|
||||
.global-popup-close:before {
|
||||
content: "×";
|
||||
}
|
||||
|
||||
.global-popup-close{
|
||||
position: fixed;
|
||||
right: 0.25em;
|
||||
top: 0;
|
||||
@@ -588,10 +601,20 @@ table.popup-table .link{
|
||||
font-size: 32pt;
|
||||
}
|
||||
|
||||
.global-popup-close{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(20, 20, 20, 0.95);
|
||||
}
|
||||
|
||||
.global-popup-inner{
|
||||
display: inline-block;
|
||||
margin: auto;
|
||||
padding: 2em;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
/* fullpage image viewer */
|
||||
@@ -613,6 +636,9 @@ table.popup-table .link{
|
||||
|
||||
.modalControls {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
left: 0px;
|
||||
gap: 1em;
|
||||
padding: 1em;
|
||||
background-color:rgba(0,0,0,0);
|
||||
@@ -652,13 +678,6 @@ table.popup-table .link{
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
#modalImage{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
|
||||
.modalPrev,
|
||||
.modalNext {
|
||||
cursor: pointer;
|
||||
@@ -1001,6 +1020,8 @@ div.block.gradio-box.edit-user-metadata {
|
||||
|
||||
.edit-user-metadata .file-metadata th, .edit-user-metadata .file-metadata td{
|
||||
padding: 0.3em 1em;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.edit-user-metadata .wrap.translucent{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@echo off
|
||||
|
||||
if not defined PYTHON (set PYTHON=python)
|
||||
if defined GIT (set "GIT_PYTHON_GIT_EXECUTABLE=%GIT%")
|
||||
if not defined VENV_DIR (set "VENV_DIR=%~dp0%venv")
|
||||
|
||||
set SD_WEBUI_RESTART=tmp/restart
|
||||
|
||||
@@ -74,7 +74,7 @@ def webui():
|
||||
if shared.opts.auto_launch_browser == "Remote" or cmd_opts.autolaunch:
|
||||
auto_launch_browser = True
|
||||
elif shared.opts.auto_launch_browser == "Local":
|
||||
auto_launch_browser = not any([cmd_opts.listen, cmd_opts.share, cmd_opts.ngrok])
|
||||
auto_launch_browser = not cmd_opts.webui_is_non_local
|
||||
|
||||
app, local_url, share_url = shared.demo.launch(
|
||||
share=cmd_opts.share,
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
# change the variables in webui-user.sh instead #
|
||||
#################################################
|
||||
|
||||
|
||||
use_venv=1
|
||||
if [[ $venv_dir == "-" ]]; then
|
||||
use_venv=0
|
||||
fi
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
|
||||
@@ -28,6 +22,12 @@ then
|
||||
source "$SCRIPT_DIR"/webui-user.sh
|
||||
fi
|
||||
|
||||
# If $venv_dir is "-", then disable venv support
|
||||
use_venv=1
|
||||
if [[ $venv_dir == "-" ]]; then
|
||||
use_venv=0
|
||||
fi
|
||||
|
||||
# Set defaults
|
||||
# Install directory without trailing slash
|
||||
if [[ -z "${install_dir}" ]]
|
||||
@@ -51,6 +51,8 @@ fi
|
||||
if [[ -z "${GIT}" ]]
|
||||
then
|
||||
export GIT="git"
|
||||
else
|
||||
export GIT_PYTHON_GIT_EXECUTABLE="${GIT}"
|
||||
fi
|
||||
|
||||
# python3 venv without trailing slash (defaults to ${install_dir}/${clone_dir}/venv)
|
||||
@@ -141,9 +143,8 @@ case "$gpu_info" in
|
||||
*"Navi 2"*) export HSA_OVERRIDE_GFX_VERSION=10.3.0
|
||||
;;
|
||||
*"Navi 3"*) [[ -z "${TORCH_COMMAND}" ]] && \
|
||||
export TORCH_COMMAND="pip install --pre torch torchvision --index-url https://download.pytorch.org/whl/nightly/rocm5.6"
|
||||
# Navi 3 needs at least 5.5 which is only on the nightly chain, previous versions are no longer online (torch==2.1.0.dev-20230614+rocm5.5 torchvision==0.16.0.dev-20230614+rocm5.5 torchaudio==2.1.0.dev-20230614+rocm5.5)
|
||||
# so switch to nightly rocm5.6 without explicit versions this time
|
||||
export TORCH_COMMAND="pip install torch torchvision --index-url https://download.pytorch.org/whl/test/rocm5.6"
|
||||
# Navi 3 needs at least 5.5 which is only on the torch 2.1.0 release candidates right now
|
||||
;;
|
||||
*"Renoir"*) export HSA_OVERRIDE_GFX_VERSION=9.0.0
|
||||
printf "\n%s\n" "${delimiter}"
|
||||
|
||||
Reference in New Issue
Block a user