Comments (19)
Hi @fredzannarbor , thanks for trying this out and raising the issue. There are couple of things in the skill code that need changes :
- The skill builder's
create
method, that creates theskill_obj
, has to be run after adding the request and exception handlers, since it delegates those handlers to the skill object. So, try moving that thing after all the handler addition code. - The
post
method has to return a string as per Flask's response documentation. Also, since Alexa responses should be JSON type, we need to return a response with content type as JSON. You can use flask'sjsonify
method, to return the skill response in the JSON format. - It's good to see the skill id validation added. However, as per the custom skill deployment as webservice documentation, you would also need Request Verification and Timestamp Verification on your input request. As mentioned in #53 , we are in the process of coming up with the steps and we will update the issue once ready. Stay tuned.
- The
Skill
object already has request validation inbuilt, and is triggered in theinvoke
call. To set it up, you can just provide the skill id to be verified on theSkillBuilder
. For eg: in this case, you can addsb.skill_id="amzn1.ask.skill.2954cb35-f478-4408-a3d0-be731bf566b3"
before creating theskill_obj
.
Can you please try out after making the changes and let us know if you still have problems?
from alexa-skills-kit-sdk-for-python.
Hi,
wow, great timing! I was working on the same exact thing and came across this issue.
Thanks to @nikhilym I was able to get the example working by moving the "skill_obj = sb.create()" after the request and exception handlers like suggested and wrapping the responses with jsonify.
I ran the flask app on my local machine behind ngrok and it worked like a charm!
Here is the code that I used (it's slightly different since I am using the hello_world with decorators example
# -*- coding: utf-8 -*-
# This is a simple Hello World Alexa Skill, built using
# the decorators approach in skill builder.
from flask import Flask, request, jsonify
import json
import logging
from ask_sdk_core.skill_builder import SkillBuilder
from ask_sdk_core.utils import is_request_type, is_intent_name
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model.ui import SimpleCard
from ask_sdk_model import Response, RequestEnvelope
app = Flask(__name__)
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
sb = SkillBuilder()
handler = sb.lambda_handler()
@sb.request_handler(can_handle_func=is_request_type("LaunchRequest"))
def launch_request_handler(handler_input):
"""Handler for Skill Launch."""
# type: (HandlerInput) -> Response
speech_text = "Welcome to the Alexa Skills Kit, you can say hello!"
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("Hello World", speech_text)).set_should_end_session(
False).response
@sb.request_handler(can_handle_func=is_intent_name("HelloWorldIntent"))
def hello_world_intent_handler(handler_input):
"""Handler for Hello World Intent."""
# type: (HandlerInput) -> Response
speech_text = "Hello Python World from Decorators!"
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("Hello World", speech_text)).set_should_end_session(
True).response
@sb.request_handler(can_handle_func=is_intent_name("AMAZON.HelpIntent"))
def help_intent_handler(handler_input):
"""Handler for Help Intent."""
# type: (HandlerInput) -> Response
speech_text = "You can say hello to me!"
return handler_input.response_builder.speak(speech_text).ask(
speech_text).set_card(SimpleCard(
"Hello World", speech_text)).response
@sb.request_handler(
can_handle_func=lambda handler_input:
is_intent_name("AMAZON.CancelIntent")(handler_input) or
is_intent_name("AMAZON.StopIntent")(handler_input))
def cancel_and_stop_intent_handler(handler_input):
"""Single handler for Cancel and Stop Intent."""
# type: (HandlerInput) -> Response
speech_text = "Goodbye!"
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("Hello World", speech_text)).response
@sb.request_handler(can_handle_func=is_intent_name("AMAZON.FallbackIntent"))
def fallback_handler(handler_input):
"""AMAZON.FallbackIntent is only available in en-US locale.
This handler will not be triggered except in that locale,
so it is safe to deploy on any locale.
"""
# type: (HandlerInput) -> Response
speech = (
"The Hello World skill can't help you with that. "
"You can say hello!!")
reprompt = "You can say hello!!"
handler_input.response_builder.speak(speech).ask(reprompt)
return handler_input.response_builder.response
@sb.request_handler(can_handle_func=is_request_type("SessionEndedRequest"))
def session_ended_request_handler(handler_input):
"""Handler for Session End."""
# type: (HandlerInput) -> Response
return handler_input.response_builder.response
@sb.exception_handler(can_handle_func=lambda i, e: True)
def all_exception_handler(handler_input, exception):
"""Catch all exception handler, log exception and
respond with custom message.
"""
# type: (HandlerInput, Exception) -> Response
logger.error(exception, exc_info=True)
speech = "Sorry, there was some problem. Please try again!!"
handler_input.response_builder.speak(speech).ask(speech)
return handler_input.response_builder.response
@app.route('/hello', methods=['POST'])
def post():
"""
Process the request as following :
- Get the input request JSON
- Deserialize it to Request Envelope
- Verify the request was sent by Alexa
- Invoke the skill
- Return the serialized response
"""
content = request.json
request_envelope = skill_obj.serializer.deserialize(
payload=json.dumps(content), obj_type=RequestEnvelope)
response_envelope = skill_obj.invoke(
request_envelope=request_envelope, context=None)
print(response_envelope)
return jsonify(skill_obj.serializer.serialize(response_envelope))
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
skill_obj = sb.create()
from alexa-skills-kit-sdk-for-python.
Hey @giordyb , awesome. Thanks for the sample. Glad it worked. @fredzannarbor please update the issue with your observations.
from alexa-skills-kit-sdk-for-python.
Thanks! What's the philosophical thinking about classes v. decorators? Having every class have 2 functions one of which is can_handle seems kind of pedantic to me. It would be different if the classes had more functions.
from alexa-skills-kit-sdk-for-python.
Hey @fredzannarbor. Thanks for the question. This seems to be a good one to add to the FAQ section of the SDK docs. We provided both ways to work for the skill developers because when we were researching which design to follow, we saw around equal interest in both the class and decorator design approaches.
Granted the class approach seems a lot of code to write, but as you mentioned above, if there are more functions that your handler might call internally or your can_handle
logic itself is not just checking for request types but doing some complex checks, then formatting it under a class makes the code more structured. It also helps skill devs coming from other OOP languages to understand how the code works. It also keeps the Python SDK design to align to the Node and Java SDKs.
Decorators provide a simple way of writing the handlers and because of the way it is wrapped, they automatically register the decorated functions on the skill. However, as you can see, sometimes the can_handle
under decorators might get little bit messy (with lambda code etc.).
From the SDK's perspective, we don't have favorites 😄 . Hope this explains why we have both designs in the SDK. Btw, let us know if the changes suggested by me and @giordyb helped, or if you have any other questions.
from alexa-skills-kit-sdk-for-python.
Still some difficulty, I think with the ngrok <=> Alexa Dev Console piece.
For expediency sake I took @giordyb's working code and am running it on my local machine. Flask seems to be working fine.
n [4]: runfile('/Users/fzimmerman/voice/helloworld/decorators-helloworld.py', wdir='/Users/fzimmerman/voice/helloworld')
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
* Restarting with stat
ngrok also seems to be working correctly.
Forwarding https://59ec3db5.ngrok.io -> localhost:5000
The ADC endpoint is https://59ec3db5.ngrok.io/hello and the certificate type is #2, wildcard.
I issue the correct invocation in Test and I get "There was a problem with the requested skill's response" and null JSON. ngrok shows a 500 server error.
I see from Google that ngrok/500/Alexa is a very common problem and I am working through the various articles from people having the same trouble. Any ideas much appreciated!
from alexa-skills-kit-sdk-for-python.
@fredzannarbor how are you running the flask app?
I noticed that my example throws an error (NameError: name 'skill_obj' is not defined) if I just run the script directly from python, if i set FLASK_APP="app.py"
and then run flask run
then it works.
from alexa-skills-kit-sdk-for-python.
that did it! %@%) ;-)
from alexa-skills-kit-sdk-for-python.
i'm making progress but still a bit away from full success. I have two machines that I care about, my laptop and an AWS Ubujntu server. I want my Alexa endpoints to point to the AWS server which is https://www.altbrains.com. On AWS have Apache serving 80 and 443 and Flask running https on 5000.
* Serving Flask app "decorators-helloworld.py"
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on https://0.0.0.0:5000/ (Press CTRL+C to quit)
69.136.137.70 - - [26/Feb/2019 23:39:03] "GET / HTTP/1.1" 404 -
69.136.137.70 - - [26/Feb/2019 23:39:04] "GET /favicon.ico HTTP/1.1" 404 -
69.136.137.70 - - [26/Feb/2019 23:39:08] "GET /hello HTTP/1.1" 405 -
As you can see, I can verify that https is working by doing a curl https://www.altbrains.com:5000/hello.
However, when I hit that endpoint via Alexa using @giordyb's code, I get an error -- no output json from the skill. Just to confirm, in the test pane, the JSON I/OK Skill input is what Amazon sent to the Skill - it's input from the skill's point of view -- so if the output is null, that means the skill program is somehow failing to properly process the request from AMazon?
{
"version": "1.0",
"session": {
"new": false,
"sessionId": "amzn1.echo-api.session.e7bc285d-636d-4d4d-a954-5999c7946d5c",
"application": {
"applicationId": "amzn1.ask.skill.a4dbba09-7e72-4171-9974-383e93d3ac5b"
},
"user": {
"userId": "amzn1.ask.account.AERFQQAHZJ6W4GQMS4FBKLXQDZQL52OLYG2IM6LVCTZUG5FK52UVOAJL3727UHIVRK2WBJVSAVWATYSS7FMFXSBNSTT5OCWSZEYB4KSENACW6Q7O3UOVBG7762NDMUX77EKLSNMRGGBPUCYJ5SLYRZ22W65PRH66AL725LN2CQ3NHQYBRPBVPHDDJPZ2JJFU6HA4VOLYTPDQY2Q"
}
},
"context": {
"System": {
"application": {
"applicationId": "amzn1.ask.skill.a4dbba09-7e72-4171-9974-383e93d3ac5b"
},
"user": {
"userId": "amzn1.ask.account.AERFQQAHZJ6W4GQMS4FBKLXQDZQL52OLYG2IM6LVCTZUG5FK52UVOAJL3727UHIVRK2WBJVSAVWATYSS7FMFXSBNSTT5OCWSZEYB4KSENACW6Q7O3UOVBG7762NDMUX77EKLSNMRGGBPUCYJ5SLYRZ22W65PRH66AL725LN2CQ3NHQYBRPBVPHDDJPZ2JJFU6HA4VOLYTPDQY2Q"
},
"device": {
"deviceId": "amzn1.ask.device.AEX4B3S7HMKFLRLHV4AWOLSJ3NS3MS3J6DNCCXIG5XWFY47IHRT55IL2UXBEVTM4KM55ZIYUKOOSEM2BXU6IC5256USL4IQTE44ORLY5NZQ2UAIMEGB2MPAO466SAGOXVG2P6PH3MM4QYAQ2AB65VMIPSF7647XNWIUMNOSNIPMZ4HCJJXMVS",
"supportedInterfaces": {}
},
"apiEndpoint": "https://api.amazonalexa.com",
"apiAccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLmE0ZGJiYTA5LTdlNzItNDE3MS05OTc0LTM4M2U5M2QzYWM1YiIsImV4cCI6MTU1MTIyNjM2NywiaWF0IjoxNTUxMjI2MDY3LCJuYmYiOjE1NTEyMjYwNjcsInByaXZhdGVDbGFpbXMiOnsiY29uc2VudFRva2VuIjpudWxsLCJkZXZpY2VJZCI6ImFtem4xLmFzay5kZXZpY2UuQUVYNEIzUzdITUtGTFJMSFY0QVdPTFNKM05TM01TM0o2RE5DQ1hJRzVYV0ZZNDdJSFJUNTVJTDJVWEJFVlRNNEtNNTVaSVlVS09PU0VNMkJYVTZJQzUyNTZVU0w0SVFURTQ0T1JMWTVOWlEyVUFJTUVHQjJNUEFPNDY2U0FHT1hWRzJQNlBIM01NNFFZQVEyQUI2NVZNSVBTRjc2NDdYTldJVU1OT1NOSVBNWjRIQ0pKWE1WUyIsInVzZXJJZCI6ImFtem4xLmFzay5hY2NvdW50LkFFUkZRUUFIWko2VzRHUU1TNEZCS0xYUURaUUw1Mk9MWUcySU02TFZDVFpVRzVGSzUyVVZPQUpMMzcyN1VISVZSSzJXQkpWU0FWV0FUWVNTN0ZNRlhTQk5TVFQ1T0NXU1pFWUI0S1NFTkFDVzZRN08zVU9WQkc3NzYyTkRNVVg3N0VLTFNOTVJHR0JQVUNZSjVTTFlSWjIyVzY1UFJINjZBTDcyNUxOMkNRM05IUVlCUlBCVlBIRERKUFoySkpGVTZIQTRWT0xZVFBEUVkyUSJ9fQ.A__40lXEgXpaWMV8mwDgn9AH0kouQn0zaeCEayiMEVXaYQ-LTZqpaBuuA0JtdtiBrlOPleicVux8THCh7Of3B3exWmg1vCEzHLCJnucbB8OG9BD5R6z3oLCo8OcfV4lJBRaaizdTPY3SaeA47MNr95l3W7qafpJ3eno28Lm0V9DvfI_8TgNiqgdoGMXMq9cxeJ_GKNdHaYV7lDpdtsboBz7ZYUmJ5PGLGfAPvCZGJdCVv4Aa2t5_Q1WKqXco6OLgrWsW0NOhC_DE8Hpqwdz9DARIbymC1hQ1p6uT9K_e9SXc-j8NobinBa19DI7lHFLVTqzOcpFdfnJUVgd6r-CN6Q"
},
"Viewport": {
"experiences": [
{
"arcMinuteWidth": 246,
"arcMinuteHeight": 144,
"canRotate": false,
"canResize": false
}
],
"shape": "RECTANGLE",
"pixelWidth": 1024,
"pixelHeight": 600,
"dpi": 160,
"currentPixelWidth": 1024,
"currentPixelHeight": 600,
"touch": [
"SINGLE"
]
}
},
"request": {
"type": "SessionEndedRequest",
"requestId": "amzn1.echo-api.request.07f1772b-2cc5-4914-8fae-88757086c30b",
"timestamp": "2019-02-27T00:07:47Z",
"locale": "en-US",
"reason": "ERROR",
"error": {
"type": "INVALID_RESPONSE",
"message": "An exception occurred while dispatching the request to the skill."
}
}
}
from alexa-skills-kit-sdk-for-python.
I think I understand what's happening. Ngrok to my laptop's port 5000 is working because Alexa is hitting https:ngrok.io, which is port 443, which is a requirement per https://developer.amazon.com/docs/custom-skills/host-a-custom-skill-as-a-web-service.html#about-ssl-options, whereas Alexa is trying to hit port 5000 on my Flask server on AWS, which is illegal. So all I need to do is to deploy my Flask app to wsgi production server at 443. Does this sound correct @nikhilym ?
BTW this goes to your earlier point about all the bits and pieces of info that need to be updated to document this use case!
from alexa-skills-kit-sdk-for-python.
@fredzannarbor I think that is what is happening in your case, but I cannot confirm without more information. Are you still facing problems?
As for the bits and pieces, agree that the documentation is not slick and we are working with the respected teams to get that sorted.
from alexa-skills-kit-sdk-for-python.
noticed that my example throws an error (NameError: name 'skill_obj' is not defined) if I just run the script directly from python, if i set
FLASK_APP="app.py"
and then runflask run
then it work
@giordyb I had the same problem and the "flask run" solution works for me but I would like to be able to run the script directly from my python IDE (Spyder), any idea how I can achieve that? what is the NameError about?
from alexa-skills-kit-sdk-for-python.
@fredzannarbor I believe flask run
is the only supported way to run a flask app other than behind a web server.
To debug the app I use VSCode, it has flask support out of the box but I'm not sure how you could replicate this in Spyder.
from alexa-skills-kit-sdk-for-python.
Hey @fredzannarbor , we are guessing you are able to run the skill through your flask application using the code sample provided by us and @giordyb . We are closing this issue because of inactivity. Please reopen in case you still have any questions. You can keep track of #53 for more information on running skills on other than AWS Lambda.
from alexa-skills-kit-sdk-for-python.
Yes, I just finally (last night) got everything working end to end. There were a lot of issues, mostly unrelated to Alexa. I may write up what I experienced.
from alexa-skills-kit-sdk-for-python.
That's great @fredzannarbor . Glad it's working now. Sure, the write-up would definitely help others. Please share whenever you can. Thanks!!
from alexa-skills-kit-sdk-for-python.
Spoke too soon. Everything's working in test, but failed certification b/c not validating.
The skill end-point is not validating the signatures for incoming requests and is accepting requests with an empty signature URL.
The skill end-point is not validating the signatures for incoming requests and is accepting requests with an incorrect certificate URL.
The skill end-point is not validating the signatures for incoming requests and is accepting requests with an invalid signature URL specified.
The skill end-point is not validating the signatures for incoming requests and is accepting requests when no signature URL headers are specified.
from alexa-skills-kit-sdk-for-python.
the app is being served as follows:
endpoint request > https (443) endpoint served by Apache on AWS Ubuntu > mod_wsgi > basketball.wsgi > basketball.py
what's working:
Alexa Dev Console Test can open "Last Shot" app at https (443) Endpoint, works correctly.
what's not?
error message as above, not validating.
@app.route('/altbrains-basketball', methods=['POST'])
def post():
"""
Process the request as following :
- Get the input request JSON
- Deserialize it to Request Envelope
- Verify the request was sent by Alexa
- Invoke the skill
- Return the serialized response
"""
content = request.json
request_envelope = skill_obj.serializer.deserialize(
payload=json.dumps(content), obj_type=RequestEnvelope)
response_envelope = skill_obj.invoke(
request_envelope=request_envelope, context=None)
print(response_envelope)
return jsonify(skill_obj.serializer.serialize(response_envelope))
if name == 'main':
#context = ('/opt/lampstack-7.1.26-0/apache2/conf/ssl_certificate.crt', '/opt/lampstack-7.1.26-0/apache2/conf/www.altbrains.com.key')
app.run(debug=True, host='0.0.0.0')
sb.skill_id = "amzn1.ask.skill.5cbfc4d6-35dd-436f-9dbe-bab5dda42409"
skill_obj = sb.create()
from alexa-skills-kit-sdk-for-python.
Hey @fredzannarbor , as mentioned in issue #53, your skill code needs to handle Request Signature
and Timestamp
validation if it is hosted as a custom webservice.
from alexa-skills-kit-sdk-for-python.
Related Issues (20)
- ask_sdk_model.services.service_exception.ServiceException: The authentication token is invalid or doesn't have access to make this HOT 11
- Sb Conflicting each other HOT 5
- `ModuleNotFoundError:` No module named 'asn1crypto'`` when importing skill adapter from flask HOT 3
- 'NoneType' object has no attribute 'system' HOT 2
- Link how to create a new security profile should be updated HOT 1
- Golang SDK - Alexa Skills kit HOT 2
- User with almost all scopes types receives unauthorized_client error HOT 2
- UserAgentManager missing from 1.15 PyPI distro HOT 3
- Alexa HOT 1
- Fail to import local modules HOT 6
- I have a intent for the alexa skill which has two slots, one of them is fulfilled while invoking the skill. I want the second slot to store the value uttered by the user at a later point of time. Is there a way to do so using python HOT 1
- Cannot import the SpokenInfo class (ask_sdk_model.services.reminder_management) HOT 2
- Receiving unauthorized_client error trying to list all skills HOT 3
- SpeakDirective doesn't create correct audio src directive HOT 1
- Outdated version of cryptography? HOT 5
- Invalid signatures with django-ask-sdk since ask-sdk-webservice-support v1.3.3 HOT 4
- ENDPOINT_TIMEOUT is not handled properly in Incorrect handling of SessionEndedRequest.
- AskForPermissionsConsentCard not showing the option to activate requested permission HOT 2
- documentation error - local_debug.py
- Bug report : Sending a voice forward consent start connection directive returns error "ask_sdk_core/response_helper.py directive.object_type has no attribute 'object_type'"
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from alexa-skills-kit-sdk-for-python.