Alexa、僕が知りたい情報を答えるようになって！

# Alexa、社内でJavaに詳しい人を教えて
実際に動かしている様子はこちらです

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Alexaに社内の有識者を聞いたら教えてくれるようにしました。<br>これで一人暮らしのテレワーク勤務で一人で抱え込まなくて済むようにしたい！<a href="https://twitter.com/hashtag/Alexa?src=hash&amp;ref_src=twsrc%5Etfw">#Alexa</a> <a href="https://twitter.com/hashtag/%E4%B8%80%E4%BA%BA%E6%9A%AE%E3%82%89%E3%81%97?src=hash&amp;ref_src=twsrc%5Etfw">#一人暮らし</a> <a href="https://twitter.com/hashtag/%E3%83%86%E3%83%AC%E3%83%AF%E3%83%BC%E3%82%AF?src=hash&amp;ref_src=twsrc%5Etfw">#テレワーク</a> <a href="https://t.co/hIjbNEZkO9">pic.twitter.com/hIjbNEZkO9</a></p>&mdash; heihei (@heihei15408697) <a href="https://twitter.com/heihei15408697/status/1331378221833568256?ref_src=twsrc%5Etfw">November 24, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# AlexaとLambdaの設定方法
下記の記事を参考
[「Alexa、Lambdaと連携する方法を教えて」と聞いても、答えがよく分からなかったので自分でやったことメモ](https://qiita.com/heihei15408697/items/4fee419fdc22cb011b0b
)

AmazonEchoを初めて買ったのでいろいろ聞いて遊んでたんですが、予想以上に返答をくれ、**すごいなこれと感動しました。**
ただ、会社のことはさすがに応えてくれなかった。。
なので、会社のことを聞いても答えてくれるようにしていきます。
手始めに僕が知りたいと思っている「社内の有識者の情報」を聞くようにしてみました。
「Alexa、社内でjavaに詳しい人を教えて」と聞いたら、答えてくれるようになっています。

# 現在の状況
Lambdaのnode.js側に配列で記載している。これをDBから取得するようにしたい。

```Javascript
// sets up dependencies
const Alexa = require('ask-sdk-core');
const i18n = require('i18next');

const {
  getRequestType,
  getIntentName,
  getSlotValue,
  getDialogState,
} = require('ask-sdk-core');

let person = {};
person["java"] = "Aさん";
person["node.js"] = "Bさん";

// core functionality for fact skill
const GetNewFactHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    // checks request type
    return request.type === 'LaunchRequest'
      || (request.type === 'IntentRequest'
        && request.intent.name === 'GetNewFactIntent');
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    // gets a random fact by assigning an array to the variable
    // the random item from the array will be selected by the i18next library
    // the i18next library is set up in the Request Interceptor
    const randomFact = requestAttributes.t('FACTS');
    // concatenates a standard message with the random fact
    const speakOutput = requestAttributes.t('GET_FACT_MESSAGE') + randomFact;

    return handlerInput.responseBuilder
      .speak(speakOutput)
      .withSimpleCard(requestAttributes.t('SKILL_NAME'), randomFact)
      .getResponse();
  },
};

const HelpHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('HELP_MESSAGE'))
      .reprompt(requestAttributes.t('HELP_REPROMPT'))
      .getResponse();
  },
};

const FallbackHandler = {
  // The FallbackIntent can only be sent in those locales which support it,
  // so this handler will always be skipped in locales where it is not supported.
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.FallbackIntent';
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('FALLBACK_MESSAGE'))
      .reprompt(requestAttributes.t('FALLBACK_REPROMPT'))
      .getResponse();
  },
};

const ExitHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && (request.intent.name === 'AMAZON.CancelIntent'
        || request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('STOP_MESSAGE'))
      .getResponse();
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    console.log(`Error handled: ${error.message}`);
    console.log(`Error stack: ${error.stack}`);
    const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
    return handlerInput.responseBuilder
      .speak(requestAttributes.t('ERROR_MESSAGE'))
      .reprompt(requestAttributes.t('ERROR_MESSAGE'))
      .getResponse();
  },
};

const LocalizationInterceptor = {
  process(handlerInput) {
    // Gets the locale from the request and initializes i18next.
    const localizationClient = i18n.init({
      lng: handlerInput.requestEnvelope.request.locale,
      resources: languageStrings,
      returnObjects: true
    });
    // Creates a localize function to support arguments.
    localizationClient.localize = function localize() {
      // gets arguments through and passes them to
      // i18next using sprintf to replace string placeholders
      // with arguments.
      const args = arguments;
      const value = i18n.t(...args);
      // If an array is used then a random value is selected
      if (Array.isArray(value)) {
        return value[Math.floor(Math.random() * value.length)];
      }
      return value;
    };
    // this gets the request attributes and save the localize function inside
    // it to be used in a handler by calling requestAttributes.t(STRING_ID, [args...])
    const attributes = handlerInput.attributesManager.getRequestAttributes();
    attributes.t = function translate(...args) {
      return localizationClient.localize(...args);
    }
  }
};

const HelloWorldIntentHandler = {
  canHandle(handlerInput) {
    console.log('called HelloWorldIntentHandler.canHandle');
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
　          && request.intent.name === 'HelloWorldIntent';
  },
  handle(handlerInput) {
    console.log('called HelloWorldIntentHandler.handle');
    return handlerInput.responseBuilder
            .speak("こんにちはインテントが呼ばれました。")
            .getResponse();
  }
};

const SearchSkillHandler = {
  canHandle(handlerInput) {
    console.log('called SearchSkillHandler.canHandle');
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
　          && request.intent.name === 'SearchSkillIntent';
  },
  handle(handlerInput) {
    const skillsNameValue = getSlotValue(handlerInput.requestEnvelope, 'skills');
    console.log('called SearchSkillHandler.handle');
    const skillsPersonName = person[`${skillsNameValue}`];
    return handlerInput.responseBuilder
            .speak(`${skillsNameValue}` + "は" + `${skillsPersonName}` + "が詳しいです。")
            .getResponse();
  }
};

const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    GetNewFactHandler,
    SearchSkillHandler,
    HelloWorldIntentHandler,
    HelpHandler,
    ExitHandler,
    FallbackHandler,
    SessionEndedRequestHandler,
  )
  .addRequestInterceptors(LocalizationInterceptor)
  .addErrorHandlers(ErrorHandler)
  .withCustomUserAgent('sample/basic-fact/v2')
  .lambda();


const jpData = {
  translation: {
    SKILL_NAME: 'テスト',
  },
};

// constructs i18n and l10n data structure
const languageStrings = {
  'ja': jpData,
};
```