ENGINEER BLOG

ENGINEER BLOG

Chrome拡張とWeb Speech APIで遊んでみる

こんにちは、イノベーション本部の朝日です。
今回はChrome拡張とWeb Speech APIを使って簡単なツールを作ってみたいと思います。

Chrome拡張の作り方

まずはChrome Developers Documentation – ExtensionsGetting startedに従ってシンプルなExtensionを作ってみます。
なお、本記事の作成直前にはManifest V3がChrome 88で利用できるようになっていたのですが、V2から色々変わっていてマイグレーションが間に合わなかったので、本記事ではManifest V2ベースで記載しています。

ドキュメントの通りですが、一応流れを書いておきます。

  1. 下記のようなmanifestファイルmanifest.jsonを任意のディレクトリに作成します。
{
  "name": "Getting Started Example",
  "version": "1.0",
  "description": "Build an Extension!",
  "manifest_version": 2
}
  1. Chromeの拡張機能ページを開きます。
  • chrome://extensions で開く

もしくは

  • Chromeメニューの「その他のツール(L)」→「拡張機能(E)」で開く
  1. 右上の「デベロッパーモード」スイッチをONにする。

  2. 「パッケージ化されていない拡張機能を読み込む」から0.で作成したmanifestファイルを格納したディレクトリを指定する。

img1

なにも機能がないExtensionですが、拡張機能ページに追加されたことがわかると思います。

機能を追加する(省略版)

公式ドキュメントはちょっと長いので、はしょります。
興味のある方はAdd instruction以降を進めてみてください。

シンプルに特定のページ(ここではGoogle Meetにしています)を表示しようとするとAlertを出すだけにしてみます。
下記の内容でloader.jsを作成します。

alert("Google Meetを表示します!");

つぎに、manifest.jsonを下記のように修正します。

{
  "name": "Getting Started Example",
  "version": "1.0",
  "description": "Build an Extension!",
  "manifest_version": 2,
  "content_scripts": [{
    "matches": ["https://meet.google.com/*"],
    "js": ["loader.js"],
    "run_at": "document_start"
  }],
  "permissions": ["https://meet.google.com/"]
}

Chrome拡張機能のページからリロードすると有効になります。
Google Meetを開こうとするとページの表示前にAlertが表示されれば正しく動作しています。

Web Speech APIと組み合わせてみる

それでは次にWeb Speech APIをChrome拡張に組み込んでみたいと思います。

次の内容でcs.jsを作成します。

SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
const recognition = new SpeechRecognition();
recognition.continuous = true;

recognition.onresult = (event) => {
  const num = event.results.length;
  const txt = event.results[num-1][0].transcript;
  console.log(txt);
}

recognition.onend = (event) => {
  recognition.start();
}

recognition.start();

SpeechRecognitionで音声認識された結果をコンソールログに出力する、という単純なモノです。

このcs.jsの内容をMeetのDOMに差し込むようにloader.jsを下記のように変更します。

async function load () {
  const res = await fetch(chrome.runtime.getURL('cs.js'), { method: 'GET' });
  const js = await res.text();
  const script = document.createElement('script');
  script.textContent = js;
  document.body.insertBefore(script, document.body.lastChild);
}

window.addEventListener('load', (evt) => {
  load();
}, false);
   

また、cs.jsにアクセスできるようにmanifest.jsonも変更しておきます。

{
  "name": "Getting Started Example",
  "version": "1.0",
  "description": "Build an Extension!",
  "manifest_version": 2,
  "content_scripts": [{
    "matches": ["https://meet.google.com/*"],
    "js": ["loader.js"],
    "run_at": "document_start"
  }],
  "permissions": ["https://meet.google.com/"],
  "web_accessible_resources": ["cs.js"]
}

リロードして、Google Meetを表示したあと、マイクに向かって話すとその内容がコンソールログに出力されます。
img2

Google Meetのチャット欄に音声認識結果を送ってみる

コンソールログに出力するだけだとつまらないので、音声認識結果をGoogle Meetのチャット欄に送ってみたいと思います。
ChromeのデベロッパーツールでMeetのチャットテキスト入力欄と送信ボタンを色々調べると、以下のコードでアクセスできそうなことがわかります。
テキスト入力欄は名前がズバリname="chatTextInput"というtextareaがあるので、そのvalueに送信したい内容をセットします。

document.getElementsByName("chatTextInput")[0].value = txt;

チャットメッセージの送信はボタンが非活性状態だとクリックできないようなので、aria-disabled属性をfalseに設定して活性状態にしてからclickを呼んであげます。

const button = document.getElementsByClassName("uArJ5e Y5FYJe cjq2Db IOMpW Cs0vCd")[0];
button.setAttribute("aria-disabled", "false");
button.click();

※送信ボタンへのアクセスは上記の通りちょっとイケてないので、良い方法があったら教えてください…

これらのコードをcs.jsに組み込んでみます。

SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
const recognition = new SpeechRecognition();
recognition.continuous = true;

recognition.onresult = (event) => {
  const num = event.results.length;
  const txt = event.results[num-1][0].transcript;
  console.log(txt);
  document.getElementsByName("chatTextInput")[0].value = txt;
  const button = document.getElementsByClassName("uArJ5e Y5FYJe cjq2Db IOMpW Cs0vCd")[0];
  button.setAttribute("aria-disabled", "false");
  button.click();
}

recognition.onend = (event) => {
  recognition.start();
}

recognition.start();

Meetで会議を開始し、チャット欄を表示させてからマイクに向かって話すとその内容がチャット欄に送信されます。

img3

以上でとりあえずおしまいです!

さいごに

なお、今回作ったChrome拡張では

  • 事前にチャット欄を開いておく必要がある
  • MeetのマイクをOFFにしていても音声認識結果を送信してしまう
  • チャットテキスト欄やチャット送信ボタンのハンドリングが強引なのでMeetのアップデートで使えなくなる可能性がある
  • Meetのチャット欄は保存されないので、そもそも別の所に音声認識結果を保存するようにした方が良さそう

と色々課題もあるのでそのまま利用は厳しいとは思います。
あくまでこんなこともできるよ、という技術デモなので興味があれば改良してみてください。