Upload ui.py
Browse files
ui.py
ADDED
|
@@ -0,0 +1,1621 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import datetime
|
| 2 |
+
import json
|
| 3 |
+
import mimetypes
|
| 4 |
+
import os
|
| 5 |
+
import sys
|
| 6 |
+
from functools import reduce
|
| 7 |
+
import warnings
|
| 8 |
+
|
| 9 |
+
import gradio as gr
|
| 10 |
+
import gradio.utils
|
| 11 |
+
import numpy as np
|
| 12 |
+
from PIL import Image, PngImagePlugin # noqa: F401
|
| 13 |
+
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call
|
| 14 |
+
|
| 15 |
+
from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, errors, shared_items, ui_settings, timer, sysinfo
|
| 16 |
+
from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML
|
| 17 |
+
from modules.paths import script_path
|
| 18 |
+
from modules.ui_common import create_refresh_button
|
| 19 |
+
from modules.ui_gradio_extensions import reload_javascript
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
from modules.shared import opts, cmd_opts
|
| 23 |
+
|
| 24 |
+
import modules.codeformer_model
|
| 25 |
+
import modules.generation_parameters_copypaste as parameters_copypaste
|
| 26 |
+
import modules.gfpgan_model
|
| 27 |
+
import modules.hypernetworks.ui
|
| 28 |
+
import modules.scripts
|
| 29 |
+
import modules.shared as shared
|
| 30 |
+
import modules.styles
|
| 31 |
+
import modules.textual_inversion.ui
|
| 32 |
+
from modules import prompt_parser
|
| 33 |
+
from modules.sd_hijack import model_hijack
|
| 34 |
+
from modules.sd_samplers import samplers, samplers_for_img2img
|
| 35 |
+
from modules.textual_inversion import textual_inversion
|
| 36 |
+
import modules.hypernetworks.ui
|
| 37 |
+
from modules.generation_parameters_copypaste import image_from_url_text
|
| 38 |
+
import modules.extras
|
| 39 |
+
|
| 40 |
+
create_setting_component = ui_settings.create_setting_component
|
| 41 |
+
|
| 42 |
+
warnings.filterwarnings("default" if opts.show_warnings else "ignore", category=UserWarning)
|
| 43 |
+
|
| 44 |
+
# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI
|
| 45 |
+
mimetypes.init()
|
| 46 |
+
mimetypes.add_type('application/javascript', '.js')
|
| 47 |
+
|
| 48 |
+
if not cmd_opts.share and not cmd_opts.listen:
|
| 49 |
+
# fix gradio phoning home
|
| 50 |
+
gradio.utils.version_check = lambda: None
|
| 51 |
+
gradio.utils.get_local_ip_address = lambda: '127.0.0.1'
|
| 52 |
+
|
| 53 |
+
if cmd_opts.ngrok is not None:
|
| 54 |
+
import modules.ngrok as ngrok
|
| 55 |
+
print('ngrok authtoken detected, trying to connect...')
|
| 56 |
+
ngrok.connect(
|
| 57 |
+
cmd_opts.ngrok,
|
| 58 |
+
cmd_opts.port if cmd_opts.port is not None else 7860,
|
| 59 |
+
cmd_opts.ngrok_options
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def gr_show(visible=True):
|
| 64 |
+
return {"visible": visible, "__type__": "update"}
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
sample_img2img = "assets/stable-samples/img2img/sketch-mountains-input.jpg"
|
| 68 |
+
sample_img2img = sample_img2img if os.path.exists(sample_img2img) else None
|
| 69 |
+
|
| 70 |
+
# Using constants for these since the variation selector isn't visible.
|
| 71 |
+
# Important that they exactly match script.js for tooltip to work.
|
| 72 |
+
random_symbol = '\U0001f3b2\ufe0f' # 🎲️
|
| 73 |
+
reuse_symbol = '\u267b\ufe0f' # ♻️
|
| 74 |
+
paste_symbol = '\u2199\ufe0f' # ↙
|
| 75 |
+
refresh_symbol = '\U0001f504' # 🔄
|
| 76 |
+
save_style_symbol = '\U0001f4be' # 💾
|
| 77 |
+
apply_style_symbol = '\U0001f4cb' # 📋
|
| 78 |
+
clear_prompt_symbol = '\U0001f5d1\ufe0f' # 🗑️
|
| 79 |
+
extra_networks_symbol = '\U0001F3B4' # 🎴
|
| 80 |
+
switch_values_symbol = '\U000021C5' # ⇅
|
| 81 |
+
restore_progress_symbol = '\U0001F300' # 🌀
|
| 82 |
+
detect_image_size_symbol = '\U0001F4D0' # 📐
|
| 83 |
+
up_down_symbol = '\u2195\ufe0f' # ↕️
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
plaintext_to_html = ui_common.plaintext_to_html
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def send_gradio_gallery_to_image(x):
|
| 90 |
+
if len(x) == 0:
|
| 91 |
+
return None
|
| 92 |
+
return image_from_url_text(x[0])
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def add_style(name: str, prompt: str, negative_prompt: str):
|
| 96 |
+
if name is None:
|
| 97 |
+
return [gr_show() for x in range(4)]
|
| 98 |
+
|
| 99 |
+
style = modules.styles.PromptStyle(name, prompt, negative_prompt)
|
| 100 |
+
shared.prompt_styles.styles[style.name] = style
|
| 101 |
+
# Save all loaded prompt styles: this allows us to update the storage format in the future more easily, because we
|
| 102 |
+
# reserialize all styles every time we save them
|
| 103 |
+
shared.prompt_styles.save_styles(shared.styles_filename)
|
| 104 |
+
|
| 105 |
+
return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(2)]
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def calc_resolution_hires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y):
|
| 109 |
+
from modules import processing, devices
|
| 110 |
+
|
| 111 |
+
if not enable:
|
| 112 |
+
return ""
|
| 113 |
+
|
| 114 |
+
p = processing.StableDiffusionProcessingTxt2Img(width=width, height=height, enable_hr=True, hr_scale=hr_scale, hr_resize_x=hr_resize_x, hr_resize_y=hr_resize_y)
|
| 115 |
+
|
| 116 |
+
with devices.autocast():
|
| 117 |
+
p.init([""], [0], [0])
|
| 118 |
+
|
| 119 |
+
return f"resize: from <span class='resolution'>{p.width}x{p.height}</span> to <span class='resolution'>{p.hr_resize_x or p.hr_upscale_to_x}x{p.hr_resize_y or p.hr_upscale_to_y}</span>"
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def resize_from_to_html(width, height, scale_by):
|
| 123 |
+
target_width = int(width * scale_by)
|
| 124 |
+
target_height = int(height * scale_by)
|
| 125 |
+
|
| 126 |
+
if not target_width or not target_height:
|
| 127 |
+
return "no image selected"
|
| 128 |
+
|
| 129 |
+
return f"resize: from <span class='resolution'>{width}x{height}</span> to <span class='resolution'>{target_width}x{target_height}</span>"
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def apply_styles(prompt, prompt_neg, styles):
|
| 133 |
+
prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, styles)
|
| 134 |
+
prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, styles)
|
| 135 |
+
|
| 136 |
+
return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value=[])]
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def process_interrogate(interrogation_function, mode, ii_input_dir, ii_output_dir, *ii_singles):
|
| 140 |
+
if mode in {0, 1, 3, 4}:
|
| 141 |
+
return [interrogation_function(ii_singles[mode]), None]
|
| 142 |
+
elif mode == 2:
|
| 143 |
+
return [interrogation_function(ii_singles[mode]["image"]), None]
|
| 144 |
+
elif mode == 5:
|
| 145 |
+
assert not shared.cmd_opts.hide_ui_dir_config, "Launched with --hide-ui-dir-config, batch img2img disabled"
|
| 146 |
+
images = shared.listfiles(ii_input_dir)
|
| 147 |
+
print(f"Will process {len(images)} images.")
|
| 148 |
+
if ii_output_dir != "":
|
| 149 |
+
os.makedirs(ii_output_dir, exist_ok=True)
|
| 150 |
+
else:
|
| 151 |
+
ii_output_dir = ii_input_dir
|
| 152 |
+
|
| 153 |
+
for image in images:
|
| 154 |
+
img = Image.open(image)
|
| 155 |
+
filename = os.path.basename(image)
|
| 156 |
+
left, _ = os.path.splitext(filename)
|
| 157 |
+
print(interrogation_function(img), file=open(os.path.join(ii_output_dir, f"{left}.txt"), 'a', encoding='utf-8'))
|
| 158 |
+
|
| 159 |
+
return [gr.update(), None]
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
def interrogate(image):
|
| 163 |
+
prompt = shared.interrogator.interrogate(image.convert("RGB"))
|
| 164 |
+
return gr.update() if prompt is None else prompt
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def interrogate_deepbooru(image):
|
| 168 |
+
prompt = deepbooru.model.tag(image)
|
| 169 |
+
return gr.update() if prompt is None else prompt
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def create_seed_inputs(target_interface):
|
| 173 |
+
with FormRow(elem_id=f"{target_interface}_seed_row", variant="compact"):
|
| 174 |
+
seed = (gr.Textbox if cmd_opts.use_textbox_seed else gr.Number)(label='Seed', value=-1, elem_id=f"{target_interface}_seed")
|
| 175 |
+
seed.style(container=False)
|
| 176 |
+
random_seed = ToolButton(random_symbol, elem_id=f"{target_interface}_random_seed", label='Random seed')
|
| 177 |
+
reuse_seed = ToolButton(reuse_symbol, elem_id=f"{target_interface}_reuse_seed", label='Reuse seed')
|
| 178 |
+
|
| 179 |
+
seed_checkbox = gr.Checkbox(label='Extra', elem_id=f"{target_interface}_subseed_show", value=False)
|
| 180 |
+
|
| 181 |
+
# Components to show/hide based on the 'Extra' checkbox
|
| 182 |
+
seed_extras = []
|
| 183 |
+
|
| 184 |
+
with FormRow(visible=False, elem_id=f"{target_interface}_subseed_row") as seed_extra_row_1:
|
| 185 |
+
seed_extras.append(seed_extra_row_1)
|
| 186 |
+
subseed = gr.Number(label='Variation seed', value=-1, elem_id=f"{target_interface}_subseed")
|
| 187 |
+
subseed.style(container=False)
|
| 188 |
+
random_subseed = ToolButton(random_symbol, elem_id=f"{target_interface}_random_subseed")
|
| 189 |
+
reuse_subseed = ToolButton(reuse_symbol, elem_id=f"{target_interface}_reuse_subseed")
|
| 190 |
+
subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=f"{target_interface}_subseed_strength")
|
| 191 |
+
|
| 192 |
+
with FormRow(visible=False) as seed_extra_row_2:
|
| 193 |
+
seed_extras.append(seed_extra_row_2)
|
| 194 |
+
seed_resize_from_w = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize seed from width", value=0, elem_id=f"{target_interface}_seed_resize_from_w")
|
| 195 |
+
seed_resize_from_h = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize seed from height", value=0, elem_id=f"{target_interface}_seed_resize_from_h")
|
| 196 |
+
|
| 197 |
+
random_seed.click(fn=None, _js="function(){setRandomSeed('" + target_interface + "_seed')}", show_progress=False, inputs=[], outputs=[])
|
| 198 |
+
random_subseed.click(fn=None, _js="function(){setRandomSeed('" + target_interface + "_subseed')}", show_progress=False, inputs=[], outputs=[])
|
| 199 |
+
|
| 200 |
+
def change_visibility(show):
|
| 201 |
+
return {comp: gr_show(show) for comp in seed_extras}
|
| 202 |
+
|
| 203 |
+
seed_checkbox.change(change_visibility, show_progress=False, inputs=[seed_checkbox], outputs=seed_extras)
|
| 204 |
+
|
| 205 |
+
return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
def connect_clear_prompt(button):
|
| 210 |
+
"""Given clear button, prompt, and token_counter objects, setup clear prompt button click event"""
|
| 211 |
+
button.click(
|
| 212 |
+
_js="clear_prompt",
|
| 213 |
+
fn=None,
|
| 214 |
+
inputs=[],
|
| 215 |
+
outputs=[],
|
| 216 |
+
)
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, dummy_component, is_subseed):
|
| 220 |
+
""" Connects a 'reuse (sub)seed' button's click event so that it copies last used
|
| 221 |
+
(sub)seed value from generation info the to the seed field. If copying subseed and subseed strength
|
| 222 |
+
was 0, i.e. no variation seed was used, it copies the normal seed value instead."""
|
| 223 |
+
def copy_seed(gen_info_string: str, index):
|
| 224 |
+
res = -1
|
| 225 |
+
|
| 226 |
+
try:
|
| 227 |
+
gen_info = json.loads(gen_info_string)
|
| 228 |
+
index -= gen_info.get('index_of_first_image', 0)
|
| 229 |
+
|
| 230 |
+
if is_subseed and gen_info.get('subseed_strength', 0) > 0:
|
| 231 |
+
all_subseeds = gen_info.get('all_subseeds', [-1])
|
| 232 |
+
res = all_subseeds[index if 0 <= index < len(all_subseeds) else 0]
|
| 233 |
+
else:
|
| 234 |
+
all_seeds = gen_info.get('all_seeds', [-1])
|
| 235 |
+
res = all_seeds[index if 0 <= index < len(all_seeds) else 0]
|
| 236 |
+
|
| 237 |
+
except json.decoder.JSONDecodeError:
|
| 238 |
+
if gen_info_string:
|
| 239 |
+
errors.report(f"Error parsing JSON generation info: {gen_info_string}")
|
| 240 |
+
|
| 241 |
+
return [res, gr_show(False)]
|
| 242 |
+
|
| 243 |
+
reuse_seed.click(
|
| 244 |
+
fn=copy_seed,
|
| 245 |
+
_js="(x, y) => [x, selected_gallery_index()]",
|
| 246 |
+
show_progress=False,
|
| 247 |
+
inputs=[generation_info, dummy_component],
|
| 248 |
+
outputs=[seed, dummy_component]
|
| 249 |
+
)
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
def update_token_counter(text, steps):
|
| 253 |
+
try:
|
| 254 |
+
text, _ = extra_networks.parse_prompt(text)
|
| 255 |
+
|
| 256 |
+
_, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
|
| 257 |
+
prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
|
| 258 |
+
|
| 259 |
+
except Exception:
|
| 260 |
+
# a parsing error can happen here during typing, and we don't want to bother the user with
|
| 261 |
+
# messages related to it in console
|
| 262 |
+
prompt_schedules = [[[steps, text]]]
|
| 263 |
+
|
| 264 |
+
flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
|
| 265 |
+
prompts = [prompt_text for step, prompt_text in flat_prompts]
|
| 266 |
+
token_count, max_length = max([model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
|
| 267 |
+
return f"<span class='gr-box gr-text-input'>{token_count}/{max_length}</span>"
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
def create_toprow(is_img2img):
|
| 271 |
+
id_part = "img2img" if is_img2img else "txt2img"
|
| 272 |
+
|
| 273 |
+
with gr.Row(elem_id=f"{id_part}_toprow", variant="compact"):
|
| 274 |
+
with gr.Column(elem_id=f"{id_part}_prompt_container", scale=6):
|
| 275 |
+
with gr.Row():
|
| 276 |
+
with gr.Column(scale=80):
|
| 277 |
+
with gr.Row():
|
| 278 |
+
prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=3, placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)", elem_classes=["prompt"])
|
| 279 |
+
|
| 280 |
+
with gr.Row():
|
| 281 |
+
with gr.Column(scale=80):
|
| 282 |
+
with gr.Row():
|
| 283 |
+
negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)", elem_classes=["prompt"])
|
| 284 |
+
|
| 285 |
+
button_interrogate = None
|
| 286 |
+
button_deepbooru = None
|
| 287 |
+
if is_img2img:
|
| 288 |
+
with gr.Column(scale=1, elem_classes="interrogate-col"):
|
| 289 |
+
button_interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate")
|
| 290 |
+
button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru")
|
| 291 |
+
|
| 292 |
+
with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"):
|
| 293 |
+
with gr.Row(elem_id=f"{id_part}_generate_box", elem_classes="generate-box"):
|
| 294 |
+
interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt", elem_classes="generate-box-interrupt")
|
| 295 |
+
skip = gr.Button('Skip', elem_id=f"{id_part}_skip", elem_classes="generate-box-skip")
|
| 296 |
+
submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
|
| 297 |
+
|
| 298 |
+
skip.click(
|
| 299 |
+
fn=lambda: shared.state.skip(),
|
| 300 |
+
inputs=[],
|
| 301 |
+
outputs=[],
|
| 302 |
+
)
|
| 303 |
+
|
| 304 |
+
interrupt.click(
|
| 305 |
+
fn=lambda: shared.state.interrupt(),
|
| 306 |
+
inputs=[],
|
| 307 |
+
outputs=[],
|
| 308 |
+
)
|
| 309 |
+
|
| 310 |
+
with gr.Row(elem_id=f"{id_part}_tools"):
|
| 311 |
+
paste = ToolButton(value=paste_symbol, elem_id="paste")
|
| 312 |
+
clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt")
|
| 313 |
+
extra_networks_button = ToolButton(value=extra_networks_symbol, elem_id=f"{id_part}_extra_networks")
|
| 314 |
+
prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id=f"{id_part}_style_apply")
|
| 315 |
+
save_style = ToolButton(value=save_style_symbol, elem_id=f"{id_part}_style_create")
|
| 316 |
+
restore_progress_button = ToolButton(value=restore_progress_symbol, elem_id=f"{id_part}_restore_progress", visible=False)
|
| 317 |
+
|
| 318 |
+
token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_token_counter", elem_classes=["token-counter"])
|
| 319 |
+
token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
|
| 320 |
+
negative_token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_negative_token_counter", elem_classes=["token-counter"])
|
| 321 |
+
negative_token_button = gr.Button(visible=False, elem_id=f"{id_part}_negative_token_button")
|
| 322 |
+
|
| 323 |
+
clear_prompt_button.click(
|
| 324 |
+
fn=lambda *x: x,
|
| 325 |
+
_js="confirm_clear_prompt",
|
| 326 |
+
inputs=[prompt, negative_prompt],
|
| 327 |
+
outputs=[prompt, negative_prompt],
|
| 328 |
+
)
|
| 329 |
+
|
| 330 |
+
with gr.Row(elem_id=f"{id_part}_styles_row"):
|
| 331 |
+
prompt_styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[k for k, v in shared.prompt_styles.styles.items()], value=[], multiselect=True)
|
| 332 |
+
create_refresh_button(prompt_styles, shared.prompt_styles.reload, lambda: {"choices": [k for k, v in shared.prompt_styles.styles.items()]}, f"refresh_{id_part}_styles")
|
| 333 |
+
|
| 334 |
+
return prompt, prompt_styles, negative_prompt, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button, restore_progress_button
|
| 335 |
+
|
| 336 |
+
|
| 337 |
+
def setup_progressbar(*args, **kwargs):
|
| 338 |
+
pass
|
| 339 |
+
|
| 340 |
+
|
| 341 |
+
def apply_setting(key, value):
|
| 342 |
+
if value is None:
|
| 343 |
+
return gr.update()
|
| 344 |
+
|
| 345 |
+
if shared.cmd_opts.freeze_settings:
|
| 346 |
+
return gr.update()
|
| 347 |
+
|
| 348 |
+
# dont allow model to be swapped when model hash exists in prompt
|
| 349 |
+
if key == "sd_model_checkpoint" and opts.disable_weights_auto_swap:
|
| 350 |
+
return gr.update()
|
| 351 |
+
|
| 352 |
+
if key == "sd_model_checkpoint":
|
| 353 |
+
ckpt_info = sd_models.get_closet_checkpoint_match(value)
|
| 354 |
+
|
| 355 |
+
if ckpt_info is not None:
|
| 356 |
+
value = ckpt_info.title
|
| 357 |
+
else:
|
| 358 |
+
return gr.update()
|
| 359 |
+
|
| 360 |
+
comp_args = opts.data_labels[key].component_args
|
| 361 |
+
if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False:
|
| 362 |
+
return
|
| 363 |
+
|
| 364 |
+
valtype = type(opts.data_labels[key].default)
|
| 365 |
+
oldval = opts.data.get(key, None)
|
| 366 |
+
opts.data[key] = valtype(value) if valtype != type(None) else value
|
| 367 |
+
if oldval != value and opts.data_labels[key].onchange is not None:
|
| 368 |
+
opts.data_labels[key].onchange()
|
| 369 |
+
|
| 370 |
+
opts.save(shared.config_filename)
|
| 371 |
+
return getattr(opts, key)
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
def create_output_panel(tabname, outdir):
|
| 375 |
+
return ui_common.create_output_panel(tabname, outdir)
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
def create_sampler_and_steps_selection(choices, tabname):
|
| 379 |
+
if opts.samplers_in_dropdown:
|
| 380 |
+
with FormRow(elem_id=f"sampler_selection_{tabname}"):
|
| 381 |
+
sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value=choices[0].name, type="index")
|
| 382 |
+
steps = gr.Slider(minimum=1, maximum=150, step=1, elem_id=f"{tabname}_steps", label="Sampling steps", value=20)
|
| 383 |
+
else:
|
| 384 |
+
with FormGroup(elem_id=f"sampler_selection_{tabname}"):
|
| 385 |
+
steps = gr.Slider(minimum=1, maximum=150, step=1, elem_id=f"{tabname}_steps", label="Sampling steps", value=20)
|
| 386 |
+
sampler_index = gr.Radio(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value=choices[0].name, type="index")
|
| 387 |
+
|
| 388 |
+
return steps, sampler_index
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
def ordered_ui_categories():
|
| 392 |
+
user_order = {x.strip(): i * 2 + 1 for i, x in enumerate(shared.opts.ui_reorder_list)}
|
| 393 |
+
|
| 394 |
+
for _, category in sorted(enumerate(shared_items.ui_reorder_categories()), key=lambda x: user_order.get(x[1], x[0] * 2 + 0)):
|
| 395 |
+
yield category
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
def create_override_settings_dropdown(tabname, row):
|
| 399 |
+
dropdown = gr.Dropdown([], label="Override settings", visible=False, elem_id=f"{tabname}_override_settings", multiselect=True)
|
| 400 |
+
|
| 401 |
+
dropdown.change(
|
| 402 |
+
fn=lambda x: gr.Dropdown.update(visible=bool(x)),
|
| 403 |
+
inputs=[dropdown],
|
| 404 |
+
outputs=[dropdown],
|
| 405 |
+
)
|
| 406 |
+
|
| 407 |
+
return dropdown
|
| 408 |
+
|
| 409 |
+
|
| 410 |
+
def create_ui():
|
| 411 |
+
import modules.img2img
|
| 412 |
+
import modules.txt2img
|
| 413 |
+
|
| 414 |
+
reload_javascript()
|
| 415 |
+
|
| 416 |
+
parameters_copypaste.reset()
|
| 417 |
+
|
| 418 |
+
modules.scripts.scripts_current = modules.scripts.scripts_txt2img
|
| 419 |
+
modules.scripts.scripts_txt2img.initialize_scripts(is_img2img=False)
|
| 420 |
+
|
| 421 |
+
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
|
| 422 |
+
txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button, restore_progress_button = create_toprow(is_img2img=False)
|
| 423 |
+
|
| 424 |
+
dummy_component = gr.Label(visible=False)
|
| 425 |
+
txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False)
|
| 426 |
+
|
| 427 |
+
with FormRow(variant='compact', elem_id="txt2img_extra_networks", visible=False) as extra_networks:
|
| 428 |
+
from modules import ui_extra_networks
|
| 429 |
+
extra_networks_ui = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'txt2img')
|
| 430 |
+
|
| 431 |
+
with gr.Row().style(equal_height=False):
|
| 432 |
+
with gr.Column(variant='compact', elem_id="txt2img_settings"):
|
| 433 |
+
modules.scripts.scripts_txt2img.prepare_ui()
|
| 434 |
+
|
| 435 |
+
for category in ordered_ui_categories():
|
| 436 |
+
if category == "sampler":
|
| 437 |
+
steps, sampler_index = create_sampler_and_steps_selection(samplers, "txt2img")
|
| 438 |
+
|
| 439 |
+
elif category == "dimensions":
|
| 440 |
+
with FormRow():
|
| 441 |
+
with gr.Column(elem_id="txt2img_column_size", scale=4):
|
| 442 |
+
width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width")
|
| 443 |
+
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height")
|
| 444 |
+
|
| 445 |
+
with gr.Column(elem_id="txt2img_dimensions_row", scale=1, elem_classes="dimensions-tools"):
|
| 446 |
+
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn", label="Switch dims")
|
| 447 |
+
|
| 448 |
+
if opts.dimensions_and_batch_together:
|
| 449 |
+
with gr.Column(elem_id="txt2img_column_batch"):
|
| 450 |
+
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
|
| 451 |
+
batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
|
| 452 |
+
|
| 453 |
+
elif category == "cfg":
|
| 454 |
+
cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0, elem_id="txt2img_cfg_scale")
|
| 455 |
+
|
| 456 |
+
elif category == "seed":
|
| 457 |
+
seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('txt2img')
|
| 458 |
+
|
| 459 |
+
elif category == "checkboxes":
|
| 460 |
+
with FormRow(elem_classes="checkboxes-row", variant="compact"):
|
| 461 |
+
restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="txt2img_restore_faces")
|
| 462 |
+
tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling")
|
| 463 |
+
enable_hr = gr.Checkbox(label='Hires. fix', value=False, elem_id="txt2img_enable_hr")
|
| 464 |
+
hr_final_resolution = FormHTML(value="", elem_id="txtimg_hr_finalres", label="Upscaled resolution", interactive=False)
|
| 465 |
+
|
| 466 |
+
elif category == "hires_fix":
|
| 467 |
+
with FormGroup(visible=False, elem_id="txt2img_hires_fix") as hr_options:
|
| 468 |
+
with FormRow(elem_id="txt2img_hires_fix_row1", variant="compact"):
|
| 469 |
+
hr_upscaler = gr.Dropdown(label="Upscaler", elem_id="txt2img_hr_upscaler", choices=[*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]], value=shared.latent_upscale_default_mode)
|
| 470 |
+
hr_second_pass_steps = gr.Slider(minimum=0, maximum=150, step=1, label='Hires steps', value=0, elem_id="txt2img_hires_steps")
|
| 471 |
+
denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7, elem_id="txt2img_denoising_strength")
|
| 472 |
+
|
| 473 |
+
with FormRow(elem_id="txt2img_hires_fix_row2", variant="compact"):
|
| 474 |
+
hr_scale = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Upscale by", value=2.0, elem_id="txt2img_hr_scale")
|
| 475 |
+
hr_resize_x = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize width to", value=0, elem_id="txt2img_hr_resize_x")
|
| 476 |
+
hr_resize_y = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize height to", value=0, elem_id="txt2img_hr_resize_y")
|
| 477 |
+
|
| 478 |
+
with FormRow(elem_id="txt2img_hires_fix_row3", variant="compact", visible=opts.hires_fix_show_sampler) as hr_sampler_container:
|
| 479 |
+
hr_sampler_index = gr.Dropdown(label='Hires sampling method', elem_id="hr_sampler", choices=["Use same sampler"] + [x.name for x in samplers_for_img2img], value="Use same sampler", type="index")
|
| 480 |
+
|
| 481 |
+
with FormRow(elem_id="txt2img_hires_fix_row4", variant="compact", visible=opts.hires_fix_show_prompts) as hr_prompts_container:
|
| 482 |
+
with gr.Column(scale=80):
|
| 483 |
+
with gr.Row():
|
| 484 |
+
hr_prompt = gr.Textbox(label="Hires prompt", elem_id="hires_prompt", show_label=False, lines=3, placeholder="Prompt for hires fix pass.\nLeave empty to use the same prompt as in first pass.", elem_classes=["prompt"])
|
| 485 |
+
with gr.Column(scale=80):
|
| 486 |
+
with gr.Row():
|
| 487 |
+
hr_negative_prompt = gr.Textbox(label="Hires negative prompt", elem_id="hires_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt for hires fix pass.\nLeave empty to use the same negative prompt as in first pass.", elem_classes=["prompt"])
|
| 488 |
+
|
| 489 |
+
elif category == "batch":
|
| 490 |
+
if not opts.dimensions_and_batch_together:
|
| 491 |
+
with FormRow(elem_id="txt2img_column_batch"):
|
| 492 |
+
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
|
| 493 |
+
batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
|
| 494 |
+
|
| 495 |
+
elif category == "override_settings":
|
| 496 |
+
with FormRow(elem_id="txt2img_override_settings_row") as row:
|
| 497 |
+
override_settings = create_override_settings_dropdown('txt2img', row)
|
| 498 |
+
|
| 499 |
+
elif category == "scripts":
|
| 500 |
+
with FormGroup(elem_id="txt2img_script_container"):
|
| 501 |
+
custom_inputs = modules.scripts.scripts_txt2img.setup_ui()
|
| 502 |
+
|
| 503 |
+
else:
|
| 504 |
+
modules.scripts.scripts_txt2img.setup_ui_for_section(category)
|
| 505 |
+
|
| 506 |
+
hr_resolution_preview_inputs = [enable_hr, width, height, hr_scale, hr_resize_x, hr_resize_y]
|
| 507 |
+
|
| 508 |
+
for component in hr_resolution_preview_inputs:
|
| 509 |
+
event = component.release if isinstance(component, gr.Slider) else component.change
|
| 510 |
+
|
| 511 |
+
event(
|
| 512 |
+
fn=calc_resolution_hires,
|
| 513 |
+
inputs=hr_resolution_preview_inputs,
|
| 514 |
+
outputs=[hr_final_resolution],
|
| 515 |
+
show_progress=False,
|
| 516 |
+
)
|
| 517 |
+
event(
|
| 518 |
+
None,
|
| 519 |
+
_js="onCalcResolutionHires",
|
| 520 |
+
inputs=hr_resolution_preview_inputs,
|
| 521 |
+
outputs=[],
|
| 522 |
+
show_progress=False,
|
| 523 |
+
)
|
| 524 |
+
|
| 525 |
+
txt2img_gallery, generation_info, html_info, html_log = create_output_panel("txt2img", opts.outdir_txt2img_samples)
|
| 526 |
+
|
| 527 |
+
connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
|
| 528 |
+
connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
|
| 529 |
+
|
| 530 |
+
txt2img_args = dict(
|
| 531 |
+
fn=wrap_gradio_gpu_call(modules.txt2img.txt2img, extra_outputs=[None, '', '']),
|
| 532 |
+
_js="submit",
|
| 533 |
+
inputs=[
|
| 534 |
+
dummy_component,
|
| 535 |
+
txt2img_prompt,
|
| 536 |
+
txt2img_negative_prompt,
|
| 537 |
+
txt2img_prompt_styles,
|
| 538 |
+
steps,
|
| 539 |
+
sampler_index,
|
| 540 |
+
restore_faces,
|
| 541 |
+
tiling,
|
| 542 |
+
batch_count,
|
| 543 |
+
batch_size,
|
| 544 |
+
cfg_scale,
|
| 545 |
+
seed,
|
| 546 |
+
subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
|
| 547 |
+
height,
|
| 548 |
+
width,
|
| 549 |
+
enable_hr,
|
| 550 |
+
denoising_strength,
|
| 551 |
+
hr_scale,
|
| 552 |
+
hr_upscaler,
|
| 553 |
+
hr_second_pass_steps,
|
| 554 |
+
hr_resize_x,
|
| 555 |
+
hr_resize_y,
|
| 556 |
+
hr_sampler_index,
|
| 557 |
+
hr_prompt,
|
| 558 |
+
hr_negative_prompt,
|
| 559 |
+
override_settings,
|
| 560 |
+
|
| 561 |
+
] + custom_inputs,
|
| 562 |
+
|
| 563 |
+
outputs=[
|
| 564 |
+
txt2img_gallery,
|
| 565 |
+
generation_info,
|
| 566 |
+
html_info,
|
| 567 |
+
html_log,
|
| 568 |
+
],
|
| 569 |
+
show_progress=False,
|
| 570 |
+
)
|
| 571 |
+
|
| 572 |
+
txt2img_prompt.submit(**txt2img_args)
|
| 573 |
+
submit.click(**txt2img_args)
|
| 574 |
+
|
| 575 |
+
res_switch_btn.click(fn=None, _js="function(){switchWidthHeight('txt2img')}", inputs=None, outputs=None, show_progress=False)
|
| 576 |
+
|
| 577 |
+
restore_progress_button.click(
|
| 578 |
+
fn=progress.restore_progress,
|
| 579 |
+
_js="restoreProgressTxt2img",
|
| 580 |
+
inputs=[dummy_component],
|
| 581 |
+
outputs=[
|
| 582 |
+
txt2img_gallery,
|
| 583 |
+
generation_info,
|
| 584 |
+
html_info,
|
| 585 |
+
html_log,
|
| 586 |
+
],
|
| 587 |
+
show_progress=False,
|
| 588 |
+
)
|
| 589 |
+
|
| 590 |
+
txt_prompt_img.change(
|
| 591 |
+
fn=modules.images.image_data,
|
| 592 |
+
inputs=[
|
| 593 |
+
txt_prompt_img
|
| 594 |
+
],
|
| 595 |
+
outputs=[
|
| 596 |
+
txt2img_prompt,
|
| 597 |
+
txt_prompt_img
|
| 598 |
+
],
|
| 599 |
+
show_progress=False,
|
| 600 |
+
)
|
| 601 |
+
|
| 602 |
+
enable_hr.change(
|
| 603 |
+
fn=lambda x: gr_show(x),
|
| 604 |
+
inputs=[enable_hr],
|
| 605 |
+
outputs=[hr_options],
|
| 606 |
+
show_progress = False,
|
| 607 |
+
)
|
| 608 |
+
|
| 609 |
+
txt2img_paste_fields = [
|
| 610 |
+
(txt2img_prompt, "Prompt"),
|
| 611 |
+
(txt2img_negative_prompt, "Negative prompt"),
|
| 612 |
+
(steps, "Steps"),
|
| 613 |
+
(sampler_index, "Sampler"),
|
| 614 |
+
(restore_faces, "Face restoration"),
|
| 615 |
+
(cfg_scale, "CFG scale"),
|
| 616 |
+
(seed, "Seed"),
|
| 617 |
+
(width, "Size-1"),
|
| 618 |
+
(height, "Size-2"),
|
| 619 |
+
(batch_size, "Batch size"),
|
| 620 |
+
(subseed, "Variation seed"),
|
| 621 |
+
(subseed_strength, "Variation seed strength"),
|
| 622 |
+
(seed_resize_from_w, "Seed resize from-1"),
|
| 623 |
+
(seed_resize_from_h, "Seed resize from-2"),
|
| 624 |
+
(txt2img_prompt_styles, lambda d: d["Styles array"] if isinstance(d.get("Styles array"), list) else gr.update()),
|
| 625 |
+
(denoising_strength, "Denoising strength"),
|
| 626 |
+
(enable_hr, lambda d: "Denoising strength" in d),
|
| 627 |
+
(hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)),
|
| 628 |
+
(hr_scale, "Hires upscale"),
|
| 629 |
+
(hr_upscaler, "Hires upscaler"),
|
| 630 |
+
(hr_second_pass_steps, "Hires steps"),
|
| 631 |
+
(hr_resize_x, "Hires resize-1"),
|
| 632 |
+
(hr_resize_y, "Hires resize-2"),
|
| 633 |
+
(hr_sampler_index, "Hires sampler"),
|
| 634 |
+
(hr_sampler_container, lambda d: gr.update(visible=True) if d.get("Hires sampler", "Use same sampler") != "Use same sampler" else gr.update()),
|
| 635 |
+
(hr_prompt, "Hires prompt"),
|
| 636 |
+
(hr_negative_prompt, "Hires negative prompt"),
|
| 637 |
+
(hr_prompts_container, lambda d: gr.update(visible=True) if d.get("Hires prompt", "") != "" or d.get("Hires negative prompt", "") != "" else gr.update()),
|
| 638 |
+
*modules.scripts.scripts_txt2img.infotext_fields
|
| 639 |
+
]
|
| 640 |
+
parameters_copypaste.add_paste_fields("txt2img", None, txt2img_paste_fields, override_settings)
|
| 641 |
+
parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(
|
| 642 |
+
paste_button=txt2img_paste, tabname="txt2img", source_text_component=txt2img_prompt, source_image_component=None,
|
| 643 |
+
))
|
| 644 |
+
|
| 645 |
+
txt2img_preview_params = [
|
| 646 |
+
txt2img_prompt,
|
| 647 |
+
txt2img_negative_prompt,
|
| 648 |
+
steps,
|
| 649 |
+
sampler_index,
|
| 650 |
+
cfg_scale,
|
| 651 |
+
seed,
|
| 652 |
+
width,
|
| 653 |
+
height,
|
| 654 |
+
]
|
| 655 |
+
|
| 656 |
+
token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_prompt, steps], outputs=[token_counter])
|
| 657 |
+
negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_negative_prompt, steps], outputs=[negative_token_counter])
|
| 658 |
+
|
| 659 |
+
ui_extra_networks.setup_ui(extra_networks_ui, txt2img_gallery)
|
| 660 |
+
|
| 661 |
+
modules.scripts.scripts_current = modules.scripts.scripts_img2img
|
| 662 |
+
modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True)
|
| 663 |
+
|
| 664 |
+
with gr.Blocks(analytics_enabled=False) as img2img_interface:
|
| 665 |
+
img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button, restore_progress_button = create_toprow(is_img2img=True)
|
| 666 |
+
|
| 667 |
+
img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="binary", visible=False)
|
| 668 |
+
|
| 669 |
+
with FormRow(variant='compact', elem_id="img2img_extra_networks", visible=False) as extra_networks:
|
| 670 |
+
from modules import ui_extra_networks
|
| 671 |
+
extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'img2img')
|
| 672 |
+
|
| 673 |
+
with FormRow().style(equal_height=False):
|
| 674 |
+
with gr.Column(variant='compact', elem_id="img2img_settings"):
|
| 675 |
+
copy_image_buttons = []
|
| 676 |
+
copy_image_destinations = {}
|
| 677 |
+
|
| 678 |
+
def add_copy_image_controls(tab_name, elem):
|
| 679 |
+
with gr.Row(variant="compact", elem_id=f"img2img_copy_to_{tab_name}"):
|
| 680 |
+
gr.HTML("Copy image to: ", elem_id=f"img2img_label_copy_to_{tab_name}")
|
| 681 |
+
|
| 682 |
+
for title, name in zip(['img2img', 'sketch', 'inpaint', 'inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
|
| 683 |
+
if name == tab_name:
|
| 684 |
+
gr.Button(title, interactive=False)
|
| 685 |
+
copy_image_destinations[name] = elem
|
| 686 |
+
continue
|
| 687 |
+
|
| 688 |
+
button = gr.Button(title)
|
| 689 |
+
copy_image_buttons.append((button, name, elem))
|
| 690 |
+
|
| 691 |
+
with gr.Tabs(elem_id="mode_img2img"):
|
| 692 |
+
img2img_selected_tab = gr.State(0)
|
| 693 |
+
|
| 694 |
+
with gr.TabItem('img2img', id='img2img', elem_id="img2img_img2img_tab") as tab_img2img:
|
| 695 |
+
init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool="editor", image_mode="RGBA").style(height=opts.img2img_editor_height)
|
| 696 |
+
add_copy_image_controls('img2img', init_img)
|
| 697 |
+
|
| 698 |
+
with gr.TabItem('Sketch', id='img2img_sketch', elem_id="img2img_img2img_sketch_tab") as tab_sketch:
|
| 699 |
+
sketch = gr.Image(label="Image for img2img", elem_id="img2img_sketch", show_label=False, source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA").style(height=opts.img2img_editor_height)
|
| 700 |
+
add_copy_image_controls('sketch', sketch)
|
| 701 |
+
|
| 702 |
+
with gr.TabItem('Inpaint', id='inpaint', elem_id="img2img_inpaint_tab") as tab_inpaint:
|
| 703 |
+
init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA").style(height=opts.img2img_editor_height)
|
| 704 |
+
add_copy_image_controls('inpaint', init_img_with_mask)
|
| 705 |
+
|
| 706 |
+
with gr.TabItem('Inpaint sketch', id='inpaint_sketch', elem_id="img2img_inpaint_sketch_tab") as tab_inpaint_color:
|
| 707 |
+
inpaint_color_sketch = gr.Image(label="Color sketch inpainting", show_label=False, elem_id="inpaint_sketch", source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA").style(height=opts.img2img_editor_height)
|
| 708 |
+
inpaint_color_sketch_orig = gr.State(None)
|
| 709 |
+
add_copy_image_controls('inpaint_sketch', inpaint_color_sketch)
|
| 710 |
+
|
| 711 |
+
def update_orig(image, state):
|
| 712 |
+
if image is not None:
|
| 713 |
+
same_size = state is not None and state.size == image.size
|
| 714 |
+
has_exact_match = np.any(np.all(np.array(image) == np.array(state), axis=-1))
|
| 715 |
+
edited = same_size and has_exact_match
|
| 716 |
+
return image if not edited or state is None else state
|
| 717 |
+
|
| 718 |
+
inpaint_color_sketch.change(update_orig, [inpaint_color_sketch, inpaint_color_sketch_orig], inpaint_color_sketch_orig)
|
| 719 |
+
|
| 720 |
+
with gr.TabItem('Inpaint upload', id='inpaint_upload', elem_id="img2img_inpaint_upload_tab") as tab_inpaint_upload:
|
| 721 |
+
init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", elem_id="img_inpaint_base")
|
| 722 |
+
init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", elem_id="img_inpaint_mask")
|
| 723 |
+
|
| 724 |
+
with gr.TabItem('Batch', id='batch', elem_id="img2img_batch_tab") as tab_batch:
|
| 725 |
+
hidden = '<br>Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else ''
|
| 726 |
+
gr.HTML(
|
| 727 |
+
"<p style='padding-bottom: 1em;' class=\"text-gray-500\">Process images in a directory on the same machine where the server is running." +
|
| 728 |
+
"<br>Use an empty output directory to save pictures normally instead of writing to the output directory." +
|
| 729 |
+
f"<br>Add inpaint batch mask directory to enable inpaint batch processing."
|
| 730 |
+
f"{hidden}</p>"
|
| 731 |
+
)
|
| 732 |
+
img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs, elem_id="img2img_batch_input_dir")
|
| 733 |
+
img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, elem_id="img2img_batch_output_dir")
|
| 734 |
+
img2img_batch_inpaint_mask_dir = gr.Textbox(label="Inpaint batch mask directory (required for inpaint batch processing only)", **shared.hide_dirs, elem_id="img2img_batch_inpaint_mask_dir")
|
| 735 |
+
with gr.Accordion("PNG info", open=False):
|
| 736 |
+
img2img_batch_use_png_info = gr.Checkbox(label="Append png info to prompts", **shared.hide_dirs, elem_id="img2img_batch_use_png_info")
|
| 737 |
+
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")
|
| 738 |
+
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.")
|
| 739 |
+
|
| 740 |
+
img2img_tabs = [tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch]
|
| 741 |
+
|
| 742 |
+
for i, tab in enumerate(img2img_tabs):
|
| 743 |
+
tab.select(fn=lambda tabnum=i: tabnum, inputs=[], outputs=[img2img_selected_tab])
|
| 744 |
+
|
| 745 |
+
def copy_image(img):
|
| 746 |
+
if isinstance(img, dict) and 'image' in img:
|
| 747 |
+
return img['image']
|
| 748 |
+
|
| 749 |
+
return img
|
| 750 |
+
|
| 751 |
+
for button, name, elem in copy_image_buttons:
|
| 752 |
+
button.click(
|
| 753 |
+
fn=copy_image,
|
| 754 |
+
inputs=[elem],
|
| 755 |
+
outputs=[copy_image_destinations[name]],
|
| 756 |
+
)
|
| 757 |
+
button.click(
|
| 758 |
+
fn=lambda: None,
|
| 759 |
+
_js=f"switch_to_{name.replace(' ', '_')}",
|
| 760 |
+
inputs=[],
|
| 761 |
+
outputs=[],
|
| 762 |
+
)
|
| 763 |
+
|
| 764 |
+
with FormRow():
|
| 765 |
+
resize_mode = gr.Radio(label="Resize mode", elem_id="resize_mode", choices=["Just resize", "Crop and resize", "Resize and fill", "Just resize (latent upscale)"], type="index", value="Just resize")
|
| 766 |
+
|
| 767 |
+
modules.scripts.scripts_img2img.prepare_ui()
|
| 768 |
+
|
| 769 |
+
for category in ordered_ui_categories():
|
| 770 |
+
if category == "sampler":
|
| 771 |
+
steps, sampler_index = create_sampler_and_steps_selection(samplers_for_img2img, "img2img")
|
| 772 |
+
|
| 773 |
+
elif category == "dimensions":
|
| 774 |
+
with FormRow():
|
| 775 |
+
with gr.Column(elem_id="img2img_column_size", scale=4):
|
| 776 |
+
selected_scale_tab = gr.State(value=0)
|
| 777 |
+
|
| 778 |
+
with gr.Tabs():
|
| 779 |
+
with gr.Tab(label="Resize to", elem_id="img2img_tab_resize_to") as tab_scale_to:
|
| 780 |
+
with FormRow():
|
| 781 |
+
with gr.Column(elem_id="img2img_column_size", scale=4):
|
| 782 |
+
width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width")
|
| 783 |
+
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height")
|
| 784 |
+
with gr.Column(elem_id="img2img_dimensions_row", scale=1, elem_classes="dimensions-tools"):
|
| 785 |
+
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
|
| 786 |
+
detect_image_size_btn = ToolButton(value=detect_image_size_symbol, elem_id="img2img_detect_image_size_btn")
|
| 787 |
+
|
| 788 |
+
with gr.Tab(label="Resize by", elem_id="img2img_tab_resize_by") as tab_scale_by:
|
| 789 |
+
scale_by = gr.Slider(minimum=0.05, maximum=4.0, step=0.05, label="Scale", value=1.0, elem_id="img2img_scale")
|
| 790 |
+
|
| 791 |
+
with FormRow():
|
| 792 |
+
scale_by_html = FormHTML(resize_from_to_html(0, 0, 0.0), elem_id="img2img_scale_resolution_preview")
|
| 793 |
+
gr.Slider(label="Unused", elem_id="img2img_unused_scale_by_slider")
|
| 794 |
+
button_update_resize_to = gr.Button(visible=False, elem_id="img2img_update_resize_to")
|
| 795 |
+
|
| 796 |
+
on_change_args = dict(
|
| 797 |
+
fn=resize_from_to_html,
|
| 798 |
+
_js="currentImg2imgSourceResolution",
|
| 799 |
+
inputs=[dummy_component, dummy_component, scale_by],
|
| 800 |
+
outputs=scale_by_html,
|
| 801 |
+
show_progress=False,
|
| 802 |
+
)
|
| 803 |
+
|
| 804 |
+
scale_by.release(**on_change_args)
|
| 805 |
+
button_update_resize_to.click(**on_change_args)
|
| 806 |
+
|
| 807 |
+
# the code below is meant to update the resolution label after the image in the image selection UI has changed.
|
| 808 |
+
# as it is now the event keeps firing continuously for inpaint edits, which ruins the page with constant requests.
|
| 809 |
+
# I assume this must be a gradio bug and for now we'll just do it for non-inpaint inputs.
|
| 810 |
+
for component in [init_img, sketch]:
|
| 811 |
+
component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress=False)
|
| 812 |
+
|
| 813 |
+
tab_scale_to.select(fn=lambda: 0, inputs=[], outputs=[selected_scale_tab])
|
| 814 |
+
tab_scale_by.select(fn=lambda: 1, inputs=[], outputs=[selected_scale_tab])
|
| 815 |
+
|
| 816 |
+
if opts.dimensions_and_batch_together:
|
| 817 |
+
with gr.Column(elem_id="img2img_column_batch"):
|
| 818 |
+
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
|
| 819 |
+
batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size")
|
| 820 |
+
|
| 821 |
+
elif category == "cfg":
|
| 822 |
+
with FormGroup():
|
| 823 |
+
with FormRow():
|
| 824 |
+
cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0, elem_id="img2img_cfg_scale")
|
| 825 |
+
image_cfg_scale = gr.Slider(minimum=0, maximum=3.0, step=0.05, label='Image CFG Scale', value=1.5, elem_id="img2img_image_cfg_scale", visible=False)
|
| 826 |
+
denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength")
|
| 827 |
+
|
| 828 |
+
elif category == "seed":
|
| 829 |
+
seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('img2img')
|
| 830 |
+
|
| 831 |
+
elif category == "checkboxes":
|
| 832 |
+
with FormRow(elem_classes="checkboxes-row", variant="compact"):
|
| 833 |
+
restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="img2img_restore_faces")
|
| 834 |
+
tiling = gr.Checkbox(label='Tiling', value=False, elem_id="img2img_tiling")
|
| 835 |
+
|
| 836 |
+
elif category == "batch":
|
| 837 |
+
if not opts.dimensions_and_batch_together:
|
| 838 |
+
with FormRow(elem_id="img2img_column_batch"):
|
| 839 |
+
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
|
| 840 |
+
batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size")
|
| 841 |
+
|
| 842 |
+
elif category == "override_settings":
|
| 843 |
+
with FormRow(elem_id="img2img_override_settings_row") as row:
|
| 844 |
+
override_settings = create_override_settings_dropdown('img2img', row)
|
| 845 |
+
|
| 846 |
+
elif category == "scripts":
|
| 847 |
+
with FormGroup(elem_id="img2img_script_container"):
|
| 848 |
+
custom_inputs = modules.scripts.scripts_img2img.setup_ui()
|
| 849 |
+
|
| 850 |
+
elif category == "inpaint":
|
| 851 |
+
with FormGroup(elem_id="inpaint_controls", visible=False) as inpaint_controls:
|
| 852 |
+
with FormRow():
|
| 853 |
+
mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4, elem_id="img2img_mask_blur")
|
| 854 |
+
mask_alpha = gr.Slider(label="Mask transparency", visible=False, elem_id="img2img_mask_alpha")
|
| 855 |
+
|
| 856 |
+
with FormRow():
|
| 857 |
+
inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode")
|
| 858 |
+
|
| 859 |
+
with FormRow():
|
| 860 |
+
inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index", elem_id="img2img_inpainting_fill")
|
| 861 |
+
|
| 862 |
+
with FormRow():
|
| 863 |
+
with gr.Column():
|
| 864 |
+
inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res")
|
| 865 |
+
|
| 866 |
+
with gr.Column(scale=4):
|
| 867 |
+
inpaint_full_res_padding = gr.Slider(label='Only masked padding, pixels', minimum=0, maximum=256, step=4, value=32, elem_id="img2img_inpaint_full_res_padding")
|
| 868 |
+
|
| 869 |
+
def select_img2img_tab(tab):
|
| 870 |
+
return gr.update(visible=tab in [2, 3, 4]), gr.update(visible=tab == 3),
|
| 871 |
+
|
| 872 |
+
for i, elem in enumerate(img2img_tabs):
|
| 873 |
+
elem.select(
|
| 874 |
+
fn=lambda tab=i: select_img2img_tab(tab),
|
| 875 |
+
inputs=[],
|
| 876 |
+
outputs=[inpaint_controls, mask_alpha],
|
| 877 |
+
)
|
| 878 |
+
else:
|
| 879 |
+
modules.scripts.scripts_img2img.setup_ui_for_section(category)
|
| 880 |
+
|
| 881 |
+
img2img_gallery, generation_info, html_info, html_log = create_output_panel("img2img", opts.outdir_img2img_samples)
|
| 882 |
+
|
| 883 |
+
connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
|
| 884 |
+
connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
|
| 885 |
+
|
| 886 |
+
img2img_prompt_img.change(
|
| 887 |
+
fn=modules.images.image_data,
|
| 888 |
+
inputs=[
|
| 889 |
+
img2img_prompt_img
|
| 890 |
+
],
|
| 891 |
+
outputs=[
|
| 892 |
+
img2img_prompt,
|
| 893 |
+
img2img_prompt_img
|
| 894 |
+
],
|
| 895 |
+
show_progress=False,
|
| 896 |
+
)
|
| 897 |
+
|
| 898 |
+
img2img_args = dict(
|
| 899 |
+
fn=wrap_gradio_gpu_call(modules.img2img.img2img, extra_outputs=[None, '', '']),
|
| 900 |
+
_js="submit_img2img",
|
| 901 |
+
inputs=[
|
| 902 |
+
dummy_component,
|
| 903 |
+
dummy_component,
|
| 904 |
+
img2img_prompt,
|
| 905 |
+
img2img_negative_prompt,
|
| 906 |
+
img2img_prompt_styles,
|
| 907 |
+
init_img,
|
| 908 |
+
sketch,
|
| 909 |
+
init_img_with_mask,
|
| 910 |
+
inpaint_color_sketch,
|
| 911 |
+
inpaint_color_sketch_orig,
|
| 912 |
+
init_img_inpaint,
|
| 913 |
+
init_mask_inpaint,
|
| 914 |
+
steps,
|
| 915 |
+
sampler_index,
|
| 916 |
+
mask_blur,
|
| 917 |
+
mask_alpha,
|
| 918 |
+
inpainting_fill,
|
| 919 |
+
restore_faces,
|
| 920 |
+
tiling,
|
| 921 |
+
batch_count,
|
| 922 |
+
batch_size,
|
| 923 |
+
cfg_scale,
|
| 924 |
+
image_cfg_scale,
|
| 925 |
+
denoising_strength,
|
| 926 |
+
seed,
|
| 927 |
+
subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
|
| 928 |
+
selected_scale_tab,
|
| 929 |
+
height,
|
| 930 |
+
width,
|
| 931 |
+
scale_by,
|
| 932 |
+
resize_mode,
|
| 933 |
+
inpaint_full_res,
|
| 934 |
+
inpaint_full_res_padding,
|
| 935 |
+
inpainting_mask_invert,
|
| 936 |
+
img2img_batch_input_dir,
|
| 937 |
+
img2img_batch_output_dir,
|
| 938 |
+
img2img_batch_inpaint_mask_dir,
|
| 939 |
+
override_settings,
|
| 940 |
+
img2img_batch_use_png_info,
|
| 941 |
+
img2img_batch_png_info_props,
|
| 942 |
+
img2img_batch_png_info_dir,
|
| 943 |
+
] + custom_inputs,
|
| 944 |
+
outputs=[
|
| 945 |
+
img2img_gallery,
|
| 946 |
+
generation_info,
|
| 947 |
+
html_info,
|
| 948 |
+
html_log,
|
| 949 |
+
],
|
| 950 |
+
show_progress=False,
|
| 951 |
+
)
|
| 952 |
+
|
| 953 |
+
interrogate_args = dict(
|
| 954 |
+
_js="get_img2img_tab_index",
|
| 955 |
+
inputs=[
|
| 956 |
+
dummy_component,
|
| 957 |
+
img2img_batch_input_dir,
|
| 958 |
+
img2img_batch_output_dir,
|
| 959 |
+
init_img,
|
| 960 |
+
sketch,
|
| 961 |
+
init_img_with_mask,
|
| 962 |
+
inpaint_color_sketch,
|
| 963 |
+
init_img_inpaint,
|
| 964 |
+
],
|
| 965 |
+
outputs=[img2img_prompt, dummy_component],
|
| 966 |
+
)
|
| 967 |
+
|
| 968 |
+
img2img_prompt.submit(**img2img_args)
|
| 969 |
+
submit.click(**img2img_args)
|
| 970 |
+
|
| 971 |
+
res_switch_btn.click(fn=None, _js="function(){switchWidthHeight('img2img')}", inputs=None, outputs=None, show_progress=False)
|
| 972 |
+
|
| 973 |
+
detect_image_size_btn.click(
|
| 974 |
+
fn=lambda w, h, _: (w or gr.update(), h or gr.update()),
|
| 975 |
+
_js="currentImg2imgSourceResolution",
|
| 976 |
+
inputs=[dummy_component, dummy_component, dummy_component],
|
| 977 |
+
outputs=[width, height],
|
| 978 |
+
show_progress=False,
|
| 979 |
+
)
|
| 980 |
+
|
| 981 |
+
restore_progress_button.click(
|
| 982 |
+
fn=progress.restore_progress,
|
| 983 |
+
_js="restoreProgressImg2img",
|
| 984 |
+
inputs=[dummy_component],
|
| 985 |
+
outputs=[
|
| 986 |
+
img2img_gallery,
|
| 987 |
+
generation_info,
|
| 988 |
+
html_info,
|
| 989 |
+
html_log,
|
| 990 |
+
],
|
| 991 |
+
show_progress=False,
|
| 992 |
+
)
|
| 993 |
+
|
| 994 |
+
img2img_interrogate.click(
|
| 995 |
+
fn=lambda *args: process_interrogate(interrogate, *args),
|
| 996 |
+
**interrogate_args,
|
| 997 |
+
)
|
| 998 |
+
|
| 999 |
+
img2img_deepbooru.click(
|
| 1000 |
+
fn=lambda *args: process_interrogate(interrogate_deepbooru, *args),
|
| 1001 |
+
**interrogate_args,
|
| 1002 |
+
)
|
| 1003 |
+
|
| 1004 |
+
prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)]
|
| 1005 |
+
style_dropdowns = [txt2img_prompt_styles, img2img_prompt_styles]
|
| 1006 |
+
style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"]
|
| 1007 |
+
|
| 1008 |
+
for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts):
|
| 1009 |
+
button.click(
|
| 1010 |
+
fn=add_style,
|
| 1011 |
+
_js="ask_for_style_name",
|
| 1012 |
+
# Have to pass empty dummy component here, because the JavaScript and Python function have to accept
|
| 1013 |
+
# the same number of parameters, but we only know the style-name after the JavaScript prompt
|
| 1014 |
+
inputs=[dummy_component, prompt, negative_prompt],
|
| 1015 |
+
outputs=[txt2img_prompt_styles, img2img_prompt_styles],
|
| 1016 |
+
)
|
| 1017 |
+
|
| 1018 |
+
for button, (prompt, negative_prompt), styles, js_func in zip([txt2img_prompt_style_apply, img2img_prompt_style_apply], prompts, style_dropdowns, style_js_funcs):
|
| 1019 |
+
button.click(
|
| 1020 |
+
fn=apply_styles,
|
| 1021 |
+
_js=js_func,
|
| 1022 |
+
inputs=[prompt, negative_prompt, styles],
|
| 1023 |
+
outputs=[prompt, negative_prompt, styles],
|
| 1024 |
+
)
|
| 1025 |
+
|
| 1026 |
+
token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter])
|
| 1027 |
+
negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[img2img_negative_prompt, steps], outputs=[negative_token_counter])
|
| 1028 |
+
|
| 1029 |
+
ui_extra_networks.setup_ui(extra_networks_ui_img2img, img2img_gallery)
|
| 1030 |
+
|
| 1031 |
+
img2img_paste_fields = [
|
| 1032 |
+
(img2img_prompt, "Prompt"),
|
| 1033 |
+
(img2img_negative_prompt, "Negative prompt"),
|
| 1034 |
+
(steps, "Steps"),
|
| 1035 |
+
(sampler_index, "Sampler"),
|
| 1036 |
+
(restore_faces, "Face restoration"),
|
| 1037 |
+
(cfg_scale, "CFG scale"),
|
| 1038 |
+
(image_cfg_scale, "Image CFG scale"),
|
| 1039 |
+
(seed, "Seed"),
|
| 1040 |
+
(width, "Size-1"),
|
| 1041 |
+
(height, "Size-2"),
|
| 1042 |
+
(batch_size, "Batch size"),
|
| 1043 |
+
(subseed, "Variation seed"),
|
| 1044 |
+
(subseed_strength, "Variation seed strength"),
|
| 1045 |
+
(seed_resize_from_w, "Seed resize from-1"),
|
| 1046 |
+
(seed_resize_from_h, "Seed resize from-2"),
|
| 1047 |
+
(img2img_prompt_styles, lambda d: d["Styles array"] if isinstance(d.get("Styles array"), list) else gr.update()),
|
| 1048 |
+
(denoising_strength, "Denoising strength"),
|
| 1049 |
+
(mask_blur, "Mask blur"),
|
| 1050 |
+
*modules.scripts.scripts_img2img.infotext_fields
|
| 1051 |
+
]
|
| 1052 |
+
parameters_copypaste.add_paste_fields("img2img", init_img, img2img_paste_fields, override_settings)
|
| 1053 |
+
parameters_copypaste.add_paste_fields("inpaint", init_img_with_mask, img2img_paste_fields, override_settings)
|
| 1054 |
+
parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(
|
| 1055 |
+
paste_button=img2img_paste, tabname="img2img", source_text_component=img2img_prompt, source_image_component=None,
|
| 1056 |
+
))
|
| 1057 |
+
|
| 1058 |
+
modules.scripts.scripts_current = None
|
| 1059 |
+
|
| 1060 |
+
with gr.Blocks(analytics_enabled=False) as extras_interface:
|
| 1061 |
+
ui_postprocessing.create_ui()
|
| 1062 |
+
|
| 1063 |
+
with gr.Blocks(analytics_enabled=False) as pnginfo_interface:
|
| 1064 |
+
with gr.Row().style(equal_height=False):
|
| 1065 |
+
with gr.Column(variant='panel'):
|
| 1066 |
+
image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil")
|
| 1067 |
+
|
| 1068 |
+
with gr.Column(variant='panel'):
|
| 1069 |
+
html = gr.HTML()
|
| 1070 |
+
generation_info = gr.Textbox(visible=False, elem_id="pnginfo_generation_info")
|
| 1071 |
+
html2 = gr.HTML()
|
| 1072 |
+
with gr.Row():
|
| 1073 |
+
buttons = parameters_copypaste.create_buttons(["txt2img", "img2img", "inpaint", "extras"])
|
| 1074 |
+
|
| 1075 |
+
for tabname, button in buttons.items():
|
| 1076 |
+
parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(
|
| 1077 |
+
paste_button=button, tabname=tabname, source_text_component=generation_info, source_image_component=image,
|
| 1078 |
+
))
|
| 1079 |
+
|
| 1080 |
+
image.change(
|
| 1081 |
+
fn=wrap_gradio_call(modules.extras.run_pnginfo),
|
| 1082 |
+
inputs=[image],
|
| 1083 |
+
outputs=[html, generation_info, html2],
|
| 1084 |
+
)
|
| 1085 |
+
|
| 1086 |
+
def update_interp_description(value):
|
| 1087 |
+
interp_description_css = "<p style='margin-bottom: 2.5em'>{}</p>"
|
| 1088 |
+
interp_descriptions = {
|
| 1089 |
+
"No interpolation": interp_description_css.format("No interpolation will be used. Requires one model; A. Allows for format conversion and VAE baking."),
|
| 1090 |
+
"Weighted sum": interp_description_css.format("A weighted sum will be used for interpolation. Requires two models; A and B. The result is calculated as A * (1 - M) + B * M"),
|
| 1091 |
+
"Add difference": interp_description_css.format("The difference between the last two models will be added to the first. Requires three models; A, B and C. The result is calculated as A + (B - C) * M")
|
| 1092 |
+
}
|
| 1093 |
+
return interp_descriptions[value]
|
| 1094 |
+
|
| 1095 |
+
with gr.Blocks(analytics_enabled=False) as modelmerger_interface:
|
| 1096 |
+
with gr.Row().style(equal_height=False):
|
| 1097 |
+
with gr.Column(variant='compact'):
|
| 1098 |
+
interp_description = gr.HTML(value=update_interp_description("Weighted sum"), elem_id="modelmerger_interp_description")
|
| 1099 |
+
|
| 1100 |
+
with FormRow(elem_id="modelmerger_models"):
|
| 1101 |
+
primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary model (A)")
|
| 1102 |
+
create_refresh_button(primary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_A")
|
| 1103 |
+
|
| 1104 |
+
secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary model (B)")
|
| 1105 |
+
create_refresh_button(secondary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_B")
|
| 1106 |
+
|
| 1107 |
+
tertiary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_tertiary_model_name", label="Tertiary model (C)")
|
| 1108 |
+
create_refresh_button(tertiary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_C")
|
| 1109 |
+
|
| 1110 |
+
custom_name = gr.Textbox(label="Custom Name (Optional)", elem_id="modelmerger_custom_name")
|
| 1111 |
+
interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Multiplier (M) - set to 0 to get model A', value=0.3, elem_id="modelmerger_interp_amount")
|
| 1112 |
+
interp_method = gr.Radio(choices=["No interpolation", "Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method", elem_id="modelmerger_interp_method")
|
| 1113 |
+
interp_method.change(fn=update_interp_description, inputs=[interp_method], outputs=[interp_description])
|
| 1114 |
+
|
| 1115 |
+
with FormRow():
|
| 1116 |
+
checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", label="Checkpoint format", elem_id="modelmerger_checkpoint_format")
|
| 1117 |
+
save_as_half = gr.Checkbox(value=False, label="Save as float16", elem_id="modelmerger_save_as_half")
|
| 1118 |
+
save_metadata = gr.Checkbox(value=True, label="Save metadata (.safetensors only)", elem_id="modelmerger_save_metadata")
|
| 1119 |
+
|
| 1120 |
+
with FormRow():
|
| 1121 |
+
with gr.Column():
|
| 1122 |
+
config_source = gr.Radio(choices=["A, B or C", "B", "C", "Don't"], value="A, B or C", label="Copy config from", type="index", elem_id="modelmerger_config_method")
|
| 1123 |
+
|
| 1124 |
+
with gr.Column():
|
| 1125 |
+
with FormRow():
|
| 1126 |
+
bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", label="Bake in VAE", elem_id="modelmerger_bake_in_vae")
|
| 1127 |
+
create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae")
|
| 1128 |
+
|
| 1129 |
+
with FormRow():
|
| 1130 |
+
discard_weights = gr.Textbox(value="", label="Discard weights with matching name", elem_id="modelmerger_discard_weights")
|
| 1131 |
+
|
| 1132 |
+
with gr.Row():
|
| 1133 |
+
modelmerger_merge = gr.Button(elem_id="modelmerger_merge", value="Merge", variant='primary')
|
| 1134 |
+
|
| 1135 |
+
with gr.Column(variant='compact', elem_id="modelmerger_results_container"):
|
| 1136 |
+
with gr.Group(elem_id="modelmerger_results_panel"):
|
| 1137 |
+
modelmerger_result = gr.HTML(elem_id="modelmerger_result", show_label=False)
|
| 1138 |
+
|
| 1139 |
+
with gr.Blocks(analytics_enabled=False) as train_interface:
|
| 1140 |
+
with gr.Row().style(equal_height=False):
|
| 1141 |
+
gr.HTML(value="<p style='margin-bottom: 0.7em'>See <b><a href=\"https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Textual-Inversion\">wiki</a></b> for detailed explanation.</p>")
|
| 1142 |
+
|
| 1143 |
+
with gr.Row(variant="compact").style(equal_height=False):
|
| 1144 |
+
with gr.Tabs(elem_id="train_tabs"):
|
| 1145 |
+
|
| 1146 |
+
with gr.Tab(label="Create embedding", id="create_embedding"):
|
| 1147 |
+
new_embedding_name = gr.Textbox(label="Name", elem_id="train_new_embedding_name")
|
| 1148 |
+
initialization_text = gr.Textbox(label="Initialization text", value="*", elem_id="train_initialization_text")
|
| 1149 |
+
nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1, elem_id="train_nvpt")
|
| 1150 |
+
overwrite_old_embedding = gr.Checkbox(value=False, label="Overwrite Old Embedding", elem_id="train_overwrite_old_embedding")
|
| 1151 |
+
|
| 1152 |
+
with gr.Row():
|
| 1153 |
+
with gr.Column(scale=3):
|
| 1154 |
+
gr.HTML(value="")
|
| 1155 |
+
|
| 1156 |
+
with gr.Column():
|
| 1157 |
+
create_embedding = gr.Button(value="Create embedding", variant='primary', elem_id="train_create_embedding")
|
| 1158 |
+
|
| 1159 |
+
with gr.Tab(label="Create hypernetwork", id="create_hypernetwork"):
|
| 1160 |
+
new_hypernetwork_name = gr.Textbox(label="Name", elem_id="train_new_hypernetwork_name")
|
| 1161 |
+
new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "1024", "320", "640", "1280"], elem_id="train_new_hypernetwork_sizes")
|
| 1162 |
+
new_hypernetwork_layer_structure = gr.Textbox("1, 2, 1", label="Enter hypernetwork layer structure", placeholder="1st and last digit must be 1. ex:'1, 2, 1'", elem_id="train_new_hypernetwork_layer_structure")
|
| 1163 |
+
new_hypernetwork_activation_func = gr.Dropdown(value="linear", label="Select activation function of hypernetwork. Recommended : Swish / Linear(none)", choices=modules.hypernetworks.ui.keys, elem_id="train_new_hypernetwork_activation_func")
|
| 1164 |
+
new_hypernetwork_initialization_option = gr.Dropdown(value = "Normal", label="Select Layer weights initialization. Recommended: Kaiming for relu-like, Xavier for sigmoid-like, Normal otherwise", choices=["Normal", "KaimingUniform", "KaimingNormal", "XavierUniform", "XavierNormal"], elem_id="train_new_hypernetwork_initialization_option")
|
| 1165 |
+
new_hypernetwork_add_layer_norm = gr.Checkbox(label="Add layer normalization", elem_id="train_new_hypernetwork_add_layer_norm")
|
| 1166 |
+
new_hypernetwork_use_dropout = gr.Checkbox(label="Use dropout", elem_id="train_new_hypernetwork_use_dropout")
|
| 1167 |
+
new_hypernetwork_dropout_structure = gr.Textbox("0, 0, 0", label="Enter hypernetwork Dropout structure (or empty). Recommended : 0~0.35 incrementing sequence: 0, 0.05, 0.15", placeholder="1st and last digit must be 0 and values should be between 0 and 1. ex:'0, 0.01, 0'")
|
| 1168 |
+
overwrite_old_hypernetwork = gr.Checkbox(value=False, label="Overwrite Old Hypernetwork", elem_id="train_overwrite_old_hypernetwork")
|
| 1169 |
+
|
| 1170 |
+
with gr.Row():
|
| 1171 |
+
with gr.Column(scale=3):
|
| 1172 |
+
gr.HTML(value="")
|
| 1173 |
+
|
| 1174 |
+
with gr.Column():
|
| 1175 |
+
create_hypernetwork = gr.Button(value="Create hypernetwork", variant='primary', elem_id="train_create_hypernetwork")
|
| 1176 |
+
|
| 1177 |
+
with gr.Tab(label="Preprocess images", id="preprocess_images"):
|
| 1178 |
+
process_src = gr.Textbox(label='Source directory', elem_id="train_process_src")
|
| 1179 |
+
process_dst = gr.Textbox(label='Destination directory', elem_id="train_process_dst")
|
| 1180 |
+
process_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="train_process_width")
|
| 1181 |
+
process_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="train_process_height")
|
| 1182 |
+
preprocess_txt_action = gr.Dropdown(label='Existing Caption txt Action', value="ignore", choices=["ignore", "copy", "prepend", "append"], elem_id="train_preprocess_txt_action")
|
| 1183 |
+
|
| 1184 |
+
with gr.Row():
|
| 1185 |
+
process_keep_original_size = gr.Checkbox(label='Keep original size', elem_id="train_process_keep_original_size")
|
| 1186 |
+
process_flip = gr.Checkbox(label='Create flipped copies', elem_id="train_process_flip")
|
| 1187 |
+
process_split = gr.Checkbox(label='Split oversized images', elem_id="train_process_split")
|
| 1188 |
+
process_focal_crop = gr.Checkbox(label='Auto focal point crop', elem_id="train_process_focal_crop")
|
| 1189 |
+
process_multicrop = gr.Checkbox(label='Auto-sized crop', elem_id="train_process_multicrop")
|
| 1190 |
+
process_caption = gr.Checkbox(label='Use BLIP for caption', elem_id="train_process_caption")
|
| 1191 |
+
process_caption_deepbooru = gr.Checkbox(label='Use deepbooru for caption', visible=True, elem_id="train_process_caption_deepbooru")
|
| 1192 |
+
|
| 1193 |
+
with gr.Row(visible=False) as process_split_extra_row:
|
| 1194 |
+
process_split_threshold = gr.Slider(label='Split image threshold', value=0.5, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_split_threshold")
|
| 1195 |
+
process_overlap_ratio = gr.Slider(label='Split image overlap ratio', value=0.2, minimum=0.0, maximum=0.9, step=0.05, elem_id="train_process_overlap_ratio")
|
| 1196 |
+
|
| 1197 |
+
with gr.Row(visible=False) as process_focal_crop_row:
|
| 1198 |
+
process_focal_crop_face_weight = gr.Slider(label='Focal point face weight', value=0.9, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_face_weight")
|
| 1199 |
+
process_focal_crop_entropy_weight = gr.Slider(label='Focal point entropy weight', value=0.15, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_entropy_weight")
|
| 1200 |
+
process_focal_crop_edges_weight = gr.Slider(label='Focal point edges weight', value=0.5, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_edges_weight")
|
| 1201 |
+
process_focal_crop_debug = gr.Checkbox(label='Create debug image', elem_id="train_process_focal_crop_debug")
|
| 1202 |
+
|
| 1203 |
+
with gr.Column(visible=False) as process_multicrop_col:
|
| 1204 |
+
gr.Markdown('Each image is center-cropped with an automatically chosen width and height.')
|
| 1205 |
+
with gr.Row():
|
| 1206 |
+
process_multicrop_mindim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension lower bound", value=384, elem_id="train_process_multicrop_mindim")
|
| 1207 |
+
process_multicrop_maxdim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension upper bound", value=768, elem_id="train_process_multicrop_maxdim")
|
| 1208 |
+
with gr.Row():
|
| 1209 |
+
process_multicrop_minarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area lower bound", value=64*64, elem_id="train_process_multicrop_minarea")
|
| 1210 |
+
process_multicrop_maxarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area upper bound", value=640*640, elem_id="train_process_multicrop_maxarea")
|
| 1211 |
+
with gr.Row():
|
| 1212 |
+
process_multicrop_objective = gr.Radio(["Maximize area", "Minimize error"], value="Maximize area", label="Resizing objective", elem_id="train_process_multicrop_objective")
|
| 1213 |
+
process_multicrop_threshold = gr.Slider(minimum=0, maximum=1, step=0.01, label="Error threshold", value=0.1, elem_id="train_process_multicrop_threshold")
|
| 1214 |
+
|
| 1215 |
+
with gr.Row():
|
| 1216 |
+
with gr.Column(scale=3):
|
| 1217 |
+
gr.HTML(value="")
|
| 1218 |
+
|
| 1219 |
+
with gr.Column():
|
| 1220 |
+
with gr.Row():
|
| 1221 |
+
interrupt_preprocessing = gr.Button("Interrupt", elem_id="train_interrupt_preprocessing")
|
| 1222 |
+
run_preprocess = gr.Button(value="Preprocess", variant='primary', elem_id="train_run_preprocess")
|
| 1223 |
+
|
| 1224 |
+
process_split.change(
|
| 1225 |
+
fn=lambda show: gr_show(show),
|
| 1226 |
+
inputs=[process_split],
|
| 1227 |
+
outputs=[process_split_extra_row],
|
| 1228 |
+
)
|
| 1229 |
+
|
| 1230 |
+
process_focal_crop.change(
|
| 1231 |
+
fn=lambda show: gr_show(show),
|
| 1232 |
+
inputs=[process_focal_crop],
|
| 1233 |
+
outputs=[process_focal_crop_row],
|
| 1234 |
+
)
|
| 1235 |
+
|
| 1236 |
+
process_multicrop.change(
|
| 1237 |
+
fn=lambda show: gr_show(show),
|
| 1238 |
+
inputs=[process_multicrop],
|
| 1239 |
+
outputs=[process_multicrop_col],
|
| 1240 |
+
)
|
| 1241 |
+
|
| 1242 |
+
def get_textual_inversion_template_names():
|
| 1243 |
+
return sorted(textual_inversion.textual_inversion_templates)
|
| 1244 |
+
|
| 1245 |
+
with gr.Tab(label="Train", id="train"):
|
| 1246 |
+
gr.HTML(value="<p style='margin-bottom: 0.7em'>Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images <a href=\"https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Textual-Inversion\" style=\"font-weight:bold;\">[wiki]</a></p>")
|
| 1247 |
+
with FormRow():
|
| 1248 |
+
train_embedding_name = gr.Dropdown(label='Embedding', elem_id="train_embedding", choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
|
| 1249 |
+
create_refresh_button(train_embedding_name, sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings, lambda: {"choices": sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())}, "refresh_train_embedding_name")
|
| 1250 |
+
|
| 1251 |
+
train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', elem_id="train_hypernetwork", choices=sorted(shared.hypernetworks))
|
| 1252 |
+
create_refresh_button(train_hypernetwork_name, shared.reload_hypernetworks, lambda: {"choices": sorted(shared.hypernetworks)}, "refresh_train_hypernetwork_name")
|
| 1253 |
+
|
| 1254 |
+
with FormRow():
|
| 1255 |
+
embedding_learn_rate = gr.Textbox(label='Embedding Learning rate', placeholder="Embedding Learning rate", value="0.005", elem_id="train_embedding_learn_rate")
|
| 1256 |
+
hypernetwork_learn_rate = gr.Textbox(label='Hypernetwork Learning rate', placeholder="Hypernetwork Learning rate", value="0.00001", elem_id="train_hypernetwork_learn_rate")
|
| 1257 |
+
|
| 1258 |
+
with FormRow():
|
| 1259 |
+
clip_grad_mode = gr.Dropdown(value="disabled", label="Gradient Clipping", choices=["disabled", "value", "norm"])
|
| 1260 |
+
clip_grad_value = gr.Textbox(placeholder="Gradient clip value", value="0.1", show_label=False)
|
| 1261 |
+
|
| 1262 |
+
with FormRow():
|
| 1263 |
+
batch_size = gr.Number(label='Batch size', value=1, precision=0, elem_id="train_batch_size")
|
| 1264 |
+
gradient_step = gr.Number(label='Gradient accumulation steps', value=1, precision=0, elem_id="train_gradient_step")
|
| 1265 |
+
|
| 1266 |
+
dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images", elem_id="train_dataset_directory")
|
| 1267 |
+
log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion", elem_id="train_log_directory")
|
| 1268 |
+
|
| 1269 |
+
with FormRow():
|
| 1270 |
+
template_file = gr.Dropdown(label='Prompt template', value="style_filewords.txt", elem_id="train_template_file", choices=get_textual_inversion_template_names())
|
| 1271 |
+
create_refresh_button(template_file, textual_inversion.list_textual_inversion_templates, lambda: {"choices": get_textual_inversion_template_names()}, "refrsh_train_template_file")
|
| 1272 |
+
|
| 1273 |
+
training_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="train_training_width")
|
| 1274 |
+
training_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="train_training_height")
|
| 1275 |
+
varsize = gr.Checkbox(label="Do not resize images", value=False, elem_id="train_varsize")
|
| 1276 |
+
steps = gr.Number(label='Max steps', value=100000, precision=0, elem_id="train_steps")
|
| 1277 |
+
|
| 1278 |
+
with FormRow():
|
| 1279 |
+
create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0, elem_id="train_create_image_every")
|
| 1280 |
+
save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0, elem_id="train_save_embedding_every")
|
| 1281 |
+
|
| 1282 |
+
use_weight = gr.Checkbox(label="Use PNG alpha channel as loss weight", value=False, elem_id="use_weight")
|
| 1283 |
+
|
| 1284 |
+
save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True, elem_id="train_save_image_with_stored_embedding")
|
| 1285 |
+
preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False, elem_id="train_preview_from_txt2img")
|
| 1286 |
+
|
| 1287 |
+
shuffle_tags = gr.Checkbox(label="Shuffle tags by ',' when creating prompts.", value=False, elem_id="train_shuffle_tags")
|
| 1288 |
+
tag_drop_out = gr.Slider(minimum=0, maximum=1, step=0.1, label="Drop out tags when creating prompts.", value=0, elem_id="train_tag_drop_out")
|
| 1289 |
+
|
| 1290 |
+
latent_sampling_method = gr.Radio(label='Choose latent sampling method', value="once", choices=['once', 'deterministic', 'random'], elem_id="train_latent_sampling_method")
|
| 1291 |
+
|
| 1292 |
+
with gr.Row():
|
| 1293 |
+
train_embedding = gr.Button(value="Train Embedding", variant='primary', elem_id="train_train_embedding")
|
| 1294 |
+
interrupt_training = gr.Button(value="Interrupt", elem_id="train_interrupt_training")
|
| 1295 |
+
train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary', elem_id="train_train_hypernetwork")
|
| 1296 |
+
|
| 1297 |
+
params = script_callbacks.UiTrainTabParams(txt2img_preview_params)
|
| 1298 |
+
|
| 1299 |
+
script_callbacks.ui_train_tabs_callback(params)
|
| 1300 |
+
|
| 1301 |
+
with gr.Column(elem_id='ti_gallery_container'):
|
| 1302 |
+
ti_output = gr.Text(elem_id="ti_output", value="", show_label=False)
|
| 1303 |
+
gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(columns=4)
|
| 1304 |
+
gr.HTML(elem_id="ti_progress", value="")
|
| 1305 |
+
ti_outcome = gr.HTML(elem_id="ti_error", value="")
|
| 1306 |
+
|
| 1307 |
+
create_embedding.click(
|
| 1308 |
+
fn=modules.textual_inversion.ui.create_embedding,
|
| 1309 |
+
inputs=[
|
| 1310 |
+
new_embedding_name,
|
| 1311 |
+
initialization_text,
|
| 1312 |
+
nvpt,
|
| 1313 |
+
overwrite_old_embedding,
|
| 1314 |
+
],
|
| 1315 |
+
outputs=[
|
| 1316 |
+
train_embedding_name,
|
| 1317 |
+
ti_output,
|
| 1318 |
+
ti_outcome,
|
| 1319 |
+
]
|
| 1320 |
+
)
|
| 1321 |
+
|
| 1322 |
+
create_hypernetwork.click(
|
| 1323 |
+
fn=modules.hypernetworks.ui.create_hypernetwork,
|
| 1324 |
+
inputs=[
|
| 1325 |
+
new_hypernetwork_name,
|
| 1326 |
+
new_hypernetwork_sizes,
|
| 1327 |
+
overwrite_old_hypernetwork,
|
| 1328 |
+
new_hypernetwork_layer_structure,
|
| 1329 |
+
new_hypernetwork_activation_func,
|
| 1330 |
+
new_hypernetwork_initialization_option,
|
| 1331 |
+
new_hypernetwork_add_layer_norm,
|
| 1332 |
+
new_hypernetwork_use_dropout,
|
| 1333 |
+
new_hypernetwork_dropout_structure
|
| 1334 |
+
],
|
| 1335 |
+
outputs=[
|
| 1336 |
+
train_hypernetwork_name,
|
| 1337 |
+
ti_output,
|
| 1338 |
+
ti_outcome,
|
| 1339 |
+
]
|
| 1340 |
+
)
|
| 1341 |
+
|
| 1342 |
+
run_preprocess.click(
|
| 1343 |
+
fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]),
|
| 1344 |
+
_js="start_training_textual_inversion",
|
| 1345 |
+
inputs=[
|
| 1346 |
+
dummy_component,
|
| 1347 |
+
process_src,
|
| 1348 |
+
process_dst,
|
| 1349 |
+
process_width,
|
| 1350 |
+
process_height,
|
| 1351 |
+
preprocess_txt_action,
|
| 1352 |
+
process_keep_original_size,
|
| 1353 |
+
process_flip,
|
| 1354 |
+
process_split,
|
| 1355 |
+
process_caption,
|
| 1356 |
+
process_caption_deepbooru,
|
| 1357 |
+
process_split_threshold,
|
| 1358 |
+
process_overlap_ratio,
|
| 1359 |
+
process_focal_crop,
|
| 1360 |
+
process_focal_crop_face_weight,
|
| 1361 |
+
process_focal_crop_entropy_weight,
|
| 1362 |
+
process_focal_crop_edges_weight,
|
| 1363 |
+
process_focal_crop_debug,
|
| 1364 |
+
process_multicrop,
|
| 1365 |
+
process_multicrop_mindim,
|
| 1366 |
+
process_multicrop_maxdim,
|
| 1367 |
+
process_multicrop_minarea,
|
| 1368 |
+
process_multicrop_maxarea,
|
| 1369 |
+
process_multicrop_objective,
|
| 1370 |
+
process_multicrop_threshold,
|
| 1371 |
+
],
|
| 1372 |
+
outputs=[
|
| 1373 |
+
ti_output,
|
| 1374 |
+
ti_outcome,
|
| 1375 |
+
],
|
| 1376 |
+
)
|
| 1377 |
+
|
| 1378 |
+
train_embedding.click(
|
| 1379 |
+
fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]),
|
| 1380 |
+
_js="start_training_textual_inversion",
|
| 1381 |
+
inputs=[
|
| 1382 |
+
dummy_component,
|
| 1383 |
+
train_embedding_name,
|
| 1384 |
+
embedding_learn_rate,
|
| 1385 |
+
batch_size,
|
| 1386 |
+
gradient_step,
|
| 1387 |
+
dataset_directory,
|
| 1388 |
+
log_directory,
|
| 1389 |
+
training_width,
|
| 1390 |
+
training_height,
|
| 1391 |
+
varsize,
|
| 1392 |
+
steps,
|
| 1393 |
+
clip_grad_mode,
|
| 1394 |
+
clip_grad_value,
|
| 1395 |
+
shuffle_tags,
|
| 1396 |
+
tag_drop_out,
|
| 1397 |
+
latent_sampling_method,
|
| 1398 |
+
use_weight,
|
| 1399 |
+
create_image_every,
|
| 1400 |
+
save_embedding_every,
|
| 1401 |
+
template_file,
|
| 1402 |
+
save_image_with_stored_embedding,
|
| 1403 |
+
preview_from_txt2img,
|
| 1404 |
+
*txt2img_preview_params,
|
| 1405 |
+
],
|
| 1406 |
+
outputs=[
|
| 1407 |
+
ti_output,
|
| 1408 |
+
ti_outcome,
|
| 1409 |
+
]
|
| 1410 |
+
)
|
| 1411 |
+
|
| 1412 |
+
train_hypernetwork.click(
|
| 1413 |
+
fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]),
|
| 1414 |
+
_js="start_training_textual_inversion",
|
| 1415 |
+
inputs=[
|
| 1416 |
+
dummy_component,
|
| 1417 |
+
train_hypernetwork_name,
|
| 1418 |
+
hypernetwork_learn_rate,
|
| 1419 |
+
batch_size,
|
| 1420 |
+
gradient_step,
|
| 1421 |
+
dataset_directory,
|
| 1422 |
+
log_directory,
|
| 1423 |
+
training_width,
|
| 1424 |
+
training_height,
|
| 1425 |
+
varsize,
|
| 1426 |
+
steps,
|
| 1427 |
+
clip_grad_mode,
|
| 1428 |
+
clip_grad_value,
|
| 1429 |
+
shuffle_tags,
|
| 1430 |
+
tag_drop_out,
|
| 1431 |
+
latent_sampling_method,
|
| 1432 |
+
use_weight,
|
| 1433 |
+
create_image_every,
|
| 1434 |
+
save_embedding_every,
|
| 1435 |
+
template_file,
|
| 1436 |
+
preview_from_txt2img,
|
| 1437 |
+
*txt2img_preview_params,
|
| 1438 |
+
],
|
| 1439 |
+
outputs=[
|
| 1440 |
+
ti_output,
|
| 1441 |
+
ti_outcome,
|
| 1442 |
+
]
|
| 1443 |
+
)
|
| 1444 |
+
|
| 1445 |
+
interrupt_training.click(
|
| 1446 |
+
fn=lambda: shared.state.interrupt(),
|
| 1447 |
+
inputs=[],
|
| 1448 |
+
outputs=[],
|
| 1449 |
+
)
|
| 1450 |
+
|
| 1451 |
+
interrupt_preprocessing.click(
|
| 1452 |
+
fn=lambda: shared.state.interrupt(),
|
| 1453 |
+
inputs=[],
|
| 1454 |
+
outputs=[],
|
| 1455 |
+
)
|
| 1456 |
+
|
| 1457 |
+
loadsave = ui_loadsave.UiLoadsave(cmd_opts.ui_config_file)
|
| 1458 |
+
|
| 1459 |
+
settings = ui_settings.UiSettings()
|
| 1460 |
+
settings.create_ui(loadsave, dummy_component)
|
| 1461 |
+
|
| 1462 |
+
interfaces = [
|
| 1463 |
+
(txt2img_interface, "txt2img", "txt2img"),
|
| 1464 |
+
(img2img_interface, "img2img", "img2img"),
|
| 1465 |
+
(extras_interface, "Extras", "extras"),
|
| 1466 |
+
(pnginfo_interface, "PNG Info", "pnginfo"),
|
| 1467 |
+
(modelmerger_interface, "Checkpoint Merger", "modelmerger"),
|
| 1468 |
+
(train_interface, "Train", "train"),
|
| 1469 |
+
]
|
| 1470 |
+
|
| 1471 |
+
interfaces += script_callbacks.ui_tabs_callback()
|
| 1472 |
+
interfaces += [(settings.interface, "Settings", "settings")]
|
| 1473 |
+
|
| 1474 |
+
extensions_interface = ui_extensions.create_ui()
|
| 1475 |
+
interfaces += [(extensions_interface, "Extensions", "extensions")]
|
| 1476 |
+
|
| 1477 |
+
shared.tab_names = []
|
| 1478 |
+
for _interface, label, _ifid in interfaces:
|
| 1479 |
+
shared.tab_names.append(label)
|
| 1480 |
+
|
| 1481 |
+
with gr.Blocks(theme=shared.gradio_theme, analytics_enabled=False, title="Stable Diffusion") as demo:
|
| 1482 |
+
settings.add_quicksettings()
|
| 1483 |
+
|
| 1484 |
+
parameters_copypaste.connect_paste_params_buttons()
|
| 1485 |
+
|
| 1486 |
+
with gr.Tabs(elem_id="tabs") as tabs:
|
| 1487 |
+
tab_order = {k: i for i, k in enumerate(opts.ui_tab_order)}
|
| 1488 |
+
sorted_interfaces = sorted(interfaces, key=lambda x: tab_order.get(x[1], 9999))
|
| 1489 |
+
|
| 1490 |
+
for interface, label, ifid in sorted_interfaces:
|
| 1491 |
+
if label in shared.opts.hidden_tabs:
|
| 1492 |
+
continue
|
| 1493 |
+
with gr.TabItem(label, id=ifid, elem_id=f"tab_{ifid}"):
|
| 1494 |
+
interface.render()
|
| 1495 |
+
|
| 1496 |
+
for interface, _label, ifid in interfaces:
|
| 1497 |
+
if ifid in ["extensions", "settings"]:
|
| 1498 |
+
continue
|
| 1499 |
+
|
| 1500 |
+
loadsave.add_block(interface, ifid)
|
| 1501 |
+
|
| 1502 |
+
loadsave.add_component(f"webui/Tabs@{tabs.elem_id}", tabs)
|
| 1503 |
+
|
| 1504 |
+
loadsave.setup_ui()
|
| 1505 |
+
|
| 1506 |
+
if os.path.exists(os.path.join(script_path, "notification.mp3")):
|
| 1507 |
+
gr.Audio(interactive=False, value=os.path.join(script_path, "notification.mp3"), elem_id="audio_notification", visible=False)
|
| 1508 |
+
|
| 1509 |
+
footer = shared.html("footer.html")
|
| 1510 |
+
footer = footer.format(versions=versions_html(), api_docs="/docs" if shared.cmd_opts.api else "https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/API")
|
| 1511 |
+
gr.HTML(footer, elem_id="footer")
|
| 1512 |
+
|
| 1513 |
+
settings.add_functionality(demo)
|
| 1514 |
+
|
| 1515 |
+
update_image_cfg_scale_visibility = lambda: gr.update(visible=shared.sd_model and shared.sd_model.cond_stage_key == "edit")
|
| 1516 |
+
settings.text_settings.change(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale])
|
| 1517 |
+
demo.load(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale])
|
| 1518 |
+
|
| 1519 |
+
def modelmerger(*args):
|
| 1520 |
+
try:
|
| 1521 |
+
results = modules.extras.run_modelmerger(*args)
|
| 1522 |
+
except Exception as e:
|
| 1523 |
+
errors.report("Error loading/saving model file", exc_info=True)
|
| 1524 |
+
modules.sd_models.list_models() # to remove the potentially missing models from the list
|
| 1525 |
+
return [*[gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"]
|
| 1526 |
+
return results
|
| 1527 |
+
|
| 1528 |
+
modelmerger_merge.click(fn=lambda: '', inputs=[], outputs=[modelmerger_result])
|
| 1529 |
+
modelmerger_merge.click(
|
| 1530 |
+
fn=wrap_gradio_gpu_call(modelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]),
|
| 1531 |
+
_js='modelmerger',
|
| 1532 |
+
inputs=[
|
| 1533 |
+
dummy_component,
|
| 1534 |
+
primary_model_name,
|
| 1535 |
+
secondary_model_name,
|
| 1536 |
+
tertiary_model_name,
|
| 1537 |
+
interp_method,
|
| 1538 |
+
interp_amount,
|
| 1539 |
+
save_as_half,
|
| 1540 |
+
custom_name,
|
| 1541 |
+
checkpoint_format,
|
| 1542 |
+
config_source,
|
| 1543 |
+
bake_in_vae,
|
| 1544 |
+
discard_weights,
|
| 1545 |
+
save_metadata,
|
| 1546 |
+
],
|
| 1547 |
+
outputs=[
|
| 1548 |
+
primary_model_name,
|
| 1549 |
+
secondary_model_name,
|
| 1550 |
+
tertiary_model_name,
|
| 1551 |
+
settings.component_dict['sd_model_checkpoint'],
|
| 1552 |
+
modelmerger_result,
|
| 1553 |
+
]
|
| 1554 |
+
)
|
| 1555 |
+
|
| 1556 |
+
loadsave.dump_defaults()
|
| 1557 |
+
demo.ui_loadsave = loadsave
|
| 1558 |
+
|
| 1559 |
+
# Required as a workaround for change() event not triggering when loading values from ui-config.json
|
| 1560 |
+
interp_description.value = update_interp_description(interp_method.value)
|
| 1561 |
+
|
| 1562 |
+
return demo
|
| 1563 |
+
|
| 1564 |
+
|
| 1565 |
+
def versions_html():
|
| 1566 |
+
import torch
|
| 1567 |
+
import launch
|
| 1568 |
+
|
| 1569 |
+
python_version = ".".join([str(x) for x in sys.version_info[0:3]])
|
| 1570 |
+
commit = launch.commit_hash()
|
| 1571 |
+
tag = launch.git_tag()
|
| 1572 |
+
|
| 1573 |
+
if shared.xformers_available:
|
| 1574 |
+
import xformers
|
| 1575 |
+
xformers_version = xformers.__version__
|
| 1576 |
+
else:
|
| 1577 |
+
xformers_version = "N/A"
|
| 1578 |
+
|
| 1579 |
+
return f"""
|
| 1580 |
+
version: <a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/{commit}">{tag}</a>
|
| 1581 |
+
 • 
|
| 1582 |
+
python: <span title="{sys.version}">{python_version}</span>
|
| 1583 |
+
 • 
|
| 1584 |
+
torch: {getattr(torch, '__long_version__',torch.__version__)}
|
| 1585 |
+
 • 
|
| 1586 |
+
xformers: {xformers_version}
|
| 1587 |
+
 • 
|
| 1588 |
+
gradio: {gr.__version__}
|
| 1589 |
+
 • 
|
| 1590 |
+
checkpoint: <a id="sd_checkpoint_hash">N/A</a>
|
| 1591 |
+
"""
|
| 1592 |
+
|
| 1593 |
+
|
| 1594 |
+
def setup_ui_api(app):
|
| 1595 |
+
from pydantic import BaseModel, Field
|
| 1596 |
+
from typing import List
|
| 1597 |
+
|
| 1598 |
+
class QuicksettingsHint(BaseModel):
|
| 1599 |
+
name: str = Field(title="Name of the quicksettings field")
|
| 1600 |
+
label: str = Field(title="Label of the quicksettings field")
|
| 1601 |
+
|
| 1602 |
+
def quicksettings_hint():
|
| 1603 |
+
return [QuicksettingsHint(name=k, label=v.label) for k, v in opts.data_labels.items()]
|
| 1604 |
+
|
| 1605 |
+
app.add_api_route("/internal/quicksettings-hint", quicksettings_hint, methods=["GET"], response_model=List[QuicksettingsHint])
|
| 1606 |
+
|
| 1607 |
+
app.add_api_route("/internal/ping", lambda: {}, methods=["GET"])
|
| 1608 |
+
|
| 1609 |
+
app.add_api_route("/internal/profile-startup", lambda: timer.startup_record, methods=["GET"])
|
| 1610 |
+
|
| 1611 |
+
def download_sysinfo(attachment=False):
|
| 1612 |
+
from fastapi.responses import PlainTextResponse
|
| 1613 |
+
|
| 1614 |
+
text = sysinfo.get()
|
| 1615 |
+
filename = f"sysinfo-{datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.txt"
|
| 1616 |
+
|
| 1617 |
+
return PlainTextResponse(text, headers={'Content-Disposition': f'{"attachment" if attachment else "inline"}; filename="{filename}"'})
|
| 1618 |
+
|
| 1619 |
+
app.add_api_route("/internal/sysinfo", download_sysinfo, methods=["GET"])
|
| 1620 |
+
app.add_api_route("/internal/sysinfo-download", lambda: download_sysinfo(attachment=True), methods=["GET"])
|
| 1621 |
+
|