1+ import argparse
12import json
23import base64
34import mimetypes
45import os
56from http .server import BaseHTTPRequestHandler , ThreadingHTTPServer
6- from ldm .dream .pngwriter import PngWriter
7+ from ldm .dream .pngwriter import PngWriter , PromptFormatter
78from threading import Event
89
10+ def build_opt (post_data , seed , gfpgan_model_exists ):
11+ opt = argparse .Namespace ()
12+ setattr (opt , 'prompt' , post_data ['prompt' ])
13+ setattr (opt , 'init_img' , post_data ['initimg' ])
14+ setattr (opt , 'strength' , float (post_data ['strength' ]))
15+ setattr (opt , 'iterations' , int (post_data ['iterations' ]))
16+ setattr (opt , 'steps' , int (post_data ['steps' ]))
17+ setattr (opt , 'width' , int (post_data ['width' ]))
18+ setattr (opt , 'height' , int (post_data ['height' ]))
19+ setattr (opt , 'seamless' , 'seamless' in post_data )
20+ setattr (opt , 'fit' , 'fit' in post_data )
21+ setattr (opt , 'mask' , 'mask' in post_data )
22+ setattr (opt , 'invert_mask' , 'invert_mask' in post_data )
23+ setattr (opt , 'cfg_scale' , float (post_data ['cfg_scale' ]))
24+ setattr (opt , 'sampler_name' , post_data ['sampler_name' ])
25+ setattr (opt , 'gfpgan_strength' , float (post_data ['gfpgan_strength' ]) if gfpgan_model_exists else 0 )
26+ setattr (opt , 'upscale' , [int (post_data ['upscale_level' ]), float (post_data ['upscale_strength' ])] if post_data ['upscale_level' ] != '' else None )
27+ setattr (opt , 'progress_images' , 'progress_images' in post_data )
28+ setattr (opt , 'seed' , seed if int (post_data ['seed' ]) == - 1 else int (post_data ['seed' ]))
29+ setattr (opt , 'variation_amount' , float (post_data ['variation_amount' ]) if int (post_data ['seed' ]) != - 1 else 0 )
30+ setattr (opt , 'with_variations' , [])
31+
32+ broken = False
33+ if int (post_data ['seed' ]) != - 1 and post_data ['with_variations' ] != '' :
34+ for part in post_data ['with_variations' ].split (',' ):
35+ seed_and_weight = part .split (':' )
36+ if len (seed_and_weight ) != 2 :
37+ print (f'could not parse with_variation part "{ part } "' )
38+ broken = True
39+ break
40+ try :
41+ seed = int (seed_and_weight [0 ])
42+ weight = float (seed_and_weight [1 ])
43+ except ValueError :
44+ print (f'could not parse with_variation part "{ part } "' )
45+ broken = True
46+ break
47+ opt .with_variations .append ([seed , weight ])
48+
49+ if broken :
50+ raise CanceledException
51+
52+ if len (opt .with_variations ) == 0 :
53+ opt .with_variations = None
54+
55+ return opt
56+
957class CanceledException (Exception ):
1058 pass
1159
@@ -81,57 +129,15 @@ def do_POST(self):
81129
82130 content_length = int (self .headers ['Content-Length' ])
83131 post_data = json .loads (self .rfile .read (content_length ))
84- prompt = post_data ['prompt' ]
85- initimg = post_data ['initimg' ]
86- strength = float (post_data ['strength' ])
87- iterations = int (post_data ['iterations' ])
88- steps = int (post_data ['steps' ])
89- width = int (post_data ['width' ])
90- height = int (post_data ['height' ])
91- fit = 'fit' in post_data
92- seamless = 'seamless' in post_data
93- cfgscale = float (post_data ['cfgscale' ])
94- sampler_name = post_data ['sampler' ]
95- variation_amount = float (post_data ['variation_amount' ])
96- with_variations = post_data ['with_variations' ]
97- gfpgan_strength = float (post_data ['gfpgan_strength' ]) if gfpgan_model_exists else 0
98- upscale_level = post_data ['upscale_level' ]
99- upscale_strength = post_data ['upscale_strength' ]
100- upscale = [int (upscale_level ),float (upscale_strength )] if upscale_level != '' else None
101- progress_images = 'progress_images' in post_data
102- seed = None if int (post_data ['seed' ]) == - 1 else int (post_data ['seed' ])
103-
104- if with_variations != '' :
105- parts = []
106- broken = False
107- for part in with_variations .split (',' ):
108- seed_and_weight = part .split (':' )
109- if len (seed_and_weight ) != 2 :
110- print (f'could not parse with_variation part "{ part } "' )
111- broken = True
112- break
113- try :
114- vseed = int (seed_and_weight [0 ])
115- vweight = float (seed_and_weight [1 ])
116- except ValueError :
117- print (f'could not parse with_variation part "{ part } "' )
118- broken = True
119- break
120- parts .append ([vseed , vweight ])
121- if broken :
122- raise CanceledException
123- if len (parts ) > 0 :
124- with_variations = parts
125- else :
126- with_variations = None
132+ opt = build_opt (post_data , self .model .seed , gfpgan_model_exists )
127133
128134 self .canceled .clear ()
129- print (f">> Request to generate with prompt: { prompt } " )
135+ print (f">> Request to generate with prompt: { opt . prompt } " )
130136 # In order to handle upscaled images, the PngWriter needs to maintain state
131137 # across images generated by each call to prompt2img(), so we define it in
132138 # the outer scope of image_done()
133139 config = post_data .copy () # Shallow copy
134- config ['initimg' ] = config .pop ('initimg_name' ,'' )
140+ config ['initimg' ] = config .pop ('initimg_name' , '' )
135141
136142 images_generated = 0 # helps keep track of when upscaling is started
137143 images_upscaled = 0 # helps keep track of when upscaling is completed
@@ -144,9 +150,21 @@ def do_POST(self):
144150 # entry should not be inserted into the image list.
145151 def image_done (image , seed , upscaled = False ):
146152 name = f'{ prefix } .{ seed } .png'
147- path = pngwriter .save_image_and_prompt_to_png (image , f'{ prompt } -S{ seed } ' , name )
148-
149- config ['seed' ] = seed
153+ iter_opt = argparse .Namespace (** vars (opt )) # copy
154+ if opt .variation_amount > 0 :
155+ this_variation = [[seed , opt .variation_amount ]]
156+ if opt .with_variations is None :
157+ iter_opt .with_variations = this_variation
158+ else :
159+ iter_opt .with_variations = opt .with_variations + this_variation
160+ iter_opt .variation_amount = 0
161+ elif opt .with_variations is None :
162+ iter_opt .seed = seed
163+ normalized_prompt = PromptFormatter (self .model , iter_opt ).normalize_prompt ()
164+ path = pngwriter .save_image_and_prompt_to_png (image , f'{ normalized_prompt } -S{ iter_opt .seed } ' , name )
165+
166+ if int (config ['seed' ]) == - 1 :
167+ config ['seed' ] = seed
150168 # Append post_data to log, but only once!
151169 if not upscaled :
152170 with open (os .path .join (self .outdir , "dream_web_log.txt" ), "a" ) as log :
@@ -157,24 +175,24 @@ def image_done(image, seed, upscaled=False):
157175 ) + '\n ' ,"utf-8" ))
158176
159177 # control state of the "postprocessing..." message
160- upscaling_requested = upscale or gfpgan_strength > 0
178+ upscaling_requested = opt . upscale or opt . gfpgan_strength > 0
161179 nonlocal images_generated # NB: Is this bad python style? It is typical usage in a perl closure.
162180 nonlocal images_upscaled # NB: Is this bad python style? It is typical usage in a perl closure.
163181 if upscaled :
164182 images_upscaled += 1
165183 else :
166- images_generated += 1
184+ images_generated += 1
167185 if upscaling_requested :
168186 action = None
169- if images_generated >= iterations :
170- if images_upscaled < iterations :
187+ if images_generated >= opt . iterations :
188+ if images_upscaled < opt . iterations :
171189 action = 'upscaling-started'
172190 else :
173191 action = 'upscaling-done'
174192 if action :
175- x = images_upscaled + 1
193+ x = images_upscaled + 1
176194 self .wfile .write (bytes (json .dumps (
177- {'event' :action ,'processed_file_cnt' :f'{ x } /{ iterations } ' }
195+ {'event' : action , 'processed_file_cnt' : f'{ x } /{ opt . iterations } ' }
178196 ) + '\n ' ,"utf-8" ))
179197
180198 step_writer = PngWriter (os .path .join (self .outdir , "intermediates" ))
@@ -187,60 +205,31 @@ def image_progress(sample, step):
187205 # since rendering images is moderately expensive, only render every 5th image
188206 # and don't bother with the last one, since it'll render anyway
189207 nonlocal step_index
190- if progress_images and step % 5 == 0 and step < steps - 1 :
208+ if opt . progress_images and step % 5 == 0 and step < opt . steps - 1 :
191209 image = self .model .sample_to_image (sample )
192- name = f'{ prefix } .{ seed } .{ step_index } .png'
193- metadata = f'{ prompt } -S{ seed } [intermediate]'
210+ name = f'{ prefix } .{ opt . seed } .{ step_index } .png'
211+ metadata = f'{ opt . prompt } -S{ opt . seed } [intermediate]'
194212 path = step_writer .save_image_and_prompt_to_png (image , metadata , name )
195213 step_index += 1
196214 self .wfile .write (bytes (json .dumps (
197215 {'event' : 'step' , 'step' : step + 1 , 'url' : path }
198216 ) + '\n ' ,"utf-8" ))
199217
200218 try :
201- if initimg is None :
219+ if opt . init_img is None :
202220 # Run txt2img
203- self .model .prompt2image (prompt ,
204- iterations = iterations ,
205- cfg_scale = cfgscale ,
206- width = width ,
207- height = height ,
208- seed = seed ,
209- steps = steps ,
210- variation_amount = variation_amount ,
211- with_variations = with_variations ,
212- gfpgan_strength = gfpgan_strength ,
213- upscale = upscale ,
214- sampler_name = sampler_name ,
215- seamless = seamless ,
216- step_callback = image_progress ,
217- image_callback = image_done )
221+ self .model .prompt2image (** vars (opt ), step_callback = image_progress , image_callback = image_done )
218222 else :
219223 # Decode initimg as base64 to temp file
220224 with open ("./img2img-tmp.png" , "wb" ) as f :
221- initimg = initimg .split ("," )[1 ] # Ignore mime type
225+ initimg = opt . init_img .split ("," )[1 ] # Ignore mime type
222226 f .write (base64 .b64decode (initimg ))
227+ opt1 = argparse .Namespace (** vars (opt ))
228+ opt1 .init_img = "./img2img-tmp.png"
223229
224230 try :
225231 # Run img2img
226- self .model .prompt2image (prompt ,
227- init_img = "./img2img-tmp.png" ,
228- strength = strength ,
229- iterations = iterations ,
230- cfg_scale = cfgscale ,
231- seed = seed ,
232- steps = steps ,
233- variation_amount = variation_amount ,
234- with_variations = with_variations ,
235- sampler_name = sampler_name ,
236- width = width ,
237- height = height ,
238- fit = fit ,
239- seamless = seamless ,
240- gfpgan_strength = gfpgan_strength ,
241- upscale = upscale ,
242- step_callback = image_progress ,
243- image_callback = image_done )
232+ self .model .prompt2image (** vars (opt1 ), step_callback = image_progress , image_callback = image_done )
244233 finally :
245234 # Remove the temp file
246235 os .remove ("./img2img-tmp.png" )
0 commit comments