feat: kb_writer 마이크로서비스 + mail_bridge 추가
- kb_writer.py: DEVONthink AppleScript 브릿지 → 마크다운 파일 기반 전환 (포트 8095) - knowledge-base/ 디렉토리 구조 (note, chat-memory, news) - Handle Note: kb_writer 파일 저장 + Qdrant 임베딩 추가 - Embed & Save Memory: DEVONthink → kb_writer 교체 - mail_bridge.py: IMAP 날짜 기반 메일 조회 (포트 8094) - mail-processing-pipeline: IMAP Trigger → Schedule + mail_bridge + dedup - docker-compose, manage_services, LaunchAgent plist 업데이트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,25 +4,19 @@
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"mailbox": "INBOX",
|
||||
"postProcessAction": "read",
|
||||
"options": {
|
||||
"customEmailConfig": "{ \"host\": \"{{$env.IMAP_HOST || '192.168.1.227'}}\", \"port\": {{$env.IMAP_PORT || 993}}, \"secure\": true, \"auth\": { \"user\": \"{{$env.IMAP_USER}}\", \"pass\": \"{{$env.IMAP_PASSWORD}}\" } }"
|
||||
},
|
||||
"pollTimes": {
|
||||
"item": [
|
||||
"rule": {
|
||||
"interval": [
|
||||
{
|
||||
"mode": "everyX",
|
||||
"value": 15,
|
||||
"unit": "minutes"
|
||||
"field": "minutes",
|
||||
"minutesInterval": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "m1000001-0000-0000-0000-000000000001",
|
||||
"name": "IMAP Trigger",
|
||||
"type": "n8n-nodes-base.imapEmail",
|
||||
"typeVersion": 2,
|
||||
"id": "m1000001-0000-0000-0000-000000000010",
|
||||
"name": "Schedule Trigger",
|
||||
"type": "n8n-nodes-base.scheduleTrigger",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
0,
|
||||
300
|
||||
@@ -30,14 +24,52 @@
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const items = $input.all();\nconst results = [];\nfor (const item of items) {\n const j = item.json;\n const from = j.from?.text || j.from || '';\n const subject = (j.subject || '').substring(0, 500);\n const body = (j.text || j.textPlain || j.html || '').substring(0, 5000)\n .replace(/<[^>]*>/g, '').replace(/\\s+/g, ' ').trim();\n const mailDate = j.date || new Date().toISOString();\n results.push({ json: { from, subject, body, mailDate, messageId: j.messageId || '' } });\n}\nreturn results;"
|
||||
"method": "GET",
|
||||
"url": "={{ $env.MAIL_BRIDGE_URL }}/recent?days=1",
|
||||
"options": {
|
||||
"timeout": 15000
|
||||
}
|
||||
},
|
||||
"id": "m1000001-0000-0000-0000-000000000011",
|
||||
"name": "Fetch Mails",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
220,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "executeQuery",
|
||||
"query": "SELECT message_id FROM mail_logs WHERE mail_date >= NOW() - INTERVAL '2 days'",
|
||||
"options": {}
|
||||
},
|
||||
"id": "m1000001-0000-0000-0000-000000000012",
|
||||
"name": "Get Existing IDs",
|
||||
"type": "n8n-nodes-base.postgres",
|
||||
"typeVersion": 2.5,
|
||||
"position": [
|
||||
440,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"postgres": {
|
||||
"id": "KaxU8iKtraFfsrTF",
|
||||
"name": "bot-postgres"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "const mailsResponse = $('Fetch Mails').first().json;\nconst mails = mailsResponse.mails || [];\nconst existingRows = $input.all();\nconst existingIds = new Set(existingRows.map(r => r.json.message_id).filter(Boolean));\n\nconst results = [];\nfor (const mail of mails) {\n const mid = mail.messageId || '';\n if (!mid || existingIds.has(mid)) continue;\n results.push({ json: {\n from: mail.from || '',\n subject: (mail.subject || '').substring(0, 500),\n body: (mail.text || '').substring(0, 5000).replace(/<[^>]*>/g, '').replace(/\\s+/g, ' ').trim(),\n mailDate: mail.date || new Date().toISOString(),\n messageId: mid\n }});\n}\nreturn results;"
|
||||
},
|
||||
"id": "m1000001-0000-0000-0000-000000000002",
|
||||
"name": "Parse Mail",
|
||||
"name": "Parse & Filter New",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
220,
|
||||
660,
|
||||
300
|
||||
]
|
||||
},
|
||||
@@ -50,14 +82,14 @@
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
440,
|
||||
880,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "executeQuery",
|
||||
"query": "=INSERT INTO mail_logs (from_address,subject,summary,label,has_events,has_tasks,mail_date) VALUES ('{{ ($json.from||'').replace(/'/g,\"''\").substring(0,255) }}','{{ ($json.subject||'').replace(/'/g,\"''\").substring(0,500) }}','{{ ($json.summary||'').replace(/'/g,\"''\").substring(0,2000) }}','{{ $json.label }}',{{ $json.has_events }},{{ $json.has_tasks }},'{{ $json.mailDate }}')",
|
||||
"query": "=INSERT INTO mail_logs (from_address,subject,summary,label,has_events,has_tasks,mail_date,message_id) VALUES ('{{ ($json.from||'').replace(/'/g,\"''\").substring(0,255) }}','{{ ($json.subject||'').replace(/'/g,\"''\").substring(0,500) }}','{{ ($json.summary||'').replace(/'/g,\"''\").substring(0,2000) }}','{{ $json.label }}',{{ $json.has_events }},{{ $json.has_tasks }},'{{ $json.mailDate }}','{{ ($json.messageId||'').replace(/'/g,\"''\").substring(0,500) }}') ON CONFLICT (message_id) DO NOTHING",
|
||||
"options": {}
|
||||
},
|
||||
"id": "m1000001-0000-0000-0000-000000000004",
|
||||
@@ -65,7 +97,7 @@
|
||||
"type": "n8n-nodes-base.postgres",
|
||||
"typeVersion": 2.5,
|
||||
"position": [
|
||||
660,
|
||||
1100,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
@@ -84,7 +116,7 @@
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
880,
|
||||
1320,
|
||||
300
|
||||
]
|
||||
},
|
||||
@@ -125,7 +157,7 @@
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2.2,
|
||||
"position": [
|
||||
1100,
|
||||
1540,
|
||||
300
|
||||
]
|
||||
},
|
||||
@@ -145,24 +177,46 @@
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1320,
|
||||
1760,
|
||||
200
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"IMAP Trigger": {
|
||||
"Schedule Trigger": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse Mail",
|
||||
"node": "Fetch Mails",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse Mail": {
|
||||
"Fetch Mails": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Get Existing IDs",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Get Existing IDs": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse & Filter New",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse & Filter New": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
@@ -222,4 +276,4 @@
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user