feat(generation): add exercise instructions, grouped display, and wizard improvements
- Add per-section instructions field to exercise wizard with sensible defaults - Group exercises by type with section headers showing instructions - Pass type_instructions to backend AI prompt for context-aware generation - Add instructions editing in exercise edit dialog - Update Exercise interface to include instructions field Made-with: Cursor
This commit is contained in:
@@ -409,14 +409,41 @@ class AIController(http.Controller):
|
|||||||
def _generate_exercises(self, ai, module, body):
|
def _generate_exercises(self, ai, module, body):
|
||||||
passage_text = body.get("passage_text", "")
|
passage_text = body.get("passage_text", "")
|
||||||
exercise_types = body.get("exercise_types", [])
|
exercise_types = body.get("exercise_types", [])
|
||||||
count = body.get("count_per_type", 5)
|
type_counts = body.get("type_counts", {})
|
||||||
types_str = ", ".join(exercise_types) if exercise_types else "multiple choice"
|
type_instructions = body.get("type_instructions", {})
|
||||||
|
default_count = body.get("count_per_type", 5)
|
||||||
|
difficulty = body.get("difficulty", "B2")
|
||||||
|
|
||||||
|
type_specs = []
|
||||||
|
total = 0
|
||||||
|
for et in exercise_types:
|
||||||
|
c = int(type_counts.get(et, default_count))
|
||||||
|
instr = type_instructions.get(et, "")
|
||||||
|
spec_line = f"- EXACTLY {c} questions of type \"{et}\""
|
||||||
|
if instr:
|
||||||
|
spec_line += f"\n Student instructions: \"{instr}\""
|
||||||
|
type_specs.append(spec_line)
|
||||||
|
total += c
|
||||||
|
spec_str = "\n".join(type_specs) if type_specs else f"- {default_count} multiple choice questions"
|
||||||
|
|
||||||
messages = [
|
messages = [
|
||||||
{"role": "system", "content": (
|
{"role": "system", "content": (
|
||||||
f"Based on the following text, generate {count} exercises of these types: {types_str}. "
|
f"You are an exam question generator. Generate EXACTLY {total} exercises "
|
||||||
"Return JSON: "
|
f"at CEFR {difficulty} level based on the passage below.\n\n"
|
||||||
'{"questions": [{"type": string, "prompt": string, "options": [string], '
|
f"REQUIRED question breakdown (you MUST follow these counts exactly):\n"
|
||||||
'"correct_answer": string, "explanation": string, "marks": number}]}'
|
f"{spec_str}\n\n"
|
||||||
|
"CRITICAL RULES:\n"
|
||||||
|
f"1. The total number of questions in your response MUST be exactly {total}.\n"
|
||||||
|
"2. Each question MUST have a 'type' field set to one of the requested types.\n"
|
||||||
|
"3. Each question MUST include an 'instructions' field with the student-facing instructions "
|
||||||
|
"for that section (use the provided instructions, or write appropriate ones).\n"
|
||||||
|
"4. For mcq/true_false types: include 'options' array and 'correct_answer'.\n"
|
||||||
|
"5. For fill_blanks/write_blanks types: use '___' in the prompt for blanks, "
|
||||||
|
"set correct_answer to the missing word(s), options can be empty.\n"
|
||||||
|
"6. For paragraph_match: prompt describes what to match, options are paragraph labels.\n\n"
|
||||||
|
"Return JSON:\n"
|
||||||
|
'{"questions": [{"type": string, "instructions": string, "prompt": string, '
|
||||||
|
'"options": [string], "correct_answer": string, "explanation": string, "marks": number}]}'
|
||||||
)},
|
)},
|
||||||
{"role": "user", "content": passage_text[:3000]},
|
{"role": "user", "content": passage_text[:3000]},
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user