{
  "name": "Text to speech Voice clone using Zonos via API(local storage)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "voice-clone",
        "options": {}
      },
      "id": "76f2c278-c769-443f-8aa5-541713323b51",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        -560,
        60
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "text",
              "value": "={{ $json.body.text || 'Hello, this is a test of voice cloning!' }}"
            },
            {
              "name": "speaking_rate",
              "value": "={{ $json.body.speaking_rate || 15 }}"
            },
            {
              "name": "language_iso_code",
              "value": "={{ $json.body.language_iso_code || 'en-us' }}"
            },
            {
              "name": "mime_type",
              "value": "={{ $json.body.mime_type || 'audio/wav'}}"
            },
            {
              "name": "sample_voice_path",
              "value": "={{ $json.body.sample_voice_path }}"
            },
            {
              "name": "model",
              "value": "={{ $json.body.model || 'zonos-v0.1-transformer' }}"
            },
            {
              "name": "output_path",
              "value": "={{ $json.body.output_path }}"
            }
          ],
          "number": [
            {
              "name": "happiness",
              "value": "={{ $json.body.emotion.happiness || 0.6}}"
            },
            {
              "name": "neutral",
              "value": "={{ $json.body.emotion.neutral || 0.6}}"
            },
            {
              "name": "sadness",
              "value": "={{ $json.body.emotion.sadness || 0.05}}"
            },
            {
              "name": "disgust",
              "value": "={{ $json.body.emotion.disgust || 0.05}}"
            },
            {
              "name": "fear",
              "value": "={{ $json.body.emotion.fear || 0.05}}"
            },
            {
              "name": "surprise",
              "value": "={{ $json.body.emotion.surprise || 0.05}}"
            },
            {
              "name": "anger",
              "value": "={{ $json.body.emotion.anger || 0.05}}"
            },
            {
              "name": "other",
              "value": "={{ $json.body.emotion.other || 0.5}}"
            }
          ]
        },
        "options": {}
      },
      "id": "0772d98e-7cd8-487d-a3db-26c3d6d50304",
      "name": "Set Clone Parameters",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        -340,
        60
      ]
    },
    {
      "parameters": {
        "fileSelector": "={{ $json.sample_voice_path }}",
        "options": {
          "mimeType": "={{ $json.mime_type }}",
          "dataPropertyName": ""
        }
      },
      "id": "b3dc1528-90d7-4397-83e6-18c5f2dbf495",
      "name": "Read Sample Voice",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        40,
        60
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "file-exists-check",
              "leftValue": "={{ $ifEmpty($binary.data, false) !== false }}\n",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "86e0f9bf-ccec-4bb1-b9ce-7d1b94fdfcca",
      "name": "Check File Loaded",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        560,
        -80
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://api.zyphra.com/v1/audio/text-to-speech",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-API-Key",
              "value": "put-your-API-key-here"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"text\": \"{{ $('Set Clone Parameters').item.json.text }}\",\n  \"speaking_rate\": {{ parseFloat($('Set Clone Parameters').item.json.speaking_rate) }},\n  \"language_iso_code\": \"{{ $('Set Clone Parameters').item.json.language_iso_code }}\",\n  \"mime_type\": \"{{ $('Set Clone Parameters').item.json.mime_type }}\",\n  \"model\": \"{{ $('Set Clone Parameters').item.json.model }}\",\n  \"emotion\": {\n    \"happiness\": {{ $('Set Clone Parameters').item.json.happiness }},\n    \"neutral\": {{ $('Set Clone Parameters').item.json.neutral }},\n    \"sadness\": {{ $('Set Clone Parameters').item.json.sadness }},\n    \"disgust\": {{ $('Set Clone Parameters').item.json.disgust }},\n    \"fear\": {{ $('Set Clone Parameters').item.json.fear }},\n    \"surprise\": {{ $('Set Clone Parameters').item.json.surprise }},\n    \"anger\": {{ $('Set Clone Parameters').item.json.anger }},\n    \"other\": {{ $('Set Clone Parameters').item.json.other }}\n  },\n  \"speaker_audio\": \"{{ $json.base64_content }}\"\n}\n",
        "options": {
          "response": {
            "response": {}
          }
        }
      },
      "id": "2980ae94-30e3-4065-8d2c-b607c73c3c5f",
      "name": "Call Zyphra Clone API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        980,
        -120
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "operation": "write",
        "fileName": "={{ $('Set Clone Parameters').item.json.output_path }}{{ 'cloned_voice_' + new Date().getTime() + '.webm' }}",
        "options": {}
      },
      "id": "0f896518-98ce-4176-8977-1f0380b54469",
      "name": "Save Cloned Audio",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        1440,
        0
      ]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "success",
              "value": "true"
            },
            {
              "name": "message",
              "value": "Voice cloning completed successfully!"
            },
            {
              "name": "filename",
              "value": "={{ $json.fileName }}"
            },
            {
              "name": "text_processed",
              "value": "={{ $('Set Clone Parameters').item.json.text }}"
            },
            {
              "name": "sample_voice_used",
              "value": "={{ $('Set Clone Parameters').item.json.sample_voice_path }}"
            }
          ]
        },
        "options": {}
      },
      "id": "02f1b766-953a-4834-8d93-4cc596ffe77c",
      "name": "Success Response",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        1660,
        0
      ]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "success",
              "value": "false"
            },
            {
              "name": "error_type",
              "value": "file_not_found"
            },
            {
              "name": "message",
              "value": "Sample voice file could not be read from: {{ $('Set Clone Parameters').item.json.sample_voice_path }}"
            },
            {
              "name": "suggestion",
              "value": "Please check the file path and ensure the file exists"
            }
          ]
        },
        "options": {}
      },
      "id": "7da98d65-08e3-4d6e-9957-ead2c8f1133f",
      "name": "File Error Response",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        860,
        480
      ]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "success",
              "value": "false"
            },
            {
              "name": "error_type",
              "value": "api_error"
            },
            {
              "name": "message",
              "value": "Voice cloning API request failed"
            },
            {
              "name": "error_details",
              "value": "={{ $json.error ? $json.error.message : 'Unknown API error' }}"
            },
            {
              "name": "suggestion",
              "value": "Please check your API key and try again"
            }
          ]
        },
        "options": {}
      },
      "id": "44006f98-4241-436d-b8cf-1c586271a35a",
      "name": "API Error Response",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        1100,
        480
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {}
      },
      "id": "e2c14808-e209-4daf-93dd-9c7049261e60",
      "name": "Webhook Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1880,
        100
      ]
    },
    {
      "parameters": {
        "content": "\ud83c\udf99\ufe0f VOICE CLONING WORKFLOW - ZONOS API\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nThis workflow clones voices using Zyphra's Zonos API\n\ud83d\udccb Input: Text + sample voice file + parameters  \n\ud83c\udfb5 Output: Generated audio file with cloned voice\n\u26a1 Trigger: Webhook POST to /voice-clone endpoint\n\nBasic setup and use:\nConfigure your Zyphra API key in the \"Call Zyphra Clone API\" node under Header parameters \u2192 X-API-Key header parameter\n\nEnsure your sample voice files are accessible at the paths you'll specify\n\nTest the webhook endpoint is accessible\n\nSend valid POST request to your webhook\n",
        "height": 340,
        "width": 780,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -960,
        -1200
      ],
      "id": "8268fd4a-fd84-4462-9ad1-9af8152d0cf3",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "jsCode": "// Get binary data from previous node\nconst binaryData = $input.first().binary?.data;\n\nif (!binaryData) {\n  throw new Error(\"No binary data found\");\n}\n\n// Binary data in n8n is already base64 encoded\nconst base64String = binaryData.data;\n\nreturn {\n  json: {\n    base64_content: base64String,\n    // Add other fields as needed\n  }\n};\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        400,
        -80
      ],
      "id": "cdbb775f-8408-43a9-89b1-1039315c6678",
      "name": "Base64 convertor"
    },
    {
      "parameters": {
        "content": "\ud83d\udce5 REQUIRED WEBHOOK PARAMETERS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\u2705 text: Text to synthesize\n\u2705 sample_voice_path: Path to your voice sample file  \n\u2705 output_path: Where to save generated audio\n\n\ud83d\udd27 OPTIONAL PARAMETERS (with defaults):\n\u2022 speaking_rate: 15 (speech speed)\n\u2022 language_iso_code: \"en-us\" \n\u2022 mime_type: \"audio/wav\"\n\u2022 model: \"zonos-v0.1-transformer\"\n\u2022 emotion: Various emotion levels (0-1 scale)\n",
        "height": 1020,
        "width": 780,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -960,
        -740
      ],
      "id": "88b0131c-f93b-4593-9c88-ed4f91b74c88",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "\ud83d\udd10 API KEY CONFIGURATION REQUIRED!\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n1\ufe0f\u20e3 Register account at: playground.zyphra.com  \n2\ufe0f\u20e3 Get API key from: playground.zyphra.com/settings/api-keys\n3\ufe0f\u20e3 Add key to \"Call Zyphra Clone API\" node\n   \u2192 Header parameters section\n   \u2192 Header: X-API-Key\n   \u2192 Value: [Your API Key]\n\n\u274c Workflow will fail without proper API key setup!\n",
        "height": 460,
        "width": 480,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        820,
        -380
      ],
      "id": "3be24130-054d-4435-9aac-d5ad9c7b92d0",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "\ud83d\udcc1 FILE HANDLING PROCESS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n1. Read sample voice from specified path\n2. Convert audio file to base64 format\n3. Validate file loaded successfully  \n\n\u26a0\ufe0f IMPORTANT: Ensure sample voice file exists \n   at the path specified in sample_voice_path!\n",
        "height": 560,
        "width": 740,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -60,
        -280
      ],
      "id": "08780e5a-4663-4a0d-aeff-69f4059495ce",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "content": "\ud83d\udea8 ERROR HANDLING & RESPONSES\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\u2705 SUCCESS: Returns success message + filename\n\u274c FILE_NOT_FOUND: Sample voice file missing/unreadable\n\u274c API_ERROR: Zyphra API request failed\n\u274c AUTH_ERROR: Invalid or missing API key\n\nAll errors return JSON with error details and suggestions\n",
        "height": 480,
        "width": 480,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        820,
        180
      ],
      "id": "223743b2-aeb2-45cc-8094-9bef48fc815e",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "content": "\ud83c\udfb5 OUTPUT DETAILS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\ud83d\udccd Location: [output_path]/cloned_voice_[timestamp].webm\n\ud83d\udcca Format: Specified by mime_type parameter\n\ud83d\udd50 Filename: Auto-generated with timestamp\n\ud83d\udcdd Response: JSON with success status and file details\n\nGenerated audio ready for download!\n",
        "height": 540,
        "width": 660,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1400,
        -220
      ],
      "id": "939714c2-9feb-4ccb-b3b6-fd133c65c56a",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "content": "POST http://localhost:5678/webhook-test/voice-clone\nContent-Type: application/json\n\n{\n  \"text\": \"Hello there, kupo! This voice sounds just like the sample!\",\n  \"speaking_rate\": 18,\n  \"sample_voice_path\": \"/data/output/sampleVoice.wav\",\n  \"output_path\": \"/data/output/\",\n  \"language_iso_code\": \"en-us\",\n  \"mime_type\": \"audio/wav\",\n  \"model\": \"zonos-v0.1-transformer\",\n  \"emotion\": {\n    \"happiness\": 0.8,\n    \"neutral\": 0.3,\n    \"sadness\": 0.05,\n    \"disgust\": 0.05,\n    \"fear\": 0.05,\n    \"surprise\": 0.05,\n    \"anger\": 0.05,\n    \"other\": 0.5\n  }\n}\n",
        "height": 440,
        "width": 700,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -940,
        -440
      ],
      "id": "0a90485e-417a-415e-a9a4-f128aea6b9f1",
      "name": "Sticky Note6"
    }
  ],
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Set Clone Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Clone Parameters": {
      "main": [
        [
          {
            "node": "Read Sample Voice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Sample Voice": {
      "main": [
        [
          {
            "node": "Base64 convertor",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "File Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check File Loaded": {
      "main": [
        [
          {
            "node": "Call Zyphra Clone API",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "File Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call Zyphra Clone API": {
      "main": [
        [
          {
            "node": "Save Cloned Audio",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "API Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Cloned Audio": {
      "main": [
        [
          {
            "node": "Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Success Response": {
      "main": [
        [
          {
            "node": "Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "File Error Response": {
      "main": [
        [
          {
            "node": "Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "API Error Response": {
      "main": [
        [
          {
            "node": "Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Base64 convertor": {
      "main": [
        [
          {
            "node": "Check File Loaded",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c4a644b3-3029-47ed-9dad-6396d22a9841",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "hqMRsze38RaTmgQh",
  "tags": []
}