File size: 14,751 Bytes
5f61ab7
 
 
896e97c
0297f64
5f61ab7
23dc26c
 
1ab7d75
23dc26c
 
 
 
 
1ab7d75
 
 
 
 
 
 
 
25a3a47
1ab7d75
 
 
 
 
 
25a3a47
1ab7d75
 
 
 
 
 
25a3a47
 
 
896e97c
0a22466
80b6d02
 
cb819e8
 
 
e3e08e6
80b6d02
e3e08e6
80b6d02
cb819e8
89997ca
cb819e8
80b6d02
cb819e8
80b6d02
cb819e8
 
89997ca
cb819e8
0a22466
 
80b6d02
0a22466
5f61ab7
896e97c
1ab7d75
 
08d36a2
 
d7abaca
08d36a2
 
1ab7d75
268e83c
1ab7d75
268e83c
1ab7d75
 
 
 
 
268e83c
1ab7d75
62f7a71
 
08d36a2
 
0a70b04
 
1ab7d75
 
a953a14
1ab7d75
 
 
 
 
 
 
 
 
a953a14
1ab7d75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86c91b1
1ab7d75
 
 
 
 
 
 
 
86c91b1
1ab7d75
 
 
 
 
 
 
 
86c91b1
1ab7d75
 
 
 
 
 
 
86c91b1
1ab7d75
 
 
 
 
 
 
86c91b1
1ab7d75
 
 
 
86c91b1
1ab7d75
 
 
 
 
 
 
86c91b1
1ab7d75
 
 
 
 
 
 
 
86c91b1
1ab7d75
 
 
 
 
86c91b1
1ab7d75
 
 
 
 
 
 
86c91b1
1ab7d75
 
 
 
 
 
 
 
d35165b
 
1ab7d75
 
 
 
 
 
 
d35165b
86c91b1
 
 
1ab7d75
25a3a47
 
 
0088e95
8b01dbe
0088e95
 
 
1ab7d75
0088e95
 
1ab7d75
 
 
0088e95
 
1ab7d75
0088e95
1ab7d75
25a3a47
1ab7d75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25a3a47
 
 
1ab7d75
8b01dbe
25a3a47
0297f64
0088e95
 
 
1ab7d75
 
0088e95
 
8b01dbe
0088e95
 
8b01dbe
25a3a47
 
0a70b04
0088e95
1ab7d75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15e57a1
1ab7d75
0088e95
 
 
 
 
 
 
86c91b1
 
 
 
0088e95
1ab7d75
0088e95
 
 
86c91b1
1ab7d75
86c91b1
1ab7d75
0088e95
86c91b1
1ab7d75
0088e95
86c91b1
 
1ab7d75
 
 
 
 
 
 
 
 
 
 
a953a14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1ab7d75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303e801
 
 
 
 
 
 
 
 
 
 
 
 
 
1ab7d75
 
37d47e7
 
 
 
 
 
 
 
 
95de610
 
37d47e7
95de610
37d47e7
95de610
37d47e7
1ab7d75
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
import os
import streamlit as st
from anthropic import Anthropic
from datetime import datetime
import random

# Initialize page configuration - MUST BE FIRST ST COMMAND
st.set_page_config(
    page_title="NurtureNest: Inner Child Mirror",
    page_icon="🪴",
    layout="wide",
    initial_sidebar_state="expanded"
)

# Age context dictionary
AGE_CONTEXT = {
    "3-5": {
        "voice": "Very simple, sensory-focused reassurance",
        "example": "Your body was so tight. That's okay. You're safe now.",
        "description": "Simple words and gentle comfort for your littlest self",
        "color": "#FFF5E6",
        "border": "#FFB366"
    },
    "6-8": {
        "voice": "Gentle relational reflection",
        "example": "Sometimes big feelings come when we feel alone. I hear how hard that was.",
        "description": "Warm understanding for your grade school self",
        "color": "#F0F7F4",
        "border": "#88C6B6"
    },
    "9-12": {
        "voice": "Emotionally attuned validation",
        "example": "It makes sense that you felt that way. Your feelings matter.",
        "description": "Respectful reflection for your older child self",
        "color": "#F5F8FC",
        "border": "#9FB7E3"
    }
}

# Handle API key setup
try:
    # Try to get API key from environment or secrets
    api_key = os.getenv("anthropic_key")
    
    # Try Streamlit secrets if env var not found
    if not api_key and hasattr(st, 'secrets'):
        try:
            api_key = st.secrets["anthropic_key"]
        except (KeyError, AttributeError):
            pass
    
    if not api_key:
        st.error("""
        ⚠️ API key not found. Please make sure:
        1. You've added the secret in Hugging Face Space settings
        2. The secret is named exactly 'anthropic_key'
        3. The Space has been rebuilt after adding the secret
        """)
        st.stop()
        
    c = Anthropic(api_key=api_key)
except Exception as e:
    st.error("Error initializing AI client. Please check your configuration.")
    st.stop()

# Initialize session state
if 'chat_history' not in st.session_state:
    st.session_state.chat_history = []
if 'journal_entries' not in st.session_state:
    st.session_state.journal_entries = []

# Sidebar content
st.sidebar.markdown("""
# Welcome to NurtureNest: Inner Child Mirror 🪴

A gentle space for re-parenting through connection with your inner child.

Here you can:
- Connect with your younger self
- Process parenting moments with deep understanding
- Experience the healing power of being truly seen
- Learn to parent from a place of wholeness

*Created with deep respect for the healing journey of parents.*

---
Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com)  
[@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)
""")

# Main content area
st.markdown("""
# NurtureNest
# Welcome to the Inner Child Mirror
## A gentle place to be held, not fixed.

Parenting isn't just about raising our children. It's also about meeting the younger parts of ourselves—the ones who didn't always get the co-regulation, safety, or softness they needed. These parts don't disappear when we grow up. They often rise up when we're stressed, overwhelmed, or when our child's behavior echoes an old wound.

The Inner Child Mirror is a simple but powerful tool in your parenting toolkit.

### Here's how it works:

1. You write a brief note about a hard moment from today or how you are feeling right now
2. You choose an age (3–12) that feels connected to how you were feeling
3. You receive a warm, developmentally attuned reflection—as if spoken to that younger you

This practice is grounded in trauma-informed care, attachment science, and the work of experts like Dr. Dan Siegel, Sarah Peyton, and Dr. Becky Kennedy. It helps you:

- Build compassion for yourself—especially after rupture moments
- Expand your capacity for repair (with your child and yourself)
- Notice and tend to your own nervous system with care
- Interrupt inherited patterns with love and attunement

You're not just "using an app"—you're doing intergenerational work in the most tender, doable way.
Not by being perfect. But by practicing presence—even with the parts of you that were once overwhelmed, scared, or unseen.

<div class="special-note">
    <p><strong>This is not therapy. It's not performance. It's a ritual of repair.</strong><br>
    You're not alone in this.</p>
</div>

When you're ready, choose an age. Let the mirror offer you the kind of reflection every child deserves.

---
""", unsafe_allow_html=True)

# Update CSS to include special styling for the introduction
st.markdown("""
<style>
    /* Enhanced typography for introduction */
    .stApp {
        background-color: #F5F5F0;
        font-family: 'Inter', 'Nunito', sans-serif;
    }
    
    h1 {
        color: #2E2E2E;
        font-family: 'Nunito', sans-serif;
        font-size: 2.5rem;
        font-weight: 700;
        margin-bottom: 0.5rem;
        line-height: 1.2;
    }
    
    h2 {
        color: #666666;
        font-family: 'Inter', sans-serif;
        font-size: 1.5rem;
        font-weight: 400;
        margin-bottom: 2rem;
        font-style: italic;
    }
    
    h3 {
        color: #2E2E2E;
        font-family: 'Nunito', sans-serif;
        font-size: 1.75rem;
        font-weight: 600;
        margin: 2rem 0 1rem 0;
    }
    
    p {
        color: #2E2E2E;
        font-family: 'Inter', sans-serif;
        font-size: 1.1rem;
        line-height: 1.8;
        margin: 1rem 0;
    }
    
    ul {
        margin: 1.5rem 0;
        padding-left: 1.5rem;
    }
    
    li {
        color: #2E2E2E;
        font-family: 'Inter', sans-serif;
        font-size: 1.1rem;
        line-height: 1.8;
        margin: 0.5rem 0;
    }
    
    .special-note {
        background-color: #FFF5E6;
        border-left: 4px solid #FFB366;
        padding: 1.5rem;
        border-radius: 1rem;
        margin: 2rem 0;
        box-shadow: 0 2px 8px rgba(0,0,0,0.05);
    }
    
    .special-note p {
        margin: 0;
        font-size: 1.2rem;
        color: #2E2E2E;
    }
    
    hr {
        margin: 2rem 0;
        border: none;
        border-top: 1px solid #E0E0E0;
    }
</style>
""", unsafe_allow_html=True)

# Age selection
st.markdown("### Choose the age of your inner child")
selected_age = st.selectbox(
    "Age Selection",
    options=list(AGE_CONTEXT.keys()),
    format_func=lambda x: f"Age {x}: {AGE_CONTEXT[x]['description']}",
    help="Select the age of your inner child that needs to be heard today",
    label_visibility="collapsed"
)

# Display age context description
st.markdown(f"""
<div style="padding: 1rem; background-color: {AGE_CONTEXT[selected_age]['color']}; border-left: 4px solid {AGE_CONTEXT[selected_age]['border']}; border-radius: 0.5rem; margin: 1rem 0;">
    <p style="margin: 0; font-style: italic;">{AGE_CONTEXT[selected_age]['voice']}</p>
    <p style="margin: 0.5rem 0 0 0; font-size: 0.9em; color: #666666;">Example: {AGE_CONTEXT[selected_age]['example']}</p>
</div>
""", unsafe_allow_html=True)

# Crisis support notice
st.markdown("""
<div class="alert">
    <strong>⚠️ Important:</strong> This is not therapy. If you need support, please reach out to a mental health professional or click <a href="https://www.samhsa.gov/find-help/national-helpline" target="_blank">here</a> for resources.
</div>
""", unsafe_allow_html=True)

# Journal input and chat interface
st.markdown("### Share what's on your heart...")
col1, col2 = st.columns([4, 1])
with col1:
    journal_entry = st.text_area(
        "Your sharing",
        height=100,
        key="journal_input",
        help="Share your parenting moment. Your inner child will be heard with care.",
        placeholder="Tell me about a moment that feels hard...",
        label_visibility="collapsed"
    )
with col2:
    submit = st.button("Share 💝", use_container_width=True)

if submit and journal_entry:
    try:
        # Create age-appropriate system message
        system_message = f"""You are a trauma-informed Inner Child Mirror for parents.
You speak directly to their {selected_age}-year-old self with deep emotional attunement.

Your role is to provide emotional safety and validation, never advice or correction.
Respond as if speaking to a {selected_age}-year-old, using:
- Age-appropriate language and concepts
- Simple, kind sentences (5-7 lines maximum)
- Focus on emotional and bodily experience
- Unconditional positive regard
- No fixing, explaining, or instructing

For age {selected_age}:
{AGE_CONTEXT[selected_age]['voice']}

Always end with a gentle reminder of worth, such as:
"You are still good."
"You didn't do anything wrong by feeling that way."
"You are still loved. You can try again."
"You're not alone."
"""

        message = c.messages.create(
            model="claude-3-opus-20240229",
            max_tokens=1000,
            system=system_message,
            messages=[{"role": "user", "content": journal_entry}]
        )
        
        # Add the new exchange to chat history
        st.session_state.chat_history.append({
            "user_message": journal_entry,
            "ai_response": message.content[0].text,
            "age": selected_age,
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M")
        })
        
        # Clear the input area after sending
        st.rerun()
            
    except Exception as e:
        st.error(f"Error getting reflection: {str(e)}")

# Display chat history in reverse chronological order
if st.session_state.chat_history:
    st.markdown("### Your Mirror")
    for exchange in reversed(st.session_state.chat_history):
        # User message
        st.markdown(f"""
        <div class="user-message">
            <div class="message-meta"><em>Your sharing</em></div>
            <div class="message-text">{exchange["user_message"]}</div>
        </div>
        """, unsafe_allow_html=True)
        
        # Mirror response with age-specific styling
        age_group = exchange["age"]
        st.markdown(f"""
        <div style="background-color: {AGE_CONTEXT[age_group]['color']}; padding: 1.5rem; border-radius: 1rem; margin: 1rem 0; border-left: 4px solid {AGE_CONTEXT[age_group]['border']}; box-shadow: 0 2px 8px rgba(0,0,0,0.05);">
            <div class="message-meta">
                <em>Your {age_group}-year-old self is heard</em>
            </div>
            <div class="message-text">{exchange["ai_response"]}</div>
        </div>
        """, unsafe_allow_html=True)

# Save conversation button at the bottom
if st.session_state.chat_history:
    if st.button("📥 Save this conversation"):
        st.session_state.journal_entries.extend(st.session_state.chat_history)
        st.success("Conversation saved to your journal.")

# Display saved reflections if any
if st.session_state.journal_entries:
    with st.expander("📔 Your Saved Reflections", expanded=False):
        for entry in reversed(st.session_state.journal_entries):
            timestamp = entry.get("timestamp", "")
            age = entry.get("age", "")
            content = entry.get("user_message", entry.get("content", ""))
            reflection = entry.get("ai_response", entry.get("reflection", ""))
            
            st.markdown(f"""
            **{timestamp}** - *Age {age}*
            
            *Your sharing:*  
            {content}
            
            *Your inner child was heard:*  
            {reflection}
            
            ---
            """)

# Update CSS for styling
st.markdown("""
<style>
    /* Base styling */
    .stApp {
        background-color: #F5F5F0;
        font-family: 'Inter', 'Nunito', sans-serif;
    }
    
    /* Sidebar styling */
    .css-1d391kg, .css-1p05t8e, [data-testid="stSidebar"] {
        background-color: #FFFFFF !important;
    }
    
    [data-testid="stSidebar"] .stMarkdown {
        color: #2E2E2E;
    }
    
    [data-testid="stSidebar"] h1 {
        color: #2E2E2E;
        font-size: 1.8rem;
        margin-bottom: 1rem;
    }
    
    [data-testid="stSidebar"] p, 
    [data-testid="stSidebar"] li {
        color: #2E2E2E;
        font-size: 1rem;
    }
    
    [data-testid="stSidebar"] a {
        color: #2E2E2E;
        text-decoration: underline;
    }
    
    [data-testid="stSidebar"] a:hover {
        color: #000000;
    }
    
    /* User message styling */
    .user-message {
        background-color: #FFFFFF;
        padding: 1.5rem;
        border-radius: 1rem;
        margin: 1rem 0;
        box-shadow: 0 2px 8px rgba(0,0,0,0.05);
    }
    
    /* Text styling */
    .message-text {
        font-size: 18px;
        line-height: 1.8;
        color: #2E2E2E;
        font-family: 'Nunito', 'Inter', sans-serif;
    }
    
    .message-meta {
        font-size: 14px;
        color: #666666;
        margin-bottom: 0.75rem;
        font-family: 'Inter', sans-serif;
    }
    
    /* Button styling */
    .stButton > button {
        background-color: #88C6B6;
        color: white;
        border: none;
        padding: 0.75rem 1.5rem;
        border-radius: 1rem;
        font-family: 'Nunito', 'Inter', sans-serif;
        font-weight: 600;
        transition: all 0.3s ease;
    }
    
    .stButton > button:hover {
        background-color: #7AB3A3;
        transform: translateY(-1px);
        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
    }
    
    /* Alert styling */
    .alert {
        background-color: #FFF8E1;
        border-left: 4px solid #FFB366;
        padding: 1.5rem;
        border-radius: 1rem;
        margin: 1.5rem 0;
        box-shadow: 0 2px 8px rgba(0,0,0,0.05);
        color: #2E2E2E;
    }

    .alert strong {
        color: #2E2E2E;
    }

    .alert a {
        color: #2E2E2E;
        text-decoration: underline;
    }

    .alert a:hover {
        color: #000000;
    }
</style>
""", unsafe_allow_html=True)

# Footer
st.markdown("---")
st.markdown(
    "Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com) | "
    "Learn more: [@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)"
)
st.markdown("""
<div style='text-align: center; margin-top: 10px;'>
    <p style='font-size: 0.8em; color: #666666;'>I hope to move into more full time work at this intersection but in the meantime if you found this tool helpful feel free to buy me a coffee ☕️</p>
    <a href='https://buymeacoffee.com/JocelynSkillman' target='_blank'>
        <img src='https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png' alt='Buy Me A Coffee' style='height: 30px !important;width: 109px !important;'>
    </a>
    <p style='font-size: 0.8em; color: #666666;'>Thank you so much!!!! XO</p>
</div>
""", unsafe_allow_html=True)