するめごはんのIT日記

主にITネタを書いていくのさ

AndroidユーザーならXperia Ear Duoすごいぞ

ごきげんよう

この記事は ADVENTARの「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の17日目の記事です。

本日はXperia Ear Duoの話です。

SONYさんのサイト

www.sonymobile.co.jp

上記だと約3万円ですが、僕が秋葉原のヨドバシさんで買ったときは25000円しないくらい。 ヨドバシのポイントが溜まってたので1万円未満でした。

Xperia Ear Duoがスマートスピーカーなのか否かですが、音声アシスタントが呼び出せればスマートスピーカーに部類されると僕は考えています。 セットアップ時にGoogle Assistantもでてきました。

ただ、Xperia Ear Duoの僕にとっての最大の魅力はLINE社のClovaを呼び出すことができ、会話できます。 右耳側を押したら起動するのでその後は声で操作できます。

モバイル端末で外でClovaが呼べるのは非常に大きなアドバンテージです。

スマホGoogle、Alexaも呼び出すことはもちろん可能ですが、いちいちスマホを取り出す必要がないのは強いです。

使ってみた系の記事

様々なサイトで賛否両論に使ってみた系の記事があります。

e-earphone.blog

estpolis.com

実物

こんな感じです。

f:id:surumegohan:20181218122130j:plain
パッケージ

f:id:surumegohan:20181218122150j:plain
箱を開けてみる

f:id:surumegohan:20181218122210j:plain
ケース兼充電器

丸いケースが充電器も兼ねていて、USB接続で給電します。

iPhoneではClovaが使えないっぽい

僕はiPhoneを所有していないのでわからないですが、当初は以下のような記事でした。

■LINEのAIアシスタント「Clova」がソニーモバイル「Xperia Ear Duo」に対応

prtimes.jp

上記サイトに4月11日時点で LINEのAIアシスタント「Clova」に対応はAndroidのみ と記載されています。

ともあれセットアップガイドにはiPhoneでのセットアップマニュアルもあります。

f:id:surumegohan:20181218122244j:plain
解説書にiPhoneも記載されている

LINE BOOT AWARDがあったんだからiPhoneでも今ならClovaは動くだろう。 と思いましたが、公式サイトをみるとダメっぽいですね。。

Siriに引っ張られてるのでしょうか。。

他の部分は「対応予定」とはありますが、Clovaの対応予定がないので、Xperia Ear DuoではAndroidになりそうですね。

f:id:surumegohan:20181218122323p:plain
SONYさんのページ

ともあれ

僕個人が作っているClovaスキルを耳元で起動できています。 もちろん公開されているスキルも使えます。 ボイスアップラボさんの「ゾンビの街」とかすごいです。

AndroidのユーザーでClovaを屋外で呼び出すなら要検討かと。 ただ、下手したらEcho Showよりお高い ですけど。

以上

LINE ClovaでSDKなしでオーディオファイルを再生する

ごきげんよう

この記事は ADVENTARの「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の16日目の記事です。

今回はClovaの話です。

LINE Clovaでスキルを作成する時、SDKを用いることは多いと思います。

けれども、SDKがなくとも自分でJSONを作成してしまえばスキルを作成できます。

このアドベントカレンダーの10日目の記事

surumegohan.hatenablog.com

にも記載している、この本からスタートするとClovaのスキルを動かすことが非常に素早くできます。

Clovaのテキストスピーチは本に書いてある

上記の本には既にAPI GatewayとLambdaを使って挨拶をするスキルの作り方、および、ソースコードが記載されておりダウンロード可能です。

ほぼ同様の記述でオーディオファイルを再生する

音声ファイルとしてmp3を作っておいて、例えばAWSならそのままS3に置いておくとします。

'use strict';

exports.handler = function (event, context, callback) {
    var response = {
        statusCode: 200,
        headers: {},
        body: ""
    };
    
    var speechText = "";
    var requestJson = JSON.parse(event.body).request;
    var endFlg = false;
    
    if (requestJson.type === 'LaunchRequest') {
        // 起動時処理
        speechText = 'https://s3-ap-northeast-1.amazonaws.com/起動時に再生したいオーディオファイル.mp3';

    } else if (requestJson.type === 'SessionEndedRequest') {
        // セッション切れ
        speechText = 'https://s3-ap-northeast-1.amazonaws.com/セッションが切れたら再生したいオーディオファイル.mp3';
        endFlg = true;
    
    } else if (requestJson.type === 'IntentRequest') {

        if (requestJson.intent.name === 'EndIntent' || requestJson.intent.name === 'Clova.NoIntent') {
            // 終了処理
            speechText = 'https://s3-ap-northeast-1.amazonaws.com/終了時に再生したいオーディオファイル.mp3';
            endFlg = true;
        
        } else if (requestJson.intent.name === 'Clova.GuideIntent') {
            // ヘルプ用
            speechText = 'https://s3-ap-northeast-1.amazonaws.com/ヘルプの時に再生したいオーディオファイル.mp3';
            
        } else if (requestJson.intent.name === 'HelloIntent') {
            
            speechText = 'https://s3-ap-northeast-1.amazonaws.com/ハローと言われたの時に再生したいオーディオファイル.mp3';

        } else if (requestJson.intent.name === 'MorningIntent') {
            
            (略)
    }

    var responseJson = JSON.stringify({
        "version": "1.0",
        "response": {
            "outputSpeech": {
                "type": "SimpleSpeech",
                "values": {
                    "type":"URL", //ここを「URL」にする
                    "lang":"ja", //ここはjaである必要すら本当はない
                    "value": speechText
                }
            },
            "card": {},
            "directives": [],
            "shouldEndSession": endFlg
        }
    });
    
    response.body = responseJson;
    
    callback(null, response);

};

要するに、JSONを組み立てられればそれでOKなわけです。

実際に公式のSDKのコードを読めばすぐに気づきます。

github.com

ド直球に言うと以下で気づくことができます。

github.com

まとめ

Clovaに限らず、要するにJSONが組み立てられればそれで良くて、SDKJSONの生成をわかりやすく補助するためのものでしかありません。

それは他のプラットフォームでも、もっというとどんなアプリやサービスでも、対応するプロトコルに合えばそれでいいのです。

後から気づいたおまけ

本の著者がそのまま書いてるじゃん・・w

qiita.com

VUIの3プラットフォームに「ほげほげ」と話しかけた場合の謝るメッセージ一覧

ごきげんよう

この記事は ADVENTARの「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の15日目の記事です。

更新が遅れていた。。Qiitaにはあげていたんですが。。orz

先日、某イベントでこんなような会話がありました。

Aさん「~~~で、大丈夫ですか?」
僕「おっけーぐーぐる!」
Aさん「わかりませんでした。すみませんw」
僕「それはAlexaだろうが!w」

というわけで、VUIのスキルやアプリ作成時のエラーメッセージはバリエーションを持たせると機械っぽさが低減されて良いです。

なので、3プラットフォームに「ほげほげ」(hogehoge)と呼びかけた時、どういう返答をするかまとめました。 謝る系で、発見できたワードのみ掲載です。

これをどうでもいいと思うか、ユーザビリティと思うかは、その人次第です。

Alexa、ほげほげ

  1. うまく答えられません、ごめんなさい。
  2. わかりません、ごめんなさい。
  3. わかりませんでした、すみません。
  4. ごめんなさい、ちょっとわかりませんでした。
  5. すみません、ちょっと難しいです。
  6. すみません、よくわかりません。
  7. ちょっとよくわからなかったです。ごめんなさい。
  8. ちょっと難しいです。ごめんなさい。
  9. ごめんなさい、今はわかりません。
  10. すみません、わかりませんでした。

Clova、ほげほげ

  1. すみません、わかりませんでした。
  2. すみません、よくわかりませんでした。

※ たまに 「あら、そうですか」 などの相槌がでます。

OK,Google、ほげほげ

  1. 聞き取れませんでした。もう一度お願いします。
  2. すみません、お役に立てそうもありません。もっと頑張ります。
  3. すみません、よくわかりません。

※ たまに 「ぽけぽけを探しましたが現在利用できないようです」 になります。

まとめ

各社、様々な対応をしていますね。

Alexaが10種類も見つかったのは意外でした。 Clovaは相槌を話すことがあり、コミュニケーションを大事にしている様子が伺えます。 Google HomeActions on Google)は「ぽけぽけ」で必死に検索しようとするので、いかにも検索の会社らしいです。

エラーメッセージにも各社の社風がでてきて面白いと思います。 何かしらの参考になれば幸いです。

以上

Echo Show、Echo Spotの電源の切り方

ごきげんよう

この記事は ADVENTARの「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の14日目の記事です。

今回は明らかに小ネタです。

Echo Spotの時もハマったのですが、Echo Showで再度それをやることになりました。

けど、僕は完全に忘れていてハマったので記事にすることにしました。

電源の切り方がわからない

Echo Showのスタンドも買ってあって、それが昨日届きました。 これ、角度が結構調整できて大変嬉しいのですが、設置するときに(哲学的に?)壁に当たりました。

説明書が「電源ひっこぬけ」の絵しかない。

f:id:surumegohan:20181214073621j:plain
いきなり引っこ抜く説明書

世界中に配るであろうスタンドの説明書・解説書なので、わざわざ日本語はありません。 そこにいきなり「1」で電源を抜く画像です。 初手から電源を引っこ抜く指示です。

もう動いちゃってます。

ところが、Echo Showの画面上部から下に向かって設定メニューを表示して、さ迷いましたが電源の切り方がない。 もちろん電源ボタンもないです。

で、もしかしたらと・・・

ミュートボタンを長押ししたら電源が切れることがわかりました。

f:id:surumegohan:20181214073504j:plain
ミュートボタン長押しで電源を切る

Echo Spotでも同じです

ミュートボタンを長押しです。 ※ ミクさんが写りこんでいるのは僕の家の仕様です

DSC_1577.JPG

さすがにEcho Spot、Echo Showで電源で何かあるのが怖い

それなりのお値段がするので、こんなことで何かあったら嫌なので、改めて記事にしました。

Dotはぶっこぬいてます。。。

以上、小ネタでした。

EchoShowでAPLを使って告白される

ごきげんよう

この記事は ADVENTARの「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の13日目の記事です。

ついにきましたね! Echo Show!

というわけで、さっそく試してみるわけです。

でかい

比較のために500mlの空き缶を添えてますがでかいです。

f:id:surumegohan:20181213154055j:plain
開封の儀

動画とかすごい

映画を観ると特に感じますが、ブラウン管かよってレベルの大きさであるだけ音がすごい良いです。 これはもう今後Echo ShowでPrime VideoやYoutubeを観ます。

スキルたちがより見やすくなる

■キャプテン九九

f:id:surumegohan:20181213154132j:plain
キャプテン九九

乙葉の時間

f:id:surumegohan:20181213154222j:plain
乙葉の時間

■ヒロインの告白

f:id:surumegohan:20181213154254j:plain
ヒロインの告白

ヒロインの告白をAPL対応にしてみる

結果、テストバージョンでこうなってます。

f:id:surumegohan:20181213154333j:plain
ヒロインの告白をAPLにしてみる

環境構築から実装まで、偉大なる @zono_0 さんが既にわかりやすい記事を掲載しています。 いつもありがとうございます。

qiita.com

上記、記事ではask cliが前提ですが、そうでなくてもAPLはもちろん使えます。 同じところは省いて、そうでないところを今回は補完していきます。

1.Amazon Developer Portal

僕は今回開いた際にに右下にデバイス検出エラーがでました。

f:id:surumegohan:20181213154445p:plain
バイス検出エラー

が、 今回は 気にしないで大丈夫です。 JSONのフォーマットが欲しいので。

ちなみに、ここで対象のデバイスの大きさを以下のように選べます。

f:id:surumegohan:20181213154519p:plain
小型ハブと中型ハブ

f:id:surumegohan:20181213154612p:plain
大型ハブと超大型TC

2.Lambdaでインラインエディタでも組める

ask cliは僕も使います。 というより、慣れるとそちらの方が開発は大変良いです。 コード管理とかもできますし。

かといって、ask cliの導入に躓く方もいらっしゃるとも思いますので、インラインでがんばってみました。

@zono_0 さんのように、APLのJSONは分割した方が良いと思います。

f:id:surumegohan:20181213154649p:plain
Lambdaのインラインエディタでがんばる

3.ソースコード

とりあえず起動して動いた段階のソースコードです。

■APLでのヒロインの告白のLaunchRequest

'use strict';

const Alexa = require('ask-sdk');


//起動時
const kotoha_smartmacchiato = '<audio src=\"https://s3XXXXXXXXXXXXXX.mp3\" />';

const kotoha_voice = '<audio src=\"https://s3-XXXXXXXXXXXXXX.mp3\" />';


const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  async handle(handlerInput) {

    // ディスプレイ有り(APL対応)の場合
    if (supportsApl(handlerInput)) {
      // APL対応(documentに設定したテンプレートレイアウトを利用し、datasourcesの内容をディスプレイに表示します。)
      handlerInput.responseBuilder
        .addDirective({
          type : 'Alexa.Presentation.APL.RenderDocument',
          version: '1.0',
          document: require('./homepage.json'),
          datasources: require('./data.json')
        });
    }

    const speechText = kotoha_smartmacchiato + kotoha_voice;
    
    return handlerInput.responseBuilder
      .speak('<speak>' + speechText + '</speak>')
      .reprompt('<speak>' + speechText + '</speak>')
      .withShouldEndSession(false)
      .getResponse();

  }
};


/**
 * ディスプレイサポート(APL対応)判定値
 * @author zono_0    いつもありがとうございます!
 */ 
const supportsApl = (handlerInput) => {
  const hasDisplay =
    handlerInput.requestEnvelope.context &&
    handlerInput.requestEnvelope.context.System &&
    handlerInput.requestEnvelope.context.System.device &&
    handlerInput.requestEnvelope.context.System.device.supportedInterfaces &&
    handlerInput.requestEnvelope.context.System.device.supportedInterfaces['Alexa.Presentation.APL'];

  return hasDisplay;
};

/**
 * Echo Spotで使っていたディスプレイかどうかを判定するfunction
   Echo Showでも引き続き使えますが、今回はAPLを使います
*/
function supportsDisplay(handlerInput) {
  var hasDisplay =
    handlerInput.requestEnvelope.context &&
    handlerInput.requestEnvelope.context.System &&
    handlerInput.requestEnvelope.context.System.device &&
    handlerInput.requestEnvelope.context.System.device.supportedInterfaces &&
    handlerInput.requestEnvelope.context.System.device.supportedInterfaces.Display;

  console.log("Supported Interfaces are" + JSON.stringify(handlerInput.requestEnvelope.context.System.device.supportedInterfaces));
  return hasDisplay;
}

//動かす
exports.handler = Alexa.SkillBuilders.standard()
  .addRequestHandlers(LaunchRequestHandler)
  .lambda();

■homepage.json

{
        "type": "APL",
        "version": "1.0",
        "theme": "dark",
        "import": [
            {
                "name": "alexa-layouts",
                "version": "1.0.0"
            }
        ],
        "resources": [
            {
                "description": "Stock color for the light theme",
                "colors": {
                    "colorTextPrimary": "#151920"
                }
            },
            {
                "description": "Stock color for the dark theme",
                "when": "${viewport.theme == 'dark'}",
                "colors": {
                    "colorTextPrimary": "#f0f1ef"
                }
            },
            {
                "description": "Standard font sizes",
                "dimensions": {
                    "textSizeBody": 48,
                    "textSizePrimary": 27,
                    "textSizeSecondary": 23,
                    "textSizeSecondaryHint": 25
                }
            },
            {
                "description": "Common spacing values",
                "dimensions": {
                    "spacingThin": 6,
                    "spacingSmall": 12,
                    "spacingMedium": 24,
                    "spacingLarge": 48,
                    "spacingExtraLarge": 72
                }
            },
            {
                "description": "Common margins and padding",
                "dimensions": {
                    "marginTop": 40,
                    "marginLeft": 60,
                    "marginRight": 60,
                    "marginBottom": 40
                }
            }
        ],
        "styles": {
            "textStyleBase": {
                "description": "Base font description; set color and core font family",
                "values": [
                    {
                        "color": "@colorTextPrimary",
                        "fontFamily": "Amazon Ember"
                    }
                ]
            },
            "textStyleBase0": {
                "description": "Thin version of basic font",
                "extend": "textStyleBase",
                "values": {
                    "fontWeight": "100"
                }
            },
            "textStyleBase1": {
                "description": "Light version of basic font",
                "extend": "textStyleBase",
                "values": {
                    "fontWeight": "300"
                }
            },
            "mixinBody": {
                "values": {
                    "fontSize": "@textSizeBody"
                }
            },
            "mixinPrimary": {
                "values": {
                    "fontSize": "@textSizePrimary"
                }
            },
            "mixinSecondary": {
                "values": {
                    "fontSize": "@textSizeSecondary"
                }
            },
            "textStylePrimary": {
                "extend": [
                    "textStyleBase1",
                    "mixinPrimary"
                ]
            },
            "textStyleSecondary": {
                "extend": [
                    "textStyleBase0",
                    "mixinSecondary"
                ]
            },
            "textStyleBody": {
                "extend": [
                    "textStyleBase1",
                    "mixinBody"
                ]
            },
            "textStyleSecondaryHint": {
                "values": {
                    "fontFamily": "Bookerly",
                    "fontStyle": "italic",
                    "fontSize": "@textSizeSecondaryHint",
                    "color": "@colorTextPrimary"
                }
            }
        },
        "layouts": {},
        "mainTemplate": {
            "parameters": [
                "payload"
            ],
            "items": [
                {
                    "when": "${viewport.shape == 'round'}",
                    "type": "Container",
                    "direction": "column",
                    "width": "100vw",
                    "height": "100vh",
                    "items": [
                        {
                            "type": "Image",
                            "source": "${payload.bodyTemplate3Data.image.sources[0].url}",
                            "scale": "best-fill",
                            "width": "100vw",
                            "height": "100vh",
                            "position": "absolute",
                            "overlayColor": "rgba(0, 0, 0, 0.6)"
                        },
                        {
                            "type": "ScrollView",
                            "width": "100vw",
                            "height": "100vh",
                            "item": [
                                {
                                    "type": "Container",
                                    "direction": "column",
                                    "alignItems": "center",
                                    "paddingLeft": 30,
                                    "paddingRight": 30,
                                    "paddingBottom": 200,
                                    "items": [
                                        {
                                            "type": "AlexaHeader",
                                            "headerAttributionImage": "${payload.bodyTemplate3Data.logoUrl}",
                                            "headerTitle": "${payload.bodyTemplate3Data.title}"
                                        },
                                        {
                                            "type": "Text",
                                            "text": "<b>告白と言えば</b> | <b>やはり学校ですよね</b>",
                                            "style": "textStylePrimary",
                                            "color": "#4dd2ff",
                                            "width": "90vw",
                                            "textAlign": "center"
                                        },
                                        {
                                            "type": "Text",
                                            "text": "<b>${payload.bodyTemplate3Data.textContent.title.text}</b>",
                                            "style": "textStyleBody",
                                            "width": "90vw",
                                            "textAlign": "center"
                                        },
                                        {
                                            "type": "Text",
                                            "text": "${payload.bodyTemplate3Data.textContent.subtitle.text}",
                                            "style": "textStylePrimary",
                                            "width": "90vw",
                                            "textAlign": "center"
                                        },
                                        {
                                            "type": "Text",
                                            "text": "${payload.bodyTemplate3Data.textContent.primaryText.text}",
                                            "paddingTop": 40,
                                            "style": "textStylePrimary",
                                            "width": "90vw",
                                            "textAlign": "center"
                                        },
                                        {
                                            "type": "Text",
                                            "text": "${payload.bodyTemplate3Data.textContent.bulletPoint.text}",
                                            "paddingTop": 50,
                                            "style": "textStylePrimary",
                                            "width": "90vw",
                                            "textAlign": "center"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                },
                {
                    "type": "Container",
                    "width": "100vw",
                    "height": "100vh",
                    "items": [
                        {
                            "type": "Image",
                            "source": "${payload.bodyTemplate3Data.backgroundImage.sources[0].url}",
                            "scale": "best-fill",
                            "width": "100vw",
                            "height": "100vh",
                            "position": "absolute"
                        },
                        {
                            "type": "AlexaHeader",
                            "headerTitle": "${payload.bodyTemplate3Data.title}",
                            "headerAttributionImage": "${payload.bodyTemplate3Data.logoUrl}"
                        },
                        {
                            "type": "Container",
                            "direction": "row",
                            "paddingLeft": 40,
                            "paddingRight": 72,
                            "grow": 1,
                            "items": [
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate3Data.image.sources[0].url}",
                                    "width": 340,
                                    "height": 360,
                                    "scale": "best-fit",
                                    "align": "center"
                                },
                                {
                                    "type": "ScrollView",
                                    "height": "60vh",
                                    "shrink": 1,
                                    "item": [
                                        {
                                            "type": "Container",
                                            "items": [
                                                {
                                                    "type": "Text",
                                                    "text": "<b>やはり告白と言えば学校ですよね</b>",
                                                    "style": "textStylePrimary",
                                                    "color": "#4dd2ff"
                                                },
                                                {
                                                    "type": "Text",
                                                    "text": "<b>${payload.bodyTemplate3Data.textContent.title.text}</b>",
                                                    "style": "textStyleBody"
                                                },
                                                {
                                                    "type": "Text",
                                                    "text": "${payload.bodyTemplate3Data.textContent.subtitle.text}",
                                                    "style": "textStylePrimary"
                                                },
                                                {
                                                    "type": "Text",
                                                    "text": "${payload.bodyTemplate3Data.textContent.primaryText.text}",
                                                    "paddingTop": 40,
                                                    "style": "textStylePrimary"
                                                },
                                                {
                                                    "type": "Text",
                                                    "text": "${payload.bodyTemplate3Data.textContent.bulletPoint.text}",
                                                    "paddingTop": 50,
                                                    "style": "textStylePrimary"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
}

■data.json

{
        "bodyTemplate3Data": {
            "type": "object",
            "objectId": "bt3Sample",
            "backgroundImage": {
                "contentDescription": null,
                "smallSourceUrl": null,
                "largeSourceUrl": null,
                "sources": [
                    {
                        "url": "https://s3-学校画像.png",
                        "size": "small",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://s3-学校画像.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    }
                ]
            },
            "title": "APLを使って Echo Show で学校で(?)告白されよう!",
            "image": {
                "contentDescription": null,
                "smallSourceUrl": null,
                "largeSourceUrl": null,
                "sources": [
                    {
                        "url": "https://s3-結城琴葉画像.png",
                        "size": "small",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://s3-結城琴葉画像.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    }
                ]
            },
            "textContent": {
                "title": {
                    "type": "PlainText",
                    "text": " ヒロイン(結城琴葉)の告白"
                },
                "subtitle": {
                    "type": "PlainText",
                    "text": " 告白メッセージ"
                },
                "primaryText": {
                    "type": "PlainText",
                    "text": " 私、あなたが好きです。世界中の誰よりも・・あなたのことが、本当に好きなんです!私と・・付き合ってください. "
                },
                "bulletPoint": {
                    "type": "PlainText",
                    "text": " 結城琴葉ちゃんから告白されてみよう! "
                }
            },
            "logoUrl": "https://s3-スキルのロゴ.png",
            "hintText": "アレクサ、「ヒロインの告白」を開いて"
        }
    }

まとめ

ask cliで躓いても、なんとかなります。 現時点では僕はこれが実機で動いたレベルですが、APLを使いこなせるようになるとそれだけで職業になる気がします。

以上

スキル作成時のアイコンや音楽の素材サイトおよびツール類

ごきげんよう

この記事は ADVENTARの「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の12日目の記事です。

今日はAmazon Echo Showが届くはずなので、その記事を書くつもりでしたが、よくよく考えてみたら何時にくるかわからない。

ですので、別の日に予定していた記事として、僕がVUIのスキル・アプリを作成する時に利用検討する素材サイトを紹介します。

先日、某所のVUIイベントで 「Alexaのスキルは様々なツールで作れるようになってきてるけど、アイコンや効果音はみなさんどうしてますか?」 という話がありまして。

そういえばVUI業界の方々がどういう素材を用いているのか共有されていることを僕は認識していないので、僕が今までスキル作成をしていた時にたどり着いた素材サイトについて貼っておきます。

ライセンスが緩い素材サイト

以下に記載するサイトは著作権などのライセンスが比較的ゆるいサイトです。 ただ、もちろん利用規約はそれぞれのサイトに記載されておりますので、各自判断・自己責任でご利用ください。

1.アイコン

スキル作成時に地味に悩むのがアイコンです。

僕の中では以下の3点が利用しやすいと考えています。

■Alexaのicon-builder

developer.amazon.com

■ICOOON MONO

icooon-mono.com

ICOOON MONOさんはめっちゃおススメです。

■いらすとや

www.irasutoya.com

たまに「使い放題」と認識している方がおりますが 20点以上の利用など、制限が実はありますのでご注意を。

2.ジングル・効果音

VUIなので効果音が欲しい方はいらっしゃると思います。

ちなみに僕のスキル「ヒロインの告白」で起動時に 「しゃらららーーんスマートマキアート」 と、流れますが、あのような効果音を「ジングル」と呼びます。

ですので「効果音」「フリー素材」等でぐぐったりする方も多いと思われますが、「ジングル」を加えると、よりよいかもしれません。

以下が、僕がたどり着いた主なサイトです。

■ポケットサウンド

ご利用規約 – ポケットサウンド – フリー効果音素材・BGMダウンロード

■TURBO X

SOUND EFFECT| 商用利用可能なフリー効果音素材「TURBO X」

■DOVA-SYNDROME

dova-s.jp

■Music is VFR

利用規約|Music is VFR

■魔王魂

maoudamashii.jokersounds.com

3.アイコン画像のサイズ変更

イコン画像を拾ってきたとして、そのサイズ変更はどうしてるの?

との話もあったので僕が使っているツールを記載しておきます。

最近僕がwindowsで使っているのはリサイズ超簡単!Proです。

以下のように、サイズ変更したい画像を変換ファイルリストにいれて、 あとは縦横指定の箇所にAlexaの512×512と108×108を指定しておけば、覚えてくれるのでラジオボタンをポチって、「PNG」で「変換開始」でおしまいです。

本当に超簡単。

f:id:surumegohan:20181212104851p:plain
リサイズ超簡単Pro

4.音楽編集ソフト

音声ファイルの編集はAudacityを使うことが多いです。直感的にわかりやすいです。

f:id:surumegohan:20181212104916p:plain
Audacity

5.マイク

自分の声をVUIのスキル・アプリで流す!となるとマイクが必要になるわけですが、僕は以下です。

SONYさんのエレクトレットコンデンサーマイクロホン

SONY エレクトレットコンデンサーマイクロホン

3000円くらいでいい感じに使えます。 本気声優でもない素人が使う分には十分かと思います。

6.オーディオファイルの変換

Alexaなどプラットフォームに対応したオーディオファイルに変換するならffmpegを使っています。

以下に僕がQiitaに書いた記事があるので適宜ご参照ください。

Windows環境でffmpegを使ってmp3ファイルをAlexa対応形式に複数ファイル一括変換するメモ https://qiita.com/surumegohan/items/63a1b4e9fe404545ed06

まとめ

僕は上記に記載していた素材やツール等を使っていますが、VUIのスキル・アプリ作成をなさっている方で 「自分はここを使うよ!」 という素材やツールがあればコメントもらえると嬉しいです。

以上です。

Node-REDを使ってdialogflowで挨拶する

ごきげんよう

この記事は ADVENTARの 「するめごはんのVUI・スマートスピーカー Advent Calendar 2018」 の11日目の記事です。

昨日はNode-REDを用いてAlexaでの挨拶スキルについて記載しました。

surumegohan.hatenablog.com

今度は同じくNode-Redを使ってdialogflow(要するにGoogle Home)の挨拶アプリを作ってみます。

今回も同じく以下の本に一部従ってみます。 もちろん、そのまま転記してはいけないので、内容は適宜変更、追加してます。

スマートスピーカーアプリ開発入門 3大スマートスピーカー Amazon Echo Google Home LINE Clova対応

作ってみる

1.昨日Alexaスキルを作っているので、まずはIBM Cloudのページに行きます。

www.ibm.com

そして、画面左上の人型マークからサインインします。

f:id:surumegohan:20181211151923p:plain
IBM Cloudの画面

2.サインインをする

2回目以降の利用ユーザーならこの画面になるはず。

f:id:surumegohan:20181211151945p:plain
既存ユーザーのサインイン

3.「起動」を押してダッシュボードを開く

上記画像の「起動」を押してダッシュボードを開きます。

前回のAlexaスキルの情報が表示されています。

f:id:surumegohan:20181211152008p:plain
ダッシュボード

4.過去に作成したインスタンスを削除

liteプランだと無料であるかわりに、インスタンスが1つしか作成できません。 そのため、liteプランを続けるならば作成済みのインスタンスを削除します。

f:id:surumegohan:20181211152032p:plain
liteプランは1つのみしか作成できないので削除

5.インスタンスを再作成してNode-REDを検索

新しいインスタンスを「作成」したら、node-red で検索するとフィルタリングされて表示されるので選択します。

liteプランを継続している場合は、lite:ライトが既にフィルターにかかっているので、その後ろに node-red と入れてあげればOKです。

f:id:surumegohan:20181211152112p:plain
node-redでフィルタリングすると楽

6.あとは画面をポチポチ

Node-REDの画面が開いたら、画面をポチポチします。

HTTPSでPOST
・templeteで fulfillmentText をキーとした挨拶文を入れる
・httpResponse

あとは、この3つを線でつないであげます。

f:id:surumegohan:20181211152219p:plain
線でつなぐ

6.DialogFlowに設定すればおしまい

あとはDialogFlowで、プロジェクトを作り、Webhookに設定してあげれば、画面右のように動いてくれます。

f:id:surumegohan:20181211152242p:plain
DialogFlowでWebhookに設定

まとめ

DialogflowでWebhookとして指定できるので、その先がNode-REDになります。

簡単な挨拶のようなスキルはプログラミングなしに画面ポチポチだけでいけます。 JSONを書くところがプログラミングに該当するなら、そこはプログラミングですが・・

ともあれ、すごく簡単にできるのでNode-REDを使ってGoogle Homeでやりとりできるようなアプリを作ってみてはいかがでしょうか。

以上です。