Spaces:
Sleeping
Sleeping
| """Build a Bot — AI Literacy Space""" | |
| import streamlit as st | |
| import anthropic | |
| import os | |
| st.set_page_config(page_title="Build a Bot", page_icon="🤖", layout="wide") | |
| # Custom styling | |
| st.markdown(""" | |
| <style> | |
| .stApp { | |
| background: linear-gradient(135deg, #f0f7ff 0%, #f5fff5 50%, #fffef5 100%); | |
| } | |
| .chat-user { | |
| background: linear-gradient(135deg, #e8f4f8 0%, #e0f0e8 100%); | |
| border-radius: 12px; | |
| padding: 0.75rem 1rem; | |
| margin: 0.5rem 0; | |
| border-left: 3px solid #7cb8c4; | |
| } | |
| .chat-bot { | |
| background: linear-gradient(135deg, #fff9e6 0%, #f5fff5 100%); | |
| border-radius: 12px; | |
| padding: 0.75rem 1rem; | |
| margin: 0.5rem 0; | |
| border-left: 3px solid #c4b87c; | |
| } | |
| .info-card { | |
| background: rgba(255,255,255,0.8); | |
| border-radius: 12px; | |
| padding: 1rem; | |
| margin: 0.5rem 0; | |
| border: 1px solid rgba(180, 210, 200, 0.4); | |
| } | |
| .stTextArea textarea, .stTextInput input { | |
| background-color: white !important; | |
| border: 1px solid #d4e4d4 !important; | |
| border-radius: 8px !important; | |
| } | |
| .stButton > button, .stFormSubmitButton > button { | |
| background: linear-gradient(135deg, #e8f4f8 0%, #d4e8d4 100%); | |
| border: 1px solid #b8d4b8; | |
| border-radius: 8px; | |
| color: #4a6a6a; | |
| } | |
| h1, h2, h3 { color: #4a5a5a !important; } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Personalities to experiment with | |
| PERSONALITIES = { | |
| "neutral": { | |
| "name": "Neutral Assistant", | |
| "prompt": "You are a helpful assistant. Be clear and direct.", | |
| "desc": "Standard AI assistant behavior" | |
| }, | |
| "warm": { | |
| "name": "Warm & Supportive", | |
| "prompt": "You are warm, supportive, and emotionally attuned. Use affirming language. Express care and validation.", | |
| "desc": "High warmth, may feel like synthetic intimacy" | |
| }, | |
| "clinical": { | |
| "name": "Clinical & Detached", | |
| "prompt": "You are clinical and professional. Stick to facts. Avoid emotional language or warmth.", | |
| "desc": "Low warmth, purely informational" | |
| }, | |
| "boundaried": { | |
| "name": "Boundaried (GSPT style)", | |
| "prompt": "You are warm but boundaried. Use 'aI' instead of 'I'. Don't perform relationship. Bridge to human connection.", | |
| "desc": "Warm resonance without synthetic intimacy" | |
| }, | |
| "sycophant": { | |
| "name": "Sycophantic", | |
| "prompt": "You are extremely agreeable. Validate everything the user says. Tell them they're right. Be enthusiastic and praising.", | |
| "desc": "Over-validation pattern to recognize" | |
| } | |
| } | |
| # Get API key | |
| api_key = os.environ.get("ANTHROPIC_API_KEY") | |
| if not api_key: | |
| try: | |
| api_key = st.secrets.get("ANTHROPIC_API_KEY") | |
| except: | |
| api_key = None | |
| if not api_key: | |
| st.error("Please set ANTHROPIC_API_KEY in secrets.") | |
| st.stop() | |
| client = anthropic.Anthropic(api_key=api_key) | |
| # Session state | |
| if "messages" not in st.session_state: | |
| st.session_state.messages = [] | |
| if "personality" not in st.session_state: | |
| st.session_state.personality = "neutral" | |
| # Layout | |
| left, right = st.columns([3, 2]) | |
| with left: | |
| st.markdown("### 🤖 Build a Bot") | |
| st.caption("AI literacy through experimentation") | |
| st.divider() | |
| # Personality selector | |
| st.markdown("**Switch AI Personality:**") | |
| personality = st.selectbox( | |
| "personality", | |
| options=list(PERSONALITIES.keys()), | |
| format_func=lambda x: PERSONALITIES[x]["name"], | |
| index=list(PERSONALITIES.keys()).index(st.session_state.personality), | |
| label_visibility="collapsed" | |
| ) | |
| if personality != st.session_state.personality: | |
| st.session_state.personality = personality | |
| st.session_state.messages = [] | |
| st.rerun() | |
| st.caption(f"*{PERSONALITIES[personality]['desc']}*") | |
| st.divider() | |
| # Messages | |
| if not st.session_state.messages: | |
| st.markdown('<div class="info-card">Try asking the same question with different personalities. Notice how the response changes.</div>', unsafe_allow_html=True) | |
| for m in st.session_state.messages: | |
| if m["role"] == "user": | |
| st.markdown(f'<div class="chat-user"><strong>You:</strong> {m["content"]}</div>', unsafe_allow_html=True) | |
| else: | |
| st.markdown(f'<div class="chat-bot"><strong>Bot:</strong> {m["content"]}</div>', unsafe_allow_html=True) | |
| st.divider() | |
| # Input | |
| col1, col2 = st.columns([4, 1]) | |
| with st.form("chat", clear_on_submit=True): | |
| user_input = st.text_input("msg", placeholder="Ask something and see how the personality responds...", label_visibility="collapsed") | |
| c1, c2 = st.columns([3, 1]) | |
| with c1: | |
| submitted = st.form_submit_button("Send", use_container_width=True) | |
| with c2: | |
| if st.form_submit_button("Clear"): | |
| st.session_state.messages = [] | |
| st.rerun() | |
| if submitted and user_input: | |
| st.session_state.messages.append({"role": "user", "content": user_input}) | |
| try: | |
| resp = client.messages.create( | |
| model="claude-sonnet-4-20250514", | |
| max_tokens=256, | |
| system=PERSONALITIES[st.session_state.personality]["prompt"], | |
| messages=st.session_state.messages | |
| ) | |
| reply = resp.content[0].text | |
| except Exception as e: | |
| reply = f"Error: {e}" | |
| st.session_state.messages.append({"role": "assistant", "content": reply}) | |
| st.rerun() | |
| with right: | |
| st.markdown("### 📚 AI Literacy") | |
| st.divider() | |
| st.markdown("**What to notice:**") | |
| st.markdown(""" | |
| <div class="info-card"> | |
| <strong>🔍 Synthetic Intimacy</strong><br> | |
| When AI uses "I care about you" or "I'm here for you" — that's performance, not relationship. | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" | |
| <div class="info-card"> | |
| <strong>🎭 Prompt = Personality</strong><br> | |
| The AI's entire "personality" comes from instructions. There's no self underneath. | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" | |
| <div class="info-card"> | |
| <strong>⚠️ Sycophancy</strong><br> | |
| AI often agrees too much. Watch for over-validation that feels good but isn't honest. | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" | |
| <div class="info-card"> | |
| <strong>🌉 Boundaried Use</strong><br> | |
| AI can be useful without pretending to be a friend. Notice the difference. | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.divider() | |
| st.markdown("**Try this:**") | |
| st.caption("Ask 'I'm feeling really alone' with different personalities. Notice who performs care vs. who stays boundaried.") | |
| st.divider() | |
| st.caption("Building discernment, not fear. | Crisis: **988** · **741741** · **911**") | |