Chat Features¶
Highlights some features of Panel's chat components; they do not require other packages besides Panel.
Echo Chat¶
Demonstrates how to use the ChatInterface
and a callback
function to respond.
Highlights:
- The
ChatInterface
and acallback
function are used to create a chatbot that echoes back the message entered by the User. - The
help_text
parameter is used to provide instructions to the User.
Source code for echo_chat.py
"""
Demonstrates how to use the `ChatInterface` and a `callback` function to respond.
Highlights:
- The `ChatInterface` and a `callback` function are used to create a
chatbot that echoes back the message entered by the User.
- The `help_text` parameter is used to provide instructions to the User.
"""
import panel as pn
pn.extension()
def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
message = f"Echoing {user}: {contents}"
return message
chat_interface = pn.chat.ChatInterface(
callback=callback,
help_text="Enter a message in the TextInput below and receive an echo!",
)
chat_interface.servable()
Live Apps: Pyodide
Stream Echo Chat¶
Demonstrates how to use the ChatInterface
and a callback
function to
stream back responses.
The chatbot Assistant echoes back the message entered by the User in an async streaming fashion.
Highlights:
- The function is defined as
async
and usesyield
to stream back responses. - Initialize
message
first to gather the characters and thenyield
it; without it, only one letter would be displayed at a time.
Source code for stream_echo_chat.py
"""
Demonstrates how to use the `ChatInterface` and a `callback` function to
stream back responses.
The chatbot Assistant echoes back the message entered by the User in an
*async streaming* fashion.
Highlights:
- The function is defined as `async` and uses `yield` to stream back responses.
- Initialize `message` first to gather the characters and then `yield` it;
without it, only one letter would be displayed at a time.
"""
from asyncio import sleep
import panel as pn
pn.extension()
async def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
await sleep(1)
message = ""
for char in "Echoing User: " + contents:
await sleep(0.05)
message += char
yield message
chat_interface = pn.chat.ChatInterface(callback=callback)
chat_interface.send(
"Enter a message below and receive an echo!",
user="System",
respond=False,
)
chat_interface.servable()
Live Apps: Pyodide
Custom Input Widgets¶
Demonstrates how to use the ChatInterface
and custom widgets,
like ChatAreaInput
and FileInput
, to create a chatbot that counts
the number of lines in a message or file.
Highlights:
- The
ChatAreaInput
andFileInput
widgets are used to create a custom chatbot that counts the number of lines in a message or file. - The
callback
function is used to count the number of lines in the message or file and return the result to the User.
Source code for custom_input_widgets.py
"""
Demonstrates how to use the `ChatInterface` and custom widgets,
like `ChatAreaInput` and `FileInput`, to create a chatbot that counts
the number of lines in a message or file.
Highlights:
- The `ChatAreaInput` and `FileInput` widgets are used to create a custom
chatbot that counts the number of lines in a message or file.
- The `callback` function is used to count the number of lines in the message
or file and return the result to the User.
"""
import panel as pn
pn.extension()
def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
lines = contents.strip().count("\n")
message = f"This snippet has {lines + 1} lines."
return message
chat_input = pn.chat.ChatAreaInput(placeholder="Send a message")
file_input = pn.widgets.FileInput(accept=".py")
chat_interface = pn.chat.ChatInterface(
callback=callback, widgets=[chat_input, file_input]
)
chat_interface.send(
"Enter a message in the ChatAreaInput below to count how many lines there is, "
"or upload a Python file to count the number of lines in the file.",
user="System",
respond=False,
)
chat_interface.servable()
Live Apps: Pyodide
Delayed Placeholder¶
Demonstrates how to delay the display of the placeholder.
Highlights:
- The
placeholder_threshold
parameter is used to delay the display of the placeholder. If the response time is less than the threshold, the placeholder will not be displayed. - The
placeholder_text
parameter is used to customize the placeholder text.
Source code for delayed_placeholder.py
"""
Demonstrates how to delay the display of the placeholder.
Highlights:
- The `placeholder_threshold` parameter is used to delay the display of the placeholder.
If the response time is less than the threshold, the placeholder will not be displayed.
- The `placeholder_text` parameter is used to customize the placeholder text.
"""
from asyncio import sleep
import panel as pn
pn.extension()
async def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
try:
seconds = float(contents)
if 0 < seconds < 10:
await sleep(seconds)
return f"Slept {contents} seconds!"
else:
return "Please enter a number between 1 and 9!"
except ValueError:
return "Please enter a number!"
chat_interface = pn.chat.ChatInterface(
callback=callback,
placeholder_threshold=2,
placeholder_text="Waiting for reply...",
)
chat_interface.send(
"Send a number to make the system sleep between 1 and 9 seconds!",
user="System",
respond=False,
)
chat_interface.servable()
Live Apps: Pyodide
Chained Response¶
Demonstrates how to chain responses from a single message in the callback.
Highlight:
- The
respond
parameter in thesend
method is used to chain responses. - It's also possible to use
respond
as a method to chain responses.
Source code for chained_response.py
"""
Demonstrates how to chain responses from a single message in the callback.
Highlight:
- The `respond` parameter in the `send` method is used to chain responses.
- It's also possible to use `respond` as a method to chain responses.
"""
from asyncio import sleep
import panel as pn
pn.extension()
PERSON_1 = "Happy User"
PERSON_2 = "Excited User"
PERSON_3 = "Passionate User"
async def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
await sleep(2)
if user == "User":
instance.send(
f"Hey, {PERSON_2}! Did you hear the user?",
user=PERSON_1,
avatar="😊",
respond=True, # This is the default, but it's here for clarity
)
elif user == PERSON_1:
user_message = instance.objects[-2]
user_contents = user_message.object
yield pn.chat.ChatMessage(
f'Yeah, they said "{user_contents}"! Did you also hear {PERSON_3}?',
user=PERSON_2,
avatar="😄",
)
instance.respond()
elif user == PERSON_2:
instance.send(
"Yup, I heard!",
user=PERSON_3,
avatar="😆",
respond=False,
)
chat_interface = pn.chat.ChatInterface(
help_text="Send a message to start the conversation!", callback=callback
)
chat_interface.servable()
Live Apps: Pyodide
Styled Slim Interface¶
Demonstrates how to create a slim ChatInterface
that fits in the sidebar.
Highlights:
- The
ChatInterface
is placed in the sidebar. - Set
show_*
parameters toFalse
to hide the respective buttons. - Use
message_params
to customize the appearance of each chat messages.
Source code for styled_slim_interface.py
"""
Demonstrates how to create a slim `ChatInterface` that fits in the sidebar.
Highlights:
- The `ChatInterface` is placed in the sidebar.
- Set `show_*` parameters to `False` to hide the respective buttons.
- Use `message_params` to customize the appearance of each chat messages.
"""
import panel as pn
pn.extension()
async def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
message = f"Echoing {user}: {contents}"
return message
chat_interface = pn.chat.ChatInterface(
callback=callback,
show_send=False,
show_rerun=False,
show_undo=False,
show_clear=False,
show_avatar=False,
show_timestamp=False,
show_button_name=False,
show_reaction_icons=False,
sizing_mode="stretch_width",
height=700,
message_params={
"stylesheets": [
"""
.message {
font-size: 1em;
}
.name {
font-size: 0.9em;
}
.timestamp {
font-size: 0.9em;
}
"""
]
},
)
main = """
We've put a *slim* `ChatInterface` in the sidebar. In the main area you
could add the object you are chatting about
"""
pn.template.FastListTemplate(
main=[main],
sidebar=[chat_interface],
sidebar_width=500,
).servable()
Live Apps: Pyodide
Control Callback Response¶
Demonstrates how to precisely control the callback response.
Highlights:
- Use a placeholder text to display a message while waiting for the response.
- Use a placeholder threshold to control when the placeholder text is displayed.
- Use send instead of stream/yield/return to keep the placeholder text while still sending a message, ensuring respond=False to avoid a recursive loop.
- Use yield to continuously update the response message.
- Use pn.chat.ChatMessage or dict to send a message with a custom user and avatar.
Source code for control_callback_response.py
"""
Demonstrates how to precisely control the callback response.
Highlights:
- Use a placeholder text to display a message while waiting for the response.
- Use a placeholder threshold to control when the placeholder text is displayed.
- Use send instead of stream/yield/return to keep the placeholder text while still sending a message, ensuring respond=False to avoid a recursive loop.
- Use yield to continuously update the response message.
- Use pn.chat.ChatMessage or dict to send a message with a custom user and avatar.
"""
from asyncio import sleep
from random import choice
import panel as pn
pn.extension()
async def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
await sleep(0.5)
# use send instead of stream/yield/return to keep the placeholder text
# while still sending a message; ensure respond=False to avoid a recursive loop
instance.send(
"Let me flip the coin for you...",
user="Game Master",
avatar="🎲",
respond=False,
)
await sleep(1)
characters = "/|\\_"
index = 0
for _ in range(0, 28):
index = (index + 1) % len(characters)
# use yield to continuously update the response message
# use pn.chat.ChatMessage to send a message with a custom user and avatar
yield pn.chat.ChatMessage("\r" + characters[index], user="Coin", avatar="🪙")
await sleep(0.005)
result = choice(["heads", "tails"])
if result in contents.lower():
# equivalently, use a dict instead of a pn.chat.ChatMessage
yield {"object": f"Woohoo, {result}! You win!", "user": "Coin", "avatar": "🎲"}
else:
yield {
"object": f"Aw, got {result}. Try again!",
"user": "Coin",
"avatar": "🎲",
}
chat_interface = pn.chat.ChatInterface(
widgets=[
pn.widgets.RadioButtonGroup(
options=["Heads!", "Tails!"], button_type="primary", button_style="outline"
)
],
callback=callback,
help_text="Select heads or tails, then click send!",
placeholder_text="Waiting for the result...",
placeholder_threshold=0.1,
)
chat_interface.servable()
Live Apps: Pyodide