日本で今話題になっているTwitterのトレンドワードをお知らせするAlexaアプリを作成した

AWS Lambda を利用して Alexa でTwitterのトレンドをお知らせするスキルを作成した

目次

作成したアプリケーション

インストール

https://www.amazon.co.jp/dp/B09MRFPFFC

主な機能

  • 「アレクサ、日本のトレンドワードを開いて」というと、Twitterのトレンドから、日本で話題になっているワードを5つお知らせしてくれます。

Alexa アプリ

Alexaアプリ側からは、Lambdaで作成したAPI をコールするだけのシンプルな構成にしています。

今回は「Twitterで日本のTwitterトレンドを5つ返却するAPI」を呼び出していますが、別のAPIを呼び出すようにすれば、簡単にアプリを複製することができます。

/**
 * モジュール参照
 */
const Alexa = require('ask-sdk-core');
const Axios = require('axios');

/**
 * LaunchRequestHandler
 * ユーザ発話:「<スキル名>を開いて」
 */
const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    async handle(handlerInput) {
        const speechText = await getTwitterTrends();
        return handlerInput.responseBuilder
            .speak(speechText)
            .reprompt(speechText)
            .withShouldEndSession(true)
            .getResponse();
    }
};

const getTwitterTrends = async (limit = 5) => {
    
    const breakTime = '<break time="1s"/>';
    const title = '現在の日本のトレンドワードを5つお伝えします。';

    const API_URL = `https://xxxxxxxx.xxx.xx?limit=${limit}`;
    
    let speechText = [];
    speechText.push(title);
    try {
        let treands = await Axios.get(API_URL).then((res) => {
            if(res.data.statusCode !== 200) {
                return 'エラーが発生しました。';
            }
            return res.data.body;
        });
        treands = treands.map(e => e.name.replace(/#/g, ''))
        speechText = [...speechText, ...treands]
    } catch (error) {
        speechText.push('APIのリクエストに失敗しました。' + error)
    }
    
    return speechText.join(breakTime);
};

/**
 * HelpIntentHandler
 * ユーザ発話:「ヘルプ」
 */
const HelpIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
    },
    handle(handlerInput) {
        const speechText = '現在の日本のトレンドワードを5つお伝えします。';

        return handlerInput.responseBuilder
            .speak(speechText)
            .reprompt(speechText)
            .getResponse();
    }
};

/**
 * CancelAndStopIntentHandler
 * ユーザ発話:「キャンセル」、「止めて」
 */
const CancelAndStopIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
                || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
    },
    handle(handlerInput) {
        const speechText = 'ご利用の中断をお受けいたしました。またのご利用をおまちしてます。';
        return handlerInput.responseBuilder
            .speak(speechText)
            .withShouldEndSession(true)
            .getResponse();
    }
};

/**
 * CancelAndStopIntentHandler
 * ユーザ発話:「終了」
 */
const SessionEndedRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
    },
    handle(handlerInput) {
        // Any cleanup logic goes here.
        return handlerInput.responseBuilder.getResponse();
    }
};

/**
 * IntentReflectorHandler
 * ユーザ発話:「<カスタムインテントのサンプル発話(デバッグ用)>」
 */
const IntentReflectorHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest';
    },
    handle(handlerInput) {
        const intentName = handlerInput.requestEnvelope.request.intent.name;
        const speechText = `デバッグモードです。${intentName}が呼び出されました。`;

        return handlerInput.responseBuilder
            .speak(speechText)
            //.reprompt('add a reprompt if you want to keep the session open for the user to respond')
            .getResponse();
    }
};

/**
 * ErrorHandler
 * エラーハンドラ
 */
const ErrorHandler = {
    canHandle() {
        return true;
    },
    handle(handlerInput, error) {
        console.log(`~~~~ Error handled: ${error.message}`);
        const speechText = `もう一度、別の言い方でおっしゃっていただけますか?`;

        return handlerInput.responseBuilder
            .speak(speechText)
            .reprompt(speechText)
            .getResponse();
    }
};

/**
 * exports.handler
 * メイン処理
 */
exports.handler = Alexa.SkillBuilders.custom()
    .addRequestHandlers(
        LaunchRequestHandler,
        HelpIntentHandler,
        CancelAndStopIntentHandler,
        SessionEndedRequestHandler,
        IntentReflectorHandler
    )
    .addErrorHandlers(
        ErrorHandler)
    .lambda();

開発時の注意点

Alexaアプリを作成して申請すると運営チームからのフィードバックを貰うことができます。

サンプルフレーズがエンドポイントに到達出来ているか?

Alexsaアプリを公開する際に、「アレクサ、○○を開いて」のようなサンプルフレーズを3つ設定することが出来ます。このサンプルフレーズで作成したAlexaアプリが起動できない場合は修正が必要になります。

第三者の商標またはブランドが使用されていないか?

作成したソースコードやアプリ名、画像に、第3者の商標やブランドが使用されている場合は修正が必要になります。「ツイッター」という文言やロゴ画像を利用していた場合は差し替えが必要です。

スキルのプロンプトがユーザーの入力を求めていないにも関わらず、セッションが開いたままになっていないか?

Alexsaアプリが起動された後、最後は必ずセッションを閉じる必要があります。セッションを閉じる際には.withShouldEndSession(true)のようにshouldEndSessionアトリビュートを「true」に変更する必要があります。

コメントを残す

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。