| """ |
| option_generator.py |
| |
| Generates the 4-option list for an MCQ. |
| |
| Changes from original: |
| - Accepts pos_tag and forwards it to generate_distractors so the |
| auto_register / cluster routing uses POS for better sub-cluster matching. |
| - All options (including the answer) are root forms β lemmatization has |
| already happened upstream in process_pipeline.py. |
| """ |
|
|
| import random |
| import sys |
| import os |
|
|
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) |
|
|
| from question_generation.cluster_store import generate_distractors |
|
|
|
|
| def generate_options(answer_word: str, |
| sentence_words: list[str], |
| pos_tags: list[tuple] | None = None, |
| n: int = 3, |
| domain: str | None = None, |
| question: str = "", |
| context: str = "") -> list[str]: |
| """ |
| Return a shuffled list of 4 options (3 distractors + 1 correct answer). |
| All items are root forms. |
| |
| Parameters |
| ---------- |
| answer_word : root form of the correct answer |
| sentence_words : tokenised words from the sentence (used to avoid |
| accidentally selecting a word already in the question) |
| pos_tags : list of (word, upos) pairs from Stanza β used to look |
| up the POS of answer_word for better cluster routing |
| n : number of distractors to generate (default 3) |
| question : MCQ question string (for keyword-based cluster detection) |
| context : original sentence (for domain detection) |
| """ |
|
|
| |
| pos_tag = "NOUN" |
| if pos_tags: |
| pos_lookup = {word: tag for word, tag in pos_tags} |
| |
| |
| if answer_word in pos_lookup: |
| pos_tag = pos_lookup[answer_word] |
| else: |
| |
| for word, tag in pos_tags: |
| if tag in ("NOUN", "PROPN"): |
| pos_tag = tag |
| break |
|
|
| distractors = generate_distractors( |
| answer=answer_word, |
| question=question, |
| context=context, |
| k=n, |
| ) |
|
|
| options = distractors[:n] + [answer_word] |
| random.shuffle(options) |
| return options |
|
|