huzey commited on
Commit
3af1fcf
1 Parent(s): 06d24e2

add download

Browse files
Files changed (1) hide show
  1. app.py +137 -8
app.py CHANGED
@@ -1,12 +1,14 @@
1
  # Author: Huzheng Yang
2
  # %%
3
  import copy
 
4
  import pickle
5
  from functools import partial
6
  from io import BytesIO
7
  import json
8
  import os
9
  import uuid
 
10
 
11
  from einops import rearrange
12
  from matplotlib import pyplot as plt
@@ -1280,15 +1282,15 @@ def make_input_video_section():
1280
  return input_gallery, submit_button, clear_images_button, max_frames_number
1281
 
1282
 
1283
- def make_input_images_section(rows=1, cols=3, height="auto", advanced=False, is_random=False):
1284
  gr.Markdown('### Input Images')
1285
  input_gallery = gr.Gallery(value=None, label="Input images", show_label=True, elem_id="input_images", columns=[cols], rows=[rows], object_fit="contain", height=height, type="pil", show_share_button=False)
1286
 
1287
  submit_button = gr.Button("🔴 RUN", elem_id="submit_button", variant='primary')
1288
  with gr.Row():
1289
- clear_images_button = gr.Button("🗑️Clear", elem_id='clear_button', variant='stop')
1290
  clear_images_button.click(fn=lambda: gr.update(value=None), outputs=[input_gallery])
1291
- upload_button = gr.UploadButton(elem_id="upload_button", label="⬆️Upload", variant='secondary', file_types=["image"], file_count="multiple")
1292
 
1293
  def convert_to_pil_and_append(images, new_images):
1294
  if images is None:
@@ -1304,7 +1306,9 @@ def make_input_images_section(rows=1, cols=3, height="auto", advanced=False, is_
1304
  gr.Info(f"Total images: {len(images)}")
1305
  return images
1306
  upload_button.upload(convert_to_pil_and_append, inputs=[input_gallery, upload_button], outputs=[input_gallery])
1307
-
 
 
1308
 
1309
  gr.Markdown('### Load Datasets')
1310
  load_images_button = gr.Button("🔴 Load Images", elem_id="load-images-button", variant='primary')
@@ -1596,7 +1600,114 @@ def add_output_images_buttons(output_gallery):
1596
  flip_button = gr.Button("🔃 Flip", elem_id="flip_button", variant='secondary')
1597
  flip_button.click(flip_rgb_gallery, inputs=[output_gallery], outputs=[output_gallery])
1598
  return rotate_button, flip_button
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1599
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1600
 
1601
  def make_output_images_section():
1602
  gr.Markdown('### Output Images')
@@ -1752,14 +1863,17 @@ with demo:
1752
 
1753
  with gr.Row():
1754
  with gr.Column(scale=5, min_width=200):
1755
- input_gallery, submit_button, clear_images_button, dataset_dropdown, num_images_slider, random_seed_slider, load_images_button = make_input_images_section()
1756
  num_images_slider.value = 30
1757
  logging_text = gr.Textbox("Logging information", label="Logging", elem_id="logging", type="text", placeholder="Logging information", autofocus=False, autoscroll=False, lines=20)
1758
 
1759
  with gr.Column(scale=5, min_width=200):
1760
  output_gallery = make_output_images_section()
 
1761
  norm_gallery = gr.Gallery(value=[], label="Eigenvector Magnitude", show_label=True, elem_id="eig_norm", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
 
1762
  cluster_gallery = gr.Gallery(value=[], label="Clusters", show_label=True, elem_id="clusters", columns=[2], rows=[4], object_fit="contain", height=600, show_share_button=True, preview=True, interactive=False)
 
1763
  [
1764
  model_dropdown, layer_slider, node_type_dropdown, num_eig_slider,
1765
  affinity_focal_gamma_slider, num_sample_ncut_slider, ncut_knn_slider, ncut_indirect_connection, ncut_make_orthogonal,
@@ -1921,27 +2035,36 @@ with demo:
1921
 
1922
  with gr.Row():
1923
  with gr.Column(scale=5, min_width=200):
1924
- input_gallery, submit_button, clear_images_button, dataset_dropdown, num_images_slider, random_seed_slider, load_images_button = make_input_images_section()
1925
  num_images_slider.value = 100
1926
  logging_text = gr.Textbox("Logging information", label="Logging", elem_id="logging", type="text", placeholder="Logging information", lines=20)
1927
  with gr.Column(scale=5, min_width=200):
1928
  gr.Markdown('### Output (Recursion #1)')
1929
  l1_gallery = gr.Gallery(format='png', value=[], label="Recursion #1", show_label=True, elem_id="ncut_l1", columns=[3], rows=[5], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False)
1930
  add_output_images_buttons(l1_gallery)
 
1931
  l1_norm_gallery = gr.Gallery(value=[], label="Recursion #1 Eigenvector Magnitude", show_label=True, elem_id="eig_norm", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
 
1932
  l1_cluster_gallery = gr.Gallery(value=[], label="Recursion #1 Clusters", show_label=True, elem_id="clusters", columns=[2], rows=[4], object_fit="contain", height=500, show_share_button=True, preview=True, interactive=False)
 
1933
  with gr.Column(scale=5, min_width=200):
1934
  gr.Markdown('### Output (Recursion #2)')
1935
  l2_gallery = gr.Gallery(format='png', value=[], label="Recursion #2", show_label=True, elem_id="ncut_l2", columns=[3], rows=[5], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False)
1936
  add_output_images_buttons(l2_gallery)
 
1937
  l2_norm_gallery = gr.Gallery(value=[], label="Recursion #2 Eigenvector Magnitude", show_label=True, elem_id="eig_norm", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
 
1938
  l2_cluster_gallery = gr.Gallery(value=[], label="Recursion #2 Clusters", show_label=True, elem_id="clusters", columns=[2], rows=[4], object_fit="contain", height=500, show_share_button=True, preview=True, interactive=False)
 
1939
  with gr.Column(scale=5, min_width=200):
1940
  gr.Markdown('### Output (Recursion #3)')
1941
  l3_gallery = gr.Gallery(format='png', value=[], label="Recursion #3", show_label=True, elem_id="ncut_l3", columns=[3], rows=[5], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False)
1942
  add_output_images_buttons(l3_gallery)
 
1943
  l3_norm_gallery = gr.Gallery(value=[], label="Recursion #3 Eigenvector Magnitude", show_label=True, elem_id="eig_norm", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
 
1944
  l3_cluster_gallery = gr.Gallery(value=[], label="Recursion #3 Clusters", show_label=True, elem_id="clusters", columns=[2], rows=[4], object_fit="contain", height=500, show_share_button=True, preview=True, interactive=False)
 
1945
 
1946
  with gr.Row():
1947
  with gr.Column(scale=5, min_width=200):
@@ -2165,16 +2288,19 @@ with demo:
2165
  gr.Markdown('### Output (Recursion #1)')
2166
  l1_gallery = gr.Gallery(format='png', value=[], label="Recursion #1", show_label=True, elem_id="ncut_l1", columns=[100], rows=[1], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False, preview=True)
2167
  add_output_images_buttons(l1_gallery)
 
2168
  gr.Markdown('### Output (Recursion #2)')
2169
  l2_gallery = gr.Gallery(format='png', value=[], label="Recursion #2", show_label=True, elem_id="ncut_l2", columns=[100], rows=[1], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False, preview=True)
2170
  add_output_images_buttons(l2_gallery)
 
2171
  gr.Markdown('### Output (Recursion #3)')
2172
  l3_gallery = gr.Gallery(format='png', value=[], label="Recursion #3", show_label=True, elem_id="ncut_l3", columns=[100], rows=[1], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False, preview=True)
2173
  add_output_images_buttons(l3_gallery)
 
2174
 
2175
  with gr.Row():
2176
  with gr.Column(scale=5, min_width=200):
2177
- input_gallery, submit_button, clear_images_button, dataset_dropdown, num_images_slider, random_seed_slider, load_images_button = make_input_images_section()
2178
  num_images_slider.value = 100
2179
 
2180
 
@@ -2311,8 +2437,11 @@ with demo:
2311
  output_gallery = gr.Gallery(format='png', value=[], label="NCUT Embedding", show_label=True, elem_id=f"ncut{i_model}", columns=[3], rows=[1], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False)
2312
  submit_button = gr.Button("🔴 RUN", elem_id=f"submit_button{i_model}", variant='primary')
2313
  add_output_images_buttons(output_gallery)
 
2314
  norm_gallery = gr.Gallery(value=[], label="Eigenvector Magnitude", show_label=True, elem_id=f"eig_norm{i_model}", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
 
2315
  cluster_gallery = gr.Gallery(value=[], label="Clusters", show_label=True, elem_id=f"clusters{i_model}", columns=[2], rows=[4], object_fit="contain", height=500, show_share_button=True, preview=True, interactive=False)
 
2316
  [
2317
  model_dropdown, layer_slider, node_type_dropdown, num_eig_slider,
2318
  affinity_focal_gamma_slider, num_sample_ncut_slider, ncut_knn_slider, ncut_indirect_connection, ncut_make_orthogonal,
@@ -2342,7 +2471,7 @@ with demo:
2342
 
2343
  with gr.Row():
2344
  with gr.Column(scale=5, min_width=200):
2345
- input_gallery, submit_button, clear_images_button, dataset_dropdown, num_images_slider, random_seed_slider, load_images_button = make_input_images_section()
2346
  submit_button.visible = False
2347
 
2348
 
 
1
  # Author: Huzheng Yang
2
  # %%
3
  import copy
4
+ from datetime import datetime
5
  import pickle
6
  from functools import partial
7
  from io import BytesIO
8
  import json
9
  import os
10
  import uuid
11
+ import zipfile
12
 
13
  from einops import rearrange
14
  from matplotlib import pyplot as plt
 
1282
  return input_gallery, submit_button, clear_images_button, max_frames_number
1283
 
1284
 
1285
+ def make_input_images_section(rows=1, cols=3, height="auto", advanced=False, is_random=False, allow_download=False):
1286
  gr.Markdown('### Input Images')
1287
  input_gallery = gr.Gallery(value=None, label="Input images", show_label=True, elem_id="input_images", columns=[cols], rows=[rows], object_fit="contain", height=height, type="pil", show_share_button=False)
1288
 
1289
  submit_button = gr.Button("🔴 RUN", elem_id="submit_button", variant='primary')
1290
  with gr.Row():
1291
+ clear_images_button = gr.Button("🗑️ Clear", elem_id='clear_button', variant='stop')
1292
  clear_images_button.click(fn=lambda: gr.update(value=None), outputs=[input_gallery])
1293
+ upload_button = gr.UploadButton(elem_id="upload_button", label="⬆️ Upload", variant='secondary', file_types=["image"], file_count="multiple")
1294
 
1295
  def convert_to_pil_and_append(images, new_images):
1296
  if images is None:
 
1306
  gr.Info(f"Total images: {len(images)}")
1307
  return images
1308
  upload_button.upload(convert_to_pil_and_append, inputs=[input_gallery, upload_button], outputs=[input_gallery])
1309
+
1310
+ if allow_download:
1311
+ create_file_button, download_button = add_download_button(input_gallery, "input_images")
1312
 
1313
  gr.Markdown('### Load Datasets')
1314
  load_images_button = gr.Button("🔴 Load Images", elem_id="load-images-button", variant='primary')
 
1600
  flip_button = gr.Button("🔃 Flip", elem_id="flip_button", variant='secondary')
1601
  flip_button.click(flip_rgb_gallery, inputs=[output_gallery], outputs=[output_gallery])
1602
  return rotate_button, flip_button
1603
+
1604
+ def add_download_button(gallery, filename_prefix="output"):
1605
+
1606
+ def make_3x5_plot(images):
1607
+ plot_list = []
1608
+
1609
+ # Split the list of images into chunks of 15
1610
+ chunks = [images[i:i + 15] for i in range(0, len(images), 15)]
1611
+
1612
+ for chunk in chunks:
1613
+ fig, axs = plt.subplots(3, 4, figsize=(12, 9))
1614
+ for ax in axs.flatten():
1615
+ ax.axis("off")
1616
+ for ax, img in zip(axs.flatten(), chunk):
1617
+ img = img.convert("RGB")
1618
+ ax.imshow(img)
1619
+
1620
+ plt.tight_layout(h_pad=0.5, w_pad=0.3)
1621
+
1622
+ # Generate a unique filename
1623
+ filename = uuid.uuid4()
1624
+ tmp_path = f"/tmp/{filename}.png"
1625
+
1626
+ # Save the plot to the temporary file
1627
+ plt.savefig(tmp_path, bbox_inches='tight', dpi=144)
1628
+
1629
+ # Open the saved image
1630
+ img = Image.open(tmp_path)
1631
+ img = img.convert("RGB")
1632
+ img = copy.deepcopy(img)
1633
+
1634
+ # Remove the temporary file
1635
+ os.remove(tmp_path)
1636
+
1637
+ plot_list.append(img)
1638
+ plt.close()
1639
+
1640
+ return plot_list
1641
+
1642
+ def delete_file_after_delay(file_path, delay):
1643
+ def delete_file():
1644
+ if os.path.exists(file_path):
1645
+ os.remove(file_path)
1646
+
1647
+ timer = threading.Timer(delay, delete_file)
1648
+ timer.start()
1649
+
1650
+ def create_zip_file(images, filename_prefix=filename_prefix):
1651
+ if images is None or len(images) == 0:
1652
+ gr.Warning("No images selected.")
1653
+ return None
1654
+ gr.Info("Creating zip file for download...")
1655
+ images = [image[0] for image in images]
1656
+ if isinstance(images[0], str):
1657
+ images = [Image.open(image) for image in images]
1658
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
1659
+
1660
+ zip_filename = f"/tmp/gallery_download/{filename_prefix}_{timestamp}.zip"
1661
+ os.makedirs(os.path.dirname(zip_filename), exist_ok=True)
1662
+
1663
+ plots = make_3x5_plot(images)
1664
+
1665
+
1666
+
1667
+ with zipfile.ZipFile(zip_filename, 'w') as zipf:
1668
+ # Create a temporary directory to store images and plots
1669
+ temp_dir = f"/tmp/gallery_download/images/{uuid.uuid4()}"
1670
+ os.makedirs(temp_dir)
1671
+
1672
+ try:
1673
+ # Save images to the temporary directory
1674
+ for i, img in enumerate(images):
1675
+ img = img.convert("RGB")
1676
+ img_path = os.path.join(temp_dir, f"single_{i:04d}.jpg")
1677
+ img.save(img_path)
1678
+ zipf.write(img_path, f"single_{i:04d}.jpg")
1679
+
1680
+ # Save plots to the temporary directory
1681
+ for i, plot in enumerate(plots):
1682
+ plot = plot.convert("RGB")
1683
+ plot_path = os.path.join(temp_dir, f"grid_{i:04d}.jpg")
1684
+ plot.save(plot_path)
1685
+ zipf.write(plot_path, f"grid_{i:04d}.jpg")
1686
+ finally:
1687
+ # Clean up the temporary directory
1688
+ for file in os.listdir(temp_dir):
1689
+ os.remove(os.path.join(temp_dir, file))
1690
+ os.rmdir(temp_dir)
1691
+
1692
+ # Schedule the deletion of the zip file after 24 hours (86400 seconds)
1693
+ delete_file_after_delay(zip_filename, 86400)
1694
+ gr.Info(f"File is ready for download: {os.path.basename(zip_filename)}")
1695
+ return gr.update(value=zip_filename, interactive=True)
1696
 
1697
+ with gr.Row():
1698
+ create_file_button = gr.Button("📦 Pack", elem_id="create_file_button", variant='secondary')
1699
+ download_button = gr.DownloadButton(label="📥 Download", value=None, variant='secondary', elem_id="download_button", interactive=False)
1700
+
1701
+ create_file_button.click(create_zip_file, inputs=[gallery], outputs=[download_button])
1702
+ def warn_on_click(filename):
1703
+ if filename is None:
1704
+ gr.Warning("No file to download, please `📦 Pack` first.")
1705
+ interactive = filename is not None
1706
+ return gr.update(interactive=interactive)
1707
+ download_button.click(warn_on_click, inputs=[download_button], outputs=[download_button])
1708
+
1709
+ return create_file_button, download_button
1710
+
1711
 
1712
  def make_output_images_section():
1713
  gr.Markdown('### Output Images')
 
1863
 
1864
  with gr.Row():
1865
  with gr.Column(scale=5, min_width=200):
1866
+ input_gallery, submit_button, clear_images_button, dataset_dropdown, num_images_slider, random_seed_slider, load_images_button = make_input_images_section(allow_download=True)
1867
  num_images_slider.value = 30
1868
  logging_text = gr.Textbox("Logging information", label="Logging", elem_id="logging", type="text", placeholder="Logging information", autofocus=False, autoscroll=False, lines=20)
1869
 
1870
  with gr.Column(scale=5, min_width=200):
1871
  output_gallery = make_output_images_section()
1872
+ add_download_button(output_gallery, "ncut_embed")
1873
  norm_gallery = gr.Gallery(value=[], label="Eigenvector Magnitude", show_label=True, elem_id="eig_norm", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
1874
+ add_download_button(norm_gallery, "eig_norm")
1875
  cluster_gallery = gr.Gallery(value=[], label="Clusters", show_label=True, elem_id="clusters", columns=[2], rows=[4], object_fit="contain", height=600, show_share_button=True, preview=True, interactive=False)
1876
+ add_download_button(cluster_gallery, "clusters")
1877
  [
1878
  model_dropdown, layer_slider, node_type_dropdown, num_eig_slider,
1879
  affinity_focal_gamma_slider, num_sample_ncut_slider, ncut_knn_slider, ncut_indirect_connection, ncut_make_orthogonal,
 
2035
 
2036
  with gr.Row():
2037
  with gr.Column(scale=5, min_width=200):
2038
+ input_gallery, submit_button, clear_images_button, dataset_dropdown, num_images_slider, random_seed_slider, load_images_button = make_input_images_section(allow_download=True)
2039
  num_images_slider.value = 100
2040
  logging_text = gr.Textbox("Logging information", label="Logging", elem_id="logging", type="text", placeholder="Logging information", lines=20)
2041
  with gr.Column(scale=5, min_width=200):
2042
  gr.Markdown('### Output (Recursion #1)')
2043
  l1_gallery = gr.Gallery(format='png', value=[], label="Recursion #1", show_label=True, elem_id="ncut_l1", columns=[3], rows=[5], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False)
2044
  add_output_images_buttons(l1_gallery)
2045
+ add_download_button(l1_gallery, "ncut_embed_recur1")
2046
  l1_norm_gallery = gr.Gallery(value=[], label="Recursion #1 Eigenvector Magnitude", show_label=True, elem_id="eig_norm", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
2047
+ add_download_button(l1_norm_gallery, "eig_norm_recur1")
2048
  l1_cluster_gallery = gr.Gallery(value=[], label="Recursion #1 Clusters", show_label=True, elem_id="clusters", columns=[2], rows=[4], object_fit="contain", height=500, show_share_button=True, preview=True, interactive=False)
2049
+ add_download_button(l1_cluster_gallery, "clusters_recur1")
2050
  with gr.Column(scale=5, min_width=200):
2051
  gr.Markdown('### Output (Recursion #2)')
2052
  l2_gallery = gr.Gallery(format='png', value=[], label="Recursion #2", show_label=True, elem_id="ncut_l2", columns=[3], rows=[5], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False)
2053
  add_output_images_buttons(l2_gallery)
2054
+ add_download_button(l2_gallery, "ncut_embed_recur2")
2055
  l2_norm_gallery = gr.Gallery(value=[], label="Recursion #2 Eigenvector Magnitude", show_label=True, elem_id="eig_norm", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
2056
+ add_download_button(l2_norm_gallery, "eig_norm_recur2")
2057
  l2_cluster_gallery = gr.Gallery(value=[], label="Recursion #2 Clusters", show_label=True, elem_id="clusters", columns=[2], rows=[4], object_fit="contain", height=500, show_share_button=True, preview=True, interactive=False)
2058
+ add_download_button(l2_cluster_gallery, "clusters_recur2")
2059
  with gr.Column(scale=5, min_width=200):
2060
  gr.Markdown('### Output (Recursion #3)')
2061
  l3_gallery = gr.Gallery(format='png', value=[], label="Recursion #3", show_label=True, elem_id="ncut_l3", columns=[3], rows=[5], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False)
2062
  add_output_images_buttons(l3_gallery)
2063
+ add_download_button(l3_gallery, "ncut_embed_recur3")
2064
  l3_norm_gallery = gr.Gallery(value=[], label="Recursion #3 Eigenvector Magnitude", show_label=True, elem_id="eig_norm", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
2065
+ add_download_button(l3_norm_gallery, "eig_norm_recur3")
2066
  l3_cluster_gallery = gr.Gallery(value=[], label="Recursion #3 Clusters", show_label=True, elem_id="clusters", columns=[2], rows=[4], object_fit="contain", height=500, show_share_button=True, preview=True, interactive=False)
2067
+ add_download_button(l3_cluster_gallery, "clusters_recur3")
2068
 
2069
  with gr.Row():
2070
  with gr.Column(scale=5, min_width=200):
 
2288
  gr.Markdown('### Output (Recursion #1)')
2289
  l1_gallery = gr.Gallery(format='png', value=[], label="Recursion #1", show_label=True, elem_id="ncut_l1", columns=[100], rows=[1], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False, preview=True)
2290
  add_output_images_buttons(l1_gallery)
2291
+ add_download_button(l1_gallery, "modelaligned_recur1")
2292
  gr.Markdown('### Output (Recursion #2)')
2293
  l2_gallery = gr.Gallery(format='png', value=[], label="Recursion #2", show_label=True, elem_id="ncut_l2", columns=[100], rows=[1], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False, preview=True)
2294
  add_output_images_buttons(l2_gallery)
2295
+ add_download_button(l2_gallery, "modelaligned_recur2")
2296
  gr.Markdown('### Output (Recursion #3)')
2297
  l3_gallery = gr.Gallery(format='png', value=[], label="Recursion #3", show_label=True, elem_id="ncut_l3", columns=[100], rows=[1], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False, preview=True)
2298
  add_output_images_buttons(l3_gallery)
2299
+ add_download_button(l3_gallery, "modelaligned_recur3")
2300
 
2301
  with gr.Row():
2302
  with gr.Column(scale=5, min_width=200):
2303
+ input_gallery, submit_button, clear_images_button, dataset_dropdown, num_images_slider, random_seed_slider, load_images_button = make_input_images_section(allow_download=True)
2304
  num_images_slider.value = 100
2305
 
2306
 
 
2437
  output_gallery = gr.Gallery(format='png', value=[], label="NCUT Embedding", show_label=True, elem_id=f"ncut{i_model}", columns=[3], rows=[1], object_fit="contain", height="auto", show_fullscreen_button=True, interactive=False)
2438
  submit_button = gr.Button("🔴 RUN", elem_id=f"submit_button{i_model}", variant='primary')
2439
  add_output_images_buttons(output_gallery)
2440
+ add_download_button(output_gallery, f"ncut_embed")
2441
  norm_gallery = gr.Gallery(value=[], label="Eigenvector Magnitude", show_label=True, elem_id=f"eig_norm{i_model}", columns=[3], rows=[1], object_fit="contain", height="auto", show_share_button=True, preview=False, interactive=False)
2442
+ add_download_button(norm_gallery, f"eig_norm")
2443
  cluster_gallery = gr.Gallery(value=[], label="Clusters", show_label=True, elem_id=f"clusters{i_model}", columns=[2], rows=[4], object_fit="contain", height=500, show_share_button=True, preview=True, interactive=False)
2444
+ add_download_button(cluster_gallery, f"clusters")
2445
  [
2446
  model_dropdown, layer_slider, node_type_dropdown, num_eig_slider,
2447
  affinity_focal_gamma_slider, num_sample_ncut_slider, ncut_knn_slider, ncut_indirect_connection, ncut_make_orthogonal,
 
2471
 
2472
  with gr.Row():
2473
  with gr.Column(scale=5, min_width=200):
2474
+ input_gallery, submit_button, clear_images_button, dataset_dropdown, num_images_slider, random_seed_slider, load_images_button = make_input_images_section(allow_download=True)
2475
  submit_button.visible = False
2476
 
2477