{
  "updatedAt": "2026-05-14T00:03:13.116Z",
  "createdAt": "2026-05-12T17:56:05.279Z",
  "id": "El1BHJZ56JlzhrRZ",
  "name": "Voice Memo Capture (Audio URL + Local Whisper)",
  "description": null,
  "active": true,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "voice-memo",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -980,
        0
      ],
      "id": "9f1da0a8-32db-4e67-a6e4-18cf8b4d42ee",
      "name": "Webhook - Voice Memo",
      "webhookId": "06796590-13b3-4347-9582-1ac92719c95d"
    },
    {
      "parameters": {
        "jsCode": "const body = $json.body ?? $json;\n\nconst audio_url = String(body.audio_url || body.url || '').trim();\nconst telegram_file_id = String(body.telegram_file_id || body.file_id || '').trim();\nconst discord_audio_url = String(body.discord_audio_url || '').trim();\nconst audio_base64 = String(body.audio_base64 || '').trim();\nconst audio_format = String(body.audio_format || body.format || 'ogg').trim();\nconst language = String(body.language || 'en').trim();\nconst title = String(body.title || 'Voice Memo').trim();\nconst tags = Array.isArray(body.tags) ? body.tags : String(body.tags || 'voice,memo').split(',').map(s => s.trim()).filter(Boolean);\nconst include_tts = body.include_tts === true || body.tts_readback === true;\nconst voice = String(body.voice || body.tts_voice || 'af_heart').trim();\nif (!audio_url && !telegram_file_id && !discord_audio_url && !audio_base64) {\n  throw new Error('POST JSON must include audio_url, telegram_file_id, discord_audio_url, or audio_base64');\n}\nreturn [{ json: { audio_url, telegram_file_id, discord_audio_url, audio_base64, audio_format, language, title, tags, include_tts, voice } }];"
      },
      "id": "vm-normalize-v2",
      "name": "Normalize Input",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -680,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://172.19.0.1:18813/process",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ audio_url: $json.audio_url, telegram_file_id: $json.telegram_file_id, discord_audio_url: $json.discord_audio_url, title: $json.title, tags: $json.tags, include_tts: $json.include_tts, voice: $json.voice }) }}",
        "options": {
          "timeout": 180000,
          "fullResponse": false
        }
      },
      "id": "vm-process-v2",
      "name": "Process Voice Memo",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -460,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "const input = $('Normalize Input').first().json;\nconst proc = $input.first().json;\n\nfunction slugify(s) { return String(s || 'voice-memo').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 80) || 'voice-memo'; }\nfunction yaml(s) { return String(s ?? '').split('\\n').join(' ').replaceAll('\"', '\\\\\"'); }\n\nconst date = new Date(proc.created_at || Date.now());\nconst ymd = date.toISOString().slice(0,10);\nconst notePath = `Voice Memos/${ymd}-${slugify(proc.title || input.title)}.md`;\n\nconst title = proc.title || input.title || 'Voice Memo';\nconst tags = proc.tags || input.tags || ['voice', 'memo'];\nconst tagLines = tags.map(t => `  - ${yaml(t)}`).join('\\n');\nconst sourceType = proc.source_type || input.source || 'unknown';\nconst sourceUrl = input.source_url || '';\n\nlet audioNote = '';\nif (proc.tts_audio_url) {\n  audioNote = `\\n## Audio Summary\\n\\n> Listen to the AI-generated summary: ${proc.tts_audio_url}\\n`;\n}\n\nconst markdown = `---\\ntitle: \"${yaml(title)}\"\\nsource: \"${yaml(sourceUrl)}\"\\nsource_type: \"${sourceType}\"\\ncreated: \"${date.toISOString()}\"\\ntags:\\n${tagLines}\\n---\\n\\n# ${title}\\n\\n## Summary\\n\\n${(proc.summary || '').trim()}\\n${audioNote}\\n## Transcript\\n\\n${proc.transcript || 'No transcript available.'}\\n`;\n\nreturn [{ json: { ...input, notePath, markdown, title, tts_audio_url: proc.tts_audio_url || null } }];\n"
      },
      "id": "vm-build-obsidian-v2",
      "name": "Build Obsidian Note",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -240,
        0
      ]
    },
    {
      "parameters": {
        "method": "PUT",
        "url": "={{'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.notePath).replace(/%2F/g, '/')}}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "text/markdown"
            }
          ]
        },
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "text/markdown",
        "body": "={{$json.markdown}}",
        "options": {
          "timeout": 30000
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "id": "vm-write-obsidian-v2",
      "name": "Write Note to Obsidian",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        0,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "465Swz2b71O2KRAK",
          "name": "Obsidian Local REST API"
        }
      }
    },
    {
      "parameters": {
        "chatId": "8367012007",
        "text": "={{ \"Voice memo captured (\" + $json.source_type + \"): \" + $json.title + \"\\nObsidian: \" + $json.notePath + ($json.tts_audio_url ? \"\\nAudio summary: \" + $json.tts_audio_url : \"\") }}",
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        1160,
        -80
      ],
      "id": "41bf5a55-2047-400a-87c7-44744a0f2a42",
      "name": "Send Telegram Notification",
      "credentials": {
        "telegramApi": {
          "id": "aox4dyIWVSRdcH5z",
          "name": "Telegram Bot (OpenClaw)"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ ok: true, notePath: $json.notePath, title: $json.title, source_type: $json.source_type, tts_audio_url: $json.tts_audio_url || null }) }}"
      },
      "id": "vm-respond-v2",
      "name": "Respond",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        460,
        0
      ]
    }
  ],
  "connections": {
    "Webhook - Voice Memo": {
      "main": [
        [
          {
            "node": "Normalize Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Input": {
      "main": [
        [
          {
            "node": "Process Voice Memo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Voice Memo": {
      "main": [
        [
          {
            "node": "Build Obsidian Note",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Obsidian Note": {
      "main": [
        [
          {
            "node": "Write Note to Obsidian",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Note to Obsidian": {
      "main": [
        [
          {
            "node": "Send Telegram Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Telegram Notification": {
      "main": [
        [
          {
            "node": "Respond",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "America/Los_Angeles",
    "saveDataErrorExecution": "all",
    "saveDataSuccessExecution": "none",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "staticData": null,
  "meta": null,
  "pinData": null,
  "versionId": "4511e901-afab-493e-9b17-99a9d9865147",
  "activeVersionId": "4511e901-afab-493e-9b17-99a9d9865147",
  "versionCounter": 38,
  "triggerCount": 1,
  "shared": [
    {
      "updatedAt": "2026-05-12T17:56:05.281Z",
      "createdAt": "2026-05-12T17:56:05.281Z",
      "role": "workflow:owner",
      "workflowId": "El1BHJZ56JlzhrRZ",
      "projectId": "WGdp8QunI1tHpjXa",
      "project": {
        "updatedAt": "2026-03-11T21:08:10.005Z",
        "createdAt": "2026-03-11T21:05:11.541Z",
        "id": "WGdp8QunI1tHpjXa",
        "name": "will will <will@wills-portal.com>",
        "type": "personal",
        "icon": null,
        "description": null,
        "creatorId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
      }
    }
  ],
  "tags": [],
  "activeVersion": {
    "updatedAt": "2026-05-14T00:03:13.117Z",
    "createdAt": "2026-05-14T00:03:13.117Z",
    "versionId": "4511e901-afab-493e-9b17-99a9d9865147",
    "workflowId": "El1BHJZ56JlzhrRZ",
    "nodes": [
      {
        "parameters": {
          "httpMethod": "POST",
          "path": "voice-memo",
          "responseMode": "responseNode",
          "options": {}
        },
        "type": "n8n-nodes-base.webhook",
        "typeVersion": 2.1,
        "position": [
          -980,
          0
        ],
        "id": "9f1da0a8-32db-4e67-a6e4-18cf8b4d42ee",
        "name": "Webhook - Voice Memo",
        "webhookId": "06796590-13b3-4347-9582-1ac92719c95d"
      },
      {
        "parameters": {
          "jsCode": "const body = $json.body ?? $json;\n\nconst audio_url = String(body.audio_url || body.url || '').trim();\nconst telegram_file_id = String(body.telegram_file_id || body.file_id || '').trim();\nconst discord_audio_url = String(body.discord_audio_url || '').trim();\nconst audio_base64 = String(body.audio_base64 || '').trim();\nconst audio_format = String(body.audio_format || body.format || 'ogg').trim();\nconst language = String(body.language || 'en').trim();\nconst title = String(body.title || 'Voice Memo').trim();\nconst tags = Array.isArray(body.tags) ? body.tags : String(body.tags || 'voice,memo').split(',').map(s => s.trim()).filter(Boolean);\nconst include_tts = body.include_tts === true || body.tts_readback === true;\nconst voice = String(body.voice || body.tts_voice || 'af_heart').trim();\nif (!audio_url && !telegram_file_id && !discord_audio_url && !audio_base64) {\n  throw new Error('POST JSON must include audio_url, telegram_file_id, discord_audio_url, or audio_base64');\n}\nreturn [{ json: { audio_url, telegram_file_id, discord_audio_url, audio_base64, audio_format, language, title, tags, include_tts, voice } }];"
        },
        "id": "vm-normalize-v2",
        "name": "Normalize Input",
        "type": "n8n-nodes-base.code",
        "typeVersion": 2,
        "position": [
          -680,
          0
        ]
      },
      {
        "parameters": {
          "method": "POST",
          "url": "http://172.19.0.1:18813/process",
          "sendBody": true,
          "specifyBody": "json",
          "jsonBody": "={{ JSON.stringify({ audio_url: $json.audio_url, telegram_file_id: $json.telegram_file_id, discord_audio_url: $json.discord_audio_url, title: $json.title, tags: $json.tags, include_tts: $json.include_tts, voice: $json.voice }) }}",
          "options": {
            "timeout": 180000,
            "fullResponse": false
          }
        },
        "id": "vm-process-v2",
        "name": "Process Voice Memo",
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          -460,
          0
        ]
      },
      {
        "parameters": {
          "jsCode": "const input = $('Normalize Input').first().json;\nconst proc = $input.first().json;\n\nfunction slugify(s) { return String(s || 'voice-memo').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 80) || 'voice-memo'; }\nfunction yaml(s) { return String(s ?? '').split('\\n').join(' ').replaceAll('\"', '\\\\\"'); }\n\nconst date = new Date(proc.created_at || Date.now());\nconst ymd = date.toISOString().slice(0,10);\nconst notePath = `Voice Memos/${ymd}-${slugify(proc.title || input.title)}.md`;\n\nconst title = proc.title || input.title || 'Voice Memo';\nconst tags = proc.tags || input.tags || ['voice', 'memo'];\nconst tagLines = tags.map(t => `  - ${yaml(t)}`).join('\\n');\nconst sourceType = proc.source_type || input.source || 'unknown';\nconst sourceUrl = input.source_url || '';\n\nlet audioNote = '';\nif (proc.tts_audio_url) {\n  audioNote = `\\n## Audio Summary\\n\\n> Listen to the AI-generated summary: ${proc.tts_audio_url}\\n`;\n}\n\nconst markdown = `---\\ntitle: \"${yaml(title)}\"\\nsource: \"${yaml(sourceUrl)}\"\\nsource_type: \"${sourceType}\"\\ncreated: \"${date.toISOString()}\"\\ntags:\\n${tagLines}\\n---\\n\\n# ${title}\\n\\n## Summary\\n\\n${(proc.summary || '').trim()}\\n${audioNote}\\n## Transcript\\n\\n${proc.transcript || 'No transcript available.'}\\n`;\n\nreturn [{ json: { ...input, notePath, markdown, title, tts_audio_url: proc.tts_audio_url || null } }];\n"
        },
        "id": "vm-build-obsidian-v2",
        "name": "Build Obsidian Note",
        "type": "n8n-nodes-base.code",
        "typeVersion": 2,
        "position": [
          -240,
          0
        ]
      },
      {
        "parameters": {
          "method": "PUT",
          "url": "={{'http://172.19.0.1:27123/vault/' + encodeURIComponent($json.notePath).replace(/%2F/g, '/')}}",
          "sendHeaders": true,
          "headerParameters": {
            "parameters": [
              {
                "name": "Content-Type",
                "value": "text/markdown"
              }
            ]
          },
          "sendBody": true,
          "contentType": "raw",
          "rawContentType": "text/markdown",
          "body": "={{$json.markdown}}",
          "options": {
            "timeout": 30000
          },
          "authentication": "genericCredentialType",
          "genericAuthType": "httpHeaderAuth"
        },
        "id": "vm-write-obsidian-v2",
        "name": "Write Note to Obsidian",
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          0,
          0
        ],
        "credentials": {
          "httpHeaderAuth": {
            "id": "465Swz2b71O2KRAK",
            "name": "Obsidian Local REST API"
          }
        }
      },
      {
        "parameters": {
          "chatId": "8367012007",
          "text": "={{ \"Voice memo captured (\" + $json.source_type + \"): \" + $json.title + \"\\nObsidian: \" + $json.notePath + ($json.tts_audio_url ? \"\\nAudio summary: \" + $json.tts_audio_url : \"\") }}",
          "additionalFields": {}
        },
        "type": "n8n-nodes-base.telegram",
        "typeVersion": 1.2,
        "position": [
          1160,
          -80
        ],
        "id": "41bf5a55-2047-400a-87c7-44744a0f2a42",
        "name": "Send Telegram Notification",
        "credentials": {
          "telegramApi": {
            "id": "aox4dyIWVSRdcH5z",
            "name": "Telegram Bot (OpenClaw)"
          }
        }
      },
      {
        "parameters": {
          "respondWith": "json",
          "responseBody": "={{ JSON.stringify({ ok: true, notePath: $json.notePath, title: $json.title, source_type: $json.source_type, tts_audio_url: $json.tts_audio_url || null }) }}"
        },
        "id": "vm-respond-v2",
        "name": "Respond",
        "type": "n8n-nodes-base.respondToWebhook",
        "typeVersion": 1.1,
        "position": [
          460,
          0
        ]
      }
    ],
    "connections": {
      "Webhook - Voice Memo": {
        "main": [
          [
            {
              "node": "Normalize Input",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Normalize Input": {
        "main": [
          [
            {
              "node": "Process Voice Memo",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Process Voice Memo": {
        "main": [
          [
            {
              "node": "Build Obsidian Note",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Build Obsidian Note": {
        "main": [
          [
            {
              "node": "Write Note to Obsidian",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Write Note to Obsidian": {
        "main": [
          [
            {
              "node": "Send Telegram Notification",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Send Telegram Notification": {
        "main": [
          [
            {
              "node": "Respond",
              "type": "main",
              "index": 0
            }
          ]
        ]
      }
    },
    "authors": "will will",
    "name": null,
    "description": null,
    "autosaved": false,
    "workflowPublishHistory": [
      {
        "createdAt": "2026-05-14T00:03:13.146Z",
        "id": 1475,
        "workflowId": "El1BHJZ56JlzhrRZ",
        "versionId": "4511e901-afab-493e-9b17-99a9d9865147",
        "event": "activated",
        "userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
      },
      {
        "createdAt": "2026-05-14T00:03:13.139Z",
        "id": 1474,
        "workflowId": "El1BHJZ56JlzhrRZ",
        "versionId": "4511e901-afab-493e-9b17-99a9d9865147",
        "event": "deactivated",
        "userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5"
      }
    ]
  }
}
