|
|
import streamlit as st |
|
|
import speech_recognition as sr |
|
|
import tempfile |
|
|
import scipy.io.wavfile |
|
|
import os |
|
|
import requests |
|
|
import numpy as np |
|
|
|
|
|
|
|
|
os.environ["MISTRAL_API_KEY"] = "your-mistral-key" |
|
|
os.environ["GROQ_API_KEY"] = "your-groq-key" |
|
|
|
|
|
|
|
|
if "state" not in st.session_state: |
|
|
st.session_state.state = { |
|
|
"active": False, |
|
|
"questions_asked": 0, |
|
|
"answers": [], |
|
|
"current_question": None, |
|
|
"consult_mode": False |
|
|
} |
|
|
|
|
|
|
|
|
def transcribe_audio(uploaded_file, language): |
|
|
if uploaded_file is None: |
|
|
return "" |
|
|
try: |
|
|
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file: |
|
|
tmp_file.write(uploaded_file.read()) |
|
|
tmp_file_path = tmp_file.name |
|
|
|
|
|
recognizer = sr.Recognizer() |
|
|
with sr.AudioFile(tmp_file_path) as source: |
|
|
audio = recognizer.record(source) |
|
|
lang_code = "en-US" if language == "English" else "ur-PK" |
|
|
return recognizer.recognize_google(audio, language=lang_code).lower() |
|
|
except Exception as e: |
|
|
return f"Transcription error: {e}" |
|
|
|
|
|
def query_llm(api, messages, model=None): |
|
|
headers = { |
|
|
"Authorization": f"Bearer {os.environ[f'{api}_API_KEY']}", |
|
|
"Content-Type": "application/json" |
|
|
} |
|
|
payload = { |
|
|
"messages": messages, |
|
|
"model": model or ("llama3-70b-8192" if api == "GROQ" else "mistral-medium") |
|
|
} |
|
|
url = "https://api.groq.com/openai/v1/chat/completions" if api == "GROQ" else "https://api.mistral.ai/v1/chat/completions" |
|
|
response = requests.post(url, headers=headers, json=payload) |
|
|
if response.ok: |
|
|
return response.json()["choices"][0]["message"]["content"] |
|
|
return "API Error" |
|
|
|
|
|
def normalize_answer(ans): |
|
|
ans = ans.strip().lower() |
|
|
return "yes" if ans in ["yes", "y", "ہاں", "haan"] else "no" if ans in ["no", "n", "نہیں", "nahi"] else None |
|
|
|
|
|
def generate_question(answers): |
|
|
prompt = "You are playing Kasoti. Ask the next best yes/no question.\n\n" |
|
|
for i, (q, a) in enumerate(answers, 1): |
|
|
prompt += f"{i}. Q: {q}\n A: {a}\n" |
|
|
return query_llm("GROQ", [{"role": "user", "content": prompt}]) |
|
|
|
|
|
def make_guess(answers): |
|
|
prompt = "Based on this history, make a best guess:\n\n" |
|
|
for i, (q, a) in enumerate(answers, 1): |
|
|
prompt += f"{i}. Q: {q}\n A: {a}\n" |
|
|
return query_llm("GROQ", [{"role": "user", "content": prompt}]) |
|
|
|
|
|
def get_hint(question, answers): |
|
|
prompt = f"The player is unsure about: {question}\n\nHistory:\n" |
|
|
for q, a in answers: |
|
|
prompt += f"- Q: {q}\n A: {a}\n" |
|
|
return query_llm("MISTRAL", [{"role": "user", "content": prompt}]) |
|
|
|
|
|
|
|
|
st.set_page_config(page_title="🎮 Kasoti 20Q", layout="centered") |
|
|
|
|
|
st.title("🎮 Kasoti - 20 Questions Game") |
|
|
st.info("Think of a famous person, place, or object. Answer with **yes/no** or **ہاں/نہیں** only.") |
|
|
|
|
|
if st.button("🔄 Start Game"): |
|
|
st.session_state.state.update({ |
|
|
"active": True, |
|
|
"questions_asked": 1, |
|
|
"answers": [], |
|
|
"current_question": "Is it a living thing?", |
|
|
"consult_mode": False |
|
|
}) |
|
|
|
|
|
if st.session_state.state["active"]: |
|
|
st.success(f"🤔 Question {st.session_state.state['questions_asked']}: {st.session_state.state['current_question']}") |
|
|
|
|
|
with st.form(key="answer_form"): |
|
|
audio_file = st.file_uploader("🎙️ Upload your answer (WAV only)", type=["wav"]) |
|
|
language = st.selectbox("🗣️ Language", ["English", "Urdu"]) |
|
|
manual_input = st.text_input("💬 Or type your answer:") |
|
|
submit = st.form_submit_button("➡️ Submit") |
|
|
|
|
|
if submit: |
|
|
answer = manual_input or transcribe_audio(audio_file, language) |
|
|
normalized = normalize_answer(answer) |
|
|
if not normalized: |
|
|
st.warning("⚠️ Please reply with 'yes' or 'no' (or 'ہاں/نہیں').") |
|
|
else: |
|
|
question = st.session_state.state["current_question"] |
|
|
st.session_state.state["answers"].append((question, normalized)) |
|
|
|
|
|
if "is this correct?" in question.lower(): |
|
|
if normalized == "yes": |
|
|
st.balloons() |
|
|
st.success("🎉 I guessed it right!") |
|
|
st.session_state.state["active"] = False |
|
|
else: |
|
|
next_q = generate_question(st.session_state.state["answers"]) |
|
|
st.session_state.state["current_question"] = next_q |
|
|
st.session_state.state["questions_asked"] += 1 |
|
|
elif st.session_state.state["questions_asked"] >= 20: |
|
|
st.session_state.state["active"] = False |
|
|
guess = make_guess(st.session_state.state["answers"]) |
|
|
st.error(f"❌ Game over! Final guess: {guess}") |
|
|
elif st.session_state.state["questions_asked"] % 5 == 0: |
|
|
guess = make_guess(st.session_state.state["answers"]) |
|
|
st.session_state.state["current_question"] = guess + " Is this correct?" |
|
|
st.session_state.state["questions_asked"] += 1 |
|
|
else: |
|
|
next_q = generate_question(st.session_state.state["answers"]) |
|
|
st.session_state.state["current_question"] = next_q |
|
|
st.session_state.state["questions_asked"] += 1 |
|
|
|
|
|
if st.session_state.state["active"]: |
|
|
if st.toggle("💡 Enable Consult Mode"): |
|
|
hint = get_hint(st.session_state.state["current_question"], st.session_state.state["answers"]) |
|
|
st.info(f"💭 Hint: {hint}") |
|
|
|