Edited at

Node-REDを使ってブラウザに喋った内容を各SNSに通知する


はじめに


やりたいこと


  • スマホにしゃべるとメールやslackやlineやカレンダーに通知したい

  • 基本的な使い方は関連記事を参照してください。


Node-REDのまとめ記事


動作環境


  • IBM bluemix Node-RED : v0.20.5


免責事項


  • 検証をして確実と思われる情報を載せておりますが、誤っている可能性もゼロではないので、参考程度にご利用ください

  • 本来はコードと実行結果のコンソールログも載せるべきなのですが、数と量が多いので、一旦は画面イメージまでとさせてください。


本編


画面


処理の流れ


  1. 画面を開くとWebSocketを使ってサーバとの通信を確立

  2. ボタンを押すと音声を認識できる状態になる

  3. WebSpeechAPIを使って、ブラウザに向かって話した内容を文字列化

  4. 文字列をサーバに送る

  5. 文字列をもとに条件分岐などをして、送信先SNSと送るデータを決める

  6. SNSに送る

  7. 送った旨のメッセージをWebSocketを使ってブラウザに返す

  8. WebSpeechAPIを使って喋らせる


フロー


各SNSへのアクセス

実際はググると山程でてきますし、ここに書いてもすぐに古くなるので、各APIを参照ください。

一応いまいま時点でどんなことをしたのかは残しておきます


  • slack : IncommingWebHookを使い実現。URLに対してデータを送っています

  • Line : DeveloperのMessaging APIを使って実現。WebHookにデータを送っています

  • メール:シンプルにメールのノードで実現。

  • googleカレンダー:googleカレンダーのノードを使って実現。node-red-node-googleの指示に従い、アカウントとアクセス許可などを設定


補足


  • 送る文章は 面倒なので 文章全体。↑の例だと 遅刻しますって LINE して とすべて送られます。

  • カレンダーは今から1時間(デフォルト)でスケジュールが作成されるため、あまり実用的でないです。

  • はっきり言って、Node-REDからみると文字列を受け取り、SNSに通知して、文字列を送り返しているだけです!


ブラウザ側の実装

このあたりを参考にさせていただきました

* ブラウザで音声操作をする。(Speech Recognition API)

* Webページでブラウザの音声認識機能を使おう - Web Speech API Speech Recognition

本家の方とほとんど変わらないので、オリジナルの方を見ていただくほうが良いかと思いますが、一応重要な部分のソースです


ブラウザのhtml内のjs

    const startBtn = document.querySelector('#start-btn');

const resultDiv = document.querySelector('#speak-text');

SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
let recognition = new SpeechRecognition();

recognition.lang = 'ja-JP';
recognition.interimResults = true;
recognition.continuous = false;

let finalTranscript = '';
recognition.onresult = (event) => {
let interimTranscript = '';
for (let i = event.resultIndex; i < event.results.length; i++) {
let transcript = event.results[i][0].transcript;
if (event.results[i].isFinal) {
finalTranscript += transcript;
} else {
interimTranscript = transcript;
}
}
resultDiv.innerHTML = finalTranscript + '<i style="color:#ddd;">' + interimTranscript + '</i>';
}

// 文字列の送信
recognition.onend = (event) => {
recognition.stop();
const speakText = $("#speak-text").text()
sock.send(speakText);
}

// 開始ボタンのクリック
startBtn.onclick = () => {
speechSynthesis.cancel();
$('#status').text('please speak');
$("#speak-text").empty();
$("#response-text").empty();
finalTranscript = '';
recognition.start();
}

//Websocketの確立と各種イベント
var socketaddy = "wss://" + window.location.host + "/ws/speaker";
$(document).ready(function () {
sock = new WebSocket(socketaddy);
sock.onopen = function () {
$('#status').text('connected');
};
sock.onerror = function () {
$('#status').text('error');
};
sock.onclose = function () {
$('#status').text('closed please reload page!!')
}
sock.onmessage = function (evt) {
$('#status').text('response received');
$("#response-text").html(evt.data);
var speakText = $("#response-text").text();

// 発言を作成
const uttr = new SpeechSynthesisUtterance(speakText);
uttr.rate = 1.3;
uttr.lang = "ja-JP";
speechSynthesis.speak(uttr);
};
});


しゃべるデータをいったんhtmlにしてから取り出しているのは、 brタグ などを喋られないようにするためです(笑)

見栄えでは2行にしたいけど、タグを喋られると気持ちが悪いので。。。