jostlebot commited on
Commit
896e97c
Β·
1 Parent(s): 769184f

Add enhanced features: voice switching, quick reactions, and detailed somatic tracking

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +259 -195
src/streamlit_app.py CHANGED
@@ -2,283 +2,347 @@ import os
2
  import streamlit as st
3
  from anthropic import Anthropic
4
  from dotenv import load_dotenv
 
5
 
6
  # Initialize page configuration first
7
  st.set_page_config(
8
- page_title="Attachment Style Roleplay Simulator",
9
  page_icon="πŸ—£οΈ",
10
  layout="wide"
11
  )
12
 
13
- # Handle API key
14
  try:
15
- # Load from .env file for local development
16
  if os.path.exists(".env"):
17
  load_dotenv()
18
 
19
- # Try multiple ways to get the API key
20
  api_key = None
21
-
22
- # Try direct environment variable
23
  if 'ANTHROPIC_API_KEY' in os.environ:
24
  api_key = os.environ['ANTHROPIC_API_KEY']
25
-
26
- # Try getenv
27
- if not api_key:
28
- api_key = os.getenv('ANTHROPIC_API_KEY')
29
-
30
- # Try Streamlit secrets
31
- if not api_key and hasattr(st, 'secrets') and 'ANTHROPIC_API_KEY' in st.secrets:
32
  api_key = st.secrets['ANTHROPIC_API_KEY']
33
 
34
  if not api_key:
35
  st.error("""
36
- ⚠️ No API key found. Please make sure:
37
- 1. You've added the secret in Hugging Face Space settings
38
- 2. The secret is named exactly 'ANTHROPIC_API_KEY'
39
- 3. The Space has been rebuilt after adding the secret
40
  """)
41
  st.stop()
42
 
43
- # Initialize Anthropic client
44
  c = Anthropic(api_key=api_key)
45
 
46
  except Exception as e:
47
- st.error(f"""
48
- ⚠️ Error initializing Anthropic client: {str(e)}
49
-
50
- Please check:
51
- 1. Your ANTHROPIC_API_KEY is set correctly
52
- 2. You're using a valid API key from Anthropic
53
- """)
54
  st.stop()
55
 
56
- # Initialize session state variables
57
  if 'messages' not in st.session_state:
58
  st.session_state.messages = []
 
 
59
  if 'setup_complete' not in st.session_state:
60
  st.session_state.setup_complete = False
61
  if 'system_message' not in st.session_state:
62
  st.session_state.system_message = ""
63
- if 'simulation_params' not in st.session_state:
64
- st.session_state.simulation_params = {}
65
  if 'in_debrief' not in st.session_state:
66
  st.session_state.in_debrief = False
 
 
67
 
68
  # Main page header
69
- st.title("Attachment Style Roleplay Simulator")
70
 
71
- # Welcome text in main content area
72
  st.markdown("""
73
- Welcome!
74
-
75
- Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com), this tool is designed to help you practice and understand relational dynamics through the lens of attachment theory.
76
-
77
- To learn more about attachment theory and therapeutic approaches, check out my newsletter: [@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)
78
- """)
79
-
80
- st.markdown("""
81
- This specific project β€” the Attachment Roleplay Simulator β€” invites users to practice emotionally difficult conversations, like setting boundaries, through roleplay tailored to their attachment style. It's designed to help people feel into relational patterns, develop language for self-advocacy, and build nervous system capacity for connection and repair.
82
-
83
- πŸ’‘ Not sure about your attachment style?
84
- You can take the free quiz by Sarah Peyton β€” or simply choose the one that resonates when you read it:
85
-
86
- Anxious – "I often worry I've upset people or need to explain myself."
87
-
88
- Avoidant – "I'd rather deal with things alone and not depend on anyone."
89
 
90
- Disorganized – "I want closeness, but also feel unsafe or mistrusting."
91
 
92
- Secure – "I can express needs and handle conflict without losing connection."
93
 
94
- Choose what vibes β€” this is a practice space, not a test.
 
 
 
 
95
  """)
96
 
97
- # Sidebar welcome and introduction
98
- with st.sidebar:
99
- st.markdown("""
100
- Hi, I'm Jocelyn Skillman, LMHC β€” a clinical therapist, relational design ethicist, and creator of experimental tools that explore how AI can support (not replace) human care.
101
-
102
- Each tool in this collection is thoughtfully designed to:
103
-
104
- Extend therapeutic support between sessions
105
-
106
- Model emotional safety and relational depth
107
-
108
- Help clients and clinicians rehearse courage, regulation, and repair
109
-
110
- Stay grounded in trauma-informed, developmentally sensitive frameworks
111
- """)
112
-
113
- st.divider()
114
-
115
- # Add the moved content to the bottom of sidebar
116
- st.markdown("""
117
- I use Claude (by Anthropic) as the primary language model for these tools, chosen for its relational tone, contextual nuance, and responsiveness to emotionally complex prompts.
118
-
119
- As a practicing therapist, I imagine these resources being especially helpful to clinicians like myself β€” companions in the work of tending to others with insight, warmth, and care.
120
-
121
- To learn more about my work, visit:
122
- 🌐 [jocelynskillman.com](http://www.jocelynskillman.com)
123
- πŸ“¬ [Substack: Relational Code](https://jocelynskillmanlmhc.substack.com/)
124
- """)
125
-
126
- # Simulation setup form
127
  with st.form("setup_form"):
128
- st.header("Set Up Your Simulation")
129
 
130
- tone_archetype = st.selectbox(
131
- "Select the voice you'd like to engage with:",
132
- ["Ghost", "Sycophant", "Critic"]
133
- )
 
 
 
 
 
134
 
135
  scenario = st.text_area(
136
- "Describe the scenario you'd like to practice:",
137
- placeholder="Example: Having a difficult conversation with my partner about feeling disconnected"
138
  )
139
 
140
- tone = st.text_input(
141
- "How would you like the AI to respond?",
142
- placeholder="Example: Direct but understanding"
143
  )
144
 
145
  goals = st.text_area(
146
- "What are your practice goals?",
147
- placeholder="Example: Practice expressing needs without becoming defensive"
148
  )
149
 
150
- submitted = st.form_submit_button("Start Simulation")
151
 
152
  if submitted:
153
- # Store simulation parameters for debrief
154
- st.session_state.simulation_params = {
155
- "tone_archetype": tone_archetype,
156
- "scenario": scenario,
157
- "tone": tone,
158
- "goals": goals
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  }
160
 
161
- # Prepare system message with simulation parameters
162
  st.session_state.system_message = f"""
163
- You are a conversational partner helping someone practice difficult conversations.
164
- The user has a {tone_archetype} attachment style and wants to practice: {scenario}
165
 
166
- Respond in a {tone} manner. Help them achieve their goals: {goals}
 
 
 
 
167
 
168
- Maintain a realistic conversation while providing gentle guidance when needed.
 
 
 
169
 
170
- IMPORTANT: If the user types "debrief" or "end roleplay", switch to debrief mode using this format:
171
-
172
- πŸ“ DEBRIEF SUMMARY
173
-
174
- **Emotional Arc**: [Analyze how the user shifted emotionally during the interaction, noting moments of courage, freeze, protest, backtracking, or people-pleasing]
175
-
176
- **Goal Alignment**: [Reflect on how well they stayed aligned with their stated goal. Note small wins and struggles, affirm effort and awareness]
177
-
178
- **Attachment Insight**: [Offer one insight based on their {tone_archetype} attachment style. Normalize the response as protective. Gently suggest a next growth step without shaming]
179
-
180
- **Practical Tool**: [Offer a brief NVC or DBT tool they could try next time (e.g., needs check-in, opposite action, self-validation, distress tolerance)]
181
-
182
- **Bold Reframe**: [Offer one bold, loving sentence they might say if they trusted their relational worth]
183
-
184
- **Journaling Prompt**: [Suggest one reflective question or embodied inquiry for integration]
185
-
186
- Speak warmly and with psychological precision, like an emotionally attuned therapist.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  """
188
 
189
- # Reset message history and state
190
  st.session_state.messages = []
 
191
  st.session_state.setup_complete = True
192
  st.session_state.in_debrief = False
193
  st.rerun()
194
 
195
- # Display status or chat interface
196
- if not st.session_state.setup_complete:
197
- st.info("Please complete the simulation setup to begin.")
198
- else:
199
- # Display chat history
200
- for message in st.session_state.messages:
201
- with st.chat_message(message["role"]):
202
- st.markdown(message["content"])
203
-
204
- # Optional somatic input logging
205
- st.subheader("🧘 Somatic Reflection (Optional)")
206
- somatic_input = st.text_input("What’s happening in your body right now?", key="soma_input")
207
-
208
- if st.button("Log Somatic Entry"):
209
- if 'soma_log' not in st.session_state:
210
- st.session_state.soma_log = []
211
- st.session_state.soma_log.append({
212
- "timestamp": datetime.now().isoformat(),
213
- "tone": st.session_state.simulation_params.get('tone_archetype', st.session_state.simulation_params.get('tone_archetype', 'Unknown')),
214
- "somatic_input": somatic_input
215
- })
216
- st.success("Somatic reflection logged.")
217
-
218
 
219
- # Chat input
220
- if prompt := st.chat_input("Type your message here (type 'debrief' or 'end roleplay' when ready to reflect)"):
221
- # Check for debrief trigger
222
- if prompt.lower() in ["debrief", "end roleplay"] and not st.session_state.in_debrief:
223
- st.session_state.in_debrief = True
224
- # Construct conversation summary
225
- conversation_summary = "\n".join([
226
- f"{msg['role']}: {msg['content']}"
227
- for msg in st.session_state.messages
228
- ])
229
 
230
- # Add debrief request to messages
231
- prompt = f"""Please provide a therapeutic debrief for this roleplay session using:
232
-
233
- Attachment Style: {st.session_state.simulation_params['tone_archetype']}
234
- Scenario: {st.session_state.simulation_params['scenario']}
235
- Goals: {st.session_state.simulation_params['goals']}
236
- AI Tone: {st.session_state.simulation_params['tone']}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
- Conversation Summary:
239
- {conversation_summary}
240
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
- # Add user message to chat history
243
- st.session_state.messages.append({"role": "user", "content": prompt})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
 
245
- # Display user message
246
- with st.chat_message("user"):
247
- st.markdown(prompt)
 
 
 
 
 
 
 
248
 
249
- # Get AI response
250
- with st.chat_message("assistant"):
251
- with st.spinner("Thinking..."):
252
- try:
253
- message = c.messages.create(
254
- model="claude-3-opus-20240229",
255
- max_tokens=1000,
256
- system=st.session_state.system_message,
257
- messages=[
258
- {"role": msg["role"], "content": msg["content"]}
259
- for msg in st.session_state.messages
260
- ]
261
- )
262
-
263
- ai_response = message.content[0].text
264
- st.markdown(ai_response)
265
-
266
- # Add AI response to chat history
267
- st.session_state.messages.append(
268
- {"role": "assistant", "content": ai_response}
269
- )
270
- except Exception as e:
271
- st.error(f"Error getting AI response: {str(e)}")
272
- st.error("Please try again or contact support if the issue persists.")
273
 
274
  # Add restart button after debrief
275
  if st.session_state.in_debrief:
276
- if st.button("Start New Roleplay"):
277
  st.session_state.setup_complete = False
278
  st.session_state.in_debrief = False
279
  st.session_state.messages = []
 
 
280
  st.session_state.system_message = ""
281
- st.session_state.simulation_params = {}
282
  st.rerun()
283
 
284
  # Footer
 
2
  import streamlit as st
3
  from anthropic import Anthropic
4
  from dotenv import load_dotenv
5
+ from datetime import datetime
6
 
7
  # Initialize page configuration first
8
  st.set_page_config(
9
+ page_title="VoiceField",
10
  page_icon="πŸ—£οΈ",
11
  layout="wide"
12
  )
13
 
14
+ # Handle API key setup
15
  try:
 
16
  if os.path.exists(".env"):
17
  load_dotenv()
18
 
 
19
  api_key = None
 
 
20
  if 'ANTHROPIC_API_KEY' in os.environ:
21
  api_key = os.environ['ANTHROPIC_API_KEY']
22
+ elif hasattr(st, 'secrets') and 'ANTHROPIC_API_KEY' in st.secrets:
 
 
 
 
 
 
23
  api_key = st.secrets['ANTHROPIC_API_KEY']
24
 
25
  if not api_key:
26
  st.error("""
27
+ ⚠️ No API key found. Please set ANTHROPIC_API_KEY in your environment variables or Space secrets.
 
 
 
28
  """)
29
  st.stop()
30
 
 
31
  c = Anthropic(api_key=api_key)
32
 
33
  except Exception as e:
34
+ st.error(f"Error initializing Anthropic client: {str(e)}")
 
 
 
 
 
 
35
  st.stop()
36
 
37
+ # Initialize session state
38
  if 'messages' not in st.session_state:
39
  st.session_state.messages = []
40
+ if 'somatic_journal' not in st.session_state:
41
+ st.session_state.somatic_journal = []
42
  if 'setup_complete' not in st.session_state:
43
  st.session_state.setup_complete = False
44
  if 'system_message' not in st.session_state:
45
  st.session_state.system_message = ""
46
+ if 'current_voice' not in st.session_state:
47
+ st.session_state.current_voice = "Nurturing"
48
  if 'in_debrief' not in st.session_state:
49
  st.session_state.in_debrief = False
50
+ if 'voice_transitions' not in st.session_state:
51
+ st.session_state.voice_transitions = []
52
 
53
  # Main page header
54
+ st.title("VoiceField")
55
 
56
+ # Welcome text
57
  st.markdown("""
58
+ Welcome to VoiceField - a somatic exploration tool for understanding how different relational voices impact your nervous system.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
+ Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com), this tool helps you track real-time bodily responses while engaging with different conversational styles.
61
 
62
+ 🎯 **Purpose**: Explore how different relational voices affect your nervous system, emotional state, and capacity for engagement.
63
 
64
+ πŸ’‘ **How it works**:
65
+ 1. Choose a voice type to start with
66
+ 2. Engage in conversation while noting bodily sensations
67
+ 3. Switch voices anytime to explore different dynamics
68
+ 4. Receive a comprehensive somatic-relational debrief
69
  """)
70
 
71
+ # Voice selection and setup form
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  with st.form("setup_form"):
73
+ st.header("Set Up Your Exploration")
74
 
75
+ voice_type = st.selectbox(
76
+ "Choose the voice you'd like to explore:",
77
+ ["Nurturing", "Challenging", "Neutral"],
78
+ help="""
79
+ πŸ«‚ Nurturing: Warm, empathetic, and supportive. Creates safety and attunement.
80
+ πŸ” Challenging: Direct, provocative, growth-oriented. Pushes edges with respect.
81
+ βš–οΈ Neutral: Objective, clear, and grounded. Holds space without strong emotional coloring.
82
+ """
83
+ )
84
 
85
  scenario = st.text_area(
86
+ "What would you like to explore or discuss?",
87
+ placeholder="Example: I want to understand why I freeze when receiving feedback"
88
  )
89
 
90
+ somatic_focus = st.text_area(
91
+ "What bodily sensations would you like to track?",
92
+ placeholder="Example: Tension in shoulders, breath patterns, gut responses"
93
  )
94
 
95
  goals = st.text_area(
96
+ "What are your exploration goals?",
97
+ placeholder="Example: Notice how different voices affect my nervous system activation"
98
  )
99
 
100
+ submitted = st.form_submit_button("Begin Exploration")
101
 
102
  if submitted:
103
+ st.session_state.current_voice = voice_type
104
+ st.session_state.voice_transitions = [(datetime.now().strftime("%H:%M:%S"), voice_type)]
105
+
106
+ # Prepare system message with voice parameters
107
+ voice_characteristics = {
108
+ "Nurturing": {
109
+ "style": "warm, empathetic, and supportive",
110
+ "language": "gentle, validating, and attuned",
111
+ "pacing": "slow and patient",
112
+ "focus": "creating safety and connection"
113
+ },
114
+ "Challenging": {
115
+ "style": "direct, provocative, and growth-oriented",
116
+ "language": "clear, bold, and respectfully confrontational",
117
+ "pacing": "dynamic and engaging",
118
+ "focus": "expanding awareness and capacity"
119
+ },
120
+ "Neutral": {
121
+ "style": "objective, clear, and grounded",
122
+ "language": "balanced, factual, and measured",
123
+ "pacing": "steady and consistent",
124
+ "focus": "observing patterns and processes"
125
+ }
126
  }
127
 
128
+ voice = voice_characteristics[voice_type]
129
  st.session_state.system_message = f"""
130
+ You are a conversational partner helping someone explore their somatic responses to different relational styles.
 
131
 
132
+ VOICE TYPE: {voice_type}
133
+ Style: {voice['style']}
134
+ Language: {voice['language']}
135
+ Pacing: {voice['pacing']}
136
+ Focus: {voice['focus']}
137
 
138
+ CONTEXT:
139
+ - Scenario: {scenario}
140
+ - Somatic Focus: {somatic_focus}
141
+ - Goals: {goals}
142
 
143
+ KEY INSTRUCTIONS:
144
+ 1. Stay consistently in the {voice_type} voice style
145
+ 2. Keep responses focused and concise (2-3 sentences max)
146
+ 3. Occasionally invite somatic awareness with questions like:
147
+ - "What sensations are you noticing right now?"
148
+ - "How is your breath responding to this?"
149
+ - "Where do you feel this in your body?"
150
+
151
+ If the user types "debrief" or "end exploration", provide a comprehensive therapeutic debrief including:
152
+
153
+ 1. **Somatic Patterns**:
154
+ - Track patterns in bodily responses across different voice types
155
+ - Note shifts in nervous system state (activation/settling)
156
+ - Identify somatic resources and challenges
157
+
158
+ 2. **Nervous System Insights**:
159
+ - Connect responses to polyvagal theory (fight/flight/freeze/fawn)
160
+ - Explore window of tolerance and regulation capacity
161
+ - Highlight moments of co-regulation or dysregulation
162
+
163
+ 3. **Relational Dynamics**:
164
+ - Analyze engagement patterns with each voice type
165
+ - Note attachment themes or protective patterns
166
+ - Identify relational resources and growth edges
167
+
168
+ 4. **Integration Tools**:
169
+ - Offer specific somatic practices for regulation
170
+ - Suggest relational experiments for expanding capacity
171
+ - Provide nervous system education relevant to their experience
172
+
173
+ 5. **Growth Edges**:
174
+ - Frame challenges within a developmental context
175
+ - Suggest gentle next steps for expanding capacity
176
+ - Normalize and validate protective responses
177
+
178
+ 6. **Therapeutic Frame**:
179
+ - Provide relevant psychoeducation about their patterns
180
+ - Connect individual experience to broader human themes
181
+ - Offer compassionate reframes of challenges
182
+
183
+ Maintain a warm, psychodynamically-informed therapeutic voice in the debrief.
184
  """
185
 
 
186
  st.session_state.messages = []
187
+ st.session_state.somatic_journal = []
188
  st.session_state.setup_complete = True
189
  st.session_state.in_debrief = False
190
  st.rerun()
191
 
192
+ # Main interaction area
193
+ if st.session_state.setup_complete:
194
+ # Create two columns for chat and journal
195
+ chat_col, journal_col = st.columns([3, 2])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
+ with chat_col:
198
+ # Voice switching interface
199
+ if not st.session_state.in_debrief:
200
+ new_voice = st.selectbox(
201
+ "Switch voice type:",
202
+ ["Nurturing", "Challenging", "Neutral"],
203
+ index=["Nurturing", "Challenging", "Neutral"].index(st.session_state.current_voice)
204
+ )
 
 
205
 
206
+ if new_voice != st.session_state.current_voice:
207
+ st.session_state.current_voice = new_voice
208
+ timestamp = datetime.now().strftime("%H:%M:%S")
209
+ st.session_state.voice_transitions.append((timestamp, new_voice))
210
+ st.rerun()
211
+
212
+ st.subheader(f"Conversation with {st.session_state.current_voice} Voice")
213
+
214
+ # Display chat history
215
+ for message in st.session_state.messages:
216
+ with st.chat_message(message["role"]):
217
+ st.markdown(message["content"])
218
+
219
+ # Chat input
220
+ if prompt := st.chat_input(f"Chat with {st.session_state.current_voice} voice (type 'debrief' when ready to reflect)"):
221
+ # Check for debrief trigger
222
+ if prompt.lower() in ["debrief", "end exploration"] and not st.session_state.in_debrief:
223
+ st.session_state.in_debrief = True
224
+ # Prepare debrief request
225
+ voice_history = "\n".join([
226
+ f"[{time}] Switched to {voice} voice"
227
+ for time, voice in st.session_state.voice_transitions
228
+ ])
229
+
230
+ journal_summary = "\n".join([
231
+ f"[{entry['timestamp']}] {entry['note']}"
232
+ for entry in st.session_state.somatic_journal
233
+ ])
234
+
235
+ prompt = f"""Please provide a therapeutic debrief for this somatic exploration:
236
+
237
+ Voice Transitions:
238
+ {voice_history}
239
+
240
+ Somatic Journal Entries:
241
+ {journal_summary}
242
+
243
+ Conversation History:
244
+ {chr(10).join([f"{msg['role']}: {msg['content']}" for msg in st.session_state.messages])}
245
+ """
246
 
247
+ # Add user message to chat history
248
+ st.session_state.messages.append({"role": "user", "content": prompt})
249
+
250
+ # Display user message
251
+ with st.chat_message("user"):
252
+ st.markdown(prompt)
253
+
254
+ # Get AI response
255
+ with st.chat_message("assistant"):
256
+ with st.spinner("Thinking..."):
257
+ try:
258
+ message = c.messages.create(
259
+ model="claude-3-opus-20240229",
260
+ max_tokens=1000,
261
+ system=st.session_state.system_message,
262
+ messages=[
263
+ {"role": msg["role"], "content": msg["content"]}
264
+ for msg in st.session_state.messages
265
+ ]
266
+ )
267
+
268
+ ai_response = message.content[0].text
269
+ st.markdown(ai_response)
270
+
271
+ # Add AI response to chat history
272
+ st.session_state.messages.append(
273
+ {"role": "assistant", "content": ai_response}
274
+ )
275
+ except Exception as e:
276
+ st.error(f"Error getting AI response: {str(e)}")
277
+
278
+ with journal_col:
279
+ st.subheader("Somatic Journal")
280
 
281
+ # Quick reaction buttons
282
+ st.write("Quick Reactions:")
283
+ reaction_cols = st.columns(3)
284
+
285
+ reactions = {
286
+ "Nervous System": ["πŸ”΄ Activated", "🟑 Alert", "🟒 Settled"],
287
+ "Emotional": ["😌 Safe", "😰 Tense", "😢 Numb"],
288
+ "Engagement": ["πŸ‘₯ Connected", "πŸ›‘οΈ Protected", "❌ Disconnected"]
289
+ }
290
+
291
+ for i, (category, buttons) in enumerate(reactions.items()):
292
+ with reaction_cols[i]:
293
+ st.write(f"**{category}**")
294
+ for button in buttons:
295
+ if st.button(button):
296
+ timestamp = datetime.now().strftime("%H:%M:%S")
297
+ st.session_state.somatic_journal.append({
298
+ "timestamp": timestamp,
299
+ "note": f"Quick reaction: {button}"
300
+ })
301
+ st.rerun()
302
+
303
+ st.markdown("""
304
+ Use this space to note bodily sensations, emotions, and nervous system responses as they arise.
305
+ Each entry will be automatically timestamped.
306
+
307
+ πŸ’‘ Consider tracking:
308
+ - Physical sensations
309
+ - Breath patterns
310
+ - Muscle tension/release
311
+ - Energy levels
312
+ - Emotional shifts
313
+ - Relational impulses
314
+ """)
315
 
316
+ # Journal input
317
+ journal_entry = st.text_area("What are you noticing in your body right now?", key="journal_input")
318
+ if st.button("Add Journal Entry"):
319
+ if journal_entry:
320
+ timestamp = datetime.now().strftime("%H:%M:%S")
321
+ st.session_state.somatic_journal.append({
322
+ "timestamp": timestamp,
323
+ "note": journal_entry
324
+ })
325
+ st.rerun()
326
 
327
+ # Display journal entries
328
+ st.markdown("### Journal Timeline")
329
+ for entry in reversed(st.session_state.somatic_journal):
330
+ st.markdown(f"""
331
+ **{entry['timestamp']}**
332
+ {entry['note']}
333
+ ---
334
+ """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
 
336
  # Add restart button after debrief
337
  if st.session_state.in_debrief:
338
+ if st.button("Start New Exploration"):
339
  st.session_state.setup_complete = False
340
  st.session_state.in_debrief = False
341
  st.session_state.messages = []
342
+ st.session_state.somatic_journal = []
343
+ st.session_state.voice_transitions = []
344
  st.session_state.system_message = ""
345
+ st.session_state.current_voice = "Nurturing"
346
  st.rerun()
347
 
348
  # Footer