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
33.78k stars 2.56k forks source link

How to return `None` from a JS function to a `gr.Image` #3654

Open oobabooga opened 1 year ago

oobabooga commented 1 year ago

Describe the bug

Until gradio==3.18.0, I could do demo.close() for a gr.Blocks() interface.

In gradio==3.23.0, I get the error below every time. This error is not an exception that I can catch. The program simply hangs and I have to force exit it.

Is there an existing issue for this?

Reproduction

I haven't been able to build a minimal working example yet.

My code uses demo.queue() which I think is probably relevant.

Screenshot

No response

Logs

Task exception was never retrieved
future: <Task finished name='x0b1i7r0z1_17' coro=<Queue.process_events() done, defined at /home/me/miniconda3/envs/textgen/lib/python3.10/site-packages/gradio/queueing.py:343> exception=ValidationError(model='PredictBody', errors=[{'loc': ('data',), 'msg': 'field required', 'type': 'value_error.missing'}])>
Traceback (most recent call last):
  File "/home/me/miniconda3/envs/textgen/lib/python3.10/site-packages/gradio/queueing.py", line 347, in process_events
    client_awake = await self.gather_event_data(event)
  File "/home/me/miniconda3/envs/textgen/lib/python3.10/site-packages/gradio/queueing.py", line 220, in gather_event_data
    data, client_awake = await self.get_message(event, timeout=receive_timeout)
  File "/home/me/miniconda3/envs/textgen/lib/python3.10/site-packages/gradio/queueing.py", line 456, in get_message
    return PredictBody(**data), True
  File "pydantic/main.py", line 341, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for PredictBody
data
  field required (type=value_error.missing)

System Info

gradio==3.23.0

Severity

annoying

abidlabs commented 1 year ago

Hi @oobabooga I tried reproducing this error, but can't with a simple example: https://colab.research.google.com/drive/1dY9-AB21Oy-BDmAi4QSCt1zgkkHUJpSP?usp=sharing

Any more details you could share to help us reproduce this?

oobabooga commented 1 year ago

@abidlabs, after some tinkering, I have produced the following minimal working example:

import time

import gradio as gr

title ='Text generation web UI'
need_restart = False

def set_interface_arguments():
    global need_restart
    need_restart = True
    return

def create_interface():
    with gr.Blocks(analytics_enabled=False) as interface:
        reset_interface = gr.Button("Apply and restart the interface", type="primary")

        reset_interface.click(set_interface_arguments, None, None)
        reset_interface.click(lambda : None, None, None, _js='() => {document.body.innerHTML=\'<h1 style="font-family:monospace;margin-top:20%;color:lightgray;text-align:center;">Reloading...</h1>\'; setTimeout(function(){location.reload()},2500)}')

    # Launch the interface
    interface.queue()
    interface.launch(prevent_thread_lock=True, server_name='0.0.0.0')

    return interface

interface = create_interface()

while True:
    time.sleep(0.5)
    if need_restart:
        need_restart = False
        interface.close()
        interface = create_interface()

The reproduction steps are as follows. Note that the error happens about 80% of the time to me. If it doesn't happen in the first try, restart the interface and try again.

  1. Save the file above as minimal.py
  2. Start it with python minimal.py
  3. Access the web UI
  4. Click on "Apply and restart the interface"
  5. The web UI hangs and the following error appears:
To create a public link, set `share=True` in `launch()`.
Task exception was never retrieved
future: <Task finished name='oexjvfvfzn_1' coro=<Queue.process_events() done, defined at /home/me/miniconda3/envs/textgen/lib/python3.10/site-packages/gradio/queueing.py:343> exception=ValidationError(model='PredictBody', errors=[{'loc': ('data',), 'msg': 'field required', 'type': 'value_error.missing'}])>
Traceback (most recent call last):
  File "/home/me/miniconda3/envs/textgen/lib/python3.10/site-packages/gradio/queueing.py", line 347, in process_events
    client_awake = await self.gather_event_data(event)
  File "/home/me/miniconda3/envs/textgen/lib/python3.10/site-packages/gradio/queueing.py", line 220, in gather_event_data
    data, client_awake = await self.get_message(event, timeout=receive_timeout)
  File "/home/me/miniconda3/envs/textgen/lib/python3.10/site-packages/gradio/queueing.py", line 456, in get_message
    return PredictBody(**data), True
  File "pydantic/main.py", line 341, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for PredictBody
data
  field required (type=value_error.missing)
space-nuko commented 1 year ago

I tested it, the problem seems to go away if you add a return []; to the end of the JS

It seems like this code receives v as undefined from the return value of your JS function

https://github.com/gradio-app/gradio/blob/becada8795a07c5845aead34721c1f3fc2954131/js/app/src/Blocks.svelte#L282-L295

Which means there's no payload.data on the JSON the backend receives so it throws that error

oobabooga commented 1 year ago

Thank you so much @space-nuko, that worked!

space-nuko commented 1 year ago

By the way this also happens when the return value is null, however there are legitimate usecases for that like sending None to a gr.Image

What should be the best way of handing this @abidlabs ? Wrapping it in an array? Defaulting to an empty array when possible?