드롭 박스와 연계하여 텍스트 파일을 낭독하는 Alexa 스킬을 개발하려고 한 이야기

<배경>



최근에 EchoDot에 빠져, Kindle 책을 읽어 주면서 차 통근의 여가를 부수고 있습니다.
문득, IR자료(투자도 흥미가 있기 때문에···)라든지 Kindle책 이외에도 읽어 주었으면 하는 것이 있다-라고 생각해,
스스로 만들까라고 생각했습니다.

<결론>



기대 시키면 그렇기 때문에 결론을 먼저 말하면,,,
Alexa 스킬로 Dropbox 계정 링크를 할 수 없었다.
원인: OAuth 2.0의 인증시에 Alexa 스킬의 요구 파라미터의 "state"가 671 문자로
  Dropbox측의 500문자 제한을 넘어 버리고 있기 (위해)때문에.
  현재, 자신에게는 해결 방법을 모릅니다. . .

<시스템 구성안>



Alexa 스킬 개발은 1회 한 적이 있기 때문에, DropBox 경유로 할까나 적당히 생각했습니다.
사실은 Pdf 업로드하고 Lambda 측에서 변환시키거나, 자동 수집을라든지 여러가지 하려고 했지만, 우선 후회해.



AlexaSkill



AlexaSkill 개발은 여러 사람이하고 있기 때문에 생략. 이하, 한 일
①호출명 : 아이아루로 등록
② 인텐트 : read_kessan, 샘플 발화 = 껄껄
③빌드·보존
④ 엔드포인트를 Lambda로 설정

람다



Lambda에서 실행하는 코드는 다음과 같습니다.

lambda_function.py
# -*- coding: utf-8 -*-
"""
This sample demonstrates a simple skill built with the Amazon Alexa Skills Kit.
The Intent Schema, Custom Slots, and Sample Utterances for this skill, as well
as testing instructions are located at http://amzn.to/1LzFrj6

For additional samples, visit the Alexa Skills Kit Getting Started guide at
http://amzn.to/1LGWsLG
"""

from __future__ import print_function


# --------------- Helpers that build all of the responses ----------------------

def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': "SessionSpeechlet - " + title,
            'content': "SessionSpeechlet - " + ""
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }


def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }


# --------------- Functions that control the skill's behavior ------------------

def get_welcome_response():
    """ If we wanted to initialize the session to have some attributes we could
    add those here
    """

    session_attributes = {}
    card_title = "Welcome、IR"
    speech_output = "IRを読むよ.何を読む?"
    # If the user either does not reply to the welcome message or says something
    # that is not understood, they will be prompted again with this text.
    reprompt_text = "何を読む?."
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def handle_session_end_request():
    card_title = "Session Ended"
    speech_output = "おつ."
    # Setting this to true ends the session and exits the skill.
    should_end_session = True
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))


#テキストファイルの読み込み
def input_text(file_path):
    f = open(file_path)
    text = f.read()
    f.close
    return text

#決算を読む
def read_kessan():
    session_attributes = {}
    card_title = "kessan"
    text=input_text('sample3.txt')
    speech_output = text
    reprompt_text = ""
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))



# --------------- Events ------------------

def on_session_started(session_started_request, session):
    """ Called when the session starts """

    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])


def on_launch(launch_request, session):
    """ Called when the user launches the skill without specifying what they
    want
    """

    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # Dispatch to your skill's launch
    return get_welcome_response()


def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """

    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    # Dispatch to your skill's intent handlers
    if intent_name == "read_kessan":
        return read_kessan()
    elif intent_name == "AMAZON.HelpIntent":
        return get_welcome_response()
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")


def on_session_ended(session_ended_request, session):
    """ Called when the user ends the session.

    Is not called when the skill returns should_end_session=true
    """
    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # add cleanup logic here


# --------------- Main handler ------------------

def lambda_handler(event, context):
    """ Route the incoming request based on type (LaunchRequest, IntentRequest,
    etc.) The JSON body of the request is provided in the event parameter.
    """
    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])

    """
    Uncomment this if statement and populate with your skill's application ID to
    prevent someone else from configuring a skill that sends requests to this
    function.
    """
    # if (event['session']['application']['applicationId'] !=
    #         "amzn1.echo-sdk-ams.app.[unique-value-here]"):
    #     raise ValueError("Invalid Application ID")

    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])

    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])

지금까지 일단 Echo로부터의 호출로 Lambda의 개발 폴더에 있는 텍스트 파일을 낭독할 수 있게 되었다.
여기에서 DropBox API와 AlexaSkill의 계정 링크를 실시한다.

Dropbox 앱 등록



· DropboxAPI 선택
· App folder를 선택
・App의 이름을 적당히 붙인다


· Appkey, Appsercret 메모
· OAuth2의 RedirectURIs 추가


AlexaSkill 계정 링크



htps //w w. d 필터 p 보 x. 코 m / ゔ ぇ ぺ rs / 도쿠 멘 타치 온 / h tp
↑보면서, 인증 화면의 URI와 액세스 토큰의 URI를 기입.


이것으로 링크 완료했으므로 알렉사 앱으로 계정 링크할 수 있는지 확인.



응?

왠지 "state"가 500문자를 넘고 있어요~. 651문자도 와요~. 같은 오류,
,,,

그러고 보니 여기 이런 기술이 있었다.



AlexaSkill의 계정 요청은 이런 식으로
https://www.dropbox.com/oauth2/authorize?client_id="Appkey"&response_type=code&state=○○○○
↑의 ○○ 부분이 500문자 넘으면 안되는 것 같다.

지금은 해결 방법을 모르겠습니다.

좋은 웹페이지 즐겨찾기