{
  "name": "YouTube \u2192 Audio \u2192 Transcribe \u2192 Summarize (Deepgram)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "yt-audio-sum",
        "responseMode": "lastNode",
        "options": {
          "responseData": {
            "responsePropertyName": "data"
          }
        }
      },
      "id": "Webhook_1",
      "name": "Webhook (trigger)",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        -1400,
        0
      ]
    },
    {
      "parameters": {
        "functionCode": "const body = items[0].json || {};\nconst url = body.url || body.input || body.link || '';\nif (!url) throw new Error('\u8bf7\u5728 JSON body \u91cc\u4f20\u5165 { \"url\": \"<YouTube\u5730\u5740>\" }');\nconst m = url.match(/(?:v=|youtu\\.be\\/|shorts\\/)([A-Za-z0-9_-]{11})/);\nif (!m) throw new Error('\u65e0\u6cd5\u4ece\u94fe\u63a5\u4e2d\u89e3\u6790\u51fa videoId');\nreturn [{ url, videoId: m[1] }];"
      },
      "id": "Function_ExtractId",
      "name": "Extract videoId",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        -1150,
        0
      ]
    },
    {
      "parameters": {
        "url": "https://piped.video/api/v1/streams/{{$json.videoId}}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "HTTP_GetStreams",
      "name": "Get Streams (Piped)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [
        -900,
        0
      ]
    },
    {
      "parameters": {
        "functionCode": "const res = items[0].json;\nif (!res || !Array.isArray(res.audioStreams)) {\n  throw new Error('\u672a\u83b7\u53d6\u5230\u97f3\u9891\u6d41\u4fe1\u606f');\n}\n// \u9009\u7801\u7387\u6700\u9ad8\u7684\u97f3\u9891\uff1b\u4f18\u5148 opus/webm \u5176\u540e m4a/mp4a\nconst prefer = s => ({\n  codec: (s.codec || '').toLowerCase(),\n  mime: (s.mimeType || '').toLowerCase(),\n  br: Number(s.bitrate || 0),\n});\nlet best = null;\nfor (const s of res.audioStreams) {\n  const p = prefer(s);\n  const score = (p.br || 0)\n    + (p.codec.includes('opus') ? 50000 : 0)\n    + (p.mime.includes('webm') ? 20000 : 0)\n    + (p.mime.includes('mp4') || p.mime.includes('m4a') ? 10000 : 0);\n  if (!best || score > best._score) {\n    best = { ...s, _score: score };\n  }\n}\nif (!best || !best.url) throw new Error('\u6ca1\u6709\u53ef\u7528\u7684\u97f3\u9891\u76f4\u94fe');\nreturn [{\n  videoId: $json.videoId,\n  sourceUrl: $json.url,\n  audioUrl: best.url,\n  audioInfo: best\n}];"
      },
      "id": "Function_PickAudio",
      "name": "Pick Best Audio",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        -650,
        0
      ]
    },
    {
      "parameters": {
        "url": "https://api.deepgram.com/v1/listen?model=nova-2&punctuate=true&paragraphs=true&detect_language=true&smart_format=true",
        "options": {
          "timeout": 180000
        },
        "sendBody": true,
        "jsonParameters": true,
        "bodyParametersJson": "{\"url\":\"{{$json.audioUrl}}\"}",
        "headerParametersJson": "{\"Authorization\":\"Token YOUR_DEEPGRAM_API_KEY\",\"Content-Type\":\"application/json\"}",
        "responseFormat": "json"
      },
      "id": "HTTP_Deepgram",
      "name": "Transcribe (Deepgram)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [
        -390,
        0
      ]
    },
    {
      "parameters": {
        "functionCode": "const dg = items[0].json;\n// \u517c\u5bb9\u4e0d\u540c\u8fd4\u56de\u7ed3\u6784\uff0c\u5c3d\u91cf\u53d6\u6bb5\u843d\nlet text = '';\ntry {\n  const alt = dg.results?.channels?.[0]?.alternatives?.[0];\n  const paras = alt?.paragraphs?.paragraphs;\n  if (Array.isArray(paras) && paras.length) {\n    text = paras.map(p => p.text).join('\\n\\n');\n  }\n  if (!text) text = alt?.transcript || '';\n} catch (e) {}\nif (!text) throw new Error('\u8f6c\u5199\u7ed3\u679c\u4e3a\u7a7a');\n// \u7b80\u5355\u6e05\u6d17\u4e0e\u5206\u5757\ntext = text.replace(/\\s+/g,' ').trim();\nconst chunks = [];\nconst chunkSize = 10000;\nfor (let i = 0; i < text.length; i += chunkSize) {\n  chunks.push(text.slice(i, i + chunkSize));\n}\nreturn [{\n  videoId: $json.videoId,\n  sourceUrl: $json.sourceUrl,\n  audioUrl: $json.audioUrl,\n  transcript: text,\n  chunks\n}];"
      },
      "id": "Function_CleanChunks",
      "name": "Clean & Chunk Transcript",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        -140,
        0
      ]
    },
    {
      "parameters": {
        "operation": "chat",
        "model": "gpt-4o",
        "systemMessage": "\u4f60\u662f\u4e13\u4e1a\u7684\u89c6\u9891\u7b14\u8bb0\u4e0e\u6458\u8981\u52a9\u624b\u3002\u8bf7\u57fa\u4e8e\u7528\u6237\u63d0\u4f9b\u7684\u9010\u5b57\u7a3f\uff0c\u8f93\u51fa\u7ed3\u6784\u5316\u4e2d\u6587\u603b\u7ed3\u3002\u8981\u6c42\uff1a\u51c6\u786e\u3001\u51dd\u7ec3\u3001\u53ef\u626b\u8bfb\uff1b\u5fc5\u8981\u65f6\u52a0\u5165\u7b80\u77ed\u65f6\u95f4\u6233\uff08\u5982\u679c\u80fd\u4ece\u8f6c\u5199\u91cc\u63a8\u65ad\uff09\u3002\u8f93\u51fa Markdown\uff0c\u5305\u542b\uff1a\\n1) 30 \u79d2\u901f\u89c8\uff083-6\u6761\u8981\u70b9\uff09\\n2) \u5173\u952e\u89c2\u70b9\u4e0e\u4e8b\u5b9e\uff08\u5206\u9879\u5217\u51fa\uff09\\n3) \u7ae0\u8282\u5927\u7eb2\uff08\u82e5\u80fd\uff0c\u7ed9\u51fa\u5927\u81f4\u65f6\u95f4\u70b9/\u8303\u56f4\uff09\\n4) \u884c\u52a8\u6e05\u5355 / \u5efa\u8bae\\n5) \u82e5\u4e3a\u6559\u7a0b/\u8bc4\u6d4b\uff1a\u7ed9\u51fa\u5de5\u5177/\u53c2\u6570/\u4f18\u7f3a\u70b9/\u7ed3\u8bba",
        "messages": {
          "messageUi": {
            "message": [
              {
                "text": "<TRANSCRIPT>\\n{{$json.transcript}}\\n</TRANSCRIPT>",
                "type": "user"
              }
            ]
          }
        },
        "additionalFields": {
          "temperature": 0.3,
          "maxTokens": 2200
        }
      },
      "id": "OpenAI_Summarize",
      "name": "Summarize (OpenAI)",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 4,
      "position": [
        120,
        0
      ],
      "credentials": {}
    },
    {
      "parameters": {
        "responseBody": "{{$json.choices[0].message.content}}",
        "statusCode": 200,
        "responseHeaders": {
          "entries": [
            {
              "name": "Content-Type",
              "value": "text/markdown; charset=utf-8"
            }
          ]
        }
      },
      "id": "Webhook_Response",
      "name": "Respond",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        370,
        0
      ]
    }
  ],
  "connections": {
    "Webhook (trigger)": {
      "main": [
        [
          {
            "node": "Extract videoId",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract videoId": {
      "main": [
        [
          {
            "node": "Get Streams (Piped)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Streams (Piped)": {
      "main": [
        [
          {
            "node": "Pick Best Audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pick Best Audio": {
      "main": [
        [
          {
            "node": "Transcribe (Deepgram)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transcribe (Deepgram)": {
      "main": [
        [
          {
            "node": "Clean & Chunk Transcript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean & Chunk Transcript": {
      "main": [
        [
          {
            "node": "Summarize (OpenAI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarize (OpenAI)": {
      "main": [
        [
          {
            "node": "Respond",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "meta": {
    "templateCredsSetup": true
  }
}