我一直试图制作涉及音频的alexa技能。我找到了一位很棒的导游here。
以下是他们的示例代码:
var stateByUser = {};
var podcastURL = "https://feeds.soundcloud.com/stream/309340878-user-652822799-episode-010-building-an-alexa-skill-with-flask-ask-with-john-wheeler.mp3";
// Entry-point for the Lambda
exports.handler = function(event, context) {
var player = new SimplePlayer(event, context);
player.handle();
};
// The SimplePlayer has helpful routines for interacting with Alexa, within minimal overhead
var SimplePlayer = function (event, context) {
this.event = event;
this.context = context;
};
// Handles an incoming Alexa request
SimplePlayer.prototype.handle = function () {
var requestType = this.event.request.type;
var userId = this.event.context ? this.event.context.System.user.userId : this.event.session.user.userId;
var response = null;
// On launch, we tell the user what they can do (Play audio :-))
if (requestType === "LaunchRequest") {
this.say("Welcome to the Simple Audio Player. Say Play to play some audio!", "You can say Play");
// Handle Intents here - Play, Pause and Resume is all for now
} else if (requestType === "IntentRequest") {
var intent = this.event.request.intent;
if (intent.name === "Play") {
this.play(podcastURL, 0);
} else if (intent.name === "AMAZON.PauseIntent") {
// When we receive a Pause Intent, we need to issue a stop directive
// Otherwise, it will resume playing - essentially, we are confirming the user's action
this.stop();
} else if (intent.name === "AMAZON.ResumeIntent") {
var lastPlayed = this.load(userId);
var offsetInMilliseconds = 0;
if (lastPlayed !== null) {
offsetInMilliseconds = lastPlayed.request.offsetInMilliseconds;
}
this.play(podcastURL, offsetInMilliseconds);
}
} else if (requestType === "AudioPlayer.PlaybackStopped") {
// We save off the PlaybackStopped Intent, so we know what was last playing
this.save(userId, this.event);
}
};
/**
* Creates a proper Alexa response using Text-To-Speech
* @param message
* @param repromptMessage
*/
SimplePlayer.prototype.say = function (message, repromptMessage) {
var response = {
version: "1.0",
response: {
shouldEndSession: false,
outputSpeech: {
type: "SSML",
ssml: "<speak> " + message + " </speak>"
},
reprompt: {
outputSpeech: {
type: "SSML",
ssml: "<speak> " + message + " </speak>"
}
}
}
}
this.context.succeed(response);
};
/**
* Plays a particular track, from specific offset
* @param audioURL The URL to play
* @param offsetInMilliseconds The point from which to play - we set this to something other than zero when resuming
*/
SimplePlayer.prototype.play = function (audioURL, offsetInMilliseconds) {
var response = {
version: "1.0",
response: {
shouldEndSession: true,
directives: [
{
type: "AudioPlayer.Play",
playBehavior: "REPLACE_ALL", // Setting to REPLACE_ALL means that this track will start playing immediately
audioItem: {
stream: {
url: audioURL,
token: "0", // Unique token for the track - needed when queueing multiple tracks
expectedPreviousToken: null, // The expected previous token - when using queues, ensures safety
offsetInMilliseconds: offsetInMilliseconds
}
}
}
]
}
}
this.context.succeed(response);
};
// Stops the playback of Audio
SimplePlayer.prototype.stop = function () {
var response = {
version: "1.0",
response: {
shouldEndSession: true,
directives: [
{
type: "AudioPlayer.Stop"
}
]
}
}
this.context.succeed(response);
};
// Saves information into our super simple, not-production-grade cache
SimplePlayer.prototype.save = function (userId, state) {
console.log("Save: " + userId);
stateByUser[userId] = state;
};
// Load information from our super simple, not-production-grade cache
SimplePlayer.prototype.load = function (userId) {
console.log("Load: " + userId);
var state = null;
if (userId in stateByUser) {
state = stateByUser[userId];
console.log("Loaded " + userId + " State: " + state);
}
return state;
};
我正在尝试重构此代码,以使其遵循与亚马逊提供的trivia skills示例类似的格式。但是,当我运行我的重构代码时,我得到一个错误说
TypeError: Cannot set property 'say' of undefined
at Object.<anonymous> (/Users/Rob/Desktop/super-simple-audio-player/index.js:47:28)
这是我尝试重构
"use strict";
var stateByUser = {};
var podcastURL = "https://p.scdn.co/mp3-preview/2385471a5d35709ad90e368dacabe4082af4541a?cid=null";
var Alexa = require("alexa-sdk");
// Entry-point for the Lambda
exports.handler = function(event, context) {
var alexa = Alexa.handler(event, context);
alexa.registerHandlers(SimplePlayer);
alexa.execute();
};
// The SimplePlayer has helpful routines for interacting with Alexa, within minimal overhead
var SimplePlayer = {
"LaunchRequest": function () {
this.emit(":tell","Welcome to the Simple Audio Player. Say play to begin.");
},
"Play": function() {
this.play(podcastURL, 0);
},
"AMAZON.PauseIntent": function() {
this.stop();
},
"AMAZON.ResumeIntent": function () {
var lastPlayed = this.load(userId);
var offsetInMilliseconds = 0;
if (lastPlayed !== null) {
offsetInMilliseconds = lastPlayed.request.offsetInMilliseconds;
}
this.play(podcastURL, offsetInMilliseconds);
},
"AudioPlayer.PlaybackStopped": function () {
this.save(userId, this.event);
}
};
// Handles an incoming Alexa request
SimplePlayer.prototype.say = function (message, repromptMessage) {
var response = {
version: "1.0",
response: {
shouldEndSession: false,
outputSpeech: {
type: "SSML",
ssml: "<speak> " + message + " </speak>"
},
reprompt: {
outputSpeech: {
type: "SSML",
ssml: "<speak> " + message + " </speak>"
}
}
}
}
this.context.succeed(response);
};
/**
* Plays a particular track, from specific offset
* @param audioURL The URL to play
* @param offsetInMilliseconds The point from which to play - we set this to something other than zero when resuming
*/
SimplePlayer.prototype.play = function (audioURL, offsetInMilliseconds) {
var response = {
version: "1.0",
response: {
shouldEndSession: true,
directives: [
{
type: "AudioPlayer.Play",
playBehavior: "REPLACE_ALL", // Setting to REPLACE_ALL means that this track will start playing immediately
audioItem: {
stream: {
url: audioURL,
token: "0", // Unique token for the track - needed when queueing multiple tracks
expectedPreviousToken: null, // The expected previous token - when using queues, ensures safety
offsetInMilliseconds: offsetInMilliseconds
}
}
}
]
}
}
this.context.succeed(response);
};
// Stops the playback of Audio
SimplePlayer.prototype.stop = function () {
var response = {
version: "1.0",
response: {
shouldEndSession: true,
directives: [
{
type: "AudioPlayer.Stop"
}
]
}
}
this.context.succeed(response);
};
// Saves information into our super simple, not-production-grade cache
SimplePlayer.prototype.save = function (userId, state) {
console.log("Save: " + userId);
stateByUser[userId] = state;
};
// Load information from our super simple, not-production-grade cache
SimplePlayer.prototype.load = function (userId) {
console.log("Load: " + userId);
var state = null;
if (userId in stateByUser) {
state = stateByUser[userId];
console.log("Loaded " + userId + " State: " + state);
}
return state;
};
我添加了alexa-sdk并更改了exports.handler和simplePlayer.prototype.handler()。有什么想法,为什么它不起作用?
提前致谢
答案 0 :(得分:0)
我实际创建了你引用的项目。很高兴你发现它很有用。
在重新分解项目时,您将其从原型样式的JS对象更改为对象文字。两者都是可行的方法,但是当保持特定请求的状态(特别是事件和上下文字段)时,对象文字成为一个问题。
这也意味着项目中定义的原型方法不能从对象文字定义中获得。您需要先实例化SimplePlayer(通过调用new SimplePlayer(event, context)
),然后才能获得它们。
如果您想更好地理解这些方法之间的权衡,可以在这里阅读:
Object literal vs constructor+prototype
以下是使用与我的项目一致的Alexa SDK的示例。它定义了&#34; LaunchRequest&#34;作为原型函数,而不仅仅是一个属性:
SimplePlayer.prototype.LaunchRequest = function () {
this.emit(":tell", "Welcome to the Simple Audio Player. Say play to begin.");
};
您还需要确保实例化SimplePlayer(不仅仅是引用它)。注册时,它应如下所示:
alexa.registerHandlers(new SimplePlayer(event, context));
希望有意义,祝你好运!让我知道它是怎么回事(我可以随时联系到https://gitter.im/bespoken/bst)