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

Use pn.Feed internally for ChatFeed #6296

Merged
merged 50 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
07a47f4
Add logs plumbing
ahuang11 Dec 12, 2023
068a09b
Rename to Log
ahuang11 Dec 12, 2023
f97efc4
Implement in column
ahuang11 Dec 12, 2023
2e20fa5
Add to index.ts
ahuang11 Dec 12, 2023
bee0431
Implement functionality
ahuang11 Dec 13, 2023
6ba4f96
Replace min_entries with loaded_entries and make 2 spaces
ahuang11 Dec 13, 2023
5832cad
use get_objects implementation
ahuang11 Dec 20, 2023
2748f9d
Cleanup
ahuang11 Dec 27, 2023
95aebb6
Add test
ahuang11 Dec 27, 2023
5a64205
Add example and fix tests
ahuang11 Dec 27, 2023
6474895
Rewrite Log implementation
philippjfr Jan 17, 2024
ceed53e
Do not reset visible_objects
philippjfr Jan 17, 2024
cfe841d
Load only after half the buffer is visible
philippjfr Jan 17, 2024
9fab290
Try to send event
ahuang11 Jan 18, 2024
109d70e
Move log to its own modules and add custom support to scroll button
ahuang11 Jan 18, 2024
a8753f4
Use super method
ahuang11 Jan 18, 2024
9ddce39
Remove loaded_entries, tweak docs, and rename visible_objects
ahuang11 Jan 18, 2024
a65e6a6
Optimize and improve behavior
ahuang11 Jan 19, 2024
83b0980
Update ref gallery
ahuang11 Jan 19, 2024
4bec589
Rename entries
ahuang11 Jan 19, 2024
956ffca
Add tests
ahuang11 Jan 19, 2024
008f0bf
Add test and watch load_buffer
ahuang11 Jan 19, 2024
1250096
Add more tests
ahuang11 Jan 19, 2024
a278079
Rename visible_indices to visible_range and visible_objects to visibl…
ahuang11 Jan 23, 2024
7f0c29d
Also cleanup synced indices to range
ahuang11 Jan 23, 2024
e8cdd8f
Rename to feed
ahuang11 Jan 23, 2024
81c9361
Missing
ahuang11 Jan 23, 2024
e27d213
Another missing
ahuang11 Jan 23, 2024
ea99984
ANother missing
ahuang11 Jan 23, 2024
71bc80f
Tests pass
ahuang11 Jan 23, 2024
6fc2a71
Couple more log mentions
ahuang11 Jan 23, 2024
2448926
Plus 1 to make it center on the last
ahuang11 Jan 23, 2024
22d55ef
Merge branch 'main' into add_logs
ahuang11 Jan 23, 2024
7b62dd5
Fix test maybe?
ahuang11 Jan 30, 2024
9f33c83
Maybe closer to fixing tests? It passes locally so I have to debug on GH
ahuang11 Jan 30, 2024
478c4e9
Be more tolerant on indeterministic numbers
ahuang11 Jan 30, 2024
08d09c7
Make more tolerant
ahuang11 Jan 30, 2024
8fa93af
Integrate Feed into chat feed
ahuang11 Feb 2, 2024
a685731
Add load buffer
ahuang11 Feb 2, 2024
a3abb9c
Fix test
ahuang11 Feb 2, 2024
0230420
Merge branch 'main' into integrate_feed
ahuang11 Feb 5, 2024
59e67e9
Merge branch 'main' into integrate_feed
ahuang11 Feb 5, 2024
a8e9432
Update scroll param
ahuang11 Feb 5, 2024
293b392
Merge branch 'main' into integrate_feed
ahuang11 Feb 19, 2024
c5856c5
Merge branch 'main' into integrate_feed
ahuang11 Feb 26, 2024
6688d78
Fix test
ahuang11 Feb 27, 2024
59ae292
Merge branch 'main' into integrate_feed
ahuang11 Mar 4, 2024
ead2501
Merge branch 'main' into integrate_feed
ahuang11 Mar 6, 2024
eddff8b
Replace class
ahuang11 Mar 6, 2024
c5027ac
Merge branch 'main' into integrate_feed
ahuang11 Mar 6, 2024
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
1 change: 1 addition & 0 deletions examples/reference/chat/ChatFeed.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"* **`placeholder_threshold`** (float): Min duration in seconds of buffering before displaying the placeholder. If 0, the placeholder will be disabled. Defaults to 0.2.\n",
"* **`auto_scroll_limit`** (int): Max pixel distance from the latest object in the Column to activate automatic scrolling upon update. Setting to 0 disables auto-scrolling.\n",
"* **`scroll_button_threshold`** (int): Min pixel distance from the latest object in the Column to display the scroll button. Setting to 0 disables the scroll button.\n",
"* **`load_buffer`** (int): The number of objects loaded on each side of the visible objects. When scrolled halfway into the buffer, the feed will automatically load additional objects while unloading objects on the opposite side.\n",
"* **`show_activity_dot`** (bool): Whether to show an activity dot on the ChatMessage while streaming the callback response.\n",
"* **`view_latest`** (bool): Whether to scroll to the latest object on init. If not enabled the view will be on the first object. Defaults to True.\n",
"\n",
Expand Down
20 changes: 17 additions & 3 deletions panel/chat/feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from .._param import Margin
from ..io.resources import CDN_DIST
from ..layout import Column, ListPanel
from ..layout import Feed, ListPanel
from ..layout.card import Card
from ..layout.spacer import VSpacer
from ..pane.image import SVG
Expand Down Expand Up @@ -156,6 +156,11 @@ class ChatFeed(ListPanel):
exception. If None, will attempt to infer the renderer
from the value.""")

load_buffer = param.Integer(default=50, bounds=(0, None), doc="""
The number of objects loaded on each side of the visible objects.
When scrolled halfway into the buffer, the feed will automatically
load additional objects while unloading objects on the opposite side.""")

scroll_button_threshold = param.Integer(default=100, bounds=(0, None),doc="""
Min pixel distance from the latest object in the Column to
display the scroll button. Setting to 0
Expand Down Expand Up @@ -211,14 +216,17 @@ def __init__(self, *objects, **params):
visible=self.param.visible
)
# we separate out chat log for the auto scroll feature
self._chat_log = Column(
*self.objects,
self._chat_log = Feed(
*objects,
load_buffer=self.load_buffer,
auto_scroll_limit=self.auto_scroll_limit,
scroll_button_threshold=self.scroll_button_threshold,
view_latest=self.view_latest,
css_classes=["chat-feed-log"],
stylesheets=self._stylesheets,
**linked_params
)
self._chat_log.height = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? Should height be removed from linked_params?

Copy link
Contributor Author

@ahuang11 ahuang11 Feb 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pn.Feed sets a fixed height if height is not explicitly set; if not, the local scrollbar never appears and thus no buffering is allowed.

Maybe it will be alleviated with this: #6266

Copy link
Contributor Author

@ahuang11 ahuang11 Feb 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, if I remove the fixed height from pn.Feed, no need to set ChatFeed._chat_log.height to None

Screen.Recording.2024-02-05.at.11.45.07.AM.mov

But Feed scroll bar is useless by the global scroll bar

Screen.Recording.2024-02-05.at.11.44.30.AM.mov

card_params = linked_params.copy()
card_stylesheets = (
self._stylesheets +
Expand Down Expand Up @@ -274,6 +282,12 @@ def _cleanup(self, root: Model | None = None) -> None:
self._card._cleanup(root)
super()._cleanup(root)

@param.depends("load_buffer", "auto_scroll_limit", "scroll_button_threshold", watch=True)
def _update_chat_log_params(self):
self._chat_log.load_buffer = self.load_buffer
self._chat_log.auto_scroll_limit = self.auto_scroll_limit
self._chat_log.scroll_button_threshold = self.scroll_button_threshold

@param.depends("card_params", watch=True)
def _update_card_params(self):
card_params = self.card_params.copy()
Expand Down
18 changes: 15 additions & 3 deletions panel/layout/feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,18 @@ class Feed(Column):
When scrolled halfway into the buffer, the feed will automatically
load additional objects while unloading objects on the opposite side.""")

scroll = param.Boolean(default=True, doc="""
Whether to add scrollbars if the content overflows the size
of the container.""")
scroll = param.Selector(
default="y",
objects=[False, True, "both-auto", "y-auto", "x-auto", "both", "x", "y"],
doc="""Whether to add scrollbars if the content overflows the size
of the container. If "both-auto", will only add scrollbars if
the content overflows in either directions. If "x-auto" or "y-auto",
will only add scrollbars if the content overflows in the
respective direction. If "both", will always add scrollbars.
If "x" or "y", will always add scrollbars in the respective
direction. If False, overflowing content will be clipped.
If True, will only add scrollbars in the direction of the container,
(e.g. Column: vertical, Row: horizontal).""")

visible_range = param.Range(readonly=True, doc="""
Read-only upper and lower bounds of the currently visible feed objects.
Expand Down Expand Up @@ -56,6 +65,9 @@ def __init__(self, *objects, **params):

@param.depends("visible_range", "load_buffer", watch=True)
def _trigger_get_objects(self):
if self.visible_range is None:
return

# visible start, end / synced start, end
vs, ve = self.visible_range
ss, se = self._last_synced
Expand Down
14 changes: 13 additions & 1 deletion panel/tests/chat/test_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class TestChatFeed:

def test_init_with_help_text(self):
chat_feed = ChatFeed(help_text="Instructions")
message = chat_feed._chat_log[0]
message = chat_feed.objects[0]
assert message.object == "Instructions"
assert message.user == "Help"

Expand Down Expand Up @@ -427,6 +427,18 @@ def test_forward_message_params(self, chat_feed):
assert chat_message.reactions == ["like"]
assert chat_message.reaction_icons.options == {"like": "thumb-up"}

def test_update_chat_log_params(self, chat_feed):
chat_feed = ChatFeed(load_buffer=5, scroll_button_threshold=5, auto_scroll_limit=5)
assert chat_feed._chat_log.load_buffer == 5
assert chat_feed._chat_log.scroll_button_threshold == 5
assert chat_feed._chat_log.auto_scroll_limit == 5

chat_feed.load_buffer = 10
chat_feed.scroll_button_threshold = 10
chat_feed.auto_scroll_limit = 10
assert chat_feed._chat_log.load_buffer == 10
assert chat_feed._chat_log.scroll_button_threshold == 10
assert chat_feed._chat_log.auto_scroll_limit == 10

@pytest.mark.xdist_group("chat")
class TestChatFeedCallback:
Expand Down
4 changes: 2 additions & 2 deletions panel/tests/ui/layout/test_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def test_feed_load_entries(page):
bbox = feed_el.bounding_box()
assert bbox["height"] == 250

expect(feed_el).to_have_class("bk-panel-models-feed-Feed scrollable-vertical")
expect(feed_el).to_have_class("bk-panel-models-feed-Feed scroll-vertical")

children_count = feed_el.evaluate(
'(element) => element.shadowRoot.querySelectorAll(".bk-panel-models-markup-HTML").length'
Expand Down Expand Up @@ -52,7 +52,7 @@ def test_feed_view_latest(page):
bbox = feed_el.bounding_box()
assert bbox["height"] == 250

expect(feed_el).to_have_class("bk-panel-models-feed-Feed scrollable-vertical")
expect(feed_el).to_have_class("bk-panel-models-feed-Feed scroll-vertical")

# Assert scroll is not at 0 (view_latest)
assert feed_el.evaluate('(el) => el.scrollTop') > 0
Expand Down
Loading