Skip to content

Commit

Permalink
Add ChatBox methods and replacing ChatRow values (#5118)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahuang11 authored Jun 15, 2023
1 parent aea57d5 commit b0ba5e3
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 17 deletions.
46 changes: 46 additions & 0 deletions panel/tests/widgets/test_chatbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,52 @@ def test_chat_box_extend(document, comm):
assert len(chat_box) == 2


def test_insert(document, comm):
chat_box = ChatBox()
message = {"user": "Hello"}
chat_box.insert(0, message)
assert chat_box.value == [message]
assert len(chat_box) == 1

# Inserting at an index greater than the current length
chat_box.insert(2, {"user": "Hi"})
assert chat_box.value == [message, {"user": "Hi"}]
assert len(chat_box) == 2


def test_pop(document, comm):
chat_box = ChatBox()
message1 = {"user": "Hello"}
message2 = {"user": "Hi"}
message3 = {"user": "Hey"}
chat_box.extend([message1, message2, message3])

# Pop the last message
popped_message = chat_box.pop()
assert popped_message == message3
assert chat_box.value == [message1, message2]
assert len(chat_box) == 2

# Pop a specific index
popped_message = chat_box.pop(0)
assert popped_message == message1
assert chat_box.value == [message2]
assert len(chat_box) == 1


def test_replace(document, comm):
chat_box = ChatBox()
message1 = {"user": "Hello"}
message2 = {"user": "Hi"}
chat_box.extend([message1, message2])

# Replace a message at a specific index
new_message = {"user": "Hey"}
chat_box.replace(1, new_message)
assert chat_box.value == [message1, new_message]
assert len(chat_box) == 2


def test_chat_box_allow_input(document, comm):
chat_box = ChatBox(allow_input=True)
assert chat_box.allow_input == True
Expand Down
71 changes: 54 additions & 17 deletions panel/widgets/chatbox.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from typing import (
Any, Callable, ClassVar, Dict, List, Optional, Tuple, Type, Union,
Any, ClassVar, Dict, List, Optional, Tuple, Type, Union,
)

import param
Expand Down Expand Up @@ -65,7 +65,6 @@ class ChatRow(CompositeWidget):
def __init__(
self,
value: List[Any],
default_message_callable: Viewable = None,
icon: str = None,
show_name: bool = True,
show_like: bool = True,
Expand All @@ -80,7 +79,6 @@ def __init__(
}
if styles:
bubble_styles.update(styles)
text_style = {"color": bubble_styles.get("color")}
icon_styles = dict((styles or {}))
icon_styles.pop("background", None)
icon_styles.pop("color", None)
Expand All @@ -94,6 +92,7 @@ def __init__(
)
if "background" not in bubble_styles:
bubble_styles["background"] = "black"
self._bubble_styles = bubble_styles
super().__init__(value=value, icon=icon, **params)

# create the chat icon
Expand All @@ -104,15 +103,11 @@ def __init__(
self._icon = None

# create the chat bubble
bubble_objects = [
self._serialize_obj(obj, default_message_callable, text_style)
for obj in value
]
self._bubble = Column(
*bubble_objects,
*[self._serialize_obj(obj) for obj in self.value],
align="center",
margin=8,
styles=bubble_styles,
styles=bubble_styles
)

# create heart icon next to chat
Expand Down Expand Up @@ -163,7 +158,7 @@ def __init__(
self._composite[:] = [row]

def _serialize_obj(
self, obj: Any, default_message_callable: Callable, text_styles: Dict
self, obj: Any
) -> Viewable:
"""
Convert an object to a Panel object.
Expand All @@ -172,15 +167,16 @@ def _serialize_obj(
return obj

stylesheets = ["p { margin-block-start: 0.2em; margin-block-end: 0.2em;}"]
text_styles = {"color": self._bubble_styles.get("color")}
try:
if default_message_callable is None or issubclass(
default_message_callable, PaneBase
if self.default_message_callable is None or issubclass(
self.default_message_callable, PaneBase
):
panel_obj = (default_message_callable or _panel)(
panel_obj = (self.default_message_callable or _panel)(
obj, stylesheets=stylesheets, styles=text_styles
)
else:
panel_obj = default_message_callable(value=obj)
panel_obj = self.default_message_callable(value=obj)
except ValueError:
panel_obj = _panel(obj, stylesheets=stylesheets, styles=text_styles)

Expand Down Expand Up @@ -543,7 +539,8 @@ def append(self, user_message: Dict[str, Union[List[Any], Any]]) -> None:
"""
if not isinstance(user_message, dict):
raise ValueError(f"Expected a dictionary, but got {user_message}")
self.value = self.value + [user_message]
self.value.append(user_message)
self.param.trigger("value")

def extend(self, user_messages: List[Dict[str, Union[List[Any], Any]]]) -> None:
"""
Expand All @@ -553,8 +550,48 @@ def extend(self, user_messages: List[Dict[str, Union[List[Any], Any]]]) -> None:
---------
user_messages (list): List of user messages to add.
"""
for user_message in user_messages:
self.append(user_message)
self.value.extend(user_messages)
self.param.trigger("value")

def insert(self, index: int, user_message: Dict[str, Union[List[Any], Any]]) -> None:
"""
Inserts a message into the chat log at the given index.
Arguments
---------
index (int): Index to insert the message at.
user_message (dict): Dictionary mapping user to message.
"""
self.value.insert(index, user_message)
self.param.trigger("value")

def pop(self, index: int = -1) -> Dict[str, Union[List[Any], Any]]:
"""
Pops the last message from the chat log.
Arguments
---------
index (int): Index of the message to pop; defaults to the last message.
Returns
-------
user_message (dict): Dictionary mapping user to message.
"""
value = self.value.pop(index)
self.param.trigger("value")
return value

def replace(self, index: int, user_message: Dict[str, Union[List[Any], Any]]):
"""
Replaces a message in the chat log at the given index.
Arguments
---------
index (int): Index to replace the message at.
user_message (dict): Dictionary mapping user to message.
"""
self.value[index] = user_message
self.param.trigger("value")

def clear(self) -> None:
"""
Expand Down

0 comments on commit b0ba5e3

Please sign in to comment.