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 →
{
"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
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Gen Document. Uses httpRequest. Webhook trigger; 7 nodes.
Source: https://github.com/DoanDuyThanh71/lmsv1/blob/b8627a2c443760d9b77fad30d6fc6eac76b41714/n8n_workflows/gen_document.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.
This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c