"""Reproduction for gradio-app/gradio#13675. Three ways a Gradio component used as chat content breaks: 1. Any component built inside a `with gr.Blocks()` block. On a broken release this raises before the app starts, so it is checked here in a try/except and the outcome is shown in the app. 2. A `gr.Plot` holding a bokeh figure returned from a chat function. 3. The same plot wrapped in a `gr.ChatMessage` so it renders as a thought, which takes a different route out of the chat function. On a broken release, sending a message fails. Which deep copy raises first depends on what the chat function returns: a bare component blows up in the queue after the prediction, so the browser gets no reply at all and the spinner keeps going, while a component wrapped in a `gr.ChatMessage` blows up inside the prediction and surfaces as an error. """ import bokeh.plotting import gradio as gr def check_component_as_initial_value() -> str: try: with gr.Blocks(): message = {"role": "assistant", "content": gr.Plot()} gr.Chatbot(value=[message]) return "**Case 1** — a component in a `gr.Chatbot`'s initial value: **works**" except Exception as e: return ( "**Case 1** — a component in a `gr.Chatbot`'s initial value: " f"**fails** with `{type(e).__name__}: {e}`" ) def make_plot(): fig = bokeh.plotting.figure(title="Bokeh plot in a chat message", width=600) fig.line(x=[1, 2, 3, 4], y=[1, 4, 9, 16]) return gr.Plot(fig) def respond(message, history): return [ gr.ChatMessage(role="assistant", content="Case 2 — a bare `gr.Plot`:"), make_plot(), gr.ChatMessage( role="assistant", content=make_plot(), metadata={"title": "Case 3 — the same plot as a thought"}, ), ] demo = gr.ChatInterface( respond, title="gradio#13675 — a Gradio component as chat content", description=( check_component_as_initial_value() + "\n\n**Cases 2 and 3** — send any message. On a broken release the " "request fails; once fixed, two plots appear, one as a normal message " "and one inside a thought." ), ) if __name__ == "__main__": demo.launch(ssr_mode=False)