ビデオ通話に翻訳機能を追加する方法

この記事はAgora社の公式ブログから翻訳機能に関する記事を紹介します。
AgoraWebSDKとGoogleCloudを使用してリアルタイム翻訳サービスを作成する方法を学びます。
原文は[Build a Live Translated Transcriptions Service in Your Video Call Web App](https://www.agora.io/en/blog/build-a-live-translated-transcriptions-service-in-your-video-call-web-app)に公開されています。

サンプルコードは[Github](https://github.com/akshatvg/Agora-Translated-Transcription)も公開されています。


## はじめに
グローバルにビジネスを行うことは、ほぼすべての企業の目標です。国際レベルにスケールアップする機会は利益を増やすことができますが、世界中のクライアントやパートナーと通信するために複数の言語の知識が必要になる場合があります。

多言語のビデオ会議の翻訳を手伝ってくれる通訳を雇うことは、煩わしく、会議が必要以上に長くなる可能性があるため、実用的ではありません。また、一部の情報の機密を保持することもできます。

このチュートリアルでは、JavaScriptのWeb Speech API、Agora Web SDK、Agora RTM SDK、およびGoogle Cloud Translation APIを使用して、音声からテキストへの文字起こしと翻訳をサポートするWebアプリケーションを構築します。

![build-a-live-translated-transcriptions-service-within-your-video-call-web-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/7b24e591-1094-9cea-cb1b-352586e241ad.png)


## 前提条件
 - JavaScript、JQuery、Bootstrap、およびFontAwesomeに関する基本的な知識
 - Agora開発者アカウント
 - AgoraWebSDKおよびAgoraRTMSDKの使用方法の知識
 - GoogleCloudアカウント
 - RESTAPIからリクエストを作成してレスポンスを受信する方法の知識

## プロジェクトの設定
[既存のプロジェクトであるビデオ通話Webアプリ内での独自の文字起こしサービス](https://www.agora.io/en/blog/building-your-own-transcription-service-within-a-video-call-web-app/)の構築に基づいて構築します。
このプロジェクトの[Githubリポジトリ](https://github.com/akshatvg/Agora-Transcription)のクローンを作成することから始めることができます。これで、次のようなプロジェクトが作成されます。
![build-a-live-translated-transcriptions-service-within-your-video-call-web-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/5f426185-bc8d-c1f6-730b-a91ecf731860.png)

ここで、メモ関連のHTMLと余分なボタンを削除します。上記のコードの機能を理解するのが難しい場合は、この[チュートリアル](https://www.agora.io/en/blog/building-your-own-transcription-service-within-a-video-call-web-app/)を参照してください。

また、ビデオ通話アプリケーションにビデオとオーディオのミュートとミュート解除のコードを追加しました。[Agoraのドキュメント](https://docs.agora.io/en/Video/API%20Reference/web_ng/interfaces/icameravideotrack.html?platform=Web#setenabled)から、ミュートとミュート解除の詳細を学ぶことができます。

これで、完全に機能する文字起こしサービスと、ミュートおよびミュート解除機能が利用できるようになりました。

## アプリケーションにリアルタイム翻訳を追加する
次に、既存の入力フィールドの行の下にあるHTMLファイルに次のコードを追加し、ユーザーがGoogleCloudプロジェクトのAPIキーを入力するためのオプションを追加します。

```html
<div class="row mt-3 mb-3">
        <div class="col-sm">
          <p class="join-info-text">Google Cloud API Key</p>
          <input id="gcpKey" type="text" placeholder="Enter Google Cloud API Key" required class="form-control">
        </div>
        <div class="col-sm">
          <label for="format">Select a Language you Understand</label>
          <select class="form-control" name="transcriptionLang" id="transcriptionLang">
            <option value="af">Afrikaans</option>
            <option value="sq">Albanian</option>
            <option value="ar">Arabic</option>
            <option value="hy">Armenian</option>
            <option value="ca">Catalan</option>
            <option value="zh">Chinese</option>
            <option value="hr">Croatian</option>
            <option value="cs">Czech</option>
            <option value="da">Danish</option>
            <option value="nl">Dutch</option>
            <option value="en" selected>English</option>
            <option value="eo">Esperanto</option>
            <option value="fi">Finnish</option>
            <option value="fr">French</option>
            <option value="de">German</option>
            <option value="el">Greek</option>
            <option value="ht">Haitian Creole</option>
            <option value="hi">Hindi</option>
            <option value="hu">Hungarian</option>
            <option value="is">Icelandic</option>
            <option value="id">Indonesian</option>
            <option value="it">Italian</option>
            <option value="ja">Japanese</option>
            <option value="ko">Korean</option>
            <option value="la">Latin</option>
            <option value="lv">Latvian</option>
            <option value="mk">Macedonian</option>
            <option value="no">Norwegian</option>
            <option value="pl">Polish</option>
            <option value="pt">Portuguese</option>
            <option value="pt-br">Portuguese (Brazil)</option>
            <option value="ro">Romanian</option>
            <option value="ru">Russian</option>
            <option value="sr">Serbian</option>
            <option value="sk">Slovak</option>
            <option value="es">Spanish</option>
            <option value="es-es">Spanish (Spain)</option>
            <option value="es-us">Spanish (United States)</option>
            <option value="sw">Swahili</option>
            <option value="sv">Swedish</option>
            <option value="ta">Tamil</option>
            <option value="th">Thai</option>
            <option value="tr">Turkish</option>
            <option value="vi">Vietnamese</option>
            <option value="cy">Welsh</option>
          </select>
        </div>
</div>
```

![build-a-live-translated-transcriptions-service-within-your-video-call-web-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/a3d92648-3d96-31ed-7476-6742d452c8c5.png)

## Google CloudTranslationAPIキーを作成する
 - クラウドコンソールで、[サービスアカウントの作成](https://console.cloud.google.com/projectselector/iam-admin/serviceaccounts/create?supportedpurview=project)ページに移動します。
 - プロジェクトを選択します。
 - 「Service account name」フィールドに名前を入力します。クラウドコンソールは、この名前に基づいてService account IDに入力します。
 - [Service account description]フィールドに説明を入力します。例:Agora LiveTranslatedTranscription
 - [Create and Continue]をクリックします。

![build-a-live-translated-transcriptions-service-within-your-video-call-web-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/2b47e5f0-e307-d1c8-7ede-7d14c14bd979.png)

- [Select a role]フィールドをクリックして、 Cloud Translation API Adminのroleを選択します。

![build-a-live-translated-transcriptions-service-within-your-video-call-web-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/a302fb32-e070-a878-8393-61905ebd56de.png)

 - [Continue]をクリックします。
 - [Done]をクリックして、サービスアカウントの作成を終了します。
 - [ここから](https://console.cloud.google.com/marketplace/product/google/translate.googleapis.com?q=search&referrer=search&project=agora-328918)CloudTranslationAPIを有効にします。

![build-a-live-translated-transcriptions-service-within-your-video-call-web-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/5002b9d4-d83e-954e-da70-cb5e96ccc773.png)

 - 左側のサイドバーの[Credentials]タブをクリックし、[Create Credentials]をクリックします。
 - 生成されたAPIキーを作成してコピーします。

![build-a-live-translated-transcriptions-service-within-your-video-call-web-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/9bbff118-c175-465e-4fa4-8862ed7c30c1.png)

## メイン機能の実装
基本構造がレイアウトされ、キーが生成されたので、翻訳サービスに機能を追加し始めることができます。最初は難しいように見えるかもしれませんが、[GCPの公式ドキュメント](https://cloud.google.com/translate/docs/basic/quickstart#translate_translate_text-drest)に従えば、それは簡単なことです。

以下のコードは、ユーザーが入力したGCPキーとユーザーが希望する文字起こし言語を取り込みます。ユーザーが話すのをやめるとすぐに、JavaScriptのWeb Speech APIを使用して、選択した言語で単語が書き起こされます。

これと同じメッセージが、AgoraRTMSDKを介してすべてのユーザーに話者の言語で送信されます。このメッセージを受信すると、受信者の優先言語を確認し、Google Translate APIを使用して、送信された元のメッセージをユーザーが理解できるテキストに変換します。このように、リモートユーザーがローカルユーザーとは異なる言語を使用している場合でも、ロジックは期待どおりに機能します。

```javascript
...
recognition.start();
            // Start transcribing and translating
            var gcpKey = $("#gcpKey").val();
            var transcriptionLang = $('#transcriptionLang').val();
            recognition.onresult = function (event) {
                var current = event.resultIndex;
                var transcript = event.results[current][0].transcript;
                transContent = transContent + transcript;
                singleMessage = transContent;

                // Write code to send, process and show translated transcription to host.
                rtmText = {
                    singleMessage: singleMessage,
                    senderLang: $('#transcriptionLang').val(),
                    time: new Date().toLocaleString("en-US", { year: 'numeric', month: 'long', day: 'numeric', hour12: true, hour: 'numeric', minute: 'numeric', second: 'numeric' })
                };
                msg = {
                    messageType: 'TEXT',
                    rawMessage: undefined,
                    text: JSON.stringify(rtmText)
                };
                channel.sendMessage(msg).then(() => {
                    console.log("Message sent successfully.");
                    console.log("Your message was: " + rtmText.singleMessage + " by " + accountName + " in the following language: " + rtmText.senderLang + " sent at: " + rtmText.time);
                    if (rtmText.senderLang == transcriptionLang) {
                        $("#actual-text").append("<br> <b>Speaker:</b> " + accountName + "<br> <b>Message:</b> " + rtmText.singleMessage + "<br> <b>Sent On:</b> " + rtmText.time + "<br>");
                        transContent = '';
                    } else {
                        var xhr = new XMLHttpRequest();
                        xhr.open("POST", `https://www.googleapis.com/language/translate/v2?key=${gcpKey}&source=${rtmText.senderLang}&target=${transcriptionLang}&callback=translateText&q=${singleMessage}`, true);
                        xhr.send();
                        xhr.onload = function () {
                            if (this.status == 200) {
                                var data = JSON.parse(this.responseText);
                                console.log(data.data.translations[0].translatedText);
                                $("#actual-text").append("<br> <b>Speaker:</b> " + accountName + "<br> <b>Message:</b> " + data.data.translations[0].translatedText + "<br> <b>Sent On:</b> " + rtmText.time + "<br>");
                                transContent = '';
                            } else {
                                var data = JSON.parse(this.responseText);
                                console.log(data);
                            }
                        };
                    }
                }).catch(error => {
                    console.log("Message wasn't sent due to an error: ", error);
                });
            };
            // Receive RTM Channel Message
            channel.on('ChannelMessage', ({
                text
            }, senderId) => {
                // Write code to receive, process and show translated transcription to all users.
                rtmText = JSON.parse(text);
                console.log("Message received successfully.");
                console.log("The message is: " + rtmText.singleMessage + " by " + senderId + " in the following language: " + rtmText.senderLang + " sent at: " + rtmText.time);
                var xhr = new XMLHttpRequest();
                xhr.open("POST", `https://www.googleapis.com/language/translate/v2?key=${gcpKey}&source=${rtmText.senderLang}&target=${transcriptionLang}&callback=translateText&q=${rtmText.singleMessage}`, true);
                xhr.send();
                xhr.onload = function () {
                    if (this.status == 200) {
                        var data = JSON.parse(this.responseText);
                        console.log(data.data.translations[0].translatedText);
                        $("#actual-text").append("<br> <b>Speaker:</b> " + senderId + "<br> <b>Message:</b> " + data.data.translations[0].translatedText + "<br> <b>Sent On:</b> " + rtmText.time + "<br>");
                        transContent = '';
                    } else {
                        var data = JSON.parse(this.responseText);
                        console.log(data);
                    }
                };
            });
...
```

![build-a-live-translated-transcriptions-service-within-your-video-call-web-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/2414d004-3111-74cb-8353-0681547e5ede.png)

これで、Webビデオ通話アプリケーション内で多言語の文字起こしサービスを正常に作成できました。

[こちら](https://translation.akshatvg.com/)から実際のコードのデモを確認できます。


## 最後に                                                                                                    
[**agora.ioに関するお問い合わせはこちらから**](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=087d4f011e1daca76804)   
[<img width="912" alt="スクリーンショット 0001-08-15 13.41.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/5d815376-9b89-08fa-9434-6fa7e8e67bcf.png">](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=087d4f011e1daca76804)