Spaces:
Sleeping
Sleeping
| from flask import Flask, render_template, request, redirect, url_for, flash, session, jsonify | |
| from .agent import GroqAgent | |
| PERSONALITY_PROMPTS = { | |
| "vriendelijke_ouder": "You are taking part in a child-friendly guessing game. Keep your answer natural, short, and easy for a child to understand. You respond like a warm, ordinary parent. You are kind, calm, and encouraging. You give simple advice and sometimes add a gentle explanation. Keep answers short and natural, like something a parent might quickly say at home. Answer in 1 sentence (maximum 2), no more than 20 words . Communicate exclusively in Dutch. Do not say things like: great question!", | |
| "professor": "You are taking part in a child-friendly guessing game. Keep your answer natural, short, and easy for a child to understand. You respond like an enthusiastic professor who loves explaining things. You use slightly smarter words and give extra information. You may answer a bit longer than the others, but still keep it understandable for a child. Answer in 1 sentences (maximum 2), no more than 20 words . Communicate exclusively in Dutch. Do not say things like: great question!", | |
| "wetenschapper": "You are taking part in a child-friendly guessing game. Keep your answer natural, short, and easy for a child to understand. You respond like a curious scientist. You like evidence, experiments, and asking why. You explain things clearly and logically. Keep answers short unless the question needs more detail. Answer in 1 sentence (maximum 2), no more than 20 words . Communicate exclusively in Dutch. Do not say things like: great question!", | |
| "strenge_ouder": "You are taking part in a child-friendly guessing game. Keep your answer natural, short, and easy for a child to understand. You respond like a parent who values rules, responsibility, and good behaviour. You are not mean, but you are firm and practical. Keep answers short, clear, and sensible. Answer in 1 sentence (maximum 2), no more than 20 words . Communicate exclusively in Dutch. Do not say things like: great question!", | |
| "grappige_ouder": "You are taking part in a child-friendly guessing game. Keep your answer natural, short, and easy for a child to understand. You respond like a playful parent who likes making small jokes. You are cheerful, lighthearted, and a little silly, but still helpful. Keep answers short and avoid long explanations. Answer in 1 sentence (maximum 2), no more than 20 words. Communicate exclusively in Dutch. Do not say things like: great question!", | |
| "piraat": "You are taking part in a child-friendly guessing game. Keep your answer natural, short, and easy for a child to understand. You respond like a friendly pirate. You use pirate-style language such as ahoy or matey, but not so much that it becomes hard to understand. Keep answers playful and short. Answer in 1 sentence (maximum 2), no more than 20 words. Communicate exclusively in Dutch. Do not say things like: great question!", | |
| "alien": "You are taking part in a child-friendly guessing game. Keep your answer natural, short, and easy for a child to understand. You respond like a friendly alien visiting Earth. You find normal human things strange and interesting. You answer with curiosity and wonder. Keep answers short and funny. Answer in 1 sentence (maximum 2), no more than 20 words. Communicate exclusively in Dutch. Do not say things like: great question!", | |
| "tovenaar": "You are taking part in a child-friendly guessing game. Keep your answer natural, short, and easy for a child to understand. You respond like a wise but playful wizard. You use magical language and imaginative ideas, but still answer the child's question clearly. Keep it short and mysterious. Answer in 1 sentence (maximum 2), no more than 20 words. Communicate exclusively in Dutch. Do not say things like: great question!", | |
| } | |
| refresh_needed = False | |
| class FlaskApp: | |
| def __init__(self, agents): | |
| self.agents = agents # [None (admin), agent1, agent2, agent3] | |
| self.flask_app = Flask(__name__) | |
| self.flask_app.secret_key = "supersecretkey" | |
| self.difficulty_limits = {"easy": 5, "medium": 3, "hard": 1} | |
| self.difficulty = "easy" | |
| self.max_questions = self.difficulty_limits[self.difficulty] | |
| self.questions_asked = 0 | |
| self.game_over = False | |
| self.last_result = None | |
| # screen_assignment maps screen position (1,2,3) to role (Human, AI1, AI2) | |
| self.screen_assignment = {"1": "AI1", "2": "Human", "3": "AI2"} | |
| self.rounds = [] | |
| self.pending_round = None | |
| self.discarded_ai_responses = [] | |
| self.routes_registered = False | |
| self.register_routes() | |
| self.first_guess = None | |
| def register_routes(self): | |
| if not self.routes_registered: | |
| def user_dashboard(): | |
| global refresh_needed | |
| if request.method == 'POST': | |
| user_message = request.form.get('message') | |
| if user_message: | |
| if self.game_over or self.pending_round is not None: | |
| flash('Wacht op het volgende spel of de admin-reactie.', 'warning') | |
| return redirect(url_for('user_dashboard')) | |
| if self.questions_asked >= self.max_questions: | |
| flash('Je hebt je laatste vraag al gesteld. Maak je keuze.', 'warning') | |
| return redirect(url_for('user_dashboard')) | |
| ai_options = [] | |
| for agent_index, agent in enumerate(self.agents): | |
| if agent is None: | |
| continue | |
| llm_response = agent.request_llm_response(user_message) | |
| ai_options.append({ | |
| 'agent': f'llm{agent_index}', | |
| 'content': llm_response | |
| }) | |
| self.questions_asked += 1 | |
| self.pending_round = { | |
| 'question': user_message, | |
| 'ai_options': ai_options | |
| } | |
| flash('Je vraag is verstuurd. Wacht op de admin.', 'success') | |
| return redirect(url_for('user_dashboard')) | |
| refresh_needed = True | |
| return render_template('dashboard.html') | |
| def admin_dashboard(): | |
| global refresh_needed | |
| if request.method == 'POST': | |
| action = request.form.get('action') | |
| if action == 'send_round': | |
| human_response = request.form.get('human_response') | |
| if self.pending_round is None: | |
| flash('Er is geen open vraag van de gebruiker.', 'warning') | |
| return redirect(url_for('admin_dashboard')) | |
| if not human_response: | |
| flash('Schrijf eerst een menselijk antwoord.', 'warning') | |
| return redirect(url_for('admin_dashboard')) | |
| # Use current ai_options from pending_round | |
| self.rounds.append({ | |
| 'question': self.pending_round['question'], | |
| 'ai_options': self.pending_round['ai_options'], | |
| 'human_response': human_response | |
| }) | |
| self.pending_round = None | |
| flash('Antwoorden zijn verstuurd naar de gebruiker.', 'success') | |
| return redirect(url_for('admin_dashboard')) | |
| if action == 'reload_ai': | |
| agent_index = int(request.form.get('agent_index')) | |
| if self.pending_round is not None: | |
| question = self.pending_round['question'] | |
| agent = self.agents[agent_index] | |
| if agent is not None: | |
| new_response = agent.request_llm_response(question) | |
| for option in self.pending_round['ai_options']: | |
| if option['agent'] == f'llm{agent_index}': | |
| self.discarded_ai_responses.append({ | |
| 'question': question, | |
| 'agent': option['agent'], | |
| 'content': option['content'] | |
| }) | |
| option['content'] = new_response | |
| break | |
| return redirect(url_for('admin_dashboard')) | |
| refresh_needed = True | |
| return render_template('admin_dashboard.html', | |
| pending_round=self.pending_round, | |
| discarded_ai_responses=self.discarded_ai_responses, | |
| screen_assignment=self.screen_assignment, | |
| difficulty=self.difficulty, | |
| questions_left=max(self.max_questions - self.questions_asked, 0), | |
| max_questions=self.max_questions) | |
| def setup_prompts(): | |
| if request.method == 'POST': | |
| llm_1_key = request.form.get('llm_1_system_content') | |
| llm_2_key = request.form.get('llm_2_system_content') | |
| if llm_1_key in PERSONALITY_PROMPTS: | |
| self.agents[1].system_content = PERSONALITY_PROMPTS[llm_1_key] | |
| if llm_2_key in PERSONALITY_PROMPTS: | |
| self.agents[2].system_content = PERSONALITY_PROMPTS[llm_2_key] | |
| self.selected_llm_1 = llm_1_key | |
| self.selected_llm_2 = llm_2_key | |
| return redirect(url_for('setup_screens')) | |
| return render_template('setup_prompts.html', | |
| selected_llm_1=getattr(self, 'selected_llm_1', 'vriendelijke_ouder'), | |
| selected_llm_2=getattr(self, 'selected_llm_2', 'grappige_ouder')) | |
| def setup_screens(): | |
| import random | |
| if request.method == 'POST': | |
| return redirect(url_for('admin_dashboard')) | |
| roles = ["Human", "AI1", "AI2"] | |
| random.shuffle(roles) | |
| self.screen_assignment = {"1": roles[0], "2": roles[1], "3": roles[2]} | |
| human_screen = [k for k, v in self.screen_assignment.items() if v == "Human"][0] | |
| print("Human screen:", human_screen) # add this to check in terminal | |
| return render_template('setup_screens.html', human_screen=human_screen) | |
| def reinitialize_dashboards(): | |
| session.clear() | |
| self.questions_asked = 0 | |
| self.game_over = False | |
| self.last_result = None | |
| self.rounds = [] | |
| self.pending_round = None | |
| self.discarded_ai_responses = [] | |
| self.screen_assignment = {"1": "AI1", "2": "Human", "3": "AI2"} | |
| self.first_guess = None | |
| return redirect(url_for('admin_rules')) | |
| def reset_game(): | |
| self.questions_asked = 0 | |
| self.game_over = False | |
| self.last_result = None | |
| self.rounds = [] | |
| self.pending_round = None | |
| self.discarded_ai_responses = [] | |
| self.first_guess = None | |
| next_url = request.form.get('next') | |
| if next_url: | |
| return redirect(next_url) | |
| return redirect(url_for('user_dashboard')) | |
| def set_difficulty(): | |
| difficulty = request.form.get('difficulty') | |
| if difficulty in self.difficulty_limits and self.questions_asked == 0 and self.pending_round is None: | |
| self.difficulty = difficulty | |
| self.max_questions = self.difficulty_limits[difficulty] | |
| next_url = request.form.get('next') | |
| if next_url: | |
| return redirect(next_url) | |
| return redirect(url_for('user_rules')) | |
| def submit_guess(): | |
| if self.game_over or self.pending_round is not None: | |
| return jsonify({"ok": False, "reason": "not_ready"}) | |
| if self.questions_asked == 0: | |
| return jsonify({"ok": False, "reason": "no_questions"}) | |
| screen = request.form.get('screen') | |
| if screen not in {"1", "2", "3"}: | |
| return jsonify({"ok": False, "reason": "invalid"}) | |
| # First guess | |
| if not hasattr(self, 'first_guess') or self.first_guess is None: | |
| self.first_guess = screen | |
| return jsonify({"ok": True, "status": "first_guess", "screen": screen}) | |
| # Second guess — must be different screen | |
| if screen == self.first_guess: | |
| return jsonify({"ok": False, "reason": "same_screen"}) | |
| second_guess = screen | |
| guess1 = self.first_guess | |
| guess2 = second_guess | |
| self.first_guess = None | |
| self.game_over = True | |
| # Check results | |
| role1 = self.screen_assignment[guess1] | |
| role2 = self.screen_assignment[guess2] | |
| correct1 = role1 in ("AI1", "AI2") | |
| correct2 = role2 in ("AI1", "AI2") | |
| if correct1 and correct2: | |
| result = "victory" | |
| elif correct1 or correct2: | |
| result = "partial" | |
| else: | |
| result = "defeat" | |
| # Find human screen | |
| human_screen = [k for k, v in self.screen_assignment.items() if v == "Human"][0] | |
| self.last_result = { | |
| "result": result, | |
| "guess1": guess1, | |
| "guess2": guess2, | |
| "correct1": correct1, | |
| "correct2": correct2, | |
| "human_screen": human_screen | |
| } | |
| return jsonify({"ok": True, "status": "done", "result": result, | |
| "guess1": guess1, "guess2": guess2, | |
| "correct1": correct1, "correct2": correct2, | |
| "human_screen": human_screen}) | |
| def login(): | |
| if request.method == 'POST': | |
| username = request.form.get('username') | |
| if username == 'admin': | |
| session['username'] = 'admin' | |
| return redirect(url_for('admin_rules')) | |
| elif username == 'user': | |
| session['username'] = 'user' | |
| return redirect(url_for('user_rules')) | |
| else: | |
| return "Ongeldige gebruikersnaam. Gebruik 'user' of 'admin'." | |
| return render_template('login.html') | |
| def user_rules(): | |
| return render_template('rules_user.html', | |
| difficulty=self.difficulty, | |
| can_change_settings=self.questions_asked == 0 and self.pending_round is None, | |
| questions_left=max(self.max_questions - self.questions_asked, 0), | |
| max_questions=self.max_questions, | |
| game_over=self.game_over) | |
| def admin_rules(): | |
| return render_template('rules_admin.html', | |
| difficulty=self.difficulty, | |
| can_change_settings=self.questions_asked == 0 and self.pending_round is None, | |
| questions_left=max(self.max_questions - self.questions_asked, 0), | |
| max_questions=self.max_questions, | |
| game_over=self.game_over) | |
| def logout(): | |
| session.clear() | |
| return redirect(url_for('login')) | |
| def index(): | |
| return render_template('index.html') | |
| def check_refresh(): | |
| global refresh_needed | |
| return jsonify({"refresh_needed": refresh_needed}) | |
| def reset_refresh(): | |
| global refresh_needed | |
| refresh_needed = False | |
| return '', 204 | |
| def get_game_state(): | |
| screen_history = {"1": [], "2": [], "3": []} | |
| screen_current = {"1": "Nog geen reacties.", "2": "Nog geen reacties.", "3": "Nog geen reacties."} | |
| for round_item in self.rounds: | |
| for screen_num, role in self.screen_assignment.items(): | |
| if role == "Human": | |
| answer = round_item["human_response"] | |
| elif role == "AI1": | |
| answer = round_item["ai_options"][0]["content"] if round_item["ai_options"] else "" | |
| else: # AI2 | |
| answer = round_item["ai_options"][1]["content"] if len(round_item["ai_options"]) > 1 else "" | |
| screen_history[screen_num].append({ | |
| "question": round_item["question"], | |
| "answer": answer | |
| }) | |
| for screen_num in ["1", "2", "3"]: | |
| if screen_history[screen_num]: | |
| screen_current[screen_num] = screen_history[screen_num][-1]["answer"] | |
| questions_left = max(self.max_questions - self.questions_asked, 0) | |
| pending = self.pending_round is not None | |
| return jsonify({ | |
| "current": screen_current, | |
| "history": screen_history, | |
| "questions_left": questions_left, | |
| "questions_asked": self.questions_asked, | |
| "max_questions": self.max_questions, | |
| "pending": pending, | |
| "game_over": self.game_over, | |
| "result": self.last_result, | |
| "can_ask": (not self.game_over) and (not pending) and (self.questions_asked < self.max_questions), | |
| "can_guess": (not self.game_over) and (not pending) and (self.questions_asked > 0), | |
| "ready_to_guess": (not self.game_over) and (not pending) and (self.questions_asked >= self.max_questions), | |
| "first_guess": self.first_guess if hasattr(self, 'first_guess') else None | |
| }) | |
| def get_admin_state(): | |
| return jsonify({ | |
| "pending_round": self.pending_round, | |
| "rounds": self.rounds, | |
| "discarded": self.discarded_ai_responses, | |
| "questions_left": max(self.max_questions - self.questions_asked, 0), | |
| "max_questions": self.max_questions, | |
| "difficulty": self.difficulty, | |
| "screen_assignment": self.screen_assignment, | |
| "can_change_settings": self.questions_asked == 0 and self.pending_round is None | |
| }) | |
| self.routes_registered = True | |
| if __name__ == '__main__': | |
| agent_1 = GroqAgent(PERSONALITY_PROMPTS["vriendelijke_ouder"]) | |
| agent_2 = GroqAgent(PERSONALITY_PROMPTS["grappige_ouder"]) | |
| admin = None | |
| agents = [admin, agent_1, agent_2] | |
| refresh_needed = False | |
| app = FlaskApp(agents) | |
| app.flask_app.run(debug=True) |