{
  "id": "hIzQqdu1LCKgMj2Q",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "PDF textbook -> MCQ's",
  "tags": [],
  "nodes": [
    {
      "id": "f165e479-2564-498b-a927-7dd343453fd4",
      "name": "Google Gemini Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        432,
        464
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5d922d59-312d-4c03-aac2-4fd19534c49a",
      "name": "Upload a File",
      "type": "n8n-nodes-uploadtourl.uploadToUrl",
      "position": [
        1152,
        288
      ],
      "parameters": {
        "uploadAllBinary": false
      },
      "credentials": {
        "uploadToUrlApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3d94b15d-b23b-4063-9cc1-3deed2cb40f0",
      "name": "Send a message",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1392,
        288
      ],
      "parameters": {
        "sendTo": "={{ $('Get-Details').item.json['E-mail'] }}",
        "message": "=<p>Hi {{ $('Get-Details').item.json.Name }},</p>\n\n<p>Your custom study quiz has been successfully generated from your textbook upload! We've made it fully interactive, so you can click the options to test your knowledge instantly and see the explanations.</p>\n\n<p>\ud83d\udd17 <b><a href=\"{{ $json.url }}\">Click here to open your Interactive Quiz</a></b></p>\n\n<p>Good luck with your studying!</p>\n\n<p>Best,<br>\nYour Automated Tutor</p>",
        "options": {
          "appendAttribution": false
        },
        "subject": "=Your Custom Interactive Quiz is Ready, {{ $('Get-Details').item.json.Name }}! \ud83d\ude80"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6a57e76c-d7c3-4346-a144-f1388a675a05",
      "name": "Extract from File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        256,
        288
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "PDF"
      },
      "typeVersion": 1.1
    },
    {
      "id": "e181ee1d-6814-4a20-b2bd-bb8ca4f6b6c4",
      "name": "Get-Details",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        16,
        288
      ],
      "parameters": {
        "options": {},
        "formTitle": "PDF textbook -> MCQ's",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Name",
              "requiredField": true
            },
            {
              "fieldType": "email",
              "fieldLabel": "E-mail",
              "requiredField": true
            },
            {
              "fieldType": "file",
              "fieldLabel": "PDF",
              "requiredField": true,
              "acceptFileTypes": ".pdf"
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Number of Questions",
              "fieldOptions": {
                "values": [
                  {
                    "option": "10"
                  },
                  {
                    "option": "20"
                  },
                  {
                    "option": "30"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "radio",
              "fieldLabel": "Difficulty",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Easy"
                  },
                  {
                    "option": "Medium"
                  },
                  {
                    "option": "Hard"
                  }
                ]
              },
              "requiredField": true
            }
          ]
        },
        "formDescription": "Upload your textbook's pdf and get some MCQ's "
      },
      "typeVersion": 2.5
    },
    {
      "id": "e893da55-c18e-4653-9faa-ecc01d5adb06",
      "name": "Generate-MCQ",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        480,
        288
      ],
      "parameters": {
        "text": "=You are an expert tutor. I am providing you with the exact extracted text from my textbook.\n\nTEXT CONTENT: {{ $json.text }}\n\n\nRequirements:\n- Number of questions: {{ $('Get-Details').item.json['Number of Questions'] }}\n- Difficulty level: {{ $('Get-Details').item.json.Difficulty }}\n\nReturn ONLY a valid JSON array in this exact format:\n[{\"q\": \"Question text?\", \"options\": {\"A\": \"...\", \"B\": \"...\", \"C\": \"...\", \"D\": \"...\"}, \"answer\": \"A\", \"explanation\": \"...\"}]\n\nCRITICAL INSTRUCTION: You must return ONLY valid, perfectly formatted JSON. Do not include any trailing commas, missing brackets, or extra text outside the JSON structure. If the JSON is invalid, the system will crash.",
        "batching": {},
        "promptType": "define"
      },
      "retryOnFail": false,
      "typeVersion": 1.9
    },
    {
      "id": "875da812-fbab-4d87-8291-aca90da03f5c",
      "name": "Template",
      "type": "n8n-nodes-base.code",
      "position": [
        864,
        288
      ],
      "parameters": {
        "jsCode": "// 1. Get the AI's output and clean the markdown backticks\nconst aiResponse = $input.item.json.text;\nconst cleanJson = aiResponse.replace(/```json/g, '').replace(/```/g, '').trim();\n\n// 2. Parse the string into an actual JavaScript array\nlet mcqs;\ntry {\n    mcqs = JSON.parse(cleanJson);\n} catch (e) {\n    mcqs = [{\"q\": \"Error loading questions\", \"options\": {\"A\":\"-\",\"B\":\"-\",\"C\":\"-\",\"D\":\"-\"}, \"answer\": \"A\", \"explanation\": \"Failed to parse AI output.\"}];\n}\n\n// 3. Get the student's name from the trigger node\nconst name = $('On form submission').first().json[\"Name\"] || \"Student\";\n\n// 4. Build the HTML template with Interactive JavaScript\nlet htmlContent = `\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <style>\n        body { font-family: Arial, sans-serif; padding: 40px; line-height: 1.6; color: #333; max-width: 800px; margin: auto; }\n        .header { text-align: center; border-bottom: 2px solid #333; padding-bottom: 10px; margin-bottom: 30px; }\n        .card { border: 1px solid #e0e0e0; padding: 20px; margin-bottom: 20px; border-radius: 8px; background-color: #fcfcfc; }\n        .question { font-weight: bold; font-size: 1.1em; color: #2c3e50; margin-bottom: 15px; }\n        .options { margin-left: 10px; margin-bottom: 15px; }\n        \n        /* Make the radio buttons look like clickable rows */\n        .option-label { display: block; margin-bottom: 8px; cursor: pointer; padding: 8px; border-radius: 4px; transition: 0.2s; }\n        .option-label:hover { background-color: #f0f0f0; }\n        \n        /* The answer box is hidden by default */\n        .answer-box { padding: 15px; border-radius: 4px; margin-top: 15px; display: none; }\n        \n        /* Dynamic colors injected by JavaScript */\n        .correct-box { background-color: #e8f5e9; border-left: 4px solid #4caf50; }\n        .incorrect-box { background-color: #ffebee; border-left: 4px solid #f44336; }\n        \n        .answer { font-weight: bold; margin-bottom: 5px; font-size: 1.1em; }\n        .explanation { color: #555; font-size: 0.95em; margin-top: 10px; }\n    </style>\n\n    <script>\n        // This function runs when a user clicks a radio button\n        function checkAnswer(qIndex, selected, correct) {\n            const box = document.getElementById('answer-box-' + qIndex);\n            const answerText = document.getElementById('answer-text-' + qIndex);\n            \n            // Show the answer box\n            box.style.display = 'block';\n            \n            // Check if they got it right or wrong\n            if(selected === correct) {\n                box.className = 'answer-box correct-box';\n                answerText.innerHTML = '\u2705 Correct! The answer is ' + correct;\n                answerText.style.color = '#2e7d32';\n            } else {\n                box.className = 'answer-box incorrect-box';\n                answerText.innerHTML = '\u274c Incorrect. The correct answer is ' + correct;\n                answerText.style.color = '#c62828';\n            }\n            \n            // Disable all radio buttons for this question so they can't change their answer\n            const radios = document.getElementsByName('q' + qIndex);\n            for(let i=0; i < radios.length; i++) {\n                radios[i].disabled = true;\n            }\n        }\n    </script>\n</head>\n<body>\n    <div class=\"header\">\n        <h1>Data Communication Quiz</h1>\n        <p>Prepared for: ${name}</p>\n    </div>\n`;\n\n// Loop through each question to generate the interactive cards\nmcqs.forEach((item, index) => {\n    // We pass the index, the user's choice, and the actual correct answer to the JavaScript function\n    htmlContent += `\n    <div class=\"card\">\n        <div class=\"question\">${index + 1}. ${item.q}</div>\n        <div class=\"options\">\n            <label class=\"option-label\">\n                <input type=\"radio\" name=\"q${index}\" value=\"A\" onclick=\"checkAnswer(${index}, 'A', '${item.answer}')\"> A) ${item.options.A}\n            </label>\n            <label class=\"option-label\">\n                <input type=\"radio\" name=\"q${index}\" value=\"B\" onclick=\"checkAnswer(${index}, 'B', '${item.answer}')\"> B) ${item.options.B}\n            </label>\n            <label class=\"option-label\">\n                <input type=\"radio\" name=\"q${index}\" value=\"C\" onclick=\"checkAnswer(${index}, 'C', '${item.answer}')\"> C) ${item.options.C}\n            </label>\n            <label class=\"option-label\">\n                <input type=\"radio\" name=\"q${index}\" value=\"D\" onclick=\"checkAnswer(${index}, 'D', '${item.answer}')\"> D) ${item.options.D}\n            </label>\n        </div>\n        \n        <!-- This box stays hidden until the JavaScript tells it to appear -->\n        <div id=\"answer-box-${index}\" class=\"answer-box\">\n            <div id=\"answer-text-${index}\" class=\"answer\"></div>\n            <div class=\"explanation\"><strong>Explanation:</strong> ${item.explanation}</div>\n        </div>\n    </div>`;\n});\n\nhtmlContent += `</body></html>`;\n\n// 5. Convert the HTML string into an actual file in n8n's memory\nreturn {\n    json: { success: true },\n    binary: {\n        data: await this.helpers.prepareBinaryData(Buffer.from(htmlContent), \"Interactive_Quiz.html\", \"text/html\")\n    }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "6a6fdf44-4707-41a1-a235-28b9a9e71244",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        -80
      ],
      "parameters": {
        "color": "#A23F3F",
        "height": 512,
        "content": "### Step 1: Get-Details (Form Trigger)\n\n**What it does:**\n- Acts as the entry point of the workflow.\n- Displays a form to the user.\n\n**Form Fields:**\n- Name\n- Email\n- PDF Upload\n- Number of Questions (10/20/30)\n- Difficulty (Easy/Medium/Hard)\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "035994b5-c26c-41fb-8bfc-7a86a969bbc2",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        32
      ],
      "parameters": {
        "color": "#821C45",
        "height": 400,
        "content": "### Step 2: Extract from File\n\n**What it does:**\n- Extracts text from the uploaded PDF.\n\n**How it works:**\n- Takes binary PDF from previous node.\n- Uses built-in PDF parser.\n- Converts PDF \u2192 plain text.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "8d9c947c-b7d5-45f9-b1c6-d3e77d054ac9",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        448,
        -16
      ],
      "parameters": {
        "color": "#603187",
        "width": 288,
        "height": 464,
        "content": "### Step 3: Generate-MCQ\n\n**What it does:**\n- Converts textbook text \u2192 MCQs using AI.\n\n**How it works:**\n1. Takes extracted text from previous node.\n2. Reads user inputs:\n   - Number of questions\n   - Difficulty level\n3. Sends structured prompt to Gemini.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "af39615e-5449-401d-80d9-9130a47635e0",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        752,
        -256
      ],
      "parameters": {
        "color": "#115678",
        "width": 320,
        "height": 704,
        "content": "### Step 4: Template (Code Node)\n\n**What it does:**\n- Converts MCQs into an interactive HTML quiz.\n\n**How it works:**\n\n **Parse JSON**\n- Converts string \u2192 JavaScript object\n- Handles errors safely\n\n **Personalization**\n- Gets user name\n- Adds it to quiz\n\n**Build HTML**\n- Creates styled quiz layout\n- Adds:\n  - Questions\n  - Options (radio buttons)\n  - Answer + explanation\n\n**Add Interactivity** (JavaScript)\n- When user clicks option:\n  - Shows correct/incorrect\n  - Displays explanation\n  - Locks answer\n"
      },
      "typeVersion": 1
    },
    {
      "id": "fffb12e2-349a-4dc0-845a-5640c2445d30",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        -64
      ],
      "parameters": {
        "color": "#AC5C11",
        "height": 512,
        "content": "### Step 6: Send a Message (Gmail)\n\n**What it does:**\n- Sends email to user with quiz link.\n\n**How it works:**\n- Uses user's email from form\n- Inserts:\n  - Name (personalization)\n  - Quiz URL (from Upload node)\n\n**Email Content:**\n- Friendly message\n- Clickable quiz link\n\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "75e10214-d65d-4bf6-8f18-148da6006e2b",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        -208
      ],
      "parameters": {
        "color": "#1B833A",
        "height": 656,
        "content": "### Step 5: Upload a File (UploadToURL)\n\n**What it does:**\n- Uploads the generated interactive HTML quiz to the internet.\n- Instantly creates a **public shareable link**.\n\n\n**Why it\u2019s powerful:**\n- No hosting required\n- No backend setup\n- Instant file sharing\n- Perfect for automation workflows\n\n- Converts our generated quiz into a **live interactive web page**\n- Makes it easy to **share via email instantly**\n\n\ud83d\udc49 Try UploadToURL here:  \nhttps://uploadtourl.com/\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5efa72fa-ced0-4971-8dbe-59f9a6319d60",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        688,
        480
      ],
      "parameters": {
        "width": 432,
        "height": 336,
        "content": "### the actual html page \n![image](https://cdn.uploadtourl.com/b119036b-8925-460e-a083-a507adc18085_Screenshot_2026-05-06_175729.png#full-width)"
      },
      "typeVersion": 1
    },
    {
      "id": "1a615015-aa59-482c-9e1b-0d5c85567f07",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1136,
        480
      ],
      "parameters": {
        "width": 448,
        "height": 320,
        "content": "### the actual html page \n![image](https://cdn.uploadtourl.com/5443e757-3f07-4987-8cda-44d8d6a009bc_Screenshot_2026-05-06_175748.png#full-width)"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "52d5ba25-ebf2-4477-9e1b-098fb5e8c7d4",
  "connections": {
    "Template": {
      "main": [
        [
          {
            "node": "Upload a File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get-Details": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate-MCQ": {
      "main": [
        [
          {
            "node": "Template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload a File": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File": {
      "main": [
        [
          {
            "node": "Generate-MCQ",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Generate-MCQ",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}