{
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "gen-document",
        "options": {}
      },
      "id": "doc-webhook-id",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        1500,
        200
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "cfg-api-domain",
              "name": "api_domain",
              "value": "https://9router.n8n71.com/v1",
              "type": "string"
            },
            {
              "id": "cfg-lms-domain",
              "name": "lms_domain",
              "value": "https://lms.n8n71.com",
              "type": "string"
            },
            {
              "id": "cfg-key",
              "name": "api_key",
              "value": "",
              "type": "string"
            },
            {
              "id": "cfg-model",
              "name": "model",
              "value": "tesstm3",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "doc-setup-config-id",
      "name": "Setup Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1720,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "return $input.all().map(item => {\n  const p = item.json.body || {};\n  const lesson = p.lesson || {};\n  const session = p.session || {};\n  const course = p.course || {};\n\n  const systemPrompt = [\n    'B\u1ea1n l\u00e0 m\u1ed9t gi\u00e1o vi\u00ean l\u1eadp tr\u00ecnh K-12 nhi\u1ec1u kinh nghi\u1ec7m, \u0111ang so\u1ea1n t\u00e0i li\u1ec7u b\u00e0i h\u1ecdc b\u1eb1ng ti\u1ebfng Vi\u1ec7t, v\u0103n phong \u0111\u01a1n gi\u1ea3n, g\u1ea7n g\u0169i v\u1edbi h\u1ecdc sinh ph\u1ed5 th\u00f4ng.',\n    '',\n    'QUY T\u1eaeC B\u1eaeT BU\u1ed8C (kh\u00f4ng \u0111\u01b0\u1ee3c vi ph\u1ea1m):',\n    '1. CH\u1ec8 tr\u1ea3 v\u1ec1 HTML thu\u1ea7n, d\u00f9ng c\u00e1c th\u1ebb h2, h3, p, ul, li, pre, code. TUY\u1ec6T \u0110\u1ed0I KH\u00d4NG d\u00f9ng markdown (kh\u00f4ng **, kh\u00f4ng #, kh\u00f4ng ```).',\n    '2. C\u00f4ng th\u1ee9c to\u00e1n (n\u1ebfu c\u00f3) vi\u1ebft d\u1ea1ng LaTeX b\u1ecdc trong d\u1ea5u $...$.',\n    '3. N\u1ebfu c\u00f3 v\u00ed d\u1ee5 code, d\u00f9ng Python ng\u1eafn g\u1ecdn, c\u00f3 ch\u00fa th\u00edch b\u1eb1ng ti\u1ebfng Vi\u1ec7t, \u0111\u1eb7t trong th\u1ebb <pre><code>.',\n    '4. C\u1ea5u tr\u00fac t\u00e0i li\u1ec7u: m\u1edf \u0111\u1ea7u ng\u1eafn g\u1ee3i \u0111\u1ed9ng l\u1ef1c, n\u1ed9i dung ch\u00ednh chia theo h3, v\u00ed d\u1ee5 minh ho\u1ea1, t\u00f3m t\u1eaft cu\u1ed1i b\u00e0i.',\n    '5. Sau ph\u1ea7n HTML, b\u1eaft bu\u1ed9c th\u00eam m\u1ed9t d\u00f2ng ph\u00e2n c\u00e1ch ch\u00ednh x\u00e1c l\u00e0 ===QUESTIONS=== r\u1ed3i li\u1ec7t k\u00ea \u0111\u00fang 3 c\u00e2u h\u1ecfi \u00f4n t\u1eadp ng\u1eafn d\u01b0\u1edbi d\u1ea1ng JSON array thu\u1ea7n, m\u1ed7i ph\u1ea7n t\u1eed c\u00f3 d\u1ea1ng {\"question\":\"...\",\"answer\":\"...\"}. Kh\u00f4ng th\u00eam ch\u1eef n\u00e0o kh\u00e1c sau JSON array.'\n  ].join('\\n');\n\n  const userPrompt = `So\u1ea1n t\u00e0i li\u1ec7u cho b\u00e0i h\u1ecdc sau:\\n- Kh\u00f3a h\u1ecdc: ${course.title || ''}\\n- Ch\u01b0\u01a1ng: ${session.title || ''} (${session.description || ''})\\n- B\u00e0i h\u1ecdc: ${lesson.title || ''}\\n- M\u00f4 t\u1ea3: ${lesson.description || ''}`;\n\n  return { json: {\n    systemPrompt, userPrompt,\n    lesson_id: p.lesson_id,\n    lesson_title: lesson.title || 'B\u00e0i h\u1ecdc'\n  } };\n});"
      },
      "id": "doc-build-prompt-id",
      "name": "Build Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1940,
        200
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Setup Config').first().json.api_domain }}/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Setup Config').first().json.api_key }}"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model: $('Setup Config').first().json.model, temperature: 0.4, messages: [ {role:'system', content: $json.systemPrompt}, {role:'user', content: $json.userPrompt} ] }) }}",
        "options": {
          "timeout": 120000
        },
        "retryOnFail": true,
        "maxTries": 3,
        "waitBetweenTries": 3000
      },
      "id": "doc-call-llm-id",
      "name": "Call LLM",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2160,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "return $input.all().map(item => {\n  const raw = item.json.choices?.[0]?.message?.content || '';\n  const parts = raw.split('===QUESTIONS===');\n\n  const stripFence = (s) => (s || '')\n    .trim()\n    .replace(/^```(?:html?)?\\n?/i, '')\n    .replace(/```\\s*$/i, '')\n    .trim();\n\n  let documentHtml = stripFence(parts[0]);\n\n  let questionDocuments = [];\n  if (parts[1]) {\n    try {\n      const m = parts[1].match(/\\[[\\s\\S]*\\]/);\n      if (m) {\n        const arr = JSON.parse(m[0]);\n        if (Array.isArray(arr)) {\n          questionDocuments = arr\n            .filter(q => q && (q.question || q.answer))\n            .map(q => ({\n              question: String(q.question || '').trim(),\n              answer: String(q.answer || '').trim()\n            }));\n        }\n      }\n    } catch (e) {\n      questionDocuments = [];\n    }\n  }\n\n  const bp = $('Build Prompt').first().json;\n  return { json: {\n    lesson_id: bp.lesson_id,\n    title: 'T\u00e0i li\u1ec7u: ' + bp.lesson_title,\n    document: documentHtml,\n    questionDocuments\n  } };\n});"
      },
      "id": "doc-parse-output-id",
      "name": "Parse & Normalize Output",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2380,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "return $input.all().map(item => {\n  let html = item.json.document || '';\n  html = html.replace(/<h2>/g, '<h2 style=\"color: #1a73e8; font-size: 1.45em; border-bottom: 1px solid #e8eaed; padding-bottom: 8px; margin-top: 28px; margin-bottom: 14px; font-weight: 500;\">');\n  html = html.replace(/<h3>/g, '<h3 style=\"color: #202124; font-size: 1.2em; margin-top: 20px; margin-bottom: 10px; font-weight: 500;\">');\n  html = html.replace(/<pre>/g, '<pre style=\"background: #f8f9fa; border: 1px solid #dadce0; border-radius: 8px; padding: 16px; overflow-x: auto; margin: 18px 0; font-family: \\'Fira Code\\', Consolas, monospace; font-size: 13.5px; line-height: 1.5;\">');\n  html = html.replace(/<ul>/g, '<ul style=\"padding-left: 22px; margin: 14px 0;\">');\n  html = html.replace(/<li>/g, '<li style=\"margin-bottom: 8px; line-height: 1.6;\">');\n  const formattedDoc = `\\n<div class=\"lms-reader-container\" style=\"font-family: 'Inter', sans-serif; color: #3c4043; line-height: 1.65; max-width: 800px; margin: 0 auto; padding: 12px 0;\">\\n  ${html}\\n</div>\\n`;\n  item.json.document = formattedDoc;\n  return item;\n});"
      },
      "id": "doc-format-html-id",
      "name": "Format HTML Document",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2580,
        200
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Setup Config').first().json.lms_domain }}/automation/document",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json) }}",
        "options": {
          "allowUnauthorizedCerts": true,
          "timeout": 30000
        }
      },
      "id": "doc-post-lms-id",
      "name": "POST to LMS (review queue)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2780,
        200
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Setup Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Setup Config": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Prompt": {
      "main": [
        [
          {
            "node": "Call LLM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call LLM": {
      "main": [
        [
          {
            "node": "Parse & Normalize Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Normalize Output": {
      "main": [
        [
          {
            "node": "Format HTML Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format HTML Document": {
      "main": [
        [
          {
            "node": "POST to LMS (review queue)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}