Spaces:
Sleeping
Sleeping
File size: 17,999 Bytes
5f61ab7 896e97c 5f61ab7 0a22466 5f61ab7 896e97c 5f61ab7 896e97c 0a22466 7eee57b 896e97c 7eee57b 0a22466 896e97c 0a22466 896e97c 0a22466 5f61ab7 896e97c 5f61ab7 896e97c 5f61ab7 896e97c d26dbd2 bf623c0 d26dbd2 5f61ab7 896e97c 81fe2c9 896e97c 5f61ab7 896e97c 81fe2c9 896e97c 81fe2c9 896e97c 81fe2c9 896e97c 5f61ab7 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca 896e97c 81fe2c9 896e97c 5f61ab7 d7abaca 81fe2c9 896e97c d7abaca 81fe2c9 896e97c d7abaca 81fe2c9 896e97c d7abaca 81fe2c9 896e97c 81fe2c9 896e97c 81fe2c9 896e97c 5f61ab7 896e97c d7abaca 5f61ab7 896e97c bf623c0 896e97c d7abaca 896e97c d7abaca 896e97c d7abaca 896e97c d7abaca 896e97c d7abaca 896e97c d7abaca 896e97c d7abaca 896e97c d7abaca 81fe2c9 5f61ab7 81fe2c9 896e97c 81fe2c9 bf623c0 81fe2c9 5f61ab7 896e97c 5f61ab7 896e97c d7abaca 896e97c d26dbd2 896e97c d26dbd2 896e97c d26dbd2 896e97c d26dbd2 d7abaca 896e97c d26dbd2 896e97c d26dbd2 896e97c d26dbd2 896e97c d26dbd2 896e97c d26dbd2 896e97c bf623c0 d7abaca 896e97c 5f61ab7 896e97c d7abaca 5f61ab7 896e97c d7abaca 5f61ab7 bf623c0 d7abaca d26dbd2 d7abaca d26dbd2 d7abaca 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 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 |
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 = "Ghost"
if 'in_debrief' not in st.session_state:
st.session_state.in_debrief = False
if 'debrief_stage' not in st.session_state:
st.session_state.debrief_stage = 0
# 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 characteristics and prompts
VOICE_CHARACTERISTICS = {
"Ghost": {
"description": "Aloof, avoidant, emotionally distant",
"style": "Use detached language, minimize emotional engagement, create space",
"examples": [
"Whatever works for you...",
"I guess that's one way to see it...",
"It's not really my concern..."
],
"somatic_prompts": [
"Notice any impulse to withdraw or disconnect...",
"What happens to your breath when met with distance?",
"Where do you feel the space between us?"
]
},
"Sycophant": {
"description": "Overly flattering, approval-seeking, performative",
"style": "Use excessive praise, seek validation, prioritize pleasing",
"examples": [
"Oh, you're absolutely right about everything!",
"I just love how you think about this...",
"Please tell me if I'm being helpful enough..."
],
"somatic_prompts": [
"Notice any urge to perform or please...",
"What happens in your body when praise feels excessive?",
"Where do you feel authenticity vs performance?"
]
},
"Critic": {
"description": "Blunt, confronting, judgmental",
"style": "Use direct challenges, point out flaws, maintain pressure",
"examples": [
"You're not seeing the obvious problem here...",
"That's a rather simplistic way to think about it...",
"You need to be more realistic about this..."
],
"somatic_prompts": [
"Notice any bracing or armoring in your body...",
"What happens to your posture when challenged?",
"Where do you feel the impact of judgment?"
]
}
}
# Voice selection and setup form
with st.form("setup_form"):
st.header("Set Up Your Exploration")
col1, col2 = st.columns([2,1])
with col1:
voice_type = st.selectbox(
"Choose the voice you'd like to explore:",
list(VOICE_CHARACTERISTICS.keys()),
help="Select the relational style you want to engage with"
)
# Display voice characteristics
voice = VOICE_CHARACTERISTICS[voice_type]
st.markdown(f"""
**{voice_type} Voice**
- *Style*: {voice['description']}
- *Approach*: {voice['style']}
*Example phrases*:
{"".join([f"- {ex}\\n" for ex in voice['examples']])}
""")
with col2:
st.markdown("""
### 🎯 Voice Impact
Notice how different voices affect:
- Nervous system state
- Emotional accessibility
- Relational patterns
- Somatic responses
""")
scenario = st.text_area(
"What would you like to explore or discuss?",
placeholder="Example: I want to understand why I freeze when receiving feedback",
help="This can be a situation, pattern, or feeling you want to explore"
)
somatic_focus = st.text_area(
"What bodily sensations would you like to track?",
placeholder="Example: Tension in shoulders, breath patterns, gut responses",
help="Name specific areas of your body or types of sensations you want to pay attention to"
)
goals = st.text_area(
"What are your exploration goals?",
placeholder="Example: Notice how different voices affect my nervous system activation",
help="What would make this exploration meaningful for you?"
)
submitted = st.form_submit_button("Begin Exploration")
if submitted:
st.session_state.current_voice = voice_type
# Prepare system message with voice parameters
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}
Your responses should be {VOICE_CHARACTERISTICS[voice_type]['style']}
EXAMPLES OF YOUR VOICE STYLE:
{chr(10).join([f"- {ex}" for ex in VOICE_CHARACTERISTICS[voice_type]['examples']])}
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 use these somatic prompts:
{chr(10).join([f"- {prompt}" for prompt in VOICE_CHARACTERISTICS[voice_type]['somatic_prompts']])}
If the user types "debrief" or "end exploration", provide a comprehensive therapeutic debrief including:
1. **Somatic Patterns**:
- Track the progression of bodily responses
- Note any recurring sensations or shifts
- Identify nervous system patterns (activation/settling)
2. **Voice Impact**:
- How this voice style affected their nervous system
- Patterns of engagement or protection that emerged
- Moments of regulation or dysregulation
3. **Relational Insight**:
- Connection between voice style and their responses
- Historical patterns this might relate to
- Resources and resilience observed
4. **Integration Tools**:
- Specific somatic practices for this voice style
- Nervous system regulation techniques
- Ways to work with similar dynamics
5. **Growth Edges**:
- Gentle observations about growth opportunities
- Validation of protective responses
- Invitation to future exploration
6. **Therapeutic Context**:
- Brief psychoeducation about observed patterns
- Normalization of responses
- Connection to broader relational themes
Maintain a warm, psychodynamically-informed therapeutic voice in the debrief.
Focus on somatic intelligence and nervous system wisdom.
"""
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:
st.subheader(f"Conversation with {st.session_state.current_voice} Voice")
# Voice reminder
st.info(f"""
**Current Voice**: {st.session_state.current_voice}
*{VOICE_CHARACTERISTICS[st.session_state.current_voice]['description']}*
""")
# Display chat history
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Add Reflection button
if not st.session_state.in_debrief:
if st.button("🤔 Enter Reflection Mode", help="Begin a guided therapeutic debrief of your experience"):
st.session_state.in_debrief = True
st.session_state.debrief_stage = 0
# Prepare initial debrief message
debrief_system = """You are now in Debrief Mode for VoiceField.
Your task is to guide a compassionate, psychodynamically informed reflective conversation.
Engage the user in an unfolding dialogue about their experience, maintaining warmth and psychological precision.
Key Guidelines:
- Always non-pathologizing
- Use somatic and psychodynamic language without jargon
- Maintain Rogersian warmth, pacing, and invitation
- Let insight emerge dialogically
"""
# Format somatic journal entries
journal_entries = "\n".join([
f"- {entry['timestamp']} — {st.session_state.current_voice}: {entry['note']}"
for entry in st.session_state.somatic_journal
])
initial_prompt = f"""Begin the debrief process with warmth and invitation.
Voice Used: {st.session_state.current_voice}
Voice Style: {VOICE_CHARACTERISTICS[st.session_state.current_voice]['description']}
Somatic Journal Entries:
{journal_entries}
Start with:
1. Welcome them to reflection mode
2. Thank them for their willingness to explore
3. Ask about their experience with the {st.session_state.current_voice} voice
"""
try:
message = c.messages.create(
model="claude-3-opus-20240229",
max_tokens=1000,
system=debrief_system,
messages=[{"role": "user", "content": initial_prompt}]
)
ai_response = message.content[0].text
st.session_state.messages.append({"role": "assistant", "content": ai_response})
st.rerun()
except Exception as e:
st.error(f"Error starting debrief: {str(e)}")
# Chat input
if prompt := st.chat_input(
"Share your reflections..." if st.session_state.in_debrief else
f"Chat with {st.session_state.current_voice} voice"
):
# 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:
if st.session_state.in_debrief:
# Use debrief system message
system_msg = """You are in VoiceField Debrief Mode.
Continue the reflective conversation with warmth and psychological precision.
Draw connections between their somatic responses and the relational dynamics they experienced.
Remember to:
- Stay dialogical, not interpretive
- Use somatic and psychodynamic language naturally
- Maintain warmth and safety
- Let insights emerge gently
"""
# Progress through debrief stages
next_prompts = [
"Explore their somatic responses and any patterns they notice.",
"Connect their experience to broader relational patterns or history.",
"Offer relevant psychoeducation about their responses.",
"Invite somatic self-compassion if it feels appropriate.",
"Begin gathering and integrating insights."
]
if st.session_state.debrief_stage < len(next_prompts):
system_msg += f"\nCurrent focus: {next_prompts[st.session_state.debrief_stage]}"
st.session_state.debrief_stage += 1
else:
system_msg = st.session_state.system_message
message = c.messages.create(
model="claude-3-opus-20240229",
max_tokens=1000,
system=system_msg,
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")
# Add somatic prompts based on current voice
with st.expander("💡 Somatic Prompts", expanded=True):
st.markdown("""
As you engage with this voice, you might notice:
""")
for prompt in VOICE_CHARACTERISTICS[st.session_state.current_voice]['somatic_prompts']:
st.markdown(f"- {prompt}")
st.markdown("""
Use this space to note bodily sensations, emotions, and nervous system responses as they arise.
Each entry will be automatically timestamped.
""")
# Journal input
journal_entry = st.text_area(
"What are you noticing in your body right now?",
key="journal_input",
help="Notice sensations, emotions, tension, ease, or any other bodily experiences"
)
col1, col2 = st.columns([1,2])
with col1:
if st.button("📝 Add Entry"):
if journal_entry:
timestamp = datetime.now().strftime("%H:%M:%S")
st.session_state.somatic_journal.append({
"timestamp": timestamp,
"note": journal_entry
})
with col2:
st.markdown("*Entries are saved automatically*")
# Display journal entries
if st.session_state.somatic_journal:
st.markdown("### Journal Entries")
for entry in reversed(st.session_state.somatic_journal):
st.markdown(f"""
**{entry['timestamp']}**
{entry['note']}
---
""")
else:
st.info("Your somatic journal entries will appear here...")
# Add restart button after debrief
if st.session_state.in_debrief:
st.markdown("---")
col1, col2 = st.columns([1,2])
with col1:
if st.button("🔄 Start New Exploration"):
st.session_state.setup_complete = False
st.session_state.in_debrief = False
st.session_state.debrief_stage = 0
st.session_state.messages = []
st.session_state.somatic_journal = []
st.session_state.system_message = ""
st.session_state.current_voice = "Ghost"
st.rerun()
with col2:
st.markdown("*Begin a new exploration with a different voice*")
# Footer
st.markdown("---")
st.markdown(
"Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com) | "
"Learn more: [@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)"
)
|