247 lines
11 KiB
JSON
247 lines
11 KiB
JSON
|
|
{
|
||
|
|
"name": "Garvis Webhook - Bot Actions",
|
||
|
|
"nodes": [
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"httpMethod": "POST",
|
||
|
|
"path": "garvis",
|
||
|
|
"responseMode": "responseNode",
|
||
|
|
"options": {}
|
||
|
|
},
|
||
|
|
"name": "Webhook",
|
||
|
|
"type": "n8n-nodes-base.webhook",
|
||
|
|
"typeVersion": 2,
|
||
|
|
"position": [260, 300],
|
||
|
|
"webhookId": "garvis-webhook-001"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"conditions": {
|
||
|
|
"options": {
|
||
|
|
"caseSensitive": true,
|
||
|
|
"leftValue": "",
|
||
|
|
"typeValidation": "strict"
|
||
|
|
},
|
||
|
|
"conditions": [
|
||
|
|
{
|
||
|
|
"id": "auth1",
|
||
|
|
"leftValue": "={{ $json.headers['x-garvis-secret'] }}",
|
||
|
|
"rightValue": "={{ $env.GARVIS_WEBHOOK_SECRET }}",
|
||
|
|
"operator": {
|
||
|
|
"type": "string",
|
||
|
|
"operation": "equals"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"combinator": "and"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"name": "IF Auth Valid?",
|
||
|
|
"type": "n8n-nodes-base.if",
|
||
|
|
"typeVersion": 2,
|
||
|
|
"position": [480, 300]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"options": {},
|
||
|
|
"respondWith": "json",
|
||
|
|
"responseBody": "={\"error\": \"Unauthorized\", \"status\": 401}",
|
||
|
|
"responseCode": 401
|
||
|
|
},
|
||
|
|
"name": "Respond 401",
|
||
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
||
|
|
"typeVersion": 1.1,
|
||
|
|
"position": [700, 500]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"rules": {
|
||
|
|
"values": [
|
||
|
|
{"conditions": {"conditions": [{"leftValue": "={{ $json.body.action }}", "rightValue": "run_pipeline", "operator": {"type": "string", "operation": "equals"}}]}, "renameOutput": true, "outputKey": "Run Pipeline"},
|
||
|
|
{"conditions": {"conditions": [{"leftValue": "={{ $json.body.action }}", "rightValue": "check_nas", "operator": {"type": "string", "operation": "equals"}}]}, "renameOutput": true, "outputKey": "Check NAS"},
|
||
|
|
{"conditions": {"conditions": [{"leftValue": "={{ $json.body.action }}", "rightValue": "check_services", "operator": {"type": "string", "operation": "equals"}}]}, "renameOutput": true, "outputKey": "Check Services"},
|
||
|
|
{"conditions": {"conditions": [{"leftValue": "={{ $json.body.action }}", "rightValue": "send_message", "operator": {"type": "string", "operation": "equals"}}]}, "renameOutput": true, "outputKey": "Send Message"},
|
||
|
|
{"conditions": {"conditions": [{"leftValue": "={{ $json.body.action }}", "rightValue": "get_status", "operator": {"type": "string", "operation": "equals"}}]}, "renameOutput": true, "outputKey": "Get Status"},
|
||
|
|
{"conditions": {"conditions": [{"leftValue": "={{ $json.body.action }}", "rightValue": "get_analytics", "operator": {"type": "string", "operation": "equals"}}]}, "renameOutput": true, "outputKey": "Get Analytics"}
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"options": {}
|
||
|
|
},
|
||
|
|
"name": "Switch Action",
|
||
|
|
"type": "n8n-nodes-base.switch",
|
||
|
|
"typeVersion": 3,
|
||
|
|
"position": [700, 300]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"mode": "manual",
|
||
|
|
"duplicateItem": false,
|
||
|
|
"assignments": {
|
||
|
|
"assignments": [
|
||
|
|
{"id": "rp1", "name": "result", "value": "Pipeline triggered manually. Processing DropZone...", "type": "string"},
|
||
|
|
{"id": "rp2", "name": "action", "value": "run_pipeline", "type": "string"}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"name": "Handle Run Pipeline",
|
||
|
|
"type": "n8n-nodes-base.set",
|
||
|
|
"typeVersion": 3.4,
|
||
|
|
"position": [960, 60]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"method": "POST",
|
||
|
|
"url": "http://192.168.2.40:5000/webapi/entry.cgi",
|
||
|
|
"sendBody": true,
|
||
|
|
"bodyParameters": {
|
||
|
|
"parameters": [
|
||
|
|
{"name": "api", "value": "SYNO.FileStation.List"},
|
||
|
|
{"name": "version", "value": "2"},
|
||
|
|
{"name": "method", "value": "list"},
|
||
|
|
{"name": "folder_path", "value": "/BlendedFamilyKitchen/DropZone"}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"name": "Handle Check NAS",
|
||
|
|
"type": "n8n-nodes-base.httpRequest",
|
||
|
|
"typeVersion": 4.1,
|
||
|
|
"position": [960, 200]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"command": "echo '{\"docker\": \"'$(systemctl is-active docker)'\", \"n8n\": \"running\", \"whisper\": \"'$(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:9000/health 2>/dev/null || echo 'unreachable')'\", \"ffmpeg\": \"'$(ffmpeg -version 2>/dev/null | head -1 || echo 'not installed')'\"}'"
|
||
|
|
},
|
||
|
|
"name": "Handle Check Services",
|
||
|
|
"type": "n8n-nodes-base.executeCommand",
|
||
|
|
"typeVersion": 1,
|
||
|
|
"position": [960, 340]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"method": "POST",
|
||
|
|
"url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage",
|
||
|
|
"sendBody": true,
|
||
|
|
"specifyBody": "json",
|
||
|
|
"jsonBody": "={\n \"chat_id\": \"{{ $json.body.chat_id || 'TODO_DEFAULT_CHAT_ID' }}\",\n \"text\": \"{{ $json.body.message }}\",\n \"parse_mode\": \"Markdown\"\n}"
|
||
|
|
},
|
||
|
|
"name": "Handle Send Message",
|
||
|
|
"type": "n8n-nodes-base.httpRequest",
|
||
|
|
"typeVersion": 4.1,
|
||
|
|
"position": [960, 480]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"mode": "manual",
|
||
|
|
"duplicateItem": false,
|
||
|
|
"assignments": {
|
||
|
|
"assignments": [
|
||
|
|
{"id": "gs1", "name": "status", "value": "operational", "type": "string"},
|
||
|
|
{"id": "gs2", "name": "workflows", "value": "content_pipeline: inactive, garvis_webhook: active", "type": "string"},
|
||
|
|
{"id": "gs3", "name": "uptime", "value": "={{ new Date().toISOString() }}", "type": "string"}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"name": "Handle Get Status",
|
||
|
|
"type": "n8n-nodes-base.set",
|
||
|
|
"typeVersion": 3.4,
|
||
|
|
"position": [960, 620]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"options": {},
|
||
|
|
"respondWith": "json",
|
||
|
|
"responseBody": "={\"success\": true, \"action\": \"{{ $json.body?.action || 'unknown' }}\", \"result\": {{ JSON.stringify($json) }}}",
|
||
|
|
"responseCode": 200
|
||
|
|
},
|
||
|
|
"name": "Respond 200 Success",
|
||
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
||
|
|
"typeVersion": 1.1,
|
||
|
|
"position": [1200, 300]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"options": {},
|
||
|
|
"respondWith": "json",
|
||
|
|
"responseBody": "={\"error\": \"Unknown action\", \"received\": \"{{ $json.body?.action }}\", \"available\": [\"run_pipeline\", \"check_nas\", \"check_services\", \"send_message\", \"get_status\", \"get_analytics\"]}",
|
||
|
|
"responseCode": 400
|
||
|
|
},
|
||
|
|
"name": "Respond 400 Unknown",
|
||
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
||
|
|
"typeVersion": 1.1,
|
||
|
|
"position": [960, 800]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"content": "## 🔐 Garvis Webhook — Auth & Setup\n\n**Endpoint:** POST http://192.168.2.113:5678/webhook/garvis\n\n**Authentication:**\n- Header: x-garvis-secret\n- Validate against env var GARVIS_WEBHOOK_SECRET\n- Returns 401 if invalid\n\n**Request Format:**\n```json\n{\n \"action\": \"run_pipeline|check_nas|check_services|send_message|get_status\",\n \"message\": \"optional message text\",\n \"chat_id\": \"optional telegram chat id\"\n}\n```\n\n**Test with curl:**\n```\ncurl -X POST http://192.168.2.113:5678/webhook/garvis \\\n -H 'Content-Type: application/json' \\\n -H 'x-garvis-secret: YOUR_SECRET' \\\n -d '{\"action\": \"get_status\"}'\n```\n\n**TODO:**\n1. Set GARVIS_WEBHOOK_SECRET in n8n environment variables\n2. Set TELEGRAM_BOT_TOKEN in n8n environment variables\n3. Activate workflow when ready\n4. Test each action endpoint\n5. Add webhook URL to Garvis bot config",
|
||
|
|
"height": 620,
|
||
|
|
"width": 520
|
||
|
|
},
|
||
|
|
"name": "Sticky - Webhook Setup",
|
||
|
|
"type": "n8n-nodes-base.stickyNote",
|
||
|
|
"typeVersion": 1,
|
||
|
|
"position": [200, -320]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"method": "POST",
|
||
|
|
"url": "http://192.168.2.40:5000/webapi/entry.cgi",
|
||
|
|
"sendBody": true,
|
||
|
|
"bodyParameters": {
|
||
|
|
"parameters": [
|
||
|
|
{"name": "api", "value": "SYNO.FileStation.List"},
|
||
|
|
{"name": "version", "value": "2"},
|
||
|
|
{"name": "method", "value": "list"},
|
||
|
|
{"name": "folder_path", "value": "/BlendedFamilyKitchen/Analytics"},
|
||
|
|
{"name": "sort_by", "value": "crtime"},
|
||
|
|
{"name": "sort_direction", "value": "desc"},
|
||
|
|
{"name": "limit", "value": "={{ $json.body.limit || 10 }}"}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"name": "Handle Get Analytics",
|
||
|
|
"type": "n8n-nodes-base.httpRequest",
|
||
|
|
"typeVersion": 4.1,
|
||
|
|
"position": [960, 760]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"parameters": {
|
||
|
|
"content": "## 🔀 Action Router — Available Actions\n\n**run_pipeline:** Manually triggers the Content Pipeline workflow. Use when Cloe drops a video and doesn't want to wait for the 30-min poll cycle.\n\n**check_nas:** Queries Synology FileStation API to list files in DropZone. Returns file count and names. Useful for: \"Garvis, anything in the drop zone?\"\n\n**check_services:** Runs local service checks — Docker, Whisper, FFmpeg availability. Returns health status JSON. Useful for: \"Garvis, is the pipeline infrastructure healthy?\"\n\n**send_message:** Forwards a message to a Telegram chat via the bot. Requires chat_id and message in request body. Useful for: cross-service notifications.\n\n**get_status:** Returns current n8n workflow states, uptime, and basic system info. Useful for: \"Garvis, n8n status?\"\n\n**TODO:**\n1. Wire run_pipeline to actually trigger Content Pipeline (use n8n Execute Workflow node)\n2. Add NAS auth to check_nas handler\n3. Expand check_services with more endpoints\n4. Add rate limiting / cooldown logic\n5. Add logging to each action handler",
|
||
|
|
"height": 580,
|
||
|
|
"width": 520
|
||
|
|
},
|
||
|
|
"name": "Sticky - Action Router",
|
||
|
|
"type": "n8n-nodes-base.stickyNote",
|
||
|
|
"typeVersion": 1,
|
||
|
|
"position": [880, -320]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"connections": {
|
||
|
|
"Webhook": {"main": [[{"node": "IF Auth Valid?", "type": "main", "index": 0}]]},
|
||
|
|
"IF Auth Valid?": {
|
||
|
|
"main": [
|
||
|
|
[{"node": "Switch Action", "type": "main", "index": 0}],
|
||
|
|
[{"node": "Respond 401", "type": "main", "index": 0}]
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"Switch Action": {
|
||
|
|
"main": [
|
||
|
|
[{"node": "Handle Run Pipeline", "type": "main", "index": 0}],
|
||
|
|
[{"node": "Handle Check NAS", "type": "main", "index": 0}],
|
||
|
|
[{"node": "Handle Check Services", "type": "main", "index": 0}],
|
||
|
|
[{"node": "Handle Send Message", "type": "main", "index": 0}],
|
||
|
|
[{"node": "Handle Get Status", "type": "main", "index": 0}],
|
||
|
|
[{"node": "Handle Get Analytics", "type": "main", "index": 0}],
|
||
|
|
[{"node": "Respond 400 Unknown", "type": "main", "index": 0}]
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"Handle Run Pipeline": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]},
|
||
|
|
"Handle Check NAS": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]},
|
||
|
|
"Handle Check Services": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]},
|
||
|
|
"Handle Send Message": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]},
|
||
|
|
"Handle Get Status": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]},
|
||
|
|
"Handle Get Analytics": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]}
|
||
|
|
},
|
||
|
|
"settings": {
|
||
|
|
"executionOrder": "v1"
|
||
|
|
}
|
||
|
|
}
|