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
34.24k stars 2.6k forks source link

[Dynamic render] - ASGI application Exception when try executing event in .then() handler. #9595

Open elismasilva opened 1 month ago

elismasilva commented 1 month ago

Describe the bug

Hi guys i am getting error when events inside dynamic render are triggered and they have .then() to some function. I think is some problem of async sincronism, because some time works. I have debuged the code and i noticed that in queueing.py on push method:

 if body.session_hash:
            session_state = self.blocks.state_holder[body.session_hash]
            fn = session_state.blocks_config.fns[body.fn_index]
        else:
            fn = self.blocks.fns[body.fn_index]

when it try return the function from collection it not exists anymore. maybe because elements are removed from render before the function is called.

Have you searched existing issues? πŸ”Ž

Reproduction

Try add a controlnet, and then remove it on X button, do it more than twice util errors happen,

My remove_controlnet.click() is calling in then update_reference_elements() function where errors occours. here is my app to test.

import time
import gradio as gr

selected_controlnets=[]
controlnet_scales=[]
CONTROLNETS = ["canny", "pose"]

def clean_status(current_status):    
    if current_status is not None and current_status != '':
        time.sleep(5)

    return None

def click_add_controlnet(controlnet):    
    if controlnet not in selected_controlnets:
        selected_controlnets.append(controlnet)                                                        
        return selected_controlnets, None
    else:                                                                                                                        
        return selected_controlnets, "This model has already been added!"

def submit_button(progress=gr.Progress(track_tqdm=True)):
    print('Testing')
    for i in controlnet_scales:
        print(f"key: {i.key[8:]}, value:{i.value}")

    return "See the result in the terminal!"

def update_reference_elements():
    outputs=[*[gr.update(visible=False)] * 2]

    for c in selected_controlnets:        
        if c == 'canny':
            outputs[0]=gr.update(visible=True)             
        if c == 'pose':
            outputs[1]=gr.update(visible=True)                               

    return outputs
with gr.Blocks(analytics_enabled=False) as app:                                    
    with gr.Row():
        with gr.Column(scale=0.4, min_width=100):
            controlnet_models = gr.Dropdown(label="Control Type", choices=CONTROLNETS, value=CONTROLNETS[0])
        with gr.Column(scale=0, min_width=50):
            refresh_controlnet = gr.Button(value="Refresh", elem_id="controlnet_refresh_button")
        with gr.Column(scale=0, min_width=50):                                                
            add_controlnet = gr.Button(value="+", elem_id="add_controlnet_button")
        with gr.Column(scale=0, min_width=50):                                                
            submit_test = gr.Button(value="Submit", elem_id="submit_button" )
    with gr.Row():
        status = gr.Textbox(label="Status", value="", show_label=False)
    with gr.Row():                                              
        with gr.Column():                                                                                                        
            selected_controlnet_state= gr.State(value=selected_controlnets)                                           

            @gr.render(inputs=selected_controlnet_state)
            def render_loras(selected): 
                global controlnet_scales                                                 
                with gr.Row(elem_id="control_row"):                                                        
                    for i in range(len(selected)):   
                        control_name = selected[i]                                                                                                                     
                        with gr.Column(variant="panel", min_width=300):
                            with gr.Row():
                                with gr.Column(min_width=300):                                            
                                    remove_controlnet = gr.Button(value="X", key=f"remove-control-{control_name}", elem_classes="remove-button vertical-center")
                                    controlnet = gr.Textbox(label="File name", value=f"{control_name}", key=f"label-{control_name}", show_label=True)                                                                
                                    control_scale = gr.Slider(                                                                            
                                        interactive=True,
                                        minimum=0.1,
                                        maximum=2.0,
                                        step=0.01,
                                        value=0.1,
                                        label="Control scale", 
                                        key=f"scale-{control_name}")                                                                

                            def click_remove_controlnet(value, canny_image, pose_image, controlnet=control_name):                                                                    
                                for l in range(len(controlnet_scales)):
                                    if controlnet in controlnet_scales[l].key:
                                        controlnet_scales.pop(l)
                                        break

                                selected_controlnets.pop(selected_controlnets.index(value))
                                canny_value=None if value == 'canny'else canny_image
                                pose_value=None if value == 'pose' else pose_image

                                return selected_controlnets, gr.update(value=canny_value), gr.update(value=pose_value), f"Control {value} removed!"

                            remove_controlnet.click(fn=click_remove_controlnet, inputs=[controlnet, canny_image, pose_image], outputs=[selected_controlnet_state, canny_image, pose_image, status]) \
                                .then(fn=update_reference_elements, outputs=[col_canny_image, col_pose_image]) \
                                .then(fn=clean_status, inputs=status)

                            def change_control_scale(value, controlnet=control_name):
                                for l in range(len(controlnet_scales)):
                                    if controlnet in controlnet_scales[l].key:
                                        controlnet_scales[l].value=value                                                                    

                            control_scale.release(fn=change_control_scale, inputs=control_scale)                                                               

                            hasControlnet = False
                            for l in range(len(controlnet_scales)):
                                if control_name in controlnet_scales[l].key:
                                    hasControlnet = True
                                    break
                            if not hasControlnet:
                                    controlnet_scales.append(control_scale)    
    with gr.Row():
        with gr.Column(scale=0, min_width=300, visible=False) as col_canny_image:
            with gr.Row():                
                canny_image = gr.Image(label="Image for canny", elem_classes="ipa", visible=True, streaming=False)
        with gr.Column(scale=0, min_width=300, visible=False) as col_pose_image:
            with gr.Row():                
                pose_image = gr.Image(label="Image for pose", elem_classes="ipa", visible=True, streaming=False)

    add_controlnet.click(fn=click_add_controlnet, inputs=controlnet_models, outputs=[selected_controlnet_state, status]) \
       .then(fn=update_reference_elements, outputs=[col_canny_image, col_pose_image]) \

    submit_test.click(           
        fn=submit_button,        
        outputs=status)

app.launch(inbrowser=True)
``

Screenshot

N/A

Logs

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 398, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 70, in __call__
    return await self.app(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\fastapi\applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\middleware\errors.py", line 186, in __call__
    raise exc
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\gradio\route_utils.py", line 767, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\gradio\route_utils.py", line 783, in simple_response
    await self.app(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\middleware\exceptions.py", line 65, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\routing.py", line 297, in handle
    await self.app(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\routing.py", line 77, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\starlette\routing.py", line 72, in app
    response = await func(request)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\fastapi\routing.py", line 278, in app
    raw_response = await run_endpoint_function(
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\fastapi\routing.py", line 191, in run_endpoint_function
    return await dependant.call(**values)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\gradio\routes.py", line 833, in queue_join
    return await queue_join_helper(body, request, username)
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\gradio\routes.py", line 851, in queue_join_helper
    success, event_id = await blocks._queue.push(
  File "f:\Projetos\DiffusersWebUI\venv\lib\site-packages\gradio\queueing.py", line 207, in push
    fn = session_state.blocks_config.fns[body.fn_index]
KeyError: 146

System Info

Gradio Environment Information:
------------------------------
Operating System: Windows
gradio version: 4.44.1
gradio_client version: 1.3.0

------------------------------------------------
gradio dependencies in your environment:

aiofiles: 23.2.1
anyio: 4.4.0
fastapi: 0.112.0
ffmpy: 0.4.0
gradio-client==1.3.0 is not installed.
httpx: 0.27.0
huggingface-hub: 0.24.5
importlib-resources: 6.4.0
jinja2: 3.1.3
markupsafe: 2.1.5
matplotlib: 3.9.0
numpy: 1.26.3
orjson: 3.10.6
packaging: 24.1
pandas: 2.2.2
pillow: 10.2.0
pydantic: 2.8.2
pydub: 0.25.1
python-multipart: 0.0.9
pyyaml: 6.0.1
ruff: 0.5.6
semantic-version: 2.10.0
tomlkit==0.12.0 is not installed.
typer: 0.12.3
typing-extensions: 4.12.2
urllib3: 2.2.2
uvicorn: 0.30.5
authlib; extra == 'oauth' is not installed.
itsdangerous; extra == 'oauth' is not installed.

gradio_client dependencies in your environment:

fsspec: 2024.2.0
httpx: 0.27.0
huggingface-hub: 0.24.5
packaging: 24.1
typing-extensions: 4.12.2
websockets: 12.0

Severity

Blocking usage of gradio

Littleele commented 1 month ago

same issue