Skip to content

chat

A control that provides the user interface for chatting.

The control represents the chat area that can be used in a messaging application that allows users to send and receive messages.

The control has two main components:

  • A list of messages.
    For any given user connected to the application, messages this user sends appear in a bubble aligned to the right. Other messages are aligned to the left and show the identifier of the sender and the sender's avatar image if one was defined.
  • A message input box.
    Located at the bottom of the message list, this input field allows users to type and send messages.

Properties

Name Type Default Description
messages(★) list[str]
dynamic
Required

The list of messages. Each item of this list must consist of a list of three strings: a message identifier, a message content, and a user identifier.

users list[Union[str,Icon]]
dynamic

The list of users. See the section on List of Values for more details.

sender_id str "taipy"

The user identifier, as indicated in the users list, associated with all messages sent from the input.

with_input bool
dynamic
True

If False, the input field is not rendered.

on_action Union[str, Callable]

A function or the name of a function that is triggered when the user enters a new message.
This function is invoked with the following parameters:

  • state (State): the state instance.
  • var_name (str): the name of the variable bound to the messages property.
  • payload (dict): the details on this callback's invocation.
    This dictionary has the following keys:
    • action: the name of the action that triggered this callback.
    • args (list): a list composed of a reason ("click" or "Enter"), the variable name, the message, and the user identifier of the sender.

page_size int 50

The number of messages retrieved from the application and sent to the frontend. Larger values imply more potential latency.

height Union[str,int,float]

The maximum height of this chat control, in CSS units.

show_sender bool False

If True, the sender avatar and name are displayed.

mode str "markdown"

Define the way the messages are processed when they are displayed:

  • "raw" no processing
  • "pre": keeps spaces and new lines
  • "markdown" or "md": basic support for Markdown.

active bool
dynamic
True

Indicates if this component is active.
An inactive component allows no user interaction.

id str

The identifier that is assigned to the rendered HTML component.

properties dict[str, Any]

Bound to a dictionary that contains additional properties for this element.

class_name str
dynamic

The list of CSS class names that are associated with the generated HTML Element.
These class names are added to the default taipy-chat class name.

hover_text str
dynamic

The information that is displayed when the user hovers over this element.

(★)messages is the default property for this visual element.

Details

Three mandatory properties can configure the chat control:

  • users defines the list of users that can send or receive messages using the control.
    This property value can be as simple as a list of user identifiers or a list of Icon objects that can associate an avatar image with a user.
  • sender_id indicates the identifier of user that is sending messages.
    This identifier must appear in the users list.
    Messages whose sender identifier (see below) is equal to this property's value appear on the right side of the message list; the other messages appear on the left side of the control.
  • messages is a list of message records.
    Each message record must a tuple or a list that must have three elements:

    • Element 0: an identifier for the message.
      That can be any string that uniquely identifies a specific message.
    • Element 1: the message content.
      The string that is represented in a message bubble.
    • Element 2: the identifier of the sender.
      This identifier must appear in the users list.

Usage

Human-to-machine dialog

A simple use case where the chat control is relevant is if you want to create an application where a user can type and send text messages that are processed by some engine, whose role is to generate messages back for the user to read.
Typical examples of such interactive applications are based on Large Language Models (LLMs) that can process incoming messages written in natural language, interpret the text, and generate responses. Such applications are known as digital assistants. There are several famous examples of these, such as ChatGPT, Microsoft Copilot, and Google Gemini, among others.

In this example, we will use the chat control in a similar manner, in a simpler context: a calculator.
The end user is invited to provide a mathematical expression. The application computes the evaluation of that expression (presumed to be a valid Python expression) and displays the result.

Let's start by defining the main variables that the chat control relies on:

users = ["human", "Result"]
messages: list[tuple[str, str, str]] = []

users holds the identifier of the two interlocutors for this application: "human" (users[0]) is to identifier the end user, "Result" is the identifier we use to represent the computer: this string is displayed above messages generated by the application.
messages stores all the created messages.

The control definition is the following:

Definition

<|{messages}|chat|users={users}|sender_id={users[0]}|on_action=evaluate|>
<taipy:chat users="{users}" sender_id="{users[0]}" on_action="evaluate">{messages}</taipy:chat>
import taipy.gui.builder as tgb
...
tgb.chat("{messages}", users="{users}", sender_id="{users[0]}", on_action="evaluate")

messages and users are bound to their respective properties and the sender_id property is set to the first user identifier in users.

The on_action property is set to the evaluate() callback function whose code is the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def evaluate(state, var_name: str, payload: dict):
    (_, _, expression, sender_id) = payload.get("args", [])
    messages.append((f"{len(messages)}", expression, sender_id))
    result = "Invalid expression"
    try:
        result = f"= {eval(expression)}"
    except Exception:
        pass
    messages.append((f"{len(messages)}", result, users[1]))
    state.messages = messages

Line 2 retrieves the callback parameters from the payload.
The variable expression saves the expression provided by the user and sender_id keeps the identifier of the user that sent this message.

Line 3 adds a new message to the chat control message list, copying the expression text and indicating who the sender is, so the message appears on the right side of the control.
Note how we generate the message identifier: each added message enlarges the message list, so we simply use the length of the message list as the message identifier. This value increments every time a new message gets in.

Line 6 evaluates the expression. If this call raises an exception, the application sets the response message to a string indicating an error has occurred.
When the evaluation succeeds, we create a response made of an equal sign followed by the result.

Finally, on line 9, we store the evaluation's result in a new message, indicating it was sent by the application (so it appears on the left side of the control).

Line 10 updates the user's state so the control is updated.

After the user has submitted a few expressions to evaluate, the control displays something like this:

A Taipy calculator

Multi-user chatting

You can also use the chat control in another situation: when you want to develop an application that allows several users to share the same chatting space.
Here is how you can create such an application using Taipy GUI.

General setup

The application has two pages:

  • The first page (called "register") allows users to register for the chatting application.
  • The second page (called "discuss") shows all the messages exchanged in a chat control. You can consider this page as showing a channel in a chat application: several users can send and read messages in a community.

Let's describe this first page.
The definition of the page is the following:

username = ""

register_page = """
Please enter your user name:

<|{username}|input|>

<|Submit|button|on_action=register|>
"""

It holds an input field bound to the variable username.

Here is how this page looks like when the user Alice has entered her name:

Alice is about to register

The control's on_action callback property is set so that the callback function register() is invoked when the "Submit" button is pressed.
Here is the code of this function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
users: list[Union[str, Icon]] = []

def register(state):
    for user in users:
        if state.username == user or (isinstance(user, (list, tuple)) and state.username == user[0]):
            notify(state, "error", "User already registered.")
            return
    avatar_image_file = f"{state.username.lower()}-avatar.png"
    if path.isfile(avatar_image_file):
        users.append((state.username, Icon(avatar_image_file, state.username)))
    else:
        users.append(state.username)
    state.users = users
    navigate(state, "discuss")

In lines 4 to 7, we test whether that user name is one of the names stored in the users list and reject the registration if it is.

In lines 8 to 12, we add this user name to the users list.
If we can find an avatar image for that user (a file called "<username>-avatar.png" located next to the Python script), then we create an Icon instance to represent the user avatar.

Line 13 updates the variable users for the user's state.
And on line 14, we navigate to the "discuss" page so the user can read and send messages.

Here is the code that defines the "discuss" page:

messages: list[tuple[str, str, str]] = []

discuss_page = """
<|### Let's discuss, {username}|text|mode=markdown|>

<|{messages}|chat|users={users}|sender_id={username}|on_action=send|>
"""

This page creates a chat control that binds its default property (messages) to the variable messages that is initialized to an empty list.
The variables users and username are bound as expected.

Note that because this application has two pages, you must create the Gui instance with the pages parameter set to a dictionary that holds those pages.
Here is the code that initializes and runs the Taipy GUI application:

pages = {"register": register_page, "discuss": discuss_page}
gui = Gui(pages=pages).run()

After the registration, this is the page that Alice will see:

The chatting area for Alice

We now need to implement the callback function send(), which is set to the on_action property of the chat control.
Here is the code for this function:

1
2
3
4
def send(state, _: str, payload: dict):
    (_, _, message, sender_id) = payload.get("args", [])
    messages.append((f"{len(messages)}", message, sender_id))
    state.messages = messages

Like in the calculator example above, we retrieve the callback parameters on line 2 and add a new message (on line 3) using the message index as its identifier.
The state's variable messages is updated on line 4.

Multi-user considerations

We want several users to connect to this application and share the messages and the user list we created.
To make that happen, you can use the function Gui.add_shared_variable() to ensure that both messages and users have the same value for every connected user.
Let's do that for our use case:

Gui.add_shared_variables("messages", "users")
After that function is invoked, every time any user modifies messages or users, the impact is propagated to all the connected users.

Let's pretend that a new user, Beatrix, connects to the application.
Here is the registration page as this user sees it:

Beatrix registers

When Beatrix presses the "Submit" button, the register() callback function is invoked.
Because users is a shared variable, every client, including Alice, is aware of this new registration: their state's users variable is updated accordingly and automatically.

Imagine that Alice enters the following message:

Alice sends a message

When Alices pressed the send button, she can see the updated chat control:

Alice has sent a message

The message sent appears in a right-aligned bubble, indicating that the current user, Alice, was the one who sent this message.

Because both users and messages are shared among all connected clients, Beatrix will see the following page:

Beatrix can see Alice's message

As expected, messages coming from Alice appear on the left side of Beatrix's page.
Also, because Alice has an avatar image, this image appears next to the messages she sent.

Here are the pages that Alice and Beatrix can see when they start sending messages to each other:

What Alice sees
What Beatrix sees

Now, let's imagine that another user, Charles, joins the discussion. The three connected users can send messages to the group, sharing the bound variables users and messages so that their chat controls all represent the same content, with a different layout depending on who sent messages.

Alice's screen
Beatrix's screen
Charles's screen

Styling

All the chat controls are generated with the "taipy-chat" CSS class. You can use this class name to select the date selectors on your page and apply style.