Building a Paragraph to Dynamic MCQ Generator with JavaScript

Creating a Multiple-Choice Question (MCQ) generator can be a fun and educational project that highlights the power of JavaScript libraries. In this blog post, we'll walk through the process of building an MCQ generator that dynamically creates questions from a given paragraph. We'll explain the functions and dependencies involved, discuss the usefulness of such generators, provide a demo link, and conclude with the pros and cons of this approach.

Dependencies

To build our MCQ generator, we rely on two primary JavaScript libraries:

  1. Compromise: A lightweight natural language processing (NLP) library for extracting key information from the text.
  2. Faker.js: A library for generating random data, which we use to create plausible distractors for the MCQs.

You can include these libraries in your HTML file using the following script tags:

<script src="https://unpkg.com/compromise"></script>
<script src="https://cdn.jsdelivr.net/npm/faker@5.5.3/dist/faker.min.js"></script>

Functions

Our MCQ generator comprises several key functions:

1. extractKeySentences

This function uses the Compromise library to extract key sentences from the given paragraph. These sentences serve as the basis for generating questions.

function extractKeySentences(text) {
    let doc = nlp(text);
    let sentences = doc.sentences();
    return sentences.out('array');
}

2. generateDistractors

This function generates context-aware distractors based on the keywords extracted from the paragraph. It ensures that the distractors are relevant and not too similar to the correct answer.

function generateDistractors(keyword, keywords) {
    let distractors = [];
    while (distractors.length < 3) {
        let distractor = keywords[Math.floor(Math.random() * keywords.length)];
        if (distractor !== keyword && !distractors.includes(distractor) && distractor.length > 3 && distractor.length <= 15) {
            distractors.push(distractor);
        }
    }
    return distractors;
}

3. createDynamicMCQ

This function combines the extracted sentences and generated distractors to create a set of MCQs. It replaces keywords with ellipses (...) to form questions and ensures that each question has a valid set of answer options.

function createDynamicMCQ(paragraph) {
    const keySentences = extractKeySentences(paragraph);
    const doc = nlp(paragraph);
    const allKeywords = doc.nouns().out('array');
    const questions = keySentences.map((sentence, index) => {
        let sentenceDoc = nlp(sentence);
        let keywords = sentenceDoc.nouns().out('array');
        if (keywords.length === 0) keywords = sentenceDoc.terms().out('array');

        let keyword = keywords.filter(word => word.length > 3 && word.length <= 15)[Math.floor(Math.random() * keywords.length)];

        if (!keyword) {
            keyword = "None of these";
        }

        let question = sentence.includes(keyword) ? sentence.replace(keyword, "...") : null;
        let options = [keyword, ...generateDistractors(keyword, allKeywords)];

        options = options.map(option => option ? option.charAt(0).toUpperCase() + option.slice(1) : "None of these");
        options = options.sort(() => Math.random() - 0.5);

        return {
            question: question,
            options: options,
            answer: keyword.charAt(0).toUpperCase() + keyword.slice(1)
        };
    }).filter(mcq => mcq.question);
    return questions;
}

4. displayMCQs

This function displays the generated MCQs in an HTML form, ensuring that each question is presented with its corresponding options.

function displayMCQs(mcqs) {
    const mcqForm = document.getElementById('mcq-form');
    mcqForm.innerHTML = ""; 
    mcqs.forEach((mcq, index) => {
        const questionDiv = document.createElement('div');
        questionDiv.className = 'question';
        const questionText = document.createElement('strong');
        questionText.textContent = `${index + 1}. ${mcq.question}`;
        questionDiv.appendChild(questionText);

        const optionsDiv = document.createElement('div');
        optionsDiv.className = 'options';
        mcq.options.forEach((option, i) => {
            const optionDiv = document.createElement('div');
            optionDiv.className = 'form-check';

            const optionInput = document.createElement('input');
            optionInput.className = 'form-check-input';
            optionInput.type = 'radio';
            optionInput.name = `question${index}`;
            optionInput.value = option;
            optionInput.id = `question${index}_${i}`;
            optionInput.required = true;

            const optionLabel = document.createElement('label');
            optionLabel.className = 'form-check-label';
            optionLabel.htmlFor = `question${index}_${i}`;
            optionLabel.textContent = option;

            optionDiv.appendChild(optionInput);
            optionDiv.appendChild(optionLabel);
            optionsDiv.appendChild(optionDiv);
        });

        questionDiv.appendChild(optionsDiv);
        mcqForm.appendChild(questionDiv);
    });
}

5. generateMCQs

This function retrieves the paragraph input from a textarea, generates MCQs, and displays them on the page.

function generateMCQs() {
    const paragraph = document.getElementById('input-paragraph').value;
    mcqs = createDynamicMCQ(paragraph);
    displayMCQs(mcqs);
}

6. submitForm

This function handles the form submission, checks if all questions are answered, calculates the score, and displays the result.

function submitForm() {
    const mcqForm = document.getElementById('mcq-form');
    const resultDiv = document.getElementById('result');
    let score = 0;
    let allAnswered = true;

    mcqs.forEach((mcq, index) => {
        const selectedOption = mcqForm.querySelector(`input[name="question${index}"]:checked`);
        if (selectedOption && selectedOption.value === mcq.answer) {
            score++;
        } else if (!selectedOption) {
            allAnswered = false;
        }
    });

    if (allAnswered) {
        resultDiv.textContent = `Your score: ${score} out of ${mcqs.length}`;
    } else {
        resultDiv.textContent = `Please complete all questions before submitting.`;
    }
}

7. Prevent Page Reload

This function prevents the page from being reloaded to avoid losing data.

window.addEventListener('beforeunload', function (e) {
    e.preventDefault();
    e.returnValue = '';
});

Usefulness of the MCQ Generator

This type of MCQ generator can be incredibly useful in various contexts:

  • Educational Tools: Teachers can quickly generate quizzes and practice tests for students based on study materials.
  • E-learning Platforms: Online courses can dynamically create assessments to enhance interactive learning.
  • Self-assessment: Learners can test their knowledge on specific topics by generating their own quizzes from textbooks or articles.

Live Demo

Check out the live demo here.

Conclusion

The dynamic MCQ generator we've built demonstrates the power of JavaScript libraries like Compromise and Faker.js in creating engaging and interactive content. By leveraging these libraries, we can automate the process of generating questions and enhance the learning experience for users.

Drawbacks

While this approach is effective, it does have some limitations:

  • Contextual Accuracy: The generated questions may not always be perfectly accurate or relevant due to the limitations of the NLP library.
  • Complex Sentences: The generator may struggle with complex sentences that contain multiple keywords or phrases.
  • Limited Customization: The current implementation offers limited customization for question formatting and options.

Overall, this project showcases the potential of JavaScript libraries in building dynamic and useful educational tools. However, there is room for improvement and further development to address the identified limitations.

Happy coding

0 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *


You may like to read


Follow Us

Sponsored Ads

GranNino Ads

Newsletter

Subscribe to our Newsletter to read our latest posts at first

We would not spam your inbox! Promise
Get In Touch

© Fullstack Coding Tips. All Rights Reserved.