gradio-app / gradio

Build and share delightful machine learning apps, all in Python. 🌟 Star to support our work!
http://www.gradio.app
Apache License 2.0
30.37k stars 2.26k forks source link

Add Progress Bar component #2750

Closed aliabid94 closed 1 year ago

aliabid94 commented 1 year ago

Add support for progressbar component. Feel free to leave feedback on API or visual design.

See example in demo/progress/run.py

Snippet for tqdm-like wrapper

def load_set(text, progress=gr.Progress()):
        imgs = [None] * 24
        for img in progress.tqdm(imgs, message="Loading from list"):
            time.sleep(0.1)
        return "done"
    load_set_btn.click(load_set, text, text2)

Snippet for explicit status:

def clean_imgs(text, progress=gr.Progress()):
        progress(0.2, message="Collecting Images")
        time.sleep(1)
        progress(0.5, message="Cleaning Images")
        time.sleep(1.5)
        progress(0.8, message="Sending Images")
        time.sleep(1.5)
        return "done"
    clean_imgs_btn.click(clean_imgs, text, text2)

Recording 2022-11-30 at 18 01 51

Closes: #340

github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

All the demos for this PR have been deployed at https://huggingface.co/spaces/gradio-pr-deploys/pr-2750-all-demos

abidlabs commented 1 year ago

That was fast @aliabid94! Backend code looks good (left some nits), but will let @pngwn or @gary149 advise on the frontend and design.

Can we release a beta version with this so that @apolinario can use it for dreambooth?

github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
abidlabs commented 1 year ago

Discussed further with @aliabid94 and we're rethinking this approach. Rather than ProgressBar being a separate component, it would make more sense to utilize the ETA status tracker that we have already implemented. The alternative approach would allow functions to yield a special type of "progress update" (syntax TBD) that would serve as a manual update of the ETA in the status bar. This would also be reflected in the progress bar that is built-in to each component.

That being said, we've released gradio==3.12.0b1 in case you want to use this stopgap progress bar @apolinario. (Also @apolinario would be interested in hearing your thoughts on these two options)

apolinario commented 1 year ago

First of all: thanks for turning this around in record time! Some thoughts:

aliabid94 commented 1 year ago

Oh I really like the idea of tqdm integration, will look into that!

abidlabs commented 1 year ago

+1 on the tqdm integration

Not sure about having two different ways of showing progress bars though. I prefer having a single way unless there is a strong advantage to have a separate progress bar component. I know AUTOMATIC1111 GUI has a progress bar, but wouldn't it be better if the progress bar is incorporated into the output component itself, as is our current status tracker?

pngwn commented 1 year ago

I'm a bit confused here. The StatusTracker is a progress bar just the styling is different. If we want to change the styling then that is a separate issue.

I thought the requests we have had a few times is for a separate ProgressBar, like in the SD WebGUI, but I do think that it should be bound to an event and receive the same data as the built in status tracker, currenttime / eta with queue position / queue size all included, otherwise I don't really see the usefulness of this. Since everything happens on the server what would be timed if not the duration of an event? And if it is a bar rather than an infinite spinner, how would a user be able to provide an accurate estimated 100% value for the bar to 'complete'?

pngwn commented 1 year ago

I know AUTOMATIC1111 GUI has a progress bar, but wouldn't it be better if the progress bar is incorporated into the output component itself, as is our current status tracker?

This has really been my position all along but as above, the StatusTracker is a progress bar. The only value of the request is if it is standalone, otherwise is just a reskin which we can support in userland in the future via custom components but I certainly don't think we should have multiple styles of the built in loading indicator in core.

abidlabs commented 1 year ago

Yes so to summarize my takeaways:

How does that sound @aliabid94?

github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
pngwn commented 1 year ago

Thing is with tqdm is that this isn't really true:

This is just a default way to do progress bar that is so simple and it contains so much information (it/s, progress %, ETA) that recreating it with yields would be a bit laborious

We would have to pass that information down to the component and render it in some way, so we'd need to support a vast array of inputs in the UI. We aren't just taking the default tqdm output and rendering it directly into the webpage somehow, we need to take the data is spits out and do something with it.

I'm strongly against dumping the stdout text into the page, i think it looks really bad and goes against the whole point of gradio. These UIs are for anyone, not just people familiar with typical CLI outputs. This needs designing properly before being included. cc @gary149

If we are going to add this can we get some API + design proposals as well as breakdown of the various possible bits of UI that we would render based on the tqdm options the user passes?

abidlabs commented 1 year ago

I'm strongly against dumping the stdout text into the page, i think it looks really bad and goes against the whole point of gradio. These UIs are for anyone, not just people familiar with typical CLI outputs. This needs designing properly before being included. cc @gary149

Not sure I follow @pngwn. We wouldn't display the raw progress bar that tqdm prints. We would extract the information and plug that into our existing status tracker. So the output would look pretty much the same.

pngwn commented 1 year ago

But even dumping the text isn't great either, what works in a CLI tool isn't a great experience for end users. And that means we need to match the tqdm API if we want to support it fully.

apolinario commented 1 year ago

@pngwn there's a TQDM Notebook class that afaik exposes some of the outputs for the programs to use, I don't really know how it works under the hood but could potentially be used for this: https://tqdm.github.io/docs/notebook/

Regarding the progress bar. I still see how it could be interesting for users to choose whether their output is in a progress bar or on the output field. I think there's room for both, but I agree this may make sense as a custom/user component. But just FYI if I had to choose between a custom progress bar or a native one on the output field for this particular demo I would choose a custom progress bar

pngwn commented 1 year ago

The big issue with a custom component ProgressBar is that we currently don't have a mechanism to pass anything but the output components the current progress of a request/ queue request. We'll need to build in more flexibility to be able to do that.

aliabid94 commented 1 year ago

To summarize:

Here's a possible implementation:

import gradio as gr
import img_model

with gr.Blocks() as demo:
     prompt = gr.Textbox(label="Enter text")
     img = gr.Image()

     def load_image(data):
          total_steps = 50
          for step in img_model.load():
               # ...
               yield gr.Status(step / total_steps, text="Loading model")
          return img_model(data[prompt])

     prompt.submit(load_image, {prompt}, img)

demo.queue().launch()

which would look something like:

Screen Shot 2022-12-05 at 2 04 48 PM

For a tqdm-like wrapper, we could have:

import gradio as gr
import img_model

with gr.Blocks() as demo:
     prompt = gr.Textbox(label="Enter text")
     img = gr.Image()

     def load_image(data):
          total_steps = 50
          for _ in gr.Track(img_model.load()):
               # ...
               yield gr.Status(text="Loading model")
          return img_model(data[prompt])

     prompt.submit(load_image, {prompt}, img)

demo.queue().launch()

where the gr.Track can automatically keep track of length and progress, and yielding a gr.Status() will automatically get that information.

abidlabs commented 1 year ago

For the tqdm integration, it would be better if users can somehow return or yield the tqdm object itself so that people don’t have to learn a new syntax. Users are already using tqdm in their code so it would be better if we integrated with tqdm instead of offering a replacement

aliabid94 commented 1 year ago

Yeah I thought about that but in the syntax

for obj in tqdm(objects):
   yield ...

there isn't really access to the tqdm object within the loop, so not sure how to yield it

aliabid94 commented 1 year ago

the other reason not to use tqdm is that we would then have the users printing to the console as a result of using tqdm. If multiple users are being processed at once, the output will get ugly

abidlabs commented 1 year ago

there isn't really access to the tqdm object within the loop, so not sure how to yield it

So tqdm(iterable) returns a new iterable, and this contains all of the info you'd need. Here's a complete example:

from tqdm import tqdm

# Create a list of numbers to iterate over
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Create a tqdm object to track the progress of the iteration
pbar = tqdm(numbers)

# Iterate over the list of numbers
for number in pbar:
    time.sleep(0.5)
    # Print the current status of the tqdm object
    print("current_iteration", pbar.n)
    print("out of", pbar.total)
abidlabs commented 1 year ago

the other reason not to use tqdm is that we would then have the users printing to the console as a result of using tqdm. If multiple users are being processed at once, the output will get ugly

That's not really a problem -- I don't think people care too much about the console

The main thing is that people are already using tqdm and so forcing them to switch to something else so that their function works with Gradio is not ideal (cc @apolinario for your thoughts too)

abidlabs commented 1 year ago

Question about the gr.Status implementation, would this replace gr.ProgressBar?

apolinario commented 1 year ago

The main thing is that people are already using tqdm and so forcing them to switch to something else so that their function works with Gradio is not ideal (cc @apolinario for your thoughts too)

I agree. Also there's quite a bit of people that re-use the same code for Colab and Gradio demos, so if tqdm worked for both that would be great.

Also, in quite a bit of occasions, the user does not have control over the loop/code that uses tqdm, they build a Gradio demo on an external function/library that contains the loop already (with tqdm), so it would be very laborious for the user to interject and change that

the other reason not to use tqdm is that we would then have the users printing to the console as a result of using tqdm. If multiple users are being processed at once, the output will get ugly

FYI this already happens on most Spaces that have generative media that I come across/build - leaving tqdm there by default. However most of them have queues (otherwise they OOM if multiple parallel requests happen) so the logs don't get that messy/overlappy and it is usually good to be able to track usage

apolinario commented 1 year ago

Another real life example that just happened to me, that makes me thing how integrating with tqdm would be great:

I would like to integrate the snapshot_download function from huggingface_hub with a Gradio progress bar. Without native integration, I would need to fork huggingface_hub just to inject Gradio integration (or capture the terminal output and throw some yields), but if Gradio can bind to already existing tqdm from other functions that automatically spit in progress bars, that would be incredibly awesome

github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
github-actions[bot] commented 1 year ago

The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:

pip install nbformat && cd demo && python generate_notebooks.py
abidlabs commented 1 year ago

Very cool @aliabid94. Going through this PR bit by bit and leaving my comments here:

abidlabs commented 1 year ago

When run without queuing enabled, I get the following:

AttributeError: 'Interface' object has no attribute '_queue'

May want to catch this and tell users to enable queueing

abidlabs commented 1 year ago

When I run this:

import gradio as gr
import time

progress = gr.Progress()

def test(x, progress=progress):
    for i in range(10):
        time.sleep(0.3)
        progress(i/10)
    return x

gr.Interface(test, "number", "number").queue().launch()

it works great, but what is the "0 steps" that it shows on the top right?

image