import panel as pn
from panel.widgets import ChatInterface
pn.extension()
The ChatInterface
is a high-level widget, providing a user-friendly front-end interface for inputting different kinds of messages: text, images, PDFs, etc.
This widget provides front-end methods to:
user
input ChatEntry
.user
input ChatEntry
.ChatEntry
objects.Since ChatInterface
inherits from ChatFeed
, it features all the capabilities of ChatFeed
; please see ChatFeed.ipynb for its backend capabilities.
widgets
(Widget | List[Widget]
): Widgets to use for the input. If not provided, defaults to [TextInput]
.user
(str
): Name of the ChatInterface user.avatar
(str | BinaryIO
): The avatar to use for the user. Can be a single character text, an emoji, or anything supported by pn.pane.Image
. If not set, uses the first character of the name.reset_on_send
(bool
): Whether to reset the widget's value after sending a message; has no effect for TextInput
.auto_send_types
(tuple
): The widget types to automatically send when the user presses enter or clicks away from the widget. If not provided, defaults to [TextInput]
.show_send
(bool
): Whether to show the send button. Default is True.show_rerun
(bool
): Whether to show the rerun button. Default is True.show_undo
(bool
): Whether to show the undo button. Default is True.show_clear
(bool
): Whether to show the clear button. Default is True.show_button_name
(bool
): Whether to show the button name. Default is True.active_widget
(Widget
): The currently active widget.active
(int
): The currently active input widget tab index; -1 if there is only one widget available which is not in a tab.ChatInterface()
Although ChatInterface
can be initialized without any arguments, it becomes much more useful, and interesting, with a callback
.
def even_or_odd(contents, user, instance):
if len(contents) % 2 == 0:
return "Even number of characters."
return "Odd number of characters."
ChatInterface(callback=even_or_odd)
You may also provide a more relevant, default user
name and avatar
.
ChatInterface(
callback=even_or_odd,
user="Asker",
avatar="?",
callback_user="Counter",
)
You can also use a different type of widget for input, like TextAreaInput
instead of TextInput
, by setting widgets
.
def count_chars(contents, user, instance):
return f"Found {len(contents)} characters."
ChatInterface(
callback=count_chars,
widgets=pn.widgets.TextAreaInput(placeholder="Enter some text to get a count!"),
)
Multiple widgets
can be set, which will be nested under a Tabs
layout.
def get_num(contents, user, instance):
if isinstance(contents, str):
num = len(contents)
else:
num = contents
return f"Got {num}."
ChatInterface(
callback=get_num,
widgets=[
pn.widgets.TextAreaInput(placeholder="Enter some text to get a count!"),
pn.widgets.IntSlider(name="Number Input", end=10)
],
)
Widgets other than TextInput
will require the user to manually click the Send
button, unless the type is specified in auto_send_types
.
ChatInterface(
callback=get_num,
widgets=[
pn.widgets.TextAreaInput(placeholder="Enter some text to get a count!"),
pn.widgets.IntSlider(name="Number Input", end=10)
],
auto_send_types=[pn.widgets.IntSlider],
)
If you include a FileInput
in the list of widgets you can enable the user to upload files.
ChatInterface(widgets=pn.widgets.FileInput(name="CSV File", accept=".csv"))
Try uploading a dataset! If you don't have a dataset in hand, download this sample dataset, penguins.csv
.
Note, if you don't like the default renderer, pn.pane.DataFrame
for CSVs, you can specify renderers
to use pn.pane.Perspective
; just be sure you have the extension added!
pn.extension("perspective")
ChatInterface(
widgets=pn.widgets.FileInput(name="CSV File", accept=".csv"),
renderers=pn.pane.Perspective
)
If a list is provided to renderers
, will attempt to use the first renderer that does not raise an exception.
In addition, you may render the input however you'd like with a custom renderer as long as the signature accepts one argument, namely value
!
def bad_renderer(value):
raise Exception("Won't render using this...")
def custom_renderer(value):
return pn.Column(
f"Found {len(value)} rows in the CSV.",
pn.pane.Perspective(value, height=600)
)
ChatInterface(
widgets=pn.widgets.FileInput(name="CSV File", accept=".csv"),
renderers=[bad_renderer, custom_renderer]
)
If you'd like to guide the user into using one widget after another, you can set active
in the callback.
def guided_get_num(contents, user, instance):
if isinstance(contents, str):
num = len(contents)
instance.active = 1 # change to IntSlider tab
else:
num = contents
instance.active = 0 # Change to TextAreaInput tab
return f"Got {num}."
pn.widgets.ChatInterface(
callback=guided_get_num,
widgets=[
pn.widgets.TextAreaInput(placeholder="Enter some text to get a count!"),
pn.widgets.IntSlider(name="Number Input", end=10)
],
)
Or, simply initialize with a single widget first, then replace with another widget in the callback.
def get_num_guided(contents, user, instance):
if isinstance(contents, str):
num = len(contents)
instance.widgets = [widgets[1]] # change to IntSlider
else:
num = contents
instance.widgets = [widgets[0]] # Change to TextAreaInput
return f"Got {num}."
widgets = [
pn.widgets.TextAreaInput(placeholder="Enter some text to get a count!"),
pn.widgets.IntSlider(name="Number Input", end=10)
]
pn.widgets.ChatInterface(
callback=get_num_guided,
widgets=widgets[0],
)
The currently active widget can be accessed with the active_widget
property.
widgets = [
pn.widgets.TextAreaInput(placeholder="Enter some text to get a count!"),
pn.widgets.IntSlider(name="Number Input", end=10)
]
chat_interface = pn.widgets.ChatInterface(
widgets=widgets,
)
print(chat_interface.active_widget)
Sometimes, you may not want the widget to be reset after its contents has been sent.
To have the widgets' value
persist, set reset_on_send=False
.
pn.widgets.ChatInterface(
widgets=pn.widgets.TextAreaInput(),
reset_on_send=False,
)
If you're not using an LLM to respond, the Rerun
button may not be practical so it can be hidden by setting show_rerun=False
.
The same can be done for other buttons as well with show_send
, show_undo
, and show_clear
.
pn.widgets.ChatInterface(callback=get_num, show_rerun=False, show_undo=False)
If you want a slimmer ChatInterface
, use show_button_name=False
to hide the labels of the buttons.
pn.widgets.ChatInterface(callback=get_num, show_button_name=False, width=400)