AutomationFlowsAI & RAG › Good2ai Agent in N8n (multimodal)

Good2ai Agent in N8n (multimodal)

good2AI Agent in n8n (Multimodal). Uses telegram, httpRequest. Webhook trigger; 17 nodes.

Webhook trigger★★★★☆ complexity17 nodesTelegramHTTP Request
AI & RAG Trigger: Webhook Nodes: 17 Complexity: ★★★★☆ Added:

This workflow follows the HTTP Request → Telegram recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "good2AI Agent in n8n (Multimodal)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "aa46a723-619e-42e9-8e51-49ba51813718",
        "authentication": "headerAuth",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        688,
        960
      ],
      "id": "c99f4e4d-8f7c-44e5-a066-0d7052247e85",
      "name": "Webhook-homework",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "080ee5fb-782f-47d6-9d64-98ec8e8c52f2",
              "name": "student_user_id",
              "value": "={{ $json.body.student_user_id }}",
              "type": "string"
            },
            {
              "id": "78fcca79-e818-4b3c-803f-94deda4f3104",
              "name": "course_id",
              "value": "={{ $json.body.course_numeric_id }}",
              "type": "string"
            },
            {
              "id": "969420d2-791b-40a4-924d-ec7e332d3d6b",
              "name": "lesson_num",
              "value": "={{ $json.body.lesson_num }}",
              "type": "string"
            },
            {
              "id": "2d2c5f78-ecaf-408d-acdb-ff6d7a4d086d",
              "name": "admin_chat_id",
              "value": "={{ $json.body.admin_group_id }}",
              "type": "string"
            },
            {
              "id": "5b60f83f-1667-4f43-9ab5-e7aad6d988f1",
              "name": "target_message_id",
              "value": "={{ $json.body.original_admin_message_id || $json.body.admin_message_id }}",
              "type": "string"
            },
            {
              "id": "c324098f-8660-4435-acef-09352a9a0a45",
              "name": "student_name",
              "value": "={{ ($json.body.user_fullname || $json.body.student_name || '\u0421\u0442\u0443\u0434\u0435\u043d\u0442').split(' ')[0] }}",
              "type": "string"
            },
            {
              "id": "753df8c9-e2c2-4ea6-aef4-5608ef8f92b1",
              "name": "hw_text",
              "value": "={{ $json.body.homework_text || '[\u0422\u0435\u043a\u0441\u0442 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442]' }}",
              "type": "string"
            },
            {
              "id": "2653261d-4f8b-494d-8bb3-975e69a96b0f",
              "name": "hw_file_id",
              "value": "={{ $json.body.homework_file_id || '' }}",
              "type": "string"
            },
            {
              "id": "2168a0e7-3cb9-44a2-b21c-85050c3405b2",
              "name": "lesson_desc",
              "value": "={{ $json.body.lesson_assignment_description ||'\u041e\u0446\u0435\u043d\u0438\u0442\u044c \u0414\u0417' }}",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        896,
        960
      ],
      "id": "5e90780f-7ead-42f0-a920-48d0c27d760b",
      "name": "Edit Fields",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "5b1189a6-6cee-49af-ad61-c91de051a0ea",
              "leftValue": "={{ $('Edit Fields').item.json.hw_file_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1104,
        960
      ],
      "id": "fc9e4e42-94e5-417f-b764-084502e4d983",
      "name": "If"
    },
    {
      "parameters": {
        "jsCode": "// \u0422\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u0414\u0417 (\u0431\u0435\u0437 \u0444\u0430\u0439\u043b\u043e\u0432) - \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 messages content\nconst hwText = $input.item.json.hw_text || $('Edit Fields').item.json.hw_text || '[\u0422\u0435\u043a\u0441\u0442 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442]';\nconst studentName = $('Edit Fields').item.json.student_name || '\u0421\u0442\u0443\u0434\u0435\u043d\u0442';\nconst lessonDesc = $('Edit Fields').item.json.lesson_desc || '\u041e\u0446\u0435\u043d\u0438\u0442\u044c \u0414\u0417';\n\nconsole.log(`\ud83d\udcdd \u0422\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u0414\u0417 \u043e\u0442 ${studentName}`);\n\n// \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c messages content \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u0442\u0435\u043a\u0441\u0442\u043e\u043c\nconst messagesContent = [\n  {\n    type: \"text\",\n    text: `\u0420\u0410\u0411\u041e\u0422\u0410 \u0421\u0422\u0423\u0414\u0415\u041d\u0422\u0410:\\n${hwText}`\n  }\n];\n\nreturn [{\n  json: {\n    ...$input.item.json,\n    messages_content: messagesContent\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1360,
        1184
      ],
      "id": "db8fa270-6c2c-4053-ba46-419a6890c552",
      "name": "Prepare Text Messages"
    },
    {
      "parameters": {
        "resource": "file",
        "fileId": "={{ $('Edit Fields').item.json.hw_file_id }}",
        "download": true,
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        1296,
        944
      ],
      "id": "ee907f71-a51f-49ee-83bb-2469ea1e7651",
      "name": "Get a file",
      "alwaysOutputData": false,
      "retryOnFail": true,
      "waitBetweenTries": 200,
      "maxTries": 2,
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "jsCode": "// \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0438\u043f\u0430 \u0444\u0430\u0439\u043b\u0430 \u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f\nconst mimeType = $input.item.json.mimeType || $input.item.json.binary?.data?.mimeType || '';\nconst fileType = mimeType.split('/')[0];\n\nlet output = 0; // 0 = text/no file, 1 = image, 2 = audio, 3 = video\n\nif (mimeType.startsWith('image')) {\n  output = 1;\n} else if (mimeType.startsWith('audio')) {\n  output = 2;\n} else if (mimeType.startsWith('video')) {\n  output = 3;\n}\n\nreturn [{\n  json: {\n    ...$input.item.json,\n    file_type: fileType,\n    mime_type: mimeType,\n    route_output: output\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1488,
        928
      ],
      "id": "c1859512-d3f2-46bc-875d-d9709f8e4c22",
      "name": "Route File Type"
    },
    {
      "parameters": {
        "jsCode": "// \u0412\u0435\u0442\u043a\u0430 \u0424\u041e\u0422\u041e: \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044f \u0432 Base64\nconst binaryData = items[0].binary?.data;\n\nif (!binaryData) {\n  throw new Error('\u041d\u0435\u0442 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445');\n}\n\nconst mimeType = binaryData.mimeType || 'image/jpeg';\nconst fileSize = binaryData.data?.length || 0;\n\nconsole.log(`\ud83d\udcf8 \u0424\u043e\u0442\u043e: ${fileSize} \u0431\u0430\u0439\u0442, MIME: ${mimeType}`);\n\nitems[0].json.base64_image = binaryData.data;\nitems[0].json.mime_type = mimeType;\nitems[0].json.file_size = fileSize;\nitems[0].json.file_type = 'image';\n\nreturn items;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1680,
        768
      ],
      "id": "646b4992-8d89-4aad-85f9-db9d8509753e",
      "name": "Process Photo"
    },
    {
      "parameters": {
        "jsCode": "// \u0412\u0435\u0442\u043a\u0430 \u0410\u0423\u0414\u0418\u041e: \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 + \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\nconst binaryData = items[0].binary?.data;\n\nif (!binaryData) {\n  throw new Error('\u041d\u0435\u0442 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445');\n}\n\nconst mimeType = binaryData.mimeType || 'audio/ogg';\nconst fileSize = binaryData.data?.length || 0;\nconst MAX_AUDIO_SIZE = 10 * 1024 * 1024; // 10 \u041c\u0411\n\nconsole.log(`\ud83c\udfa7 \u0410\u0443\u0434\u0438\u043e: ${fileSize} \u0431\u0430\u0439\u0442 (${(fileSize / 1024 / 1024).toFixed(2)} \u041c\u0411), MIME: ${mimeType}`);\n\nif (fileSize > MAX_AUDIO_SIZE) {\n  console.log(`\u26a0\ufe0f \u0410\u0443\u0434\u0438\u043e \u0431\u043e\u043b\u044c\u0448\u0435 10 \u041c\u0411!`);\n  items[0].json.audio_truncated = true;\n  items[0].json.audio_warning = `\u0410\u0443\u0434\u0438\u043e \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0435 (${(fileSize / 1024 / 1024).toFixed(2)} \u041c\u0411). \u0418\u0418 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u044c.`;\n} else {\n  items[0].json.audio_truncated = false;\n}\n\n// \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c binary data \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 OpenRouter\nitems[0].json.audio_data = binaryData.data;\nitems[0].json.file_size = fileSize;\nitems[0].json.file_type = 'audio';\nitems[0].json.mime_type = mimeType;\n\nreturn items;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1680,
        928
      ],
      "id": "f9701ae0-84ee-452e-b674-feca53f772c3",
      "name": "Process Audio"
    },
    {
      "parameters": {
        "jsCode": "// \u0412\u0435\u0442\u043a\u0430 \u0412\u0418\u0414\u0415\u041e (\u043a\u0440\u0443\u0436\u043e\u0447\u043a\u0438/\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u044b\u0435 video/ogg): \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 + \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\nconst binaryData = items[0].binary?.data;\n\nif (!binaryData) {\n  throw new Error('\u041d\u0435\u0442 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445');\n}\n\nconst mimeType = binaryData.mimeType || 'video/ogg';\nconst fileSize = binaryData.data?.length || 0;\nconst MAX_SIZE = 10 * 1024 * 1024; // 10 \u041c\u0411\n\nconsole.log(`\ud83c\udfa5 \u0412\u0438\u0434\u0435\u043e/\u043a\u0440\u0443\u0436\u043e\u0447\u0435\u043a: ${fileSize} \u0431\u0430\u0439\u0442 (${(fileSize / 1024 / 1024).toFixed(2)} \u041c\u0411), MIME: ${mimeType}`);\n\nif (fileSize > MAX_SIZE) {\n  console.log(`\u26a0\ufe0f \u0412\u0438\u0434\u0435\u043e \u0431\u043e\u043b\u044c\u0448\u0435 10 \u041c\u0411!`);\n  items[0].json.file_truncated = true;\n  items[0].json.file_warning = `\u0424\u0430\u0439\u043b \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 (${(fileSize / 1024 / 1024).toFixed(2)} \u041c\u0411).`;\n} else {\n  items[0].json.file_truncated = false;\n}\n\n// \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c binary data \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 OpenRouter\nitems[0].json.audio_data = binaryData.data; // Gemini \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0430\u0443\u0434\u0438\u043e \u0438\u0437 \u0432\u0438\u0434\u0435\u043e \u043a\u0430\u043a audio_data\nitems[0].json.file_size = fileSize;\nitems[0].json.file_type = 'video';\nitems[0].json.mime_type = mimeType;\n\nreturn items;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1680,
        1088
      ],
      "id": "870ac92f-fa6d-42cb-a2a9-9eb253c822de",
      "name": "Process Video"
    },
    {
      "parameters": {
        "jsCode": "// \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 messages content \u0434\u043b\u044f OpenRouter AI\nconst hwText = $input.item.json.hw_text || $('Edit Fields').item.json.hw_text || '[\u0422\u0435\u043a\u0441\u0442 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442]';\nconst audioWarning = $input.item.json.audio_warning || '';\nconst fileWarning = $input.item.json.file_warning || '';\nconst base64Image = $input.item.json.base64_image || null;\nconst mimeType = $input.item.json.mime_type || '';\nconst fileType = $input.item.json.file_type || '';\nconst audioData = $input.item.json.audio_data || null;\n\n// \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c text content\nlet textContent = `\u0420\u0410\u0411\u041e\u0422\u0410 \u0421\u0422\u0423\u0414\u0415\u041d\u0422\u0410:\\n${hwText}`;\nif (audioWarning) textContent += `\\n\\n\u26a0\ufe0f ${audioWarning}`;\nif (fileWarning) textContent += `\\n\\n\u26a0\ufe0f ${fileWarning}`;\n\n// \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c messages content array\nconst messagesContent = [\n  {\n    type: \"text\",\n    text: textContent\n  }\n];\n\n// \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c image \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c\nif (base64Image && mimeType) {\n  messagesContent.push({\n    type: \"image_url\",\n    image_url: {\n      url: `data:${mimeType};base64,${base64Image}`\n    }\n  });\n}\n\n// \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c audio \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c (\u0434\u043b\u044f audio \u0438 video)\nif (audioData && (fileType === 'audio' || fileType === 'video')) {\n  const audioFormat = mimeType.includes('ogg') ? 'ogg' : 'wav';\n  messagesContent.push({\n    type: \"input_audio\",\n    input_audio: {\n      data: audioData,\n      format: audioFormat\n    }\n  });\n}\n\nconsole.log('\ud83d\udcdd Messages content prepared:', JSON.stringify(messagesContent).substring(0, 200));\n\nreturn [{\n  json: {\n    ...$input.item.json,\n    messages_content: messagesContent\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1920,
        928
      ],
      "id": "d6ee30a7-fdcf-43dd-ba0c-f409610bed03",
      "name": "Prepare AI Messages"
    },
    {
      "parameters": {
        "jsCode": "// \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 JSON \u0434\u043b\u044f OpenRouter AI\nconst studentName = $('Edit Fields').item.json.student_name || '\u0421\u0442\u0443\u0434\u0435\u043d\u0442';\nconst lessonDesc = $('Edit Fields').item.json.lesson_desc || '\u041e\u0446\u0435\u043d\u0438\u0442\u044c \u0414\u0417';\nconst messagesContent = $input.item.json.messages_content || [];\n\nconsole.log(`\ud83e\udd16 \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a \u0418\u0418 \u0434\u043b\u044f ${studentName}`);\n\nreturn [{\n  json: {\n    openrouter_request: {\n      model: 'google/gemini-2.5-flash',\n      response_format: { type: 'json_object' },\n      messages: [\n        {\n          role: 'system',\n          content: `\u0422\u044b \u043c\u0443\u0434\u0440\u044b\u0439 \u043d\u0430\u0441\u0442\u0430\u0432\u043d\u0438\u043a \u043d\u0430 \u043e\u043d\u043b\u0430\u0439\u043d-\u043a\u0443\u0440\u0441\u0435. \u0418\u043c\u044f \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430: ${studentName}.\\n\\n\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0437\u0430\u0434\u0430\u043d\u0438\u044f:\\n${lessonDesc}\\n\\n\u0422\u0412\u041e\u0418 \u041f\u0420\u0410\u0412\u0418\u041b\u0410:\\n1. \u041e\u0446\u0435\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0443. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0444\u043e\u0442\u043e \u2014 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u043e\u043d\u043e \u0437\u0430\u0434\u0430\u043d\u0438\u044e.\\n2. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0430\u0443\u0434\u0438\u043e/\u0432\u0438\u0434\u0435\u043e \u2014 \u0418\u0418 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0430\u0443\u0434\u0438\u043e.\\n3. \u0415\u0441\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430 \u043e\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u0430\u044f \u2014 \u0441\u0442\u0430\u0432\u044c \"is_approved\": true. \u0411\u0435\u0441\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u0430\u044f \u2014 false.\\n4. \u0422\u0432\u043e\u0439 \"feedback_text\" \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043b\u0438\u0447\u043d\u044b\u043c, \u043e\u0431\u043e\u0434\u0440\u044f\u044e\u0449\u0438\u043c, \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c\u0438 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f\u043c\u0438.\\n5. \u0415\u0441\u043b\u0438 \u0441\u0442\u0443\u0434\u0435\u043d\u0442 \u043f\u0440\u0438\u0441\u043b\u0430\u043b \u0444\u043e\u0442\u043e \u2014 \u0443\u043f\u043e\u043c\u044f\u043d\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0434\u0435\u0442\u0430\u043b\u0438.\\n\\n\u041e\u0442\u0432\u0435\u0442 \u0421\u0422\u0420\u041e\u0413\u041e \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON: {\"is_approved\": boolean, \"feedback_text\": \"string\"}`\n        },\n        {\n          role: 'user',\n          content: messagesContent\n        }\n      ]\n    }\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2128,
        1104
      ],
      "id": "61288c47-8205-4a02-bb33-b9be1463b572",
      "name": "Prepare OpenRouter JSON"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://openrouter.ai/api/v1/chat/completions",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "openRouterApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "HTTP-Referer",
              "value": "https://n8n.indikov.ru"
            },
            {
              "name": "X-Title",
              "value": "AntBot Homework Checker"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.openrouter_request }}",
        "options": {
          "timeout": 60000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2368,
        1280
      ],
      "id": "a9086ae4-f10f-4b62-8dae-56eb77a67ab3",
      "name": "OpenRouter AI",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000,
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "jsCode": "// \u041f\u0430\u0440\u0441\u0438\u043d\u0433 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 OpenRouter\ntry {\n  const rawResponse = $input.item.json.choices[0].message.content;\n  \n  console.log('\ud83e\udd14 \u0421\u044b\u0440\u043e\u0439 \u043e\u0442\u0432\u0435\u0442 \u0418\u0418:', rawResponse.substring(0, 200));\n  \n  const jsonMatch = rawResponse.match(/(\\{[\\s\\S]*\\})/);\n  \n  if (!jsonMatch || !jsonMatch[1]) {\n    throw new Error('\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0438\u0437\u0432\u043b\u0435\u0447\u044c JSON \u0438\u0437 \u043e\u0442\u0432\u0435\u0442\u0430 \u0418\u0418');\n  }\n  \n  const parsedData = JSON.parse(jsonMatch[1]);\n  \n  if (typeof parsedData.is_approved !== 'boolean') {\n    throw new Error('is_approved \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c boolean');\n  }\n  \n  if (typeof parsedData.feedback_text !== 'string') {\n    throw new Error('feedback_text \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c string');\n  }\n  \n  return {\n    json: {\n      is_approved: parsedData.is_approved,\n      feedback_text: parsedData.feedback_text,\n      ai_raw_response: rawResponse\n    }\n  };\n} catch (error) {\n  console.error('\u274c \u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430:', error.message);\n  \n  return {\n    json: {\n      is_approved: true,\n      feedback_text: `\u26a0\ufe0f \u0412\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043f\u0440\u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0435 \u0418\u0418, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u043e\u0434\u043e\u0431\u0440\u0435\u043d\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438. \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435!\\n\\n(\u041e\u0448\u0438\u0431\u043a\u0430: ${error.message})`,\n      ai_raw_response: $input.item.json.choices?.[0]?.message?.content || '\u041d\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0430',\n      parse_error: true\n    }\n  };\n}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2560,
        1088
      ],
      "id": "cf9e90bc-443b-41bf-bf28-b05ebdf08fd0",
      "name": "Parse JSON Response",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Webhook-homework').item.json.body.callback_webhook_url_result }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-CALLBACK-SIGNATURE",
              "value": "=500"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "feedback_text",
              "value": "={{ $('Parse JSON Response').item.json.feedback_text }}"
            },
            {
              "name": "is_approved",
              "value": "={{ $('Parse JSON Response').item.json.is_approved }}"
            },
            {
              "name": "original_admin_message_id",
              "value": "={{ $('Webhook-homework').item.json.body.original_admin_message_id || $('Webhook-homework').item.json.body.admin_message_id }}"
            },
            {
              "name": "student_user_id",
              "value": "={{ $('Edit Fields').item.json.student_user_id }}"
            },
            {
              "name": "course_numeric_id",
              "value": "={{ $('Webhook-homework').item.json.body.course_numeric_id }}"
            },
            {
              "name": "lesson_num",
              "value": "={{ $('Webhook-homework').item.json.body.lesson_num }}"
            }
          ]
        },
        "options": {
          "timeout": 30000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2816,
        1088
      ],
      "id": "cb1c729a-634b-4cd2-ae11-ed87293dcbf3",
      "name": "HTTP Request",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Webhook-homework').item.json.body.callback_webhook_url_result }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-CALLBACK-SIGNATURE",
              "value": "=500"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "feedback_text",
              "value": "=\u26a0\ufe0f \u0412\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043f\u0440\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0414\u0417, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u043e\u0434\u043e\u0431\u0440\u0435\u043d\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438. \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435!"
            },
            {
              "name": "is_approved",
              "value": "=true"
            },
            {
              "name": "original_admin_message_id",
              "value": "={{ $('Webhook-homework').item.json.body.original_admin_message_id || $('Webhook-homework').item.json.body.admin_message_id }}"
            },
            {
              "name": "student_user_id",
              "value": "={{ $('Edit Fields').item.json.student_user_id }}"
            },
            {
              "name": "course_numeric_id",
              "value": "={{ $('Webhook-homework').item.json.body.course_numeric_id }}"
            },
            {
              "name": "lesson_num",
              "value": "={{ $('Webhook-homework').item.json.body.lesson_num }}"
            },
            {
              "name": "error_details",
              "value": "={{ $json.error }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2816,
        1248
      ],
      "id": "b07bd967-d9cd-4c76-b4cc-c2555b3c769c",
      "name": "HTTP Request (Error Fallback)",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "## \ud83d\udea8 \u041e\u0428\u0418\u0411\u041a\u0410 \u0412\u041e\u0420\u041a\u0424\u041b\u041e\u0423\n\n\u0415\u0441\u043b\u0438 \u0432\u044b \u0432\u0438\u0434\u0438\u0442\u0435 \u044d\u0442\u043e \u2014 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0414\u0417.\n\n**\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u044b:**\n- OpenRouter API \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d\n- \u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0444\u0430\u0439\u043b\u0430 \u043e\u0442 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430\n- \u041f\u0440\u0435\u0432\u044b\u0448\u0435\u043d \u043b\u0438\u043c\u0438\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438\n\n**\u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c:**\n1. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043b\u043e\u0433\u0438 n8n: `docker compose logs n8n`\n2. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0431\u0430\u043b\u0430\u043d\u0441 OpenRouter\n3. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c \u0447\u0442\u043e \u0444\u0430\u0439\u043b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u043b\u0441\u044f \u0438\u0437 Telegram",
        "height": 460,
        "width": 592
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2816,
        1408
      ],
      "id": "d78f8d0e-597a-4209-8301-32bde8469226",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## \ud83d\udcca \u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\n\n\u0412\u0441\u0435 \u044d\u0442\u0430\u043f\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043b\u043e\u0433\u0438\u0440\u0443\u044e\u0442\u0441\u044f:\n- \ud83d\udcf8 \u0424\u043e\u0442\u043e: \u0440\u0430\u0437\u043c\u0435\u0440, MIME \u0442\u0438\u043f\n- \ud83c\udfa7 \u0410\u0443\u0434\u0438\u043e: \u0440\u0430\u0437\u043c\u0435\u0440, \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u044f \u0435\u0441\u043b\u0438 >10 \u041c\u0411\n- \ud83c\udfa5 \u0412\u0438\u0434\u0435\u043e: \u0440\u0430\u0437\u043c\u0435\u0440, \u0442\u0438\u043f \u0444\u0430\u0439\u043b\u0430\n- \ud83e\udd14 \u041e\u0442\u0432\u0435\u0442 \u0418\u0418: \u043f\u0435\u0440\u0432\u044b\u0435 200 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432\n- \u274c \u041e\u0448\u0438\u0431\u043a\u0438: \u0434\u0435\u0442\u0430\u043b\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430\n\n**\u0414\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043b\u043e\u0433\u043e\u0432:**\n```bash\ndocker compose logs n8n | grep -E \"\ud83d\udcf8|\ud83c\udfa7|\ud83c\udfa5|\ud83e\udd14|\u274c\"\n```",
        "height": 314,
        "width": 350
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1488,
        1280
      ],
      "id": "f6c479b0-9f96-4736-bf2f-0ba3e72cd5ea",
      "name": "Sticky Note1"
    }
  ],
  "connections": {
    "Webhook-homework": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If": {
      "main": [
        [
          {
            "node": "Get a file",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Text Messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Text Messages": {
      "main": [
        [
          {
            "node": "Prepare OpenRouter JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get a file": {
      "main": [
        [
          {
            "node": "Route File Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route File Type": {
      "main": [
        [
          {
            "node": "Process Photo",
            "type": "main",
            "index": 0
          },
          {
            "node": "Process Audio",
            "type": "main",
            "index": 0
          },
          {
            "node": "Process Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Photo": {
      "main": [
        [
          {
            "node": "Prepare AI Messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Audio": {
      "main": [
        [
          {
            "node": "Prepare AI Messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Video": {
      "main": [
        [
          {
            "node": "Prepare AI Messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare AI Messages": {
      "main": [
        [
          {
            "node": "Prepare OpenRouter JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare OpenRouter JSON": {
      "main": [
        [
          {
            "node": "OpenRouter AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter AI": {
      "main": [
        [
          {
            "node": "Parse JSON Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HTTP Request (Error Fallback)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse JSON Response": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HTTP Request (Error Fallback)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  },
  "versionId": "e776f1ec-eaf8-436f-8f89-4a80238c0993",
  "id": "vzQALMCXBCd11Epz",
  "tags": []
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

good2AI Agent in n8n (Multimodal). Uses telegram, httpRequest. Webhook trigger; 17 nodes.

Source: https://github.com/andrjur/antbot4/blob/main/n8n_flow.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

🤖 Telegram Messaging Agent for Text/Audio/Images. Uses telegram, httpRequest. Webhook trigger; 39 nodes.

Telegram, HTTP Request
AI & RAG

AI Phone Agent with RetellAI. Uses telegram, googleCalendar, httpRequest, googleDrive. Webhook trigger; 36 nodes.

Telegram, Google Calendar, HTTP Request +1
AI & RAG

Trato Hecho - Chat Agent. Uses httpRequest, telegram, gmail. Webhook trigger; 26 nodes.

HTTP Request, Telegram, Gmail
AI & RAG

Trato Hecho - Chat Agent. Uses httpRequest, telegram, gmail. Webhook trigger; 26 nodes.

HTTP Request, Telegram, Gmail
AI & RAG

Local AI Agent (HTTP-based). Uses telegram, httpRequest. Webhook trigger; 24 nodes.

Telegram, HTTP Request