Update app.py
Browse files
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
|
| 777 |
-
return gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
|
| 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
|
| 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
|
| 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
|
| 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
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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")
|