Debdeep30 commited on
Commit
6ba126c
·
verified ·
1 Parent(s): a375b99

style: clear-sky theme — white/sky-blue, large fonts, elderly-friendly UI

Browse files
Files changed (1) hide show
  1. app.py +272 -27
app.py CHANGED
@@ -297,14 +297,256 @@ def load_memory_display():
297
  # ---------------------------------------------------------------------------
298
 
299
  CSS = """
300
- #avatar-img { border-radius: 50%; max-width: 200px; margin: auto; display: block; }
301
- #avatar-video { border-radius: 16px; max-width: 280px; margin: auto; display: block; }
302
- #lumi-header { text-align: center; }
303
- .status-badge { font-size: 0.85rem; color: #555; text-align: center; }
304
- .profile-desc { font-size: 0.85rem; color: #666; text-align: center; margin-top: 4px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  """
306
 
307
- with gr.Blocks(title="Lumi — Voice Companion", theme=gr.themes.Soft(), css=CSS) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
 
309
  # ── Persistent state ────────────────────────────────────────────────────
310
  profile_state = gr.State(DEFAULT_PROFILE_ID)
@@ -312,13 +554,13 @@ with gr.Blocks(title="Lumi — Voice Companion", theme=gr.themes.Soft(), css=CSS
312
  # ── Header ──────────────────────────────────────────────────────────────
313
  with gr.Row(elem_id="lumi-header"):
314
  gr.Markdown(
315
- "# Lumi — AI Voice Companion\n"
316
- "*Powered by AMD MI300X · Fine-tuned Qwen3-4B (SFT + GRPO)*"
317
  )
318
 
319
- # ── Avatar area: static portrait (idle) + talking video (speaking) ──────
320
  with gr.Row():
321
- with gr.Column(scale=1):
322
  avatar_img = gr.Image(
323
  value=_load_portrait(DEFAULT_PROFILE_ID) or AVATAR_IMAGES["smile"],
324
  label="",
@@ -327,8 +569,8 @@ with gr.Blocks(title="Lumi — Voice Companion", theme=gr.themes.Soft(), css=CSS
327
  interactive=False,
328
  show_download_button=False,
329
  show_fullscreen_button=False,
330
- width=200,
331
- height=200,
332
  visible=True,
333
  )
334
  avatar_video = gr.Video(
@@ -337,8 +579,8 @@ with gr.Blocks(title="Lumi — Voice Companion", theme=gr.themes.Soft(), css=CSS
337
  elem_id="avatar-video",
338
  autoplay=True,
339
  visible=False,
340
- width=280,
341
- height=280,
342
  )
343
  profile_desc_md = gr.Markdown(
344
  f"**{get_profile(DEFAULT_PROFILE_ID)['display_name']}** — "
@@ -346,18 +588,19 @@ with gr.Blocks(title="Lumi — Voice Companion", theme=gr.themes.Soft(), css=CSS
346
  elem_classes=["profile-desc"],
347
  )
348
 
349
- # ── Tabs ────────────────────────────────────────────────────────────────
350
  with gr.Tabs():
351
 
352
- # Tab 1 — Text Chat ──────────────────────────────────────────────────
353
- with gr.Tab("💬 Text Chat"):
354
- chatbot1 = gr.Chatbot(height=400, label="Conversation", type="messages",
355
- show_copy_button=False, show_share_button=False)
 
356
  with gr.Row():
357
  msg1 = gr.Textbox(
358
- placeholder="Type a message to Lumi…", scale=7, container=False
359
  )
360
- send1 = gr.Button("Send", scale=1, variant="primary")
361
 
362
  gr.Examples(
363
  examples=[
@@ -367,6 +610,7 @@ with gr.Blocks(title="Lumi — Voice Companion", theme=gr.themes.Soft(), css=CSS
367
  "Tell me something cheerful.",
368
  ],
369
  inputs=msg1,
 
370
  )
371
 
372
  send1.click(
@@ -378,14 +622,15 @@ with gr.Blocks(title="Lumi — Voice Companion", theme=gr.themes.Soft(), css=CSS
378
  [chatbot1, avatar_img],
379
  ).then(lambda: "", None, msg1)
380
 
381
- # Tab 2 — Voice Chat (record → Send) ──────────────────────────────────
382
- with gr.Tab("🎤 Voice Chat"):
383
  gr.Markdown(
384
- "**Record your message, then click Send.** "
385
- "Lumi will transcribe, think, and speak back."
386
  )
387
- chatbot2 = gr.Chatbot(height=280, label="Conversation", type="messages",
388
- show_copy_button=False, show_share_button=False)
 
389
 
390
  with gr.Row():
391
  mic_input = gr.Audio(
 
297
  # ---------------------------------------------------------------------------
298
 
299
  CSS = """
300
+ /* ================================================================
301
+ Lumi Clear Sky Theme (white + soft sky-blue)
302
+ Large fonts, generous spacing, calming palette for elderly users
303
+ ================================================================ */
304
+
305
+ /* Base */
306
+ .gradio-container {
307
+ max-width: 860px !important;
308
+ margin: 0 auto !important;
309
+ background: #f7fbff !important;
310
+ font-family: 'Georgia', serif !important;
311
+ }
312
+
313
+ /* Soft sky-blue page background */
314
+ body, .main, footer {
315
+ background: #f0f6ff !important;
316
+ }
317
+
318
+ /* ── Header ─────────────────────────────────────────────────── */
319
+ #lumi-header {
320
+ text-align: center;
321
+ padding: 28px 0 12px;
322
+ background: linear-gradient(160deg, #e8f4fd 0%, #daeeff 50%, #f0f6ff 100%);
323
+ border-radius: 20px;
324
+ margin-bottom: 4px;
325
+ box-shadow: 0 2px 12px rgba(100, 160, 220, 0.12);
326
+ }
327
+ #lumi-header h1 {
328
+ font-size: 2.0rem !important;
329
+ font-weight: 700;
330
+ color: #1a5f8a;
331
+ letter-spacing: -0.3px;
332
+ margin: 0 0 4px;
333
+ }
334
+ #lumi-header p, #lumi-header em {
335
+ font-size: 0.95rem;
336
+ color: #5a8aaf;
337
+ }
338
+
339
+ /* ── Avatar ─────────────────────────────────────────────────── */
340
+ #avatar-img img {
341
+ border-radius: 50% !important;
342
+ max-width: 180px !important;
343
+ max-height: 180px !important;
344
+ object-fit: cover !important;
345
+ margin: auto;
346
+ display: block;
347
+ border: 4px solid #b8ddf5;
348
+ box-shadow: 0 4px 18px rgba(100, 160, 220, 0.25);
349
+ }
350
+ #avatar-img {
351
+ background: transparent !important;
352
+ border: none !important;
353
+ box-shadow: none !important;
354
+ padding: 0 !important;
355
+ }
356
+ #avatar-video {
357
+ border-radius: 16px;
358
+ max-width: 260px;
359
+ margin: auto;
360
+ display: block;
361
+ box-shadow: 0 4px 18px rgba(100, 160, 220, 0.22);
362
+ }
363
+ .profile-desc {
364
+ font-size: 1.0rem !important;
365
+ color: #3a7dad !important;
366
+ text-align: center;
367
+ margin-top: 8px;
368
+ font-style: italic;
369
+ }
370
+
371
+ /* ── Tabs ────────────────────────────────────────────────────── */
372
+ .tab-nav button {
373
+ font-size: 1.0rem !important;
374
+ font-weight: 600 !important;
375
+ color: #4a7fa0 !important;
376
+ border-radius: 30px 30px 0 0 !important;
377
+ padding: 10px 20px !important;
378
+ background: #eaf4fb !important;
379
+ border: none !important;
380
+ transition: all 0.2s ease;
381
+ }
382
+ .tab-nav button.selected, .tab-nav button:hover {
383
+ background: #ffffff !important;
384
+ color: #1a5f8a !important;
385
+ box-shadow: 0 -2px 8px rgba(100,160,220,0.15) !important;
386
+ }
387
+
388
+ /* ── Chatbot ─────────────────────────────────────────────────── */
389
+ .message-wrap {
390
+ font-size: 1.1rem !important;
391
+ line-height: 1.6 !important;
392
+ }
393
+ .message.user .bubble-wrap {
394
+ background: #d6ecfa !important;
395
+ border-radius: 18px 18px 4px 18px !important;
396
+ color: #1a3a52 !important;
397
+ }
398
+ .message.bot .bubble-wrap {
399
+ background: #ffffff !important;
400
+ border-radius: 18px 18px 18px 4px !important;
401
+ color: #1a3a52 !important;
402
+ border: 1.5px solid #cce5f7 !important;
403
+ box-shadow: 0 2px 8px rgba(100,160,220,0.09) !important;
404
+ }
405
+
406
+ /* ── Input textbox ───────────────────────────────────────────── */
407
+ textarea, input[type=text] {
408
+ font-size: 1.1rem !important;
409
+ border-radius: 14px !important;
410
+ border: 1.5px solid #b8d8f0 !important;
411
+ background: #ffffff !important;
412
+ color: #1a3a52 !important;
413
+ padding: 12px 16px !important;
414
+ transition: border-color 0.2s;
415
+ }
416
+ textarea:focus, input[type=text]:focus {
417
+ border-color: #5aabdf !important;
418
+ box-shadow: 0 0 0 3px rgba(90,171,223,0.15) !important;
419
+ }
420
+
421
+ /* ── Buttons ─────────────────────────────────────────────────── */
422
+ .gr-button-primary, button.primary {
423
+ background: linear-gradient(135deg, #5aabdf 0%, #2a85c7 100%) !important;
424
+ color: #ffffff !important;
425
+ font-size: 1.1rem !important;
426
+ font-weight: 700 !important;
427
+ border-radius: 30px !important;
428
+ border: none !important;
429
+ padding: 12px 28px !important;
430
+ box-shadow: 0 3px 12px rgba(42,133,199,0.28) !important;
431
+ transition: transform 0.15s, box-shadow 0.15s;
432
+ cursor: pointer;
433
+ }
434
+ .gr-button-primary:hover, button.primary:hover {
435
+ transform: translateY(-1px) !important;
436
+ box-shadow: 0 5px 18px rgba(42,133,199,0.38) !important;
437
+ }
438
+ .gr-button-secondary, button.secondary {
439
+ background: #e8f4fd !important;
440
+ color: #1a5f8a !important;
441
+ font-size: 1.0rem !important;
442
+ border-radius: 20px !important;
443
+ border: 1.5px solid #b8d8f0 !important;
444
+ }
445
+
446
+ /* ── Audio/mic recorder ─────────────────────────────────────── */
447
+ .audio-component .record-button {
448
+ background: linear-gradient(135deg, #5aabdf 0%, #2a85c7 100%) !important;
449
+ border-radius: 50% !important;
450
+ width: 56px !important;
451
+ height: 56px !important;
452
+ font-size: 1.4rem !important;
453
+ }
454
+
455
+ /* ── Status badge ────────────────────────────────────────────── */
456
+ .status-badge {
457
+ font-size: 1.0rem !important;
458
+ color: #4a7fa0 !important;
459
+ text-align: center;
460
+ padding: 6px;
461
+ font-style: italic;
462
+ }
463
+
464
+ /* ── Radio group (profile selector) ─────────────────────────── */
465
+ .gr-radio label {
466
+ font-size: 1.05rem !important;
467
+ padding: 10px 18px !important;
468
+ border-radius: 20px !important;
469
+ border: 1.5px solid #c5dfef !important;
470
+ background: #f0f8ff !important;
471
+ margin: 4px !important;
472
+ cursor: pointer;
473
+ transition: all 0.15s;
474
+ }
475
+ .gr-radio label:hover {
476
+ background: #d6edfb !important;
477
+ border-color: #7ac0e8 !important;
478
+ }
479
+ .gr-radio input[type=radio]:checked + span, .gr-radio label.selected {
480
+ background: linear-gradient(135deg, #5aabdf 0%, #2a85c7 100%) !important;
481
+ color: #ffffff !important;
482
+ border-color: #2a85c7 !important;
483
+ }
484
+
485
+ /* ── Panel / block styling ───────────────────────────────────── */
486
+ .gr-panel, .gradio-box, .block {
487
+ border-radius: 18px !important;
488
+ border: 1px solid #daeeff !important;
489
+ background: #ffffff !important;
490
+ }
491
+
492
+ /* ── Examples ────────────────────────────────────────────────── */
493
+ .examples-table td {
494
+ font-size: 1.0rem !important;
495
+ color: #2a6a98 !important;
496
+ background: #f0f8ff !important;
497
+ border-radius: 12px !important;
498
+ padding: 8px 14px !important;
499
+ border: 1px solid #c5dfef !important;
500
+ cursor: pointer;
501
+ transition: background 0.15s;
502
+ }
503
+ .examples-table td:hover {
504
+ background: #d6edfb !important;
505
+ }
506
+
507
+ /* ── Markdown text ───────────────────────────────────────────── */
508
+ .gr-markdown, .md {
509
+ font-size: 1.05rem !important;
510
+ color: #1a3a52 !important;
511
+ line-height: 1.7 !important;
512
+ }
513
+ .gr-markdown h3 {
514
+ color: #1a5f8a !important;
515
+ font-size: 1.2rem !important;
516
+ border-bottom: 1.5px solid #c5dfef;
517
+ padding-bottom: 6px;
518
+ margin-bottom: 12px;
519
+ }
520
+
521
+ /* ── Footer ─────────────────────────────────────────────────── */
522
+ footer { display: none !important; }
523
  """
524
 
525
+ _lumi_theme = gr.themes.Soft(
526
+ primary_hue=gr.themes.colors.sky,
527
+ secondary_hue=gr.themes.colors.blue,
528
+ neutral_hue=gr.themes.colors.slate,
529
+ font=[gr.themes.GoogleFont("Lato"), "Georgia", "serif"],
530
+ font_mono=["Courier New", "monospace"],
531
+ ).set(
532
+ body_background_fill="#f0f6ff",
533
+ background_fill_primary="#ffffff",
534
+ background_fill_secondary="#eaf4fb",
535
+ border_color_primary="#c5dfef",
536
+ color_accent_soft="#d6edfb",
537
+ button_primary_background_fill="*primary_500",
538
+ button_primary_text_color="white",
539
+ button_primary_background_fill_hover="*primary_600",
540
+ block_radius="18px",
541
+ block_shadow="0 2px 12px rgba(100,160,220,0.10)",
542
+ input_radius="14px",
543
+ input_border_color="#b8d8f0",
544
+ checkbox_border_radius="8px",
545
+ prose_text_size="*text_lg",
546
+ prose_header_text_weight="700",
547
+ )
548
+
549
+ with gr.Blocks(title="Lumi — Voice Companion", theme=_lumi_theme, css=CSS) as demo:
550
 
551
  # ── Persistent state ────────────────────────────────────────────────────
552
  profile_state = gr.State(DEFAULT_PROFILE_ID)
 
554
  # ── Header ──────────────────────────────────────────────────────────────
555
  with gr.Row(elem_id="lumi-header"):
556
  gr.Markdown(
557
+ f"# ☀️ Lumi — Your Voice Companion\n"
558
+ f"*Good day, {PATIENT_NAME}! I'm here whenever you'd like to chat.*"
559
  )
560
 
561
+ # ── Avatar area: portrait (idle) + talking video (speaking) ─────────────
562
  with gr.Row():
563
+ with gr.Column(scale=1, min_width=220):
564
  avatar_img = gr.Image(
565
  value=_load_portrait(DEFAULT_PROFILE_ID) or AVATAR_IMAGES["smile"],
566
  label="",
 
569
  interactive=False,
570
  show_download_button=False,
571
  show_fullscreen_button=False,
572
+ width=180,
573
+ height=180,
574
  visible=True,
575
  )
576
  avatar_video = gr.Video(
 
579
  elem_id="avatar-video",
580
  autoplay=True,
581
  visible=False,
582
+ width=260,
583
+ height=260,
584
  )
585
  profile_desc_md = gr.Markdown(
586
  f"**{get_profile(DEFAULT_PROFILE_ID)['display_name']}** — "
 
588
  elem_classes=["profile-desc"],
589
  )
590
 
591
+ # ── Tabs ────────────────────────────────────────────────────────────────
592
  with gr.Tabs():
593
 
594
+ # Tab 1 — Chat ────────────────────────────────────────────────────────
595
+ with gr.Tab("💬 Chat"):
596
+ chatbot1 = gr.Chatbot(height=380, label="", type="messages",
597
+ show_copy_button=False, show_share_button=False,
598
+ bubble_full_width=False)
599
  with gr.Row():
600
  msg1 = gr.Textbox(
601
+ placeholder="Type something to Lumi…", scale=7, container=False, lines=1
602
  )
603
+ send1 = gr.Button("Send", scale=1, variant="primary")
604
 
605
  gr.Examples(
606
  examples=[
 
610
  "Tell me something cheerful.",
611
  ],
612
  inputs=msg1,
613
+ label="💡 Try saying...",
614
  )
615
 
616
  send1.click(
 
622
  [chatbot1, avatar_img],
623
  ).then(lambda: "", None, msg1)
624
 
625
+ # Tab 2 — Voice Chat ────────────────────────────────────
626
+ with gr.Tab("🎤 Voice"):
627
  gr.Markdown(
628
+ "🎤 **Record your message, then click Send.** "
629
+ "Lumi will listen, think, and speak back."
630
  )
631
+ chatbot2 = gr.Chatbot(height=260, label="", type="messages",
632
+ show_copy_button=False, show_share_button=False,
633
+ bubble_full_width=False)
634
 
635
  with gr.Row():
636
  mic_input = gr.Audio(