転写し、任意のWebページ上でオーディオを翻訳


私の提出の概要


任意のWebページ上でオーディオを転写し、翻訳することができるシンプルなブラウザの拡張子.拡張機能は、Webページ上でオーディオをキャプチャし、それをストリーミングによって動作しますDeepgram's Speech-To-Text API 転写のために、結果として生じる転写物はAzure's translation service ターゲット言語への翻訳.
ここでは、アーキテクチャの非常に高いレベルの概要です.

ここでは、様々なサイトからのオーディオコンテンツの転写と翻訳の拡張を示すデモです.私は、ディープグラムとAzureがどれくらい速く写して、オーディオを翻訳することができたかに感動しました.私は、2つの別々のサービスへのリアルタイム流動が理想的な解決でないと思います、しかし、プロトタイプとして、それはかなりよく行いました.
このような拡張モジュールの使用例は以下のようになります.
  • 古いコンテンツについては、誰も新しい転写や翻訳で更新する予定はありません
  • 小さな組織からのコンテンツ/個人/リソースを欠いている/複数の翻訳を提供する能力
  • あなたがより一般的な言語に翻訳を必要とするとき
  • この拡張のための私の目標は、コンテンツをよりアクセス可能にすることです.

    提出カテゴリ


    私は、「アクセシビリティ擁護者」カテゴリの下でこれを提出しています.

    Githubのコードへのリンク


    生雲 / 転写と翻訳


    単純なブラウザの拡張子を転写し、オーディオコンテンツを任意のWebページを翻訳することができます。


    転写と翻訳


    任意のWebページからオーディオを転写および変換することができるシンプルなブラウザの拡張子.拡張機能は、Webページ上でオーディオをキャプチャすることによって動作しDeepgram's Speech-To-Text API 転写してからAzure's translation service ターゲット言語への最終的な翻訳.それは私のエントリです.
    View on GitHub

    どうやってエクステンションを作ったの


    これはどのように拡張モジュールを構築するかについてのごく簡単な概要です.

    テキストへのディープグラムスピーチ


    使用するDeepgram's Speech-to-Text service 転写を扱う.Deepgramを使ったのは初めてでしたが、なかなか速く走れましたgreat documentation and lots of tutorials APIを理解するために.基本的には、

  • create an account , generate an API key
  • グラブワンthe SDKs またはREST endpoint directly
  • その後、ストリームのオーディオには、次のことができます転写のためのディープグラムにオーディオ.
    const socket = new WebSocket('wss://api.deepgram.com/v1/listen', ['token', token.key]);
    mediaRecorder.ondataavailable = function(evt) {
      if (socket && socket.readyState === socket.OPEN) {
        socket.send(evt.data); //
      }
    }
    socket.onmessage = function(results) {
      // parse the results from Deepgram
    }
    

    紺碧翻訳者


    使用するAzure's Translator ディープグラムSTTから目的言語への結果として生じる転写物を翻訳するサービス.繰り返しますが、ディープグラムには、次のようにする必要があります.
  • クリエイトan Azure account , を設定し、translator service ( APIサブスクリプションキーが生成されます)
  • グラブワンthe SDKs またはREST endpoint directly
  • 翻訳サービスを使用するには、トランスレータの残りのエンドポイントへのhttpsリクエストです.
    fetch(`https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=${toLang}`, {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + token.key,
        'Ocp-Apim-Subscription-Region': token.region,
        'Content-Type': 'application/json; charset=UTF-8',
        'Content-Length': data.length
      },
      body: data
    }).then(resp => resp.json())
    .then(handleTranslationResults);
    

    ブラウザ拡張


    これが初めてですdeveloping a browser extension , それで、それがどのように働くかについて説明するために、最善を尽くします.次のコンポーネントを使用します

  • background scripts あなたが長期的であるか複雑な論理を置くところ、または下にあるブラウザーへのアクセスを必要とするかもしれないコード

  • content scripts は、Webページ(例えば、タブ)のコンテキストで実行されるサンドボックススクリプトであり、ほとんどの場合、Webページからデータを表示および収集するために使用されます.

  • browser action は、拡張子を表すアイコンであり、拡張子と対話するための一般的な方法です.

  • The background scripts and content scripts 独自のそれぞれのコンテキスト/スコープで動作します.Webページ、コンテンツスクリプトと背景スクリプトの間の通信は、すべてevent-driven messaging system . 例えば、
    // Sending data from web page to an extension's content script
    window.postMessage({type: 'some-action', data: ...});
    
    // Listening to a web page from a content script
    window.addEventListener('message', (evt) => {
      ...
    });
    
    要約すると、これは拡張モジュールで使用されているブラウザ拡張機能の一部についての簡単な概要で、後に私たちの実装で使用されます.

    機能部品


    今までのところ、テキストとAzureの翻訳サービスの両方にDeepgramのスピーチを設定し、使用する方法を見ました.また、一般的なブラウザ拡張コンポーネントとその機能について簡単に触れます.次に、拡張機能の機能を定義します.
  • ユーザークリックbrowser action , もし実行していないか、既に実行しているならば、それはクローズします
  • 私たちが開いた/タブに切り替えるとき、それが前のタブ
  • 拡張を閉じる必要があるなら
  • 使用しているリソースをシャットダウンしてください.MediaRecorder , WebSocket )
  • Webページ上の翻訳結果を削除する
  • 拡張子を開く必要があるなら
  • 翻訳結果コンテナを作成し、Webページに表示します
  • 現在のWebページのオーディオをキャプチャ開始
  • オーディオを聞くためにMediaReaderを作成します
  • 深さにオーディオを送信するWebSocketを作成する
  • オーディオオーディオをキャプチャするたびに
  • 我々が転写を得るときはいつでも、Azure翻訳者に転写物を送ってください
  • 翻訳結果を送信するたびに、表示のためのコンテンツスクリプトに送信します
  • このリストは徹底的ではありません、それは我々の拡張の主要な機能性について説明します.各項目をどのように実装できるかを見てみましょう.

    拡張の活性化


    拡張子をbrowser action , 我々add a listener —トリガされると、それは開いているか、または拡張機能を閉じます.
    chrome.browserAction.onClicked.addListener(function() {
      if (someStateAboutCurrentTab.isOpen) {
        // ... handle closing the extension
      } else {
        // ... handle opening the extension
      }
    });
    

    タブを開くか、または切り替える


    ブラウザは複数のタブを持つことができますが、拡張機能は1つのタブで同時に動作します.前のタブがあった場合は、必ず前のタブで開いているかどうかにかかわらず、常に拡張モジュールを強制的に閉じる必要があります.
    chrome.tabs.onActivated.addListener(function (tabInfo) {
      prevTabId = activeTabId;
      activeTabId = tabInfo.tabId;
      if (prevTabId) {
        closeExtension(prevTabId);
      }
    });
    

    締め切りを延長


    エクステンションを閉じるには、リソース(例えば、WebSocket、MediaReader)をクリーンアップし、コンテンツスクリプトに通知して、翻訳結果コンテナを削除します.
    function cleanUpResources() {
      if (socket && socket.readyState !== 'inactive') {
        socket.close();
      }
      if (mediaRecorder && mediaRecorder.state !== 'inactive') {
        mediaRecorder.stop();
      }
    }
    
    function notifyContentScriptToClose() {
      chrome.tabs.sendMessage(prevTabId, {type: 'close'});
    }
    

    イベントを聞いている内容スクリプト


    …の目的content scripts は、ユーザーに翻訳を表示し、通知するbackground script ユーザーが新しいターゲット翻訳言語を好むこと.
    翻訳結果を表示/非表示する方法の例です.
    // Create the div that will display the translations, and add to the body
    function createTranslationDisplay() {
      const template = document.createElement('template');
      template.innerHTML = '<div id="translations"></div>';
      document.getElementsByTagName('body')[0].append(template.content.firstChild);
    }
    
    function hideTranslationDisplay() {
      document.getElementById('translations').style.display = 'none';
    }
    
    function showTranslationDisplay(translation) {
      const div = document.getElementById('translations');
      div.style.display = 'block';
      div.innerText = translation;
    }
    
    ここでは、コンテンツスクリプトがどのように新しい翻訳、またはイベント(例えば、close、open)を受け取ることを扱うことができますbackground script .
    function onBackgroundMessage(evt, sender, callback) {
      if (evt.type === 'close') {
        hideTranslationDisplay();
      } else if (evt.type === 'translation') {
        showTranslationDisplay(evt.translation);
      } ...
    }
    
    chrome.runtime.onMessage.addListener(onBackgroundMessage);
    

    オーディオキャプチャ


    オーディオをキャプチャするにはtabCapture API.
    chrome.tabCapture.capture(
      {audio: true, video: false},
      function (stream) {
        // Once a stream has been establish, we need to make
        // sure it continues on it's original destination (e.g, your speaker device), but we can now also record it
        AudioContext audioContext = new AudioContext();
        audioContext.createMediaStreamSource(stream)
          .connect(audioContext.destination);
      }
    );
    
    注:Chromeベースのブラウザー(例えばクロム、edge)のために働くだけであるように、我々の転写物と翻訳延長はChrome特有の拡張APIに対して開発されました.

    録音オーディオストリームの転写


    我々はどのように任意のWebページからオーディオをキャプチャする方法を見てきました、今我々は、拡張子を使用して転写プロセスを開始する必要があります.
    // Receives an audio stream from the tabCapture
    function startAudioTranscription(stream) {
      mediaRecorder = new MediaRecorder(stream, {mimeType: 'audio/webm'});
      // Start a connection to Deepgram for streaming audio
      socket = new WebSocket(deepgramEndpoint, ['token', key]);
      socket.onmessage = handleTranscriptionResults;
      mediaRecorder.ondataavailable = function (evt) {
        if (socket && socket.readyState === socket.OPEN) {
          socket.send(evt.data); // audio blob
        }
      }
    }
    

    翻訳への変換


    次に、それぞれの成功した転写Deepgram's Speech-to-Text サービス、我々はトランスクリプトを取って、Azureの翻訳サービスにそれを送ります.
    function translate(transcript) {
      const bodyData = JSON.stringify([{Text: transcript}]);
      fetch(azTranslatorEndpoint, {
        method: 'POST',
        headers: {
          //... auth stuff
          'Content-Type': 'application/json; charset=UTF-8',
          'Content-Length': bodyData.length
        },
        body: bodyData
      })
      .then(resp => resp.json())
      .then(handleTranslationResults);
    }
    
    function handleTranscriptionResults(results) {
      const data = JSON.parse(results.data);
      if (data.channel.alternatives) {
        const transcript = data.channel.alternatives.map(t => t.transcript).join(' ');
        translate(transcript);
      }
    }
    
    最後に翻訳を表示するには、我々はからの翻訳を送信する必要が送信されますbackground scriptcontent script .
    function handleTranslationResults(results) {
      if (results && results[0].translations) {
        const text = results[0].translations[0].text;
        chrome.tabs.sendMessage(tabId, {type: 'translation', text});
      }
    }
    
    それは私がどのように転写と翻訳拡張を構築したかの私の簡単な概要を包みます.あなたはGithubレポで完全なソースコードをチェックアウトすることができます.
    https://github.com/ikumen/transcribe-and-translate/tree/main/extension

    要約する


    Phew、それを作りました:-)私の提出をチェックアウトするためのおかげで、私はあなたがそれを好きで、より重要なことについて少し学ぶことを望むDeepgram ブラウザの拡張機能がどのように動作するか.

    追加情報


    インストール


    このポストの時点で、私はローカルのデモをインストールして、実行するための指示を持っていません、しかし、時間が許すとき、私はそれをレポに加えます.あなたは単に未パックの拡張子としてロードすることができます.
    https://github.com/ikumen/transcribe-and-translate/tree/main/extension