tianleliphoebe commited on
Commit
26dad4e
1 Parent(s): 3efdac8

update video generation

Browse files
model/model_manager.py CHANGED
@@ -37,7 +37,7 @@ class ModelManager:
37
  results = []
38
  with concurrent.futures.ThreadPoolExecutor() as executor:
39
  future_to_result = {executor.submit(self.generate_image_ig, prompt, model): model for model in model_names}
40
- for future in concurrent.futures.as_completed(future_to_result):
41
  result = future.result()
42
  results.append(result)
43
  return results[0], results[1], model_names[0], model_names[1]
@@ -47,7 +47,7 @@ class ModelManager:
47
  model_names = [model_A, model_B]
48
  with concurrent.futures.ThreadPoolExecutor() as executor:
49
  future_to_result = {executor.submit(self.generate_image_ig, prompt, model): model for model in model_names}
50
- for future in concurrent.futures.as_completed(future_to_result):
51
  result = future.result()
52
  results.append(result)
53
  return results[0], results[1]
@@ -63,7 +63,7 @@ class ModelManager:
63
  model_names = [model_A, model_B]
64
  with concurrent.futures.ThreadPoolExecutor() as executor:
65
  future_to_result = {executor.submit(self.generate_image_ie, textbox_source, textbox_target, textbox_instruct, source_image, model): model for model in model_names}
66
- for future in concurrent.futures.as_completed(future_to_result):
67
  result = future.result()
68
  results.append(result)
69
  return results[0], results[1]
@@ -77,7 +77,7 @@ class ModelManager:
77
  # model_names = [model_A, model_B]
78
  with concurrent.futures.ThreadPoolExecutor() as executor:
79
  future_to_result = {executor.submit(self.generate_image_ie, textbox_source, textbox_target, textbox_instruct, source_image, model): model for model in model_names}
80
- for future in concurrent.futures.as_completed(future_to_result):
81
  result = future.result()
82
  results.append(result)
83
  return results[0], results[1], model_names[0], model_names[1]
@@ -97,7 +97,7 @@ class ModelManager:
97
  results = []
98
  with concurrent.futures.ThreadPoolExecutor() as executor:
99
  future_to_result = {executor.submit(self.generate_video_vg, prompt, model): model for model in model_names}
100
- for future in concurrent.futures.as_completed(future_to_result):
101
  result = future.result()
102
  results.append(result)
103
  return results[0], results[1], model_names[0], model_names[1]
@@ -107,7 +107,7 @@ class ModelManager:
107
  model_names = [model_A, model_B]
108
  with concurrent.futures.ThreadPoolExecutor() as executor:
109
  future_to_result = {executor.submit(self.generate_video_vg, prompt, model): model for model in model_names}
110
- for future in concurrent.futures.as_completed(future_to_result):
111
  result = future.result()
112
  results.append(result)
113
  return results[0], results[1]
 
37
  results = []
38
  with concurrent.futures.ThreadPoolExecutor() as executor:
39
  future_to_result = {executor.submit(self.generate_image_ig, prompt, model): model for model in model_names}
40
+ for future in future_to_result:
41
  result = future.result()
42
  results.append(result)
43
  return results[0], results[1], model_names[0], model_names[1]
 
47
  model_names = [model_A, model_B]
48
  with concurrent.futures.ThreadPoolExecutor() as executor:
49
  future_to_result = {executor.submit(self.generate_image_ig, prompt, model): model for model in model_names}
50
+ for future in future_to_result:
51
  result = future.result()
52
  results.append(result)
53
  return results[0], results[1]
 
63
  model_names = [model_A, model_B]
64
  with concurrent.futures.ThreadPoolExecutor() as executor:
65
  future_to_result = {executor.submit(self.generate_image_ie, textbox_source, textbox_target, textbox_instruct, source_image, model): model for model in model_names}
66
+ for future in future_to_result:
67
  result = future.result()
68
  results.append(result)
69
  return results[0], results[1]
 
77
  # model_names = [model_A, model_B]
78
  with concurrent.futures.ThreadPoolExecutor() as executor:
79
  future_to_result = {executor.submit(self.generate_image_ie, textbox_source, textbox_target, textbox_instruct, source_image, model): model for model in model_names}
80
+ for future in future_to_result:
81
  result = future.result()
82
  results.append(result)
83
  return results[0], results[1], model_names[0], model_names[1]
 
97
  results = []
98
  with concurrent.futures.ThreadPoolExecutor() as executor:
99
  future_to_result = {executor.submit(self.generate_video_vg, prompt, model): model for model in model_names}
100
+ for future in future_to_result:
101
  result = future.result()
102
  results.append(result)
103
  return results[0], results[1], model_names[0], model_names[1]
 
107
  model_names = [model_A, model_B]
108
  with concurrent.futures.ThreadPoolExecutor() as executor:
109
  future_to_result = {executor.submit(self.generate_video_vg, prompt, model): model for model in model_names}
110
+ for future in future_to_result:
111
  result = future.result()
112
  results.append(result)
113
  return results[0], results[1]
model/model_registry.py CHANGED
@@ -166,18 +166,39 @@ register_model_info(
166
  )
167
 
168
  register_model_info(
169
- ["fal_fast-animatediff/text-to-video_text2video"],
170
  "AnimateDiff",
171
  "https://fal.ai/models/fast-animatediff-t2v",
172
  "AnimateDiff is a text-driven models that produce diverse and personalized animated images.",
173
  )
174
 
175
  register_model_info(
176
- ["fal_fast-animatediff/turbo/text-to-video_text2video"],
177
  "AnimateDiff Turbo",
178
  "https://fal.ai/models/fast-animatediff-t2v-turbo",
179
  "AnimateDiff Turbo is a lightning version of AnimateDiff.",
180
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
 
182
 
183
  models = ['imagenhub_LCM_generation','imagenhub_SDXLTurbo_generation','imagenhub_SDXL_generation',
@@ -185,4 +206,5 @@ models = ['imagenhub_LCM_generation','imagenhub_SDXLTurbo_generation','imagenhub
185
  'imagenhub_StableCascade_generation','imagenhub_PlaygroundV2_generation', 'fal_Playground-v25_generation', 'fal_stable-cascade_text2image',
186
  'imagenhub_CycleDiffusion_edition', 'imagenhub_Pix2PixZero_edition', 'imagenhub_Prompt2prompt_edition',
187
  'imagenhub_SDEdit_edition', 'imagenhub_InstructPix2Pix_edition', 'imagenhub_MagicBrush_edition', 'imagenhub_PNP_edition'
188
- "fal_fast-animatediff/turbo/text-to-video_text2video", "fal_fast-animatediff/text-to-video_text2video"]
 
 
166
  )
167
 
168
  register_model_info(
169
+ ["fal_AnimateDiff_text2video"],
170
  "AnimateDiff",
171
  "https://fal.ai/models/fast-animatediff-t2v",
172
  "AnimateDiff is a text-driven models that produce diverse and personalized animated images.",
173
  )
174
 
175
  register_model_info(
176
+ ["fal_AnimateDiffTurbo_text2video"],
177
  "AnimateDiff Turbo",
178
  "https://fal.ai/models/fast-animatediff-t2v-turbo",
179
  "AnimateDiff Turbo is a lightning version of AnimateDiff.",
180
  )
181
+
182
+ register_model_info(
183
+ ["videogenhub_LaVie_generation"],
184
+ "LaVie",
185
+ "https://github.com/Vchitect/LaVie",
186
+ "LaVie is a video generation model with cascaded latent diffusion models.",
187
+ )
188
+
189
+ register_model_info(
190
+ ["videogenhub_VideoCrafter2_generation"],
191
+ "VideoCrafter2",
192
+ "https://ailab-cvc.github.io/videocrafter2/",
193
+ "VideoCrafter2 is a T2V model that disentangling motion from appearance.",
194
+ )
195
+
196
+ register_model_info(
197
+ ["videogenhub_ModelScope_generation"],
198
+ "ModelScope",
199
+ "https://arxiv.org/abs/2308.06571",
200
+ "ModelScope is a a T2V synthesis model that evolves from a T2I synthesis model.",
201
+ )
202
 
203
 
204
  models = ['imagenhub_LCM_generation','imagenhub_SDXLTurbo_generation','imagenhub_SDXL_generation',
 
206
  'imagenhub_StableCascade_generation','imagenhub_PlaygroundV2_generation', 'fal_Playground-v25_generation', 'fal_stable-cascade_text2image',
207
  'imagenhub_CycleDiffusion_edition', 'imagenhub_Pix2PixZero_edition', 'imagenhub_Prompt2prompt_edition',
208
  'imagenhub_SDEdit_edition', 'imagenhub_InstructPix2Pix_edition', 'imagenhub_MagicBrush_edition', 'imagenhub_PNP_edition'
209
+ "fal_AnimateDiffTurbo_text2video", "fal_AnimateDiff_text2video",
210
+ "videogenhub_LaVie_generation", "videogenhub_VideoCrafter2_generation", "videogenhub_ModelScope_generation"]
model/models/__init__.py CHANGED
@@ -1,14 +1,17 @@
1
  from .imagenhub_models import load_imagenhub_model
2
  from .playground_api import load_playground_model
3
  from .fal_api_models import load_fal_model
 
4
 
5
  IMAGE_GENERATION_MODELS = ['imagenhub_LCM_generation','imagenhub_SDXLTurbo_generation','imagenhub_SDXL_generation', 'imagenhub_PixArtAlpha_generation',
6
  'imagenhub_OpenJourney_generation','imagenhub_SDXLLightning_generation', 'imagenhub_StableCascade_generation',
7
  'playground_PlayGroundV2_generation', 'playground_PlayGroundV2.5_generation']
8
  IMAGE_EDITION_MODELS = ['imagenhub_CycleDiffusion_edition', 'imagenhub_Pix2PixZero_edition', 'imagenhub_Prompt2prompt_edition',
9
  'imagenhub_SDEdit_edition', 'imagenhub_InstructPix2Pix_edition', 'imagenhub_MagicBrush_edition', 'imagenhub_PNP_edition']
10
- VIDEO_GENERATION_MODELS = ['fal_fast-animatediff/text-to-video_text2video',
11
- 'fal_fast-animatediff/turbo/text-to-video_text2video']
 
 
12
 
13
 
14
  def load_pipeline(model_name):
@@ -27,6 +30,8 @@ def load_pipeline(model_name):
27
  pipe = load_playground_model(model_name)
28
  elif model_source == "fal":
29
  pipe = load_fal_model(model_name, model_type)
 
 
30
  else:
31
  raise ValueError(f"Model source {model_source} not supported")
32
  return pipe
 
1
  from .imagenhub_models import load_imagenhub_model
2
  from .playground_api import load_playground_model
3
  from .fal_api_models import load_fal_model
4
+ from .videogenhub_models import load_videogenhub_model
5
 
6
  IMAGE_GENERATION_MODELS = ['imagenhub_LCM_generation','imagenhub_SDXLTurbo_generation','imagenhub_SDXL_generation', 'imagenhub_PixArtAlpha_generation',
7
  'imagenhub_OpenJourney_generation','imagenhub_SDXLLightning_generation', 'imagenhub_StableCascade_generation',
8
  'playground_PlayGroundV2_generation', 'playground_PlayGroundV2.5_generation']
9
  IMAGE_EDITION_MODELS = ['imagenhub_CycleDiffusion_edition', 'imagenhub_Pix2PixZero_edition', 'imagenhub_Prompt2prompt_edition',
10
  'imagenhub_SDEdit_edition', 'imagenhub_InstructPix2Pix_edition', 'imagenhub_MagicBrush_edition', 'imagenhub_PNP_edition']
11
+ VIDEO_GENERATION_MODELS = ['fal_AnimateDiff_text2video',
12
+ 'fal_AnimateDiffTurbo_text2video',
13
+ 'videogenhub_LaVie_generation', 'videogenhub_VideoCrafter2_generation',
14
+ 'videogenhub_ModelScope_generation']
15
 
16
 
17
  def load_pipeline(model_name):
 
30
  pipe = load_playground_model(model_name)
31
  elif model_source == "fal":
32
  pipe = load_fal_model(model_name, model_type)
33
+ elif model_source == "videogenhub":
34
+ pipe = load_videogenhub_model(model_name)
35
  else:
36
  raise ValueError(f"Model source {model_source} not supported")
37
  return pipe
model/models/fal_api_models.py CHANGED
@@ -51,8 +51,14 @@ class FalModel():
51
  # return result
52
  elif self.model_type == "text2video":
53
  assert "prompt" in kwargs, "prompt is required for text2video model"
 
 
 
 
 
 
54
  handler = fal_client.submit(
55
- f"fal-ai/{self.model_name}",
56
  arguments={
57
  "prompt": kwargs["prompt"]
58
  },
 
51
  # return result
52
  elif self.model_type == "text2video":
53
  assert "prompt" in kwargs, "prompt is required for text2video model"
54
+ if self.model_name == 'AnimateDiff':
55
+ fal_model_name = 'fast-animatediff/text-to-video'
56
+ elif self.model_name == 'AnimateDiffTurbo':
57
+ fal_model_name = 'fast-animatediff/turbo/text-to-video'
58
+ else:
59
+ raise NotImplementedError(f"text2video model of {self.model_name} in fal is not implemented yet")
60
  handler = fal_client.submit(
61
+ f"fal-ai/{fal_model_name}",
62
  arguments={
63
  "prompt": kwargs["prompt"]
64
  },
model/models/videogenhub_models.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import videogen_hub
2
+
3
+
4
+ class VideogenHubModel():
5
+ def __init__(self, model_name):
6
+ self.model = videogen_hub.load(model_name)
7
+
8
+ def __call__(self, *args, **kwargs):
9
+ return self.model.infer_one_video(*args, **kwargs)
10
+
11
+ def load_videogenhub_model(model_name):
12
+ return VideogenHubModel(model_name)
requirements.txt CHANGED
@@ -5,7 +5,7 @@ faiss-cpu
5
  fire
6
  h5py
7
  xformers~=0.0.20
8
- numpy>=1.24.0
9
  pandas<2.0.0
10
  peft
11
  torch
@@ -49,4 +49,12 @@ statsmodels
49
  plotly
50
  -e git+https://github.com/TIGER-AI-Lab/ImagenHub.git#egg=imagen-hub
51
  fal_client
52
-
 
 
 
 
 
 
 
 
 
5
  fire
6
  h5py
7
  xformers~=0.0.20
8
+ numpy>=1.23.5
9
  pandas<2.0.0
10
  peft
11
  torch
 
49
  plotly
50
  -e git+https://github.com/TIGER-AI-Lab/ImagenHub.git#egg=imagen-hub
51
  fal_client
52
+ -e git+https://github.com/TIGER-AI-Lab/VideoGenHub.git#egg=videogen-hub
53
+ open_clip_torch
54
+ decord
55
+ huggingface_hub
56
+ open-clip-torch-any-py3
57
+ modelscope
58
+ protobuf==3.20.*
59
+ rotary_embedding_torch
60
+ av
serve/vote_utils.py CHANGED
@@ -8,6 +8,7 @@ from pathlib import Path
8
  from .utils import *
9
  from .log_utils import build_logger
10
  from .constants import IMAGE_DIR, VIDEO_DIR
 
11
 
12
  ig_logger = build_logger("gradio_web_server_image_generation", "gr_web_image_generation.log") # ig = image generation, loggers for single model direct chat
13
  igm_logger = build_logger("gradio_web_server_image_generation_multi", "gr_web_image_generation_multi.log") # igm = image generation multi, loggers for side-by-side and battle
@@ -105,9 +106,14 @@ def vote_last_response_vg(state, vote_type, model_selector, request: gr.Request)
105
 
106
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
107
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
108
- r = requests.get(state.output)
109
- with open(output_file, 'wb') as outfile:
110
- outfile.write(r.content)
 
 
 
 
 
111
  save_video_file_on_log_server(output_file)
112
 
113
 
@@ -126,9 +132,14 @@ def vote_last_response_vgm(states, vote_type, model_selectors, request: gr.Reque
126
  for state in states:
127
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
128
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
129
- r = requests.get(state.output)
130
- with open(output_file, 'wb') as outfile:
131
- outfile.write(r.content)
 
 
 
 
 
132
  save_video_file_on_log_server(output_file)
133
 
134
 
@@ -799,7 +810,7 @@ def generate_vg(gen_func, state, text, model_name, request: gr.Request):
799
  state.output = generated_video
800
  state.model_name = model_name
801
 
802
- yield state, generated_video
803
 
804
  finish_tstamp = time.time()
805
 
@@ -819,10 +830,17 @@ def generate_vg(gen_func, state, text, model_name, request: gr.Request):
819
 
820
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
821
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
822
- r = requests.get(state.output)
823
- with open(output_file, 'wb') as outfile:
824
- outfile.write(r.content)
 
 
 
 
 
 
825
  save_video_file_on_log_server(output_file)
 
826
 
827
  def generate_vgm(gen_func, state0, state1, text, model_name0, model_name1, request: gr.Request):
828
  if not text:
@@ -848,11 +866,13 @@ def generate_vgm(gen_func, state0, state1, text, model_name0, model_name1, reque
848
  state1.output = generated_video1
849
  state0.model_name = model_name0
850
  state1.model_name = model_name1
 
 
 
851
 
852
- yield state0, state1, generated_video0, generated_video1
853
 
854
  finish_tstamp = time.time()
855
- # logger.info(f"===output===: {output}")
856
 
857
  with open(get_conv_log_filename(), "a") as fout:
858
  data = {
@@ -883,10 +903,19 @@ def generate_vgm(gen_func, state0, state1, text, model_name0, model_name1, reque
883
  for i, state in enumerate([state0, state1]):
884
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
885
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
886
- r = requests.get(state.output)
887
- with open(output_file, 'wb') as outfile:
888
- outfile.write(r.content)
 
 
 
 
 
 
 
 
889
  save_video_file_on_log_server(output_file)
 
890
 
891
 
892
  def generate_vgm_annoy(gen_func, state0, state1, text, model_name0, model_name1, request: gr.Request):
@@ -909,8 +938,8 @@ def generate_vgm_annoy(gen_func, state0, state1, text, model_name0, model_name1,
909
  state0.model_name = model_name0
910
  state1.model_name = model_name1
911
 
912
- yield state0, state1, generated_video0, generated_video1, \
913
- gr.Markdown(f"### Model A: {model_name0}"), gr.Markdown(f"### Model B: {model_name1}")
914
 
915
  finish_tstamp = time.time()
916
  # logger.info(f"===output===: {output}")
@@ -944,7 +973,15 @@ def generate_vgm_annoy(gen_func, state0, state1, text, model_name0, model_name1,
944
  for i, state in enumerate([state0, state1]):
945
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
946
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
947
- r = requests.get(state.output)
948
- with open(output_file, 'wb') as outfile:
949
- outfile.write(r.content)
950
- save_video_file_on_log_server(output_file)
 
 
 
 
 
 
 
 
 
8
  from .utils import *
9
  from .log_utils import build_logger
10
  from .constants import IMAGE_DIR, VIDEO_DIR
11
+ import imageio
12
 
13
  ig_logger = build_logger("gradio_web_server_image_generation", "gr_web_image_generation.log") # ig = image generation, loggers for single model direct chat
14
  igm_logger = build_logger("gradio_web_server_image_generation_multi", "gr_web_image_generation_multi.log") # igm = image generation multi, loggers for side-by-side and battle
 
106
 
107
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
108
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
109
+ if state.model_name.startswith('fal'):
110
+ r = requests.get(state.output)
111
+ with open(output_file, 'wb') as outfile:
112
+ outfile.write(r.content)
113
+ else:
114
+ print("======== video shape: ========")
115
+ print(state.output.shape)
116
+ imageio.mimwrite(output_file, state.output, fps=8, quality=9)
117
  save_video_file_on_log_server(output_file)
118
 
119
 
 
132
  for state in states:
133
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
134
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
135
+ if state.model_name.startswith('fal'):
136
+ r = requests.get(state.output)
137
+ with open(output_file, 'wb') as outfile:
138
+ outfile.write(r.content)
139
+ else:
140
+ print("======== video shape: ========")
141
+ print(state.output.shape)
142
+ imageio.mimwrite(output_file, state.output, fps=8, quality=9)
143
  save_video_file_on_log_server(output_file)
144
 
145
 
 
810
  state.output = generated_video
811
  state.model_name = model_name
812
 
813
+ # yield state, generated_video
814
 
815
  finish_tstamp = time.time()
816
 
 
830
 
831
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
832
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
833
+ if model_name.startswith('fal'):
834
+ r = requests.get(state.output)
835
+ with open(output_file, 'wb') as outfile:
836
+ outfile.write(r.content)
837
+ else:
838
+ print("======== video shape: ========")
839
+ print(state.output.shape)
840
+ imageio.mimwrite(output_file, state.output, fps=8, quality=9)
841
+
842
  save_video_file_on_log_server(output_file)
843
+ yield state, output_file
844
 
845
  def generate_vgm(gen_func, state0, state1, text, model_name0, model_name1, request: gr.Request):
846
  if not text:
 
866
  state1.output = generated_video1
867
  state0.model_name = model_name0
868
  state1.model_name = model_name1
869
+ print("====== model name =========")
870
+ print(state0.model_name)
871
+ print(state1.model_name)
872
 
 
873
 
874
  finish_tstamp = time.time()
875
+
876
 
877
  with open(get_conv_log_filename(), "a") as fout:
878
  data = {
 
903
  for i, state in enumerate([state0, state1]):
904
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
905
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
906
+ print(state.model_name)
907
+
908
+ if state.model_name.startswith('fal'):
909
+ r = requests.get(state.output)
910
+ with open(output_file, 'wb') as outfile:
911
+ outfile.write(r.content)
912
+ else:
913
+ print("======== video shape: ========")
914
+ print(state.output)
915
+ print(state.output.shape)
916
+ imageio.mimwrite(output_file, state.output, fps=8, quality=9)
917
  save_video_file_on_log_server(output_file)
918
+ yield state0, state1, f'{VIDEO_DIR}/generation/{state0.conv_id}.mp4', f'{VIDEO_DIR}/generation/{state1.conv_id}.mp4'
919
 
920
 
921
  def generate_vgm_annoy(gen_func, state0, state1, text, model_name0, model_name1, request: gr.Request):
 
938
  state0.model_name = model_name0
939
  state1.model_name = model_name1
940
 
941
+ # yield state0, state1, generated_video0, generated_video1, \
942
+ # gr.Markdown(f"### Model A: {model_name0}"), gr.Markdown(f"### Model B: {model_name1}")
943
 
944
  finish_tstamp = time.time()
945
  # logger.info(f"===output===: {output}")
 
973
  for i, state in enumerate([state0, state1]):
974
  output_file = f'{VIDEO_DIR}/generation/{state.conv_id}.mp4'
975
  os.makedirs(os.path.dirname(output_file), exist_ok=True)
976
+ if state.model_name.startswith('fal'):
977
+ r = requests.get(state.output)
978
+ with open(output_file, 'wb') as outfile:
979
+ outfile.write(r.content)
980
+ else:
981
+ print("======== video shape: ========")
982
+ print(state.output.shape)
983
+ imageio.mimwrite(output_file, state.output, fps=8, quality=9)
984
+ save_video_file_on_log_server(output_file)
985
+
986
+ yield state0, state1, f'{VIDEO_DIR}/generation/{state0.conv_id}.mp4', f'{VIDEO_DIR}/generation/{state1.conv_id}.mp4', \
987
+ gr.Markdown(f"### Model A: {model_name0}"), gr.Markdown(f"### Model B: {model_name1}")