Alexaと他のWebサービスをつなぐ「アカウントリンク」機能を使って、Alexaに話しかけた内容をSlackへと投稿するスキルを作成してみよう。
Alexaが持つ「アカウントリンク」機能を使うと、Alexaから特定のサービスに特定のユーザーとしてアクセスできる。この機能を使って、「原稿を書くよ」とAlexaに伝えると、その本心をSlackに投稿してくれるスキルを作ってみよう。実際にこのスキルが動作している様子を以下に示す。
なお、アカウントリンクではOAuth 2.0が使われるが、本稿では詳しい説明は省略する。OAuthを利用したアカウントリンクの詳細については「Alexaユーザーとシステムユーザーを関連付ける」ページなどを、OAuthの概要については「『OAuth』の基本動作を知る」や「図解:OAuth 2.0に潜む『5つの脆弱性』と解決法」などを参照されたい。
上でご覧いただいたように、今回作成した「PostTelltaleFromAlexaToSlack」スキルは筆者の「ぼやき」や「やる気マンマンな発言」を、Alexaが全てネガティブな内容としてSlackに書き込んでくれるというものだ。ここでは、以下の3種類のインテントを作成し、ユーザー(筆者)がAlexaにしゃべった内容に応じて、Alexaの対応(Slackに書き込むメッセージの内容や、ユーザーに返送するメッセージ)に変化を付けている。
「原稿を書きたくない」系の発言ならWantNotToWriteIntentが、「仕事がいや」系の発言ならWantNotToWorkIntentが、「休みたい」系の発言ならWantToBeAbsentIntentが起動される。さらにちゃんと「原稿書くぞ」とAlexaに伝えてもやはり「WantNotToWriteIntent」が起動されるようにしてある。例として、「WantNotToWriteIntent」インテントのサンプル発話(の一部)を以下に示す。ここではスキルの「呼び出し名」を「スラック」にしている。
他の2つのインテントも同様だ(「スラックで仕事をしたくないよと伝えて」といえば、WantNotToWorkIntentインテントが起動されるといった具合)。
Slackへ実際に投稿するAWS Lambda関数のコードは次のようになる(AWS Toolkit for Visual Studioを使用して、Lambdaプロジェクトを新規に作成し、Alexa.NET NuGetパッケージをインストールしている。具体的な手順については前々回および前回を参照されたい)。
public class Function
{
SkillResponse response = new SkillResponse
{
Version = "1.0",
Response = new ResponseBody
{
ShouldEndSession = true
}
};
public SkillResponse FunctionHandler(
SkillRequest input, ILambdaContext context)
{
var token = input.Session.User.AccessToken;
if (token == null)
return ComposeMessage("認証が必要です");
if (input.Request.Type == "LaunchRequest")
return ComposeMessage("何でもSlackに投稿するよ");
IntentRequest ir = input.Request as IntentRequest;
if (ir == null)
return null;
var name = ir.Intent.Name;
string text = "";
switch (name)
{
case "AMAZON.CancelIntent":
case "AMAZON.StopIntent":
text = "終了します";
return ComposeMessage(text);
case "WantNotToWorkIntent":
text = "この人、仕事したくないとかゆーてますよ(by Alexa)";
break;
case "WantNotToWriteIntent":
text = "この人、原稿書く気ありませんわ(by Alexa)";
break;
case "WantToBeAbsentIntent":
text = "この人、仮病で会社休もうとしてますよ!(by Alexa)";
break;
default:
text = "この人、ダメな人ですわ(by Alexa)";
break;
}
var result = Post2Slack(text, input.Session.User.AccessToken);
if (result.IsSuccessStatusCode)
{
return ComposeMessage($"Slackに「{text}」て告げ口しときましたわ");
}
else
{
return ComposeMessage("Slackすら相手にしてくれませんわ");
}
}
private SkillResponse ComposeMessage(string text)
{
response.Response.OutputSpeech = new PlainTextOutputSpeech
{
Text = text
};
return response;
}
private HttpResponseMessage Post2Slack(string msg, string token)
{
var client = new HttpClient();
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "channel", "#general" },
{ "token", token },
{ "text", msg }
});
var task = client.PostAsync(
"https://slack.com/api/chat.postMessage", content);
task.Wait();
var result = task.Result;
return result;
}
}
Alexaスキルから呼び出されるFunctionHandler関数では、だいたい次のようなことを行っている。
アカウントリンクによって、Alexaとの連携が確立されたサービスからはユーザーがそのサービスにアクセスするためのトークンが渡される。これはFunctionHandler関数に渡されるSkillResponseオブジェクトのSession.User.AccessTokenプロパティに保存されるので、その値を見れば、アカウントリンクが行われているかを判断できる。
var token = input.Session.User.AccessToken;
if (token == null)
return ComposeMessage("認証が必要です");
また、このプロパティの値は後続のコード(ここではPost2Slackメソッド)で実際にサービスを利用する際に使用される。ここではHttpClientクラスのPostAsyncメソッドを使用して、Slackに接続したユーザーが所属するチームの「#general」チャネルに投稿するようにしている(サンプルコードということもあり、手を抜いて、非同期呼び出しを待機し、Slackへのポストが成功したかどうかの結果を得ている)。
private HttpResponseMessage Post2Slack(string msg, string token)
{
var client = new HttpClient();
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "channel", "#general" },
{ "token", token },
{ "text", msg }
});
var task = client.PostAsync(
"https://slack.com/api/chat.postMessage", content);
task.Wait();
var result = task.Result;
return result;
}
残りのコードについては、深く説明する必要はないだろう。送られてきたリクエストがLaunchRequestであればウエルカムメッセージを表示している。その後、リクエストからインテントを取り出して、その名前に応じてメッセージを作成し(て、上記のPost2Slackメソッドを呼び出し)ているだけだ(あるいは、「ストップ」「キャンセル」などについては、それを処理するようにしているだけだ)。
コードについてはこれくらいにして、次にアカウントリンクの設定について見ていこう。
Copyright© Digital Advantage Corp. All Rights Reserved.