66일차 교안/실습 추가
This commit is contained in:
1 parent
787d7d8514
commit
d7dc9dd68a
52 files changed
+6144
No files matched your search
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "빈 회의록",
|
||||
"notes": ""
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "분기 실적 공유",
|
||||
"notes": "오늘은 지난 분기 실적을 공유하고 질의응답을 했습니다. 별도 결정 사항은 없습니다."
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "10월 16일 주간 회의",
|
||||
"notes": "참석: 김민지, 이준호, 박서연. 1) 신규 고객 문의 응답 템플릿을 이준호가 금요일까지 정리한다. 2) 박서연은 다음 주 월요일까지 VPN 장애 보고서를 작성한다. 3) 서버 점검 일정은 김민지가 오늘 중 공지한다. 4) 회의실 예약 규칙 개선은 담당자를 다음 회의에서 정한다. 다음 회의는 10월 23일."
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
{
|
||||
"name": "66-01 Meeting notes to action items",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"httpMethod": "POST",
|
||||
"path": "meeting-actions",
|
||||
"responseMode": "responseNode",
|
||||
"options": {}
|
||||
},
|
||||
"id": "b0f12ecc-f34f-5b93-ab1a-b4f0e776cd07",
|
||||
"name": "Meeting webhook",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"webhookId": "fd884467-4d6e-5e1e-b81c-8d909d0348a5"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "a65c3a2e-b4c8-5087-a475-c6a858d9b7d6",
|
||||
"name": "llm_url",
|
||||
"value": "https://api.openai.com/v1",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "e30dbc5a-e549-5565-9f8f-96e55670f69f",
|
||||
"name": "model",
|
||||
"value": "gpt-4.1-mini",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "4ef048c7-0ac0-5913-b743-12cda43aa2b2",
|
||||
"name": "title",
|
||||
"value": "={{ $json.body.title || '제목 없음' }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "b901c535-f38f-5a59-975a-05074ce8044c",
|
||||
"name": "notes",
|
||||
"value": "={{ $json.body.notes }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"id": "99de8b0b-c43f-58dc-ad3d-543621575770",
|
||||
"name": "Settings",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
220,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "loose",
|
||||
"version": 2
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "41964561-0243-53d7-b1cd-0e64054d7460",
|
||||
"leftValue": "={{ $json.notes }}",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "notEmpty",
|
||||
"singleValue": true
|
||||
},
|
||||
"rightValue": ""
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "21232562-8565-5643-96a1-d643847e0ffb",
|
||||
"name": "Has notes?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2.2,
|
||||
"position": [
|
||||
440,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"respondWith": "json",
|
||||
"responseBody": "={{ { \"error\": \"notes is required\" } }}",
|
||||
"options": {
|
||||
"responseCode": 400
|
||||
}
|
||||
},
|
||||
"id": "076e2cf3-ed8d-5b8a-bd2c-026784a818e1",
|
||||
"name": "Reject empty",
|
||||
"type": "n8n-nodes-base.respondToWebhook",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
680,
|
||||
260
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "={{ $('Settings').first().json.llm_url }}/chat/completions",
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={{ JSON.stringify({ model: $('Settings').first().json.model, temperature: 0, response_format: { type: 'json_schema', json_schema: { name: 'reply', schema: {\"type\": \"object\", \"properties\": {\"actions\": {\"type\": \"array\", \"items\": {\"type\": \"object\", \"properties\": {\"task\": {\"type\": \"string\"}, \"owner\": {\"type\": \"string\"}, \"due\": {\"type\": \"string\"} }, \"required\": [\"task\", \"owner\", \"due\"]} } }, \"required\": [\"actions\"]} } }, messages: [ { role: 'system', content: \"Extract action items from the meeting notes. Answer in JSON: {\\\"actions\\\": [{\\\"task\\\": str, \\\"owner\\\": str, \\\"due\\\": str}]}. Write task in Korean. Use \\\"미정\\\" when the owner or due date is not stated. Return {\\\"actions\\\": []} when there is no action item.\" }, { role: 'user', content: $('Settings').first().json.notes } ] }) }}",
|
||||
"options": {
|
||||
"timeout": 180000
|
||||
},
|
||||
"authentication": "predefinedCredentialType",
|
||||
"nodeCredentialType": "openAiApi"
|
||||
},
|
||||
"id": "b704079a-e151-5b7f-814a-1e94e3ccd940",
|
||||
"name": "LLM extract actions",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
680,
|
||||
-120
|
||||
],
|
||||
"credentials": {
|
||||
"openAiApi": {
|
||||
"id": "openAiCourse0001",
|
||||
"name": "OpenAI (.env)"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Parse the LLM answer (JSON text) into a clean list of action items.\nconst raw = String($input.first().json.choices?.[0]?.message?.content ?? '').trim().replace(/^```(json)?\\s*|```$/g, '');\nlet data;\ntry {\n data = JSON.parse(raw);\n} catch (error) {\n return [{ json: { actions: [], count: 0, error: 'answer is not valid JSON' } }];\n}\nconst items = Array.isArray(data) ? data : (data.actions ?? []);\nconst actions = items\n .filter(item => item && String(item.task ?? '').trim())\n .map(item => ({\n task: String(item.task).trim(),\n owner: String(item.owner || '미정').trim() || '미정',\n due: String(item.due || '미정').trim() || '미정',\n }));\nreturn [{ json: { actions, count: actions.length } }];"
|
||||
},
|
||||
"id": "c78c7bb3-c72d-5ca2-ac9f-d541c024fa75",
|
||||
"name": "Parse actions",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
900,
|
||||
-120
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "={{ $('Settings').first().json.llm_url }}/chat/completions",
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={{ JSON.stringify({ model: $('Settings').first().json.model, temperature: 0, messages: [ { role: 'system', content: \"You summarize meeting notes. Reply only with the summary in Korean, at most 2 sentences. No English, no comments.\" }, { role: 'user', content: '다음 회의록을 요약하세요.\\n\\n회의록:\\n' + $('Settings').first().json.notes } ] }) }}",
|
||||
"options": {
|
||||
"timeout": 180000
|
||||
},
|
||||
"authentication": "predefinedCredentialType",
|
||||
"nodeCredentialType": "openAiApi"
|
||||
},
|
||||
"id": "ddb065b8-063a-5741-a301-577f004c04d3",
|
||||
"name": "LLM summarize",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
680,
|
||||
100
|
||||
],
|
||||
"credentials": {
|
||||
"openAiApi": {
|
||||
"id": "openAiCourse0001",
|
||||
"name": "OpenAI (.env)"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "1a7470e6-3557-5a05-b3c2-2b52762c1d54",
|
||||
"name": "summary",
|
||||
"value": "={{ $json.choices[0].message.content.trim() }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"id": "0e8b9b2f-e48c-591d-a712-a351cd715fd3",
|
||||
"name": "Keep summary",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
900,
|
||||
100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"mode": "combine",
|
||||
"combineBy": "combineByPosition",
|
||||
"options": {}
|
||||
},
|
||||
"id": "506361cb-50b7-5d5d-9dcc-76121628d788",
|
||||
"name": "Join results",
|
||||
"type": "n8n-nodes-base.merge",
|
||||
"typeVersion": 3,
|
||||
"position": [
|
||||
1120,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "loose",
|
||||
"version": 2
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "cdd4276c-6039-5731-aadf-bafdf9fdf535",
|
||||
"leftValue": "={{ $json.count }}",
|
||||
"operator": {
|
||||
"type": "number",
|
||||
"operation": "gt"
|
||||
},
|
||||
"rightValue": 0
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "bf7c1717-f207-5071-a0a8-961a65bfdbe3",
|
||||
"name": "Any actions?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2.2,
|
||||
"position": [
|
||||
1340,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"fieldToSplitOut": "actions",
|
||||
"options": {}
|
||||
},
|
||||
"id": "a9f538fb-61c0-5a8d-9051-9778db98a4d1",
|
||||
"name": "One item per action",
|
||||
"type": "n8n-nodes-base.splitOut",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
1560,
|
||||
-120
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "99cb6b63-de3c-560f-8170-b33332fb5cb9",
|
||||
"name": "task",
|
||||
"value": "={{ $json.task }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "ee9068cb-7666-5a5b-8937-d9c748333d6a",
|
||||
"name": "owner",
|
||||
"value": "={{ $json.owner }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "067da7cb-3f07-5f20-b45d-6f5fe45ca441",
|
||||
"name": "due",
|
||||
"value": "={{ $json.due }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "1efe8c52-179a-5a38-8648-f78d96bb8e88",
|
||||
"name": "priority",
|
||||
"value": "={{ ['오늘', '내일', '긴급'].some(w => $json.due.includes(w)) ? '높음' : '보통' }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"id": "000677ea-2fe7-5e70-9983-db85cafbde43",
|
||||
"name": "Normalize action",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
1780,
|
||||
-120
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"aggregate": "aggregateAllItemData",
|
||||
"destinationFieldName": "actions",
|
||||
"options": {}
|
||||
},
|
||||
"id": "1adf8b41-b947-52ea-939b-8c630e7b7c2b",
|
||||
"name": "Collect actions",
|
||||
"type": "n8n-nodes-base.aggregate",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
2000,
|
||||
-120
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Build the final result from the collected actions.\nconst settings = $('Settings').first().json;\nconst joined = $('Join results').first().json;\nconst actions = $input.first().json.actions;\nconst lines = actions.map((a, i) => `${i + 1}. [${a.priority}] ${a.task} - ${a.owner} (${a.due})`);\nreturn [{ json: {\n title: settings.title,\n route: '할 일 정리',\n count: actions.length,\n summary: joined.summary,\n actions,\n report_text: `${settings.title}\\n${joined.summary}\\n\\n${lines.join('\\n')}`,\n} }];"
|
||||
},
|
||||
"id": "5d19a847-10d1-565b-90ec-4476443e4a35",
|
||||
"name": "Build report",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
2220,
|
||||
-120
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "4fbd9776-6e85-560c-a217-529108a8b787",
|
||||
"name": "title",
|
||||
"value": "={{ $('Settings').first().json.title }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "709b7545-af8b-5be2-8b4a-add33d70849a",
|
||||
"name": "route",
|
||||
"value": "할 일 없음",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "6563e214-e619-5c86-a3a9-3b40608432ab",
|
||||
"name": "count",
|
||||
"value": "0",
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"id": "1b86f1f8-0486-5c45-853d-8ab5cf62c80c",
|
||||
"name": "summary",
|
||||
"value": "={{ $json.summary }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "406a4e0c-7283-5c3e-9762-52690b884289",
|
||||
"name": "actions",
|
||||
"value": "={{ [] }}",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"id": "19b6ad75-3169-59d3-bc1b-5196f43d8d59",
|
||||
"name": "No actions",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
1560,
|
||||
120
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"respondWith": "json",
|
||||
"responseBody": "={{ $json }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "b773d7a3-74dc-59f1-8e61-0279ce658cdb",
|
||||
"name": "Send result",
|
||||
"type": "n8n-nodes-base.respondToWebhook",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
2440,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Meeting webhook": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Settings",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Settings": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Has notes?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Has notes?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "LLM extract actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "LLM summarize",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Reject empty",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"LLM extract actions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse actions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Join results",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"LLM summarize": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Keep summary",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Keep summary": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Join results",
|
||||
"type": "main",
|
||||
"index": 1
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Join results": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Any actions?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Any actions?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "One item per action",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "No actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"One item per action": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Normalize action",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Normalize action": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Collect actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Collect actions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Build report",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Build report": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send result",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"No actions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send result",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"pinData": {},
|
||||
"id": "a6c07c353caf55"
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"name": "66 Practice 1 · parse text",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"name": "Start",
|
||||
"position": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"id": "188d4e06-7014-58e1-8053-cfebb3d2b1ac"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "d932ecca-eec2-5729-96c4-d0fe4e05ed98",
|
||||
"name": "content",
|
||||
"value": "{\"actions\": [{\"task\": \"신규 고객 문의 응답 템플릿 정리\", \"owner\": \"이준호\", \"due\": \"금요일\"}, {\"task\": \"회의실 예약 규칙 개선\", \"owner\": \"\", \"due\": \"\"}]}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"name": "Fake LLM answer",
|
||||
"position": [
|
||||
220,
|
||||
0
|
||||
],
|
||||
"id": "92fb2178-5944-5b66-8399-23529f0255f0"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Parse the answer text (JSON written as text) into a clean list of action items.\nconst raw = String($input.first().json.content ?? '').trim().replace(/^```(json)?\\s*|```$/g, '');\nlet data;\ntry {\n data = JSON.parse(raw);\n} catch (error) {\n return [{ json: { actions: [], count: 0, error: 'answer is not valid JSON' } }];\n}\nconst items = Array.isArray(data) ? data : (data.actions ?? []);\nconst actions = items\n .filter(item => item && String(item.task ?? '').trim())\n .map(item => ({\n task: String(item.task).trim(),\n owner: String(item.owner || '미정').trim() || '미정',\n due: String(item.due || '미정').trim() || '미정',\n }));\nreturn [{ json: { actions, count: actions.length } }];"
|
||||
},
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"name": "Parse actions",
|
||||
"position": [
|
||||
440,
|
||||
0
|
||||
],
|
||||
"id": "b97d203a-dcbf-5d31-9265-106a5f6a83aa"
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Start": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Fake LLM answer",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Fake LLM answer": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"pinData": {},
|
||||
"id": "a6c07c353c6610"
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
{
|
||||
"name": "66 Meeting notes (my)",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"httpMethod": "POST",
|
||||
"path": "my-meeting-actions",
|
||||
"responseMode": "responseNode",
|
||||
"options": {}
|
||||
},
|
||||
"id": "c3c17991-1bf8-5a91-abf1-f1cfdf0f12be",
|
||||
"name": "Meeting webhook",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"webhookId": "f65c6c90-0042-57c2-832a-bce70f02d66b"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "a65c3a2e-b4c8-5087-a475-c6a858d9b7d6",
|
||||
"name": "llm_url",
|
||||
"value": "https://api.openai.com/v1",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "e30dbc5a-e549-5565-9f8f-96e55670f69f",
|
||||
"name": "model",
|
||||
"value": "gpt-4.1-mini",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "4ef048c7-0ac0-5913-b743-12cda43aa2b2",
|
||||
"name": "title",
|
||||
"value": "={{ $json.body.title || '제목 없음' }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "b901c535-f38f-5a59-975a-05074ce8044c",
|
||||
"name": "notes",
|
||||
"value": "={{ $json.body.notes }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"id": "9f1fe720-925b-5518-9038-88631e8fc018",
|
||||
"name": "Settings",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
220,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "loose",
|
||||
"version": 2
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "41964561-0243-53d7-b1cd-0e64054d7460",
|
||||
"leftValue": "={{ $json.notes }}",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "notEmpty",
|
||||
"singleValue": true
|
||||
},
|
||||
"rightValue": ""
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "ceaaa37c-8541-574a-9fae-1bc55fd90a2a",
|
||||
"name": "Has notes?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2.2,
|
||||
"position": [
|
||||
440,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"respondWith": "json",
|
||||
"responseBody": "={{ { \"error\": \"notes is required\" } }}",
|
||||
"options": {
|
||||
"responseCode": 400
|
||||
}
|
||||
},
|
||||
"id": "35a8cb08-bc4c-502f-9176-e6414457c99e",
|
||||
"name": "Reject empty",
|
||||
"type": "n8n-nodes-base.respondToWebhook",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
660,
|
||||
120
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "={{ $('Settings').first().json.llm_url }}/chat/completions",
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={{ JSON.stringify({\n model: $('Settings').first().json.model,\n temperature: 0,\n response_format: { type: 'json_schema', json_schema: { name: 'reply', schema: {\n type: 'object',\n properties: {\n actions: { type: 'array', items: { type: 'object',\n properties: { task: { type: 'string' }, owner: { type: 'string' }, due: { type: 'string' } },\n required: ['task', 'owner', 'due'] } },\n },\n required: ['actions'],\n } } },\n messages: [\n { role: 'system', content: \"Extract action items from the meeting notes. Answer in JSON: {\\\"actions\\\": [{\\\"task\\\": str, \\\"owner\\\": str, \\\"due\\\": str}]}. Write task in Korean. Use \\\"미정\\\" when the owner or due date is not stated. Return {\\\"actions\\\": []} when there is no action item.\" },\n { role: 'user', content: $('Settings').first().json.notes },\n ],\n}) }}",
|
||||
"options": {
|
||||
"timeout": 180000
|
||||
},
|
||||
"authentication": "predefinedCredentialType",
|
||||
"nodeCredentialType": "openAiApi"
|
||||
},
|
||||
"id": "bab5c8f4-53c5-5623-b7c8-1f75f962e60b",
|
||||
"name": "LLM extract actions",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
660,
|
||||
-100
|
||||
],
|
||||
"credentials": {
|
||||
"openAiApi": {
|
||||
"id": "openAiCourse0001",
|
||||
"name": "OpenAI (.env)"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Parse the LLM answer (JSON text) into a clean list of action items.\nconst raw = String($input.first().json.choices?.[0]?.message?.content ?? '').trim().replace(/^```(json)?\\s*|```$/g, '');\nlet data;\ntry {\n data = JSON.parse(raw);\n} catch (error) {\n return [{ json: { actions: [], count: 0, error: 'answer is not valid JSON' } }];\n}\nconst items = Array.isArray(data) ? data : (data.actions ?? []);\nconst actions = items\n .filter(item => item && String(item.task ?? '').trim())\n .map(item => ({\n task: String(item.task).trim(),\n owner: String(item.owner || '미정').trim() || '미정',\n due: String(item.due || '미정').trim() || '미정',\n }));\nreturn [{ json: { actions, count: actions.length } }];"
|
||||
},
|
||||
"id": "2d12968a-6877-53a7-a7e4-ec7c51d893b1",
|
||||
"name": "Parse actions",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
880,
|
||||
-100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"respondWith": "json",
|
||||
"responseBody": "={{ $json }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "155b7034-4293-50ca-a6f6-71db885a2e06",
|
||||
"name": "Send result",
|
||||
"type": "n8n-nodes-base.respondToWebhook",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
1100,
|
||||
-100
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Meeting webhook": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Settings",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Settings": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Has notes?",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Has notes?": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "LLM extract actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Reject empty",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"LLM extract actions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse actions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send result",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"pinData": {},
|
||||
"id": "a6c07c353c6611"
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"name": "66 Practice 2 · loop and merge",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"name": "Start",
|
||||
"position": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"id": "188d4e06-7014-58e1-8053-cfebb3d2b1ac"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "8ee7c660-4702-575c-a2b7-cd64a157d621",
|
||||
"name": "actions",
|
||||
"value": "={{ [ { task: '신규 고객 문의 응답 템플릿 정리', owner: '이준호', due: '금요일' }, { task: '서버 점검 일정 공지', owner: '김민지', due: '오늘' }, { task: '회의실 예약 규칙 개선', owner: '미정', due: '미정' } ] }}",
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"name": "Sample actions",
|
||||
"position": [
|
||||
220,
|
||||
-100
|
||||
],
|
||||
"id": "f85d4eae-f60b-5f2e-a6f3-592638343b0c"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"fieldToSplitOut": "actions",
|
||||
"options": {}
|
||||
},
|
||||
"id": "5fa4a092-6961-574a-89fa-c2e05a5113f3",
|
||||
"name": "One item per action",
|
||||
"type": "n8n-nodes-base.splitOut",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
440,
|
||||
-100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "99cb6b63-de3c-560f-8170-b33332fb5cb9",
|
||||
"name": "task",
|
||||
"value": "={{ $json.task }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "ee9068cb-7666-5a5b-8937-d9c748333d6a",
|
||||
"name": "owner",
|
||||
"value": "={{ $json.owner }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "067da7cb-3f07-5f20-b45d-6f5fe45ca441",
|
||||
"name": "due",
|
||||
"value": "={{ $json.due }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "1efe8c52-179a-5a38-8648-f78d96bb8e88",
|
||||
"name": "priority",
|
||||
"value": "={{ ['오늘', '내일', '긴급'].some(w => $json.due.includes(w)) ? '높음' : '보통' }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"id": "3605a441-d86c-5f4a-98f5-2edfae18a003",
|
||||
"name": "Normalize action",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
660,
|
||||
-100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"aggregate": "aggregateAllItemData",
|
||||
"destinationFieldName": "actions",
|
||||
"options": {}
|
||||
},
|
||||
"id": "44e52bee-7b5a-547d-9c1c-3579d5499c85",
|
||||
"name": "Collect actions",
|
||||
"type": "n8n-nodes-base.aggregate",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
880,
|
||||
-100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "78c8fca5-5936-5934-b362-52f09a6df40f",
|
||||
"name": "summary",
|
||||
"value": "주간 회의에서 할 일 3건을 정했습니다. 서버 점검 공지는 오늘 안에 합니다.",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"includeOtherFields": false,
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"name": "Sample summary",
|
||||
"position": [
|
||||
220,
|
||||
120
|
||||
],
|
||||
"id": "d551b1bf-b437-5eb6-bde7-9391f51d468a"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"mode": "combine",
|
||||
"combineBy": "combineByPosition",
|
||||
"options": {}
|
||||
},
|
||||
"id": "41b96eeb-592f-5a28-a9a3-dc7e9b077939",
|
||||
"name": "Join results",
|
||||
"type": "n8n-nodes-base.merge",
|
||||
"typeVersion": 3,
|
||||
"position": [
|
||||
1100,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Start": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Sample actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Sample summary",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Sample actions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "One item per action",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"One item per action": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Normalize action",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Normalize action": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Collect actions",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Collect actions": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Join results",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Sample summary": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Join results",
|
||||
"type": "main",
|
||||
"index": 1
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"pinData": {},
|
||||
"id": "a6c07c353c6612"
|
||||
}
|
||||
Reference in new issue
Block a user