├── .gitignore ├── LICENSE ├── README.md ├── intent_schema.json ├── lambda_function.py ├── sample_utterances.txt ├── screenshots ├── bart_departures.png ├── bart_elevators.png ├── bart_status.png ├── bart_welcome.png └── video_thumb.png └── stations.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | *.bak 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Modus Create 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![No longer maintained](https://img.shields.io/badge/Maintenance-OFF-red.svg) 2 | ### [DEPRECATED] This repository is no longer maintained 3 | > While this project is fully functional, the dependencies are no longer up to date. You are still welcome to explore, learn, and use the code provided here. 4 | > 5 | > Modus is dedicated to supporting the community with innovative ideas, best-practice patterns, and inspiring open source solutions. Check out the latest [Modus Labs](https://labs.moduscreate.com?utm_source=github&utm_medium=readme&utm_campaign=deprecated) projects. 6 | 7 | [![Modus Labs](https://res.cloudinary.com/modus-labs/image/upload/h_80/v1531492623/labs/logo-black.png)](https://labs.moduscreate.com?utm_source=github&utm_medium=readme&utm_campaign=deprecated) 8 | 9 | --- 10 | 11 | # Alexa Skill Demo 12 | 13 | Alexa Skill Demonstration using Python. 14 | 15 | Build a Skill for Alexa / Amazon Echo that tells you about the status of the Bay Area Rapid Transit (BART) train network. Full blog post describing this can be found [here](http://moduscreate.com/build-an-alexa-skill-with-python-and-aws-lambda/). 16 | -------------------------------------------------------------------------------- /intent_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "intents": [ 3 | { 4 | "intent": "GetStatus" 5 | }, 6 | { 7 | "intent": "GetElevators" 8 | }, 9 | { 10 | "intent": "GetTrainTimes", 11 | "slots": [ 12 | { 13 | "name": "Station", 14 | "type": "LIST_OF_STATIONS" 15 | } 16 | ] 17 | }, 18 | { 19 | "intent": "AMAZON.HelpIntent" 20 | }, 21 | { 22 | "intent": "AMAZON.StopIntent" 23 | }, 24 | { 25 | "intent": "AMAZON.CancelIntent" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /lambda_function.py: -------------------------------------------------------------------------------- 1 | import urllib2 2 | import json 3 | 4 | API_BASE="http://bartjsonapi.elasticbeanstalk.com/api" 5 | 6 | def lambda_handler(event, context): 7 | if (event["session"]["application"]["applicationId"] != 8 | "amzn1.echo-sdk-ams.app.bd304b90-xxxx-xxxx-xxxx-xxxxd4772bab"): 9 | raise ValueError("Invalid Application ID") 10 | 11 | if event["session"]["new"]: 12 | on_session_started({"requestId": event["request"]["requestId"]}, event["session"]) 13 | 14 | if event["request"]["type"] == "LaunchRequest": 15 | return on_launch(event["request"], event["session"]) 16 | elif event["request"]["type"] == "IntentRequest": 17 | return on_intent(event["request"], event["session"]) 18 | elif event["request"]["type"] == "SessionEndedRequest": 19 | return on_session_ended(event["request"], event["session"]) 20 | 21 | def on_session_started(session_started_request, session): 22 | print "Starting new session." 23 | 24 | def on_launch(launch_request, session): 25 | return get_welcome_response() 26 | 27 | def on_intent(intent_request, session): 28 | intent = intent_request["intent"] 29 | intent_name = intent_request["intent"]["name"] 30 | 31 | if intent_name == "GetStatus": 32 | return get_system_status() 33 | elif intent_name == "GetElevators": 34 | return get_elevator_status() 35 | elif intent_name == "GetTrainTimes": 36 | return get_train_times(intent) 37 | elif intent_name == "AMAZON.HelpIntent": 38 | return get_welcome_response() 39 | elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent": 40 | return handle_session_end_request() 41 | else: 42 | raise ValueError("Invalid intent") 43 | 44 | def on_session_ended(session_ended_request, session): 45 | print "Ending session." 46 | # Cleanup goes here... 47 | 48 | def handle_session_end_request(): 49 | card_title = "BART - Thanks" 50 | speech_output = "Thank you for using the BART skill. See you next time!" 51 | should_end_session = True 52 | 53 | return build_response({}, build_speechlet_response(card_title, speech_output, None, should_end_session)) 54 | 55 | def get_welcome_response(): 56 | session_attributes = {} 57 | card_title = "BART" 58 | speech_output = "Welcome to the Alexa BART times skill. " \ 59 | "You can ask me for train times from any station, or " \ 60 | "ask me for system status or elevator status reports." 61 | reprompt_text = "Please ask me for trains times from a station, " \ 62 | "for example Fremont." 63 | should_end_session = False 64 | return build_response(session_attributes, build_speechlet_response( 65 | card_title, speech_output, reprompt_text, should_end_session)) 66 | 67 | def get_system_status(): 68 | session_attributes = {} 69 | card_title = "BART System Status" 70 | reprompt_text = "" 71 | should_end_session = False 72 | 73 | response = urllib2.urlopen(API_BASE + "/status") 74 | bart_system_status = json.load(response) 75 | 76 | speech_output = "There are currently " + bart_system_status["traincount"] + " trains operating. " 77 | 78 | if len(bart_system_status["message"]) > 0: 79 | speech_output += bart_system_status["message"] 80 | else: 81 | speech_output += "The trains are running normally." 82 | 83 | return build_response(session_attributes, build_speechlet_response( 84 | card_title, speech_output, reprompt_text, should_end_session)) 85 | 86 | def get_elevator_status(): 87 | session_attributes = {} 88 | card_title = "BART Elevator Status" 89 | reprompt_text = "" 90 | should_end_session = False 91 | 92 | response = urllib2.urlopen(API_BASE + "/elevatorstatus") 93 | bart_elevator_status = json.load(response) 94 | 95 | speech_output = "BART elevator status. " + bart_elevator_status["bsa"]["description"] 96 | 97 | return build_response(session_attributes, build_speechlet_response( 98 | card_title, speech_output, reprompt_text, should_end_session)) 99 | 100 | def get_train_times(intent): 101 | session_attributes = {} 102 | card_title = "BART Departures" 103 | speech_output = "I'm not sure which station you wanted train times for. " \ 104 | "Please try again." 105 | reprompt_text = "I'm not sure which station you wanted train times for. " \ 106 | "Try asking about Fremont or Powell Street for example." 107 | should_end_session = False 108 | 109 | if "Station" in intent["slots"]: 110 | station_name = intent["slots"]["Station"]["value"] 111 | station_code = get_station_code(station_name.lower()) 112 | 113 | if (station_code != "unkn"): 114 | card_title = "BART Departures from " + station_name.title() 115 | 116 | response = urllib2.urlopen(API_BASE + "/departures/" + station_code) 117 | station_departures = json.load(response) 118 | 119 | speech_output = "Train departures from " + station_name + " are as follows: " 120 | for destination in station_departures["etd"]: 121 | speech_output += "Towards " + destination["destination"] + " on platform " + destination["estimate"][0]["platform"] + ". "; 122 | for estimate in destination["estimate"]: 123 | if estimate["minutes"] == "Leaving": 124 | speech_output += "Leaving now: " 125 | elif estimate["minutes"] == "1": 126 | speech_output += "In one minute: " 127 | else: 128 | speech_output += "In " + estimate["minutes"] + " minutes: " 129 | 130 | speech_output += estimate["length"] + " car train. " 131 | 132 | reprompt_text = "" 133 | 134 | return build_response(session_attributes, build_speechlet_response( 135 | card_title, speech_output, reprompt_text, should_end_session)) 136 | 137 | def get_station_code(station_name): 138 | return { 139 | "12th street oakland city center": "12th", 140 | "16th street mission": "16th", 141 | "19th street oakland": "19th", 142 | "24th street mission": "24th", 143 | "ashby": "ashb", 144 | "balboa park": "balb", 145 | "bay fair": "bayf", 146 | "castro valley": "cast", 147 | "civic center": "civc", 148 | "coliseum": "cols", 149 | "colma": "colm", 150 | "concord": "conc", 151 | "daly city": "daly", 152 | "downtown berkeley": "dbrk", 153 | "dublin pleasanton": "dubl", 154 | "el cerrito del norte": "deln", 155 | "del norte": "deln", 156 | "el cerrito plaza": "plza", 157 | "embarcadero": "embr", 158 | "fremont": "frmt", 159 | "fruitvale": "ftvl", 160 | "glen park": "glen", 161 | "hayward": "hayw", 162 | "lafayette": "lafy", 163 | "lake merritt": "lake", 164 | "macarthur": "mcar", 165 | "millbrae": "mlbr", 166 | "montgomery street": "mont", 167 | "north berkeley": "nbrk", 168 | "north concord martinez": "ncon", 169 | "oakland airport": "oakl", 170 | "orinda": "orin", 171 | "pittsburg bay point": "pitt", 172 | "pleasant hill": "phil", 173 | "powell street": "powl", 174 | "richmond": "rich", 175 | "rockridge": "rock", 176 | "san bruno": "sbrn", 177 | "san francisco airport": "sfia", 178 | "san leandro": "sanl", 179 | "south hayward": "shay", 180 | "south san francisco": "ssan", 181 | "union city": "ucty", 182 | "walnut creek": "wcrk", 183 | "west dublin pleasanton": "wdub", 184 | "west oakland": "woak", 185 | }.get(station_name, "unkn") 186 | 187 | def build_speechlet_response(title, output, reprompt_text, should_end_session): 188 | return { 189 | "outputSpeech": { 190 | "type": "PlainText", 191 | "text": output 192 | }, 193 | "card": { 194 | "type": "Simple", 195 | "title": title, 196 | "content": output 197 | }, 198 | "reprompt": { 199 | "outputSpeech": { 200 | "type": "PlainText", 201 | "text": reprompt_text 202 | } 203 | }, 204 | "shouldEndSession": should_end_session 205 | } 206 | 207 | def build_response(session_attributes, speechlet_response): 208 | return { 209 | "version": "1.0", 210 | "sessionAttributes": session_attributes, 211 | "response": speechlet_response 212 | } 213 | -------------------------------------------------------------------------------- /sample_utterances.txt: -------------------------------------------------------------------------------- 1 | GetStatus status 2 | GetStatus system status 3 | GetStatus what is the system status 4 | GetStatus how are the trains doing 5 | GetStatus what is the current status 6 | GetStatus what do the trains look like right now 7 | GetStatus how are the trains looking 8 | GetStatus are there any issues 9 | GetStatus are there any problems 10 | GetStatus are there any problems with the trains 11 | GetStatus are the trains running on schedule 12 | GetStatus are the trains running to schedule 13 | GetStatus is bart running normally 14 | GetStatus is bart doing ok 15 | GetElevators are there any elevator outages 16 | GetElevators are there any elevator outages right now 17 | GetElevators which elevators are out of order 18 | GetElevators how are the elevators 19 | GetElevators how are the elevators looking 20 | GetElevators are there any problems with the elevators 21 | 22 | GetTrainTimes when are the trains from {Station} 23 | GetTrainTimes what time are the trains from {Station} 24 | GetTrainTimes trains from {Station} 25 | GetTrainTimes departures from {Station} 26 | -------------------------------------------------------------------------------- /screenshots/bart_departures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModusCreateOrg/alexa-skill-demo/588a4517da07961948ffb995f89a743c290a091a/screenshots/bart_departures.png -------------------------------------------------------------------------------- /screenshots/bart_elevators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModusCreateOrg/alexa-skill-demo/588a4517da07961948ffb995f89a743c290a091a/screenshots/bart_elevators.png -------------------------------------------------------------------------------- /screenshots/bart_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModusCreateOrg/alexa-skill-demo/588a4517da07961948ffb995f89a743c290a091a/screenshots/bart_status.png -------------------------------------------------------------------------------- /screenshots/bart_welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModusCreateOrg/alexa-skill-demo/588a4517da07961948ffb995f89a743c290a091a/screenshots/bart_welcome.png -------------------------------------------------------------------------------- /screenshots/video_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModusCreateOrg/alexa-skill-demo/588a4517da07961948ffb995f89a743c290a091a/screenshots/video_thumb.png -------------------------------------------------------------------------------- /stations.txt: -------------------------------------------------------------------------------- 1 | 12th Street Oakland City Center 2 | 16th Street Mission 3 | 19th Street Oakland 4 | 24th Street Mission 5 | Ashby 6 | Balboa Park 7 | Bay Fair 8 | Castro Valley 9 | Civic Center 10 | Coliseum 11 | Colma 12 | Concord 13 | Daly City 14 | Downtown Berkeley 15 | Dublin Pleasanton 16 | El Cerrito del Norte 17 | del Norte 18 | El Cerrito Plaza 19 | Embarcadero 20 | Fremont 21 | Fruitvale 22 | Glen Park 23 | Hayward 24 | Lafayette 25 | Lake Merritt 26 | MacArthur 27 | Millbrae 28 | Montgomery Street 29 | North Berkeley 30 | North Concord Martinez 31 | Oakland Airport 32 | Orinda 33 | Pittsburg Bay Point 34 | Pleasant Hill 35 | Powell Street 36 | Richmond 37 | Rockridge 38 | San Bruno 39 | San Francisco Airport 40 | San Leandro 41 | South Hayward 42 | South San Francisco 43 | Union City 44 | Walnut Creek 45 | West Dublin Pleasanton 46 | West Oakland --------------------------------------------------------------------------------