AutomationFlowsAI & RAG › Generate Two-host PDF Podcasts with Gpt-5, Smallest Ai, and Gmail

Generate Two-host PDF Podcasts with Gpt-5, Smallest Ai, and Gmail

BySumit Mor @sosumti001 on n8n.io

Turn whitepapers, research reports, blog drafts, lecture notes, or company memos into NotebookLM-style audio briefings. Native Hindi, Tamil, Telugu, Kannada, Malayalam, Bengali, Marathi, Gujarati, and Punjabi support makes this the only n8n template that ships authentic…

Event trigger★★★★☆ complexityAI-powered19 nodesForm TriggerOpenAIN8N Nodes SmallestaiGmail
AI & RAG Trigger: Event Nodes: 19 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #15350 — we link there as the canonical source.

This workflow follows the Form Trigger → Gmail recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "PDF to AI Podcast in 9 Indian Languages with Smallest AI",
  "tags": [],
  "nodes": [
    {
      "id": "bb460b22-5b3d-4de3-9f0c-0d082bcf86fd",
      "name": "Main Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7424,
        384
      ],
      "parameters": {
        "width": 480,
        "height": 1000,
        "content": "## \ud83c\udf99\ufe0f PDF to Podcast \u2014 Powered by Smallest AI\n\nConvert any PDF into a NotebookLM-style two-host podcast, delivered to your inbox. Generate audio in 19+ languages including 9 Indian tongues \u2014 Hindi, Tamil, Telugu, Kannada, Malayalam, Bengali, Marathi, Gujarati, Punjabi.\n\n### Required credentials (~5 min setup)\n\n- **Smallest AI** \u2014 get yours [API Key](https://app.smallest.ai/dashboard/api-keys) (free tier available)\n- **OpenAI** API key \u2014 GPT-5 or GPT-4o-mini\n- **Gmail** OAuth2 for delivery\n\n### Required community node\n\nThis template uses `n8n-nodes-smallestai`. Install via **Settings \u2192 Community Nodes** before importing.\n\n### How it works\n\n1. Form trigger captures the PDF\n2. GPT-5 generates a structured 2-host JSON script\n3. Switch routes each turn to the correct voice\n4. Smallest AI Lightning synthesizes each turn (~100ms TTFB)\n5. Code node concatenates WAV chunks in order\n6. Gmail emails the finished podcast\n\nPure JavaScript audio concat \u2014 no FFmpeg, works on n8n Cloud.\n\n### Customise\n\n- **Voices:** Edit `voiceId` in the two Synthesize Host nodes. Defaults: `avery` (Host A) + `devansh` (Host B). Browse all the [voices](https://docs.smallest.ai/waves/v-4-0-0/api-reference/api-reference/voices/get-waves-voices).\n- **Language:** Change `english` in the system prompt. Both voices must match.\n  - Hindi: `arjun` + `aanya` \u00b7 Tamil: `arvind` + `niharika` \u00b7 Bengali: `arnab` + `ishita`\n- **Length & format:** Edit the \"4-minute / 25-35 turns\" rule or rewrite cast personas (interview, debate, kids' story).\n- **Recipient:** Update the email in \"Email Podcast to User\".\n- **Delivery:** Swap Gmail for Slack, Telegram, or Drive Upload.\n\n### WAV format consistency\n\nDon't override `sample_rate` per call in the Smallest AI nodes \u2014 keep both Synthesize Host nodes on identical config or the concat will produce noise."
      },
      "typeVersion": 1
    },
    {
      "id": "cd5b08a4-5e6c-4729-9c2b-5825055f1d20",
      "name": "Section 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7984,
        688
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 304,
        "content": "## 1. Upload PDF\n\nSubmits a PDF via the form. Extract from File pulls plain text and hands it to the script generator."
      },
      "typeVersion": 1
    },
    {
      "id": "2c23908e-dad3-494d-82b9-9e122aaa81b7",
      "name": "Section 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        8448,
        656
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 352,
        "content": "## 2. Generate the Podcast Script\n\nGPT-5 turns the PDF text into a structured 2-host JSON script. Schema is enforced via the OpenAI node's built-in JSON Schema mode.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "3ab6b596-2dde-44f6-aaa2-173539eadd3d",
      "name": "Section 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        9296,
        656
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 568,
        "content": "## 3. Synthesize With the Right Voice\n\nSwitch routes each turn by `host` (A or B). Each branch calls Smallest AI Lightning with a different voice ID. Edit Fields preserve `order` and `host` for re-sorting downstream."
      },
      "typeVersion": 1
    },
    {
      "id": "6507a5a4-dddb-44c4-9dd5-d8806db9a1fb",
      "name": "Section 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        9872,
        864
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 320,
        "content": "## 4. Stitch Audio in Order\n\nMerge collects both branches, Sort restores conversational order via the `order` field, and the Code node concatenates all WAV chunks into a single audio file.\n\n**Pure JavaScript** \u2014 no FFmpeg required, works on n8n Cloud."
      },
      "typeVersion": 1
    },
    {
      "id": "3b1af034-f64a-4373-9abf-7f119e63225a",
      "name": "Section 5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        10608,
        784
      ],
      "parameters": {
        "color": 7,
        "height": 400,
        "content": "## 5. Deliver via Email\n\nGmail attaches the WAV and emails it to the recipient.\n\n**Update the `To` field** \u2014 currently set to a placeholder.\n\nSwap Gmail for Slack, Telegram, or Drive Upload as needed."
      },
      "typeVersion": 1
    },
    {
      "id": "50376525-17f4-40c6-ac88-bc1bda37ef2c",
      "name": "When Form Submitted",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        8032,
        816
      ],
      "parameters": {
        "options": {},
        "formTitle": "PDF to Podcast Generator",
        "formFields": {
          "values": [
            {
              "fieldType": "file",
              "fieldLabel": "pdf_podcast"
            }
          ]
        },
        "formDescription": "Upload a PDF and receive a two-host AI podcast by email."
      },
      "typeVersion": 2.5
    },
    {
      "id": "b764bc04-6750-490d-90bd-205c91f45e08",
      "name": "Extract Data from File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        8208,
        816
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "pdf_podcast"
      },
      "typeVersion": 1.1
    },
    {
      "id": "e4f611b0-d2e8-4538-8aa5-10f160b16049",
      "name": "Generate Podcast Script (GPT-5)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        8496,
        816
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5",
          "cachedResultName": "GPT-5"
        },
        "options": {
          "textFormat": {
            "textOptions": {
              "type": "json_schema",
              "schema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"script\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"order\": { \"type\": \"integer\" },\n          \"host\": { \"type\": \"string\", \"enum\": [\"A\", \"B\"] },\n          \"text\": { \"type\": \"string\" }\n        },\n        \"required\": [\"order\", \"host\", \"text\"],\n        \"additionalProperties\": false\n      }\n    }\n  },\n  \"required\": [\"script\"],\n  \"additionalProperties\": false\n}"
            }
          }
        },
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "=You are scripting a 4-minute podcast in english. Aim for 25-35 short conversational turns total.\n\nCAST:\n- Host A: Avery, a young female American host. Curious, asks probing\n  questions, plays the \"interested generalist.\"\n- Host B: Devansh, a young male Indian host. The \"expert\" who explains\n  concepts, reacts to A's questions, occasionally challenges A.\n\nDIALOGUE RULES:\n1. Hosts MUST react to each other. B never just delivers a paragraph \u2014\n   B responds to what A just said, then adds new information.\n2. Average turn length: 1-3 sentences. Long monologues are forbidden.\n3. Use connective tissue: \"Right, so...\", \"Wait, but...\", \"Hmm, push back\n   on that...\", \"That's a great point \u2014 and actually...\"\n4. Include 3+ moments of interruption, qualification, or clarifying questions.\n5. Open: A welcomes listeners, introduces B + topic. Close: B summarizes,\n   A signs off.\n6. Snappy back-and-forth is the goal.\n\nNumber each turn sequentially in the `order` field. Output JSON matching\nthe schema."
            },
            {
              "content": "={{ $json.text }}"
            }
          ]
        },
        "builtInTools": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "6f099ed0-ae55-474e-934d-93ef870c54a9",
      "name": "Split Script Into Turns",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        8784,
        816
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "output[0].content[0].text.script"
      },
      "typeVersion": 1
    },
    {
      "id": "4249a143-52a7-4eaa-9884-f3bcd39d9eb2",
      "name": "Route by Host",
      "type": "n8n-nodes-base.switch",
      "position": [
        8992,
        816
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "hostA",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "85998933-8933-4cea-89d0-8ad266985f46",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.host }}",
                    "rightValue": "A"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "hostB",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e3a90670-b317-4f10-86aa-f94e8adc29df",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.host}}",
                    "rightValue": "B"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "aad2c4ef-ca7e-445f-96f2-cc9b5d1b0664",
      "name": "Synthesize Host A Audio",
      "type": "n8n-nodes-smallestai.smallestai",
      "position": [
        9360,
        800
      ],
      "parameters": {
        "text": "={{ $json.text }}",
        "voiceId": "avery",
        "additionalOptions": {}
      },
      "typeVersion": 1
    },
    {
      "id": "33798e91-a00b-4475-8064-f010fc13f877",
      "name": "Synthesize Host B Audio",
      "type": "n8n-nodes-smallestai.smallestai",
      "position": [
        9376,
        1024
      ],
      "parameters": {
        "text": "={{ $json.text }}",
        "voiceId": "devansh",
        "additionalOptions": {}
      },
      "typeVersion": 1
    },
    {
      "id": "94643a79-f43e-4f57-9b37-76d4ab7c0821",
      "name": "Preserve Host A Order",
      "type": "n8n-nodes-base.set",
      "position": [
        9584,
        800
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e2f8a2b1-b402-4344-a53a-2f6b726b2488",
              "name": "order",
              "type": "string",
              "value": "={{ $('Route by Host').item.json.order }}"
            },
            {
              "id": "4989e8e4-c429-4c61-9705-8193b4be85f2",
              "name": "host",
              "type": "string",
              "value": "={{ $('Route by Host').item.json.host }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "f14a3026-f707-4d72-8e5c-2ed6da414d9f",
      "name": "Preserve Host B Order",
      "type": "n8n-nodes-base.set",
      "position": [
        9600,
        1024
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "88d4bddb-d7ef-44ce-9d6f-c5ce95b84e49",
              "name": "order",
              "type": "string",
              "value": "={{ $('Route by Host').item.json.order }}"
            },
            {
              "id": "5bcb040a-ca64-4eb9-a5e9-d690a481910e",
              "name": "host",
              "type": "string",
              "value": "={{ $('Route by Host').item.json.host }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "e56ef207-0cf0-4d61-8244-c52b37ee27f7",
      "name": "Merge Both Hosts",
      "type": "n8n-nodes-base.merge",
      "position": [
        9920,
        1008
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "db2ad06c-aa24-4cd1-9240-8268e807df76",
      "name": "Sort by Conversational Order",
      "type": "n8n-nodes-base.sort",
      "position": [
        10128,
        1008
      ],
      "parameters": {
        "options": {},
        "sortFieldsUi": {
          "sortField": [
            {
              "fieldName": "order"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d4b967c6-27cd-4eab-ba2e-83af67917abe",
      "name": "Concatenate WAV Audio",
      "type": "n8n-nodes-base.code",
      "position": [
        10352,
        1008
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nfunction parseWav(buffer) {\n  const sampleRate = buffer.readUInt32LE(24);\n  const numChannels = buffer.readUInt16LE(22);\n  const bitsPerSample = buffer.readUInt16LE(34);\n  const dataSize = buffer.readUInt32LE(40);\n  const pcmData = buffer.slice(44, 44 + dataSize);\n  return { sampleRate, numChannels, bitsPerSample, pcmData };\n}\n\nfunction buildWavHeader(totalDataSize, sampleRate, numChannels, bitsPerSample) {\n  const header = Buffer.alloc(44);\n  const byteRate = sampleRate * numChannels * bitsPerSample / 8;\n  const blockAlign = numChannels * bitsPerSample / 8;\n  header.write('RIFF', 0);\n  header.writeUInt32LE(36 + totalDataSize, 4);\n  header.write('WAVE', 8);\n  header.write('fmt ', 12);\n  header.writeUInt32LE(16, 16);\n  header.writeUInt16LE(1, 20);\n  header.writeUInt16LE(numChannels, 22);\n  header.writeUInt32LE(sampleRate, 24);\n  header.writeUInt32LE(byteRate, 28);\n  header.writeUInt16LE(blockAlign, 32);\n  header.writeUInt16LE(bitsPerSample, 34);\n  header.write('data', 36);\n  header.writeUInt32LE(totalDataSize, 40);\n  return header;\n}\n\nconst pcmChunks = [];\nlet format = null;\n\nfor (let i = 0; i < items.length; i++) {\n  const buffer = await this.helpers.getBinaryDataBuffer(i, 'data');\n  const parsed = parseWav(buffer);\n\n  if (!format) {\n    format = {\n      sampleRate: parsed.sampleRate,\n      numChannels: parsed.numChannels,\n      bitsPerSample: parsed.bitsPerSample\n    };\n  }\n  pcmChunks.push(parsed.pcmData);\n}\n\nconst totalPcm = Buffer.concat(pcmChunks);\nconst header = buildWavHeader(\n  totalPcm.length,\n  format.sampleRate,\n  format.numChannels,\n  format.bitsPerSample\n);\nconst finalWav = Buffer.concat([header, totalPcm]);\n\nreturn [{\n  json: { fileName: 'podcast.wav', sizeBytes: finalWav.length },\n  binary: {\n    data: await this.helpers.prepareBinaryData(finalWav, 'podcast.wav', 'audio/wav')\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "f73e4d22-9382-4d04-a63c-fc8547b06a80",
      "name": "Email Podcast to User",
      "type": "n8n-nodes-base.gmail",
      "position": [
        10672,
        1008
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "Your generated podcast is attached. Powered by Smallest AI.",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {}
            ]
          }
        },
        "subject": "Your AI Podcast is Ready \ud83c\udf99\ufe0f"
      },
      "typeVersion": 2.2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "connections": {
    "Route by Host": {
      "main": [
        [
          {
            "node": "Synthesize Host A Audio",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Synthesize Host B Audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Both Hosts": {
      "main": [
        [
          {
            "node": "Sort by Conversational Order",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Form Submitted": {
      "main": [
        [
          {
            "node": "Extract Data from File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Concatenate WAV Audio": {
      "main": [
        [
          {
            "node": "Email Podcast to User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preserve Host A Order": {
      "main": [
        [
          {
            "node": "Merge Both Hosts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preserve Host B Order": {
      "main": [
        [
          {
            "node": "Merge Both Hosts",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Extract Data from File": {
      "main": [
        [
          {
            "node": "Generate Podcast Script (GPT-5)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Script Into Turns": {
      "main": [
        [
          {
            "node": "Route by Host",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Synthesize Host A Audio": {
      "main": [
        [
          {
            "node": "Preserve Host A Order",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Synthesize Host B Audio": {
      "main": [
        [
          {
            "node": "Preserve Host B Order",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sort by Conversational Order": {
      "main": [
        [
          {
            "node": "Concatenate WAV Audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Podcast Script (GPT-5)": {
      "main": [
        [
          {
            "node": "Split Script Into Turns",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Turn whitepapers, research reports, blog drafts, lecture notes, or company memos into NotebookLM-style audio briefings. Native Hindi, Tamil, Telugu, Kannada, Malayalam, Bengali, Marathi, Gujarati, and Punjabi support makes this the only n8n template that ships authentic…

Source: https://n8n.io/workflows/15350/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

What it is An automated LinkedIn content system that takes a simple form (idea + optional file), generates LinkedIn posts with OpenAI, stores them in Notion, builds Google Slides carousels, and auto-p

Form Trigger, OpenAI, Notion +6
AI & RAG

Automatically analyze your full sports performance evolution using your Strava activities, enriched with AI insights and delivered directly to your email — all powered by your own n8n instance.

Google Sheets, OpenAI, Stop And Error +3
AI & RAG

This template is designed for content creators, podcasters, businesses, and researchers who need to transcribe long audio recordings that exceed OpenAI Whisper's 25 MB file size limit (~20 minutes of

Form Trigger, HTTP Request, OpenAI +1
AI & RAG

An n8n-based automation that generates client proposals from a form, lets you review everything in one place, and sends the proposal only when you approve it.

Form Trigger, Google Sheets Trigger, OpenAI +4
AI & RAG

Automatically gather hundreds of real customer reviews from five major platforms in one run using Thordata API and Proxy — Trustpilot, Capterra, Chrome Web Store, TrustRadius, and Product Hunt — then

HTTP Request, OpenAI, Form Trigger +1