from typing import List from openai import OpenAI from models import BaseLearningObjective, LearningObjective, TEMPERATURE_UNAVAILABLE from prompts.incorrect_answers import INCORRECT_ANSWER_EXAMPLES_WITH_EXPLANATION def generate_incorrect_answer_options(client: OpenAI, model: str, temperature: float, file_contents: List[str], base_objectives: List[BaseLearningObjective], model_override: str = None) -> List[LearningObjective]: """ Generate incorrect answer options for each base learning objective. Args: file_contents: List of file contents with source tags base_objectives: List of base learning objectives to enhance Returns: List of learning objectives with incorrect answer suggestions """ print(f"Generating incorrect answer options for {len(base_objectives)} learning objectives") # Create combined content for context combined_content = "\n\n".join(file_contents) enhanced_objectives = [] for i, objective in enumerate(base_objectives): print(f"Processing objective {i+1}/{len(base_objectives)}: {objective.learning_objective[:50]}...") print(f"Learning objective: {objective.learning_objective}") print(f"Correct answer: {objective.correct_answer}") # # Create the prompt for generating incorrect answer options prompt = f""" Based on the learning objective and correct answer provided below. Learning Objective: {objective.learning_objective} Correct Answer: {objective.correct_answer} Generate 3 incorrect answer options. Use the examples with explanations below to guide you in generating incorrect answer options: {INCORRECT_ANSWER_EXAMPLES_WITH_EXPLANATION} Here's the course content that the student has been exposed to: {combined_content} Here's the learning objective that was identified: "id": {objective.id}, "learning_objective": "{objective.learning_objective}", "source_reference": "{objective.source_reference}", "correct_answer": "{objective.correct_answer}" When creating incorrect answers, refer to the correct answer {objective.correct_answer}. Make sure incorrect answers match the correct answer in terms of length, complexity, phrasing, style, and subject matter. Incorrect answers should be of approximate equal length to the correct answer, preferably one sentence and 20 words long. Pay attention to the example in about avoiding unnecessary length. """ try: model_to_use = model_override if model_override else model # Use OpenAI beta API for structured output system_prompt = "You are an expert in designing effective multiple-choice questions that assess higher-order thinking skills while following established educational best practices." params = { "model": model_to_use, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt} ], "response_format": LearningObjective } if not TEMPERATURE_UNAVAILABLE.get(model_to_use, True): params["temperature"] = temperature # Use higher temperature for creative misconceptions print(f"DEBUG - Using model {model_to_use} for incorrect answer options with temperature {params.get('temperature', 'N/A')}") completion = client.beta.chat.completions.parse(**params) enhanced_obj = completion.choices[0].message.parsed # Simple debugging for incorrect answer suggestions if enhanced_obj.incorrect_answer_options: print(f" → Got {len(enhanced_obj.incorrect_answer_options)} incorrect answers") print(f" → First option: {enhanced_obj.incorrect_answer_options[0][:100]}..." if len(enhanced_obj.incorrect_answer_options[0]) > 100 else enhanced_obj.incorrect_answer_options[0]) else: print(" → No incorrect answer options received!") # Preserve grouping metadata from the original objective enhanced_obj.in_group = getattr(objective, 'in_group', None) enhanced_obj.group_members = getattr(objective, 'group_members', None) enhanced_obj.best_in_group = getattr(objective, 'best_in_group', None) enhanced_objectives.append(enhanced_obj) except Exception as e: print(f"Error generating incorrect answer options for objective {objective.id}: {e}") # If there's an error, create a learning objective without suggestions enhanced_obj = LearningObjective( id=objective.id, learning_objective=objective.learning_objective, source_reference=objective.source_reference, correct_answer=objective.correct_answer, incorrect_answer_options=None, in_group=getattr(objective, 'in_group', None), group_members=getattr(objective, 'group_members', None), best_in_group=getattr(objective, 'best_in_group', None) ) enhanced_objectives.append(enhanced_obj) print(f"Generated incorrect answer options for {len(enhanced_objectives)} learning objectives") return enhanced_objectives