|
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"]) |
|
|
|
|
|
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) |
|
|
|
|
|
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() |
|
|