8
n8n 中文网amn8n.com

语音翻译桥接 (Telegram → Slack),集成GPT-4o-mini和Whisper

高级

这是一个Personal Productivity, Multimodal AI领域的自动化工作流,包含 24 个节点。主要使用 If, Set, Code, Function, HttpRequest 等节点。 语音翻译桥接 (Telegram → Slack),集成GPT-4o-mini和Whisper

前置要求
  • 可能需要目标 API 的认证凭证
  • Telegram Bot Token
  • OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "name": "Voice Translator Bridge (Telegram → Slack) with GPT-4o-mini + Whisper",
  "nodes": [
    {
      "id": "92ef6daa-251b-4203-b7c3-aa64451e9973",
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "notes": "📥 Telegramで音声メッセージを受信したら起動するトリガー。messageイベントを監視。",
      "position": [
        -2192,
        -560
      ],
      "webhookId": "8052efdf-3111-4357-8f76-11509f3bc4f1",
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "id": "",
          "name": "TELEGRAM_BOT_CRED"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "46355ee1-472a-45b8-9a30-bd2661b2edf6",
      "name": "Is Voice?",
      "type": "n8n-nodes-base.if",
      "notes": "🎤 受信データが音声メッセージかどうか判定。voice要素がある場合のみ次へ進む。",
      "position": [
        -1952,
        -560
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{$json[\"message\"][\"voice\"] !== undefined ? \"voice\" : \"other\"}}",
              "value2": "voice"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ff56e185-727a-4aed-af00-dbc583e62078",
      "name": "Get File ID",
      "type": "n8n-nodes-base.set",
      "notes": "📄 Telegramメッセージからfile_idと送信者情報を抽出。ユーザー名がなければfirst_nameを使用。",
      "position": [
        -1760,
        -656
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "file_id",
              "value": "={{$json[\"message\"][\"voice\"][\"file_id\"]}}"
            },
            {
              "name": "chat_id",
              "value": "={{$json[\"message\"][\"chat\"][\"id\"]}}"
            },
            {
              "name": "from_username",
              "value": "={{$json[\"message\"][\"from\"][\"username\"] || $json[\"message\"][\"from\"][\"first_name\"] || \"unknown\"}}"
            }
          ]
        },
        "options": {},
        "keepOnlySet": true
      },
      "typeVersion": 1
    },
    {
      "id": "714c4a56-f886-47a9-97bf-85099f70b35d",
      "name": "Telegram getFile",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "🧾 Telegram APIから音声ファイルのファイルパス(file_path)を取得。",
      "position": [
        -1440,
        -656
      ],
      "parameters": {
        "url": "=https://api.telegram.org/bot{{$json[\"bot_token\"]}}/getFile?file_id={{$json[\"file_id\"]}}",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "8c523645-2952-45ce-9e3a-a3850084b858",
      "name": "Build File URL",
      "type": "n8n-nodes-base.function",
      "notes": "🔗 実際にダウンロードできるファイルURLを組み立て。",
      "position": [
        -1184,
        -560
      ],
      "parameters": {
        "functionCode": "// 1. Telegramの音声ファイルの相対パス (e.g. \"voice/file_0.oga\")\nconst filePath = items[0].json.result.file_path;\n\n// 2. Botトークンは Add Bot Token ノードから取る\nconst token = $items(\"Add Bot Token\")[0].json.bot_token;\n\n// 3. Telegramの実ファイルURLを組み立て\n//    形式: https://api.telegram.org/file/bot<BOT_TOKEN>/<file_path>\nconst fileUrl = `https://api.telegram.org/file/bot${token}/${filePath}`;\n\n// 4. chat_id と from_username は Get File ID ノードの値をそのまま流す\nconst chat_id = $items(\"Get File ID\")[0].json.chat_id;\nconst from_username = $items(\"Get File ID\")[0].json.from_username;\n\n// 5. 後続ノード(Download Voice File)に必要な情報を返す\nreturn [\n  {\n    json: {\n      file_url: fileUrl,\n      chat_id,\n      from_username\n    }\n  }\n];\n"
      },
      "typeVersion": 1
    },
    {
      "id": "00727b12-217a-4169-925d-f0988c608a3c",
      "name": "Download Voice File",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "⬇️ Telegramの音声データをバイナリとして取得。",
      "position": [
        -864,
        -560
      ],
      "parameters": {
        "url": "={{$json[\"file_url\"]}}",
        "options": {},
        "responseFormat": "file"
      },
      "typeVersion": 1
    },
    {
      "id": "dc8c842b-675f-4423-a86b-358fa479c256",
      "name": "Extract Transcript",
      "type": "n8n-nodes-base.set",
      "notes": "📝 Whisperの結果(text)を取り出して整形。",
      "position": [
        -2192,
        -320
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "transcript_text",
              "value": "={{$json.text}}"
            },
            {
              "name": "from_username",
              "value": "={{$items(\"Build File URL\")[0].json.from_username}}"
            }
          ]
        },
        "options": {},
        "keepOnlySet": true
      },
      "typeVersion": 1
    },
    {
      "id": "148b8a46-4a3a-4574-932e-ec84c3e01a8d",
      "name": "Detect Language",
      "type": "n8n-nodes-base.function",
      "notes": "🌏 日本語/英語をざっくり判定。漢字・かなを含めばja扱い。",
      "position": [
        -1952,
        -320
      ],
      "parameters": {
        "functionCode": "const text = $json.transcript_text || \"\";\nconst jaRegex = /[ぁ-んァ-ン一-龠]/;\nconst isJa = jaRegex.test(text);\nreturn [{ json: { original_text: text, source_lang: isJa ? 'ja' : 'en', target_lang: isJa ? 'en' : 'ja', from_username: $json.from_username } }];"
      },
      "typeVersion": 1
    },
    {
      "id": "0096f37e-8157-46e5-af36-67c5397389a4",
      "name": "Translate (OpenAI)",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "🔁 OpenAI GPT-4o-miniで翻訳(Whisperと同じAPIキーで完結)。",
      "position": [
        -1360,
        -320
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/chat/completions",
        "options": {},
        "requestMethod": "POST",
        "authentication": "headerAuth",
        "jsonParameters": true,
        "bodyParametersJson": "={\n  \"model\": \"gpt-4o-mini\",\n  \"temperature\": 0.2,\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"You are a translation engine. Translate exactly, preserving meaning and tone. Output ONLY the translated text.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"Source language: {{$json.source_lang}}\\nTarget language: {{$json.target_lang}}\\nText:\\n{{$json.original_text}}\"\n    }\n  ]\n}\n",
        "queryParametersJson": "=",
        "headerParametersJson": "={\n  \"Authorization\": \"Bearer {{$credentials.httpHeaderAuth.headerValue}}\",\n  \"Content-Type\": \"application/json\"\n}\n"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "",
          "name": "OPENAI_HEADER_AUTH"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "40a54c88-fed2-4388-a2ac-f1e824ecc900",
      "name": "Build Slack Message",
      "type": "n8n-nodes-base.function",
      "notes": "💬 Slackに投稿する本文を組み立て。Bot投稿+Telegramの@ユーザー名付き。",
      "position": [
        -704,
        -320
      ],
      "parameters": {
        "functionCode": "// === 言語コードを国旗に変換 ===\nfunction flagFor(lang) {\n  if (lang === 'ja') return '🇯🇵';\n  if (lang === 'en') return '🇺🇸';\n  return '🌐';\n}\n\n// Detect Language ノードから言語を取得\nconst sourceLang = $node[\"Detect Language\"].json.source_lang || 'en';\nconst targetLang = $node[\"Detect Language\"].json.target_lang || 'en';\n\nconst src = flagFor(sourceLang);\nconst dst = flagFor(targetLang);\n\n// Telegram ユーザー名\nconst username = $node[\"Get File ID\"].json.from_username || 'unknown';\n\n// Whisper or Detect Language の原文テキスト\nconst original =\n  $node[\"Extract Transcript\"].json.text ||\n  $node[\"Detect Language\"].json.original_text ||\n  '(no transcript)';\n\n// 翻訳結果\nconst translated =\n  $node[\"Translate (OpenAI)\"].json.choices[0].message.content ||\n  '(no translation)';\n\n// Slackに投稿する本文\nconst text = `*${src} → ${dst}* (@${username})\n> ${original}\n\n${translated}\n`;\n\nreturn [{ json: { slack_text: text } }];\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5c36ed2c-cf48-4162-abc4-9ed8c7dc6f0b",
      "name": "Post to Slack",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "🚀 Slack Botが指定チャンネルに翻訳結果を投稿。投稿者はBot、本文にTelegram名を表示。",
      "position": [
        -224,
        -320
      ],
      "parameters": {
        "url": "https://slack.com/api/chat.postMessage",
        "options": {},
        "requestMethod": "POST",
        "authentication": "headerAuth",
        "bodyParametersUi": {
          "parameter": [
            {
              "name": "channel",
              "value": "{{YOUR_SLACK_CHANNEL_ID}}"
            },
            {
              "name": "text",
              "value": "={{$json.slack_text}}"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "",
          "name": "SLACK_BOT_TOKEN_HEADER"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5c36c02a-46ac-4d67-bc28-de11f7c9f258",
      "name": "Add Bot Token",
      "type": "n8n-nodes-base.set",
      "position": [
        -1600,
        -560
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "83ae047b-fdd8-4061-b10a-82921ae9201c",
              "name": "bot_token",
              "type": "string",
              "value": "{{YOUR_TELEGRAM_BOT_TOKEN}}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "29bb8262-a2a3-4a28-a5b6-a8c4013a5179",
      "name": "Prepare Whisper Input1",
      "type": "n8n-nodes-base.code",
      "position": [
        -544,
        -560
      ],
      "parameters": {
        "jsCode": "// \"data\" バイナリを \"audio\" にコピーし、Whisper用に渡す\nreturn [\n  {\n    json: { ...$json },\n    binary: { audio: $binary.data }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "160f0494-e66c-4da0-8ae4-bfad272bfdc8",
      "name": "Transcribe a recording",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        -240,
        -560
      ],
      "parameters": {
        "options": {},
        "resource": "audio",
        "operation": "transcribe",
        "binaryPropertyName": "audio"
      },
      "credentials": {
        "openAiApi": {
          "id": "",
          "name": "OPENAI_API_KEY_HEADER"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "9b9e59f1-67fe-42ba-88b5-3a7259d4340b",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -928,
        -976
      ],
      "parameters": {
        "height": 416,
        "content": "### 🎯 Purpose  \nDownloads the actual `.oga` or `.mp3` file from Telegram.\n\n### ⚙️ Setup  \n- Method: `GET`\n- URL: `{{$json.file_url}}`\n- **Send Binary Data:** ✅ (ON)\n\n### 🧩 Output  \nBinary data under `$binary.data`\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c6ac3585-a699-4713-b816-00a05f735f3b",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1248,
        -976
      ],
      "parameters": {
        "color": 5,
        "width": 256,
        "height": 416,
        "content": "### 🎯 Purpose  \nConstructs the Telegram file URL for download.\n\n### ⚙️ Setup  \nUse an **Expression**:\n```\nhttps://api.telegram.org/file/bot{{$credentials.telegramApi.accessToken}}/{{$json.file_path}}\n```\n\n### 🧩 Output  \n`file_url` → used in **Download Voice File**\n"
      },
      "typeVersion": 1
    },
    {
      "id": "475b3e8a-34f4-4687-b58e-7474792ec14f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2304,
        -944
      ],
      "parameters": {
        "color": 4,
        "width": 320,
        "height": 384,
        "content": "### 🎯 Purpose  \nStarts the workflow when a **voice message** is received in Telegram.\n\n### ⚙️ Setup  \n- Connect your **Telegram Bot Token** (Credential: `TELEGRAM_BOT_TOKEN`).\n- This node listens for incoming messages (`audio`, `voice`, or `text`).\n\n### 🧩 Output  \nContains:\n- `message.from.username`\n- `message.voice.file_id`\n- Optional `message.text`"
      },
      "typeVersion": 1
    },
    {
      "id": "c2ccfb01-1eae-4577-9cf8-bf5ebdb5c2db",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1760,
        -976
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 320,
        "content": "### 🎯 Purpose  \nRetrieve the Telegram voice file's metadata.\n\n### ⚙️ Setup  \n- Input: `file_id` from the Trigger node  \n- Calls Telegram API `getFile` to obtain the `file_path`.\n\n### 🧩 Output  \n`file_path` (used to build the actual download URL)"
      },
      "typeVersion": 1
    },
    {
      "id": "23fca2a8-99ee-49b4-9129-dfc38e23225e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        -976
      ],
      "parameters": {
        "color": 2,
        "width": 224,
        "height": 416,
        "content": "### 🎯 Purpose  \nPrepare binary audio data for the Whisper node.\n\n### ⚙️ Setup  \n- Input: `$binary.data`\n- Output: rename to `audio` (binary key expected by Whisper)\n\n### 🧩 Output  \nBinary → `$binary.audio`"
      },
      "typeVersion": 1
    },
    {
      "id": "a762b0c7-2b17-4380-8947-cea69841b5ba",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -304,
        -976
      ],
      "parameters": {
        "color": 3,
        "height": 416,
        "content": "### 🎯 Purpose  \nConvert voice to text using **OpenAI Whisper**.\n\n### ⚙️ Setup  \n- Credential: `OPENAI_API_KEY_HEADER`\n- Resource: `Audio`\n- Operation: `Transcribe a Recording`\n- Input Data Field Name: `audio`\n\n### ⚠️ Note  \nMax file size = 25 MB.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "eae1d9fa-9cec-4209-b7d8-f11246380512",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2032,
        -176
      ],
      "parameters": {
        "color": 6,
        "width": 272,
        "height": 432,
        "content": "### 🎯 Purpose  \nDetect source language from the transcription text.\n\n### ⚙️ Setup  \nSimple **IF or Code node** to detect “ja” vs “en”.  \nUsed later for flag direction (🇯🇵→🇺🇸 or 🇺🇸→🇯🇵)."
      },
      "typeVersion": 1
    },
    {
      "id": "fb850072-380e-4b4a-bed1-d141814e7fe3",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1648,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 624,
        "content": "### 🎯 Purpose  \nTranslate transcribed text using **GPT-4o-mini**.\n\n### ⚙️ Setup  \n- Request Method: POST  \n- URL: `https://api.openai.com/v1/chat/completions`  \n- Headers:\n  ```json\n  {\n    \"Authorization\": \"Bearer {{$credentials.OPENAI_API_KEY_HEADER}}\",\n    \"Content-Type\": \"application/json\"\n  }\n  ```\n- Body (JSON/RAW):\n  ```json\n  {\n    \"model\": \"gpt-4o-mini\",\n    \"temperature\": 0.2,\n    \"messages\": [\n      { \"role\": \"system\", \"content\": \"You are a translation engine. Translate accurately and clearly.\" },\n      { \"role\": \"user\", \"content\": \"Source language: {{$json.source_lang}}\\nTarget language: {{$json.target_lang}}\\nText:\\n{{$json.text}}\" }\n    ]\n  }\n  ```\n\n### 🧩 Output  \n`choices[0].message.content` → translated text\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c8bd3ff0-7181-4611-a1a8-c901fc62795f",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -832,
        -176
      ],
      "parameters": {
        "color": 3,
        "width": 368,
        "height": 432,
        "content": "### 🎯 Purpose  \nFormats the translated message for Slack.\n\n### ⚙️ Example (Code node)\n```js\nconst src = $json.source_lang === 'ja' ? '🇯🇵' : '🇺🇸';\nconst dst = $json.target_lang === 'ja' ? '🇯🇵' : '🇺🇸';\nconst username = $node[\"Get File ID\"].json.from_username || 'unknown';\nconst original = $node[\"Extract Transcript\"].json.text || '(no transcript)';\nconst translated = $node[\"Translate (OpenAI)\"].json.choices[0].message.content || '(no translation)';\n\nconst text = `${src} → ${dst} (@${username})\\n> ${original}\\n\\n${translated}`;\nreturn [{ json: { slack_text: text } }];\n```\n\n### 🧩 Output  \n`slack_text` → sent to next node\n"
      },
      "typeVersion": 1
    },
    {
      "id": "287d070d-c5df-458b-8c33-00c9b4215a03",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -352,
        -176
      ],
      "parameters": {
        "color": 4,
        "width": 368,
        "height": 496,
        "content": "### 🎯 Purpose  \nPost the final translated message into Slack.\n\n### ⚙️ Setup  \n- Authentication: `Header Auth`  \n- Credential: `SLACK_BOT_TOKEN_HEADER`  \n- URL: `https://slack.com/api/chat.postMessage`  \n- JSON Body:\n  ```json\n  {\n    \"channel\": \"C09NT81DQU\",\n    \"text\": \"{{$json.slack_text}}\"\n  }\n  ```\n\n### ✅ Tip  \nUse a test channel first (e.g., `#voice-bridge`) before production.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7924fc16-4594-4c87-b564-5b7eaaa5dd1e",
  "connections": {
    "Is Voice?": {
      "main": [
        [
          {
            "node": "Get File ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get File ID": {
      "main": [
        [
          {
            "node": "Add Bot Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Bot Token": {
      "main": [
        [
          {
            "node": "Telegram getFile",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build File URL": {
      "main": [
        [
          {
            "node": "Download Voice File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Detect Language": {
      "main": [
        [
          {
            "node": "Translate (OpenAI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Is Voice?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram getFile": {
      "main": [
        [
          {
            "node": "Build File URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Transcript": {
      "main": [
        [
          {
            "node": "Detect Language",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Translate (OpenAI)": {
      "main": [
        [
          {
            "node": "Build Slack Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Slack Message": {
      "main": [
        [
          {
            "node": "Post to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Voice File": {
      "main": [
        [
          {
            "node": "Prepare Whisper Input1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Whisper Input1": {
      "main": [
        [
          {
            "node": "Transcribe a recording",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transcribe a recording": {
      "main": [
        [
          {
            "node": "Extract Transcript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 个人效率, 多模态 AI

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量24
分类2
节点类型8
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Tomohiro Goto

Tomohiro Goto

@taoo

Creative Technologist blending design and automation to make work a little more fun. Exploring how AI and workflow tools like n8n can bring creativity into everyday work.

外部链接
在 n8n.io 查看

分享此工作流