kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

LipSurfで自作プラグインを作ってブラウザの音声操作を拡張する① 〜Hello Worldプラグイン〜

この記事は、Voice User Interface Advent Calendar 2022 の1日目の記事です。

前回の記事で紹介した音声でブラウザを操作できる「LipSurf」ですが、プラグインによる音声操作の拡張が可能です。

標準でもいくつかプラグインがインストール済になっています。

そして自分で独自のプラグインを開発することもできます。

今回は、公式ドキュメントにある5 Minute Quick Startというチュートリアルがあるのでこれにしたがって、「ハローワールド」と発話するとJavaScriptで「Hello, Developer!」というアラートが表示されるプラグインを作成してみます。

目次

前提

LipSurfプラグインの開発にはNode.js環境が必要ですが、環境がない場合でもできるようにGoogle Colaboratoryでやってみました。Colaboratoryのノートブックは以下で公開しています。

https://gist.github.com/kun432/fd6de9b7a1bde15433c662a0289a6c23

上から順番に実行していけばよいだけなのですが、せっかくなので説明も含めてやっていきましょう。

あと、予めLipSurfのChrome拡張をインストールしておいてください。

1. 事前準備

Google ColaboratoryはPythonで使うのが一般的かと思いますが、一応Node.jsも使えます。ただし、LipSurfプラグインの開発にはいくつか事前準備が必要になります。

まずデフォルトのNode.jsのバージョンを確認します。

!node -v
!which node

私が試した環境だと、デフォルトはv14系のようです。

あとで使う異なるLipSurfプラグイン開発用のCLI「lipsurf-cli」はこのバージョンだと古すぎてインストールに失敗します。そこでNode.js v16をインストールします。いろいろ試してみたのですが、ColaboratoryだとNode.jsのバージョン管理ツール「N」を使ってインストールするのが良さそうでした(全部試したわけではないですが、他のだと色々失敗しました)

!npm i -g n
!n 16
!node --version
!which node

v16.18.1がインストールされました。

lipsurf-cliのインストールはyarnで行いますのでyarnもインストールしておきましょう。

!npm i -g yarn
!which yarn
!yarn -v

事前準備はこれで完了です。

2. lipsurf-cliでプラグインを作成

ではプラグインを作成しましょう。LipSurfプラグインの作成にはlipsurf-cliが必要ですので、まずこれをインストールします。

!yarn global add @lipsurf/cli
!which lipsurf-cli

インストールされました。

lipsurf-cliでプラグインのscaffold(雛形)を生成します。プラグイン名はHelloWorldとしました。最初に2行ほどエラーが出ますが気にしなくても大丈夫なようです。

!lipsurf-cli init HelloWorld

左の「ファイル」のアイコンをクリックするファイルブラウザが表示されて、lipsurf-plugin-helloworldフォルダができているのがわかると思います。この中にあるsrc/HelloWorld/HelloWorld.tsがプラグインのソースになります。中身については後ほど・・・

このフォルダ内に移動します。

%cd lipsurf-plugin-helloworld

ではプラグインをビルドしましょう。チュートリアルではyarn watchになっていますが、Colaboratoryだとあまり意味がない気がしますので、yarn buildでOKです。

!yarn build

"Done in ..." と表示されていればOKです。

作成されたプラグインファイルはdistディレクトリに生成されます。見てみましょう。

!ls dist

プラグインファイルは.lsという拡張子になります。ファイルブラウザの方でも見えると思います。

ではこのプラグインファイルをダウンロードします。ファイルブラウザで、プラグインファイルを右クリックしてダウンロードします。

3. Chrome拡張でプラグインをインポート

ではこのプラグインをLipSurfのChrome拡張にインポートします。LipSurf拡張を右クリックしてオプションを開いてください。

左のメニューの「General」の一番下にある「Developer mode」を有効化します。これで自作プラグインのインポートが可能になります。

左のメニューの「Plugins」に「Load a Local Plugin」ボタンが表示されますので、これをクリックしてダウンロードしたプラグインファイルを指定します。ちなみに「Get More Plugins」というボタンがありますが、2022/11/30現在この機能はまだ使えないようです。

プラグインが正しく読み込まれると、他のプラグインと同じようにこの画面に表示されます。

で、よく見ると、”Supported Language”のところが"English"のみになっていますね。LipSurfのプラグインは多言語対応が可能ですが、lipsurf-cliでscaffold作成しただけだと、英語のみの対応となっています。多言語対応は別の機会に触れることとして、まずはこのプラグインが正しく動くかを確認しましょう。

英語のみのプラグインなので、このプラグインを使うには言語を切り替える必要があります。

「General」メニューの「Language & dialect」で直接切り替えてしまっても良いのですが、せっかくなので音声で切り替えれるようにしてみましょう。同じところにある「Enable language switching commands」をクリックします。

「リップサーフ」プラグインの設定箇所にジャンプします。標準的な機能も実はプラグインで実装されている、ということなのかもしれません。ここにある「英語に変更」を有効化します。お好みで他の言語を変更してもいいかもしれません。

これで「えいご」「にほんご」「English」「Japanese」など音声で切り替えれるようになりますので、英語に切り替えておいてください。切り替えるとChrome拡張のアイコンがこんな感じになります。

では作成したHelloWorldプラグインを動かしてみましょう。

アラートが開きましたね!

Colaboratoryのノートブックはここまでです。

プラグインのコードを見てみる。

ここからはおまけです。Colaboratoryに戻って少しプラグインのコードを見てみましょう。lipsurf-plugin-helloworld/src/HelloWorld/HelloWorld.tsがソースです。ただ、Colaboratoryでは、ブラウザ内でそのままエディタで開けるファイルの種類に制限があります。.tsファイルは開けないので一旦ダウンロードして適当なエディタで開いてみてください。

こんな感じになっています。

/// <reference types="@lipsurf/types/extension"/>
declare const PluginBase: IPluginBase;

export default <IPluginBase & IPlugin>{
  ...PluginBase,
  ...{
    niceName: "Hello World",
    description: 'A "hello world" plugin.',
    // a RegEx that must match against the current tab's url for the plugin to be active (all of it's commands minus global commands)
    match: /.*/,
    version: "1.0.0",
    apiVersion: 2,

    commands: [
      {
        name: "Respond",
        description:
          "Respond with something incredibly insightful to the user.",
        // what the user actually has to say to run this command
        match: "hello world",
        // the js that's run on the page
        pageFn: function () {
          alert("Hello, Developer!");
        },
      },
    ],
  },
};

プラグインのアーキテクチャは以下に説明があります。

docs.lipsurf.com

すいません、TypeScriptよくわかってないので、音声の操作部分だけざっと見てみます。

最初の数行はとりあえずおまじない的に考えとけば良さそうです。

matchでプラグインを有効化するサイトのURLを正規表現で指定します。以下のように指定するとどのURLを開いていたとしてもプラグインが動作します。特定のサイトに特化したプラグインを作る場合はここにURLを指定すれば良さそうです。

    match: /.*/,

で、音声操作のキモとなるのがcommandsのところですね。

    commands: [
      {
        name: "Respond",
        description:
          "Respond with something incredibly insightful to the user.",
        // what the user actually has to say to run this command
        match: "hello world",
        // the js that's run on the page
        pageFn: function () {
          alert("Hello, Developer!");
        },
      },
    ],

commandsでユーザの発話内容とブラウザで操作する内容を指定します。上記の例だと、commands内のmatchで"hello world"という発話を定義して、その発話が行われた場合はpageFnalert()が実行されるということがなんとなくわかるような気がしますよね。

ぱっと見、とても簡単そうに思えませんか?他にも追加したいコマンドがあればcommandsの配列に同じように定義していけば良さそうです。

ということでダウンロードしてきたソースコードに以下を少し追加してみました。

/// <reference types="@lipsurf/types/extension"/>
declare const PluginBase: IPluginBase;

export default <IPluginBase & IPlugin>{
  ...PluginBase,
  ...{
    niceName: "Hello World",
    description: 'A "hello world" plugin.',
    // a RegEx that must match against the current tab's url for the plugin to be active (all of it's commands minus global commands)
    match: /.*/,
    version: "1.0.0",
    apiVersion: 2,

    commands: [
      {
        name: "Respond",
        description:
          "Respond with something incredibly insightful to the user.",
        match: "hello world",
        // the js that's run on the page
        pageFn: function () {
          alert("Hello, Developer!");
        },
      },
      {
        name: "Respond morning",
        description:
          "Respond with something incredibly insightful to the user.",
        match: "good morning world",
        // the js that's run on the page
        pageFn: function () {
          alert("Good morning, Developer!");
        },
      },
      {
        name: "Respond night",
        description:
          "Respond with something incredibly insightful to the user.",
        match: "good night world",
        // the js that's run on the page
        pageFn: function () {
          alert("Good night, Developer!");
        },
      },
    ],
  },
};

「hello world」に加えて、「good morning world」「good night world」の発話の場合にそれぞれアラートの内容を少し変えただけのシンプルなものですね。

修正したファイルをアップロードします。HelloWorld.tsファイルがあるディレクトリを右クリックしてアップロードします。

コードセルを追加して、再度ビルドします。

!yarn build

プラグインファイルがこれで生成されますので、後は同じようにダウンロードしてインポートします。

こんな感じで追加した内容が反映されているのがわかりますね。

実際に動かしてみるとちゃんと動いてるのが確認できるかと思います。

まとめ

公式のチュートリアルに従ってLipSurfで自作プラグインを作る流れを体験してみました。ごくごく単純な例だけでしたが、どうでしょう?JavaScriptが書ける人なら色々作れそうな気がしてきませんか?

次回はもう少し突っ込んだところで、ユーザの発話の一部を受け取ったり、日本語でも動作するようにプラグインの多言語化をやってみようと思います。