Skip to content

Commit

Permalink
Re-enable send button and remove placeholder on stop (#6033)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahuang11 authored Dec 15, 2023
1 parent 88b676b commit aa61fe6
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 5 deletions.
18 changes: 13 additions & 5 deletions panel/chat/feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ class ChatFeed(ListPanel):
_callback_state = param.ObjectSelector(objects=list(CallbackState), doc="""
The current state of the callback.""")

_was_disabled = param.Boolean(default=False, doc="""
The previous disabled state of the feed.""")

_stylesheets: ClassVar[List[str]] = [f"{CDN_DIST}css/chat_feed.css"]

def __init__(self, *objects, **params):
Expand Down Expand Up @@ -441,7 +444,7 @@ async def _prepare_response(self, _) -> None:
if self.callback is None:
return

disabled = self.disabled
self._was_disabled = self.disabled
try:
with param.parameterized.batch_call_watchers(self):
self.disabled = True
Expand Down Expand Up @@ -485,8 +488,8 @@ async def _prepare_response(self, _) -> None:
finally:
with param.parameterized.batch_call_watchers(self):
self._replace_placeholder(None)
self.disabled = disabled
self._callback_state = CallbackState.IDLE
self.disabled = self._was_disabled

# Public API

Expand Down Expand Up @@ -607,15 +610,20 @@ def stop(self) -> bool:
Whether the task was successfully stopped or done.
"""
if self._callback_future is None:
return False
cancelled = False
elif self._callback_state == CallbackState.GENERATING:
# cannot cancel generator directly as it's already "finished"
# by the time cancel is called; instead, set the state to STOPPING
# and let upsert_message raise StopCallback
self._callback_state = CallbackState.STOPPING
return True
cancelled = True
else:
return self._callback_future.cancel()
cancelled = self._callback_future.cancel()

if cancelled:
self.disabled = self._was_disabled
self._replace_placeholder(None)
return cancelled

def undo(self, count: int = 1) -> List[Any]:
"""
Expand Down
29 changes: 29 additions & 0 deletions panel/tests/chat/test_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from panel.chat.interface import ChatInterface
from panel.layout import Row, Tabs
from panel.pane import Image
from panel.tests.util import wait_until
from panel.widgets.button import Button
from panel.widgets.input import FileInput, TextAreaInput, TextInput

Expand Down Expand Up @@ -92,6 +93,7 @@ async def callback(msg, user, instance):
assert send_button.name == "Send"
assert stop_button.name == "Stop"
assert send_button.visible
assert not send_button.disabled
assert not stop_button.visible
yield "B" # should not stream this

Expand All @@ -103,6 +105,7 @@ async def callback(msg, user, instance):
assert send_button.name == "Send"
assert stop_button.name == "Stop"
assert send_button.visible
assert not send_button.disabled
assert not stop_button.visible

def test_show_stop_for_async(self, chat_interface: ChatInterface):
Expand All @@ -116,6 +119,8 @@ async def callback(msg, user, instance):

chat_interface.callback = callback
chat_interface.send("Message", respond=True)
send_button = chat_interface._input_layout[1]
assert not send_button.disabled

def test_show_stop_for_sync(self, chat_interface: ChatInterface):
def callback(msg, user, instance):
Expand All @@ -128,6 +133,30 @@ def callback(msg, user, instance):

chat_interface.callback = callback
chat_interface.send("Message", respond=True)
send_button = chat_interface._input_layout[1]
assert not send_button.disabled

def test_click_stop(self, chat_interface: ChatInterface):
async def callback(msg, user, instance):
send_button = instance._input_layout[1]
stop_button = instance._input_layout[2]
assert send_button.name == "Send"
assert stop_button.name == "Stop"
assert not send_button.visible
assert stop_button.visible
wait_until(lambda: len(instance.objects) == 2)
assert instance._placeholder in instance.objects
instance._click_stop(None)
assert send_button.visible
assert not send_button.disabled
assert not stop_button.visible
assert instance._placeholder not in instance.objects

chat_interface.callback = callback
chat_interface.placeholder_threshold = 0.001
chat_interface.send("Message", respond=True)
send_button = chat_interface._input_layout[1]
assert not send_button.disabled

@pytest.mark.parametrize("widget", [TextInput(), TextAreaInput()])
def test_auto_send_types(self, chat_interface: ChatInterface, widget):
Expand Down

0 comments on commit aa61fe6

Please sign in to comment.