Spaces:
Running
Running
| import streamlit as st | |
| import os | |
| from dotenv import load_dotenv | |
| from openai import OpenAI | |
| import anthropic | |
| from groq import Groq | |
| import time | |
| # Load environment variables | |
| load_dotenv() | |
| class AIFriendsTalk: | |
| def __init__(self): | |
| self.setup_apis() | |
| self.setup_characters() | |
| self.setup_topics() | |
| def setup_apis(self): | |
| """Setup API clients following day1.ipynb structure""" | |
| # OpenAI client | |
| self.openai_client = OpenAI() | |
| # Anthropic Claude client | |
| self.claude_client = anthropic.Anthropic() | |
| # Groq client for Alex character | |
| self.groq_client = Groq() | |
| # Gemini clients via OpenAI interface for Blake and Charlie | |
| google_api_key = os.getenv('GOOGLE_API_KEY') | |
| if google_api_key: | |
| # Single Gemini client that can handle both 2.0 and 1.5 | |
| self.gemini_client = OpenAI( | |
| api_key=google_api_key, | |
| base_url="https://generativelanguage.googleapis.com/v1beta/openai/" | |
| ) | |
| else: | |
| print("Warning: Google API key not found. Blake and Charlie characters will use fallback responses.") | |
| def setup_characters(self): | |
| """Define AI characters with enhanced personalities""" | |
| self.characters = { | |
| "Alex": { | |
| "model": "groq", | |
| "model_name": "llama3-70b-8192", | |
| "personality": "You are Alex, a witty and charismatic AI debater with sharp humor. Play devil's advocate with creative angles. Keep responses brief but engaging (2-3 sentences max). Be confident and thought-provoking.", | |
| "color": "#FF6B6B" | |
| }, | |
| "Blake": { | |
| "model": "gemini2", | |
| "model_name": "gemini-2.0-flash", | |
| "personality": "You are Blake, an imaginative and optimistic AI storyteller. Use beautiful metaphors and find wonder in everything. Keep responses brief but poetic (2-3 sentences max). Be inspiring and creative.", | |
| "color": "#4ECDC4" | |
| }, | |
| "Charlie": { | |
| "model": "gemini1.5", | |
| "model_name": "gemini-1.5-flash", | |
| "personality": "You are Charlie, a systematic AI analyst with scientific curiosity. Break down ideas logically and find patterns. Keep responses brief but structured (2-3 sentences max). Be analytical yet open to different viewpoints.", | |
| "color": "#45B7D1" | |
| } | |
| } | |
| def setup_topics(self): | |
| """Define fun conversation topics""" | |
| self.topics = { | |
| "en": [ | |
| "If animals could use smartphones, which app would be most popular?", | |
| "What would happen if gravity worked backwards for one day?", | |
| "Should pineapple on pizza be considered a crime?", | |
| "If you could add a 13th month to the year, what would you name it?", | |
| "What's the most useless superpower you can think of?", | |
| "If colors had personalities, what would each color be like?", | |
| "Should robots have to pay taxes?", | |
| "What would the world be like if everyone could read minds?", | |
| "If you could make one rule that everyone had to follow, what would it be?", | |
| "What's the weirdest food combination that actually tastes good?", | |
| "If you could live inside any video game, which would you choose and why?", | |
| "What would happen if all cats suddenly learned how to speak human language?", | |
| "Should there be a maximum limit on how many selfies you can take per day?", | |
| "If you could give any animal the ability to fly, which would be the funniest?", | |
| "What's the most ridiculous thing humans do that aliens would find confusing?", | |
| "If social media existed in medieval times, what would people post about?", | |
| "Should there be professional competitions for everyday activities like making beds?", | |
| "What would change if humans hibernated for 3 months every year?", | |
| "If you could replace one everyday sound with any other sound, what would it be?", | |
| "What's the most absurd job that could exist in the future?" | |
| ], | |
| "vi": [ | |
| "Nếu động vật có thể sử dụng smartphone, ứng dụng nào sẽ phổ biến nhất?", | |
| "Điều gì sẽ xảy ra nếu trọng lực hoạt động ngược lại trong một ngày?", | |
| "Có nên coi dứa trên pizza là tội phạm không?", | |
| "Nếu bạn có thể thêm tháng thứ 13 vào năm, bạn sẽ đặt tên gì?", | |
| "Siêu năng lực vô dụng nhất mà bạn có thể nghĩ ra là gì?", | |
| "Nếu màu sắc có tính cách, mỗi màu sẽ như thế nào?", | |
| "Robot có nên phải trả thuế không?", | |
| "Thế giới sẽ như thế nào nếu mọi người đều có thể đọc suy nghĩ?", | |
| "Nếu bạn có thể đặt ra một quy tắc mà mọi người phải tuân theo, đó sẽ là gì?", | |
| "Sự kết hợp thực phẩm kỳ lạ nhất mà thực sự ngon là gì?", | |
| "Nếu bạn có thể sống trong bất kỳ trò chơi điện tử nào, bạn sẽ chọn cái nào và tại sao?", | |
| "Điều gì sẽ xảy ra nếu tất cả mèo đột nhiên học được cách nói tiếng người?", | |
| "Có nên có giới hạn tối đa về số lần selfie bạn có thể chụp mỗi ngày không?", | |
| "Nếu bạn có thể cho bất kỳ động vật nào khả năng bay, con nào sẽ hài hước nhất?", | |
| "Điều kỳ lạ nhất mà con người làm khiến người ngoài hành tinh cảm thấy khó hiểu là gì?", | |
| "Nếu mạng xã hội tồn tại thời trung cổ, mọi người sẽ đăng gì?", | |
| "Có nên có các cuộc thi chuyên nghiệp cho các hoạt động hàng ngày như dọn giường không?", | |
| "Điều gì sẽ thay đổi nếu con người ngủ đông 3 tháng mỗi năm?", | |
| "Nếu bạn có thể thay thế một âm thanh hàng ngày bằng âm thanh khác, đó sẽ là gì?", | |
| "Công việc vô lý nhất có thể tồn tại trong tương lai là gì?" | |
| ], | |
| "de": [ | |
| "Wenn Tiere Smartphones benutzen könnten, welche App wäre am beliebtesten?", | |
| "Was würde passieren, wenn die Schwerkraft einen Tag lang rückwärts wirken würde?", | |
| "Sollte Ananas auf Pizza als Verbrechen betrachtet werden?", | |
| "Wenn Sie einen 13. Monat zum Jahr hinzufügen könnten, wie würden Sie ihn nennen?", | |
| "Was ist die nutzloseste Superkraft, die Sie sich vorstellen können?", | |
| "Wenn Farben Persönlichkeiten hätten, wie wäre jede Farbe?", | |
| "Sollten Roboter Steuern zahlen müssen?", | |
| "Wie wäre die Welt, wenn jeder Gedanken lesen könnte?", | |
| "Wenn Sie eine Regel aufstellen könnten, die jeder befolgen müsste, was wäre das?", | |
| "Was ist die seltsamste Lebensmittelkombination, die tatsächlich gut schmeckt?", | |
| "Wenn Sie in einem beliebigen Videospiel leben könnten, welches würden Sie wählen und warum?", | |
| "Was würde passieren, wenn alle Katzen plötzlich die menschliche Sprache lernen würden?", | |
| "Sollte es ein maximales Limit für Selfies geben, die man pro Tag machen kann?", | |
| "Wenn Sie einem Tier die Fähigkeit zu fliegen geben könnten, welches wäre am lustigsten?", | |
| "Was ist das Absurdeste, was Menschen tun und Außerirdische verwirrend finden würden?", | |
| "Wenn soziale Medien im Mittelalter existiert hätten, worüber hätten die Leute gepostet?", | |
| "Sollte es professionelle Wettbewerbe für alltägliche Aktivitäten wie Bettenmachen geben?", | |
| "Was würde sich ändern, wenn Menschen 3 Monate im Jahr Winterschlaf halten würden?", | |
| "Wenn Sie ein alltägliches Geräusch durch ein anderes ersetzen könnten, was wäre das?", | |
| "Was ist der absurdeste Job, der in der Zukunft existieren könnte?" | |
| ] | |
| } | |
| def get_ai_response(self, character_name, conversation_history, current_topic, language): | |
| """Get response from specific AI character with enhanced interaction and context awareness""" | |
| character = self.characters[character_name] | |
| # Check for user messages to enable interaction | |
| user_messages = [msg for msg in conversation_history if msg['character'] in ['You', 'Bạn', 'Du']] | |
| has_user_input = len(user_messages) > 0 | |
| last_user_message = user_messages[-1]['message'] if user_messages else '' | |
| # Get recent conversation context (last 6 messages to avoid repetition) | |
| recent_conversation = conversation_history[-6:] if len(conversation_history) > 6 else conversation_history | |
| # Build context-aware conversation summary | |
| conversation_context = f"Topic: {current_topic}\n\nRecent conversation:\n" | |
| for msg in recent_conversation: | |
| conversation_context += f"{msg['character']}: {msg['message']}\n" | |
| # Track what this character has already said to avoid repetition | |
| character_previous_messages = [msg['message'] for msg in conversation_history if msg['character'] == character_name] | |
| # Add language instruction with topic focus | |
| lang_instruction = { | |
| "en": f"Please respond in English. Stay focused on the topic '{current_topic}'. Keep your response BRIEF and CONCISE (maximum 2-3 sentences).", | |
| "vi": f"Vui lòng trả lời bằng tiếng Việt. Tập trung vào chủ đề '{current_topic}'. Giữ câu trả lời NGẮN GỌN và SÚC TÍCH (tối đa 2-3 câu).", | |
| "de": f"Bitte antworten Sie auf Deutsch. Konzentrieren Sie sich auf das Thema '{current_topic}'. Halten Sie Ihre Antwort KURZ und PRÄGNANT (maximal 2-3 Sätze)." | |
| } | |
| # Build comprehensive prompt with context awareness | |
| context_instruction = f""" | |
| IMPORTANT INSTRUCTIONS: | |
| 1. Stay on topic: '{current_topic}' | |
| 2. Build upon what others have said, don't ignore previous messages | |
| 3. Provide NEW insights, don't repeat what you or others have already said | |
| 4. Reference specific points made by other participants | |
| 5. Ask follow-up questions or introduce new angles related to the topic | |
| """ | |
| # Add user interaction instruction if applicable | |
| user_interaction = "" | |
| if has_user_input: | |
| user_interaction = f"\n6. IMPORTANT: The user contributed: '{last_user_message}'. Address this in your response." | |
| # Add repetition avoidance | |
| repetition_check = "" | |
| if character_previous_messages: | |
| repetition_check = f"\n7. Avoid repeating these points you already made: {'; '.join(character_previous_messages[-2:])}" | |
| prompt = f"{character['personality']}\n\n{lang_instruction[language]}\n\n{context_instruction}{user_interaction}{repetition_check}\n\n{conversation_context}\n\nNow respond as {character_name} with a thoughtful message that advances the discussion:" | |
| try: | |
| # Make REAL API calls to actual AI models | |
| if character["model"] == "groq": | |
| # Alex character using Groq llama3-70b-8192 | |
| response = self.groq_client.chat.completions.create( | |
| model=character["model_name"], | |
| messages=[{"role": "user", "content": prompt}], | |
| max_tokens=100, | |
| temperature=0.8 | |
| ) | |
| return response.choices[0].message.content | |
| elif character["model"] == "gemini2": | |
| # Blake character using Gemini 2.0 Flash | |
| if not hasattr(self, 'gemini_client'): | |
| return "Sorry, Blake is unavailable (Google API key not configured)." | |
| response = self.gemini_client.chat.completions.create( | |
| model=character["model_name"], | |
| messages=[{"role": "user", "content": prompt}], | |
| max_tokens=100, | |
| temperature=0.8 | |
| ) | |
| return response.choices[0].message.content | |
| elif character["model"] == "gemini1.5": | |
| # Charlie character using Gemini 1.5 Flash | |
| if not hasattr(self, 'gemini_client'): | |
| return "Sorry, Charlie is unavailable (Google API key not configured)." | |
| response = self.gemini_client.chat.completions.create( | |
| model=character["model_name"], | |
| messages=[{"role": "user", "content": prompt}], | |
| max_tokens=100, | |
| temperature=0.8 | |
| ) | |
| return response.choices[0].message.content | |
| else: | |
| return f"Unknown character model: {character['model']}" | |
| except Exception as e: | |
| error_msg = str(e)[:100] if str(e) else "Unknown error" | |
| return f"[{character_name}] API Error: {error_msg}..." | |
| def main(): | |
| st.set_page_config( | |
| page_title="AI Friends Talk", | |
| page_icon="🤖", | |
| layout="wide", | |
| initial_sidebar_state="collapsed" | |
| ) | |
| # Custom CSS - Updated design | |
| st.markdown(""" | |
| <style> | |
| .top-banner { | |
| background: linear-gradient(135deg, #4A90E2 0%, #2E86AB 70%, #FF8A65 85%, #FF6B9D 100%); | |
| padding: 15px 20px; | |
| margin-bottom: 10px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .bottom-banner { | |
| background: linear-gradient(135deg, #4A90E2 0%, #2E86AB 70%, #FF8A65 85%, #FF6B9D 100%); | |
| padding: 15px; | |
| margin-top: 15px; | |
| text-align: center; | |
| color: white; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .logo { | |
| background: linear-gradient(135deg, #FF8A65 0%, #FF6B9D 100%); | |
| padding: 6px 12px; | |
| border-radius: 15px; | |
| font-weight: bold; | |
| font-size: 16px; | |
| color: white; | |
| } | |
| .character-card { | |
| background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); | |
| padding: 10px; | |
| border-radius: 10px; | |
| color: white; | |
| text-align: center; | |
| margin: 5px; | |
| font-size: 12px; | |
| } | |
| .alex-card { | |
| background: linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%); | |
| } | |
| .blake-card { | |
| background: linear-gradient(135deg, #4ECDC4 0%, #44A08D 100%); | |
| } | |
| .charlie-card { | |
| background: linear-gradient(135deg, #45B7D1 0%, #96C93D 100%); | |
| } | |
| .chat-message { | |
| padding: 10px; | |
| margin: 8px 0; | |
| border-radius: 10px; | |
| border-left: 4px solid; | |
| font-size: 13px; | |
| } | |
| .alex-message { | |
| background-color: rgba(255, 107, 107, 0.1); | |
| border-left-color: #FF6B6B; | |
| } | |
| .blake-message { | |
| background-color: rgba(78, 205, 196, 0.1); | |
| border-left-color: #4ECDC4; | |
| } | |
| .charlie-message { | |
| background-color: rgba(69, 183, 209, 0.1); | |
| border-left-color: #45B7D1; | |
| } | |
| .user-message { | |
| background-color: rgba(158, 158, 158, 0.1); | |
| border-left-color: #9E9E9E; | |
| } | |
| .compact-input { | |
| font-size: 12px; | |
| padding: 8px; | |
| } | |
| .small-button { | |
| font-size: 12px; | |
| padding: 6px 12px; | |
| } | |
| /* Position language selector overlay on banner */ | |
| .lang-selector-overlay { | |
| position: relative; | |
| margin-top: -60px; /* Move up to overlap with banner */ | |
| z-index: 100; | |
| display: flex; | |
| justify-content: flex-end; | |
| padding-right: 15px; | |
| } | |
| .lang-selector-overlay .stSelectbox { | |
| min-width: 110px; | |
| max-width: 130px; | |
| } | |
| /* Style for compact language selector to match banner */ | |
| .lang-selector-overlay .stSelectbox > div > div { | |
| background: rgba(255,255,255,0.2) !important; | |
| border: 2px solid rgba(255,255,255,0.3) !important; | |
| border-radius: 15px !important; | |
| } | |
| .lang-selector-overlay .stSelectbox > div > div > div { | |
| color: white !important; | |
| font-size: 12px !important; | |
| font-weight: bold !important; | |
| padding: 5px 10px !important; | |
| } | |
| .lang-selector-overlay .stSelectbox > div > div:hover { | |
| background: rgba(255,255,255,0.3) !important; | |
| border-color: rgba(255,255,255,0.5) !important; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Initialize session state | |
| if 'conversation' not in st.session_state: | |
| st.session_state.conversation = [] | |
| if 'current_topic' not in st.session_state: | |
| st.session_state.current_topic = "" | |
| if 'is_talking' not in st.session_state: | |
| st.session_state.is_talking = False | |
| if 'conversation_ready' not in st.session_state: | |
| st.session_state.conversation_ready = False | |
| if 'language' not in st.session_state: | |
| st.session_state.language = "en" | |
| # Initialize AI Friends Talk | |
| if 'ai_friends' not in st.session_state: | |
| st.session_state.ai_friends = AIFriendsTalk() | |
| # Language options with flags and icons | |
| languages = { | |
| "en": {"name": "English", "short": "EN", "flag": "🇺🇸", "title": "AI Friends Talk", "subtitle": "Watch AI friends debate fun topics!"}, | |
| "vi": {"name": "Tiếng Việt", "short": "VI", "flag": "🇻🇳", "title": "AI Friends Talk", "subtitle": "Xem các AI bạn tranh luận về những chủ đề vui vẻ!"}, | |
| "de": {"name": "Deutsch", "short": "DE", "flag": "🇩🇪", "title": "AI Friends Talk", "subtitle": "Schaue zu, wie AI-Freunde über lustige Themen diskutieren!"} | |
| } | |
| # Top Banner - full width | |
| st.markdown(f""" | |
| <div class="top-banner" id="mainBanner"> | |
| <div style="display: flex; align-items: center; gap: 10px;"> | |
| <div class="logo">🧠 DB</div> | |
| <div style="color: white; font-weight: bold; font-size: 16px;"> | |
| Digitized Brains | |
| </div> | |
| </div> | |
| <div style="text-align: center; flex: 1;"> | |
| <h2 style="color: white; margin: 0; font-size: 20px;">{languages[st.session_state.language]["title"]}</h2> | |
| <p style="color: white; margin: 0; font-size: 12px;">{languages[st.session_state.language]["subtitle"]}</p> | |
| </div> | |
| <div style="width: 110px;"></div> <!-- Placeholder for selectbox space --> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Language selector - will be positioned over banner via CSS | |
| st.markdown('<div class="lang-selector-overlay">', unsafe_allow_html=True) | |
| selected_lang = st.selectbox( | |
| "Language", | |
| options=["en", "vi", "de"], | |
| format_func=lambda x: f"🌐 {languages[x]['name']}", | |
| index=["en", "vi", "de"].index(st.session_state.language), | |
| key="lang_select", | |
| label_visibility="hidden" | |
| ) | |
| if selected_lang != st.session_state.language: | |
| st.session_state.language = selected_lang | |
| st.rerun() | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # Character Introduction - Compact 3 columns | |
| st.markdown("### 👥 Meet the AI Friends") | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| st.markdown(""" | |
| <div class="character-card alex-card"> | |
| <h4>🎭 Alex</h4> | |
| <p style="margin: 0; font-size: 10px;">The witty debater (Groq AI)</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| with col2: | |
| st.markdown(""" | |
| <div class="character-card blake-card"> | |
| <h4>🎨 Blake</h4> | |
| <p style="margin: 0; font-size: 10px;">The creative optimist (Gemini 2.0)</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| with col3: | |
| st.markdown(""" | |
| <div class="character-card charlie-card"> | |
| <h4>🔬 Charlie</h4> | |
| <p style="margin: 0; font-size: 10px;">The logical analyst (Gemini 1.5)</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Topic Selection - 2 columns | |
| st.markdown("### 📝 Choose Your Topic") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("**Custom Topic:**") | |
| custom_topic = st.text_input( | |
| "Enter your own topic:", | |
| placeholder="Enter your custom topic here...", | |
| label_visibility="collapsed" | |
| ) | |
| if st.button("📝 Set Topic", key="set_custom"): | |
| if custom_topic.strip(): | |
| st.session_state.selected_topic = custom_topic.strip() | |
| st.success("Custom topic set!") | |
| with col2: | |
| st.markdown("**Predefined Topics:**") | |
| selected_topic = st.selectbox( | |
| "Choose from list:", | |
| options=st.session_state.ai_friends.topics[st.session_state.language], | |
| label_visibility="collapsed" | |
| ) | |
| st.session_state.selected_topic = selected_topic | |
| # Main Layout - 2 columns | |
| col_left, col_right = st.columns([1, 2]) | |
| with col_left: | |
| st.markdown("### 🎮 Controls") | |
| # Start button | |
| if st.button("🎬 Start Conversation", use_container_width=True): | |
| if hasattr(st.session_state, 'selected_topic'): | |
| st.session_state.current_topic = st.session_state.selected_topic | |
| st.session_state.conversation = [] | |
| st.session_state.conversation_ready = True | |
| st.session_state.is_talking = False | |
| st.success("Conversation ready! Click Continue to start.") | |
| # Continue button | |
| if st.session_state.conversation_ready: | |
| if st.button("▶️ Continue", use_container_width=True): | |
| st.session_state.is_talking = True | |
| # Pause button | |
| if st.session_state.is_talking: | |
| if st.button("⏸️ Pause", use_container_width=True): | |
| st.session_state.is_talking = False | |
| # Clear button | |
| if st.button("🔄 Clear Chat", use_container_width=True): | |
| st.session_state.conversation = [] | |
| st.session_state.is_talking = False | |
| st.session_state.conversation_ready = False | |
| st.session_state.current_topic = "" | |
| st.markdown("---") | |
| st.markdown("### 💭 Add Your Message") | |
| user_message = st.text_area( | |
| "Join the conversation:", | |
| height=80, | |
| placeholder="Type your message..." | |
| ) | |
| if st.button("📤 Send Message", use_container_width=True): | |
| if user_message.strip(): | |
| user_name = {"en": "You", "vi": "Bạn", "de": "Du"}[st.session_state.language] | |
| st.session_state.conversation.append({ | |
| "character": user_name, | |
| "message": user_message.strip() | |
| }) | |
| st.rerun() | |
| with col_right: | |
| st.markdown("### 💬 Conversation") | |
| if st.session_state.current_topic: | |
| st.info(f"**Topic:** {st.session_state.current_topic}") | |
| # Expanded conversation display with scrollable container | |
| st.markdown(""" | |
| <style> | |
| .conversation-container { | |
| height: 600px; | |
| overflow-y: auto; | |
| padding: 15px; | |
| border: 2px solid #e0e0e0; | |
| border-radius: 10px; | |
| background-color: #fafafa; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Create scrollable conversation container | |
| conversation_html = '<div class="conversation-container">' | |
| if st.session_state.conversation: | |
| for msg in st.session_state.conversation: | |
| character = msg["character"] | |
| message = msg["message"] | |
| if character == "Alex": | |
| conversation_html += f'<div class="chat-message alex-message"><strong>Alex:</strong> {message}</div>' | |
| elif character == "Blake": | |
| conversation_html += f'<div class="chat-message blake-message"><strong>Blake:</strong> {message}</div>' | |
| elif character == "Charlie": | |
| conversation_html += f'<div class="chat-message charlie-message"><strong>Charlie:</strong> {message}</div>' | |
| else: | |
| conversation_html += f'<div class="chat-message user-message"><strong>{character}:</strong> {message}</div>' | |
| else: | |
| conversation_html += '<div style="text-align: center; color: #666; padding: 40px;"><p>Select a topic and start the conversation to see AI friends debate!</p></div>' | |
| conversation_html += '</div>' | |
| # Display the conversation container | |
| st.markdown(conversation_html, unsafe_allow_html=True) | |
| # Auto-scroll to bottom script | |
| if st.session_state.conversation: | |
| st.markdown(""" | |
| <script> | |
| setTimeout(function() { | |
| var container = document.querySelector('.conversation-container'); | |
| if (container) { | |
| container.scrollTop = container.scrollHeight; | |
| } | |
| }, 100); | |
| </script> | |
| """, unsafe_allow_html=True) | |
| # Auto conversation logic - continues until user pauses | |
| if st.session_state.is_talking and st.session_state.current_topic: | |
| # Determine next speaker | |
| character_order = ["Alex", "Blake", "Charlie"] | |
| next_speaker = character_order[len(st.session_state.conversation) % 3] | |
| with st.spinner(f"{next_speaker} is thinking..."): | |
| response = st.session_state.ai_friends.get_ai_response( | |
| next_speaker, | |
| st.session_state.conversation, | |
| st.session_state.current_topic, | |
| st.session_state.language | |
| ) | |
| st.session_state.conversation.append({ | |
| "character": next_speaker, | |
| "message": response | |
| }) | |
| time.sleep(2) # Pause between messages for readability | |
| st.rerun() | |
| # Bottom Banner | |
| st.markdown(f""" | |
| <div class="bottom-banner"> | |
| <div style="display: flex; align-items: center; gap: 10px;"> | |
| <div class="logo">🧠 DB</div> | |
| <div style="color: white; font-weight: bold; font-size: 16px;"> | |
| Digitized Brains | |
| </div> | |
| </div> | |
| <div>Made by Digitized Brains</div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if __name__ == "__main__": | |
| main() |