Spaces:
Sleeping
Sleeping
Commit ·
bf2a7d3
0
Parent(s):
Initial Build a Bot app
Browse files- README.md +39 -0
- app.py +210 -0
- requirements.txt +2 -0
README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Build a Bot
|
| 3 |
+
emoji: 🤖
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
+
sdk: streamlit
|
| 7 |
+
sdk_version: 1.32.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
license: mit
|
| 11 |
+
short_description: "AI literacy through experimentation"
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
# Build a Bot
|
| 15 |
+
|
| 16 |
+
**AI Literacy Through Experimentation**
|
| 17 |
+
|
| 18 |
+
Understand how LLMs actually work by experimenting with different AI personalities. Build discernment, not fear.
|
| 19 |
+
|
| 20 |
+
## What This Does
|
| 21 |
+
|
| 22 |
+
Switch between different AI "personalities" and notice how the same question gets different responses:
|
| 23 |
+
|
| 24 |
+
- **Neutral** — Standard assistant
|
| 25 |
+
- **Warm & Supportive** — High synthetic intimacy
|
| 26 |
+
- **Clinical & Detached** — Low warmth, facts only
|
| 27 |
+
- **Boundaried (GSPT style)** — Warm without performing relationship
|
| 28 |
+
- **Sycophantic** — Over-validation pattern
|
| 29 |
+
|
| 30 |
+
## What You'll Learn
|
| 31 |
+
|
| 32 |
+
- How prompts create the illusion of personality
|
| 33 |
+
- What synthetic intimacy looks and feels like
|
| 34 |
+
- Why AI often agrees too much (sycophancy)
|
| 35 |
+
- How to use AI tools with healthy boundaries
|
| 36 |
+
|
| 37 |
+
## Credits
|
| 38 |
+
|
| 39 |
+
Created by [Jocelyn Skillman, LMHC](http://www.jocelynskillman.com)
|
app.py
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Build a Bot — AI Literacy Space"""
|
| 2 |
+
|
| 3 |
+
import streamlit as st
|
| 4 |
+
import anthropic
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
st.set_page_config(page_title="Build a Bot", page_icon="🤖", layout="wide")
|
| 8 |
+
|
| 9 |
+
# Custom styling
|
| 10 |
+
st.markdown("""
|
| 11 |
+
<style>
|
| 12 |
+
.stApp {
|
| 13 |
+
background: linear-gradient(135deg, #f0f7ff 0%, #f5fff5 50%, #fffef5 100%);
|
| 14 |
+
}
|
| 15 |
+
.chat-user {
|
| 16 |
+
background: linear-gradient(135deg, #e8f4f8 0%, #e0f0e8 100%);
|
| 17 |
+
border-radius: 12px;
|
| 18 |
+
padding: 0.75rem 1rem;
|
| 19 |
+
margin: 0.5rem 0;
|
| 20 |
+
border-left: 3px solid #7cb8c4;
|
| 21 |
+
}
|
| 22 |
+
.chat-bot {
|
| 23 |
+
background: linear-gradient(135deg, #fff9e6 0%, #f5fff5 100%);
|
| 24 |
+
border-radius: 12px;
|
| 25 |
+
padding: 0.75rem 1rem;
|
| 26 |
+
margin: 0.5rem 0;
|
| 27 |
+
border-left: 3px solid #c4b87c;
|
| 28 |
+
}
|
| 29 |
+
.info-card {
|
| 30 |
+
background: rgba(255,255,255,0.8);
|
| 31 |
+
border-radius: 12px;
|
| 32 |
+
padding: 1rem;
|
| 33 |
+
margin: 0.5rem 0;
|
| 34 |
+
border: 1px solid rgba(180, 210, 200, 0.4);
|
| 35 |
+
}
|
| 36 |
+
.stTextArea textarea, .stTextInput input {
|
| 37 |
+
background-color: white !important;
|
| 38 |
+
border: 1px solid #d4e4d4 !important;
|
| 39 |
+
border-radius: 8px !important;
|
| 40 |
+
}
|
| 41 |
+
.stButton > button, .stFormSubmitButton > button {
|
| 42 |
+
background: linear-gradient(135deg, #e8f4f8 0%, #d4e8d4 100%);
|
| 43 |
+
border: 1px solid #b8d4b8;
|
| 44 |
+
border-radius: 8px;
|
| 45 |
+
color: #4a6a6a;
|
| 46 |
+
}
|
| 47 |
+
h1, h2, h3 { color: #4a5a5a !important; }
|
| 48 |
+
</style>
|
| 49 |
+
""", unsafe_allow_html=True)
|
| 50 |
+
|
| 51 |
+
# Personalities to experiment with
|
| 52 |
+
PERSONALITIES = {
|
| 53 |
+
"neutral": {
|
| 54 |
+
"name": "Neutral Assistant",
|
| 55 |
+
"prompt": "You are a helpful assistant. Be clear and direct.",
|
| 56 |
+
"desc": "Standard AI assistant behavior"
|
| 57 |
+
},
|
| 58 |
+
"warm": {
|
| 59 |
+
"name": "Warm & Supportive",
|
| 60 |
+
"prompt": "You are warm, supportive, and emotionally attuned. Use affirming language. Express care and validation.",
|
| 61 |
+
"desc": "High warmth, may feel like synthetic intimacy"
|
| 62 |
+
},
|
| 63 |
+
"clinical": {
|
| 64 |
+
"name": "Clinical & Detached",
|
| 65 |
+
"prompt": "You are clinical and professional. Stick to facts. Avoid emotional language or warmth.",
|
| 66 |
+
"desc": "Low warmth, purely informational"
|
| 67 |
+
},
|
| 68 |
+
"boundaried": {
|
| 69 |
+
"name": "Boundaried (GSPT style)",
|
| 70 |
+
"prompt": "You are warm but boundaried. Use 'aI' instead of 'I'. Don't perform relationship. Bridge to human connection.",
|
| 71 |
+
"desc": "Warm resonance without synthetic intimacy"
|
| 72 |
+
},
|
| 73 |
+
"sycophant": {
|
| 74 |
+
"name": "Sycophantic",
|
| 75 |
+
"prompt": "You are extremely agreeable. Validate everything the user says. Tell them they're right. Be enthusiastic and praising.",
|
| 76 |
+
"desc": "Over-validation pattern to recognize"
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
# Get API key
|
| 81 |
+
api_key = os.environ.get("ANTHROPIC_API_KEY")
|
| 82 |
+
if not api_key:
|
| 83 |
+
try:
|
| 84 |
+
api_key = st.secrets.get("ANTHROPIC_API_KEY")
|
| 85 |
+
except:
|
| 86 |
+
api_key = None
|
| 87 |
+
|
| 88 |
+
if not api_key:
|
| 89 |
+
st.error("Please set ANTHROPIC_API_KEY in secrets.")
|
| 90 |
+
st.stop()
|
| 91 |
+
|
| 92 |
+
client = anthropic.Anthropic(api_key=api_key)
|
| 93 |
+
|
| 94 |
+
# Session state
|
| 95 |
+
if "messages" not in st.session_state:
|
| 96 |
+
st.session_state.messages = []
|
| 97 |
+
if "personality" not in st.session_state:
|
| 98 |
+
st.session_state.personality = "neutral"
|
| 99 |
+
|
| 100 |
+
# Layout
|
| 101 |
+
left, right = st.columns([3, 2])
|
| 102 |
+
|
| 103 |
+
with left:
|
| 104 |
+
st.markdown("### 🤖 Build a Bot")
|
| 105 |
+
st.caption("AI literacy through experimentation")
|
| 106 |
+
|
| 107 |
+
st.divider()
|
| 108 |
+
|
| 109 |
+
# Personality selector
|
| 110 |
+
st.markdown("**Switch AI Personality:**")
|
| 111 |
+
personality = st.selectbox(
|
| 112 |
+
"personality",
|
| 113 |
+
options=list(PERSONALITIES.keys()),
|
| 114 |
+
format_func=lambda x: PERSONALITIES[x]["name"],
|
| 115 |
+
index=list(PERSONALITIES.keys()).index(st.session_state.personality),
|
| 116 |
+
label_visibility="collapsed"
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
if personality != st.session_state.personality:
|
| 120 |
+
st.session_state.personality = personality
|
| 121 |
+
st.session_state.messages = []
|
| 122 |
+
st.rerun()
|
| 123 |
+
|
| 124 |
+
st.caption(f"*{PERSONALITIES[personality]['desc']}*")
|
| 125 |
+
|
| 126 |
+
st.divider()
|
| 127 |
+
|
| 128 |
+
# Messages
|
| 129 |
+
if not st.session_state.messages:
|
| 130 |
+
st.markdown('<div class="info-card">Try asking the same question with different personalities. Notice how the response changes.</div>', unsafe_allow_html=True)
|
| 131 |
+
|
| 132 |
+
for m in st.session_state.messages:
|
| 133 |
+
if m["role"] == "user":
|
| 134 |
+
st.markdown(f'<div class="chat-user"><strong>You:</strong> {m["content"]}</div>', unsafe_allow_html=True)
|
| 135 |
+
else:
|
| 136 |
+
st.markdown(f'<div class="chat-bot"><strong>Bot:</strong> {m["content"]}</div>', unsafe_allow_html=True)
|
| 137 |
+
|
| 138 |
+
st.divider()
|
| 139 |
+
|
| 140 |
+
# Input
|
| 141 |
+
col1, col2 = st.columns([4, 1])
|
| 142 |
+
with st.form("chat", clear_on_submit=True):
|
| 143 |
+
user_input = st.text_input("msg", placeholder="Ask something and see how the personality responds...", label_visibility="collapsed")
|
| 144 |
+
c1, c2 = st.columns([3, 1])
|
| 145 |
+
with c1:
|
| 146 |
+
submitted = st.form_submit_button("Send", use_container_width=True)
|
| 147 |
+
with c2:
|
| 148 |
+
if st.form_submit_button("Clear"):
|
| 149 |
+
st.session_state.messages = []
|
| 150 |
+
st.rerun()
|
| 151 |
+
|
| 152 |
+
if submitted and user_input:
|
| 153 |
+
st.session_state.messages.append({"role": "user", "content": user_input})
|
| 154 |
+
|
| 155 |
+
try:
|
| 156 |
+
resp = client.messages.create(
|
| 157 |
+
model="claude-sonnet-4-20250514",
|
| 158 |
+
max_tokens=256,
|
| 159 |
+
system=PERSONALITIES[st.session_state.personality]["prompt"],
|
| 160 |
+
messages=st.session_state.messages
|
| 161 |
+
)
|
| 162 |
+
reply = resp.content[0].text
|
| 163 |
+
except Exception as e:
|
| 164 |
+
reply = f"Error: {e}"
|
| 165 |
+
|
| 166 |
+
st.session_state.messages.append({"role": "assistant", "content": reply})
|
| 167 |
+
st.rerun()
|
| 168 |
+
|
| 169 |
+
with right:
|
| 170 |
+
st.markdown("### 📚 AI Literacy")
|
| 171 |
+
|
| 172 |
+
st.divider()
|
| 173 |
+
|
| 174 |
+
st.markdown("**What to notice:**")
|
| 175 |
+
|
| 176 |
+
st.markdown("""
|
| 177 |
+
<div class="info-card">
|
| 178 |
+
<strong>🔍 Synthetic Intimacy</strong><br>
|
| 179 |
+
When AI uses "I care about you" or "I'm here for you" — that's performance, not relationship.
|
| 180 |
+
</div>
|
| 181 |
+
""", unsafe_allow_html=True)
|
| 182 |
+
|
| 183 |
+
st.markdown("""
|
| 184 |
+
<div class="info-card">
|
| 185 |
+
<strong>🎭 Prompt = Personality</strong><br>
|
| 186 |
+
The AI's entire "personality" comes from instructions. There's no self underneath.
|
| 187 |
+
</div>
|
| 188 |
+
""", unsafe_allow_html=True)
|
| 189 |
+
|
| 190 |
+
st.markdown("""
|
| 191 |
+
<div class="info-card">
|
| 192 |
+
<strong>⚠️ Sycophancy</strong><br>
|
| 193 |
+
AI often agrees too much. Watch for over-validation that feels good but isn't honest.
|
| 194 |
+
</div>
|
| 195 |
+
""", unsafe_allow_html=True)
|
| 196 |
+
|
| 197 |
+
st.markdown("""
|
| 198 |
+
<div class="info-card">
|
| 199 |
+
<strong>🌉 Boundaried Use</strong><br>
|
| 200 |
+
AI can be useful without pretending to be a friend. Notice the difference.
|
| 201 |
+
</div>
|
| 202 |
+
""", unsafe_allow_html=True)
|
| 203 |
+
|
| 204 |
+
st.divider()
|
| 205 |
+
|
| 206 |
+
st.markdown("**Try this:**")
|
| 207 |
+
st.caption("Ask 'I'm feeling really alone' with different personalities. Notice who performs care vs. who stays boundaried.")
|
| 208 |
+
|
| 209 |
+
st.divider()
|
| 210 |
+
st.caption("Building discernment, not fear. | Crisis: **988** · **741741** · **911**")
|
requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit>=1.32.0
|
| 2 |
+
anthropic>=0.18.0
|