multimodalart HF Staff commited on
Commit
9c01f36
·
verified ·
1 Parent(s): 2787953

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -8
app.py CHANGED
@@ -19,6 +19,8 @@ import os
19
  from PIL import Image
20
  import os
21
  import gradio as gr
 
 
22
 
23
 
24
  # --- Model Loading ---
@@ -55,6 +57,16 @@ optimize_pipeline_(pipe, image=[Image.new("RGB", (1024, 1024)), Image.new("RGB",
55
 
56
  MAX_SEED = np.iinfo(np.int32).max
57
 
 
 
 
 
 
 
 
 
 
 
58
  def build_camera_prompt(rotate_deg, move_forward, vertical_tilt, wideangle):
59
  prompt_parts = []
60
 
@@ -138,6 +150,37 @@ def infer_camera_edit(
138
 
139
  return result, seed, prompt
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
 
142
  # --- UI ---
143
  css = '''#col-container { max-width: 800px; margin: 0 auto; }
@@ -210,8 +253,10 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
210
  with gr.Column():
211
  result = gr.Image(label="Output Image", interactive=False)
212
  prompt_preview = gr.Textbox(label="Processed Prompt", interactive=False)
213
- #gr.Markdown("_Each change applies a fresh camera instruction to the last output image._")
214
-
 
 
215
  inputs = [
216
  image,rotate_deg, move_forward,
217
  vertical_tilt, wideangle,
@@ -227,8 +272,30 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
227
  queue=False
228
  ).then(fn=end_reset, inputs=None, outputs=[is_reset], queue=False)
229
 
230
- # Manual generation
231
- run_event = run_btn.click(fn=infer_camera_edit, inputs=inputs, outputs=outputs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
  # Examples
234
  gr.Examples(
@@ -267,9 +334,12 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
267
  # Live updates
268
  def maybe_infer(is_reset, progress=gr.Progress(track_tqdm=True), *args):
269
  if is_reset:
270
- return gr.update(), gr.update(), gr.update()
271
  else:
272
- return infer_camera_edit(*args)
 
 
 
273
 
274
  control_inputs = [
275
  image, rotate_deg, move_forward,
@@ -279,9 +349,9 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=css) as demo:
279
  control_inputs_with_flag = [is_reset] + control_inputs
280
 
281
  for control in [rotate_deg, move_forward, vertical_tilt]:
282
- control.release(fn=maybe_infer, inputs=control_inputs_with_flag, outputs=outputs)
283
 
284
- wideangle.change(fn=maybe_infer, inputs=control_inputs_with_flag, outputs=outputs)
285
 
286
  run_event.then(lambda img, *_: img, inputs=[result], outputs=[prev_output])
287
 
 
19
  from PIL import Image
20
  import os
21
  import gradio as gr
22
+ from gradio_client import Client, handle_file
23
+ import tempfile
24
 
25
 
26
  # --- Model Loading ---
 
57
 
58
  MAX_SEED = np.iinfo(np.int32).max
59
 
60
+ def _generate_video_segment(input_image_path: str, output_image_path: str, prompt: str) -> str:
61
+ """Generates a single video segment using the external service."""
62
+ video_client = Client("multimodalart/wan-2-2-first-last-frame")
63
+ result = video_client.predict(
64
+ start_image_pil=handle_file(input_image_path),
65
+ end_image_pil=handle_file(output_image_path),
66
+ prompt=prompt, api_name="/generate_video"
67
+ )
68
+ return result[0]["video"]
69
+
70
  def build_camera_prompt(rotate_deg, move_forward, vertical_tilt, wideangle):
71
  prompt_parts = []
72
 
 
150
 
151
  return result, seed, prompt
152
 
153
+ def create_video_between_images(input_image: str, output_image: str, prompt: str) -> str:
154
+ """Create a video between the input and output images."""
155
+ if not input_image or not output_image:
156
+ raise gr.Error("Both input and output images are required to create a video.")
157
+
158
+ try:
159
+ # Save images to temporary files if they're not already file paths
160
+ if isinstance(input_image, Image.Image):
161
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
162
+ input_image.save(tmp.name)
163
+ input_image_path = tmp.name
164
+ else:
165
+ input_image_path = input_image
166
+
167
+ if isinstance(output_image, Image.Image):
168
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
169
+ output_image.save(tmp.name)
170
+ output_image_path = tmp.name
171
+ else:
172
+ output_image_path = output_image
173
+
174
+ # Generate the video
175
+ video_path = _generate_video_segment(
176
+ input_image_path,
177
+ output_image_path,
178
+ prompt if prompt else "Camera movement transformation"
179
+ )
180
+ return video_path
181
+ except Exception as e:
182
+ raise gr.Error(f"Video generation failed: {e}")
183
+
184
 
185
  # --- UI ---
186
  css = '''#col-container { max-width: 800px; margin: 0 auto; }
 
253
  with gr.Column():
254
  result = gr.Image(label="Output Image", interactive=False)
255
  prompt_preview = gr.Textbox(label="Processed Prompt", interactive=False)
256
+ create_video_button = gr.Button("🎥 Create Video Between Images", variant="secondary", visible=False)
257
+ with gr.Group(visible=False) as video_group:
258
+ video_output = gr.Video(label="Generated Video", show_download_button=True, autoplay=True)
259
+
260
  inputs = [
261
  image,rotate_deg, move_forward,
262
  vertical_tilt, wideangle,
 
272
  queue=False
273
  ).then(fn=end_reset, inputs=None, outputs=[is_reset], queue=False)
274
 
275
+ # Manual generation with video button visibility control
276
+ def infer_and_show_video_button(*args):
277
+ result_img, result_seed, result_prompt = infer_camera_edit(*args)
278
+ # Show video button if we have both input and output images
279
+ show_button = args[0] is not None and result_img is not None
280
+ return result_img, result_seed, result_prompt, gr.update(visible=show_button)
281
+
282
+ run_event = run_btn.click(
283
+ fn=infer_and_show_video_button,
284
+ inputs=inputs,
285
+ outputs=outputs + [create_video_button]
286
+ )
287
+
288
+ # Video creation
289
+ create_video_button.click(
290
+ fn=lambda: gr.update(visible=True),
291
+ outputs=[video_group],
292
+ api_name=False
293
+ ).then(
294
+ fn=create_video_between_images,
295
+ inputs=[image, result, prompt_preview],
296
+ outputs=[video_output],
297
+ api_name=False
298
+ )
299
 
300
  # Examples
301
  gr.Examples(
 
334
  # Live updates
335
  def maybe_infer(is_reset, progress=gr.Progress(track_tqdm=True), *args):
336
  if is_reset:
337
+ return gr.update(), gr.update(), gr.update(), gr.update()
338
  else:
339
+ result_img, result_seed, result_prompt = infer_camera_edit(*args)
340
+ # Show video button if we have both input and output
341
+ show_button = args[0] is not None and result_img is not None
342
+ return result_img, result_seed, result_prompt, gr.update(visible=show_button)
343
 
344
  control_inputs = [
345
  image, rotate_deg, move_forward,
 
349
  control_inputs_with_flag = [is_reset] + control_inputs
350
 
351
  for control in [rotate_deg, move_forward, vertical_tilt]:
352
+ control.release(fn=maybe_infer, inputs=control_inputs_with_flag, outputs=outputs + [create_video_button])
353
 
354
+ wideangle.change(fn=maybe_infer, inputs=control_inputs_with_flag, outputs=outputs + [create_video_button])
355
 
356
  run_event.then(lambda img, *_: img, inputs=[result], outputs=[prev_output])
357