KASOTI / app.py
iisadia's picture
Update app.py
1194971 verified
raw
history blame
14.8 kB
import streamlit as st
import time
import requests
from streamlit.components.v1 import html
import os
# Custom CSS for professional look (fixed text color)
def inject_custom_css():
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
* {
font-family: 'Poppins', sans-serif;
}
.title {
font-size: 3rem !important;
font-weight: 700 !important;
color: #6C63FF !important;
text-align: center;
margin-bottom: 0.5rem;
}
.subtitle {
font-size: 1.2rem !important;
text-align: center;
color: #666 !important;
margin-bottom: 2rem;
}
.question-box {
background: #F8F9FA;
border-radius: 15px;
padding: 2rem;
margin: 1.5rem 0;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
color: black !important;
}
.mic-button {
margin-left: 10px;
padding: 5px 10px !important;
border-radius: 5px;
background: #6C63FF !important;
color: white !important;
border: none;
cursor: pointer;
}
.language-selector {
position: absolute;
top: 10px;
right: 10px;
z-index: 1000;
}
</style>
""", unsafe_allow_html=True)
# Speech-to-text component
def speech_to_text(language, key):
component = f"""
<script>
function startRecording{key}() {{
const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
recognition.lang = '{language}';
recognition.interimResults = false;
recognition.maxAlternatives = 1;
recognition.start();
recognition.onresult = function(event) {{
const transcript = event.results[0][0].transcript;
window.location.href = window.location.origin + window.location.pathname + '?speech_input=' +
encodeURIComponent(transcript) + '&speech_key={key}';
}};
recognition.onerror = function(event) {{
console.error('Speech recognition error:', event.error);
}};
}}
</script>
<button class="mic-button" onclick="startRecording{key}()">
🎤
</button>
"""
html(component, height=50)
# Handle speech input
def handle_speech_input():
params = st.query_params
if 'speech_input' in params and 'speech_key' in params:
speech_input = params['speech_input']
speech_key = params['speech_key']
st.session_state[speech_key] = speech_input
st.query_params.clear()
st.experimental_rerun()
# Import transformers and cache the help agent for performance
@st.cache_resource
def get_help_agent():
from transformers import pipeline
return pipeline("conversational", model="facebook/blenderbot-400M-distill")
# Enhanced AI question generation
def ask_llama(conversation_history, category, is_final_guess=False):
api_url = "https://api.groq.com/openai/v1/chat/completions"
headers = {
"Authorization": "Bearer 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",
"Content-Type": "application/json"
}
system_prompt = f"""You're playing 20 questions to guess a {category}. Follow these rules:
1. Ask strategic, non-repeating yes/no questions that narrow down possibilities
2. Consider all previous answers carefully before asking next question
3. If you're very confident (80%+ sure), respond with "Final Guess: [your guess]"
4. For places: ask about continent, climate, famous landmarks, country, city or population
5. For people: ask about fictional or real, profession, gender, alive/dead, nationality, or fame
6. For objects: ask about size, color, usage, material, or where it's found
7. Never repeat questions and always make progress toward guessing"""
messages = [
{"role": "system", "content": system_prompt},
*conversation_history
]
data = {
"model": "llama-3.3-70b-versatile",
"messages": messages,
"temperature": 0.7 if is_final_guess else 0.8,
"max_tokens": 100
}
try:
response = requests.post(api_url, headers=headers, json=data)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
except Exception as e:
st.error(f"Error calling Llama API: {str(e)}")
return "Could not generate question"
# Main game logic
def main():
inject_custom_css()
handle_speech_input()
# Language selector
lang_options = {"English": "en-US", "Urdu": "ur-PK"}
with st.container():
st.markdown('<div class="language-selector">', unsafe_allow_html=True)
selected_lang = st.selectbox("Voice Language", options=list(lang_options.keys()), label_visibility="collapsed")
st.markdown('</div>', unsafe_allow_html=True)
selected_lang_code = lang_options[selected_lang]
st.markdown('<div class="title">KASOTI</div>', unsafe_allow_html=True)
st.markdown('<div class="subtitle">The Smart Guessing Game</div>', unsafe_allow_html=True)
if 'game_state' not in st.session_state:
st.session_state.game_state = "start"
st.session_state.questions = []
st.session_state.current_q = 0
st.session_state.answers = []
st.session_state.conversation_history = []
st.session_state.category = None
st.session_state.final_guess = None
st.session_state.help_conversation = []
# Start screen
if st.session_state.game_state == "start":
st.markdown("""
<div class="question-box">
<h3>Welcome to <span style='color:#6C63FF;'>KASOTI 🎯</span></h3>
<p>Think of something and I'll try to guess it in 20 questions or less!</p>
<p>Choose a category:</p>
<ul>
<li><strong>Person</strong> - celebrity, fictional character, historical figure</li>
<li><strong>Place</strong> - city, country, landmark, geographical location</li>
<li><strong>Object</strong> - everyday item, tool, vehicle, etc.</li>
</ul>
<p>Type or speak your category below to begin:</p>
</div>
""", unsafe_allow_html=True)
with st.form("start_form"):
col1, col2 = st.columns([4, 1])
with col1:
category_input = st.text_input("Enter category (person/place/object):",
key="category_input").strip().lower()
with col2:
st.write("")
st.write("")
speech_to_text(language=selected_lang_code, key="category_input")
if st.form_submit_button("Start Game"):
urdu_to_english = {
'شخص': 'person',
'جگہ': 'place',
'چیز': 'object'
}
category = urdu_to_english.get(category_input, category_input)
if not category:
st.error("Please enter a category!")
elif category not in ["person", "place", "object"]:
st.error("Please enter either 'person', 'place', or 'object'!")
else:
st.session_state.category = category
first_question = ask_llama([
{"role": "user", "content": "Ask your first strategic yes/no question."}
], category)
st.session_state.questions = [first_question]
st.session_state.conversation_history = [
{"role": "assistant", "content": first_question}
]
st.session_state.game_state = "gameplay"
st.experimental_rerun()
# Gameplay screen
elif st.session_state.game_state == "gameplay":
current_question = st.session_state.questions[st.session_state.current_q]
if "Final Guess:" in current_question:
st.session_state.final_guess = current_question.split("Final Guess:")[1].strip()
st.session_state.game_state = "confirm_guess"
st.experimental_rerun()
st.markdown(f'<div class="question-box">Question {st.session_state.current_q + 1}/20:<br><br>'
f'<strong>{current_question}</strong></div>',
unsafe_allow_html=True)
with st.form("answer_form"):
col1, col2 = st.columns([4, 1])
with col1:
answer_input = st.text_input("Your answer (yes/no/both):",
key=f"answer_{st.session_state.current_q}").strip().lower()
with col2:
st.write("")
st.write("")
speech_to_text(language=selected_lang_code, key=f"answer_{st.session_state.current_q}")
if st.form_submit_button("Submit"):
# Map Urdu responses to English
urdu_to_english = {
'ہاں': 'yes',
'نہیں': 'no',
'دونوں': 'both'
}
processed_answer = urdu_to_english.get(answer_input, answer_input)
if processed_answer not in ["yes", "no", "both"]:
st.error("Please answer with 'yes', 'no', or 'both'!")
else:
st.session_state.answers.append(processed_answer)
st.session_state.conversation_history.append(
{"role": "user", "content": processed_answer}
)
# Generate next response
next_response = ask_llama(
st.session_state.conversation_history,
st.session_state.category
)
if "Final Guess:" in next_response:
st.session_state.final_guess = next_response.split("Final Guess:")[1].strip()
st.session_state.game_state = "confirm_guess"
else:
st.session_state.questions.append(next_response)
st.session_state.conversation_history.append(
{"role": "assistant", "content": next_response}
)
st.session_state.current_q += 1
if st.session_state.current_q >= 20:
st.session_state.game_state = "result"
st.experimental_rerun()
# Guess confirmation screen
elif st.session_state.game_state == "confirm_guess":
st.markdown(f'<div class="question-box">🤖 My Final Guess:<br><br>'
f'<strong>Is it {st.session_state.final_guess}?</strong></div>',
unsafe_allow_html=True)
with st.form("confirm_form"):
col1, col2 = st.columns([4, 1])
with col1:
confirm_input = st.text_input("Type your answer (yes/no/both):", key="confirm_input").strip().lower()
with col2:
st.write("")
st.write("")
speech_to_text(language=selected_lang_code, key="confirm_input")
if st.form_submit_button("Submit"):
urdu_to_english = {
'ہاں': 'yes',
'نہیں': 'no',
'دونوں': 'both'
}
processed_confirm = urdu_to_english.get(confirm_input, confirm_input)
if processed_confirm not in ["yes", "no", "both"]:
st.error("Please answer with 'yes', 'no', or 'both'!")
else:
if processed_confirm == "yes":
st.session_state.game_state = "result"
st.experimental_rerun()
else:
st.session_state.conversation_history.append(
{"role": "user", "content": "no"}
)
st.session_state.game_state = "gameplay"
next_response = ask_llama(
st.session_state.conversation_history,
st.session_state.category
)
st.session_state.questions.append(next_response)
st.session_state.conversation_history.append(
{"role": "assistant", "content": next_response}
)
st.session_state.current_q += 1
st.experimental_rerun()
# Result screen
elif st.session_state.game_state == "result":
if not st.session_state.final_guess:
qa_history = "\n".join(
[f"Q{i+1}: {q}\nA: {a}"
for i, (q, a) in enumerate(zip(st.session_state.questions, st.session_state.answers))]
)
final_guess = ask_llama(
[{"role": "user", "content": qa_history}],
st.session_state.category,
is_final_guess=True
)
st.session_state.final_guess = final_guess.split("Final Guess:")[-1].strip()
html("""
<canvas id="confetti-canvas"></canvas>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
<script>
const canvas = document.getElementById('confetti-canvas');
const confetti = confetti.create(canvas, { resize: true });
confetti({
particleCount: 150,
spread: 70,
origin: { y: 0.6 }
});
setTimeout(() => { canvas.remove(); }, 5000);
</script>
""")
st.markdown(f'<div class="final-reveal">🎉 It\'s...</div>', unsafe_allow_html=True)
time.sleep(1)
st.markdown(f'<div class="final-reveal" style="font-size:3.5rem;color:#6C63FF;">{st.session_state.final_guess}</div>',
unsafe_allow_html=True)
st.markdown(f"<p style='text-align:center'>Guessed in {len(st.session_state.questions)} questions</p>",
unsafe_allow_html=True)
if st.button("Play Again", key="play_again"):
st.session_state.clear()
st.experimental_rerun()
if __name__ == "__main__":
main()