anhkhoiphan commited on
Commit
16846bc
·
verified ·
1 Parent(s): 911781e

Sửa để animation chạy liên tục cho đến khi có response từ API hoặc timeout

Browse files
Files changed (1) hide show
  1. app.py +54 -12
app.py CHANGED
@@ -537,14 +537,14 @@ class UIService:
537
 
538
  @staticmethod
539
  async def create_typing_animation():
540
- """Create typing animation effect"""
541
  msg = cl.Message(content="", author="assistant")
542
  await msg.send()
543
 
544
  # Typing animation frames
545
  typing_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
546
 
547
- for i in range(40): # Show animation for ~10 seconds
548
  frame = typing_frames[i % len(typing_frames)]
549
  msg.content = f"{frame} Đang suy nghĩ..."
550
  await msg.update()
@@ -553,6 +553,25 @@ class UIService:
553
  return msg
554
 
555
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
  # HELPER FUNCTIONS: Session management with proper async error handling
557
  async def ensure_session_state() -> Optional[ConversationState]:
558
  """Ensure session state exists, create if not"""
@@ -803,7 +822,7 @@ async def on_debug_sessions(action):
803
 
804
  @cl.on_message
805
  async def main(message: cl.Message):
806
- """Main message handler with proper async flow"""
807
  app_state = await ensure_session_state()
808
  if app_state is None:
809
  await cl.Message(content="Error: Session state not found", author="assistant").send()
@@ -817,14 +836,37 @@ async def main(message: cl.Message):
817
  image_path = element.path
818
  break
819
 
820
- # Show typing animation
821
- typing_msg = await UIService.create_typing_animation()
 
822
 
823
- # Get response from API - now fully async, won't block event loop
824
- response = await ChatService.respond_to_chat(app_state, message.content, image_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
825
 
826
- # Update the typing message with final response and buttons
827
- typing_msg.content = response
828
- typing_msg.actions = UIService.create_action_buttons(app_state)
829
- typing_msg.author = "assistant"
830
- await typing_msg.update()
 
537
 
538
  @staticmethod
539
  async def create_typing_animation():
540
+ """Create typing animation effect (legacy method - kept for compatibility)"""
541
  msg = cl.Message(content="", author="assistant")
542
  await msg.send()
543
 
544
  # Typing animation frames
545
  typing_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
546
 
547
+ for i in range(27): # Show animation for ~2 seconds
548
  frame = typing_frames[i % len(typing_frames)]
549
  msg.content = f"{frame} Đang suy nghĩ..."
550
  await msg.update()
 
553
  return msg
554
 
555
 
556
+ async def run_typing_animation(msg: cl.Message):
557
+ """Run typing animation until cancelled"""
558
+ typing_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
559
+ frame_index = 0
560
+
561
+ try:
562
+ while True: # Run indefinitely until cancelled
563
+ frame = typing_frames[frame_index % len(typing_frames)]
564
+ msg.content = f"{frame} Đang suy nghĩ..."
565
+ await msg.update()
566
+ await asyncio.sleep(0.25)
567
+ frame_index += 1
568
+
569
+ except asyncio.CancelledError:
570
+ # Animation was cancelled, this is expected
571
+ print("🎬 Animation cancelled - API response received")
572
+ raise
573
+
574
+
575
  # HELPER FUNCTIONS: Session management with proper async error handling
576
  async def ensure_session_state() -> Optional[ConversationState]:
577
  """Ensure session state exists, create if not"""
 
822
 
823
  @cl.on_message
824
  async def main(message: cl.Message):
825
+ """Main message handler with concurrent animation and API call"""
826
  app_state = await ensure_session_state()
827
  if app_state is None:
828
  await cl.Message(content="Error: Session state not found", author="assistant").send()
 
836
  image_path = element.path
837
  break
838
 
839
+ # Create initial message for animation
840
+ msg = cl.Message(content="", author="assistant")
841
+ await msg.send()
842
 
843
+ # Create concurrent tasks for animation and API call
844
+ animation_task = asyncio.create_task(run_typing_animation(msg))
845
+ api_task = asyncio.create_task(ChatService.respond_to_chat(app_state, message.content, image_path))
846
+
847
+ try:
848
+ # Wait for API response (this will complete first usually)
849
+ response = await api_task
850
+
851
+ # Cancel animation task since we have the response
852
+ animation_task.cancel()
853
+
854
+ # Wait a bit for graceful animation cancellation
855
+ try:
856
+ await asyncio.wait_for(animation_task, timeout=0.1)
857
+ except (asyncio.CancelledError, asyncio.TimeoutError):
858
+ pass
859
+
860
+ except Exception as e:
861
+ # If API fails, cancel animation and show error
862
+ animation_task.cancel()
863
+ try:
864
+ await asyncio.wait_for(animation_task, timeout=0.1)
865
+ except (asyncio.CancelledError, asyncio.TimeoutError):
866
+ pass
867
+ response = f"Error: {e}"
868
 
869
+ # Update message with final response and buttons
870
+ msg.content = response
871
+ msg.actions = UIService.create_action_buttons(app_state)
872
+ await msg.update()