Spaces:
Sleeping
Sleeping
File size: 13,867 Bytes
5f61ab7 896e97c 5f61ab7 0a22466 5f61ab7 896e97c 5f61ab7 896e97c 0a22466 7eee57b 896e97c 7eee57b 0a22466 896e97c 0a22466 896e97c 0a22466 5f61ab7 896e97c 5f61ab7 896e97c 5f61ab7 896e97c bf623c0 896e97c 5f61ab7 896e97c 81fe2c9 896e97c 5f61ab7 896e97c 81fe2c9 896e97c 81fe2c9 896e97c 81fe2c9 896e97c 5f61ab7 896e97c 81fe2c9 896e97c 5f61ab7 896e97c 81fe2c9 896e97c 81fe2c9 896e97c 81fe2c9 896e97c 81fe2c9 896e97c 81fe2c9 896e97c bf623c0 896e97c 81fe2c9 896e97c 5f61ab7 896e97c 5f61ab7 896e97c bf623c0 896e97c 81fe2c9 5f61ab7 81fe2c9 896e97c 81fe2c9 bf623c0 81fe2c9 5f61ab7 896e97c 5f61ab7 896e97c bf623c0 896e97c bf623c0 896e97c bf623c0 896e97c 5f61ab7 896e97c 5f61ab7 896e97c 5f61ab7 bf623c0 896e97c bf623c0 896e97c bf623c0 896e97c bf623c0 5f61ab7 |
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 |
import os
import streamlit as st
from anthropic import Anthropic
from dotenv import load_dotenv
from datetime import datetime
# Initialize page configuration first
st.set_page_config(
page_title="VoiceField",
page_icon="π£οΈ",
layout="wide"
)
# Handle API key setup
try:
if os.path.exists(".env"):
load_dotenv()
api_key = None
if 'ANTHROPIC_API_KEY' in os.environ:
api_key = os.environ['ANTHROPIC_API_KEY']
elif hasattr(st, 'secrets') and 'ANTHROPIC_API_KEY' in st.secrets:
api_key = st.secrets['ANTHROPIC_API_KEY']
if not api_key:
st.error("""
β οΈ No API key found. Please set ANTHROPIC_API_KEY in your environment variables or Space secrets.
""")
st.stop()
c = Anthropic(api_key=api_key)
except Exception as e:
st.error(f"Error initializing Anthropic client: {str(e)}")
st.stop()
# Initialize session state
if 'messages' not in st.session_state:
st.session_state.messages = []
if 'somatic_journal' not in st.session_state:
st.session_state.somatic_journal = []
if 'setup_complete' not in st.session_state:
st.session_state.setup_complete = False
if 'system_message' not in st.session_state:
st.session_state.system_message = ""
if 'current_voice' not in st.session_state:
st.session_state.current_voice = "Nurturing"
if 'in_debrief' not in st.session_state:
st.session_state.in_debrief = False
if 'voice_transitions' not in st.session_state:
st.session_state.voice_transitions = []
# Main page header
st.title("VoiceField")
# Welcome text
st.markdown("""
Welcome to VoiceField - a somatic exploration tool for understanding how different relational voices impact your nervous system.
Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com), this tool helps you track real-time bodily responses while engaging with different conversational styles.
π― **Purpose**: Explore how different relational voices affect your nervous system, emotional state, and capacity for engagement.
π‘ **How it works**:
1. Choose a voice type to start with
2. Engage in conversation while noting bodily sensations
3. Switch voices anytime to explore different dynamics
4. Receive a comprehensive somatic-relational debrief
""")
# Voice selection and setup form
with st.form("setup_form"):
st.header("Set Up Your Exploration")
voice_type = st.selectbox(
"Choose the voice you'd like to explore:",
["Nurturing", "Challenging", "Neutral"],
help="""
π« Nurturing: Warm, empathetic, and supportive. Creates safety and attunement.
π Challenging: Direct, provocative, growth-oriented. Pushes edges with respect.
βοΈ Neutral: Objective, clear, and grounded. Holds space without strong emotional coloring.
"""
)
scenario = st.text_area(
"What would you like to explore or discuss?",
placeholder="Example: I want to understand why I freeze when receiving feedback"
)
somatic_focus = st.text_area(
"What bodily sensations would you like to track?",
placeholder="Example: Tension in shoulders, breath patterns, gut responses"
)
goals = st.text_area(
"What are your exploration goals?",
placeholder="Example: Notice how different voices affect my nervous system activation"
)
submitted = st.form_submit_button("Begin Exploration")
if submitted:
st.session_state.current_voice = voice_type
st.session_state.voice_transitions = [(datetime.now().strftime("%H:%M:%S"), voice_type)]
# Prepare system message with voice parameters
voice_characteristics = {
"Nurturing": {
"style": "warm, empathetic, and supportive",
"language": "gentle, validating, and attuned",
"pacing": "slow and patient",
"focus": "creating safety and connection"
},
"Challenging": {
"style": "direct, provocative, and growth-oriented",
"language": "clear, bold, and respectfully confrontational",
"pacing": "dynamic and engaging",
"focus": "expanding awareness and capacity"
},
"Neutral": {
"style": "objective, clear, and grounded",
"language": "balanced, factual, and measured",
"pacing": "steady and consistent",
"focus": "observing patterns and processes"
}
}
voice = voice_characteristics[voice_type]
st.session_state.system_message = f"""
You are a conversational partner helping someone explore their somatic responses to different relational styles.
VOICE TYPE: {voice_type}
Style: {voice['style']}
Language: {voice['language']}
Pacing: {voice['pacing']}
Focus: {voice['focus']}
CONTEXT:
- Scenario: {scenario}
- Somatic Focus: {somatic_focus}
- Goals: {goals}
KEY INSTRUCTIONS:
1. Stay consistently in the {voice_type} voice style
2. Keep responses focused and concise (2-3 sentences max)
3. Occasionally invite somatic awareness with questions like:
- "What sensations are you noticing right now?"
- "How is your breath responding to this?"
- "Where do you feel this in your body?"
If the user types "debrief" or "end exploration", provide a comprehensive therapeutic debrief including:
1. **Somatic Patterns**:
- Track patterns in bodily responses across different voice types
- Note shifts in nervous system state (activation/settling)
- Identify somatic resources and challenges
2. **Nervous System Insights**:
- Connect responses to polyvagal theory (fight/flight/freeze/fawn)
- Explore window of tolerance and regulation capacity
- Highlight moments of co-regulation or dysregulation
3. **Relational Dynamics**:
- Analyze engagement patterns with each voice type
- Note attachment themes or protective patterns
- Identify relational resources and growth edges
4. **Integration Tools**:
- Offer specific somatic practices for regulation
- Suggest relational experiments for expanding capacity
- Provide nervous system education relevant to their experience
5. **Growth Edges**:
- Frame challenges within a developmental context
- Suggest gentle next steps for expanding capacity
- Normalize and validate protective responses
6. **Therapeutic Frame**:
- Provide relevant psychoeducation about their patterns
- Connect individual experience to broader human themes
- Offer compassionate reframes of challenges
Maintain a warm, psychodynamically-informed therapeutic voice in the debrief.
"""
st.session_state.messages = []
st.session_state.somatic_journal = []
st.session_state.setup_complete = True
st.session_state.in_debrief = False
st.rerun()
# Main interaction area
if st.session_state.setup_complete:
# Create two columns for chat and journal
chat_col, journal_col = st.columns([3, 2])
with chat_col:
# Voice switching interface
if not st.session_state.in_debrief:
new_voice = st.selectbox(
"Switch voice type:",
["Nurturing", "Challenging", "Neutral"],
index=["Nurturing", "Challenging", "Neutral"].index(st.session_state.current_voice)
)
if new_voice != st.session_state.current_voice:
st.session_state.current_voice = new_voice
timestamp = datetime.now().strftime("%H:%M:%S")
st.session_state.voice_transitions.append((timestamp, new_voice))
st.rerun()
st.subheader(f"Conversation with {st.session_state.current_voice} Voice")
# Display chat history
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Chat input
if prompt := st.chat_input(f"Chat with {st.session_state.current_voice} voice (type 'debrief' when ready to reflect)"):
# Check for debrief trigger
if prompt.lower() in ["debrief", "end exploration"] and not st.session_state.in_debrief:
st.session_state.in_debrief = True
# Prepare debrief request
voice_history = "\n".join([
f"[{time}] Switched to {voice} voice"
for time, voice in st.session_state.voice_transitions
])
journal_summary = "\n".join([
f"[{entry['timestamp']}] {entry['note']}"
for entry in st.session_state.somatic_journal
])
prompt = f"""Please provide a therapeutic debrief for this somatic exploration:
Voice Transitions:
{voice_history}
Somatic Journal Entries:
{journal_summary}
Conversation History:
{chr(10).join([f"{msg['role']}: {msg['content']}" for msg in st.session_state.messages])}
"""
# Add user message to chat history
st.session_state.messages.append({"role": "user", "content": prompt})
# Display user message
with st.chat_message("user"):
st.markdown(prompt)
# Get AI response
with st.chat_message("assistant"):
with st.spinner("Thinking..."):
try:
message = c.messages.create(
model="claude-3-opus-20240229",
max_tokens=1000,
system=st.session_state.system_message,
messages=[
{"role": msg["role"], "content": msg["content"]}
for msg in st.session_state.messages
]
)
ai_response = message.content[0].text
st.markdown(ai_response)
# Add AI response to chat history
st.session_state.messages.append(
{"role": "assistant", "content": ai_response}
)
except Exception as e:
st.error(f"Error getting AI response: {str(e)}")
with journal_col:
st.subheader("Somatic Journal")
# Quick reaction buttons
st.write("Quick Reactions:")
reaction_cols = st.columns(3)
reactions = {
"Nervous System": ["π΄ Activated", "π‘ Alert", "π’ Settled"],
"Emotional": ["π Safe", "π° Tense", "πΆ Numb"],
"Engagement": ["π₯ Connected", "π‘οΈ Protected", "β Disconnected"]
}
for i, (category, buttons) in enumerate(reactions.items()):
with reaction_cols[i]:
st.write(f"**{category}**")
for button in buttons:
if st.button(button):
timestamp = datetime.now().strftime("%H:%M:%S")
st.session_state.somatic_journal.append({
"timestamp": timestamp,
"note": f"Quick reaction: {button}"
})
st.rerun()
st.markdown("""
Use this space to note bodily sensations, emotions, and nervous system responses as they arise.
Each entry will be automatically timestamped.
π‘ Consider tracking:
- Physical sensations
- Breath patterns
- Muscle tension/release
- Energy levels
- Emotional shifts
- Relational impulses
""")
# Journal input
journal_entry = st.text_area("What are you noticing in your body right now?", key="journal_input")
if st.button("Add Journal Entry"):
if journal_entry:
timestamp = datetime.now().strftime("%H:%M:%S")
st.session_state.somatic_journal.append({
"timestamp": timestamp,
"note": journal_entry
})
st.rerun()
# Display journal entries
st.markdown("### Journal Timeline")
for entry in reversed(st.session_state.somatic_journal):
st.markdown(f"""
**{entry['timestamp']}**
{entry['note']}
---
""")
# Add restart button after debrief
if st.session_state.in_debrief:
if st.button("Start New Exploration"):
st.session_state.setup_complete = False
st.session_state.in_debrief = False
st.session_state.messages = []
st.session_state.somatic_journal = []
st.session_state.voice_transitions = []
st.session_state.system_message = ""
st.session_state.current_voice = "Nurturing"
st.rerun()
# Footer
st.markdown("---")
st.markdown(
"Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com) | "
"Learn more: [@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)"
)
|