{
  "name": "n8n_flow",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "aa46a723-619e-42e9-8e51-49ba51813718",
        "authentication": "headerAuth",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        192,
        1216
      ],
      "id": "0590c5f6-8164-4ee0-b5c0-91211b88d496",
      "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": [
        400,
        1216
      ],
      "id": "9ad9c3dc-01f3-4787-9b46-d4ff55e43163",
      "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').first().json.hw_file_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        608,
        1216
      ],
      "id": "ec3fb10a-4e02-43f7-81e6-c7b5c52fc219",
      "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.first().json.hw_text || $('Edit Fields').first().json.hw_text || '[\u0422\u0435\u043a\u0441\u0442 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442]';\nconst studentName = $('Edit Fields').first().json.student_name || '\u0421\u0442\u0443\u0434\u0435\u043d\u0442';\nconst lessonDesc = $('Edit Fields').first().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.first().json,\n    messages_content: messagesContent\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        864,
        1440
      ],
      "id": "3abe1ac7-fa0a-4e3a-8c22-95f0bdd56e6e",
      "name": "Prepare Text Messages"
    },
    {
      "parameters": {
        "resource": "file",
        "fileId": "={{ $('Edit Fields').item.json.hw_file_id }}",
        "additionalFields": {
          "mimeType": ""
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        800,
        1280
      ],
      "id": "46f93837-0c47-4bfa-a5e3-0bd8b54bc8ad",
      "name": "Get a file",
      "alwaysOutputData": false,
      "retryOnFail": true,
      "waitBetweenTries": 200,
      "maxTries": 2,
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "dataType": "string",
        "value1": "={{ ['jpg', 'jpeg', 'png'].includes($binary.data.fileExtension) || $binary.data.mimeType.startsWith('image') ? 'image' :['ogg', 'mp3', 'wav', 'm4a', 'oga'].includes($binary.data.fileExtension) || $binary.data.mimeType.startsWith('audio') ? 'audio' : ['mp4', 'mov', 'avi'].includes($binary.data.fileExtension) || $binary.data.mimeType.startsWith('video') ? 'video' : 'unknown' }}",
        "rules": {
          "rules": [
            {
              "operation": "startsWith",
              "value2": "image"
            },
            {
              "operation": "startsWith",
              "value2": "audio"
            },
            {
              "operation": "startsWith",
              "value2": "video"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 2,
      "position": [
        976,
        1200
      ],
      "id": "4798db87-2e90-4c51-943a-7d9f37e7607a",
      "name": "Switch",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "jsCode": "const item = $input.first();\nif (!item || !item.binary || !item.binary.data) return[];\n\n// \u0427\u0438\u0442\u0430\u0435\u043c \u0420\u0415\u0410\u041b\u042c\u041d\u042b\u0419 \u0444\u0430\u0439\u043b \u0441 \u0434\u0438\u0441\u043a\u0430 n8n \u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u043c \u0432 Base64\nconst binaryBuffer = await this.helpers.getBinaryDataBuffer(0, 'data');\nconst actualBase64String = binaryBuffer.toString('base64');\n\n// \u0427\u0438\u043d\u0438\u043c \u043a\u0440\u0438\u0432\u043e\u0439 \u0442\u0438\u043f \u043e\u0442 \u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u0430\nlet mimeType = item.binary.data.mimeType;\nif (!mimeType || mimeType.includes('octet-stream')) {\n  mimeType = item.binary.data.fileExtension === 'png' ? 'image/png' : 'image/jpeg';\n}\n\nitem.json.base64_image = actualBase64String; \nitem.json.mime_type = mimeType;\nitem.json.file_type = 'image';\n\nreturn [item];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1184,
        1024
      ],
      "id": "833c517f-78d8-44c1-8303-faec9d653293",
      "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\n\nconst item = $input.first();\nif (!item || !item.binary || !item.binary.data) return[];\n\n// \u0427\u0438\u0442\u0430\u0435\u043c \u0420\u0415\u0410\u041b\u042c\u041d\u042b\u0419 \u0444\u0430\u0439\u043b \u0441 \u0434\u0438\u0441\u043a\u0430 n8n \u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u043c \u0432 Base64\nconst binaryBuffer = await this.helpers.getBinaryDataBuffer(0, 'data');\nconst actualBase64String = binaryBuffer.toString('base64');\n\nlet mimeType = item.binary.data.mimeType || 'audio/ogg';\nconst fileSize = item.binary.data.fileSize || 0;\n\nif (fileSize > 10 * 1024 * 1024) {\n  item.json.audio_warning = `\u0410\u0443\u0434\u0438\u043e \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0435. \u0418\u0418 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u044c.`;\n}\n\nitem.json.audio_data = actualBase64String;\nitem.json.file_type = 'audio';\nitem.json.mime_type = mimeType;\n\nreturn [item];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1184,
        1184
      ],
      "id": "c3698a97-e0d0-4d2a-a437-f31144211bd3",
      "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 item = $input.first();\nif (!item || !item.binary || !item.binary.data) return[];\n\n// \u0427\u0438\u0442\u0430\u0435\u043c \u0420\u0415\u0410\u041b\u042c\u041d\u042b\u0419 \u0444\u0430\u0439\u043b \u0441 \u0434\u0438\u0441\u043a\u0430 n8n \u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u043c \u0432 Base64\nconst binaryBuffer = await this.helpers.getBinaryDataBuffer(0, 'data');\nconst actualBase64String = binaryBuffer.toString('base64');\n\nlet mimeType = item.binary.data.mimeType || 'video/ogg';\nconst fileSize = item.binary.data.fileSize || 0;\n\nif (fileSize > 10 * 1024 * 1024) {\n  item.json.file_warning = `\u0424\u0430\u0439\u043b \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0439.`;\n}\n\nitem.json.audio_data = actualBase64String;\nitem.json.file_type = 'video';\nitem.json.mime_type = mimeType;\n\nreturn [item];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1184,
        1344
      ],
      "id": "a878bc4b-0795-448b-b520-d68b4d383b08",
      "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.first().json.hw_text || $('Edit Fields').first().json.hw_text || '[\u0422\u0435\u043a\u0441\u0442 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442]';\nconst audioWarning = $input.first().json.audio_warning || '';\nconst fileWarning = $input.first().json.file_warning || '';\nconst base64Image = $input.first().json.base64_image || null;\nconst mimeType = $input.first().json.mime_type || '';\nconst fileType = $input.first().json.file_type || '';\nconst audioData = $input.first().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\n// \ud83d\udd0d DEBUG \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438\nconsole.log('\ud83d\udd0d Prepare AI Messages DEBUG:');\nconsole.log('  base64Image:', base64Image ? '\u0415\u0421\u0422\u042c' : '\u041d\u0415\u0422');\nconsole.log('  mimeType:', mimeType || '\u041d\u0415\u0422');\nconsole.log('  fileType:', fileType || '\u041d\u0415\u0422');\nconsole.log('  audioData:', audioData ? '\u0415\u0421\u0422\u042c' : '\u041d\u0415\u0422');\nconsole.log('  messages_content:', JSON.stringify(messagesContent));\n\nreturn [{\n  json: {\n    ...$input.first().json,\n    messages_content: messagesContent\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1424,
        1184
      ],
      "id": "eb7d45ae-9201-477b-8630-7de2300226ae",
      "name": "Prepare AI Messages"
    },
    {
      "parameters": {
        "jsCode": "// \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 JSON \u0434\u043b\u044f OpenRouter AI\n// \u0411\u0435\u0440\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430 \u0438\u0437 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430\nconst studentName = $('Edit Fields').first().json.student_name || '\u0421\u0442\u0443\u0434\u0435\u043d\u0442';\nconst lessonDesc = $('Edit Fields').first().json.lesson_desc || '\u041e\u0446\u0435\u043d\u0438\u0442\u044c \u0414\u0417';\n\n// \u0411\u0435\u0440\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b\u0438 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u043d\u043e\u0434\u0430\u0445 (\u0442\u0435\u043a\u0441\u0442 + \u0444\u043e\u0442\u043e/\u0430\u0443\u0434\u0438\u043e)\nconst messagesContent = $input.first().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    // \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f OpenRouter\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": [
        1632,
        1360
      ],
      "id": "d2f1f377-3c5b-471d-ab92-e820df9b36c7",
      "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": [
        1872,
        1536
      ],
      "id": "eb48b57c-38bf-43fb-b9d6-392de4e4daa5",
      "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": [
        2064,
        1344
      ],
      "id": "4105ceaf-ec08-410a-8b88-12ee76b2aa25",
      "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": [
        2320,
        1344
      ],
      "id": "bd5ab723-2dd8-411a-90d8-676f47c96801",
      "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": [
        2320,
        1504
      ],
      "id": "de66127b-db2e-475b-9275-23351cab9e48",
      "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": [
        2320,
        1664
      ],
      "id": "53e3f5f9-6652-435c-a425-3304a8ef7f26",
      "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": [
        992,
        1536
      ],
      "id": "e88f3566-1eb5-49ae-8481-14d6821a200c",
      "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": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "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": true,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  },
  "versionId": "c3d33d06-a79b-4675-80f1-30b453df6a63",
  "id": "vzQALMCXBCd11Epz",
  "tags": []
}