> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Telegram-Bot für Transkriptionen

> **Note**
>
> **Anleitung** · Setzt voraus, dass Sie den [Speech to Text Schnellstart](/docs/de/eleven-api/guides/cookbooks/speech-to-text) abgeschlossen haben und über ein Telegram-Bot-Token sowie ein
> Supabase-Konto verfügen.

## Einführung

In diesem Tutorial lernen Sie, wie Sie einen Telegram-Bot erstellen, der Audio- und Videonachrichten in über 90 Sprachen mit TypeScript und dem ElevenLabs-Scribe-Modell über die Speech-to-Text-API transkribiert.

## Voraussetzungen

* Ein ElevenLabs-Konto mit einem [API-Schlüssel](https://elevenlabs.io/app/settings/api-keys).
* Ein [Supabase](https://supabase.com)-Konto (Sie können sich über [database.new](https://database.new) kostenlos registrieren).
* Die auf Ihrem Gerät installierte [Supabase CLI](https://supabase.com/docs/guides/local-development).
* Die auf Ihrem Gerät installierte [Deno-Runtime](https://docs.deno.com/runtime/getting_started/installation/) und optional die [Einrichtung in Ihrer bevorzugten IDE](https://docs.deno.com/runtime/getting_started/setup_your_environment).
* Ein [Telegram](https://telegram.org)-Konto.

## Einrichtung

### Einen Telegram-Bot registrieren

Erstellen Sie mit dem [BotFather](https://t.me/BotFather) einen neuen Telegram-Bot. Führen Sie den Befehl `/newbot` aus und folgen Sie den Anweisungen, um einen neuen Bot zu erstellen. Am Ende erhalten Sie Ihr geheimes Bot-Token. Notieren Sie es sicher für den nächsten Schritt.

![BotFather](/docs/_fern-img/28aa856bb6ace1b49b82076a18f1e281a8a4f37bbb6cfc59c22d644564377248.webp)

### Ein Supabase-Projekt lokal erstellen

Führen Sie nach der Installation der [Supabase CLI](https://supabase.com/docs/guides/local-development) den folgenden Befehl aus, um lokal ein neues Supabase-Projekt zu erstellen:

```bash
supabase init
```

### Eine Datenbanktabelle für Transkriptionsergebnisse erstellen

Erstellen Sie als Nächstes eine neue Datenbanktabelle, um die Transkriptionsergebnisse zu protokollieren:

```bash
supabase migrations new init
```

Dadurch wird im Verzeichnis `supabase/migrations` eine neue Migrationsdatei erstellt. Öffnen Sie die Datei und fügen Sie das folgende SQL hinzu:

**`supabase/migrations/init.sql`**

```sql supabase/migrations/init.sql
CREATE TABLE IF NOT EXISTS transcription_logs (
  id BIGSERIAL PRIMARY KEY,
  file_type VARCHAR NOT NULL,
  duration INTEGER NOT NULL,
  chat_id BIGINT NOT NULL,
  message_id BIGINT NOT NULL,
  username VARCHAR,
  transcript TEXT,
  language_code VARCHAR,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
  error TEXT
);

ALTER TABLE transcription_logs ENABLE ROW LEVEL SECURITY;
```

### Eine Supabase Edge Function für Telegram-Webhook-Anfragen erstellen

Erstellen Sie als Nächstes eine neue Edge Function, die Telegram-Webhook-Anfragen verarbeitet:

```bash
supabase functions new scribe-bot
```

Wenn Sie VS Code oder Cursor verwenden, wählen Sie `y`, wenn die CLI „Generate VS Code settings for Deno? \[y/N]“ abfragt.

### Umgebungsvariablen einrichten

Erstellen Sie im Verzeichnis `supabase/functions` eine neue `.env`-Datei und fügen Sie die folgenden Variablen hinzu:

**`supabase/functions/.env`**

```env supabase/functions/.env
# Find / create an API key at https://elevenlabs.io/app/settings/api-keys
ELEVENLABS_API_KEY=your_api_key

# The bot token you received from the BotFather.
TELEGRAM_BOT_TOKEN=your_bot_token

# A random secret chosen by you to secure the function.
FUNCTION_SECRET=random_secret
```

### Abhängigkeiten

Das Projekt verwendet einige Abhängigkeiten:

* Das Open-Source-[grammY-Framework](https://grammy.dev/) zur Verarbeitung der Telegram-Webhook-Anfragen.
* Die Bibliothek [@supabase/supabase-js](https://supabase.com/docs/reference/javascript) für die Interaktion mit der Supabase-Datenbank.
* Das ElevenLabs-[JavaScript SDK](/docs/de/eleven-api/quickstart) für die Interaktion mit der Speech-to-Text-API.

Da Supabase Edge Function die [Deno-Runtime](https://deno.land/) verwendet, müssen Sie die Abhängigkeiten nicht installieren. Sie können sie über das Präfix `npm:` [importieren](https://docs.deno.com/examples/npm/).

## Telegram-Bot programmieren

Fügen Sie in Ihrer neu erstellten Datei `scribe-bot/index.ts` den folgenden Code hinzu:

**`supabase/functions/scribe-bot/index.ts`**

```ts supabase/functions/scribe-bot/index.ts
import { Bot, webhookCallback } from "https://deno.land/x/grammy@v1.34.0/mod.ts";
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import { createClient } from "jsr:@supabase/supabase-js@2";
import { ElevenLabsClient } from "npm:elevenlabs@1.50.5";

console.log(`Function "elevenlabs-scribe-bot" up and running!`);

const elevenlabs = new ElevenLabsClient({
  apiKey: Deno.env.get("ELEVENLABS_API_KEY") || "",
});

const supabase = createClient(
  Deno.env.get("SUPABASE_URL") || "",
  Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") || ""
);

async function scribe({
  fileURL,
  fileType,
  duration,
  chatId,
  messageId,
  username,
}: {
  fileURL: string;
  fileType: string;
  duration: number;
  chatId: number;
  messageId: number;
  username: string;
}) {
  let transcript: string | null = null;
  let languageCode: string | null = null;
  let errorMsg: string | null = null;
  try {
    const sourceFileArrayBuffer = await fetch(fileURL).then((res) => res.arrayBuffer());
    const sourceBlob = new Blob([sourceFileArrayBuffer], {
      type: fileType,
    });

    const scribeResult = await elevenlabs.speechToText.convert({
      file: sourceBlob,
      model_id: "scribe_v2",
      tag_audio_events: false,
    });

    transcript = scribeResult.text;
    languageCode = scribeResult.language_code;

    // Reply to the user with the transcript
    await bot.api.sendMessage(chatId, transcript, {
      reply_parameters: { message_id: messageId },
    });
  } catch (error) {
    errorMsg = error.message;
    console.log(errorMsg);
    await bot.api.sendMessage(chatId, "Sorry, there was an error. Please try again.", {
      reply_parameters: { message_id: messageId },
    });
  }
  // Write log to Supabase.
  const logLine = {
    file_type: fileType,
    duration,
    chat_id: chatId,
    message_id: messageId,
    username,
    language_code: languageCode,
    error: errorMsg,
  };
  console.log({ logLine });
  await supabase.from("transcription_logs").insert({ ...logLine, transcript });
}

const telegramBotToken = Deno.env.get("TELEGRAM_BOT_TOKEN");
const bot = new Bot(telegramBotToken || "");
const startMessage = `Welcome to the ElevenLabs Scribe Bot\\! I can transcribe speech in 90\\+ languages with super high accuracy\\!
    \nTry it out by sending or forwarding me a voice message, video, or audio file\\!
    \n[Learn more about Scribe](https://elevenlabs.io/speech-to-text) or [build your own bot](https://elevenlabs.io/developers/guides/cookbooks/speech-to-text/telegram-bot)\\!
  `;
bot.command("start", (ctx) => ctx.reply(startMessage.trim(), { parse_mode: "MarkdownV2" }));

bot.on([":voice", ":audio", ":video"], async (ctx) => {
  try {
    const file = await ctx.getFile();
    const fileURL = `https://api.telegram.org/file/bot${telegramBotToken}/${file.file_path}`;
    const fileMeta = ctx.message?.video ?? ctx.message?.voice ?? ctx.message?.audio;

    if (!fileMeta) {
      return ctx.reply("No video|audio|voice metadata found. Please try again.");
    }

    // Run the transcription in the background.
    EdgeRuntime.waitUntil(
      scribe({
        fileURL,
        fileType: fileMeta.mime_type!,
        duration: fileMeta.duration,
        chatId: ctx.chat.id,
        messageId: ctx.message?.message_id!,
        username: ctx.from?.username || "",
      })
    );

    // Reply to the user immediately to let them know we received their file.
    return ctx.reply("Received. Scribing...");
  } catch (error) {
    console.error(error);
    return ctx.reply(
      "Sorry, there was an error getting the file. Please try again with a smaller file!"
    );
  }
});

const handleUpdate = webhookCallback(bot, "std/http");

Deno.serve(async (req) => {
  try {
    const url = new URL(req.url);
    if (url.searchParams.get("secret") !== Deno.env.get("FUNCTION_SECRET")) {
      return new Response("not allowed", { status: 405 });
    }

    return await handleUpdate(req);
  } catch (err) {
    console.error(err);
  }
});
```

### Code im Detail

Im Code gibt es einige wichtige Punkte. Sehen wir sie uns Schritt für Schritt an.

#### Eingehende Anfrage verarbeiten

Verwenden Sie zur Verarbeitung der eingehenden Anfrage den Handler `Deno.serve`. Der Handler prüft, ob die Anfrage das richtige Secret enthält, und übergibt die Anfrage dann an die Funktion `handleUpdate`.

```ts {1,6,10}
const handleUpdate = webhookCallback(bot, 'std/http');

Deno.serve(async (req) => {
  try {
    const url = new URL(req.url);
    if (url.searchParams.get('secret') !== Deno.env.get('FUNCTION_SECRET')) {
      return new Response('not allowed', { status: 405 });
    }

    return await handleUpdate(req);
  } catch (err) {
    console.error(err);
  }
});
```

#### Sprach-, Audio- und Videonachrichten verarbeiten

Das grammY-Framework bietet eine praktische Möglichkeit, nach bestimmten Nachrichtentypen zu [filtern](https://grammy.dev/guide/filter-queries#combining-multiple-queries). In diesem Fall lauscht der Bot auf Sprach-, Audio- und Videonachrichten.

Über den Anfragekontext extrahiert der Bot die Dateimetadaten und verwendet dann [Supabase Background Tasks](https://supabase.com/docs/guides/functions/background-tasks) `EdgeRuntime.waitUntil`, um die Transkription im Hintergrund auszuführen.

So können Sie dem Nutzer sofort antworten und die Transkription der Datei im Hintergrund verarbeiten.

```ts {1,3,12,24}
bot.on([':voice', ':audio', ':video'], async (ctx) => {
  try {
    const file = await ctx.getFile();
    const fileURL = `https://api.telegram.org/file/bot${telegramBotToken}/${file.file_path}`;
    const fileMeta = ctx.message?.video ?? ctx.message?.voice ?? ctx.message?.audio;

    if (!fileMeta) {
      return ctx.reply('No video|audio|voice metadata found. Please try again.');
    }

    // Run the transcription in the background.
    EdgeRuntime.waitUntil(
      scribe({
        fileURL,
        fileType: fileMeta.mime_type!,
        duration: fileMeta.duration,
        chatId: ctx.chat.id,
        messageId: ctx.message?.message_id!,
        username: ctx.from?.username || '',
      })
    );

    // Reply to the user immediately to let them know we received their file.
    return ctx.reply('Received. Scribing...');
  } catch (error) {
    console.error(error);
    return ctx.reply(
      'Sorry, there was an error getting the file. Please try again with a smaller file!'
    );
  }
});
```

#### Transkription mit der ElevenLabs-API

Schließlich verwendet der Bot im Hintergrund-Worker das ElevenLabs JavaScript SDK, um die Datei zu transkribieren. Sobald die Transkription abgeschlossen ist, antwortet der Bot dem Nutzer mit dem Transkript und schreibt mit [supabase-js](https://supabase.com/docs/reference/javascript) einen Protokolleintrag in die Supabase-Datenbank.

```ts {29-38,43-46,54-65}
const elevenlabs = new ElevenLabsClient({
  apiKey: Deno.env.get('ELEVENLABS_API_KEY') || '',
});

const supabase = createClient(
  Deno.env.get('SUPABASE_URL') || '',
  Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') || ''
);

async function scribe({
  fileURL,
  fileType,
  duration,
  chatId,
  messageId,
  username,
}: {
  fileURL: string;
  fileType: string;
  duration: number;
  chatId: number;
  messageId: number;
  username: string;
}) {
  let transcript: string | null = null;
  let languageCode: string | null = null;
  let errorMsg: string | null = null;
  try {
    const sourceFileArrayBuffer = await fetch(fileURL).then((res) => res.arrayBuffer());
    const sourceBlob = new Blob([sourceFileArrayBuffer], {
      type: fileType,
    });

    const scribeResult = await elevenlabs.speechToText.convert({
      file: sourceBlob,
      model_id: 'scribe_v2',
      tag_audio_events: false,
    });

    transcript = scribeResult.text;
    languageCode = scribeResult.language_code;

    // Reply to the user with the transcript
    await bot.api.sendMessage(chatId, transcript, {
      reply_parameters: { message_id: messageId },
    });
  } catch (error) {
    errorMsg = error.message;
    console.log(errorMsg);
    await bot.api.sendMessage(chatId, 'Sorry, there was an error. Please try again.', {
      reply_parameters: { message_id: messageId },
    });
  }
  // Write log to Supabase.
  const logLine = {
    file_type: fileType,
    duration,
    chat_id: chatId,
    message_id: messageId,
    username,
    language_code: languageCode,
    error: errorMsg,
  };
  console.log({ logLine });
  await supabase.from('transcription_logs').insert({ ...logLine, transcript });
}
```

## In Supabase bereitstellen

Falls noch nicht geschehen, erstellen Sie unter [database.new](https://database.new) ein neues Supabase-Konto und verknüpfen Sie das lokale Projekt mit Ihrem Supabase-Konto:

```bash
supabase link
```

### Datenbankmigrationen anwenden

Führen Sie den folgenden Befehl aus, um die Datenbankmigrationen aus dem Verzeichnis `supabase/migrations` anzuwenden:

```bash
supabase db push
```

Öffnen Sie im Supabase-Dashboard den [Tabelleneditor](https://supabase.com/dashboard/project/_/editor). Dort sollte eine leere Tabelle `transcription_logs` angezeigt werden.

![Leere Tabelle](/docs/_fern-img/c1493deafcd6c53712dcb4fa7a44b3253b571ade0bb2e9c2b4fdb090088b0695.webp)

Führen Sie abschließend den folgenden Befehl aus, um die Edge Function bereitzustellen:

```bash
supabase functions deploy --no-verify-jwt scribe-bot
```

Öffnen Sie im Supabase-Dashboard die [Edge-Functions-Ansicht](https://supabase.com/dashboard/project/_/functions). Dort sollte die bereitgestellte Funktion `scribe-bot` angezeigt werden. Notieren Sie sich die Funktions-URL, da Sie sie später benötigen. Sie sollte etwa so aussehen: `https://<project-ref>.functions.supabase.co/scribe-bot`.

![Bereitgestellte Edge Function](/docs/_fern-img/d12141a51a09563d625b379201de844800e0c7dcfa9e6c7f21484cbca7ff37cf.webp)

### Webhook einrichten

Setzen Sie die Webhook-URL Ihres Bots auf `https://<PROJECT_REFERENCE>.functions.supabase.co/telegram-bot` (ersetzen Sie `<...>` durch die jeweiligen Werte). Senden Sie dazu einfach eine GET-Anfrage an die folgende URL, beispielsweise in Ihrem Browser:

```
https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/setWebhook?url=https://<PROJECT_REFERENCE>.supabase.co/functions/v1/scribe-bot?secret=<FUNCTION_SECRET>
```

Beachten Sie, dass `FUNCTION_SECRET` dem Secret entspricht, das Sie in Ihrer `.env`-Datei festgelegt haben.

![Webhook festlegen](/docs/_fern-img/ac72044bd3df138da3d8a0df09e8413e8a9fd8a5c3156a525d6b13664854482f.webp)

### Funktions-Secrets festlegen

Nachdem Sie alle Secrets lokal festgelegt haben, können Sie mit dem folgenden Befehl die Secrets in Ihrem Supabase-Projekt setzen:

```bash
supabase secrets set --env-file supabase/functions/.env
```

## Bot testen

Testen Sie den Bot abschließend, indem Sie ihm eine Sprach-, Audio- oder Videonachricht senden.

![Bot testen](/docs/_fern-img/a42c784e6324f15575e0299bafe02a253a2bdc57f2ad5844f83e5b64297780e7.webp)

Nachdem Sie das Transkript als Antwort sehen, wechseln Sie zurück zum Tabelleneditor im Supabase-Dashboard. Dort sollte eine neue Zeile in Ihrer Tabelle `transcription_logs` angezeigt werden.

![Neue Zeile in der Tabelle](/docs/_fern-img/25c008858276b7cd4af6f8e72473891176bb9e2ce62e7002af353a2dac205e06.webp)

## Nächste Schritte

#### [API-Referenz](/docs/de/api-reference/speech-to-text)

Vollständige Speech-to-Text-API-Referenz und Parameter.

#### [Twilio-Integration](/docs/de/eleven-api/guides/how-to/text-to-speech/twilio)

Integrieren Sie ElevenLabs TTS mit Twilio für telefonbasierte Sprachanwendungen.