Deminiko commited on
Commit
23172e4
Β·
1 Parent(s): af942d4

stop emoji fade

Browse files
Files changed (1) hide show
  1. app.py +69 -50
app.py CHANGED
@@ -88,6 +88,12 @@ custom_css = """
88
  min-width: 120px;
89
  }
90
 
 
 
 
 
 
 
91
  .chat-container {
92
  border-radius: 15px;
93
  overflow: hidden;
@@ -121,7 +127,7 @@ with gr.Blocks(title="Emoji AI Avatar") as demo:
121
  with gr.Row(elem_classes="emoji-container"):
122
  with gr.Column(elem_classes="emoji-box"):
123
  user_emoji_display = gr.HTML(
124
- get_emoji_html("😐", "You: waiting..."),
125
  label="Your Emoji"
126
  )
127
  with gr.Column(elem_classes="emoji-box"):
@@ -266,7 +272,7 @@ with gr.Blocks(title="Emoji AI Avatar") as demo:
266
  def update_user_emoji_live(text: str):
267
  """Update user emoji in real-time as they type - EVERY KEYSTROKE"""
268
  if not text or not text.strip():
269
- return get_emoji_html("😐", "You: waiting...")
270
 
271
  # Analyze sentiment on every keystroke for live updates
272
  # The analyzer now focuses on the LAST SENTENCE for accuracy
@@ -331,12 +337,16 @@ with gr.Blocks(title="Emoji AI Avatar") as demo:
331
  """
332
  Stream chat response with MCP as grounding context.
333
  MCP provides context/skills that enhance Gemini's responses.
 
 
 
334
  """
335
  if not message.strip():
 
336
  yield (
337
  history,
338
- get_emoji_html("😐", "You: neutral"),
339
- get_emoji_html("😐", "AI: neutral"),
340
  )
341
  return
342
 
@@ -348,31 +358,22 @@ with gr.Blocks(title="Emoji AI Avatar") as demo:
348
  # Create new history with user message
349
  new_history = list(history) + [{"role": "user", "content": message}]
350
 
351
- # Initial state - show MCP context gathering if enabled
352
- if use_mcp and mcp_client.connected:
353
- current_ai_emoji = "πŸ”Œ"
354
- current_ai_label = f"AI + MCP ({mcp_client.space_name}): gathering context..."
355
- else:
356
- current_ai_emoji = "πŸ€”"
357
- current_ai_label = "AI: thinking..."
358
 
 
359
  yield (
360
  new_history,
361
  user_emoji_html,
362
- get_emoji_html(current_ai_emoji, current_ai_label),
363
  )
364
 
365
- # Get MCP context if enabled
366
  mcp_context = ""
367
  if use_mcp and mcp_client.connected:
368
  mcp_context = mcp_client.get_context_for_llm(message)
369
- if mcp_context:
370
- # Update status to show we got context
371
- yield (
372
- new_history,
373
- user_emoji_html,
374
- get_emoji_html("🧠", f"AI + MCP: processing with context..."),
375
- )
376
 
377
  # Build the enhanced message with MCP context
378
  if mcp_context:
@@ -404,19 +405,25 @@ Please answer the user's question, incorporating the MCP context where relevant.
404
  if elapsed < STREAM_DELAY:
405
  time.sleep(STREAM_DELAY - elapsed)
406
  last_yield_time = time.time()
407
-
408
- # Update AI emoji every 2 chunks
409
  if chunk_count % 2 == 0:
410
- partial_sentiment = sentiment_analyzer.analyze(full_response)
411
- detected_emotion = partial_sentiment["label"]
412
- if detected_emotion != last_emotion and detected_emotion:
413
- last_emotion = detected_emotion
414
- current_ai_emoji = emoji_mapper.get_emoji(detected_emotion)
415
- # Show MCP indicator if using MCP
416
- if mcp_context:
417
- current_ai_label = f"AI+MCP: {detected_emotion}"
418
- else:
419
- current_ai_label = f"AI: {detected_emotion}"
 
 
 
 
 
 
420
 
421
  # Add MCP indicator to response if context was used
422
  display_response = full_response
@@ -429,11 +436,21 @@ Please answer the user's question, incorporating the MCP context where relevant.
429
  {"role": "user", "content": message},
430
  {"role": "assistant", "content": display_response}
431
  ]
432
-
 
 
 
 
 
 
 
 
 
 
433
  yield (
434
  display_history,
435
  user_emoji_html,
436
- get_emoji_html(current_ai_emoji, current_ai_label),
437
  )
438
 
439
  # Final sentiment analysis
@@ -502,10 +519,6 @@ Please answer the user's question, incorporating the MCP context where relevant.
502
  lambda: "",
503
  None,
504
  msg,
505
- ).then(
506
- lambda: get_emoji_html("😐", "You: waiting..."),
507
- None,
508
- user_emoji_display,
509
  )
510
 
511
  submit_btn.click(
@@ -516,10 +529,6 @@ Please answer the user's question, incorporating the MCP context where relevant.
516
  lambda: "",
517
  None,
518
  msg,
519
- ).then(
520
- lambda: get_emoji_html("😐", "You: waiting..."),
521
- None,
522
- user_emoji_display,
523
  )
524
 
525
  # Clear button
@@ -527,7 +536,7 @@ Please answer the user's question, incorporating the MCP context where relevant.
527
 
528
  def clear_chat():
529
  gemini.reset_chat() # Reset Gemini chat history too
530
- return [], get_emoji_html("😐", "You: waiting..."), get_emoji_html("😐", "AI: neutral")
531
 
532
  clear_btn.click(
533
  clear_chat,
@@ -592,13 +601,23 @@ if __name__ == "__main__":
592
  port = _choose_port(preferred=preferred_port, start=7861, end=7870)
593
 
594
  if port:
595
- print(f"πŸš€ Starting Gradio on 0.0.0.0:{port}")
596
  else:
597
  print(f"πŸš€ Starting Gradio with auto-assigned port")
598
 
599
- demo.launch(
600
- server_name="0.0.0.0",
601
- server_port=port,
602
- share=False,
603
- css=custom_css,
604
- )
 
 
 
 
 
 
 
 
 
 
 
88
  min-width: 120px;
89
  }
90
 
91
+ /* Prevent fades/transitions and enforce full opacity for emoji displays */
92
+ .emoji-box, .emoji-box * {
93
+ transition: none !important;
94
+ opacity: 1 !important;
95
+ }
96
+
97
  .chat-container {
98
  border-radius: 15px;
99
  overflow: hidden;
 
127
  with gr.Row(elem_classes="emoji-container"):
128
  with gr.Column(elem_classes="emoji-box"):
129
  user_emoji_display = gr.HTML(
130
+ get_emoji_html("😐", "You"),
131
  label="Your Emoji"
132
  )
133
  with gr.Column(elem_classes="emoji-box"):
 
272
  def update_user_emoji_live(text: str):
273
  """Update user emoji in real-time as they type - EVERY KEYSTROKE"""
274
  if not text or not text.strip():
275
+ return get_emoji_html("😐", "You")
276
 
277
  # Analyze sentiment on every keystroke for live updates
278
  # The analyzer now focuses on the LAST SENTENCE for accuracy
 
337
  """
338
  Stream chat response with MCP as grounding context.
339
  MCP provides context/skills that enhance Gemini's responses.
340
+
341
+ EMOJI DISPLAY: Keeps previous emoji stable until new emotion is detected.
342
+ No 'thinking' or intermediate states shown.
343
  """
344
  if not message.strip():
345
+ # No message β€” don't overwrite existing emoji displays
346
  yield (
347
  history,
348
+ None,
349
+ None,
350
  )
351
  return
352
 
 
358
  # Create new history with user message
359
  new_history = list(history) + [{"role": "user", "content": message}]
360
 
361
+ # STABLE EMOJI: Keep previous AI emoji unchanged until a new emotion is detected
362
+ current_ai_emoji = None
363
+ current_ai_label = None
364
+ last_yielded_ai_html = None
 
 
 
365
 
366
+ # don't overwrite the AI emoji at stream start; leave it unchanged until we detect a real emotion
367
  yield (
368
  new_history,
369
  user_emoji_html,
370
+ None,
371
  )
372
 
373
+ # Get MCP context if enabled (no emoji change during context gathering)
374
  mcp_context = ""
375
  if use_mcp and mcp_client.connected:
376
  mcp_context = mcp_client.get_context_for_llm(message)
 
 
 
 
 
 
 
377
 
378
  # Build the enhanced message with MCP context
379
  if mcp_context:
 
405
  if elapsed < STREAM_DELAY:
406
  time.sleep(STREAM_DELAY - elapsed)
407
  last_yield_time = time.time()
408
+
409
+ # Update AI emoji every 2 chunks - ONLY when emotion changes
410
  if chunk_count % 2 == 0:
411
+ partial_sentiment = sentiment_analyzer.analyze(full_response)
412
+ detected_emotion = partial_sentiment["label"]
413
+ # Only update emoji if emotion actually changed (not empty)
414
+ if detected_emotion and detected_emotion != "neutral" and detected_emotion != last_emotion:
415
+ last_emotion = detected_emotion
416
+ current_ai_emoji = emoji_mapper.get_emoji(detected_emotion)
417
+ # Show MCP indicator if using MCP
418
+ if mcp_context:
419
+ current_ai_label = f"AI+MCP: {detected_emotion}"
420
+ else:
421
+ current_ai_label = f"AI: {detected_emotion}"
422
+ elif detected_emotion == "neutral" and last_emotion == "":
423
+ # First detection is neutral - update label but keep neutral emoji
424
+ last_emotion = "neutral"
425
+ current_ai_emoji = "😐"
426
+ current_ai_label = "AI: neutral"
427
 
428
  # Add MCP indicator to response if context was used
429
  display_response = full_response
 
436
  {"role": "user", "content": message},
437
  {"role": "assistant", "content": display_response}
438
  ]
439
+
440
+ # Only update ai_emoji_display when AI emoji actually changed
441
+ ai_html_to_yield = None
442
+ if current_ai_emoji is not None:
443
+ ai_html_to_yield = get_emoji_html(current_ai_emoji, current_ai_label)
444
+ # If identical to last yielded HTML, avoid updating to prevent visual flicker
445
+ if ai_html_to_yield == last_yielded_ai_html:
446
+ ai_html_to_yield = None
447
+ else:
448
+ last_yielded_ai_html = ai_html_to_yield
449
+
450
  yield (
451
  display_history,
452
  user_emoji_html,
453
+ ai_html_to_yield,
454
  )
455
 
456
  # Final sentiment analysis
 
519
  lambda: "",
520
  None,
521
  msg,
 
 
 
 
522
  )
523
 
524
  submit_btn.click(
 
529
  lambda: "",
530
  None,
531
  msg,
 
 
 
 
532
  )
533
 
534
  # Clear button
 
536
 
537
  def clear_chat():
538
  gemini.reset_chat() # Reset Gemini chat history too
539
+ return [], get_emoji_html("😐", "You"), get_emoji_html("😐", "AI: neutral")
540
 
541
  clear_btn.click(
542
  clear_chat,
 
601
  port = _choose_port(preferred=preferred_port, start=7861, end=7870)
602
 
603
  if port:
604
+ print(f"πŸš€ Attempting to start Gradio on 0.0.0.0:{port}")
605
  else:
606
  print(f"πŸš€ Starting Gradio with auto-assigned port")
607
 
608
+ # Try launching on the chosen port, but gracefully fallback to auto-assignment
609
+ # if Gradio raises OSError (port collision/race condition).
610
+ try:
611
+ demo.launch(
612
+ server_name="0.0.0.0",
613
+ server_port=port,
614
+ share=False,
615
+ css=custom_css,
616
+ )
617
+ except OSError as e:
618
+ print(f"⚠️ Failed to bind to port {port}: {e}. Falling back to auto-assigned port.")
619
+ demo.launch(
620
+ server_name="0.0.0.0",
621
+ share=False,
622
+ css=custom_css,
623
+ )