Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples for the chat control #1631

Merged
merged 8 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions doc/gui/examples/charts/advanced-python-lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@
figure.update_layout(title="Different Probability Distributions")

page = """
# Plotly Python
<|toggle|theme|>

<|chart|figure={figure}|>
"""

Expand Down
Binary file added doc/gui/examples/controls/alice-avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/gui/examples/controls/beatrix-avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/gui/examples/controls/charles-avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions doc/gui/examples/controls/chat-calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2021-2024 Avaiga Private Limited
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
# -----------------------------------------------------------------------------------------
# To execute this script, make sure that the taipy-gui package is installed in your
# Python environment and run:
# python <script>
# -----------------------------------------------------------------------------------------
# Human-computer dialog UI based on the chat control.
# -----------------------------------------------------------------------------------------
from math import cos, pi, sin, sqrt, tan # noqa: F401

from taipy.gui import Gui

# The user interacts with the Python interpreter
users = ["human", "Result"]
messages: list[tuple[str, str, str]] = []


def evaluate(state, var_name: str, payload: dict):
# Retrieve the callback parameters
(_, _, expression, sender_id) = payload.get("args", [])
# Add the input content as a sent message
messages.append((f"{len(messages)}", expression, sender_id))
# Default message used if evaluation fails
result = "Invalid expression"
try:
# Evaluate the expression and store the result
result = f"= {eval(expression)}"
except Exception:
pass
# Add the result as an incoming message
messages.append((f"{len(messages)}", result, users[1]))
state.messages = messages


page = """
<|{messages}|chat|users={users}|sender_id={users[0]}|on_action=evaluate|>
"""

Gui(page).run()
84 changes: 84 additions & 0 deletions doc/gui/examples/controls/chat-discuss.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Copyright 2021-2024 Avaiga Private Limited
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
# -----------------------------------------------------------------------------------------
# To execute this script, make sure that the taipy-gui package is installed in your
# Python environment and run:
# python <script>
# -----------------------------------------------------------------------------------------
# A chatting application based on the chat control.
# In order to see the users' avatars, the image files must be stored next to this script.
# If you want to test this application locally, you need to use several browsers and/or
# incognito windows so a given user's context is not reused.
# -----------------------------------------------------------------------------------------
from os import path

from taipy.gui import Gui, Icon
from taipy.gui.gui_actions import navigate, notify

username = ""
users: list[str|Icon] = []
messages: list[tuple[str, str, str]] = []

Gui.add_shared_variables("messages", "users")


def on_init(state):
# Copy the global variables users and messages to this user's state
state.users = users
state.messages = messages


def on_navigate(state, path: str):
# Navigate to the 'register' page if the user is not registered
if path == "discuss" and state.username == "":
return "register"
return path


def register(state):
# Check that the user is not already registered
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
# Use the avatar image if we can find it
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)
# Because users is a shared variable, this propagates to every client
state.users = users
navigate(state, "discuss")


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


register_page = """
Please enter your user name:

<|{username}|input|>

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

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

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

pages = {"register": register_page, "discuss": discuss_page}
gui = Gui(pages=pages).run()
40 changes: 40 additions & 0 deletions doc/gui/examples/controls/table-formatting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2021-2024 Avaiga Private Limited
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
# -----------------------------------------------------------------------------------------
# To execute this script, make sure that the taipy-gui package is installed in your
# Python environment and run:
# python <script>
# -----------------------------------------------------------------------------------------
import datetime

from taipy.gui import Gui

stock = {
"date": [datetime.datetime(year=2000, month=12, day=d) for d in range(20, 30)],
"price": [119.88, 112.657, 164.5, 105.42, 188.36, 103.9, 143.97, 160.11, 136.3, 174.06],
"change": [7.814, -5.952, 0.01, 8.781, 7.335, 6.623, -6.635, -6.9, 0.327, -0.089],
"volume": [773, 2622, 2751, 1108, 7400, 3772, 9398, 4444, 9264, 1108],
}

columns = {
"date" : {"title": "Data", "format": "MMM d"},
"price" : {"title": "Price", "format": "$%.02f"},
"change" : {"title": "% change", "format": "%.01f"},
"volume" : {"title": "Volume"}
}

page = """
# Formatting cells in a table

<|{stock}|table|columns={columns}|>
"""

Gui(page).run()
3 changes: 0 additions & 3 deletions doc/gui/examples/controls/text-format.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
pi = 3.14159265358979

page = """
# Text - Formatting
<|toggle|theme|>

π≈<|{pi}|text|format=%.3f|>
"""

Expand Down
3 changes: 0 additions & 3 deletions doc/gui/examples/controls/text-md.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@
""" # noqa W291

page = """
# Text - Markdown
<|toggle|theme|>

<|{markdown}|text|mode=markdown|>
"""

Expand Down
3 changes: 0 additions & 3 deletions doc/gui/examples/controls/text-pre.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ def say_hello(name: str):
"""

page = """
# Text - pre
<|toggle|theme|>

<|{code}|text|mode=pre|>
"""

Expand Down
3 changes: 0 additions & 3 deletions doc/gui/examples/controls/text-simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
name = "Taipy"

page = """
# Text - simple
<|toggle|theme|>

<|Hello {name}!|>
"""

Expand Down
4 changes: 1 addition & 3 deletions frontend/taipy-gui/src/components/Taipy/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ const Chat = (props: ChatProps) => {

const [rows, setRows] = useState<RowType[]>([]);
const page = useRef<key2Rows>({ key: defaultKey });
const [rowCount, setRowCount] = useState(0);
const [columns, setColumns] = useState<Array<string>>([]);
const scrollDivRef = useRef<HTMLDivElement>(null);
const anchorDivRef = useRef<HTMLElement>(null);
Expand Down Expand Up @@ -291,7 +290,6 @@ const Chat = (props: ChatProps) => {
useEffect(() => {
if (!refresh && props.messages && page.current.key && props.messages[page.current.key] !== undefined) {
const newValue = props.messages[page.current.key];
setRowCount(newValue.rowcount);
const nr = newValue.data as RowType[];
if (Array.isArray(nr) && nr.length > newValue.start && nr[newValue.start]) {
setRows((old) => {
Expand Down Expand Up @@ -341,7 +339,7 @@ const Chat = (props: ChatProps) => {
);

return (
<Tooltip title={hover || "" || `rowCount: ${rowCount}`}>
<Tooltip title={hover || ""}>
<Paper className={className} sx={boxSx} id={id}>
<Grid container rowSpacing={2} sx={gridSx} ref={scrollDivRef}>
{rows.length && !rows[0] ? (
Expand Down
1 change: 1 addition & 0 deletions taipy/gui/_renderers/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@


class JsonAdapter(ABC):
"""NOT DOCUMENTED"""
def register(self):
_TaipyJsonAdapter().register(self)

Expand Down
13 changes: 8 additions & 5 deletions taipy/gui/gui_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def download(
name: File name for the content on the client browser (defaults to content name).
on_action: Callback function (or callback name) to call when the download ends. See below.

## Notes:
<h4>Notes:</h4>

- *content*: this parameter can hold several values depending on your use case:
- a string: the value must be an existing path name to the file that gets downloaded or
Expand Down Expand Up @@ -122,9 +122,12 @@ def hold_control(
chooses to cancel.<br/>
If empty or None, no cancel action is provided to the user.<br/>
The signature of this function is:
- state (State^): The user state;

- state (`State^`): The user state;
- id (str): the id of the button that triggered the callback. That will always be
"UIBlocker" since it is created and managed internally;

If this parameter is None, no "Cancel" button is displayed.
message: The message to show. The default value is the string "Work in Progress...".
"""
if state and isinstance(state._gui, Gui):
Expand Down Expand Up @@ -212,8 +215,8 @@ def get_state_id(state: State) -> t.Optional[str]:
state (State^): The current user state as received in any callback.

Returns:
A string that uniquely identifies the state.<br/>
If None, then **state** was not handled by a `Gui^` instance.
A string that uniquely identifies the state. If this value None, it indicates that *state* is not
handled by a `Gui^` instance.
"""
if state and isinstance(state._gui, Gui):
return state._gui._get_client_id()
Expand Down Expand Up @@ -273,7 +276,7 @@ def invoke_callback(
"""Invoke a user callback for a given state.

Calling this function is equivalent to calling
*gui*.[Gui.]invoke_callback(state_id, callback, args, module_context)^`.
*gui*.`(Gui.)invoke_callback(state_id, callback, args, module_context)^`.

Arguments:
gui (Gui^): The current Gui instance.
Expand Down
Loading
Loading