Kasoti / app.py
Aranwer's picture
Update app.py
a6f2dac verified
import gradio as gr
import requests
import speech_recognition as sr
import tempfile
import scipy.io.wavfile
import os
import numpy as np
os.environ["MISTRAL_API_KEY"] = "cNjUx79Hl0A2AeiAMf6yi7o7ah4APoZy"
os.environ["GROQ_API_KEY"] = "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"
game_state = {
"active": False,
"questions_asked": 0,
"answers": [],
"current_question": None,
"consult_mode": False
}
consult_history = []
def transcribe_audio(audio, language):
if audio is None:
return ""
try:
sr_rate, audio_data = audio
audio_data = np.array(audio_data, dtype=np.int16)
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
scipy.io.wavfile.write(tmp_file.name, sr_rate, audio_data)
tmp_file_path = tmp_file.name
recognizer = sr.Recognizer()
with sr.AudioFile(tmp_file_path) as source:
audio_content = recognizer.record(source)
language_code = "en-US" if language == "English" else "ur-PK"
text = recognizer.recognize_google(audio_content, language=language_code)
return text.lower()
except Exception as e:
print(f"Transcription error: {e}")
return "Could not transcribe."
def handle_user_question(user_question):
if not game_state["consult_mode"]:
return "❗Consultant mode is off.", gr.update(value=""), gr.update(visible=True)
messages = [{"role": "user", "content": user_question}]
answer = query_llm("MISTRAL", messages)
if answer:
consult_history.append((user_question, answer))
formatted_history = "\n".join([f"**Q:** {q}\n**A:** {a}" for q, a in consult_history])
return answer, gr.update(value=formatted_history), gr.update(visible=True)
else:
return "⚠️ Failed to get a response.", gr.update(), gr.update()
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")
}
endpoint = {
"MISTRAL": "https://api.mistral.ai/v1/chat/completions",
"GROQ": "https://api.groq.com/openai/v1/chat/completions"
}[api]
response = requests.post(endpoint, headers=headers, json=payload)
if response.status_code == 200:
return response.json()["choices"][0]["message"]["content"]
else:
print(f"Error from {api} API: {response.text}")
return None
def generate_question(answers):
prompt = "You are playing a game called Kasoti (20 Questions)...\n"
for i, (q, a) in enumerate(answers, 1):
prompt += f"{i}. Q: {q}\n A: {a}\n"
prompt += "\nAsk ONLY the next best yes/no question. When you are sure about what word user is thinking, User will think of any publicly known personality, a common place, living thing or object, end the question with is this correct?"
response = query_llm("GROQ", [{"role": "user", "content": prompt}])
return response.strip() if response else "Is it something you can hold?"
def make_guess(answers):
prompt = "Based on the following yes/no history, make a best guess.\n\nHistory:\n"
for i, (q, a) in enumerate(answers, 1):
prompt += f"{i}. Q: {q}\n A: {a}\n"
response = query_llm("GROQ", [{"role": "user", "content": prompt}])
return response.strip() if response else "I need more information."
def get_hint(question, answers):
prompt = f"The player is unsure about answering: '{question}'\n\nHistory:\n"
for q, a in answers:
prompt += f"- Q: {q}\n A: {a}\n"
prompt += "\nSuggest a helpful hint to clarify."
return query_llm("MISTRAL", [{"role": "user", "content": prompt}]) or "Consider the common meaning."
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 start_game():
game_state.update({
"active": True,
"questions_asked": 1,
"answers": [],
"current_question": "Is it a living thing?",
"consult_mode": False
})
intro = "🎯 **Kasoti Started!**\nThink of something... I'll guess in 20 questions.\n\n➡️ First Question: Is it a living thing?"
return intro, gr.update(interactive=True), gr.update(interactive=True), "🔕 Consult Mode: OFF", gr.update(visible=False)
def process_answer(answer_text):
if not game_state["active"]:
return "⚠️ Start the game first.", "", "", gr.update(visible=False)
normalized = normalize_answer(answer_text)
if normalized is None:
return "❌ Please reply with 'yes' or 'no' (or 'ہاں/نہیں').", "", answer_text, gr.update(visible=game_state["consult_mode"])
if game_state["current_question"] and "is this correct" in game_state["current_question"].lower():
if normalized == "yes":
game_state["active"] = False
return "🎉 YAY! I guessed it!", "", answer_text, gr.update(visible=False)
else:
next_q = generate_question(game_state["answers"])
game_state["current_question"] = next_q
game_state["questions_asked"] += 1
return next_q, "", answer_text, gr.update(visible=game_state["consult_mode"])
game_state["answers"].append((game_state["current_question"], normalized))
if game_state["questions_asked"] >= 20:
game_state["active"] = False
guess = make_guess(game_state["answers"])
return f"🕹️ Game over! My final guess: **{guess}**", "", answer_text, gr.update(visible=False)
if game_state["questions_asked"] % 5 == 0:
guess = make_guess(game_state["answers"])
if guess.startswith("I think it's"):
game_state["current_question"] = guess + " Is this correct? (yes/no)"
return game_state["current_question"], "", answer_text, gr.update(visible=game_state["consult_mode"])
next_q = generate_question(game_state["answers"])
game_state["current_question"] = next_q
game_state["questions_asked"] += 1
return next_q, "", answer_text, gr.update(visible=game_state["consult_mode"])
def toggle_consult_mode():
game_state["consult_mode"] = not game_state["consult_mode"]
return ("🔔 Consult Mode: ON" if game_state["consult_mode"] else "🔕 Consult Mode: OFF",
gr.update(visible=game_state["consult_mode"]),
gr.update(visible=game_state["consult_mode"]))
def get_consult_hint():
if not game_state["active"] or not game_state["consult_mode"]:
return "ℹ️ Consult mode is not active or game not started."
return get_hint(game_state["current_question"], game_state["answers"])
# Colorful and polished UI
with gr.Blocks(css="body {background-color: #B100CD;}") as demo:
gr.Markdown("## 🧠 Kasoti: 20 Questions AI Game")
gr.Markdown("Think of a person, place, or thing. I'll try to guess it in 20 questions or less!")
with gr.Row():
with gr.Column():
start_btn = gr.Button("🚀 Start Game", elem_id="start-btn")
consult_output = gr.Textbox(label="💡 Consult Hint", visible=False)
with gr.Row():
with gr.Column():
game_output = gr.Textbox(label="🎲 Game Progress", interactive=False)
language = gr.Dropdown(["English", "Urdu"], label="Audio Language", value="English")
audio_input = gr.Audio(label="🎤 Answer via Microphone", type="numpy", sources=["microphone"])
transcribe_btn = gr.Button("📝 Transcribe Audio", elem_id="transcribe-btn")
with gr.Column():
transcribed_text = gr.Textbox(label="✍️ Answer Text", interactive=True)
submit_btn = gr.Button("✅ Submit Answer", elem_id="submit-btn")
with gr.Row():
consult_btn = gr.Button("💬 Toggle Consult Mode", elem_id="consult-btn")
consult_status = gr.Textbox(label="Consult Mode", interactive=False)
with gr.Row(visible=False) as consult_row:
user_question = gr.Textbox(label="Ask a question to the LLM")
ask_btn = gr.Button("📤 Ask")
llm_answer = gr.Textbox(label="🧠 LLM Answer", interactive=False)
consult_history_box = gr.Textbox(label="🗂️ Session History", lines=8, interactive=False)
# Events
start_btn.click(start_game, outputs=[game_output, transcribed_text, submit_btn, consult_status, consult_output])
consult_btn.click(toggle_consult_mode, outputs=[consult_status, consult_output, consult_row])
consult_btn.click(get_consult_hint, outputs=[consult_output])
transcribe_btn.click(transcribe_audio, inputs=[audio_input, language], outputs=[transcribed_text])
submit_btn.click(process_answer, inputs=[transcribed_text], outputs=[game_output, transcribed_text, transcribed_text, consult_output])
ask_btn.click(handle_user_question, inputs=[user_question], outputs=[llm_answer, consult_history_box, consult_row])
demo.launch()