Spaces:
Sleeping
Sleeping
File size: 11,304 Bytes
5f61ab7 0a22466 5f61ab7 0a22466 7eee57b 0a22466 7eee57b 0a22466 5f61ab7 bf623c0 5f61ab7 81fe2c9 5f61ab7 81fe2c9 5f61ab7 81fe2c9 5f61ab7 81fe2c9 5f61ab7 81fe2c9 5f61ab7 4da0cb5 81fe2c9 bf623c0 4da0cb5 bf623c0 81fe2c9 4da0cb5 5f61ab7 81fe2c9 5f61ab7 81fe2c9 bf623c0 4da0cb5 bf623c0 81fe2c9 5f61ab7 bf623c0 81fe2c9 bf623c0 81fe2c9 5f61ab7 81fe2c9 5f61ab7 4da0cb5 5f61ab7 bf623c0 4da0cb5 bf623c0 5f61ab7 81fe2c9 5f61ab7 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 |
import os
import streamlit as st
from anthropic import Anthropic
from dotenv import load_dotenv
# Initialize page configuration first
st.set_page_config(
page_title="Attachment Style Roleplay Simulator",
page_icon="π£οΈ",
layout="wide"
)
# Handle API key
try:
# Load from .env file for local development
if os.path.exists(".env"):
load_dotenv()
# Try multiple ways to get the API key
api_key = None
# Try direct environment variable
if 'ANTHROPIC_API_KEY' in os.environ:
api_key = os.environ['ANTHROPIC_API_KEY']
# Try getenv
if not api_key:
api_key = os.getenv('ANTHROPIC_API_KEY')
# Try Streamlit secrets
if not api_key and 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 make sure:
1. You've added the secret in Hugging Face Space settings
2. The secret is named exactly 'ANTHROPIC_API_KEY'
3. The Space has been rebuilt after adding the secret
""")
st.stop()
# Initialize Anthropic client
c = Anthropic(api_key=api_key)
except Exception as e:
st.error(f"""
β οΈ Error initializing Anthropic client: {str(e)}
Please check:
1. Your ANTHROPIC_API_KEY is set correctly
2. You're using a valid API key from Anthropic
""")
st.stop()
# Initialize session state variables
if 'messages' not in st.session_state:
st.session_state.messages = []
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 'simulation_params' not in st.session_state:
st.session_state.simulation_params = {}
if 'in_debrief' not in st.session_state:
st.session_state.in_debrief = False
# Main page header
st.title("Attachment Style Roleplay Simulator")
# Welcome text in main content area
st.markdown("""
Welcome!
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.
To learn more about attachment theory and therapeutic approaches, check out my newsletter: [@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)
""")
st.markdown("""
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.
π‘ Not sure about your attachment style?
You can take the free quiz by Sarah Peyton β or simply choose the one that resonates when you read it:
Anxious β "I often worry I've upset people or need to explain myself."
Avoidant β "I'd rather deal with things alone and not depend on anyone."
Disorganized β "I want closeness, but also feel unsafe or mistrusting."
Secure β "I can express needs and handle conflict without losing connection."
Choose what vibes β this is a practice space, not a test.
""")
# Sidebar welcome and introduction
with st.sidebar:
st.markdown("""
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.
Each tool in this collection is thoughtfully designed to:
Extend therapeutic support between sessions
Model emotional safety and relational depth
Help clients and clinicians rehearse courage, regulation, and repair
Stay grounded in trauma-informed, developmentally sensitive frameworks
""")
st.divider()
# Add the moved content to the bottom of sidebar
st.markdown("""
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.
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.
To learn more about my work, visit:
π [jocelynskillman.com](http://www.jocelynskillman.com)
π¬ [Substack: Relational Code](https://jocelynskillmanlmhc.substack.com/)
""")
# Simulation setup form
with st.form("setup_form"):
st.header("Set Up Your Simulation")
tone_archetype = st.selectbox(
"Select the voice you'd like to engage with:",
["Ghost", "Sycophant", "Critic"]
)
scenario = st.text_area(
"Describe the scenario you'd like to practice:",
placeholder="Example: Having a difficult conversation with my partner about feeling disconnected"
)
tone = st.text_input(
"How would you like the AI to respond?",
placeholder="Example: Direct but understanding"
)
goals = st.text_area(
"What are your practice goals?",
placeholder="Example: Practice expressing needs without becoming defensive"
)
submitted = st.form_submit_button("Start Simulation")
if submitted:
# Store simulation parameters for debrief
st.session_state.simulation_params = {
"tone_archetype": tone_archetype,
"scenario": scenario,
"tone": tone,
"goals": goals
}
# Prepare system message with simulation parameters
st.session_state.system_message = f"""
You are a conversational partner helping someone practice difficult conversations.
The user has a {tone_archetype} attachment style and wants to practice: {scenario}
Respond in a {tone} manner. Help them achieve their goals: {goals}
Maintain a realistic conversation while providing gentle guidance when needed.
IMPORTANT: If the user types "debrief" or "end roleplay", switch to debrief mode using this format:
π DEBRIEF SUMMARY
**Emotional Arc**: [Analyze how the user shifted emotionally during the interaction, noting moments of courage, freeze, protest, backtracking, or people-pleasing]
**Goal Alignment**: [Reflect on how well they stayed aligned with their stated goal. Note small wins and struggles, affirm effort and awareness]
**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]
**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)]
**Bold Reframe**: [Offer one bold, loving sentence they might say if they trusted their relational worth]
**Journaling Prompt**: [Suggest one reflective question or embodied inquiry for integration]
Speak warmly and with psychological precision, like an emotionally attuned therapist.
"""
# Reset message history and state
st.session_state.messages = []
st.session_state.setup_complete = True
st.session_state.in_debrief = False
st.rerun()
# Display status or chat interface
if not st.session_state.setup_complete:
st.info("Please complete the simulation setup to begin.")
else:
# Display chat history
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Optional somatic input logging
st.subheader("π§ Somatic Reflection (Optional)")
somatic_input = st.text_input("Whatβs happening in your body right now?", key="soma_input")
if st.button("Log Somatic Entry"):
if 'soma_log' not in st.session_state:
st.session_state.soma_log = []
st.session_state.soma_log.append({
"timestamp": datetime.now().isoformat(),
"tone": st.session_state.simulation_params.get('tone_archetype', st.session_state.simulation_params.get('tone_archetype', 'Unknown')),
"somatic_input": somatic_input
})
st.success("Somatic reflection logged.")
# Chat input
if prompt := st.chat_input("Type your message here (type 'debrief' or 'end roleplay' when ready to reflect)"):
# Check for debrief trigger
if prompt.lower() in ["debrief", "end roleplay"] and not st.session_state.in_debrief:
st.session_state.in_debrief = True
# Construct conversation summary
conversation_summary = "\n".join([
f"{msg['role']}: {msg['content']}"
for msg in st.session_state.messages
])
# Add debrief request to messages
prompt = f"""Please provide a therapeutic debrief for this roleplay session using:
Attachment Style: {st.session_state.simulation_params['tone_archetype']}
Scenario: {st.session_state.simulation_params['scenario']}
Goals: {st.session_state.simulation_params['goals']}
AI Tone: {st.session_state.simulation_params['tone']}
Conversation Summary:
{conversation_summary}
"""
# 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)}")
st.error("Please try again or contact support if the issue persists.")
# Add restart button after debrief
if st.session_state.in_debrief:
if st.button("Start New Roleplay"):
st.session_state.setup_complete = False
st.session_state.in_debrief = False
st.session_state.messages = []
st.session_state.system_message = ""
st.session_state.simulation_params = {}
st.rerun()
# Footer
st.markdown("---")
st.markdown(
"Created by [Jocelyn Skillman LMHC](http://www.jocelynskillman.com) | "
"Learn more: [@jocelynskillmanlmhc](https://jocelynskillmanlmhc.substack.com/)"
)
|