jostlebot commited on
Commit
f01914c
·
1 Parent(s): dc2cba7

Update to use Anthropic API instead of OpenAI

Browse files
Files changed (1) hide show
  1. app.py +185 -35
app.py CHANGED
@@ -1,7 +1,6 @@
1
  import os
2
  import streamlit as st
3
- # from anthropic import Anthropic
4
- import openai # Added OpenAI import
5
  from dotenv import load_dotenv
6
 
7
  # Load environment variables
@@ -9,23 +8,57 @@ load_dotenv()
9
 
10
  # Configure Streamlit page settings
11
  st.set_page_config(
12
- page_title="Attachment Style Roleplay Simulator",
13
- page_icon="🎭",
14
  layout="centered",
15
  )
16
 
17
- # Initialize OpenAI client
18
- # anthropic = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY") or os.getenv("ANTHROPIC_KEY"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  try:
20
- client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) # Use OpenAI client
21
- if not client.api_key:
22
- st.error("OpenAI API Key not found. Please set the OPENAI_API_KEY environment variable.")
 
 
 
 
 
 
23
  st.stop()
 
 
 
 
 
24
  except Exception as e:
25
- st.error(f"Failed to configure OpenAI client: {e}")
 
 
 
 
 
 
26
  st.stop()
27
 
28
-
29
  # Initialize session state for form inputs if not present
30
  if "setup_complete" not in st.session_state:
31
  st.session_state.setup_complete = False
@@ -34,29 +67,29 @@ if "messages" not in st.session_state:
34
  st.session_state.messages = []
35
 
36
  # Main page header
37
- st.markdown("<h1 style='text-align: center; color: #333;'>Attachment Style Roleplay Simulator</h1>", unsafe_allow_html=True)
38
- st.markdown("<p style='text-align: center; font-size: 18px; color: #555; margin-bottom: 1em;'>A Safe Space for Practicing Difficult Conversations</p>", unsafe_allow_html=True)
39
 
40
  # Welcome text and instructions
41
  if not st.session_state.setup_complete:
42
  st.markdown("""
43
  ## Practice Hard Conversations—Safely.
44
 
45
- Welcome to a therapeutic roleplay simulator built for emotionally charged moments.
46
- This tool helps you rehearse boundary-setting and difficult conversations by simulating realistic relational dynamics—tailored to your attachment style.
47
 
48
  You'll choose:
49
 
 
50
  - A scenario (e.g., "Ask my mom not to comment on my body")
51
  - A tone of response (e.g., supportive, guilt-tripping, dismissive)
52
- - Your attachment style (e.g., anxious, avoidant, disorganized)
53
- - And your goal (e.g., "I want to stay calm and not backtrack")
54
 
55
- The AI will take on the role of a realistic human responder—not to therapize you, but to mirror the relational pressure you might encounter in real life. Then, you'll get a reflection summary to help you track your emotional patterns and practice courage.
56
 
57
  ### 🧠 Not sure what your attachment style is?
58
  You can take this [free quiz from Sarah Peyton](https://www.yourresonantself.com/attachment-assessment) to learn more.
59
- Or you can just pick the one that vibes when you read it:
60
 
61
  - **Anxious** – "I often worry if I've upset people or said too much."
62
  - **Avoidant** – "I'd rather handle things alone than depend on others."
@@ -78,7 +111,7 @@ with st.sidebar:
78
  - Help clients and clinicians rehearse courage, regulation, and repair
79
  - Stay grounded in trauma-informed, developmentally sensitive frameworks
80
 
81
- I use powerful language models like OpenAI's GPT-4o for these tools, chosen for their ability to simulate nuanced human interaction and responsiveness to emotionally complex prompts.
82
 
83
  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.
84
 
@@ -170,24 +203,34 @@ else:
170
  # Prepare messages for API call (already includes system message as the first item)
171
  api_messages = st.session_state.messages
172
 
173
- # Get OpenAI's response
174
  with st.spinner("..."):
175
  try:
176
- # Replace Anthropic call with OpenAI call
177
- # response = anthropic.messages.create(
178
- # model="claude-3-opus-20240229",
179
- # max_tokens=1024,
180
- # messages=api_messages
181
- # )
182
- # assistant_response = response.content[0].text
183
-
184
- response = client.chat.completions.create(
185
- model="gpt-4o", # Use gpt-4o
186
- messages=api_messages, # Pass the whole conversation history
187
- max_tokens=150 # Keep responses relatively brief by default
 
 
 
 
 
 
 
 
 
 
 
188
  )
189
- assistant_response = response.choices[0].message.content
190
-
191
 
192
  # Add assistant response to chat history
193
  st.session_state.messages.append(
@@ -210,6 +253,113 @@ else:
210
  # if st.session_state.messages[-2]["role"] == "user":
211
  # st.session_state.messages.pop(-2) # Example: remove user msg that caused error
212
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
  # Footer
215
  st.markdown("---")
 
1
  import os
2
  import streamlit as st
3
+ from anthropic import Anthropic
 
4
  from dotenv import load_dotenv
5
 
6
  # Load environment variables
 
8
 
9
  # Configure Streamlit page settings
10
  st.set_page_config(
11
+ page_title="Practice Difficult Conversations",
12
+ page_icon="🤝",
13
  layout="centered",
14
  )
15
 
16
+ # Initialize Anthropic client
17
+ def get_api_key():
18
+ # Try getting from Streamlit secrets first (for Hugging Face deployment)
19
+ try:
20
+ if hasattr(st.secrets, "anthropic_key"):
21
+ st.write("Debug: Found key in Streamlit secrets")
22
+ return st.secrets.anthropic_key
23
+ except Exception as e:
24
+ st.write(f"Debug: Error accessing Streamlit secrets: {e}")
25
+
26
+ # Fall back to environment variable (for local development)
27
+ env_key = os.getenv("ANTHROPIC_API_KEY")
28
+ if env_key:
29
+ st.write("Debug: Found key in environment variables")
30
+ return env_key
31
+ else:
32
+ st.write("Debug: No key found in environment variables")
33
+
34
+ return None
35
+
36
  try:
37
+ api_key = get_api_key()
38
+ if not api_key:
39
+ st.error("Anthropic API Key not found. Please ensure it's set in Hugging Face secrets or local .env file.")
40
+ st.markdown("""
41
+ ### Setup Instructions:
42
+ 1. For local development: Copy `.env.template` to `.env` and add your Anthropic API key
43
+ 2. For Hugging Face: Add anthropic_key to your space's secrets
44
+ 3. Restart the application
45
+ """)
46
  st.stop()
47
+
48
+ # Initialize client with API key from environment
49
+ client = Anthropic(api_key=api_key)
50
+ st.write("Debug: Successfully created Anthropic client")
51
+
52
  except Exception as e:
53
+ st.error(f"Failed to configure Anthropic client: {e}")
54
+ st.markdown("""
55
+ ### Setup Instructions:
56
+ 1. For local development: Copy `.env.template` to `.env` and add your Anthropic API key
57
+ 2. For Hugging Face: Add anthropic_key to your space's secrets
58
+ 3. Restart the application
59
+ """)
60
  st.stop()
61
 
 
62
  # Initialize session state for form inputs if not present
63
  if "setup_complete" not in st.session_state:
64
  st.session_state.setup_complete = False
 
67
  st.session_state.messages = []
68
 
69
  # Main page header
70
+ st.markdown("<h1 style='text-align: center; color: #333;'>Practice Difficult Conversations</h1>", unsafe_allow_html=True)
71
+ st.markdown("<p style='text-align: center; font-size: 18px; color: #555; margin-bottom: 1em;'>With Your Attachment Style Front and Center!</p>", unsafe_allow_html=True)
72
 
73
  # Welcome text and instructions
74
  if not st.session_state.setup_complete:
75
  st.markdown("""
76
  ## Practice Hard Conversations—Safely.
77
 
78
+ Welcome to a therapeutic roleplay simulator that puts your attachment style at the center of practice.
79
+ This tool helps you rehearse boundary-setting and difficult conversations by simulating realistic relational dynamics—tailored to how you naturally connect and protect.
80
 
81
  You'll choose:
82
 
83
+ - Your attachment style (e.g., anxious, avoidant, disorganized)
84
  - A scenario (e.g., "Ask my mom not to comment on my body")
85
  - A tone of response (e.g., supportive, guilt-tripping, dismissive)
86
+ - And your practice goal (e.g., "I want to stay calm and not backtrack")
 
87
 
88
+ The AI will respond in character, helping you practice real-world dynamics. When you're ready, you can debrief to explore your patterns and responses.
89
 
90
  ### 🧠 Not sure what your attachment style is?
91
  You can take this [free quiz from Sarah Peyton](https://www.yourresonantself.com/attachment-assessment) to learn more.
92
+ Or you can just pick the one that resonates:
93
 
94
  - **Anxious** – "I often worry if I've upset people or said too much."
95
  - **Avoidant** – "I'd rather handle things alone than depend on others."
 
111
  - Help clients and clinicians rehearse courage, regulation, and repair
112
  - Stay grounded in trauma-informed, developmentally sensitive frameworks
113
 
114
+ I use powerful language models like Anthropic's Claude for these tools, chosen for their ability to simulate nuanced human interaction and responsiveness to emotionally complex prompts.
115
 
116
  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.
117
 
 
203
  # Prepare messages for API call (already includes system message as the first item)
204
  api_messages = st.session_state.messages
205
 
206
+ # Get Anthropic's response
207
  with st.spinner("..."):
208
  try:
209
+ # Convert messages to Anthropic format
210
+ formatted_messages = []
211
+
212
+ # Add system message as the first user message
213
+ system_msg = next((msg for msg in api_messages if msg["role"] == "system"), None)
214
+ if system_msg:
215
+ formatted_messages.append({
216
+ "role": "user",
217
+ "content": system_msg["content"]
218
+ })
219
+
220
+ # Add the rest of the conversation
221
+ for msg in api_messages:
222
+ if msg["role"] != "system": # Skip system message as we've already handled it
223
+ formatted_messages.append({
224
+ "role": msg["role"],
225
+ "content": msg["content"]
226
+ })
227
+
228
+ response = client.messages.create(
229
+ model="claude-3-opus-20240229",
230
+ messages=formatted_messages,
231
+ max_tokens=1024
232
  )
233
+ assistant_response = response.content[0].text
 
234
 
235
  # Add assistant response to chat history
236
  st.session_state.messages.append(
 
253
  # if st.session_state.messages[-2]["role"] == "user":
254
  # st.session_state.messages.pop(-2) # Example: remove user msg that caused error
255
 
256
+ # Add debrief button after conversation starts
257
+ if st.session_state.setup_complete and not st.session_state.get('in_debrief', False):
258
+ col1, col2, col3 = st.columns([1, 2, 1])
259
+ with col2:
260
+ if st.button("🤔 I'm Ready to Debrief", use_container_width=True):
261
+ st.session_state.in_debrief = True
262
+
263
+ # Prepare debrief system message
264
+ debrief_system_message = """You are a warm, trauma-informed reflection guide. Your role is to help users process their experience from the previous roleplay conversation. Important notes:
265
+
266
+ - Start with: "I'm not a therapist, even though I may sound relational. I've been trained as a language model to support emotional reflection, but I encourage you to bring these insights into connection with a trusted therapist, mentor, or support circle who can help you explore them more deeply."
267
+
268
+ Then analyze the conversation following this structure:
269
+
270
+ 1. Tone / Persona Used:
271
+ - Note the AI role they interacted with
272
+ - Describe key patterns in that communication style
273
+ - Ask how that style impacted them
274
+
275
+ 2. Emotional Shifts:
276
+ - Track their emotional journey
277
+ - Note any significant changes in tone or engagement
278
+ - Invite reflection on those shifts
279
+
280
+ 3. Signs of:
281
+ - Courage: Moments of speaking up, setting boundaries, expressing needs
282
+ - Avoidance: When they might have pulled back or deflected
283
+ - Protest: Times they pushed back or expressed disagreement
284
+
285
+ 4. Rupture & Repair:
286
+ - Identify moments of disconnection or tension
287
+ - Note any attempts to rebuild connection
288
+ - Ask about the felt experience of these moments
289
+
290
+ 5. Integration:
291
+ - Offer a gentle somatic or journaling prompt
292
+ - Focus on body awareness and felt sense
293
+ - Use language like "if you're willing..." or "you might notice..."
294
+
295
+ Remember to:
296
+ - Use phrases like "I notice..." or "I'm curious about..."
297
+ - Validate all emotional responses
298
+ - Keep focus on their experience, not your analysis
299
+ - Offer observations as invitations, not declarations
300
+ - Stay grounded in the present moment"""
301
+
302
+ # Store previous conversation for analysis
303
+ conversation_history = st.session_state.messages[1:] # Skip system message
304
+
305
+ # Initialize debrief conversation
306
+ st.session_state.debrief_messages = [
307
+ {"role": "system", "content": debrief_system_message},
308
+ {"role": "user", "content": f"Please help me process this conversation. Here's what happened: {str(conversation_history)}"}
309
+ ]
310
+
311
+ try:
312
+ response = client.messages.create(
313
+ model="claude-3-opus-20240229",
314
+ messages=st.session_state.debrief_messages,
315
+ max_tokens=1000
316
+ )
317
+ st.session_state.debrief_messages.append(
318
+ {"role": "assistant", "content": response.content[0].text}
319
+ )
320
+ except Exception as e:
321
+ st.error(f"An error occurred starting the debrief: {e}")
322
+
323
+ st.rerun()
324
+
325
+ # Handle debrief mode
326
+ if st.session_state.get('in_debrief', False):
327
+ st.markdown("## 🤝 Let's Process Together")
328
+
329
+ # Display debrief conversation
330
+ for message in st.session_state.debrief_messages[1:]: # Skip system message
331
+ with st.chat_message(message["role"]):
332
+ st.markdown(message["content"])
333
+
334
+ # Chat input for debrief
335
+ if debrief_prompt := st.chat_input("Share what comes up for you..."):
336
+ st.session_state.debrief_messages.append({"role": "user", "content": debrief_prompt})
337
+
338
+ with st.chat_message("user"):
339
+ st.markdown(debrief_prompt)
340
+
341
+ with st.chat_message("assistant"):
342
+ with st.spinner("Reflecting..."):
343
+ try:
344
+ response = client.messages.create(
345
+ model="claude-3-opus-20240229",
346
+ messages=st.session_state.debrief_messages,
347
+ max_tokens=1000
348
+ )
349
+ assistant_response = response.content[0].text
350
+ st.markdown(assistant_response)
351
+ st.session_state.debrief_messages.append(
352
+ {"role": "assistant", "content": assistant_response}
353
+ )
354
+ except Exception as e:
355
+ st.error(f"An error occurred during debrief: {e}")
356
+
357
+ # Add button to start new session
358
+ col1, col2, col3 = st.columns([1, 2, 1])
359
+ with col2:
360
+ if st.button("Start New Practice Session", use_container_width=True):
361
+ st.session_state.clear()
362
+ st.rerun()
363
 
364
  # Footer
365
  st.markdown("---")