jostlebot Claude Opus 4.5 commited on
Commit
b688aed
·
1 Parent(s): 64a21bd

Update UI with custom color palette (warm gold, sage green, deep forest)

Browse files

- Beautiful gradient header and buttons
- Custom CSS with your color scheme
- Cleaner layout without external resource links
- Kept all 13-stage NVC practice flow

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +257 -89
app.py CHANGED
@@ -1,9 +1,5 @@
1
  """
2
  NVC Deep Practice - A Multi-Stage Nonviolent Communication Learning Space
3
-
4
- Infused with the exquisite warmth of Sarah Peyton and Tara Brach -
5
- resonant empathy meeting radical acceptance, holding space with
6
- the tenderness of complete belonging.
7
  """
8
 
9
  import gradio as gr
@@ -556,14 +552,13 @@ def get_client():
556
  """Initialize Anthropic client"""
557
  api_key = os.environ.get("anthropic_key")
558
  if not api_key:
559
- raise ValueError("anthropic_key environment variable not set")
560
  return anthropic.Anthropic(api_key=api_key)
561
 
562
  def call_claude(system_prompt, messages, context=""):
563
  """Call Claude API with given prompts"""
564
  client = get_client()
565
 
566
- # Build message content
567
  if context:
568
  user_content = f"{context}\n\nUser message: {messages[-1]['content']}" if messages else context
569
  else:
@@ -583,17 +578,12 @@ def call_claude(system_prompt, messages, context=""):
583
  def process_stage(user_input, stage, session_data, somatic_enabled):
584
  """Process current stage and return response"""
585
 
586
- # Handle stage 3 skip
587
  if stage == 3 and not somatic_enabled:
588
  return "", 4, session_data, "Skipping somatic check-in..."
589
 
590
- # Build context based on stage
591
  context = build_context(stage, session_data)
592
-
593
- # Get system prompt for current stage
594
  system_prompt = STAGE_PROMPTS.get(stage, STAGE_PROMPTS[1])
595
 
596
- # Call Claude
597
  try:
598
  response = call_claude(
599
  system_prompt,
@@ -603,10 +593,7 @@ def process_stage(user_input, stage, session_data, somatic_enabled):
603
  except Exception as e:
604
  return "", stage, session_data, f"Error calling Claude: {str(e)}"
605
 
606
- # Update session data based on stage
607
  session_data = update_session_data(stage, user_input, session_data)
608
-
609
- # Determine next stage
610
  next_stage = stage + 1 if stage < 13 else 1
611
 
612
  return response, next_stage, session_data, None
@@ -640,7 +627,6 @@ def update_session_data(stage, user_input, session_data):
640
  if stage == 1:
641
  session_data["original_message"] = user_input
642
  elif stage == 2:
643
- # Store any feelings user confirms/mentions
644
  session_data["feelings"] = session_data.get("feelings", [])
645
  elif stage == 3:
646
  session_data["body_sensations"] = user_input
@@ -654,30 +640,198 @@ def update_session_data(stage, user_input, session_data):
654
  # ============ GRADIO INTERFACE ============
655
 
656
  def create_app():
657
- """Create the Gradio interface"""
658
 
659
- # Custom CSS for warm theme
660
  custom_css = """
 
 
 
 
 
 
 
 
 
661
  .gradio-container {
662
- font-family: 'Georgia', serif !important;
 
 
 
 
 
 
 
 
 
 
663
  }
664
- .prose h1, .prose h2, .prose h3 {
665
- color: #5d4e37 !important;
 
 
 
 
 
 
666
  }
667
- .chatbot {
668
- font-size: 16px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
669
  }
670
  """
671
 
672
- with gr.Blocks(
673
- theme=gr.themes.Soft(
674
- primary_hue="amber",
675
- secondary_hue="orange",
676
- neutral_hue="stone"
677
- ),
678
- css=custom_css,
679
- title="NVC Deep Practice"
680
- ) as demo:
681
 
682
  # State variables
683
  current_stage = gr.State(value=1)
@@ -685,26 +839,29 @@ def create_app():
685
  selected_needs = gr.State(value=[])
686
 
687
  # Header
688
- gr.Markdown("""
689
- # NVC Deep Practice
690
-
691
- *Learn [Nonviolent Communication](https://www.cnvc.org/) through embodied practice*
692
-
693
- ---
694
 
695
- **How it works:** Write a raw message you want to send someone. This practice
696
- will guide you through understanding your feelings, needs, and how to express
697
- them with clarity and compassion.
 
 
698
  """)
699
 
700
  with gr.Row():
701
- # Main column
702
  with gr.Column(scale=2):
703
  chatbot = gr.Chatbot(
704
  label="Practice Session",
705
- height=450,
706
  show_label=True,
707
- avatar_images=(None, "https://em-content.zobj.net/source/twitter/376/seedling_1f331.png")
 
708
  )
709
 
710
  # Needs selector (hidden until stage 5)
@@ -750,50 +907,73 @@ def create_app():
750
 
751
  confirm_needs_btn = gr.Button("Confirm My Needs", variant="primary")
752
 
753
- # Message input
754
  msg = gr.Textbox(
755
  label="Your Message",
756
- placeholder="What do you want to say? Or type 'continue' to proceed...",
757
- lines=3
 
758
  )
759
 
760
  with gr.Row():
761
- submit_btn = gr.Button("Continue Practice", variant="primary")
762
- reset_btn = gr.Button("Start New Practice", variant="secondary")
 
 
 
 
 
 
 
 
 
763
 
764
  # Sidebar
765
  with gr.Column(scale=1):
766
- gr.Markdown("### Settings")
 
 
 
 
767
 
768
  somatic_check = gr.Checkbox(
769
  label="Include body check-ins",
770
  value=True,
771
- info="Pause to notice body sensations"
 
772
  )
773
 
774
- gr.Markdown("### Current Stage")
775
-
776
- stage_display = gr.Textbox(
777
- label="Stage",
778
- value="1/13: Raw Input",
779
- interactive=False
780
- )
 
781
 
782
  focus_display = gr.Textbox(
783
- label="Learning Focus",
784
  value="Emotional awareness",
785
- interactive=False
 
 
786
  )
787
 
788
- progress = gr.Slider(
789
- minimum=1,
790
- maximum=13,
791
- value=1,
792
- step=1,
793
- label="Progress",
794
  interactive=False
795
  )
796
 
 
 
 
 
 
 
 
 
 
 
797
 
798
  # Event handlers
799
  def handle_submit(message, history, stage, session, somatic, sel_needs):
@@ -801,7 +981,6 @@ def create_app():
801
  if not message.strip():
802
  message = "continue"
803
 
804
- # If at stage 5 and needs haven't been confirmed, prompt to select
805
  if stage == 5 and not sel_needs:
806
  bot_response = "Please take a moment to select your needs from the list above, then click 'Confirm My Needs' to continue."
807
  history = history + [[message, bot_response]]
@@ -809,16 +988,13 @@ def create_app():
809
  history, "", stage, session, sel_needs,
810
  f"{stage}/13: {STAGE_NAMES[stage]}",
811
  STAGE_FOCUS[stage],
812
- stage,
813
  gr.update(visible=True)
814
  )
815
 
816
- # If needs were just confirmed, add them to context
817
  if stage == 5 and sel_needs:
818
  session["needs"] = sel_needs
819
  message = f"I've identified these needs: {', '.join(sel_needs)}"
820
 
821
- # Process the stage
822
  response, next_stage, updated_session, error = process_stage(
823
  message, stage, session, somatic
824
  )
@@ -829,20 +1005,16 @@ def create_app():
829
  history, "", stage, session, sel_needs,
830
  f"{stage}/13: {STAGE_NAMES[stage]}",
831
  STAGE_FOCUS[stage],
832
- stage,
833
  gr.update(visible=(stage == 5))
834
  )
835
 
836
- # Update history
837
  if message != "continue":
838
  history = history + [[message, response]]
839
  else:
840
  history = history + [[None, response]]
841
 
842
- # Show needs accordion at stage 5
843
  show_needs = (next_stage == 5)
844
 
845
- # Reset if completed
846
  if stage == 13:
847
  next_stage = 1
848
  updated_session = {}
@@ -856,23 +1028,21 @@ def create_app():
856
  sel_needs,
857
  f"{next_stage}/13: {STAGE_NAMES[next_stage]}",
858
  STAGE_FOCUS[next_stage],
859
- next_stage,
860
  gr.update(visible=show_needs)
861
  )
862
 
863
  def handle_reset():
864
  """Reset the practice session"""
865
  return (
866
- [], # history
867
- "", # message
868
- 1, # stage
869
- {}, # session_data
870
- [], # selected_needs
871
  "1/13: Raw Input",
872
  "Emotional awareness",
873
- 1,
874
  gr.update(visible=False),
875
- [], [], [], [] # clear all checkboxes
876
  )
877
 
878
  def update_selected_needs(emotional, relational, value, lifestyle):
@@ -894,12 +1064,11 @@ def create_app():
894
 
895
  session["needs"] = all_selected
896
 
897
- # Process to next stage with the needs
898
  response, next_stage, updated_session, error = process_stage(
899
  f"I've identified these needs: {', '.join(all_selected)}",
900
  stage,
901
  session,
902
- True # somatic_enabled doesn't matter at this stage
903
  )
904
 
905
  history = history + [[f"Selected needs: {', '.join(all_selected)}", response]]
@@ -912,7 +1081,7 @@ def create_app():
912
  inputs=[msg, chatbot, current_stage, session_data, somatic_check, selected_needs],
913
  outputs=[
914
  chatbot, msg, current_stage, session_data, selected_needs,
915
- stage_display, focus_display, progress, needs_accordion
916
  ]
917
  )
918
 
@@ -921,7 +1090,7 @@ def create_app():
921
  inputs=[msg, chatbot, current_stage, session_data, somatic_check, selected_needs],
922
  outputs=[
923
  chatbot, msg, current_stage, session_data, selected_needs,
924
- stage_display, focus_display, progress, needs_accordion
925
  ]
926
  )
927
 
@@ -929,12 +1098,11 @@ def create_app():
929
  fn=handle_reset,
930
  outputs=[
931
  chatbot, msg, current_stage, session_data, selected_needs,
932
- stage_display, focus_display, progress, needs_accordion,
933
  emotional_needs, relational_needs, value_needs, lifestyle_needs
934
  ]
935
  )
936
 
937
- # Update selected needs display when checkboxes change
938
  for checkbox in [emotional_needs, relational_needs, value_needs, lifestyle_needs]:
939
  checkbox.change(
940
  fn=update_selected_needs,
@@ -947,9 +1115,9 @@ def create_app():
947
  inputs=[emotional_needs, relational_needs, value_needs, lifestyle_needs, chatbot, current_stage, session_data],
948
  outputs=[selected_needs, chatbot, current_stage, session_data]
949
  ).then(
950
- fn=lambda s: (f"{s}/13: {STAGE_NAMES[s]}", STAGE_FOCUS[s], s, gr.update(visible=False)),
951
  inputs=[current_stage],
952
- outputs=[stage_display, focus_display, progress, needs_accordion]
953
  )
954
 
955
  return demo
 
1
  """
2
  NVC Deep Practice - A Multi-Stage Nonviolent Communication Learning Space
 
 
 
 
3
  """
4
 
5
  import gradio as gr
 
552
  """Initialize Anthropic client"""
553
  api_key = os.environ.get("anthropic_key")
554
  if not api_key:
555
+ raise ValueError("anthropic_key environment variable not set. Add it in Space Settings > Repository secrets.")
556
  return anthropic.Anthropic(api_key=api_key)
557
 
558
  def call_claude(system_prompt, messages, context=""):
559
  """Call Claude API with given prompts"""
560
  client = get_client()
561
 
 
562
  if context:
563
  user_content = f"{context}\n\nUser message: {messages[-1]['content']}" if messages else context
564
  else:
 
578
  def process_stage(user_input, stage, session_data, somatic_enabled):
579
  """Process current stage and return response"""
580
 
 
581
  if stage == 3 and not somatic_enabled:
582
  return "", 4, session_data, "Skipping somatic check-in..."
583
 
 
584
  context = build_context(stage, session_data)
 
 
585
  system_prompt = STAGE_PROMPTS.get(stage, STAGE_PROMPTS[1])
586
 
 
587
  try:
588
  response = call_claude(
589
  system_prompt,
 
593
  except Exception as e:
594
  return "", stage, session_data, f"Error calling Claude: {str(e)}"
595
 
 
596
  session_data = update_session_data(stage, user_input, session_data)
 
 
597
  next_stage = stage + 1 if stage < 13 else 1
598
 
599
  return response, next_stage, session_data, None
 
627
  if stage == 1:
628
  session_data["original_message"] = user_input
629
  elif stage == 2:
 
630
  session_data["feelings"] = session_data.get("feelings", [])
631
  elif stage == 3:
632
  session_data["body_sensations"] = user_input
 
640
  # ============ GRADIO INTERFACE ============
641
 
642
  def create_app():
643
+ """Create the Gradio interface with custom color palette"""
644
 
 
645
  custom_css = """
646
+ :root {
647
+ --warm-gold: #B8941E;
648
+ --olive-yellow: #A8A832;
649
+ --deep-forest: #3D5932;
650
+ --sage-green: #6B8070;
651
+ --soft-cream: #F8F6F0;
652
+ --warm-beige: #EAE6DC;
653
+ }
654
+
655
  .gradio-container {
656
+ font-family: 'Inter', 'Segoe UI', system-ui, sans-serif !important;
657
+ background: var(--soft-cream) !important;
658
+ }
659
+
660
+ .main-header {
661
+ background: linear-gradient(135deg, var(--warm-gold) 0%, #C9A52E 100%);
662
+ padding: 2.5rem 2rem;
663
+ border-radius: 16px;
664
+ margin-bottom: 2rem;
665
+ border: none;
666
+ box-shadow: 0 4px 20px rgba(184, 148, 30, 0.2);
667
  }
668
+
669
+ .main-header h1 {
670
+ color: white;
671
+ font-size: 2.2rem;
672
+ font-weight: 600;
673
+ margin-bottom: 0.5rem;
674
+ letter-spacing: -0.02em;
675
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
676
  }
677
+
678
+ .main-header p {
679
+ color: rgba(255, 255, 255, 0.95);
680
+ font-size: 1.05rem;
681
+ line-height: 1.6;
682
+ margin-top: 0.5rem;
683
+ }
684
+
685
+ .intro-text {
686
+ color: var(--deep-forest);
687
+ font-size: 1.05rem;
688
+ line-height: 1.7;
689
+ padding: 1.25rem 1.5rem;
690
+ background: white;
691
+ border-radius: 12px;
692
+ border-left: 4px solid var(--sage-green);
693
+ margin-bottom: 1.5rem;
694
+ box-shadow: 0 2px 8px rgba(61, 89, 50, 0.08);
695
+ }
696
+
697
+ #chatbot {
698
+ border: 2px solid var(--sage-green) !important;
699
+ border-radius: 16px !important;
700
+ background: white !important;
701
+ box-shadow: 0 4px 16px rgba(61, 89, 50, 0.1) !important;
702
+ }
703
+
704
+ .message.user {
705
+ background: linear-gradient(135deg, var(--olive-yellow) 0%, #B8B840 100%) !important;
706
+ color: white !important;
707
+ border: none !important;
708
+ border-radius: 18px 18px 4px 18px !important;
709
+ padding: 0.85rem 1.1rem !important;
710
+ margin: 0.5rem 0 !important;
711
+ box-shadow: 0 2px 8px rgba(168, 168, 50, 0.2) !important;
712
+ }
713
+
714
+ .message.bot {
715
+ background: linear-gradient(135deg, var(--sage-green) 0%, #7A9080 100%) !important;
716
+ color: white !important;
717
+ border: none !important;
718
+ border-radius: 18px 18px 18px 4px !important;
719
+ padding: 0.85rem 1.1rem !important;
720
+ margin: 0.5rem 0 !important;
721
+ box-shadow: 0 2px 8px rgba(107, 128, 112, 0.2) !important;
722
+ }
723
+
724
+ textarea {
725
+ border: 2px solid var(--sage-green) !important;
726
+ border-radius: 12px !important;
727
+ padding: 1rem !important;
728
+ font-size: 1rem !important;
729
+ background: white !important;
730
+ transition: all 0.3s ease !important;
731
+ color: var(--deep-forest) !important;
732
+ }
733
+
734
+ textarea:focus {
735
+ border-color: var(--deep-forest) !important;
736
+ box-shadow: 0 0 0 3px rgba(61, 89, 50, 0.1) !important;
737
+ outline: none !important;
738
+ }
739
+
740
+ textarea::placeholder {
741
+ color: var(--sage-green) !important;
742
+ opacity: 0.7 !important;
743
+ }
744
+
745
+ .primary-button button {
746
+ background: linear-gradient(135deg, var(--deep-forest) 0%, #2D4426 100%) !important;
747
+ color: white !important;
748
+ border: none !important;
749
+ border-radius: 10px !important;
750
+ padding: 0.85rem 1.75rem !important;
751
+ font-weight: 600 !important;
752
+ font-size: 1rem !important;
753
+ transition: all 0.3s ease !important;
754
+ box-shadow: 0 3px 12px rgba(61, 89, 50, 0.3) !important;
755
+ }
756
+
757
+ .primary-button button:hover {
758
+ background: linear-gradient(135deg, #2D4426 0%, #1D3416 100%) !important;
759
+ box-shadow: 0 5px 16px rgba(61, 89, 50, 0.4) !important;
760
+ transform: translateY(-2px) !important;
761
+ }
762
+
763
+ .secondary-button button {
764
+ background: linear-gradient(135deg, var(--sage-green) 0%, #7A9080 100%) !important;
765
+ color: white !important;
766
+ border: none !important;
767
+ border-radius: 10px !important;
768
+ padding: 0.85rem 1.5rem !important;
769
+ font-weight: 500 !important;
770
+ transition: all 0.3s ease !important;
771
+ box-shadow: 0 2px 8px rgba(107, 128, 112, 0.2) !important;
772
+ }
773
+
774
+ .secondary-button button:hover {
775
+ background: linear-gradient(135deg, #7A9080 0%, #8AA090 100%) !important;
776
+ box-shadow: 0 4px 12px rgba(107, 128, 112, 0.3) !important;
777
+ transform: translateY(-1px) !important;
778
+ }
779
+
780
+ .sidebar-section {
781
+ background: white;
782
+ border-radius: 12px;
783
+ padding: 1.25rem;
784
+ margin-bottom: 1.25rem;
785
+ border: 2px solid var(--warm-beige);
786
+ box-shadow: 0 2px 8px rgba(61, 89, 50, 0.06);
787
+ }
788
+
789
+ .sidebar-section h3 {
790
+ color: var(--deep-forest);
791
+ font-size: 1.1rem;
792
+ font-weight: 600;
793
+ margin-bottom: 0.75rem;
794
+ padding-bottom: 0.5rem;
795
+ border-bottom: 2px solid var(--olive-yellow);
796
+ }
797
+
798
+ .focus-display input {
799
+ background: linear-gradient(135deg, var(--warm-gold) 0%, #C9A52E 100%) !important;
800
+ border: none !important;
801
+ border-radius: 10px !important;
802
+ padding: 1rem !important;
803
+ font-size: 1.05rem !important;
804
+ font-weight: 600 !important;
805
+ color: white !important;
806
+ text-align: center !important;
807
+ box-shadow: 0 3px 12px rgba(184, 148, 30, 0.25) !important;
808
+ }
809
+
810
+ input[type="checkbox"] {
811
+ accent-color: var(--deep-forest) !important;
812
+ }
813
+
814
+ .checkbox-label {
815
+ color: var(--deep-forest) !important;
816
+ font-weight: 500 !important;
817
+ }
818
+
819
+ label {
820
+ color: var(--deep-forest) !important;
821
+ font-weight: 500 !important;
822
+ }
823
+
824
+ .card-shadow {
825
+ box-shadow: 0 3px 15px rgba(61, 89, 50, 0.1);
826
  }
827
  """
828
 
829
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft(
830
+ primary_hue="green",
831
+ secondary_hue="amber",
832
+ neutral_hue="stone",
833
+ font=["Inter", "system-ui", "sans-serif"]
834
+ )) as demo:
 
 
 
835
 
836
  # State variables
837
  current_stage = gr.State(value=1)
 
839
  selected_needs = gr.State(value=[])
840
 
841
  # Header
842
+ gr.HTML("""
843
+ <div class="main-header card-shadow">
844
+ <h1>NVC Deep Practice</h1>
845
+ <p><strong>Learn <a href="https://www.cnvc.org/" target="_blank" style="color: white; text-decoration: underline;">Nonviolent Communication</a> through embodied practice</strong></p>
846
+ </div>
847
+ """)
848
 
849
+ gr.HTML("""
850
+ <div class="intro-text">
851
+ Write a raw message you want to send someone. This practice will guide you through
852
+ understanding your feelings, needs, and how to express them with clarity and compassion.
853
+ </div>
854
  """)
855
 
856
  with gr.Row():
857
+ # Main chat area
858
  with gr.Column(scale=2):
859
  chatbot = gr.Chatbot(
860
  label="Practice Session",
861
+ height=500,
862
  show_label=True,
863
+ elem_id="chatbot",
864
+ bubble_full_width=False
865
  )
866
 
867
  # Needs selector (hidden until stage 5)
 
907
 
908
  confirm_needs_btn = gr.Button("Confirm My Needs", variant="primary")
909
 
 
910
  msg = gr.Textbox(
911
  label="Your Message",
912
+ placeholder="What would you like to say? Share what's alive in you...",
913
+ lines=3,
914
+ show_label=False
915
  )
916
 
917
  with gr.Row():
918
+ submit_btn = gr.Button(
919
+ "Continue Practice",
920
+ variant="primary",
921
+ elem_classes=["primary-button"],
922
+ scale=2
923
+ )
924
+ reset_btn = gr.Button(
925
+ "Start Fresh",
926
+ elem_classes=["secondary-button"],
927
+ scale=1
928
+ )
929
 
930
  # Sidebar
931
  with gr.Column(scale=1):
932
+ gr.HTML("""
933
+ <div class="sidebar-section card-shadow">
934
+ <h3>Practice Settings</h3>
935
+ </div>
936
+ """)
937
 
938
  somatic_check = gr.Checkbox(
939
  label="Include body check-ins",
940
  value=True,
941
+ info="Pause to notice body sensations",
942
+ elem_classes=["checkbox-label"]
943
  )
944
 
945
+ gr.HTML("""
946
+ <div class="sidebar-section card-shadow" style="margin-top: 1.5rem;">
947
+ <h3>Current Focus</h3>
948
+ <p style="color: #6B8070; font-size: 0.9rem; margin-bottom: 0.75rem;">
949
+ Track your learning journey
950
+ </p>
951
+ </div>
952
+ """)
953
 
954
  focus_display = gr.Textbox(
 
955
  value="Emotional awareness",
956
+ interactive=False,
957
+ elem_classes=["focus-display"],
958
+ show_label=False
959
  )
960
 
961
+ stage_display = gr.Textbox(
962
+ label="Stage",
963
+ value="1/13: Raw Input",
 
 
 
964
  interactive=False
965
  )
966
 
967
+ gr.HTML("""
968
+ <div class="sidebar-section card-shadow" style="margin-top: 1.5rem;">
969
+ <h3>About This Practice</h3>
970
+ <p style="color: #3D5932; font-size: 0.9rem; line-height: 1.6;">
971
+ This practice uses AI to guide you through the NVC process with warmth
972
+ and attunement. Each stage builds on the last, helping you discover
973
+ what's truly alive in you and how to express it with clarity.
974
+ </p>
975
+ </div>
976
+ """)
977
 
978
  # Event handlers
979
  def handle_submit(message, history, stage, session, somatic, sel_needs):
 
981
  if not message.strip():
982
  message = "continue"
983
 
 
984
  if stage == 5 and not sel_needs:
985
  bot_response = "Please take a moment to select your needs from the list above, then click 'Confirm My Needs' to continue."
986
  history = history + [[message, bot_response]]
 
988
  history, "", stage, session, sel_needs,
989
  f"{stage}/13: {STAGE_NAMES[stage]}",
990
  STAGE_FOCUS[stage],
 
991
  gr.update(visible=True)
992
  )
993
 
 
994
  if stage == 5 and sel_needs:
995
  session["needs"] = sel_needs
996
  message = f"I've identified these needs: {', '.join(sel_needs)}"
997
 
 
998
  response, next_stage, updated_session, error = process_stage(
999
  message, stage, session, somatic
1000
  )
 
1005
  history, "", stage, session, sel_needs,
1006
  f"{stage}/13: {STAGE_NAMES[stage]}",
1007
  STAGE_FOCUS[stage],
 
1008
  gr.update(visible=(stage == 5))
1009
  )
1010
 
 
1011
  if message != "continue":
1012
  history = history + [[message, response]]
1013
  else:
1014
  history = history + [[None, response]]
1015
 
 
1016
  show_needs = (next_stage == 5)
1017
 
 
1018
  if stage == 13:
1019
  next_stage = 1
1020
  updated_session = {}
 
1028
  sel_needs,
1029
  f"{next_stage}/13: {STAGE_NAMES[next_stage]}",
1030
  STAGE_FOCUS[next_stage],
 
1031
  gr.update(visible=show_needs)
1032
  )
1033
 
1034
  def handle_reset():
1035
  """Reset the practice session"""
1036
  return (
1037
+ [],
1038
+ "",
1039
+ 1,
1040
+ {},
1041
+ [],
1042
  "1/13: Raw Input",
1043
  "Emotional awareness",
 
1044
  gr.update(visible=False),
1045
+ [], [], [], []
1046
  )
1047
 
1048
  def update_selected_needs(emotional, relational, value, lifestyle):
 
1064
 
1065
  session["needs"] = all_selected
1066
 
 
1067
  response, next_stage, updated_session, error = process_stage(
1068
  f"I've identified these needs: {', '.join(all_selected)}",
1069
  stage,
1070
  session,
1071
+ True
1072
  )
1073
 
1074
  history = history + [[f"Selected needs: {', '.join(all_selected)}", response]]
 
1081
  inputs=[msg, chatbot, current_stage, session_data, somatic_check, selected_needs],
1082
  outputs=[
1083
  chatbot, msg, current_stage, session_data, selected_needs,
1084
+ stage_display, focus_display, needs_accordion
1085
  ]
1086
  )
1087
 
 
1090
  inputs=[msg, chatbot, current_stage, session_data, somatic_check, selected_needs],
1091
  outputs=[
1092
  chatbot, msg, current_stage, session_data, selected_needs,
1093
+ stage_display, focus_display, needs_accordion
1094
  ]
1095
  )
1096
 
 
1098
  fn=handle_reset,
1099
  outputs=[
1100
  chatbot, msg, current_stage, session_data, selected_needs,
1101
+ stage_display, focus_display, needs_accordion,
1102
  emotional_needs, relational_needs, value_needs, lifestyle_needs
1103
  ]
1104
  )
1105
 
 
1106
  for checkbox in [emotional_needs, relational_needs, value_needs, lifestyle_needs]:
1107
  checkbox.change(
1108
  fn=update_selected_needs,
 
1115
  inputs=[emotional_needs, relational_needs, value_needs, lifestyle_needs, chatbot, current_stage, session_data],
1116
  outputs=[selected_needs, chatbot, current_stage, session_data]
1117
  ).then(
1118
+ fn=lambda s: (f"{s}/13: {STAGE_NAMES[s]}", STAGE_FOCUS[s], gr.update(visible=False)),
1119
  inputs=[current_stage],
1120
+ outputs=[stage_display, focus_display, needs_accordion]
1121
  )
1122
 
1123
  return demo