Fix Download From Gradio < Download From Streamlit?

About 8 of 12 months this year I have been practicing apps in streamlit. I started with gradio on HF & felt with Blocks a new important style emerged.

When I go to do everything in gradio that I can do in streamlit, there is one glaring obscurity about Gradio Blocks - the Download feature.

For example in this space: 4๐Ÿ“RT๐Ÿ–ผ๏ธImages - a Hugging Face Space by awacke1

There are a few lines of code to generate a zip file. Next I would like to add a button or base64 link for the created and saved file.

However if I use gr.HTML for the base 64 link it doesnโ€™t inject the HTML so while it runs, the link doesnโ€™t appear in output the way it would in streamlit.

Next if I try a File object, that works for the functions but if I want to change the file at runtime it doesnโ€™t seem to update so that was a dead end for me too.

Sample code for HTML link:

def get_zip_download_link(zip_file):
โ€œโ€"
Generate a link to download the zip file.
โ€œโ€"
with open(zip_file, โ€˜rbโ€™) as f:
data = f.read()
b64 = base64.b64encode(data).decode()
href = fโ€™Download Allโ€™
return href

What am I doing wrong and can you share a good working example of a Download link injected at end of events in gr.Blocks flow? Below is mine:

with gr.Blocks(css=css) as demo:

    with gr.Column(elem_id="container"):
        gr.Markdown(
            """4๐Ÿ“RT๐Ÿ–ผ๏ธImages - ๐Ÿ•น๏ธ Real Time ๐ŸŽจ Image Generator Gallery ๐ŸŒ""",
            elem_id="intro",
        )
        with gr.Row():
            with gr.Row():
                prompt = gr.Textbox(
                    placeholder="Insert your prompt here:", scale=5, container=False
                )
                generate_bt = gr.Button("Generate", scale=1)

        # Image Result from last prompt
        image = gr.Image(type="filepath")

        # Gallery of Generated Images with Image Names in Random Set to Download
        with gr.Row(variant="compact"):
            text = gr.Textbox(
                label="Image Sets",
                show_label=False,
                max_lines=1,
                placeholder="Enter your prompt",
            )
            btn = gr.Button("Generate Gallery of Saved Images")
        gallery = gr.Gallery(
            label="Generated Images", show_label=False, elem_id="gallery"
        )

        with gr.Row(variant="compact"):
            # Add "Save All" button with emoji
            save_all_button = gr.Button("๐Ÿ’พ Save All", scale=1)
            # Add "Clear All" button with emoji
            clear_all_button = gr.Button("๐Ÿ—‘๏ธ Clear All", scale=1)

        # Advanced Generate Options
        with gr.Accordion("Advanced options", open=False):
            guidance = gr.Slider(
                label="Guidance", minimum=0.0, maximum=5, value=0.3, step=0.001
            )
            steps = gr.Slider(label="Steps", value=4, minimum=2, maximum=10, step=1)
            seed = gr.Slider(
                randomize=True, minimum=0, maximum=12013012031030, label="Seed", step=1
            )

        # Diffusers
        with gr.Accordion("Run with diffusers"):
            gr.Markdown(
                """## Running LCM-LoRAs it with `diffusers`
            ```bash
            pip install diffusers==0.23.0
            ```
            
            ```py
            from diffusers import DiffusionPipeline, LCMScheduler
            pipe = DiffusionPipeline.from_pretrained("Lykon/dreamshaper-7").to("cuda") 
            pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
            pipe.load_lora_weights("latent-consistency/lcm-lora-sdv1-5") #yes, it's a normal LoRA
            results = pipe(
                prompt="ImageEditor",
                num_inference_steps=4,
                guidance_scale=0.0,
            )
            results.images[0]
            ```
            """
            )

        # Function IO Eventing and Controls
        inputs = [prompt, guidance, steps, seed]
        generate_bt.click(fn=predict, inputs=inputs, outputs=image, show_progress=False)
        btn.click(fake_gan, None, gallery)
        prompt.input(fn=predict, inputs=inputs, outputs=image, show_progress=False)
        guidance.change(fn=predict, inputs=inputs, outputs=image, show_progress=False)
        steps.change(fn=predict, inputs=inputs, outputs=image, show_progress=False)
        seed.change(fn=predict, inputs=inputs, outputs=image, show_progress=False)

        # Attach click event handlers to the buttons
        save_all_button.click(save_all_button_click)

        with gr.Column():
            file_obj = gr.File(label="Input File")
            input= file_obj
                    
        clear_all_button.click(clear_all_button_click)

demo.queue()
demo.launch()