lunarring commited on
Commit
22d942d
·
1 Parent(s): d8439d3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +406 -23
app.py CHANGED
@@ -1,26 +1,409 @@
1
- import random
2
- import tempfile
3
- import time
4
- import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  import numpy as np
 
 
 
6
  import torch
7
- import math
8
- import re
9
-
10
- from gradio import inputs
11
- from diffusers import (
12
- AutoencoderKL,
13
- DDIMScheduler,
14
- UNet2DConditionModel,
15
- )
16
- from modules.model import (
17
- CrossAttnProcessor,
18
- StableDiffusionPipeline,
19
- )
20
- from torchvision import transforms
21
- from transformers import CLIPTokenizer, CLIPTextModel
22
  from PIL import Image
23
- from pathlib import Path
24
- from safetensors.torch import load_file
25
- import modules.safe as _
26
- from modules.lora import LoRANetwork
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import hf_hub_download
2
+ hf_hub_download(repo_id="stabilityai/stable-diffusion-2-1-base", filename="v2-1_512-ema-pruned.ckpt")
3
+
4
+ # Copyright 2022 Lunar Ring. All rights reserved.
5
+ # Written by Johannes Stelzer, email [email protected] twitter @j_stelzer
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ import os, sys
20
+ import torch
21
+ torch.backends.cudnn.benchmark = False
22
  import numpy as np
23
+ import warnings
24
+ warnings.filterwarnings('ignore')
25
+ import warnings
26
  import torch
27
+ from tqdm.auto import tqdm
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  from PIL import Image
29
+ import torch
30
+ from movie_util import MovieSaver, concatenate_movies
31
+ from typing import Callable, List, Optional, Union
32
+ from latent_blending import get_time, yml_save, LatentBlending, add_frames_linear_interp, compare_dicts
33
+ from stable_diffusion_holder import StableDiffusionHolder
34
+ torch.set_grad_enabled(False)
35
+ import gradio as gr
36
+ import copy
37
+ from dotenv import find_dotenv, load_dotenv
38
+ import shutil
39
+
40
+ """
41
+ never hit compute trans -> multi movie add fail
42
+
43
+ """
44
+
45
+
46
+ #%%
47
+
48
+ class BlendingFrontend():
49
+ def __init__(self, sdh=None):
50
+ self.num_inference_steps = 30
51
+ if sdh is None:
52
+ self.use_debug = True
53
+ self.height = 768
54
+ self.width = 768
55
+ else:
56
+ self.use_debug = False
57
+ self.lb = LatentBlending(sdh)
58
+ self.lb.sdh.num_inference_steps = self.num_inference_steps
59
+ self.height = self.lb.sdh.height
60
+ self.width = self.lb.sdh.width
61
+
62
+ self.init_save_dir()
63
+ self.save_empty_image()
64
+ self.share = True
65
+ self.transition_can_be_computed = False
66
+ self.depth_strength = 0.25
67
+ self.seed1 = 420
68
+ self.seed2 = 420
69
+ self.guidance_scale = 4.0
70
+ self.guidance_scale_mid_damper = 0.5
71
+ self.mid_compression_scaler = 1.2
72
+ self.prompt1 = ""
73
+ self.prompt2 = ""
74
+ self.negative_prompt = ""
75
+ self.state_current = {}
76
+ self.branch1_crossfeed_power = self.lb.branch1_crossfeed_power
77
+ self.branch1_crossfeed_range = self.lb.branch1_crossfeed_range
78
+ self.branch1_crossfeed_decay = self.lb.branch1_crossfeed_decay
79
+ self.parental_crossfeed_power = self.lb.parental_crossfeed_power
80
+ self.parental_crossfeed_range = self.lb.parental_crossfeed_range
81
+ self.parental_crossfeed_power_decay = self.lb.parental_crossfeed_power_decay
82
+ self.fps = 30
83
+ self.duration_video = 10
84
+ self.t_compute_max_allowed = 10
85
+ self.list_fp_imgs_current = []
86
+ self.current_timestamp = None
87
+ self.recycle_img1 = False
88
+ self.recycle_img2 = False
89
+ self.fp_img1 = None
90
+ self.fp_img2 = None
91
+ self.multi_idx_current = -1
92
+ self.list_imgs_shown_last = 5*[self.fp_img_empty]
93
+ self.list_all_segments = []
94
+ self.dp_session = ""
95
+
96
+
97
+ def init_save_dir(self):
98
+ load_dotenv(find_dotenv(), verbose=False)
99
+ self.dp_out = os.getenv("DIR_OUT")
100
+ if self.dp_out is None:
101
+ self.dp_out = ""
102
+ self.dp_imgs = os.path.join(self.dp_out, "imgs")
103
+ os.makedirs(self.dp_imgs, exist_ok=True)
104
+ self.dp_movies = os.path.join(self.dp_out, "movies")
105
+ os.makedirs(self.dp_movies, exist_ok=True)
106
+
107
+
108
+ # make dummy image
109
+ def save_empty_image(self):
110
+ self.fp_img_empty = os.path.join(self.dp_imgs, 'empty.jpg')
111
+ Image.fromarray(np.zeros((self.height, self.width, 3), dtype=np.uint8)).save(self.fp_img_empty, quality=5)
112
+
113
+
114
+ def randomize_seed1(self):
115
+ # Dont randomize seed if we are in a multi concat mode. we don't want to change this one otherwise the movie breaks
116
+ if len(self.list_all_segments) > 0:
117
+ seed = self.seed1
118
+ else:
119
+ seed = np.random.randint(0, 10000000)
120
+ self.seed1 = int(seed)
121
+ print(f"randomize_seed1: new seed = {self.seed1}")
122
+ return seed
123
+
124
+ def randomize_seed2(self):
125
+ seed = np.random.randint(0, 10000000)
126
+ self.seed2 = int(seed)
127
+ print(f"randomize_seed2: new seed = {self.seed2}")
128
+ return seed
129
+
130
+
131
+ def setup_lb(self, list_ui_elem):
132
+ # Collect latent blending variables
133
+ self.state_current = self.get_state_dict()
134
+ self.lb.set_width(list_ui_elem[list_ui_keys.index('width')])
135
+ self.lb.set_height(list_ui_elem[list_ui_keys.index('height')])
136
+ self.lb.set_prompt1(list_ui_elem[list_ui_keys.index('prompt1')])
137
+ self.lb.set_prompt2(list_ui_elem[list_ui_keys.index('prompt2')])
138
+ self.lb.set_negative_prompt(list_ui_elem[list_ui_keys.index('negative_prompt')])
139
+ self.lb.guidance_scale = list_ui_elem[list_ui_keys.index('guidance_scale')]
140
+ self.lb.guidance_scale_mid_damper = list_ui_elem[list_ui_keys.index('guidance_scale_mid_damper')]
141
+ self.t_compute_max_allowed = list_ui_elem[list_ui_keys.index('duration_compute')]
142
+ self.lb.num_inference_steps = list_ui_elem[list_ui_keys.index('num_inference_steps')]
143
+ self.lb.sdh.num_inference_steps = list_ui_elem[list_ui_keys.index('num_inference_steps')]
144
+ self.duration_video = list_ui_elem[list_ui_keys.index('duration_video')]
145
+ self.lb.seed1 = list_ui_elem[list_ui_keys.index('seed1')] #seed
146
+ self.lb.seed2 = list_ui_elem[list_ui_keys.index('seed2')]
147
+
148
+ self.lb.branch1_crossfeed_power = list_ui_elem[list_ui_keys.index('branch1_crossfeed_power')]
149
+ self.lb.branch1_crossfeed_range = list_ui_elem[list_ui_keys.index('branch1_crossfeed_range')]
150
+ self.lb.branch1_crossfeed_decay = list_ui_elem[list_ui_keys.index('branch1_crossfeed_decay')]
151
+ self.lb.parental_crossfeed_power = list_ui_elem[list_ui_keys.index('parental_crossfeed_power')]
152
+ self.lb.parental_crossfeed_range = list_ui_elem[list_ui_keys.index('parental_crossfeed_range')]
153
+ self.lb.parental_crossfeed_power_decay = list_ui_elem[list_ui_keys.index('parental_crossfeed_power_decay')]
154
+ self.num_inference_steps = list_ui_elem[list_ui_keys.index('num_inference_steps')]
155
+ self.depth_strength = list_ui_elem[list_ui_keys.index('depth_strength')]
156
+
157
+
158
+ def compute_img1(self, *args):
159
+ list_ui_elem = args
160
+ self.setup_lb(list_ui_elem)
161
+ self.fp_img1 = os.path.join(self.dp_imgs, f"img1_{get_time('second')}.jpg")
162
+ img1 = Image.fromarray(self.lb.compute_latents1(return_image=True))
163
+ img1.save(self.fp_img1)
164
+ self.recycle_img1 = True
165
+ self.recycle_img2 = False
166
+ return [self.fp_img1, self.fp_img_empty, self.fp_img_empty, self.fp_img_empty, self.fp_img_empty]
167
+
168
+ def compute_img2(self, *args):
169
+ if self.fp_img1 is None: # don't do anything
170
+ return [self.fp_img_empty, self.fp_img_empty, self.fp_img_empty, self.fp_img_empty]
171
+ list_ui_elem = args
172
+ self.setup_lb(list_ui_elem)
173
+ self.fp_img2 = os.path.join(self.dp_imgs, f"img2_{get_time('second')}.jpg")
174
+ img2 = Image.fromarray(self.lb.compute_latents2(return_image=True))
175
+ img2.save(self.fp_img2)
176
+ self.recycle_img2 = True
177
+ self.transition_can_be_computed = True
178
+ return [self.fp_img_empty, self.fp_img_empty, self.fp_img_empty, self.fp_img2]
179
+
180
+ def compute_transition(self, *args):
181
+
182
+ if not self.transition_can_be_computed:
183
+ list_return = [self.fp_img_empty, self.fp_img_empty, self.fp_img_empty, self.fp_img_empty]
184
+ return list_return
185
+
186
+ list_ui_elem = args
187
+ self.setup_lb(list_ui_elem)
188
+ print("STARTING TRANSITION...")
189
+ if self.use_debug:
190
+ list_imgs = [(255*np.random.rand(self.height,self.width,3)).astype(np.uint8) for l in range(5)]
191
+ list_imgs = [Image.fromarray(l) for l in list_imgs]
192
+ print("DONE! SENDING BACK RESULTS")
193
+ return list_imgs
194
+
195
+ fixed_seeds = [self.seed1, self.seed2]
196
+
197
+ # Run Latent Blending
198
+ imgs_transition = self.lb.run_transition(
199
+ recycle_img1=self.recycle_img1,
200
+ recycle_img2=self.recycle_img2,
201
+ num_inference_steps=self.num_inference_steps,
202
+ depth_strength=self.depth_strength,
203
+ t_compute_max_allowed=self.t_compute_max_allowed,
204
+ fixed_seeds=fixed_seeds
205
+ )
206
+ print(f"Latent Blending pass finished. Resulted in {len(imgs_transition)} images")
207
+
208
+ # Subselect three preview images
209
+ idx_img_prev = np.round(np.linspace(0, len(imgs_transition)-1, 5)[1:-1]).astype(np.int32)
210
+ list_imgs_preview = []
211
+ for j in idx_img_prev:
212
+ list_imgs_preview.append(Image.fromarray(imgs_transition[j]))
213
+
214
+ # Save the preview imgs as jpgs on disk so we are not sending umcompressed data around
215
+ self.current_timestamp = get_time('second')
216
+ self.list_fp_imgs_current = []
217
+ for i in range(len(list_imgs_preview)):
218
+ fp_img = os.path.join(self.dp_imgs, f"img_preview_{i}_{self.current_timestamp}.jpg")
219
+ list_imgs_preview[i].save(fp_img)
220
+ self.list_fp_imgs_current.append(fp_img)
221
+
222
+ # Insert cheap frames for the movie
223
+ imgs_transition_ext = add_frames_linear_interp(imgs_transition, self.duration_video, self.fps)
224
+
225
+ # Save as movie
226
+ self.fp_movie = os.path.join(self.dp_movies, f"movie_{self.current_timestamp}.mp4")
227
+ if os.path.isfile(self.fp_movie):
228
+ os.remove(self.fp_movie)
229
+ ms = MovieSaver(self.fp_movie, fps=self.fps)
230
+ for img in tqdm(imgs_transition_ext):
231
+ ms.write_frame(img)
232
+ ms.finalize()
233
+ print("DONE SAVING MOVIE! SENDING BACK...")
234
+
235
+ # Assemble Output, updating the preview images and le movie
236
+ list_return = self.list_fp_imgs_current + [self.fp_movie]
237
+ return list_return
238
+
239
+
240
+ def stack_forward(self, prompt2, seed2):
241
+ # Save preview images, prompts and seeds into dictionary for stacking
242
+ if len(self.list_all_segments) == 0:
243
+ timestamp_session = get_time('second')
244
+ self.dp_session = os.path.join(self.dp_out, f"session_{timestamp_session}")
245
+ os.makedirs(self.dp_session)
246
+
247
+ self.transition_can_be_computed = False
248
+
249
+ idx_segment = len(self.list_all_segments)
250
+ dp_segment = os.path.join(self.dp_session, f"segment_{str(idx_segment).zfill(3)}")
251
+
252
+ self.list_all_segments.append(dp_segment)
253
+ self.lb.write_imgs_transition(dp_segment)
254
+ shutil.copyfile(self.fp_movie, os.path.join(dp_segment, "movie.mp4"))
255
+
256
+ self.lb.swap_forward()
257
+ fp_multi = self.multi_concat()
258
+ list_out = [fp_multi]
259
+ list_out.extend([self.fp_img2])
260
+ list_out.extend([self.fp_img_empty]*4)
261
+ list_out.append(gr.update(interactive=False, value=prompt2))
262
+ list_out.append(gr.update(interactive=False, value=seed2))
263
+ list_out.append("")
264
+ list_out.append(np.random.randint(0, 10000000))
265
+ print(f"stack_forward: fp_multi {fp_multi}")
266
+ return list_out
267
+
268
+
269
+ def multi_concat(self):
270
+ list_fp_movies = []
271
+ for dp_segment in self.list_all_segments:
272
+ list_fp_movies.append(os.path.join(dp_segment, "movie.mp4"))
273
+
274
+ # Concatenate movies and save
275
+ fp_final = os.path.join(self.dp_session, "movie.mp4")
276
+ concatenate_movies(fp_final, list_fp_movies)
277
+ return fp_final
278
+
279
+ def get_state_dict(self):
280
+ state_dict = {}
281
+ grab_vars = ['prompt1', 'prompt2', 'seed1', 'seed2', 'height', 'width',
282
+ 'num_inference_steps', 'depth_strength', 'guidance_scale',
283
+ 'guidance_scale_mid_damper', 'mid_compression_scaler']
284
+
285
+ for v in grab_vars:
286
+ state_dict[v] = getattr(self, v)
287
+ return state_dict
288
+
289
+
290
+
291
+ if __name__ == "__main__":
292
+
293
+ # fp_ckpt = "../stable_diffusion_models/ckpt/v2-1_768-ema-pruned.ckpt"
294
+ fp_ckpt = "v2-1_512-ema-pruned.ckpt"
295
+ bf = BlendingFrontend(StableDiffusionHolder(fp_ckpt))
296
+ # self = BlendingFrontend(None)
297
+
298
+ with gr.Blocks() as demo:
299
+ with gr.Tab("Single Transition"):
300
+ with gr.Row():
301
+ prompt1 = gr.Textbox(label="prompt 1")
302
+ prompt2 = gr.Textbox(label="prompt 2")
303
+
304
+ with gr.Row():
305
+ duration_compute = gr.Slider(5, 200, bf.t_compute_max_allowed, step=1, label='compute budget for transition (seconds)', interactive=True)
306
+ duration_video = gr.Slider(1, 100, bf.duration_video, step=0.1, label='result video duration (seconds)', interactive=True)
307
+ height = gr.Slider(256, 2048, bf.height, step=128, label='height', interactive=True)
308
+ width = gr.Slider(256, 2048, bf.width, step=128, label='width', interactive=True)
309
+
310
+ with gr.Accordion("Advanced Settings (click to expand)", open=False):
311
+
312
+ with gr.Accordion("Diffusion settings", open=True):
313
+ with gr.Row():
314
+ num_inference_steps = gr.Slider(5, 100, bf.num_inference_steps, step=1, label='num_inference_steps', interactive=True)
315
+ guidance_scale = gr.Slider(1, 25, bf.guidance_scale, step=0.1, label='guidance_scale', interactive=True)
316
+ negative_prompt = gr.Textbox(label="negative prompt")
317
+
318
+ with gr.Accordion("Seed control: adjust seeds for first and last images", open=True):
319
+ with gr.Row():
320
+ b_newseed1 = gr.Button("randomize seed 1", variant='secondary')
321
+ seed1 = gr.Number(bf.seed1, label="seed 1", interactive=True)
322
+ seed2 = gr.Number(bf.seed2, label="seed 2", interactive=True)
323
+ b_newseed2 = gr.Button("randomize seed 2", variant='secondary')
324
+
325
+ with gr.Accordion("Last image crossfeeding.", open=True):
326
+ with gr.Row():
327
+ branch1_crossfeed_power = gr.Slider(0.0, 1.0, bf.branch1_crossfeed_power, step=0.01, label='branch1 crossfeed power', interactive=True)
328
+ branch1_crossfeed_range = gr.Slider(0.0, 1.0, bf.branch1_crossfeed_range, step=0.01, label='branch1 crossfeed range', interactive=True)
329
+ branch1_crossfeed_decay = gr.Slider(0.0, 1.0, bf.branch1_crossfeed_decay, step=0.01, label='branch1 crossfeed decay', interactive=True)
330
+
331
+ with gr.Accordion("Transition settings", open=True):
332
+ with gr.Row():
333
+ parental_crossfeed_power = gr.Slider(0.0, 1.0, bf.parental_crossfeed_power, step=0.01, label='parental crossfeed power', interactive=True)
334
+ parental_crossfeed_range = gr.Slider(0.0, 1.0, bf.parental_crossfeed_range, step=0.01, label='parental crossfeed range', interactive=True)
335
+ parental_crossfeed_power_decay = gr.Slider(0.0, 1.0, bf.parental_crossfeed_power_decay, step=0.01, label='parental crossfeed decay', interactive=True)
336
+ with gr.Row():
337
+ depth_strength = gr.Slider(0.01, 0.99, bf.depth_strength, step=0.01, label='depth_strength', interactive=True)
338
+ guidance_scale_mid_damper = gr.Slider(0.01, 2.0, bf.guidance_scale_mid_damper, step=0.01, label='guidance_scale_mid_damper', interactive=True)
339
+
340
+
341
+ with gr.Row():
342
+ b_compute1 = gr.Button('compute first image', variant='primary')
343
+ b_compute_transition = gr.Button('compute transition', variant='primary')
344
+ b_compute2 = gr.Button('compute last image', variant='primary')
345
+
346
+ with gr.Row():
347
+ img1 = gr.Image(label="1/5")
348
+ img2 = gr.Image(label="2/5", show_progress=False)
349
+ img3 = gr.Image(label="3/5", show_progress=False)
350
+ img4 = gr.Image(label="4/5", show_progress=False)
351
+ img5 = gr.Image(label="5/5")
352
+
353
+ with gr.Row():
354
+ vid_single = gr.Video(label="single trans")
355
+ vid_multi = gr.Video(label="multi trans")
356
+
357
+ with gr.Row():
358
+ # b_restart = gr.Button("RESTART EVERYTHING")
359
+ b_stackforward = gr.Button('append last movie segment (left) to multi movie (right)', variant='primary')
360
+
361
+
362
+ # Collect all UI elemts in list to easily pass as inputs in gradio
363
+ dict_ui_elem = {}
364
+ dict_ui_elem["prompt1"] = prompt1
365
+ dict_ui_elem["negative_prompt"] = negative_prompt
366
+ dict_ui_elem["prompt2"] = prompt2
367
+
368
+ dict_ui_elem["duration_compute"] = duration_compute
369
+ dict_ui_elem["duration_video"] = duration_video
370
+ dict_ui_elem["height"] = height
371
+ dict_ui_elem["width"] = width
372
+
373
+ dict_ui_elem["depth_strength"] = depth_strength
374
+ dict_ui_elem["branch1_crossfeed_power"] = branch1_crossfeed_power
375
+ dict_ui_elem["branch1_crossfeed_range"] = branch1_crossfeed_range
376
+ dict_ui_elem["branch1_crossfeed_decay"] = branch1_crossfeed_decay
377
+
378
+ dict_ui_elem["num_inference_steps"] = num_inference_steps
379
+ dict_ui_elem["guidance_scale"] = guidance_scale
380
+ dict_ui_elem["guidance_scale_mid_damper"] = guidance_scale_mid_damper
381
+ dict_ui_elem["seed1"] = seed1
382
+ dict_ui_elem["seed2"] = seed2
383
+
384
+ dict_ui_elem["parental_crossfeed_range"] = parental_crossfeed_range
385
+ dict_ui_elem["parental_crossfeed_power"] = parental_crossfeed_power
386
+ dict_ui_elem["parental_crossfeed_power_decay"] = parental_crossfeed_power_decay
387
+
388
+ # Convert to list, as gradio doesn't seem to accept dicts
389
+ list_ui_elem = []
390
+ list_ui_keys = []
391
+ for k in dict_ui_elem.keys():
392
+ list_ui_elem.append(dict_ui_elem[k])
393
+ list_ui_keys.append(k)
394
+ bf.list_ui_keys = list_ui_keys
395
+
396
+ b_newseed1.click(bf.randomize_seed1, outputs=seed1)
397
+ b_newseed2.click(bf.randomize_seed2, outputs=seed2)
398
+ b_compute1.click(bf.compute_img1, inputs=list_ui_elem, outputs=[img1, img2, img3, img4, img5])
399
+ b_compute2.click(bf.compute_img2, inputs=list_ui_elem, outputs=[img2, img3, img4, img5])
400
+ b_compute_transition.click(bf.compute_transition,
401
+ inputs=list_ui_elem,
402
+ outputs=[img2, img3, img4, vid_single])
403
+
404
+ b_stackforward.click(bf.stack_forward,
405
+ inputs=[prompt2, seed2],
406
+ outputs=[vid_multi, img1, img2, img3, img4, img5, prompt1, seed1, prompt2])
407
+
408
+
409
+ demo.launch(share=bf.share, inbrowser=True, inline=False)