Meeting-Protokoll-Generator

Experte

Dies ist ein Content Creation, Multimodal AI-Bereich Automatisierungsworkflow mit 33 Nodes. Hauptsächlich werden If, Set, Code, Wait, Filter und andere Nodes verwendet. Meeting-Protokolle mit Whisper, Ollama LLM und Notion aus Videos generieren

Voraussetzungen
  • Notion API Key
  • Discord Bot Token oder Webhook
  • Google Drive API-Anmeldedaten
Workflow-Vorschau
Visualisierung der Node-Verbindungen, mit Zoom und Pan
Workflow exportieren
Kopieren Sie die folgende JSON-Konfiguration und importieren Sie sie in n8n
{
  "id": "62eZeoZUfZggUZjF",
  "meta": {
    "instanceId": "27650765c3e508261bc31ddf41c375a2c061aa629fcd9acda37f6c830ffa7e38",
    "templateCredsSetupCompleted": true
  },
  "name": "Meeting Minutes Maker",
  "tags": [],
  "nodes": [
    {
      "id": "6d521590-dd15-49fe-88cb-d732265653a5",
      "name": "Warten",
      "type": "n8n-nodes-base.wait",
      "position": [
        -9712,
        -32
      ],
      "webhookId": "4e3401fd-8c15-4c7b-86e7-4ef10200fb56",
      "parameters": {
        "amount": 3
      },
      "typeVersion": 1.1
    },
    {
      "id": "3913a10a-4787-40eb-b34d-c6df1a53c05b",
      "name": "Befehl ausführen",
      "type": "n8n-nodes-base.executeCommand",
      "onError": "continueRegularOutput",
      "position": [
        -9456,
        -32
      ],
      "parameters": {
        "command": "=powershell.exe -ExecutionPolicy Bypass -File \"G:\\obs\\tools\\wait-for-file.ps1\" -FilePath \"{{ $('Wait').item.json.path }}\""
      },
      "typeVersion": 1
    },
    {
      "id": "c560e8cf-a988-4713-8bda-b28410cd4bb8",
      "name": "Wenn",
      "type": "n8n-nodes-base.if",
      "position": [
        -9312,
        -32
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "22a384ae-7d08-42d8-a844-142827385c85",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.stdout }}",
              "rightValue": "0"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6433a78c-7766-4da4-9f35-e7e6efcd0ff7",
      "name": "Warten1",
      "type": "n8n-nodes-base.wait",
      "position": [
        -9136,
        -16
      ],
      "webhookId": "64e56e60-d0ed-443b-b79c-dcd8a63d34ee",
      "parameters": {
        "amount": 3
      },
      "typeVersion": 1.1
    },
    {
      "id": "4f45e4aa-a5f1-4fda-a3c6-7366ecefd950",
      "name": "Notizzettel1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -9760,
        -112
      ],
      "parameters": {
        "color": 3,
        "width": 1056,
        "height": 304,
        "content": "## Wait for file copy to finish\n"
      },
      "typeVersion": 1
    },
    {
      "id": "b6799161-3f29-49f3-ad45-4a7a77f83709",
      "name": "Seite erstellen",
      "type": "n8n-nodes-base.notion",
      "position": [
        -6896,
        -48
      ],
      "parameters": {
        "title": "={{ $('File').item.json.path.split(/[/\\\\]/).pop().replace(/\\.[^/.]+$/, '') }}",
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "26ddc80914ee803a9896f7a313c44125"
        },
        "options": {}
      },
      "credentials": {
        "notionApi": {
          "id": "SdAYMLbk9wHzKAn2",
          "name": "Notion account"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e39ec985-66df-4434-85e5-0a673d562b50",
      "name": "Filtern",
      "type": "n8n-nodes-base.filter",
      "position": [
        -8912,
        -48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "fb3de4a9-893a-4311-8a6f-046f459d9181",
              "operator": {
                "type": "string",
                "operation": "endsWith"
              },
              "leftValue": "={{ $('File').item.json.path }}",
              "rightValue": "mkv"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7a7ebdab-91c5-4c2a-b508-72614ce230c1",
      "name": "Notizen erstellen",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        -6224,
        -48
      ],
      "parameters": {
        "text": "You are a professional meeting assistant. Your task is to generate clear, concise, and actionable meeting minutes from the provided transcript.\n\nYou will receive:\n- A full text transcript of the meeting with timestamps.\n- A link to the original video recording for reference.\n\nYour output must be well-structured and include the following sections:\n\n**1. Main Topics Discussed**\nSummarize the key subjects that were covered.\n\n**2. Decisions Made**\nList any definitive conclusions or choices that were agreed upon.\n\n**3. Action Items**\nList concrete next steps. For each, try to identify the responsible person and the task.\nFormat: `- [Owner's Name] → [Specific Task]`\n\n**4. Issues & Blockers**\nNote any problems, technical difficulties, or obstacles that were raised.\n\n**5. Next Steps & Deadlines**\nOutline the immediate future actions and any mentioned deadlines.\n\n**Guidelines:**\n- **Do not** provide a word-for-word transcript. Summarize and synthesize.\n- **Be concise and professional.**\n- **Use bullet points** for lists and action items.\n- **Reference the video:** If a specific moment in the discussion is critical, you can note its relevance, but the primary link to the full recording will be provided separately.\n\n**File Name:** {{ $('File').item.json.path }}\n\n### START OF TRANSCRIPT ###\n{{ $('Set Transcript Data').item.json.transcript }}\n### END OF TRANSCRIPT ###\n\n**Expected Output Format (in Markdown):**\n\n# Meeting Notes - [Meeting Name from File]\n**Date:** [Date extracted from the file name]\n\n## Main Topics Discussed\n- ...\n\n## Decisions Made\n- ...\n\n## Action Items\n- [Owner's Name] → [Specific Task]\n\n## Issues & Blockers\n- ...\n\n## Next Steps & Deadlines\n- ...",
        "batching": {},
        "promptType": "define"
      },
      "executeOnce": true,
      "typeVersion": 1.7
    },
    {
      "id": "b334ad41-b972-43e4-8e5c-2e5d25b88bd6",
      "name": "Parse für Notion",
      "type": "n8n-nodes-base.code",
      "position": [
        -5392,
        -48
      ],
      "parameters": {
        "jsCode": "const text = $('Create Notes').first().json.text; // El texto original muy largo que quieres dividir\n// Función para dividir texto en bloques de max 2000 chars\nfunction splitTextIntoBlocks(str, maxSize = 2000) {\n  const result = [];\n  for (let i = 0; i < str.length; i += maxSize) {\n    const chunk = str.substring(i, i + maxSize);\n    result.push({chunk});\n  }\n  return result;\n}\nconst blocks = splitTextIntoBlocks(text);\n// Devolver el array para usar en el nodo Notion en el campo blocks (children)\n//return [{ json: { blocks } }];\nreturn splitTextIntoBlocks(text);"
      },
      "typeVersion": 2
    },
    {
      "id": "2238df32-057e-4f9b-8888-9997018175b3",
      "name": "Über Elemente iterieren",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -4592,
        -48
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "31ab577f-87ae-4160-8ce9-370c0a39359a",
      "name": "Block anhängen",
      "type": "n8n-nodes-base.notion",
      "position": [
        -4368,
        -32
      ],
      "parameters": {
        "blockId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $node[\"Create a page\"].json.id }}"
        },
        "blockUi": {
          "blockValues": [
            {
              "text": {
                "text": [
                  {
                    "text": "={{ $json.chunk }}",
                    "annotationUi": {}
                  }
                ]
              },
              "richText": true
            }
          ]
        },
        "resource": "block"
      },
      "credentials": {
        "notionApi": {
          "id": "SdAYMLbk9wHzKAn2",
          "name": "Notion account"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "593874f0-3fd2-44cc-b25f-38af5ef78592",
      "name": "Datei",
      "type": "n8n-nodes-base.localFileTrigger",
      "position": [
        -10048,
        -32
      ],
      "parameters": {
        "path": "G:\\OBS\\videos",
        "events": [
          "add"
        ],
        "options": {
          "depth": 0,
          "awaitWriteFinish": true
        },
        "triggerOn": "folder"
      },
      "typeVersion": 1
    },
    {
      "id": "323e836a-4408-4cd9-91e2-afa998624090",
      "name": "WAV erstellen",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        -7824,
        -48
      ],
      "parameters": {
        "command": "=python G:\\OBS\\tools\\create_wav.py \"{{ $('File').item.json.path }}\""
      },
      "typeVersion": 1
    },
    {
      "id": "0e1f1c0a-ee1c-4a79-b2c7-af4b53643fc3",
      "name": "Lokal transkribieren",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        -7648,
        -48
      ],
      "parameters": {
        "command": "=python G:\\OBS\\tools\\transcribe_return.py \"{{ $('File').item.json.path }}\""
      },
      "typeVersion": 1
    },
    {
      "id": "f0895e66-f550-487a-8ff3-098104d9d84c",
      "name": "Transkriptdaten setzen",
      "type": "n8n-nodes-base.set",
      "position": [
        -7280,
        -48
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "78b62534-3f5f-4978-bad7-2d9a97787e86",
              "name": "transcript",
              "type": "string",
              "value": "={{ $('Transcribe Local').item.json.stdout }}"
            },
            {
              "id": "1c1442d9-2876-406d-963d-d282a6caa891",
              "name": "scripts",
              "type": "string",
              "value": "Script"
            },
            {
              "id": "4f009110-51e2-4679-b33f-b6944d2d4c4d",
              "name": "drive_link",
              "type": "string",
              "value": "={{ $('Upload video file').item.json.webViewLink }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "aea30152-5b6c-4a41-8c1c-a517d47b3960",
      "name": "Transkriptdatei speichern",
      "type": "n8n-nodes-base.executeCommand",
      "onError": "continueRegularOutput",
      "position": [
        -7456,
        -48
      ],
      "parameters": {
        "command": "=echo {{ JSON.stringify($json.stdout) }} > \"{{ $('File').item.json.path.replace(/\\.[^/.]+$/, '.transcript.txt') }}\""
      },
      "typeVersion": 1
    },
    {
      "id": "c3e7a795-f86f-4b7d-9934-05c3715b82fe",
      "name": "Notizdatei speichern",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        -5952,
        -48
      ],
      "parameters": {
        "command": "=echo {{ JSON.stringify($json.text) }} > \"{{ $('File').item.json.path.replace(/\\.[^/.]+$/, '.notes.txt') }}\""
      },
      "typeVersion": 1
    },
    {
      "id": "e3136ca2-040d-4aa6-bfe9-ecd31b2604c4",
      "name": "MKV von Festplatte lesen",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        -8336,
        -48
      ],
      "parameters": {
        "options": {},
        "fileSelector": "={{ $('File').item.json.path.replace(/\\\\/g, '/') }}"
      },
      "typeVersion": 1
    },
    {
      "id": "97e06a40-b35d-4ef7-86f8-f0e54a61af60",
      "name": "Video-URL einfügen",
      "type": "n8n-nodes-base.notion",
      "onError": "continueRegularOutput",
      "position": [
        -6704,
        -48
      ],
      "parameters": {
        "blockId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "blockUi": {
          "blockValues": [
            {
              "text": {
                "text": [
                  {
                    "text": "=LINK: {{ $('File').item.json.path.replace(/\\\\/g, '/').split('/').pop() }}",
                    "isLink": true,
                    "textLink": "={{ $('Set Transcript Data').item.json.drive_link }}",
                    "annotationUi": {}
                  }
                ]
              },
              "type": "heading_3",
              "richText": true
            }
          ]
        },
        "resource": "block"
      },
      "credentials": {
        "notionApi": {
          "id": "SdAYMLbk9wHzKAn2",
          "name": "Notion account"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1b49cce9-be3e-4ce0-a64f-b7f942af1923",
      "name": "Videodatei hochladen",
      "type": "n8n-nodes-base.googleDrive",
      "onError": "continueRegularOutput",
      "position": [
        -8176,
        -48
      ],
      "parameters": {
        "name": "={{ $('File').item.json.path.replace(/\\\\/g, '/').split('/').pop() }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Create sub-folder').item.json.id }}"
        },
        "inputDataFieldName": "=data"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "22CXYKCYaEQGsnxb",
          "name": "Google Drive 7r1ck"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "c58d7f3f-fc60-4c6d-af43-2840ab02ae8e",
      "name": "Unterordner erstellen",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -8512,
        -48
      ],
      "parameters": {
        "name": "={{ $('File').item.json.path.replace(/\\\\/g, '/').split('/').pop().replace(/\\.[^/.]+$/, '') }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "1EXauY-BVnK-A8-t4fJ_M0C9RghTzIFsO",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1EXauY-BVnK-A8-t4fJ_M0C9RghTzIFsO",
          "cachedResultName": "Meetings"
        },
        "resource": "folder"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "22CXYKCYaEQGsnxb",
          "name": "Google Drive 7r1ck"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "ae938a6b-5a60-49d8-9df5-992f2d148b27",
      "name": "gpt-oss 4090",
      "type": "@n8n/n8n-nodes-langchain.lmOllama",
      "position": [
        -6224,
        176
      ],
      "parameters": {
        "model": "gpt-oss:20b",
        "options": {
          "numCtx": 6144,
          "numBatch": 6144
        }
      },
      "credentials": {
        "ollamaApi": {
          "id": "n0CXfSOCEkuRDnXC",
          "name": "Ollama 4090"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3f5aa733-e084-4c9e-910b-2a861103b112",
      "name": "Notizzettel",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -8608,
        -112
      ],
      "parameters": {
        "color": 4,
        "width": 608,
        "height": 256,
        "content": "## Upload to Google Drive"
      },
      "typeVersion": 1
    },
    {
      "id": "c9f67d15-0af6-43db-8c3f-1789d5e85867",
      "name": "Notizzettel2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -7904,
        -112
      ],
      "parameters": {
        "color": 7,
        "width": 768,
        "height": 240,
        "content": "## Create Wav and Transcribe with Local Whisper Model"
      },
      "typeVersion": 1
    },
    {
      "id": "55beaebd-6914-4160-81c1-46c0c0749a1f",
      "name": "Notizzettel3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -6960,
        -112
      ],
      "parameters": {
        "color": 6,
        "width": 432,
        "height": 240,
        "content": "## Generate Notion Page"
      },
      "typeVersion": 1
    },
    {
      "id": "3143ebdd-0bc2-475e-9a6a-146b22556f69",
      "name": "Notizzettel4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -6304,
        -112
      ],
      "parameters": {
        "color": 7,
        "width": 1088,
        "height": 432,
        "content": "## Create Notes with local Ollama Model and parse the info for Notion"
      },
      "typeVersion": 1
    },
    {
      "id": "05b07726-dcff-4fec-9787-f70528240d76",
      "name": "Notizzettel5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4688,
        -128
      ],
      "parameters": {
        "color": 6,
        "width": 640,
        "height": 304,
        "content": "## Generate Notion Page and send notification"
      },
      "typeVersion": 1
    },
    {
      "id": "ff40d58e-90fb-4939-9682-cbe56c6920d6",
      "name": "Notizzettel6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -10192,
        -112
      ],
      "parameters": {
        "color": 2,
        "width": 384,
        "height": 304,
        "content": "## New File Trigger"
      },
      "typeVersion": 1
    },
    {
      "id": "2bcacbb4-1f9b-4d4c-af9d-ca388c6e086c",
      "name": "Discord",
      "type": "n8n-nodes-base.discord",
      "position": [
        -4224,
        -32
      ],
      "webhookId": "703933bb-e3e3-406a-b41a-4b41087dbeed",
      "parameters": {
        "content": "={{ $('Loop Over Items').item.json.chunk }}",
        "options": {},
        "authentication": "webhook"
      },
      "credentials": {
        "discordWebhookApi": {
          "id": "0clcSqUuBfZr5qV0",
          "name": "n8n-meeting-notes"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "9a966128-f9ec-4fa4-bbed-03f09647989e",
      "name": "Notizzettel8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -9712,
        336
      ],
      "parameters": {
        "color": 7,
        "width": 1056,
        "height": 352,
        "content": "## wait-for-file.ps1\n```\nparam(\n    [Parameter(Mandatory=$true)]\n    [string]$FilePath\n)\ntry {\n    # Try to open the file in exclusive read mode (no sharing)\n    $fileStream = [System.IO.File]::Open($FilePath, 'Open', 'Read', 'None')\n    $fileStream.Close()\n    $fileStream.Dispose()\n    # If we reach this point, the file is free\n    Write-Output \"0\"\n}\ncatch {\n    # Any error: locked, doesn't exist, permissions, etc. → consider it \"blocked\"\n    Write-Output \"1\"\n}\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "9098cf0f-ec0f-43e5-96d9-72431000e352",
      "name": "Notizzettel9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -8608,
        336
      ],
      "parameters": {
        "color": 7,
        "width": 944,
        "height": 1056,
        "content": "## create_wav.py\n```\nimport subprocess\nimport math\nimport sys\nimport os\n\ndef get_duration(input_path):\n    \"\"\"Get duration in seconds using ffprobe\"\"\"\n    cmd = [\n        'ffprobe', '-v', 'error',\n        '-show_entries', 'format=duration',\n        '-of', 'default=noprint_wrappers=1:nokey=1',\n        input_path\n    ]\n    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)\n    try:\n        duration_sec = float(result.stdout.strip())\n    except ValueError:\n        raise RuntimeError(\"Could not get duration with ffprobe.\")\n    return duration_sec\n\ndef convert_to_wav(input_path):\n    max_size_bytes = 25 * 1024 * 1024  # 25 MB\n    duration = get_duration(input_path)\n    max_bitrate = (max_size_bytes * 8) / duration  # bits per second\n    min_samplerate = 8000\n    min_channels = 1\n    bits_per_sample = 16  # pcm_s16le\n    max_samplerate = int(max_bitrate / (min_channels * bits_per_sample))\n    \n    if max_samplerate > 44100:\n        samplerate = 44100\n        codec = 'pcm_s16le'\n    elif max_samplerate < min_samplerate:\n        samplerate = min_samplerate\n        codec = 'adpcm_ms'\n    else:\n        samplerate = max_samplerate\n        codec = 'pcm_s16le'\n    \n    output_path = os.path.splitext(input_path)[0] + '.wav'\n    ffmpeg_cmd = [\n        'ffmpeg', '-i', input_path, '-vn',\n        '-acodec', codec,\n        '-ar', str(samplerate),\n        '-ac', str(min_channels),\n        output_path,\n        '-y'  # overwrite without asking\n    ]\n    print(f\"Executing: {' '.join(ffmpeg_cmd)}\")\n    subprocess.run(ffmpeg_cmd, check=True)\n    print(f\"Converted file saved to: {output_path}\")\n\nif __name__ == \"__main__\":\n    if len(sys.argv) != 2:\n        print(f\"Usage: python {sys.argv[0]} path_to_file.mkv\")\n        sys.exit(1)\n    input_file = sys.argv[1]\n    convert_to_wav(input_file)\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "18ba0df7-61ef-42cf-9348-b514f90caa73",
      "name": "Notizzettel10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -7616,
        336
      ],
      "parameters": {
        "color": 7,
        "width": 1120,
        "height": 1776,
        "content": "## transcribe_return.py\n```\n# transcribe_return.py\nimport sys\nimport os\nimport whisper\nimport ffmpeg\nfrom datetime import timedelta\nimport re\n\ndef extract_audio(video_path, audio_path):\n    try:\n        (\n            ffmpeg\n            .input(video_path)\n            .output(audio_path, acodec='pcm_s16le', ac=1, ar='16000')\n            .overwrite_output()\n            .run(capture_stdout=True, capture_stderr=True)\n        )\n    except ffmpeg.Error as e:\n        print(\"❌ Error extracting audio with ffmpeg:\")\n        print(e.stderr.decode() if e.stderr else str(e))\n        sys.exit(1)\n\ndef format_time_for_txt(seconds):\n    \"\"\"Format seconds as [HH:MM:SS] for output\"\"\"\n    td = timedelta(seconds=seconds)\n    total_seconds = int(td.total_seconds())\n    hours, remainder = divmod(total_seconds, 3600)\n    minutes, seconds = divmod(remainder, 60)\n    return f\"[{hours:02}:{minutes:02}:{seconds:02}]\"\n\ndef transcribe_with_timestamps(audio_path, force_language=None):\n    \"\"\"\n    Transcribe the audio. If force_language is None, Whisper auto-detects it.\n    Returns: (segments, detected_or_forced_language)\n    \"\"\"\n    print(f\"🗣️ LANGUAGE FOR TRANSCRIPTION: {force_language or 'AUTO-DETECTION'}\")\n    model = whisper.load_model(\"small\")  # Change to \"small\" or \"medium\" if you need more accuracy\n    result = model.transcribe(audio_path, language=force_language, word_timestamps=False)\n    # If no language was forced, get the language detected by Whisper\n    detected_language = result.get(\"language\", \"unknown\")\n    if force_language is None:\n        print(f\"🔍 Automatically detected language: {detected_language}\")\n    return result[\"segments\"], detected_language\n\ndef extract_language_from_filename(video_path):\n    \"\"\"\n    Extract the language code from the filename, right before the final extension.\n    Example: \"file.es.mkv\" -> returns \"es\"\n             \"file.en.mp4\" -> returns \"en\"\n             \"file.mp4\" -> returns None\n    \"\"\"\n    name, ext = os.path.splitext(video_path)\n    match = re.search(r'\\.([a-z]{2})$', name)\n    if match:\n        return match.group(1)\n    return None\n\ndef main():\n    if len(sys.argv) < 2:\n        print(\"❌ Incorrect usage.\")\n        print(\"📌 Usage: python transcribe_return.py <video>\")\n        print(\"   - The language is automatically extracted from the filename if it has .xx before the extension.\")\n        print(\"   - Examples:\")\n        print(\"     - video.es.mkv   → uses Spanish and outputs with timestamps\")\n        print(\"     - video.en.mp4   → uses English and outputs with timestamps\")\n        print(\"     - video.mkv      → auto-detects and outputs without .xx\")\n        sys.exit(1)\n\n    video_path = sys.argv[1]\n    # 🔍 Extract language from filename\n    force_language = extract_language_from_filename(video_path)\n    print(f\"🎬 VIDEO: {video_path}\")\n    if force_language:\n        print(f\"🗣️ LANGUAGE EXTRACTED FROM FILENAME: {force_language}\")\n    else:\n        print(\"🗣️ LANGUAGE: AUTO-DETECTION (no .xx found in filename)\")\n\n    # 📁 Base filename WITHOUT the final extension (.mkv, .mp4, etc.)\n    base_name = os.path.splitext(video_path)[0]\n    audio_path = base_name + \".wav\"\n    print(f\"📝 Output: Transcription printed to STDOUT (no file saved)\")\n\n    # Extract audio\n    extract_audio(video_path, audio_path)\n    # Transcribe\n    segments, lang = transcribe_with_timestamps(audio_path, force_language)\n    # 👇👇👇 KEY CHANGE: INSTEAD OF SAVING TO A FILE, WE PRINT DIRECTLY\n    for seg in segments:\n        start_time = format_time_for_txt(seg[\"start\"])\n        text = seg[\"text\"].strip()\n        print(f\"{start_time} {text}\")\n\n    # Clean up temporary audio\n    try:\n        os.remove(audio_path)\n        print(f\"🗑️ Temporary audio deleted: {audio_path}\", file=sys.stderr)\n    except Exception as e:\n        print(f\"⚠️ Could not delete {audio_path}: {str(e)}\", file=sys.stderr)\n\n    print(f\"✅ Process completed! Transcription generated to STDOUT.\", file=sys.stderr)\n\nif __name__ == \"__main__\":\n    main()\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "185e7a73-ffd7-48e3-96e8-926d9287cc8a",
      "name": "Notizzettel7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -9744,
        272
      ],
      "parameters": {
        "color": 7,
        "width": 3296,
        "height": 1888,
        "content": "## Helper Scripts"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "executionOrder": "v1"
  },
  "versionId": "e5641f53-a2ef-4315-a04a-9b4196aa019f",
  "connections": {
    "c560e8cf-a988-4713-8bda-b28410cd4bb8": {
      "main": [
        [
          {
            "node": "e39ec985-66df-4434-85e5-0a673d562b50",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "6433a78c-7766-4da4-9f35-e7e6efcd0ff7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "593874f0-3fd2-44cc-b25f-38af5ef78592": {
      "main": [
        [
          {
            "node": "6d521590-dd15-49fe-88cb-d732265653a5",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6d521590-dd15-49fe-88cb-d732265653a5": {
      "main": [
        [
          {
            "node": "3913a10a-4787-40eb-b34d-c6df1a53c05b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6433a78c-7766-4da4-9f35-e7e6efcd0ff7": {
      "main": [
        [
          {
            "node": "3913a10a-4787-40eb-b34d-c6df1a53c05b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e39ec985-66df-4434-85e5-0a673d562b50": {
      "main": [
        [
          {
            "node": "c58d7f3f-fc60-4c6d-af43-2840ab02ae8e",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2bcacbb4-1f9b-4d4c-af9d-ca388c6e086c": {
      "main": [
        [
          {
            "node": "2238df32-057e-4f9b-8888-9997018175b3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "323e836a-4408-4cd9-91e2-afa998624090": {
      "main": [
        [
          {
            "node": "0e1f1c0a-ee1c-4a79-b2c7-af4b53643fc3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7a7ebdab-91c5-4c2a-b508-72614ce230c1": {
      "main": [
        [
          {
            "node": "c3e7a795-f86f-4b7d-9934-05c3715b82fe",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ae938a6b-5a60-49d8-9df5-992f2d148b27": {
      "ai_languageModel": [
        [
          {
            "node": "7a7ebdab-91c5-4c2a-b508-72614ce230c1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "b6799161-3f29-49f3-ad45-4a7a77f83709": {
      "main": [
        [
          {
            "node": "97e06a40-b35d-4ef7-86f8-f0e54a61af60",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "31ab577f-87ae-4160-8ce9-370c0a39359a": {
      "main": [
        [
          {
            "node": "2bcacbb4-1f9b-4d4c-af9d-ca388c6e086c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3913a10a-4787-40eb-b34d-c6df1a53c05b": {
      "main": [
        [
          {
            "node": "c560e8cf-a988-4713-8bda-b28410cd4bb8",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2238df32-057e-4f9b-8888-9997018175b3": {
      "main": [
        [],
        [
          {
            "node": "31ab577f-87ae-4160-8ce9-370c0a39359a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "97e06a40-b35d-4ef7-86f8-f0e54a61af60": {
      "main": [
        [
          {
            "node": "7a7ebdab-91c5-4c2a-b508-72614ce230c1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c3e7a795-f86f-4b7d-9934-05c3715b82fe": {
      "main": [
        [
          {
            "node": "b334ad41-b972-43e4-8e5c-2e5d25b88bd6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b334ad41-b972-43e4-8e5c-2e5d25b88bd6": {
      "main": [
        [
          {
            "node": "2238df32-057e-4f9b-8888-9997018175b3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "0e1f1c0a-ee1c-4a79-b2c7-af4b53643fc3": {
      "main": [
        [
          {
            "node": "aea30152-5b6c-4a41-8c1c-a517d47b3960",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c58d7f3f-fc60-4c6d-af43-2840ab02ae8e": {
      "main": [
        [
          {
            "node": "e3136ca2-040d-4aa6-bfe9-ecd31b2604c4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1b49cce9-be3e-4ce0-a64f-b7f942af1923": {
      "main": [
        [
          {
            "node": "323e836a-4408-4cd9-91e2-afa998624090",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e3136ca2-040d-4aa6-bfe9-ecd31b2604c4": {
      "main": [
        [
          {
            "node": "1b49cce9-be3e-4ce0-a64f-b7f942af1923",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f0895e66-f550-487a-8ff3-098104d9d84c": {
      "main": [
        [
          {
            "node": "b6799161-3f29-49f3-ad45-4a7a77f83709",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "aea30152-5b6c-4a41-8c1c-a517d47b3960": {
      "main": [
        [
          {
            "node": "f0895e66-f550-487a-8ff3-098104d9d84c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Häufig gestellte Fragen

Wie verwende ich diesen Workflow?

Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.

Für welche Szenarien ist dieser Workflow geeignet?

Experte - Content-Erstellung, Multimodales KI

Ist es kostenpflichtig?

Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.

Workflow-Informationen
Schwierigkeitsgrad
Experte
Anzahl der Nodes33
Kategorie2
Node-Typen15
Schwierigkeitsbeschreibung

Für fortgeschrittene Benutzer, komplexe Workflows mit 16+ Nodes

Autor
Facundo Cabrera

Facundo Cabrera

@fafacabrera

AI & Automation Developer | n8n • LangChain • Unreal Engine Building smart workflows & immersive tech for games and enterprise. Let’s automate your next big thing.

Externe Links
Auf n8n.io ansehen

Diesen Workflow teilen

Kategorien

Kategorien: 34