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: @self.flask_app.route('/dashboard', methods=['GET', 'POST']) 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') @self.flask_app.route('/admin_dashboard', methods=['GET', 'POST']) 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) @self.flask_app.route('/setup_prompts', methods=['GET', 'POST']) 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')) @self.flask_app.route('/setup_screens', methods=['GET', 'POST']) 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) @self.flask_app.route('/reinitialize', methods=['POST']) 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')) @self.flask_app.route('/reset_game', methods=['POST']) 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')) @self.flask_app.route('/set_difficulty', methods=['POST']) 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')) @self.flask_app.route('/submit_guess', methods=['POST']) 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}) @self.flask_app.route('/login', methods=['GET', 'POST']) 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') @self.flask_app.route('/rules/user') 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) @self.flask_app.route('/rules/admin') 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) @self.flask_app.route('/logout') def logout(): session.clear() return redirect(url_for('login')) @self.flask_app.route('/') def index(): return render_template('index.html') @self.flask_app.route('/check_refresh') def check_refresh(): global refresh_needed return jsonify({"refresh_needed": refresh_needed}) @self.flask_app.route('/reset_refresh', methods=['POST']) def reset_refresh(): global refresh_needed refresh_needed = False return '', 204 @self.flask_app.route('/get_game_state', methods=['GET']) 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 }) @self.flask_app.route('/get_admin_state', methods=['GET']) 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)