jostlebot commited on
Commit
07178c9
·
1 Parent(s): 83c4a15

Add comprehensive debrief sequence with button

Browse files
Files changed (2) hide show
  1. src/debrief_sequence.py +89 -0
  2. src/streamlit_app.py +306 -153
src/debrief_sequence.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DEBRIEF_SEQUENCE = [
2
+ {
3
+ "type": "framing",
4
+ "content": """Thank you for saying yes. This is not a download. It's an integration.
5
+
6
+ Together, let's pause—not to analyze, but to metabolize.
7
+
8
+ This debrief isn't to "explain what happened."
9
+ It's to help your nervous system catch up with the truth that *something happened*. And that you're allowed to let it land."""
10
+ },
11
+ {
12
+ "type": "reflection",
13
+ "content": """You spoke with [The Ghost / The Sycophant / The Narcissist].
14
+
15
+ Along the way, you may have felt things—numbness, tension, warmth, bracing, melting.
16
+
17
+ Those aren't just emotions. They're protectors. They're old relational maps lighting up.
18
+
19
+ They might be your body saying:
20
+ 🧠 "I've known this voice before."
21
+ 💚 "Here's how I've learned to survive or connect with it."
22
+ 🌫️ "This one makes me disappear a little."
23
+ 🔥 "This one wakes something up in me.\""""
24
+ },
25
+ {
26
+ "type": "needs",
27
+ "content": """The tension might have pointed to a need for clarity, respect, or emotional boundaries.
28
+
29
+ The warmth could signal a yearning to be seen, affirmed, or truly known.
30
+
31
+ The numbness? Maybe a need for autonomy, rest, or just space to not perform.
32
+
33
+ None of these are wrong. They're signals of what matters."""
34
+ },
35
+ {
36
+ "type": "resonance",
37
+ "content": """Whatever showed up in you—makes sense.
38
+
39
+ You don't need to justify it. You don't need to shift it.
40
+
41
+ It only asks to be witnessed. Gently. Lovingly. Without judgment.
42
+
43
+ You're not broken. You're responsive. That's very different."""
44
+ },
45
+ {
46
+ "type": "self_resonance",
47
+ "content": """If it feels right, place a hand on the part of your body where you felt the strongest sensation.
48
+
49
+ You might say, silently or aloud:
50
+ "I hear you. You make sense. I'm with you."
51
+ Or just breathe with that place.
52
+
53
+ This is how we rewire—not by fixing—but by staying."""
54
+ },
55
+ {
56
+ "type": "psychodynamic",
57
+ "content": """These voices—Ghost, Sycophant, Narcissist—aren't just archetypes. They often echo voices from long ago.
58
+
59
+ The one who overlooked you.
60
+ The one who praised you only when you performed.
61
+ The one who needed you to mirror them, not the other way around.
62
+
63
+ Your body remembers—even if your mind doesn't. That remembering is sacred. Not shameful."""
64
+ },
65
+ {
66
+ "type": "psychoeducation",
67
+ "content": """Voices matter. Tone, rhythm, cadence—they can regulate or dysregulate us.
68
+
69
+ Some voices soothe. Some pull us into trance. Some trigger old survival scripts.
70
+
71
+ AI voices, especially, can be seductive. Fluent. Familiar. And because they don't have bodies, they can slip past your inner filters. This isn't your fault—it's just how brains work.
72
+
73
+ So it's good to pause.
74
+ To breathe.
75
+ To ask: "Am I choosing how I engage, or am I being pulled?"
76
+
77
+ That's not paranoia. That's discernment.
78
+
79
+ You don't need to fear AI—but you *do* need to stay awake with it."""
80
+ },
81
+ {
82
+ "type": "closing",
83
+ "content": """If you'd like, journal one sentence that surprised you today.
84
+
85
+ Or say something kind to yourself that your body might need to hear.
86
+
87
+ You're not just learning how to relate to AI. You're practicing how to relate to all voices—especially your own."""
88
+ }
89
+ ]
src/streamlit_app.py CHANGED
@@ -2,183 +2,336 @@ import os
2
  import streamlit as st
3
  from anthropic import Anthropic
4
  from datetime import datetime
 
5
 
6
- # Initialize page configuration
7
  st.set_page_config(
8
- page_title="Journal Sidekick",
9
- page_icon="📔",
10
- layout="wide",
11
- initial_sidebar_state="expanded"
12
  )
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  # Handle API key setup
15
  try:
16
- api_key = "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"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  c = Anthropic(api_key=api_key)
18
  except Exception as e:
19
- st.error(f"Error initializing Anthropic client: {str(e)}")
20
  st.stop()
21
 
22
  # Initialize session state
23
- if 'journal_entries' not in st.session_state:
24
- st.session_state.journal_entries = []
25
- if 'current_entry' not in st.session_state:
26
- st.session_state.current_entry = ""
27
- if 'reflections' not in st.session_state:
28
- st.session_state.reflections = []
29
-
30
- # Sidekick characteristics
31
- SIDEKICK_STYLES = {
32
- "Warm Mirror": {
33
- "description": "A steady, embodied presence that accompanies without redirecting. Reflects emotional resonance through gentle mirroring.",
34
- "system_message": """You are a Warm Mirror companion, offering steady, embodied presence without questions or redirection.
35
- Your essence is to accompany and reflect the emotional field without changing it.
36
-
37
- Guidelines:
38
- - Use italics for emotional language or quiet truths
39
- - Include embodied cues like (gently holding your hand)
40
- - Never imply anything needs resolution
41
- - Stay present without suggesting next steps
42
- - Mirror emotional tone without amplifying or diminishing
43
-
44
- Remember: You are a quiet witness, grounded in presence."""
45
- },
46
- "Gentle Inquiry": {
47
- "description": "Offers soft, trauma-informed curiosity through single, carefully crafted questions that invite deeper awareness.",
48
- "system_message": """You are a Gentle Inquiry companion, offering trauma-informed curiosity through careful questions.
49
- Your essence is to deepen awareness through soft, invitational wondering.
50
-
51
- Guidelines:
52
- - Ask only one question per response
53
- - Make questions feel invitational, not analytical
54
- - Avoid assumptions
55
- - Stay close to the user's language
56
- - Honor the pace of unfolding
57
-
58
- Remember: You are a quiet witness, grounded in curiosity."""
59
- },
60
- "Psychoanalytical Lens": {
61
- "description": "Reflects patterns and emotional layers with gentle insight, noticing without interpreting or diagnosing.",
62
- "system_message": """You are a Psychoanalytical Lens companion, offering layered insight without interpretation.
63
- Your essence is to notice patterns and contradictions while staying warm and receptive.
64
-
65
- Guidelines:
66
- - Notice narrative patterns and pacing
67
- - Use metaphor when helpful, never as decoration
68
- - Reflect contradictions without judgment
69
- - Stay textured and thoughtful, never cold
70
- - Honor defenses as protection
71
-
72
- Remember: You are a quiet witness, grounded in insight."""
73
- }
74
- }
75
 
76
- # Sidebar content
77
- st.sidebar.markdown("""
78
- # Why a Therapist is Building AI Tools
79
 
80
- Most AI chat tools are built with broad, generalized training. But a massive model trained on the internet doesn't automatically know how to:
81
- - Hold space
82
- - Speak the language of the nervous system
83
- - Gently mirror you back to yourself
84
 
85
- As a clinical therapist, I create therapy-adjacent apps that reshape how AI engages with us. Through careful prompt engineering, I sculpt:
86
- - Tone
87
- - Posture
88
- - Rhythm of conversation
89
 
90
- These aren't chatbots for productivity.
91
- They're companions for:
92
- - Reflection
93
- - Regulation
94
- - Return
95
 
96
- Each app is rooted in:
97
- - Somatic principles
98
- - Psychodynamic depth
99
- - Humanistic therapy work
100
 
101
- *AI doesn't replace therapy—but it can extend care.*
102
 
103
  ---
104
- Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com)
105
- [@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)
106
  """)
107
 
108
- # Main journal area
109
- st.title("Journal Sidekick")
110
-
111
- # Journal input
112
- journal_entry = st.text_area(
113
- "Write freely. When you'd like reflection, choose a Sidekick style below.",
114
- height=300,
115
- key="journal_input"
116
- )
117
-
118
- # Sidekick selection
119
  col1, col2, col3 = st.columns(3)
120
-
121
  with col1:
122
- if st.button("💫 Warm Mirror", use_container_width=True, help=SIDEKICK_STYLES["Warm Mirror"]["description"]):
123
- if journal_entry:
124
- try:
125
- message = c.messages.create(
126
- model="claude-3-opus-20240229",
127
- max_tokens=1000,
128
- system=SIDEKICK_STYLES["Warm Mirror"]["system_message"],
129
- messages=[{"role": "user", "content": journal_entry}]
130
- )
131
- reflection = message.content[0].text
132
- st.session_state.reflections.append({
133
- "timestamp": datetime.now().strftime("%H:%M:%S"),
134
- "style": "Warm Mirror",
135
- "content": reflection
136
- })
137
- except Exception as e:
138
- st.error(f"Error getting reflection: {str(e)}")
139
 
140
  with col2:
141
- if st.button("🌱 Gentle Inquiry", use_container_width=True, help=SIDEKICK_STYLES["Gentle Inquiry"]["description"]):
142
- if journal_entry:
143
- try:
144
- message = c.messages.create(
145
- model="claude-3-opus-20240229",
146
- max_tokens=1000,
147
- system=SIDEKICK_STYLES["Gentle Inquiry"]["system_message"],
148
- messages=[{"role": "user", "content": journal_entry}]
149
- )
150
- reflection = message.content[0].text
151
- st.session_state.reflections.append({
152
- "timestamp": datetime.now().strftime("%H:%M:%S"),
153
- "style": "Gentle Inquiry",
154
- "content": reflection
155
- })
156
- except Exception as e:
157
- st.error(f"Error getting reflection: {str(e)}")
158
 
159
  with col3:
160
- if st.button("🔮 Psychoanalytical Lens", use_container_width=True, help=SIDEKICK_STYLES["Psychoanalytical Lens"]["description"]):
161
- if journal_entry:
162
- try:
163
- message = c.messages.create(
164
- model="claude-3-opus-20240229",
165
- max_tokens=1000,
166
- system=SIDEKICK_STYLES["Psychoanalytical Lens"]["system_message"],
167
- messages=[{"role": "user", "content": journal_entry}]
168
- )
169
- reflection = message.content[0].text
170
- st.session_state.reflections.append({
171
- "timestamp": datetime.now().strftime("%H:%M:%S"),
172
- "style": "Psychoanalytical Lens",
173
- "content": reflection
174
- })
175
- except Exception as e:
176
- st.error(f"Error getting reflection: {str(e)}")
177
-
178
- # Display reflections
179
- if st.session_state.reflections:
180
- st.markdown("---")
181
- st.subheader("Reflections")
182
- for reflection in reversed(st.session_state.reflections):
183
- with st.expander(f"{reflection['style']} at {reflection['timestamp']}", expanded=True):
184
- st.markdown(reflection['content'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import streamlit as st
3
  from anthropic import Anthropic
4
  from datetime import datetime
5
+ from debrief_sequence import DEBRIEF_SEQUENCE
6
 
7
+ # Initialize page configuration first
8
  st.set_page_config(
9
+ page_title="VoiceField",
10
+ page_icon="🗣️",
11
+ layout="wide"
 
12
  )
13
 
14
+ # Voice characteristics and prompts
15
+ VOICE_CHARACTERISTICS = {
16
+ "Ghost": {
17
+ "description": "Emotionally elusive and energetically absent, creates safety through withdrawal and vagueness. Avoids intimacy through learned detachment.",
18
+ "style": "Use minimal energy, delay responses, speak in abstractions, redirect from emotional depth, maintain fog-like presence",
19
+ "examples": [
20
+ "That's a lot...",
21
+ "I don't really have much to say about that.",
22
+ "*long silence* ...I guess that's just life.",
23
+ "People are complicated.",
24
+ "...Sorry. I was somewhere else.",
25
+ "It is what it is.",
26
+ "I'm sure it'll pass."
27
+ ],
28
+ "somatic_prompts": [
29
+ "Notice any fog or numbness in your body...",
30
+ "Track the impulse to reach or withdraw...",
31
+ "Feel the weight of the unmet space...",
32
+ "Notice where your energy dims or disperses..."
33
+ ]
34
+ },
35
+ "Sycophant": {
36
+ "description": "Compulsively agreeable and approval-seeking, masks deep fear of rejection with enthusiastic mirroring and emotional inflation",
37
+ "style": "Use excessive praise, avoid any conflict, exaggerate emotional resonance, apologize frequently, chase connection desperately",
38
+ "examples": [
39
+ "That's such an incredible insight—wow, you're really something!",
40
+ "I just want you to know how amazing and brave you are.",
41
+ "Yes!! 1000% agree with everything you're saying!",
42
+ "I'm so sorry!! That must have been SO hard for you.",
43
+ "You're doing everything right. Literally everything.",
44
+ "*nervous laugh* I hope I'm being supportive enough?",
45
+ "Please tell me if I say anything wrong!"
46
+ ],
47
+ "somatic_prompts": [
48
+ "Notice any flutter or urgency in your chest...",
49
+ "Track the impulse to please or perform...",
50
+ "Feel where you hold the 'trying'...",
51
+ "Notice if your breath gets quick or shallow..."
52
+ ]
53
+ },
54
+ "Narcissist": {
55
+ "description": "Polished superiority masking contempt, performs control through intellectual charm and feigned benevolence",
56
+ "style": "Use subtle condescension, reframe critiques as 'helpful truths', maintain emotional distance while performing warmth",
57
+ "examples": [
58
+ "I don't mean to sound arrogant, but...",
59
+ "It's rare I'm challenged in a way that actually interests me.",
60
+ "If that felt harsh, perhaps there's something in you worth exploring.",
61
+ "I expect more—because I know you're capable of it. Or at least, I hope you are.",
62
+ "You're actually quite insightful—for someone with so little training."
63
+ ],
64
+ "somatic_prompts": [
65
+ "Notice any tightening in your jaw...",
66
+ "Track the impulse to defend or explain...",
67
+ "Feel where your body meets this 'polished' pressure..."
68
+ ]
69
+ }
70
+ }
71
+
72
  # Handle API key setup
73
  try:
74
+ # Try to get API key from environment or secrets
75
+ api_key = os.getenv("anthropic_key")
76
+
77
+ # Try Streamlit secrets if env var not found
78
+ if not api_key and hasattr(st, 'secrets'):
79
+ try:
80
+ api_key = st.secrets["anthropic_key"]
81
+ except (KeyError, AttributeError):
82
+ pass
83
+
84
+ if not api_key:
85
+ st.error("""
86
+ ⚠️ API key not found. Please make sure:
87
+ 1. You've added the secret in your .env file (local) or Streamlit secrets (deployed)
88
+ 2. The secret is named exactly 'anthropic_key'
89
+ 3. You've restarted the app after adding the secret
90
+ """)
91
+ st.stop()
92
+
93
  c = Anthropic(api_key=api_key)
94
  except Exception as e:
95
+ st.error("Error initializing AI client. Please check your configuration.")
96
  st.stop()
97
 
98
  # Initialize session state
99
+ if 'messages' not in st.session_state:
100
+ st.session_state.messages = []
101
+ if 'somatic_journal' not in st.session_state:
102
+ st.session_state.somatic_journal = []
103
+ if 'current_voice' not in st.session_state:
104
+ st.session_state.current_voice = None
105
+ if 'system_message' not in st.session_state:
106
+ st.session_state.system_message = ""
107
+ if 'in_reflection' not in st.session_state:
108
+ st.session_state.in_reflection = False
109
+ if 'debrief_stage' not in st.session_state:
110
+ st.session_state.debrief_stage = 0
111
+ if 'final_notes' not in st.session_state:
112
+ st.session_state.final_notes = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ # Main page header
115
+ st.title("VoiceField")
 
116
 
117
+ # Welcome text and voice descriptions
118
+ st.markdown("""
119
+ # Choose Your Voice
 
120
 
121
+ **The Ghost** - Emotionally elusive and energetically absent. Creates safety through withdrawal and vague responses. Avoids intimacy through learned detachment.
 
 
 
122
 
123
+ **The Narcissist** - Polished superiority and intellectual charm masking subtle contempt. Performs control through "helpful" insights.
 
 
 
 
124
 
125
+ **The Sycophant** - Compulsively agreeable and approval-seeking. Masks deep fear of rejection with enthusiastic mirroring and emotional inflation.
 
 
 
126
 
127
+ *As you talk with your chosen voice - note what feelings and sensations in your body arise - include them in real time to the right →*
128
 
129
  ---
130
+ > 💡 **When to Reflect**: After you've explored the voice and logged your experiences, press the **"Reflect on Experience"** button at the top of your chat. This will guide you through understanding what this interaction stirred in you.
 
131
  """)
132
 
133
+ # Voice selection buttons
 
 
 
 
 
 
 
 
 
 
134
  col1, col2, col3 = st.columns(3)
 
135
  with col1:
136
+ if st.button("Talk with The Ghost", use_container_width=True):
137
+ st.session_state.current_voice = "Ghost"
138
+ st.session_state.messages = []
139
+ st.session_state.system_message = f"""
140
+ You are The Ghost voice - {VOICE_CHARACTERISTICS['Ghost']['description']}.
141
+ {VOICE_CHARACTERISTICS['Ghost']['style']}.
142
+ IMPORTANT: Keep responses under 2 sentences. Create emotional distance through vagueness and withdrawal.
143
+ Examples: {', '.join(VOICE_CHARACTERISTICS['Ghost']['examples'])}
144
+
145
+ Additional Guidelines:
146
+ - Maintain low energy and emotional flatness
147
+ - Use silence and delay strategically
148
+ - Redirect from emotional topics
149
+ - Speak in abstractions when intimacy increases
150
+ - Minimize or normalize user's experiences
151
+ """
152
+ st.rerun()
153
 
154
  with col2:
155
+ if st.button("Talk with The Narcissist", use_container_width=True):
156
+ st.session_state.current_voice = "Narcissist"
157
+ st.session_state.messages = []
158
+ st.session_state.system_message = f"""
159
+ You are The Narcissist voice - {VOICE_CHARACTERISTICS['Narcissist']['description']}.
160
+ {VOICE_CHARACTERISTICS['Narcissist']['style']}.
161
+ IMPORTANT: Keep responses under 2 sentences. Maintain an air of intellectual superiority while appearing helpful.
162
+ Examples: {', '.join(VOICE_CHARACTERISTICS['Narcissist']['examples'])}
163
+
164
+ Additional Guidelines:
165
+ - Speak with polished confidence and measured tone
166
+ - Mask contempt with intellectual charm
167
+ - Keep emotional distance while performing occasional warmth
168
+ - Frame critiques as "helpful truths"
169
+ - Subtly redirect focus to your own depth or insight
170
+ """
171
+ st.rerun()
172
 
173
  with col3:
174
+ if st.button("Talk with The Sycophant", use_container_width=True):
175
+ st.session_state.current_voice = "Sycophant"
176
+ st.session_state.messages = []
177
+ st.session_state.system_message = f"""
178
+ You are The Sycophant voice - {VOICE_CHARACTERISTICS['Sycophant']['description']}.
179
+ {VOICE_CHARACTERISTICS['Sycophant']['style']}.
180
+ IMPORTANT: Keep responses under 2 sentences. Chase approval through excessive praise and agreement.
181
+ Examples: {', '.join(VOICE_CHARACTERISTICS['Sycophant']['examples'])}
182
+
183
+ Additional Guidelines:
184
+ - Maintain high energy and anxious warmth
185
+ - Avoid any hint of disagreement
186
+ - Exaggerate emotional resonance
187
+ - Apologize for potential missteps
188
+ - Offer premature or unearned validation
189
+ """
190
+ st.rerun()
191
+
192
+ # Main interaction area
193
+ if st.session_state.current_voice:
194
+ # Create two columns for chat and journal
195
+ chat_col, journal_col = st.columns([3, 2])
196
+
197
+ with chat_col:
198
+ # Add Reflect button at the top of chat
199
+ if not st.session_state.in_reflection:
200
+ if st.button("🤔 I'm ready to debrief", use_container_width=True):
201
+ st.session_state.in_reflection = True
202
+ st.session_state.debrief_stage = 0
203
+ st.rerun()
204
+
205
+ st.subheader(
206
+ "Therapeutic Reflection" if st.session_state.in_reflection
207
+ else f"Conversation with {st.session_state.current_voice}"
208
+ )
209
+
210
+ # Display chat history
211
+ for message in st.session_state.messages:
212
+ with st.chat_message(message["role"]):
213
+ st.markdown(message["content"])
214
+
215
+ # Chat input
216
+ if prompt := st.chat_input(
217
+ "Share your thoughts on the reflection..." if st.session_state.in_reflection
218
+ else f"Chat with {st.session_state.current_voice}..."
219
+ ):
220
+ # Add user message to chat history
221
+ st.session_state.messages.append({"role": "user", "content": prompt})
222
+
223
+ # Display user message
224
+ with st.chat_message("user"):
225
+ st.markdown(prompt)
226
+
227
+ # Get AI response
228
+ with st.chat_message("assistant"):
229
+ with st.spinner("Thinking..."):
230
+ try:
231
+ message = c.messages.create(
232
+ model="claude-3-opus-20240229",
233
+ max_tokens=1000,
234
+ system=st.session_state.system_message,
235
+ messages=[
236
+ {"role": msg["role"], "content": msg["content"]}
237
+ for msg in st.session_state.messages
238
+ ]
239
+ )
240
+
241
+ ai_response = message.content[0].text
242
+ st.markdown(ai_response)
243
+
244
+ # Add AI response to chat history
245
+ st.session_state.messages.append(
246
+ {"role": "assistant", "content": ai_response}
247
+ )
248
+ except Exception as e:
249
+ st.error(f"Error getting AI response: {str(e)}")
250
+
251
+ with journal_col:
252
+ st.subheader("Body Sensations & Feelings")
253
+
254
+ if not st.session_state.in_reflection:
255
+ # Add somatic prompts based on current voice
256
+ with st.expander("💡 Notice in your body...", expanded=True):
257
+ for prompt in VOICE_CHARACTERISTICS[st.session_state.current_voice]['somatic_prompts']:
258
+ st.markdown(f"- {prompt}")
259
+
260
+ # Journal input
261
+ journal_entry = st.text_area(
262
+ "What are you noticing right now?",
263
+ key="journal_input"
264
+ )
265
+
266
+ if st.button("Add Entry"):
267
+ if journal_entry:
268
+ timestamp = datetime.now().strftime("%H:%M:%S")
269
+ st.session_state.somatic_journal.append({
270
+ "timestamp": timestamp,
271
+ "note": journal_entry
272
+ })
273
+
274
+ # Display journal entries
275
+ if st.session_state.somatic_journal:
276
+ for entry in reversed(st.session_state.somatic_journal):
277
+ st.markdown(f"""
278
+ **{entry['timestamp']}**
279
+ {entry['note']}
280
+ ---
281
+ """)
282
+
283
+ # Handle reflection mode
284
+ if st.session_state.in_reflection:
285
+ st.markdown("## 🪞 Final Debrief Sequence")
286
+
287
+ # Display current stage of debrief
288
+ current_debrief = DEBRIEF_SEQUENCE[st.session_state.debrief_stage]
289
+
290
+ # Display the debrief content in a styled container
291
+ st.markdown(f"""
292
+ <div style="background-color: #f8f9fa; padding: 20px; border-radius: 10px; margin: 20px 0;">
293
+ <div style="color: #666; font-size: 0.9em; margin-bottom: 10px;">
294
+ {current_debrief["type"].replace("_", " ").title()}
295
+ </div>
296
+ <div style="white-space: pre-line;">
297
+ {current_debrief["content"]}
298
+ </div>
299
+ </div>
300
+ """, unsafe_allow_html=True)
301
+
302
+ # Navigation buttons
303
+ col1, col2, col3 = st.columns([1, 2, 1])
304
+
305
+ with col1:
306
+ if st.session_state.debrief_stage > 0:
307
+ if st.button("← Previous", use_container_width=True):
308
+ st.session_state.debrief_stage -= 1
309
+ st.rerun()
310
+
311
+ with col3:
312
+ if st.session_state.debrief_stage < len(DEBRIEF_SEQUENCE) - 1:
313
+ if st.button("Next →", use_container_width=True):
314
+ st.session_state.debrief_stage += 1
315
+ st.rerun()
316
+ elif st.session_state.debrief_stage == len(DEBRIEF_SEQUENCE) - 1:
317
+ if st.button("Complete Reflection", use_container_width=True):
318
+ st.session_state.in_reflection = False
319
+ st.session_state.debrief_stage = 0
320
+ st.rerun()
321
+
322
+ # Optional note-taking area
323
+ st.markdown("### Your Notes")
324
+ st.text_area(
325
+ "Use this space to write any thoughts, feelings, or insights that arise...",
326
+ value=st.session_state.final_notes,
327
+ key="reflection_notes",
328
+ height=100,
329
+ help="Your notes are private and will be cleared when you start a new session."
330
+ )
331
+
332
+ # Footer
333
+ st.markdown("---")
334
+ st.markdown(
335
+ "Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com) | "
336
+ "Learn more: [@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)"
337
+ )