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