Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Overbill1683
Stable Diffusion Webui
提交
5fbed652
S
Stable Diffusion Webui
项目概览
Overbill1683
/
Stable Diffusion Webui
10 个月 前同步成功
通知
1736
Star
81
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
分析
仓库
DevOps
项目成员
Pages
S
Stable Diffusion Webui
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Pages
分析
分析
仓库分析
DevOps
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
提交
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
5fbed652
编写于
9月 11, 2022
作者:
C
cryzed
提交者:
AUTOMATIC1111
9月 11, 2022
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add support for saving styles with negative prompts
上级
d97c6f22
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
72 addition
and
50 deletion
+72
-50
.gitignore
.gitignore
+1
-0
modules/styles.py
modules/styles.py
+52
-29
modules/ui.py
modules/ui.py
+16
-14
script.js
script.js
+3
-7
未找到文件。
.gitignore
浏览文件 @
5fbed652
...
...
@@ -12,5 +12,6 @@ __pycache__
/webui.settings.bat
/embeddings
/styles.csv
/styles.csv.bak
/webui-user.bat
/interrogate
modules/styles.py
浏览文件 @
5fbed652
# We need this so Python doesn't complain about the unknown StableDiffusionProcessing-typehint at runtime
from
__future__
import
annotations
import
csv
import
os
import
os.path
from
collections
import
namedtuple
import
typing
import
collections.abc
as
abc
import
tempfile
import
shutil
PromptStyle
=
namedtuple
(
"PromptStyle"
,
[
"name"
,
"text"
])
if
typing
.
TYPE_CHECKING
:
# Only import this when code is being type-checked, it doesn't have any effect at runtime
from
.processing
import
StableDiffusionProcessing
def
load_styles
(
filename
):
res
=
{
"None"
:
PromptStyle
(
"None"
,
""
)}
class
PromptStyle
(
typing
.
NamedTuple
):
name
:
str
prompt
:
str
negative_prompt
:
str
if
os
.
path
.
exists
(
filename
):
with
open
(
filename
,
"r"
,
encoding
=
"utf8"
,
newline
=
''
)
as
file
:
reader
=
csv
.
DictReader
(
file
)
for
row
in
reader
:
res
[
row
[
"name"
]]
=
PromptStyle
(
row
[
"name"
],
row
[
"text"
])
def
load_styles
(
path
:
str
)
->
dict
[
str
,
PromptStyle
]
:
styles
=
{
"None"
:
PromptStyle
(
"None"
,
""
,
""
)}
return
res
if
os
.
path
.
exists
(
path
):
with
open
(
path
,
"r"
,
encoding
=
"utf8"
,
newline
=
''
)
as
file
:
reader
=
csv
.
DictReader
(
file
)
for
row
in
reader
:
# Support loading old CSV format with "name, text"-columns
prompt
=
row
[
"prompt"
]
if
"prompt"
in
row
else
row
[
"text"
]
negative_prompt
=
row
.
get
(
"negative_prompt"
,
""
)
styles
[
row
[
"name"
]]
=
PromptStyle
(
row
[
"name"
],
prompt
,
negative_prompt
)
return
styles
def
apply_style_text
(
style_text
,
prompt
):
if
style_text
==
""
:
return
prompt
return
prompt
+
", "
+
style_text
if
prompt
else
style_text
def
merge_prompts
(
style_prompt
:
str
,
prompt
:
str
)
->
str
:
parts
=
filter
(
None
,
(
prompt
.
strip
(),
style_prompt
.
strip
()))
return
", "
.
join
(
parts
)
def
apply_style
(
p
,
style
)
:
if
type
(
p
.
prompt
)
==
list
:
p
.
prompt
=
[
apply_style_text
(
style
.
text
,
x
)
for
x
in
p
.
prompt
]
def
apply_style
(
p
rocessing
:
StableDiffusionProcessing
,
style
:
PromptStyle
)
->
None
:
if
isinstance
(
processing
.
prompt
,
list
)
:
p
rocessing
.
prompt
=
[
merge_prompts
(
style
.
prompt
,
p
)
for
p
in
processing
.
prompt
]
else
:
p
.
prompt
=
apply_style_text
(
style
.
text
,
p
.
prompt
)
p
rocessing
.
prompt
=
merge_prompts
(
style
.
prompt
,
processing
.
prompt
)
def
save_style
(
filename
,
style
):
with
open
(
filename
,
"a"
,
encoding
=
"utf8"
,
newline
=
''
)
as
file
:
atstart
=
file
.
tell
()
==
0
writer
=
csv
.
DictWriter
(
file
,
fieldnames
=
[
"name"
,
"text"
])
if
atstart
:
writer
.
writeheader
()
writer
.
writerow
({
"name"
:
style
.
name
,
"text"
:
style
.
text
})
if
isinstance
(
processing
.
negative_prompt
,
list
):
processing
.
negative_prompt
=
[
merge_prompts
(
style
.
negative_prompt
,
p
)
for
p
in
processing
.
negative_prompt
]
else
:
processing
.
negative_prompt
=
merge_prompts
(
style
.
negative_prompt
,
processing
.
negative_prompt
)
def
save_styles
(
path
:
str
,
styles
:
abc
.
Iterable
[
PromptStyle
])
->
None
:
# Write to temporary file first, so we don't nuke the file if something goes wrong
fd
,
temp_path
=
tempfile
.
mkstemp
(
".csv"
)
with
os
.
fdopen
(
fd
,
"w"
,
encoding
=
"utf8"
,
newline
=
''
)
as
file
:
# _fields is actually part of the public API: typing.NamedTuple is a replacement for collections.NamedTuple,
# and collections.NamedTuple has explicit documentation for accessing _fields. Same goes for _asdict()
writer
=
csv
.
DictWriter
(
file
,
fieldnames
=
PromptStyle
.
_fields
)
writer
.
writeheader
()
writer
.
writerows
(
style
.
_asdict
()
for
style
in
styles
)
# Always keep a backup file around
shutil
.
copy
(
path
,
path
+
".bak"
)
shutil
.
move
(
temp_path
,
path
)
modules/ui.py
浏览文件 @
5fbed652
...
...
@@ -228,17 +228,17 @@ def create_seed_inputs():
return
seed
,
subseed
,
subseed_strength
,
seed_resize_from_h
,
seed_resize_from_w
def
add_style
(
style_name
,
text
):
if
style_
name
is
None
:
def
add_style
(
name
:
str
,
prompt
:
str
,
negative_prompt
:
str
):
if
name
is
None
:
return
[
gr_show
(),
gr_show
()]
style
=
modules
.
styles
.
PromptStyle
(
style_name
,
text
)
modules
.
styles
.
save_style
(
shared
.
styles_filename
,
style
)
style
=
modules
.
styles
.
PromptStyle
(
name
,
prompt
,
negative_prompt
)
shared
.
prompt_styles
[
style
.
name
]
=
style
# Save all loaded prompt styles: this allows us to update the storage format in the future more easily, because we
# reserialize all styles every time we save them
modules
.
styles
.
save_styles
(
shared
.
styles_filename
,
shared
.
prompt_styles
.
values
())
update
=
{
"visible"
:
True
,
"choices"
:
[
k
for
k
,
v
in
shared
.
prompt_styles
.
items
()]
,
"__type__"
:
"update"
}
update
=
{
"visible"
:
True
,
"choices"
:
list
(
shared
.
prompt_styles
)
,
"__type__"
:
"update"
}
return
[
update
,
update
]
...
...
@@ -251,7 +251,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
with
gr
.
Blocks
(
analytics_enabled
=
False
)
as
txt2img_interface
:
with
gr
.
Row
(
elem_id
=
"toprow"
):
txt2img_prompt
=
gr
.
Textbox
(
label
=
"Prompt"
,
elem_id
=
"txt2img_prompt"
,
show_label
=
False
,
placeholder
=
"Prompt"
,
lines
=
1
)
negative_prompt
=
gr
.
Textbox
(
label
=
"Negative prompt"
,
elem_id
=
"txt2img_negative_prompt"
,
show_label
=
False
,
placeholder
=
"Negative prompt"
,
lines
=
1
)
txt2img_
negative_prompt
=
gr
.
Textbox
(
label
=
"Negative prompt"
,
elem_id
=
"txt2img_negative_prompt"
,
show_label
=
False
,
placeholder
=
"Negative prompt"
,
lines
=
1
)
txt2img_prompt_style
=
gr
.
Dropdown
(
label
=
"Style"
,
show_label
=
False
,
elem_id
=
"style_index"
,
choices
=
[
k
for
k
,
v
in
shared
.
prompt_styles
.
items
()],
value
=
next
(
iter
(
shared
.
prompt_styles
.
keys
())),
visible
=
len
(
shared
.
prompt_styles
)
>
1
)
roll
=
gr
.
Button
(
'Roll'
,
elem_id
=
"txt2img_roll"
,
visible
=
len
(
shared
.
artist_db
.
artists
)
>
0
)
submit
=
gr
.
Button
(
'Generate'
,
elem_id
=
"txt2img_generate"
,
variant
=
'primary'
)
...
...
@@ -308,7 +308,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
_js
=
"submit"
,
inputs
=
[
txt2img_prompt
,
negative_prompt
,
txt2img_
negative_prompt
,
txt2img_prompt_style
,
steps
,
sampler_index
,
...
...
@@ -372,7 +372,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
with
gr
.
Blocks
(
analytics_enabled
=
False
)
as
img2img_interface
:
with
gr
.
Row
(
elem_id
=
"toprow"
):
img2img_prompt
=
gr
.
Textbox
(
label
=
"Prompt"
,
elem_id
=
"img2img_prompt"
,
show_label
=
False
,
placeholder
=
"Prompt"
,
lines
=
1
)
negative_prompt
=
gr
.
Textbox
(
label
=
"Negative prompt"
,
elem_id
=
"img2img_negative_prompt"
,
show_label
=
False
,
placeholder
=
"Negative prompt"
,
lines
=
1
)
img2img_
negative_prompt
=
gr
.
Textbox
(
label
=
"Negative prompt"
,
elem_id
=
"img2img_negative_prompt"
,
show_label
=
False
,
placeholder
=
"Negative prompt"
,
lines
=
1
)
img2img_prompt_style
=
gr
.
Dropdown
(
label
=
"Style"
,
show_label
=
False
,
elem_id
=
"style_index"
,
choices
=
[
k
for
k
,
v
in
shared
.
prompt_styles
.
items
()],
value
=
next
(
iter
(
shared
.
prompt_styles
.
keys
())),
visible
=
len
(
shared
.
prompt_styles
)
>
1
)
img2img_interrogate
=
gr
.
Button
(
'Interrogate'
,
elem_id
=
"img2img_interrogate"
,
variant
=
'primary'
)
submit
=
gr
.
Button
(
'Generate'
,
elem_id
=
"img2img_generate"
,
variant
=
'primary'
)
...
...
@@ -441,7 +441,6 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
img2img_save_style
=
gr
.
Button
(
'Save prompt as style'
)
progressbar
=
gr
.
HTML
(
elem_id
=
"progressbar"
)
style_dummpy
=
gr
.
Textbox
(
visible
=
False
)
with
gr
.
Group
():
html_info
=
gr
.
HTML
()
...
...
@@ -510,7 +509,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
_js
=
"submit"
,
inputs
=
[
img2img_prompt
,
negative_prompt
,
img2img_
negative_prompt
,
img2img_prompt_style
,
init_img
,
init_img_with_mask
,
...
...
@@ -580,11 +579,14 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
]
)
for
button
,
propmt
in
zip
([
txt2img_save_style
,
img2img_save_style
],
[
txt2img_prompt
,
img2img_prompt
]):
dummy_component
=
gr
.
Label
(
visible
=
False
)
for
button
,
(
prompt
,
negative_prompt
)
in
zip
([
txt2img_save_style
,
img2img_save_style
],
[(
txt2img_prompt
,
txt2img_negative_prompt
),
(
img2img_prompt
,
img2img_negative_prompt
)]):
button
.
click
(
fn
=
add_style
,
_js
=
"ask_for_style_name"
,
inputs
=
[
style_dummpy
,
propmt
],
# Have to pass empty dummy component here, because the JavaScript and Python function have to accept
# the same number of parameters, but we only know the style-name after the JavaScript prompt
inputs
=
[
dummy_component
,
prompt
,
negative_prompt
],
outputs
=
[
txt2img_prompt_style
,
img2img_prompt_style
],
)
...
...
script.js
浏览文件 @
5fbed652
...
...
@@ -186,11 +186,7 @@ window.addEventListener('paste', e => {
});
});
function
ask_for_style_name
(
style_name
,
text
){
input
=
prompt
(
'
Style name:
'
);
if
(
input
===
null
)
{
return
[
null
,
null
]
}
return
[
input
,
text
]
function
ask_for_style_name
(
_
,
prompt_text
,
negative_prompt_text
)
{
name_
=
prompt
(
'
Style name:
'
)
return
name_
===
null
?
[
null
,
null
,
null
]:
[
name_
,
prompt_text
,
negative_prompt_text
]
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录