AI_Game / AI_Talk.py
ducnguyen1978's picture
Upload folder using huggingface_hub
815d041 verified
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()