ecuartasm's picture
Initial commit: AI Course Assessment Generator
217abc3
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:
<examples_with_explanation>
{INCORRECT_ANSWER_EXAMPLES_WITH_EXPLANATION}
</examples_with_explanation>
Here's the course content that the student has been exposed to:
<course_content>
{combined_content}
</course_content>
Here's the learning objective that was identified:
<learning_objective>
"id": {objective.id},
"learning_objective": "{objective.learning_objective}",
"source_reference": "{objective.source_reference}",
"correct_answer": "{objective.correct_answer}"
</learning_objective>
When creating incorrect answers, refer to the correct answer <correct_answer>{objective.correct_answer}</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 <examples_with_explanation> 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