File size: 3,349 Bytes
fcbf272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f3760c3
 
 
 
 
 
 
 
 
fcbf272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""Reproduction for gradio-app/gradio#10107 - a plot in a chatbot remounts on every
streaming update.

1. Send `plot`. A bokeh chart appears in the conversation.
2. Send anything else, then watch the chat area while the reply streams.

Before the fix the chart flickers and the view flips between the top and the bottom
of the conversation on every streaming update. After the fix the chart stays put and
the view stays pinned to the bottom.
"""

import json
from time import sleep

import bokeh.plotting
import gradio as gr
from bokeh.embed import json_item
from gradio import ChatMessage
from gradio.components.plot import PlotData

AFTER_TEXT = "And this is the reply that streams once the plot is on screen."


def bokeh_plot():
    fig = bokeh.plotting.figure(title="Title", width=1500)
    fig.line(x=[1, 2, 3, 4], y=[1, 2, 3, 4])
    # Serialized here rather than handing the figure to gr.Plot: Chatbot._postprocess
    # deepcopies the message and bokeh figures are not deepcopy-able (#13675). That is
    # a separate bug and not what this Space demonstrates.
    return PlotData(type="bokeh", plot=json.dumps(json_item(fig)))


def add_message(history, message):
    history.append(ChatMessage(role="user", content=message))
    return history, message


def bot_stream(history, input_msg):
    msg = ChatMessage(role="assistant", content="")
    history.append(msg)
    for c in "Text before plot":
        msg.content += c
        yield history
        sleep(0.05)

    if input_msg.strip().lower() == "plot":
        history.append(ChatMessage(role="assistant", content=gr.Plot(bokeh_plot())))
        yield history

    msg2 = ChatMessage(role="assistant", content="")
    history.append(msg2)
    for c in AFTER_TEXT:
        msg2.content += c
        yield history
        sleep(0.06)


with gr.Blocks(fill_height=True, fill_width=True) as demo:
    gr.Markdown(
        "### gradio-app/gradio#10107\n"
        "1. Send `plot`. A bokeh chart appears in the conversation.\n"
        "2. Send anything else, then watch the chat area while the reply streams.\n\n"
        "**Before the fix**: the chart flickers and the view flips between the top "
        "and the bottom on every streaming update. "
        "**After the fix**: the chart stays put and the view stays pinned to the bottom."
    )

    # scale + fill_height is what lets the chat area grow; height alone would pin it
    # to 200px and the 600px bokeh chart would barely fit in the viewport.
    chatbot = gr.Chatbot(
        label="Chatbot",
        elem_id="chatbot",
        scale=5,
        height=200,
        min_width=200,
    )

    with gr.Group():
        with gr.Row():
            chat_input = gr.Textbox(
                container=False,
                show_label=False,
                placeholder="Type `plot`, send it, then send anything else...",
                scale=7,
                autofocus=True,
            )
            submit_btn = gr.Button("Send", scale=1)

    for listener in [chat_input.submit, submit_btn.click]:
        chat_msg = listener(add_message, [chatbot, chat_input], [chatbot, chat_input])
        chat_msg.then(bot_stream, [chatbot, chat_input], chatbot)


# SSR is disabled deliberately: preview wheels have shipped with a broken SSR server
# bundle, and this repro has nothing to do with SSR.
demo.launch(ssr_mode=False)