2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

アレクサを好きなようにしゃべらせる(Webインターフェイス編)

Posted at

ひとりアドベントカレンダー24日目
途中で詰まってしまったので抜けたところは飛ばします。
と言いつつ24日目にも間に合っていませんが。

はじめに

 コマンドラインでアレクサをしゃべらせられるようになったので、Webインターフェイスを作ります。
 ローカルで動けばいいのでRaspberryPi上でExpressでWeb APIとスマホ等から操作するためのページを一つ作ります。

環境

  • RaspberryPi
  • Raspbian GNU/Linux 10 (stretch)
$ node --version
v12.22.3
$ npm --version
6.14.13

ところで、Raspberry Pi の初代はArmv6搭載のため新しいnodejsがパッケージで提供されていないため、以下のページの手順に従いUnofficialビルドをインストールしてあります。

使用したUnofficialイメージはここから

手順

  1. Expressを導入
  2. メッセージをスクリプトに渡す処理を実装し、
    メッセージを受け取るエンドポイントを追加
  3. 任意のテキストコマンドを実行する処理とエンドポイントを追加
  4. リクエストを送るフォーム入りのページを作成し、ルートに割り当て
  5. サービス起動

Expressを導入

mkdir speak-alexa
cd speak-alexa
npm init
npm install --save express

テンプレートとか使わず app.js 1ファイルで済ませてしまいます。

メッセージをスクリプトに渡す処理を実装し、メッセージを受け取るエンドポイントを追加

app.jsに実装していきます。

app.js
var express = require("express");
var app = express();

var server = app.listen(3000, function(){
    console.log("Node.js is listening to PORT:" + server.address().port);
});

app.get("/api/speak/free", (req, res) =>{
    console.log("acsess to /api/speak/free");
    const utterance = req.query.u;
    speak(utterance);
    res.json(utterance);
});

function speak(mes){
    console.log(`speak: ${mes}`);
    exec(`~/alexa/alexa_remote_control_plain.sh -d 'DeviceName' -e speak:'${mes}'`, (err, stdout, stderr) => {
        if (err) {
          console.log(`stderr: ${stderr}`)
          return
        }
        console.log(`stdout: ${stdout}`)
        }
    )
}

-dオプションで指定しているDeviceNameは -aオプションで実行すると得られるデバイスリストの名前を使用します。

任意のテキストコマンドを実行する処理を追加

しゃべらすだけでなく、通常alexaに話しかけるのと同じ内容をテキストで送ると実行されるtextcommandも実行できるようにしておきます。

app.js
app.get("/api/textcommand/free", (req, res) =>{
    console.log("acsess to /api/textcommand/free");
    const cmd = req.query.cmd;
    textcommand(cmd);
    res.json(cmd);
});

function textcommand(cmd){
    console.log(`textcommand: ${cmd}`);
    if ( cmd == 'undefined') {
      return
    }
    exec(`~/work/alexa/alexa_remote_control_plain.sh -d 'DeviceName' -e textcommand:'${cmd}'`, (err, stdout, stderr) => {
        if (err) {
          console.log(`stderr: ${stderr}`)
          return
        }
        console.log(`stdout: ${stdout}`)
        }
    )
}

リクエストを送るページを作成し、ルートに割り当て

Web APIの口はできたので、スマホ等から操作しやすいようにUIのページを作ります。

text-form.html
<html>
<body>
<h1>Text-to-Alexa 入力画面</h1>
入力されたテキストをアレクサに送信してしゃべらせたり、<br>
呼びかける事無くテキストでコマンドを実行できます。
<hr><br>
しゃべってもらうテキスト
<form action="http://raspberrypi.local:3000/api/speak/free" method="get">
<input type="text" name="u" size="64"><br>
<input type="submit" value="speak">
</form>
テキストコマンド
<form action="http://raspberrypi.local:3000/api/textcommand/free" method="get">
<input type="text" name="cmd" size="64"><br>
<input type="submit" value="command">
</form>
</body>
</html>

これをルート(/)へのアクセスで返すようにしておきます。

app.js
app.get("/", function(req, res, next){
    console.log("access to /");
    res.status(200).sendFile('/home/pi/alexa-speak/html/text-form.html');
});

サービス起動

あとはこれを起動します。

$ node app.js
[2021-12-20T02:42:57.461Z] Node.js is listening to PORT:3000

package.jsonのscriptsに以下のように追記しておけばnpm startで起動できるようになります。

package.json
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node app.js"
  },

スマホからアクセスした画面は以下のように

2F474A07-4570-4227-92B3-4ED61B44228D.png

まとめ

 アレクサに好きなように発言させることができるようになり、アレクサっぽい口調で送ると自発的にしゃべりだしたようでびっくりさせることができます。しかし、やりすぎると慣れてしまうのでたまに思い出したように使っています。
 それだけでなく、声を出さずに操作できるようになったのは案外便利で、隣の部屋で鳴っているタイマーを遠隔で止めたりできるようになりました。
 自由にしゃべらせられるようになったので、センサーが異常値になった時の通知とかにも使ってます。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?