{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "6fc105e9-70fb-4b39-94aa-443c6ce55dfe",
      "name": "Analyze image",
      "type": "@n8n/n8n-nodes-langchain.ollama",
      "position": [
        960,
        1936
      ],
      "parameters": {
        "text": "=You are an OMR sheet analysis system.\n\nTask:\nAnalyze the provided OMR answer sheet image and extract ONLY the student's marked answers.\n\nStrict rules:\n- Ignore all headers, instructions, logos, barcodes, or any other text.\n- High Focus ONLY on the answer bubbles and properlly right answer provide.\n- For each question, detect the clearly filled/marked option (A, B, C, or D).\n- If multiple bubbles are filled for a question, select the darkest/most clearly marked one.\n- If no option is clearly marked for a question, skip that question entirely.\n- Do NOT guess answers.\n- Do NOT explain anything.\n- Do NOT add confidence scores or metadata.\n\nOutput format (MANDATORY):\n- Plain text only\n- Exactly in the format shown below\n- One answer per line\n- Sequential numbering starting from question 1\n- No extra spaces, symbols, or commentary\n- Extract a student details\n\nRequired output structure:\n \"student\":\n    \"name\": \"string | null\",\n    \"rollNumber\": \"string | null\",\n    \"class\": \"string | null\"\nanswer :\n1. A\n2. B\n3. C\n4. D\n5. A\n...\n(continue until the last detected question)",
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gemini-3-flash-preview",
          "cachedResultName": "gemini-3-flash-preview"
        },
        "options": {
          "format": "json"
        },
        "resource": "image",
        "simplify": false
      },
      "typeVersion": 1
    },
    {
      "id": "e98c50f8-98e3-4b94-951c-40a94197cd6b",
      "name": "Merge Answer",
      "type": "n8n-nodes-base.merge",
      "position": [
        1408,
        1888
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "0d328c98-9fe6-487e-bbb1-cca7a93539dc",
      "name": "Calculate Result",
      "type": "n8n-nodes-base.code",
      "position": [
        1616,
        1856
      ],
      "parameters": {
        "jsCode": "// // function parseAnswers(input) {\n// //   if (!input) return {};\n\n// //   // If already object, return as is\n// //   if (typeof input === \"object\") {\n// //     return input;\n// //   }\n\n// //   // If string, normalize and parse\n// //   if (typeof input === \"string\") {\n// //     let obj = {};\n// //     let parts = input\n// //       .replace(/->/g, \":\")        // handle \"->\" also\n// //       .replace(/\\n/g, \",\")        // handle line breaks\n// //       .split(\",\");\n\n// //     for (let p of parts) {\n// //       let [q, ans] = p.split(\":\").map(s => s.trim());\n// //       if (q && ans) obj[q] = ans.toUpperCase();\n// //     }\n// //     return obj;\n// //   }\n\n// //   return {};\n// // }\n\n// // // ---- Extract Inputs (safe handling)\n// // const item = $input.item?.json || {};\n// // const originalRaw = item.chatInput || item.CorrectAnswer || {};\n// // const userRaw = item.UserAnswers || {};\n\n// // const original = parseAnswers(originalRaw);\n// // const user = parseAnswers(userRaw);\n\n// // let correct = 0;\n// // let incorrect = 0;\n// // let results = [];\n\n// // const total = Object.keys(original).length || Object.keys(user).length || 0;\n\n// // // ---- Comparison logic\n// // for (let i = 1; i <= total; i++) {\n// //   const q = String(i);\n// //   const correctAns = original[q] || \"Not Available\";\n// //   const given = user[q] || \"Not Attempted\";\n\n// //   if (given === correctAns) {\n// //     correct++;\n// //     results.push({ question: i, given, correctAns, status: \"Correct\" });\n// //   } else {\n// //     incorrect++;\n// //     results.push({ question: i, given, correctAns, status: \"Incorrect\" });\n// //   }\n// // }\n\n// // // ---- Calculate percentage safely\n// // const scorePercentage = total > 0 ? ((correct / total) * 100).toFixed(2) : \"0.00\";\n\n// // // ---- Return final structured output\n// // return [\n// //   {\n// //     json: {\n// //       totalQuestions: total,\n// //       correct,\n// //       incorrect,\n// //       scorePercentage,\n// //       results\n// //     }\n// //   }\n// // ];\n\n\n\n\n// function parseAnswers(input) {\n//   if (!input) return {};\n\n//   // If already object, return as is\n//   if (typeof input === \"object\") {\n//     return input;\n//   }\n\n//   // If string, normalize and parse\n//   if (typeof input === \"string\") {\n//     let obj = {};\n//     let parts = input\n//       .replace(/->/g, \":\")\n//       .replace(/\\n/g, \",\")\n//       .split(\",\");\n\n//     for (let p of parts) {\n//       let [q, ans] = p.split(\":\").map(s => s.trim());\n//       if (q && ans) obj[q] = ans.toUpperCase();\n//     }\n//     return obj;\n//   }\n\n//   return {};\n// }\n\n// // ---- Extract Inputs\n// const item = $input.item?.json || {};\n\n// // \u2705 STUDENT DETAILS (DIRECT, NO PARSING)\n// const student = item.student || {\n//   name: null,\n//   rollNumber: null,\n//   class: null\n// };\n\n// // ---- Answers\n// const originalRaw = item.chatInput || item.CorrectAnswer || {};\n// const userRaw = item.UserAnswers || {};\n\n// const original = parseAnswers(originalRaw);\n// const user = parseAnswers(userRaw);\n\n// // ---- Evaluation\n// let correct = 0;\n// let incorrect = 0;\n// let results = [];\n\n// const total =\n//   Object.keys(original).length ||\n//   Object.keys(user).length ||\n//   0;\n\n// for (let i = 1; i <= total; i++) {\n//   const q = String(i);\n//   const correctAns = original[q] || \"Not Available\";\n//   const given = user[q] || \"Not Attempted\";\n\n//   if (given === correctAns) {\n//     correct++;\n//     results.push({\n//       question: i,\n//       given,\n//       correctAns,\n//       status: \"Correct\"\n//     });\n//   } else {\n//     incorrect++;\n//     results.push({\n//       question: i,\n//       given,\n//       correctAns,\n//       status: \"Incorrect\"\n//     });\n//   }\n// }\n\n// // ---- Score\n// const scorePercentage =\n//   total > 0 ? ((correct / total) * 100).toFixed(2) : \"0.00\";\n\n// // ---- FINAL API RESPONSE\n// return [\n//   {\n//     json: {\n//       student,\n//       totalQuestions: total,\n//       correct,\n//       incorrect,\n//       scorePercentage,\n//       results\n//     }\n//   }\n// ];\n\n\nfunction parseAnswers(input) {\n  if (!input) return {};\n\n  if (typeof input === \"object\") {\n    return input;\n  }\n\n  if (typeof input === \"string\") {\n    let obj = {};\n    let parts = input\n      .replace(/->/g, \":\")\n      .replace(/\\n/g, \",\")\n      .split(\",\");\n\n    for (let p of parts) {\n      let [q, ans] = p.split(\":\").map(s => s.trim());\n      if (q && ans) obj[q] = ans.toUpperCase();\n    }\n    return obj;\n  }\n\n  return {};\n}\n\n// ---- Extract Inputs\nconst item = $input.item?.json || {};\n\n// ---- Student Details\nconst student = item.student || {\n  name: null,\n  rollNumber: null,\n  class: null\n};\n\n// ---- Answers\nconst original = parseAnswers(item.chatInput || item.CorrectAnswer || {});\nconst user = parseAnswers(item.UserAnswers || {});\n\n// ---- Evaluation\nlet correct = 0;\nlet incorrect = 0;\nlet results = [];\nlet binaryResult = {}; // \ud83d\udc48 for Google Sheets (Q.1 = 1/0)\n\nconst total =\n  Object.keys(original).length ||\n  Object.keys(user).length ||\n  0;\n\nfor (let i = 1; i <= total; i++) {\n  const q = String(i);\n  const correctAns = original[q] || \"Not Available\";\n  const given = user[q] || \"Not Attempted\";\n\n  const isCorrect = given === correctAns;\n  const value = isCorrect ? 1 : 0;\n\n  if (isCorrect) {\n    correct++;\n  } else {\n    incorrect++;\n  }\n\n  results.push({\n    question: i,\n    given,\n    correctAns,\n    status: isCorrect ? \"Correct\" : \"Incorrect\",\n    value // \ud83d\udc48 1 or 0\n  });\n\n  binaryResult[`Q.${i}`] = value; // \ud83d\udc48 Q.1, Q.2, ...\n}\n\n// ---- Score\nconst scorePercentage =\n  total > 0 ? ((correct / total) * 100).toFixed(2) : \"0.00\";\n\n// ---- FINAL OUTPUT\nreturn [\n  {\n    json: {\n      student,\n      totalQuestions: total,\n      correct,\n      incorrect,\n      scorePercentage,\n      results,        // detailed\n      binaryResult    // \ud83d\udc48 PERFECT FOR GOOGLE SHEETS\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "78f5bed1-1583-4429-ae5b-960be1d44795",
      "name": "Send Result Respond",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2016,
        1856
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ {\n  status: \"success\",\n  data: $json\n} }}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "21acd37d-0f9b-4475-96a5-794a7497d4e4",
      "name": "Convert User Ans in Formate",
      "type": "n8n-nodes-base.code",
      "position": [
        1216,
        1968
      ],
      "parameters": {
        "jsCode": "// // Get input JSON\n// const input = items[0].json;\n\n// // Get raw AI response text\n// const content = input.message?.content || \"\";\n\n// // Regex to capture answers like \"1:A\", \"2 : B\", etc.\n// const regex = /(\\d+)\\s*[:\\.]\\s*([A-D])/g;\n\n// let match;\n// const pairs = [];\n\n// // Extract question-answer pairs\n// while ((match = regex.exec(content)) !== null) {\n//   pairs.push(`${match[1]}:${match[2]}`);\n// }\n\n// // Join into a single string\n// const userAnswersStr = pairs.join(\", \");\n\n// // Return ONLY user answers\n// return [\n//   {\n//     json: {\n//       UserAnswers: userAnswersStr\n//     }\n//   }\n// ];\n\n\n\n// ===============================\n// 1. GET INPUT\n// ===============================\nconst input = items[0].json;\nlet content = input.message?.content || \"\";\n\n// Remove ``` fences if present\ncontent = content.replace(/```/g, \"\").trim();\n\n// ===============================\n// 2. EXTRACT STUDENT DETAILS\n// ===============================\nconst student = {\n  name: null,\n  rollNumber: null,\n  class: null\n};\n\n// Name\nconst nameMatch = content.match(/\"name\"\\s*:\\s*\"([^\"]+)\"/i);\nif (nameMatch) student.name = nameMatch[1].trim();\n\n// Roll Number\nconst rollMatch = content.match(/\"rollNumber\"\\s*:\\s*\"([^\"]+)\"/i);\nif (rollMatch) student.rollNumber = rollMatch[1].trim();\n\n// Class\nconst classMatch = content.match(/\"class\"\\s*:\\s*\"([^\"]+)\"/i);\nif (classMatch) student.class = classMatch[1].trim();\n\n// ===============================\n// 3. EXTRACT USER ANSWERS\n// ===============================\n\n// Regex to capture answers like \"1:A\", \"1. A\", \"2 : B\"\nconst regex = /(\\d+)\\s*[:\\.]\\s*([A-D])/g;\n\nlet match;\nconst pairs = [];\n\n// Extract question-answer pairs\nwhile ((match = regex.exec(content)) !== null) {\n  pairs.push(`${match[1]}:${match[2]}`);\n}\n\n// Join into a single string\nconst userAnswersStr = pairs.join(\", \");\n\n// ===============================\n// 4. FINAL OUTPUT\n// ===============================\nreturn [\n  {\n    json: {\n      student,\n      UserAnswers: userAnswersStr\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "d4f4b88d-30c3-4355-a404-b9000db1d2ea",
      "name": "Set Your Correct Answer",
      "type": "n8n-nodes-base.set",
      "position": [
        1216,
        1824
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1209b6e5-0167-4c2a-b9bd-b894760a4027",
              "name": "CorrectAnswer",
              "type": "string",
              "value": "1:B, 2:A, 3:D, 4:C, 5:B, 6:D, 7:B, 8:C, 9:A, 10:B, 11:D, 12:C, 13:A, 14:D, 15:B, 16:C, 17:D, 18:A, 19:B, 20:C"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "0bd1adb7-3475-4251-b343-79b2608d800f",
      "name": "Send Student Ans Img",
      "type": "n8n-nodes-base.webhook",
      "position": [
        640,
        1856
      ],
      "parameters": {
        "path": "omr-sheet-checker",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "52442ffc-824d-432b-aaad-80eab9257104",
      "name": "Append Result in Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1824,
        1856
      ],
      "parameters": {
        "columns": {
          "value": {
            "Q.1": "={{ $json.results[0].value }}",
            "Q.2": "={{ $json.results[1].value }}",
            "Q.3": "={{ $json.results[2].value }}",
            "Q.4": "={{ $json.results[3].value }}",
            "Q.5": "={{ $json.results[4].value }}",
            "Q.6": "={{ $json.results[5].value }}",
            "Q.7": "={{ $json.results[6].value }}",
            "Q.8": "={{ $json.results[7].value }}",
            "Q.9": "={{ $json.results[8].value }}",
            "Q.10": "={{ $json.results[9].value }}",
            "Q.11": "={{ $json.results[10].value }}",
            "Q.12": "={{ $json.results[11].value }}",
            "Q.13": "={{ $json.results[12].value }}",
            "Q.14": "={{ $json.results[13].value }}",
            "Q.15": "={{ $json.results[14].value }}",
            "Q.16": "={{ $json.results[15].value }}",
            "Q.17": "={{ $json.results[16].value }}",
            "Q.18": "={{ $json.results[17].value }}",
            "Q.19": "={{ $json.results[18].value }}",
            "Q.20": "={{ $json.results[19].value }}",
            "Class": "={{ $json.student.class }}",
            "Correct": "={{ $json.correct }}",
            "Roll No": "={{ $json.student.rollNumber }}",
            "Incorrect": "={{ $json.incorrect }}",
            "Student Name": "={{ $json.student.name }}",
            "Score Percentage": "={{ $json.scorePercentage }}%"
          },
          "schema": [
            {
              "id": "Student Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Student Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Roll No",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Roll No",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Class",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Class",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.1",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.1",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.2",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.2",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.3",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.3",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.4",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.4",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.5",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.5",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.6",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.6",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.7",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.7",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.8",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.8",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.9",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.9",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.10",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.10",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.11",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.11",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.12",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.12",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.13",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.13",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.14",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.14",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.15",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.15",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.16",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.16",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.17",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.17",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.18",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.18",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.19",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.19",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Q.20",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Q.20",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Correct",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Correct",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Incorrect",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Incorrect",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Score Percentage",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Score Percentage",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/15nvRI8zcJ2n-QBXNk9xyd1GM8Vj7_1lJ3K7vO7Qfq3w/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "15nvRI8zcJ2n-QBXNk9xyd1GM8Vj7_1lJ3K7vO7Qfq3w",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/15nvRI8zcJ2n-QBXNk9xyd1GM8Vj7_1lJ3K7vO7Qfq3w/edit?usp=drivesdk",
          "cachedResultName": "Students Result"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "37946fab-f3c4-41d5-ab75-64570b720429",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        2128
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 256,
        "content": "## Google Sheet\nhttps://docs.google.com/spreadsheets/d/15nvRI8zcJ2n-QBXNk9xyd1GM8Vj7_1lJ3K7vO7Qfq3w/edit?usp=sharing\n\n\n## Webhook Payload :\nForm-Data\nkey-name : file\nValue : Upload Img"
      },
      "typeVersion": 1
    },
    {
      "id": "a81c3963-b846-440c-90e2-c13bd394713a",
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        144,
        1696
      ],
      "parameters": {
        "width": 420,
        "height": 528,
        "content": "## How it works\nThis workflow automates OMR (Optical Mark Recognition) answer sheet evaluation. Upload a student's answer sheet image via webhook, and AI analyzes the marked bubbles to extract answers. The system compares them against correct answers, calculates scores, and stores results in Google Sheets.\n\nKey features:\n- AI-powered bubble detection using Gemini\n- Automatic student detail extraction (name, roll number, class)\n- Question-by-question comparison with correct answers\n- Binary scoring (1/0) for each question\n- Real-time results via webhook response\n\n## Setup steps\n1. Configure Ollama credentials for Gemini AI model\n2. Set correct answers in \"Set Your Correct Answer\" node\n3. Connect Google Sheets OAuth2 credentials\n4. Test webhook with form-data (key: \"file\", value: OMR image)\n5. Verify results appear in Google Sheet"
      },
      "typeVersion": 1
    },
    {
      "id": "4ab41919-537e-40a3-b051-e0bbe3a19b65",
      "name": "Input Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        1696
      ],
      "parameters": {
        "color": 7,
        "width": 264,
        "height": 412,
        "content": "## Input Section\nReceives OMR sheet image via webhook and sets up correct answer key for comparison."
      },
      "typeVersion": 1
    },
    {
      "id": "b13f3985-fec0-41e0-95fa-5fa7501fcbb1",
      "name": "AI Processing",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        848,
        1696
      ],
      "parameters": {
        "color": 7,
        "width": 280,
        "height": 412,
        "content": "## AI Processing\nGemini AI analyzes the image to extract student details and marked answers from bubbles."
      },
      "typeVersion": 1
    },
    {
      "id": "c75ce701-c5ac-441d-a9e2-2d3d2d29e284",
      "name": "Answer Comparison",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1136,
        1696
      ],
      "parameters": {
        "color": 7,
        "width": 408,
        "height": 412,
        "content": "## Answer Comparison\n\nMerges student answers with correct answers, then calculates score and generates detailed results."
      },
      "typeVersion": 1
    },
    {
      "id": "2622777b-a6b4-41c9-a33f-58fbaa7707a0",
      "name": "Output Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1552,
        1696
      ],
      "parameters": {
        "color": 7,
        "width": 644,
        "height": 412,
        "content": "## Output Section\nSaves results to Google Sheets and returns JSON response with complete evaluation data."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Merge Answer": {
      "main": [
        [
          {
            "node": "Calculate Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze image": {
      "main": [
        [
          {
            "node": "Convert User Ans in Formate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Result": {
      "main": [
        [
          {
            "node": "Append Result in Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Student Ans Img": {
      "main": [
        [
          {
            "node": "Analyze image",
            "type": "main",
            "index": 0
          },
          {
            "node": "Set Your Correct Answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Result in Sheet": {
      "main": [
        [
          {
            "node": "Send Result Respond",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Your Correct Answer": {
      "main": [
        [
          {
            "node": "Merge Answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert User Ans in Formate": {
      "main": [
        [
          {
            "node": "Merge Answer",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  }
}