from typing import Any, Optional from smolagents.tools import Tool import json import random class QCMTool(Tool): """ A tool for running multiple-choice question (QCM) quizzes. It picks a random question, checks the user's answer, and provides feedback. """ name = "qcm_tool" description = "A tool for running multiple-choice question (QCM) quizzes. It picks a random question, checks the user's answer, and provides feedback." inputs = { 'user_answer': { 'type': 'string', 'description': 'The user\'s selected answer (e.g., "A", "B", "C", "D").' } } output_type = "string" def __init__(self, json_file: str, *args, **kwargs): """ Initialize the QCM tool with a JSON file containing questions. Args: json_file (str): Path to the JSON file containing the questions. """ super().__init__(*args, **kwargs) self.json_file = json_file self.questions = self._load_questions() self.is_initialized = True def _load_questions(self): """ Load questions from the JSON file. Returns: list: A list of questions loaded from the JSON file. Raises: FileNotFoundError: If the JSON file is not found. json.JSONDecodeError: If the JSON file is malformed. """ try: with open(self.json_file, 'r') as file: return json.load(file) except FileNotFoundError: raise FileNotFoundError(f"The file {self.json_file} was not found.") except json.JSONDecodeError: raise json.JSONDecodeError(f"The file {self.json_file} contains invalid JSON.") def _pick_random_question(self): """ Pick a random question from the loaded questions. Returns: dict: A randomly selected question. """ return random.choice(self.questions) def _check_answer(self, question: dict, user_answer: str) -> tuple[bool, str]: """ Check if the user's answer is correct and provide an explanation. Args: question (dict): The question dictionary containing the correct answer and explanation. user_answer (str): The user's selected answer. Returns: tuple: A tuple containing a boolean (True if correct, False otherwise) and the explanation. """ is_correct = user_answer == question["correct_answer"] return is_correct, question["explanation"] def forward(self, user_answer: str) -> str: """ The main entry point for the QCM tool. It picks a random question, checks the user's answer, and provides feedback. Args: user_answer: The user's selected answer (e.g., "A", "B", "C", "D"). Returns: str: A formatted string indicating whether the answer was correct and providing an explanation. Raises: ValueError: If the user's answer is invalid. """ # Pick a random question question = self._pick_random_question() # Validate the user's answer if user_answer.upper() not in ['A', 'B', 'C', 'D']: raise ValueError("Invalid input. Please enter a valid option letter (A, B, C, D).") # Map the user's answer to the corresponding option option_index = ord(user_answer.upper()) - 65 # Convert 'A' to 0, 'B' to 1, etc. selected_option = question["options"][option_index] # Check the answer is_correct, explanation = self._check_answer(question, selected_option) # Return feedback if is_correct: return f"Correct! 🎉\nExplanation: {explanation}" else: return f"Incorrect! 😞\nExplanation: {explanation}" if __name__ == "__main__": # Initialize the QCM tool qcm_tool = QCMTool(json_file="../info/questions.json") question = qcm_tool._pick_random_question() print(question) # Simulate a user answering 'A' try: result = qcm_tool.forward(user_answer="A") print(result) except ValueError as e: print(f"Error: {e}")