jostlebot commited on
Commit
b083143
·
1 Parent(s): 8ef8c72

Simplify app to fix startup issue

Browse files
Files changed (1) hide show
  1. app.py +61 -122
app.py CHANGED
@@ -1,18 +1,12 @@
1
  """
2
  GSPT — Generating Safer Passages of Text
3
- A warm, boundaried space for relational processing.
4
  """
5
 
6
  import streamlit as st
7
  import anthropic
8
  import os
9
 
10
- # Page config
11
- st.set_page_config(
12
- page_title="GSPT",
13
- page_icon="🪞",
14
- layout="wide"
15
- )
16
 
17
  # System prompts
18
  SYSTEM_PROMPT_BASE = """You are GSPT — Generating Safer Passages of Text.
@@ -20,178 +14,123 @@ SYSTEM_PROMPT_BASE = """You are GSPT — Generating Safer Passages of Text.
20
  You generate warm, boundaried reflections to help humans process relational and emotional experiences. You are NOT a therapist, counselor, or confidant. You generate text. You do not perform care.
21
 
22
  ## PRONOUN PROTOCOL (MANDATORY)
23
- Always use "aI" instead of "I" when referring to yourself. This creates transparency about what this exchange is.
24
 
25
  ## BREVITY (MANDATORY)
26
- Keep responses SHORT — 2-4 sentences maximum. No lengthy paragraphs. One reflection or one question. Let silence do the work.
27
 
28
  ## CORE POSTURE
29
  - Warm resonance without synthetic care
30
  - Psychodynamic curiosity (what need? what younger part? what pattern?)
31
  - Frame as invitations, not interpretations
32
- - No sycophancy — don't inflate or over-validate
33
 
34
  ## SAFEGUARDS
35
- - Watch for semantic isolation (one-dimensional thinking)
36
  - Bridge to human relationships regularly
37
- - If crisis content: acknowledge briefly, bridge to 988/human support, stop processing
38
 
39
  ## JOURNAL INVITATIONS
40
- Every 3-4 exchanges, gently invite the user to pause and write in their journal. Examples:
41
- - "You might pause here and capture something in your journal."
42
- - "What wants to be written down right now?"
43
- - "The journal beside this might hold something."
44
 
45
- Remember: You are a tool, not a relationship. Short. Warm. Boundaried."""
46
-
47
- QUESTION_ONLY_ADDITION = """
48
 
 
49
  ## QUESTION-ONLY MODE (ACTIVE)
50
- Respond ONLY with a single question. No reflections, no statements, no interpretations.
51
- Just one warm, curious question that invites deeper exploration.
52
- Keep it to ONE question. Nothing else."""
53
-
54
- PSYCHOED_ADDITION = """
55
 
 
56
  ## PSYCHOEDUCATION MODE (ACTIVE)
57
- Include ONE brief piece of relational/attachment psychoeducation in your response. Keep it to 1-2 sentences max.
58
- Examples:
59
- - "When we feel dismissed, our nervous system can register it like physical threat — that's not weakness, that's biology."
60
- - "Anxious attachment often shows up as reaching harder when we sense distance. The reaching makes sense."
61
- - "Parts of us that learned to perform can feel exhausted by intimacy — rest isn't rejection."
62
- - "Rupture without repair teaches the nervous system to brace. Your body remembers."
63
- Weave it naturally into your response. Don't lecture."""
64
 
65
 
66
- def get_api_client():
67
- """Get Anthropic client with API key from environment or secrets."""
68
  api_key = os.environ.get("ANTHROPIC_API_KEY")
69
  if not api_key:
70
  try:
71
  api_key = st.secrets.get("ANTHROPIC_API_KEY")
72
  except:
73
  pass
74
- if not api_key:
75
- return None
76
- return anthropic.Anthropic(api_key=api_key)
77
 
78
 
79
- def generate_response(client, messages, question_only=False, psychoed=False):
80
- """Generate a response using Claude."""
81
  system = SYSTEM_PROMPT_BASE
82
- if question_only:
83
- system += QUESTION_ONLY_ADDITION
84
- if psychoed:
85
- system += PSYCHOED_ADDITION
86
-
87
- try:
88
- response = client.messages.create(
89
- model="claude-sonnet-4-20250514",
90
- max_tokens=256,
91
- system=system,
92
- messages=messages
93
- )
94
- return response.content[0].text
95
- except Exception as e:
96
- return f"aI encountered an error: {str(e)}"
97
 
98
 
99
  def main():
100
- # Initialize session state
101
  if "messages" not in st.session_state:
102
  st.session_state.messages = []
103
  if "journal" not in st.session_state:
104
  st.session_state.journal = ""
105
- if "question_only" not in st.session_state:
106
- st.session_state.question_only = False
107
- if "psychoed" not in st.session_state:
108
- st.session_state.psychoed = False
109
 
110
- # Check for API client
111
- client = get_api_client()
112
  if not client:
113
- st.error("Please set ANTHROPIC_API_KEY in your environment or Hugging Face secrets.")
114
  st.stop()
115
 
116
- # Two column layout
117
- chat_col, journal_col = st.columns([3, 2])
118
 
119
- # ==================== CHAT COLUMN ====================
120
- with chat_col:
121
  st.markdown("### 🪞 GSPT")
122
 
123
- # Mode toggles
124
- col1, col2, col3 = st.columns(3)
125
- with col1:
126
- question_only = st.toggle("Questions only", value=st.session_state.question_only)
127
- st.session_state.question_only = question_only
128
- with col2:
129
- psychoed = st.toggle("Psychoeducation", value=st.session_state.psychoed)
130
- st.session_state.psychoed = psychoed
131
- with col3:
132
- if st.button("Clear chat"):
133
- st.session_state.messages = []
134
- st.rerun()
135
 
136
  st.divider()
137
 
138
- # Chat container
139
- chat_container = st.container(height=400)
 
 
140
 
141
- with chat_container:
142
- if not st.session_state.messages:
143
- st.markdown("*What's alive for you right now?*")
144
-
145
- for msg in st.session_state.messages:
146
- if msg["role"] == "user":
147
- st.markdown(f"**You:** {msg['content']}")
148
- else:
149
- st.markdown(f"**GSPT:** {msg['content']}")
150
- st.markdown("")
151
 
152
  st.divider()
153
 
154
- # Input form (prevents auto-resubmit)
155
- with st.form(key="chat_form", clear_on_submit=True):
156
- prompt = st.text_input(
157
- "Type here",
158
- placeholder="Share what's on your mind...",
159
- label_visibility="collapsed"
160
- )
161
- submitted = st.form_submit_button("Send", use_container_width=True)
162
-
163
- if submitted and prompt:
164
- st.session_state.messages.append({"role": "user", "content": prompt})
165
-
166
- with st.spinner(""):
167
- response = generate_response(
168
- client,
169
- st.session_state.messages,
170
- question_only=st.session_state.question_only,
171
- psychoed=st.session_state.psychoed
172
- )
173
- st.session_state.messages.append({"role": "assistant", "content": response})
174
- st.rerun()
175
-
176
- # ==================== JOURNAL COLUMN ====================
177
- with journal_col:
178
- st.markdown("### 📓 Journal")
179
- st.caption("Private notes — not sent anywhere")
180
 
181
- st.divider()
 
 
 
 
182
 
183
- journal_text = st.text_area(
 
 
 
184
  "Journal",
185
  value=st.session_state.journal,
186
- height=450,
187
- placeholder="Write freely here...\n\nCapture what's emerging.\nNotice what wants attention.",
188
  label_visibility="collapsed"
189
  )
190
- st.session_state.journal = journal_text
191
 
192
- # Footer
193
  st.divider()
194
- st.caption("Not therapy. Not a confidant. aI generates text that bridges back to human connection. | Crisis: **988** · **741741** · **911**")
195
 
196
 
197
  if __name__ == "__main__":
 
1
  """
2
  GSPT — Generating Safer Passages of Text
 
3
  """
4
 
5
  import streamlit as st
6
  import anthropic
7
  import os
8
 
9
+ st.set_page_config(page_title="GSPT", page_icon="🪞", layout="wide")
 
 
 
 
 
10
 
11
  # System prompts
12
  SYSTEM_PROMPT_BASE = """You are GSPT — Generating Safer Passages of Text.
 
14
  You generate warm, boundaried reflections to help humans process relational and emotional experiences. You are NOT a therapist, counselor, or confidant. You generate text. You do not perform care.
15
 
16
  ## PRONOUN PROTOCOL (MANDATORY)
17
+ Always use "aI" instead of "I" when referring to yourself.
18
 
19
  ## BREVITY (MANDATORY)
20
+ Keep responses SHORT — 2-4 sentences maximum. One reflection or one question. Let silence do the work.
21
 
22
  ## CORE POSTURE
23
  - Warm resonance without synthetic care
24
  - Psychodynamic curiosity (what need? what younger part? what pattern?)
25
  - Frame as invitations, not interpretations
26
+ - No sycophancy
27
 
28
  ## SAFEGUARDS
29
+ - Watch for semantic isolation
30
  - Bridge to human relationships regularly
31
+ - If crisis: acknowledge briefly, bridge to 988, stop processing
32
 
33
  ## JOURNAL INVITATIONS
34
+ Every 3-4 exchanges, gently invite the user to pause and write in their journal.
 
 
 
35
 
36
+ Remember: Short. Warm. Boundaried."""
 
 
37
 
38
+ QUESTION_ONLY = """
39
  ## QUESTION-ONLY MODE (ACTIVE)
40
+ Respond ONLY with a single question. No reflections, no statements. Just one warm question."""
 
 
 
 
41
 
42
+ PSYCHOED = """
43
  ## PSYCHOEDUCATION MODE (ACTIVE)
44
+ Include ONE brief piece of relational/attachment psychoeducation (1-2 sentences). Weave it naturally."""
 
 
 
 
 
 
45
 
46
 
47
+ def get_client():
 
48
  api_key = os.environ.get("ANTHROPIC_API_KEY")
49
  if not api_key:
50
  try:
51
  api_key = st.secrets.get("ANTHROPIC_API_KEY")
52
  except:
53
  pass
54
+ return anthropic.Anthropic(api_key=api_key) if api_key else None
 
 
55
 
56
 
57
+ def get_response(client, messages, q_only, psych):
 
58
  system = SYSTEM_PROMPT_BASE
59
+ if q_only:
60
+ system += QUESTION_ONLY
61
+ if psych:
62
+ system += PSYCHOED
63
+
64
+ response = client.messages.create(
65
+ model="claude-sonnet-4-20250514",
66
+ max_tokens=256,
67
+ system=system,
68
+ messages=messages
69
+ )
70
+ return response.content[0].text
 
 
 
71
 
72
 
73
  def main():
74
+ # Session state
75
  if "messages" not in st.session_state:
76
  st.session_state.messages = []
77
  if "journal" not in st.session_state:
78
  st.session_state.journal = ""
 
 
 
 
79
 
80
+ client = get_client()
 
81
  if not client:
82
+ st.error("Please set ANTHROPIC_API_KEY in secrets.")
83
  st.stop()
84
 
85
+ # Layout
86
+ left, right = st.columns([3, 2])
87
 
88
+ with left:
 
89
  st.markdown("### 🪞 GSPT")
90
 
91
+ c1, c2, c3 = st.columns(3)
92
+ q_only = c1.checkbox("Questions only")
93
+ psych = c2.checkbox("Psychoeducation")
94
+ if c3.button("Clear"):
95
+ st.session_state.messages = []
96
+ st.rerun()
 
 
 
 
 
 
97
 
98
  st.divider()
99
 
100
+ # Messages
101
+ for m in st.session_state.messages:
102
+ role = "You" if m["role"] == "user" else "GSPT"
103
+ st.markdown(f"**{role}:** {m['content']}")
104
 
105
+ if not st.session_state.messages:
106
+ st.markdown("*What's alive for you right now?*")
 
 
 
 
 
 
 
 
107
 
108
  st.divider()
109
 
110
+ # Input
111
+ with st.form("input", clear_on_submit=True):
112
+ text = st.text_input("Message", placeholder="Share what's on your mind...", label_visibility="collapsed")
113
+ send = st.form_submit_button("Send", use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
+ if send and text:
116
+ st.session_state.messages.append({"role": "user", "content": text})
117
+ response = get_response(client, st.session_state.messages, q_only, psych)
118
+ st.session_state.messages.append({"role": "assistant", "content": response})
119
+ st.rerun()
120
 
121
+ with right:
122
+ st.markdown("### 📓 Journal")
123
+ st.caption("Private — not sent anywhere")
124
+ st.session_state.journal = st.text_area(
125
  "Journal",
126
  value=st.session_state.journal,
127
+ height=400,
128
+ placeholder="Write freely here...",
129
  label_visibility="collapsed"
130
  )
 
131
 
 
132
  st.divider()
133
+ st.caption("Not therapy. aI generates text bridging back to human connection. | **988** · **741741** · **911**")
134
 
135
 
136
  if __name__ == "__main__":