multimodalart HF Staff commited on
Commit
9f1ceae
·
verified ·
1 Parent(s): 161c052

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +18 -38
app.py CHANGED
@@ -758,27 +758,19 @@ with gr.Blocks() as demo:
758
  height = gr.Slider(label="Height", minimum=256, maximum=2048, step=8, value=1024)
759
  width = gr.Slider(label="Width", minimum=256, maximum=2048, step=8, value=1024)
760
 
761
- # State to prevent circular updates between 3D control and sliders
762
- is_syncing_from_3d = gr.State(False)
763
-
764
  # --- Helper Functions ---
765
  def update_prompt_from_sliders(rotate, forward, tilt, wide):
766
  return build_camera_prompt(rotate, forward, tilt, wide)
767
 
768
  def sync_3d_to_sliders(camera_value):
769
- """Sync 3D control values to sliders. Returns syncing flag = True."""
770
  if camera_value and isinstance(camera_value, dict):
771
  rot = camera_value.get('rotate_deg', 0)
772
  fwd = camera_value.get('move_forward', 0)
773
  tilt = camera_value.get('vertical_tilt', 0)
774
  wide = camera_value.get('wideangle', False)
775
  prompt = build_camera_prompt(rot, fwd, tilt, wide)
776
- return rot, fwd, tilt, wide, prompt, True # Set syncing flag
777
- return gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), False
778
-
779
- def clear_syncing_flag():
780
- """Clear the syncing flag after sync is complete."""
781
- return False
782
 
783
  def sync_sliders_to_3d(rotate, forward, tilt, wide):
784
  return {"rotate_deg": rotate, "move_forward": forward, "vertical_tilt": tilt, "wideangle": wide}
@@ -792,20 +784,6 @@ with gr.Blocks() as demo:
792
  data_url = f"data:image/png;base64,{img_str}"
793
  return gr.update(imageUrl=data_url)
794
 
795
- def sync_3d_on_slider_change_if_not_syncing(is_syncing, img, rot, fwd, tilt, wide):
796
- """Only sync sliders to 3D if we're not already syncing from 3D."""
797
- if is_syncing:
798
- # Skip update to prevent circular trigger
799
- return gr.update()
800
- camera_value = {"rotate_deg": rot, "move_forward": fwd, "vertical_tilt": tilt, "wideangle": wide}
801
- if img is not None:
802
- buffered = BytesIO()
803
- img.save(buffered, format="PNG")
804
- img_str = base64.b64encode(buffered.getvalue()).decode()
805
- data_url = f"data:image/png;base64,{img_str}"
806
- return gr.update(value=camera_value, imageUrl=data_url)
807
- return gr.update(value=camera_value)
808
-
809
  # Define inputs/outputs
810
  inputs = [image, rotate_deg, move_forward, vertical_tilt, wideangle, seed, randomize_seed, true_guidance_scale, num_inference_steps, height, width, prev_output]
811
  outputs = [result, seed, prompt_preview]
@@ -826,22 +804,18 @@ with gr.Blocks() as demo:
826
  slider.change(fn=update_prompt_from_sliders, inputs=[rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[prompt_preview])
827
  wideangle.change(fn=update_prompt_from_sliders, inputs=[rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[prompt_preview])
828
 
829
- # 3D control -> Sliders + Prompt + Inference (with syncing flag)
830
  camera_3d.change(
831
  fn=sync_3d_to_sliders,
832
  inputs=[camera_3d],
833
- outputs=[rotate_deg, move_forward, vertical_tilt, wideangle, prompt_preview, is_syncing_from_3d]
834
  ).then(
835
  fn=maybe_infer,
836
  inputs=control_inputs_with_flag,
837
  outputs=outputs + [create_video_button]
838
- ).then(
839
- fn=clear_syncing_flag,
840
- inputs=None,
841
- outputs=[is_syncing_from_3d]
842
  )
843
 
844
- # Sliders -> 3D control (only on user release, not programmatic changes)
845
  for slider in [rotate_deg, move_forward, vertical_tilt]:
846
  slider.release(fn=sync_sliders_to_3d, inputs=[rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[camera_3d])
847
  wideangle.input(fn=sync_sliders_to_3d, inputs=[rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[camera_3d])
@@ -871,7 +845,7 @@ with gr.Blocks() as demo:
871
 
872
  image.clear(fn=lambda: gr.update(imageUrl=None), outputs=[camera_3d])
873
 
874
- # Live updates on slider release (user interaction only)
875
  for control in [rotate_deg, move_forward, vertical_tilt]:
876
  control.release(fn=maybe_infer, inputs=control_inputs_with_flag, outputs=outputs + [create_video_button])
877
  wideangle.input(fn=maybe_infer, inputs=control_inputs_with_flag, outputs=outputs + [create_video_button])
@@ -896,13 +870,19 @@ with gr.Blocks() as demo:
896
  )
897
 
898
  # Sync 3D component when sliders change (covers example loading)
899
- # Uses syncing flag to prevent circular updates
 
 
 
 
 
 
 
 
 
 
900
  for slider in [rotate_deg, move_forward, vertical_tilt]:
901
- slider.change(
902
- fn=sync_3d_on_slider_change_if_not_syncing,
903
- inputs=[is_syncing_from_3d, image, rotate_deg, move_forward, vertical_tilt, wideangle],
904
- outputs=[camera_3d]
905
- )
906
 
907
  gr.api(infer_camera_edit, api_name="infer_edit_camera_angles")
908
  gr.api(create_video_between_images, api_name="create_video_between_images")
 
758
  height = gr.Slider(label="Height", minimum=256, maximum=2048, step=8, value=1024)
759
  width = gr.Slider(label="Width", minimum=256, maximum=2048, step=8, value=1024)
760
 
 
 
 
761
  # --- Helper Functions ---
762
  def update_prompt_from_sliders(rotate, forward, tilt, wide):
763
  return build_camera_prompt(rotate, forward, tilt, wide)
764
 
765
  def sync_3d_to_sliders(camera_value):
 
766
  if camera_value and isinstance(camera_value, dict):
767
  rot = camera_value.get('rotate_deg', 0)
768
  fwd = camera_value.get('move_forward', 0)
769
  tilt = camera_value.get('vertical_tilt', 0)
770
  wide = camera_value.get('wideangle', False)
771
  prompt = build_camera_prompt(rot, fwd, tilt, wide)
772
+ return rot, fwd, tilt, wide, prompt
773
+ return gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
 
 
 
 
774
 
775
  def sync_sliders_to_3d(rotate, forward, tilt, wide):
776
  return {"rotate_deg": rotate, "move_forward": forward, "vertical_tilt": tilt, "wideangle": wide}
 
784
  data_url = f"data:image/png;base64,{img_str}"
785
  return gr.update(imageUrl=data_url)
786
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
787
  # Define inputs/outputs
788
  inputs = [image, rotate_deg, move_forward, vertical_tilt, wideangle, seed, randomize_seed, true_guidance_scale, num_inference_steps, height, width, prev_output]
789
  outputs = [result, seed, prompt_preview]
 
804
  slider.change(fn=update_prompt_from_sliders, inputs=[rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[prompt_preview])
805
  wideangle.change(fn=update_prompt_from_sliders, inputs=[rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[prompt_preview])
806
 
807
+ # 3D control -> Sliders + Prompt + Inference
808
  camera_3d.change(
809
  fn=sync_3d_to_sliders,
810
  inputs=[camera_3d],
811
+ outputs=[rotate_deg, move_forward, vertical_tilt, wideangle, prompt_preview]
812
  ).then(
813
  fn=maybe_infer,
814
  inputs=control_inputs_with_flag,
815
  outputs=outputs + [create_video_button]
 
 
 
 
816
  )
817
 
818
+ # Sliders -> 3D control
819
  for slider in [rotate_deg, move_forward, vertical_tilt]:
820
  slider.release(fn=sync_sliders_to_3d, inputs=[rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[camera_3d])
821
  wideangle.input(fn=sync_sliders_to_3d, inputs=[rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[camera_3d])
 
845
 
846
  image.clear(fn=lambda: gr.update(imageUrl=None), outputs=[camera_3d])
847
 
848
+ # Live updates on slider release
849
  for control in [rotate_deg, move_forward, vertical_tilt]:
850
  control.release(fn=maybe_infer, inputs=control_inputs_with_flag, outputs=outputs + [create_video_button])
851
  wideangle.input(fn=maybe_infer, inputs=control_inputs_with_flag, outputs=outputs + [create_video_button])
 
870
  )
871
 
872
  # Sync 3D component when sliders change (covers example loading)
873
+ def sync_3d_on_slider_change(img, rot, fwd, tilt, wide):
874
+ camera_value = {"rotate_deg": rot, "move_forward": fwd, "vertical_tilt": tilt, "wideangle": wide}
875
+ if img is not None:
876
+ buffered = BytesIO()
877
+ img.save(buffered, format="PNG")
878
+ img_str = base64.b64encode(buffered.getvalue()).decode()
879
+ data_url = f"data:image/png;base64,{img_str}"
880
+ return gr.update(value=camera_value, imageUrl=data_url)
881
+ return gr.update(value=camera_value)
882
+
883
+ # When any slider value changes (including from examples), sync the 3D component
884
  for slider in [rotate_deg, move_forward, vertical_tilt]:
885
+ slider.change(fn=sync_3d_on_slider_change, inputs=[image, rotate_deg, move_forward, vertical_tilt, wideangle], outputs=[camera_3d])
 
 
 
 
886
 
887
  gr.api(infer_camera_edit, api_name="infer_edit_camera_angles")
888
  gr.api(create_video_between_images, api_name="create_video_between_images")