Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

【Alexa】あつ森スキルがリジェクトされたので公開します

大人気中の任天堂switchのソフト「あつまれどうぶつの森」のアレクサスキルを開発したものの、ものの見事に申請が通らなかったのでオープンソース化します。

公開するに至った経緯

(あつ森プレイ中)

「ゲーム中断して魚とか虫の値段スマホで調べるのめんどいな。。」

「声のやりとりだけで完結できたら便利だよね。」

と思ったのが開発しようと思ったきっかけ。

  1. 開発が終わり、Amazonへ申請 → Amazon「却下(任天堂の許可を得よ)」
  2. 任天堂への許可取り → 任天堂「個別には対応しかねる。公開情報だけでなんとかしろ」
  3. 以下のガイドラインを発見。商用利用でなければOKと書いてあるからこれをAmazonに見せつければいける!→ Amazon 「Alexaスキルについて言及がないから承諾を得ているとは言えない、却下」
  4. 詰み

https://www.nintendo.co.jp/networkservice_guideline/ja/index.html (任天堂ガイドライン)

せっかく作ったし、多くの人に使ってもらおうと思い、公開。

実際使ってみて便利なのは間違いないです。よかったら使ってやってください。

機能紹介

ソースコードはgithubから落としてもらえればそのまま使える。詳細は後ほど。

1 . LaunchRequest(スキル起動時に呼ばれるインテント)

@sb.request_handler(can_handle_func=is_request_type("LaunchRequest"))
def launch_request_handler(handler_input):
    # type: (HandlerInput) -> Response
    speech_text = "ようこそ、森のどうぶつたちへ。何が聞きたいですか?"

    handler_input.response_builder.speak(speech_text).ask(
        "今月から釣れる魚はなに、と言ってみてください").set_card(SimpleCard(
        "森のどうぶつ", speech_text)).set_should_end_session(False)
    return handler_input.response_builder.response

2 . ItemsIntent (全ての情報を教えてくれるインテント)

例えば、カブトムシについて教えて、と聞くとカブトムシに関する情報(売価、出現場所、出現時期、雑学)について教えてくれる。虫と魚の情報は全てinsects.jsonとfish.jsonにまとめてあってそこから取得してる。(このjsonファイル作るのが一番骨の折れる作業だった。。)

@sb.request_handler(can_handle_func=is_intent_name("ItemsIntent"))
def about_items_intent_handler(handler_input):
    # type: (HandlerInput) -> Response
    slot = get_slot_value(handler_input=handler_input, slot_name="insects")
    if slot is not None:
        with open("insects.json") as f:
            insects = json.load(f)
            price = insects[slot]["price"]
            habitat = insects[slot]["habitat"]
            season = insects[slot]["season"]
            trivia = insects[slot]["trivia"]

        speech_text = slot + "は売価" + price + "です。出現場所は" + habitat \
        + "で、" + season + "にあらわれます。" + trivia

    slot = get_slot_value(handler_input=handler_input, slot_name="fish")
    if slot is not None:
        with open("fish.json") as f:
            fish = json.load(f)
            price = fish[slot]["price"]
            habitat = fish[slot]["habitat"]
            season = fish[slot]["season"]
            size = fish[slot]["size"]
            trivia = fish[slot]["trivia"]

        speech_text = slot + "は売価" + price + "です。出現場所は" + habitat \
            + "で、" + season + "に現れます。サイズは" + size + "です。" + trivia

    handler_input.response_builder.speak(speech_text).ask(
        "他に聞きたいことはありますか?").set_card(SimpleCard(
        "森のどうぶつ", speech_text)).set_should_end_session(True)
    return handler_input.response_builder.response

3 . PriceIntent (価格を教えてくれるインテント)

生物の売価だけを知りたい時に呼び出す。仕組みは2と変わらないのでソースコードは割愛。シーラカンスはいくらで売れる?みたいに聞くと価格を教えてくれる。

4 . HabitatIntent (生息地を教えてくれるインテント)

生息地と現れる時期を知りたい時に呼び出す。キンギョはいつとれる?とか、キンギョはどこで釣れる?みたいに聞くと教えてくれる。

5 . SeasonBeginIntent (○月からとれる生物を教えてくれるインテント)

今月から釣れる魚は?とか9月からとれる虫は?って聞くと教えてくれる。ちなみにここで使う情報はSeasonItems.jsonにまとめてあって、そこから取得してる。月初に使えそう。

@sb.request_handler(can_handle_func=is_intent_name("SeasonNormalIntent"))
def about_items_intent_handler(handler_input):
    # type: (HandlerInput) -> Response
    season = get_slot_value(handler_input=handler_input, slot_name="season")
    kind = get_slot_value(handler_input=handler_input, slot_name="kind")

    if season == "今月" or season == "来月":
        today = datetime.date.today()
        if season == "今月":
            month = today.month
        elif season == "来月":
            month = today.month + 1

        if month == 1:
            season = "一月"
        elif month == 2:
            season = "二月"
        elif month == 3:
            season = "三月"
        elif month == 4:
            season = "四月"
        elif month == 5:
            season = "五月"
        elif month == 6:
            season = "六月"
        elif month == 7:
            season = "七月"
        elif month == 8:
            season = "八月"
        elif month == 9:
            season = "九月"
        elif month == 10:
            season = "十月"
        elif month == 11:
            season = "十一月"
        elif month == 12:
            season = "十二月"
        elif month == 13:
            season = "一月"

    with open("SeasonItems.json") as f:
        items = json.load(f)
        item = items[season][kind]["normal"]
        speech_text = item

    handler_input.response_builder.speak(speech_text).ask(
        "他に聞きたいことはありますか?").set_card(SimpleCard(
        "森のどうぶつ", speech_text)).set_should_end_session(True)
    return handler_input.response_builder.response

今が何月をを取得して、来月ならばそれに1を足してみたいなことをする必要があったのと、スロット値は数字ではなく漢数字を入れないとうまく行かなかったという理由からわざわざ数字から漢数字に変換してる。なんかもっと上手いやり方ある気がすると思いつつ、とりあえず動けばいいや精神で乗り切る。せめて配列にするべきだったかな。

6 . SeasonNormalIntent (○月に釣れる高価な生物を教えてくれるインテント)

今月釣れる魚を教えて、とか5月にとれる虫を教えてみたいにいうとその月にとれる高価な生物上位10ぐらいを教えてくれる。5とほぼ同じなのでソースコードは割愛。

7 . SeasonEndIntent (○月までにとれる生物を教えてくれるインテント)

今月までにとれる虫を教えて、とか9月までに釣れる魚を教えてみたいにいうと教えてくれる。5とほぼ同じなのでソースコードは割愛。

ソースコード

https://github.com/enoharas/Alexa-Atsumori.git

ここからクローンして使ってください。実装方法はREADMEに書いてますが、経験者向けにかなり雑に書いています。ただ、AlexaのDeveloperアカウントとAWSアカウントを作ってもらって、出来上がったコードをデプロイするだけなら初心者でも簡単にできるとおもいます。Lambdaは個人利用であれば毎月の無料枠を超えることはまずないのでお金はかかりません。READMEだけで分からなかったらコメントか連絡ください。

さいごに

またなんか作ったら公開します!

shiyo1011
普段はSIerで働くインフラエンジニア。 クイズサイトも運営しています。 資格:AWS認定(SAP,SOA)、CCNA
https://fiveace.tokyo/
fiveace
エンジニア、デザイナー等、様々なバックグラウンドを持つプロフェッショナル集団です。クイズや役立つコラムを配信しているサイトを運営しています。
https://fiveace.tokyo
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away