I can't understand the way to use the the method to retrieve the customer mail in Alexa
The doc says to make a request with a token.
https://developer.amazon.com/fr/docs/custom-skills/request-customer-contact-information-for-use-in-your-skill.html
Then I have done that :
function AlexaRequest(accessToken){
Host: api.amazonalexa.com
Accept: application/json
Authorization: Bearer +accessToken+
GET https://api.amazonalexa.com/v2/accounts/~current/settings/Profile.email
}
2 questions
1 - Why do I get a "Parsing Error" : Unexpected Token https ?
2 - How do I get the response from Alexa ?
Thanks !
You can use UpsServiceClient methods to get user's Personal Information.
Follow the steps below or watch detailed tutorial HERE
Step 1: Write this code in your intent handler
const GreetMeIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'GreetMeIntent';
},
async handle(handlerInput) {
const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
const token = requestEnvelope.context.System.user.permissions &&
requestEnvelope.context.System.user.permissions.consentToken;
if (!token) {
return handlerInput.responseBuilder
.speak('Please Provide Permissions!')
.withAskForPermissionsConsentCard(['alexa::profile:email:read'])
.getResponse();
}
let {deviceId} = requestEnvelope.context.System.device;
const upsServiceClient = serviceClientFactory.getUpsServiceClient();
const email = await upsServiceClient.getProfileEmail();
let speechText = `Hello! Your email is ${email}`;
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Hello World', speechText)
.getResponse();
},
}
Step 2: Add withApiClient in your exports
exports.handler = skillBuilder
.addRequestHandlers(
GreetMeIntentHandler
)
.addErrorHandlers(ErrorHandler)
.withApiClient(new Alexa.DefaultApiClient())
.lambda();
Related
So basically, my idea for a new command for my discord bot is a "link searcher", which will be a searching command that sends the url of the video that is chosen by the user. Something like in the image attached.
What I already have made is a searching command with embed, but im not quite sure how to send the video url that gets chosen via reaction. Any ideas/solutions?
I have found a solution after some tries, so here's the final code.
//////CONFIG LOAD///////////
////////////////////////////
const ytsr = require("youtube-sr")
const { Client, Collection, MessageEmbed } = require("discord.js");
const { attentionembed } = require("../util/attentionembed"); //attentionembed is an embed i pre-made for errors/attention cases for when the user gets one
const { approveemoji, denyemoji, PREFIX, } = require(`../config.json`); //my config contains the definitions for "yes" and "no" emojis, together with the bot token
////////////////////////////
//////COMMAND BEGIN/////////
////////////////////////////
module.exports = {
name: "linkfor",
aliases: ["searchlink","findlink","link","lf"], //optional
cooldown: 3, //optional
async execute(message, args, client) {
//if its not in a guild return
if (!message.guild) return;
//react with approve emoji
message.react(approveemoji).catch(console.error);
//if the argslength is null return error
if (!args.length)
return attentionembed(message, `Usage: ${message.client.prefix}${module.exports.name} <Video Name>`)
//if there is already a search return error
if (message.channel.activeCollector)
return attentionembed(message, "There is a search active!");
//define search
const search = args.join(" ");
//define a temporary Loading Embed
let temEmbed = new MessageEmbed()
.setAuthor("Searching...", "put a gif link here if you want")
.setColor("#F0EAD6")
//define the Result Embed
let resultsEmbed = new MessageEmbed()
.setTitle("Results for ")
.setDescription(`\`${search}\``)
.setColor("#F0EAD6")
.setAuthor("Search results:", "put a gif link here if you want")
.setFooter("Respond with the right number", "put a gif link here if you want")
//try to find top 9 results
try {
//find them
const results = await ytsr.search(search, { limit: 9 });
//map them and sort them and add a Field to the ResultEmbed
results.map((video, index) => resultsEmbed.addField(video.url, `${index + 1}. ${video.title}`));
//send the temporary embed aka Loading... embed
const resultsMessage = await message.channel.send(temEmbed)
//react with 9 Numbers
await resultsMessage.react("1️⃣");
await resultsMessage.react("2️⃣");
await resultsMessage.react("3️⃣");
await resultsMessage.react("4️⃣");
await resultsMessage.react("5️⃣");
await resultsMessage.react("6️⃣");
await resultsMessage.react("7️⃣");
await resultsMessage.react("8️⃣");
await resultsMessage.react("9️⃣");
//edit the resultmessage to the resultembed (you can also try deleting and sending the new one, if you need to)
await resultsMessage.edit(resultsEmbed)
//set the collector to true
message.channel.activeCollector = true;
//wait for a response
let response;
await resultsMessage.awaitReactions((reaction, user) => user.id == message.author.id,
{ max: 1, time: 60000, errors: ['time'], }).then(collected => {
//if its one of the emoji set them to 1 / 2 / 3 / 4 / ...
if (collected.first().emoji.name == "1️⃣") { return response = 1; }
if (collected.first().emoji.name == "2️⃣") { return response = 2; }
if (collected.first().emoji.name == "3️⃣") { return response = 3; }
if (collected.first().emoji.name == "4️⃣") { return response = 4; }
if (collected.first().emoji.name == "5️⃣") { return response = 5; }
if (collected.first().emoji.name == "6️⃣") { return response = 6; }
if (collected.first().emoji.name == "7️⃣") { return response = 7; }
if (collected.first().emoji.name == "8️⃣") { return response = 8; }
if (collected.first().emoji.name == "9️⃣") { return response = 9; }
//otherwise set it to error
else {
response = "error";
}
});
//if response is error return error
if (response === "error") {
//send error message
attentionembed(message, "Please use the right emoji symbol.");
//try to delete the message
return resultsMessage.delete().catch(console.error);
}
//get the response link
const URL = resultsEmbed.fields[parseInt(response) - 1].name;
//set collector to false aka off
message.channel.activeCollector = false;
//send the collected url
message.channel.send(URL);
//delete the search embed (optional, for better displaying)
resultsMessage.delete().catch(console.error);
//catch any errors while searching
} catch (error) {
//log them
console.error(error);
//set collector false, just incase its still true
message.channel.activeCollector = false;
}
}
};
Im making a Discord Bot Dashboard and implementing Discord OAuth2. I'm following the guide here: https://discordjs.guide/oauth2/#a-quick-example and the code is essentially the same.
async getJSONResponse(body) {
let fullBody = '';
for await(const data of body) {
fullBody += data.toString();
}
return JSON.parse(fullBody)
}
async getAccessToken(code) {
if (code) {
try {
let body = new URLSearchParams();
body.append('client_id', environment.discord.clientId)
body.append('client_secret', environment.discord.clientSecret)
body.append('code', code)
body.append('grant_type', 'authorization_code')
body.append('redirect_uri', environment.discord.redirect)
body.append('scope', 'identify')
let options = {
headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
};
const tokenResponseData = await this.http.post('https://discord.com/api/oauth2/token', body.toString(), options)
const oauthData = await this.getJSONResponse(tokenResponseData.body)
console.log(oauthData)
} catch(err) {
console.error('an error')
console.error(err)
}
}
}
However, I get this error: Property 'body' does not exist on type 'Observable<Object>'.
As you can see, the guide above clearly shows that body does in fact exist on the object.
I'm out of ideas, any help is appreciated.
Thanks
I have a React front end and Flask Backend. There's a Long-Running Task in the Back end which is gonna start when I submit the Job from the Front end. I assigned 2 Buttons on the front end to Submit the Job and the Other One to Check the status of the Job and Retrieve Data if the Job Is Finished.
Front End Job Submit Function
const sendSubmitRequest = async () => {
try {
const resp = await axios.get('http://localhost:8000/submit-job/'+embedId);
if (resp.status === 202) {
setTaskId(resp.data.task_id)
console.log(resp.data);
alert("Job Submision Success..")
console.log("Job Submitted Successfully...")
} else {
alert("Job Submision Failed... \nCheck If the Video URL Is Correct")
}
} catch (err) {
// Handle Error Here
console.error(err);
}
};
Front End Check Job Status Function
const checkJobStatusTime = async () => {
let refreshId = null
try {
const refreshId = setInterval(async () => {
const resp = await axios.get('http://localhost:8000/get-result/'+taskId);
if (resp.status === 200 && resp.data.status === 'success') {
const resl = resp.data.result;
console.log(resl)
setData(resl);
alert("Data Retrieved Successfully...")
clearInterval(refreshId);
}
else if(resp.status === 200 && resp.data.status === 'not_found') {
clearInterval(refreshId);
} else {
console.log("Job Still Runing...")
}
}, 3000);
} catch(e) {
console.log(e);
clearInterval(refreshId);
}
}
In the Flask Back End, I have 2 Functions corresponds to the 2 Front End Functions
Backend Handle Job Submit Function
#app.route('/submit-job/<video_id>')
#cross_origin(origin='*', headers=['Content-Type', 'Authorization'])
def handle_submit(video_id):
job_id = id_generator()
executor.submit_stored(job_id, test_func, video_id)
return jsonify({'status': 'success', 'task_id': job_id, 'message': 'Job Submitted Successfully'}), 202
Backend Handle Check Job Status Function
#app.route('/get-result/<task_id>')
#cross_origin(origin='*', headers=['Content-Type', 'Authorization'])
def get_result(task_id):
if task_id in executor.futures._futures.keys():
if executor.futures.done(task_id):
future = executor.futures.pop(task_id)
return jsonify({'status': 'success',
'message': 'Job Completed Successfully',
'result': future.result()}), 200
else:
return jsonify({'status': executor.futures._state(task_id),
'message': 'Job Still Running',
'result': None}), 200
else:
return jsonify({'status': 'not_found',
'message': 'Task Id Cannot be Found.',
'result': None}), 200
Import 'cross_origin'
from flask_cors import cross_origin
PROBLEM:
When I Assigned the 2 Functions to the 2 Buttons Separately Everything works fine As Expected. However, If I try to call the Check status Function with the Job submit Function Like this,
const sendSubmitRequest = async () => {
try {
const resp = await axios.get(endPoint+'/youtube/submit-job/'+embedId);
if (resp.status === 202) {
setTaskId(resp.data.task_id);
console.log("Job Submitted Successfully...")
// Calling the Status Check Function
checkJobStatusTime();
} else {
alert("Job Submision Failed... \nCheck If the Video URL Is Correct")
}
} catch (err) {
// Handle Error Here
console.error(err);
}
};
This gives the CORs error.
Access to XMLHttpRequest at 'http://localhost:8000/get-result/' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Can someone help me figure out why this is Happening?
Try to use the #cross_origin decorator without any arguments.
As it's written in the Documentation:
In the simplest case, simply use the default parameters to allow all origins in what is the most permissive configuration
Also headers is not a valid parameter for this decorator.
You might want to use allow_headers.
I'm a beginner at ASK development and currently stuck on playing audio from multiple different URLs using .addAudioPlayerPlayDirective from handlerInput.responseBuilder. So if I add multiple addAudioPlayerPlayDirective to the responseBuilder it returns error instead. For example :
handlerInput.responseBuilder
.speak(speakOutput)
.addAudioPlayerPlayDirective('REPLACE_ALL', podcastBeginning.url, podcastBeginning.token, 0, null, podcastBeginning.metadata)
.addAudioPlayerPlayDirective('REPLACE_ALL', podcastBeginning.url, podcastBeginning.token, 0, null, podcastBeginning.metadata);
Also, I added the method of the issue below.
const LatestHeadlinesIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest' ||
handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
(
handlerInput.requestEnvelope.request.intent.name === 'LatestHeadlinesIntent' ||
handlerInput.requestEnvelope.request.intent.name === 'AMAZON.ResumeIntent' ||
handlerInput.requestEnvelope.request.intent.name === 'AMAZON.LoopOnIntent' ||
handlerInput.requestEnvelope.request.intent.name === 'AMAZON.NextIntent' ||
handlerInput.requestEnvelope.request.intent.name === 'AMAZON.PreviousIntent' ||
handlerInput.requestEnvelope.request.intent.name === 'AMAZON.RepeatIntent' ||
handlerInput.requestEnvelope.request.intent.name === 'AMAZON.ShuffleOnIntent' ||
handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StartOverIntent'
);
},
async handle(handlerInput) {
const response = await httpGet();
let responseBuilder = handlerInput.responseBuilder;
let speakOutput;
let podcastBeginning = audio[0];
let podcastNext = audio[1];
let podcastEnd = audio[2];
let audioCount = 0;
let podcast = {
"token": response.audios[audioCount].intId,
"url": response.audios[audioCount].url,
"metadata" : {
"title": response.audios[audioCount].title,
}
}
if (sucessfulGet === true){
speakOutput = 'Alright, reading you the latest headlines!';
handlerInput.responseBuilder
.speak(speakOutput)
.addAudioPlayerPlayDirective('REPLACE_ALL', podcastBeginning.url, podcastBeginning.token, 0, null, podcastBeginning.metadata)
}else {
speakOutput = "No stories found. Response Code: " + responseCode;
}
return handlerInput.responseBuilder
.getResponse();
}
};
Any help would be appreciated. Thanks.
The AudioPlayer interface can help you achieve this functionality. It provides directives and requests (i.e next, previous, pause) for streaming audio and monitoring playback progression. For more information :
https://developer.amazon.com/en-US/docs/alexa/custom-skills/audioplayer-interface-reference.html
Also there is a an Alexa skill sample (https://github.com/alexa-samples/skill-sample-nodejs-multistream-audio-player/blob/main/lambda/index.js) which handles multiple audio files. The audio data is contained in an array found in /lambda/constants and imported into /lambda/index.js, which contains the logic to handle requests to manage the audio (play, pause, play next, etc) from your skill.
Please also note that each audio item URL must meet the following requirements listed here: https://developer.amazon.com/en-US/docs/alexa/custom-skills/audioplayer-interface-reference.html#audio-stream-requirements
Well, I followed "The Source Code" "discord.js" tutorial, (even copy-pasted his code from GitHub) but the ban and kick commands he's shown don't work, I assume they got broken by a recent update. It sends the embed to the incidents channel but doesn't actually ban the player. Also, if you have any suggestions for me to change things, please suggest!
if (cmd === `${prefix}ban`) {
let bUser = message.guild.member(message.mentions.users.first() || message.guild.members.get(args[0]));
if (!bUser) return message.channel.send("Can't find user!");
let bReason = args.join(" ").slice(22);
if (!message.member.hasPermission("MANAGE_MEMBERS")) return message.channel.send("No can do pal!");
if (bUser.hasPermission("MANAGE_MESSAGES")) return message.channel.send("That person can't be banned!");
let banEmbed = new Discord.RichEmbed()
.setDescription("Ban Management")
.setColor("#bc0000")
.addField("Banned User", `${bUser} with ID ${bUser.id}`)
.addField("Banned By", `<#${message.author.id}> with ID ${message.author.id}`)
.addField("Banned In", message.channel)
.addField("Time", message.createdAt)
.addField("Reason", bReason);
let incidentchannel = message.guild.channels.find(`name`, "incidents");
if (!incidentchannel) return message.channel.send("Can't find incidents channel.");
message.guild.member(bUser).ban(bReason);
message.delete().catch(O_o => {});
incidentchannel.send(banEmbed);
return;
}
message.guild.member(bUser).ban(bReason);
This will not ban the member. The message has a member property so you don't need to use message.guild.member you can just easily use message.member.
So it should look like this:
if (cmd === `${prefix}ban`) {
let bUser = message.guild.member(message.mentions.members.first() || message.guild.members.get(args[0]));
if (!bUser) return message.channel.send("Can't find user!");
let bReason = args.join(" ").slice(22);
if (!message.member.hasPermission("MANAGE_MEMBERS")) return message.channel.send("No can do pal!");
if (bUser.hasPermission("MANAGE_MESSAGES")) return message.channel.send("That person can't be banned!");
let banEmbed = new Discord.RichEmbed()
.setDescription("Ban Management")
.setColor("#bc0000")
.addField("Banned User", `${bUser.user.tag} with ID ${bUser.id}`)
.addField("Banned By", `<#${message.author.id}> with ID ${message.author.id}`)
.addField("Banned In", message.channel.name)
.addField("Time", message.createdAt)
.addField("Reason", bReason);
let incidentchannel = message.guild.channels.find(`name`, "incidents");
if (!incidentchannel) return message.channel.send("Can't find incidents channel.");
message.guild.member(bUser).ban({
reason: bReason
});
message.delete();
incidentchannel.send({
embed: banEmbed
});
return;
}
I changed a lot because a lot was outdated and could not work. It could be that I haven't seen one or the other mistake.
Let me know if it worked! :)
Best regards,
Monkeyyy11
This seems awfully complicated, I hope my command can make things a bit easier!
bot.on('message', message => {
const arguments = message.content.slice(prefix.length).trim().split(/ +/g);
const commandName = arguments.shift().toLowerCase();
if (message.content.startsWith(prefix) && commandName == "kick") {
if(!message.member.hasPermission("KICK_MEMBERS")) return message.channel.send("Permissions invalid");
const userKick = message.mentions.users.first();
if (userKick) {
var member = message.guild.member(userKick);
if (member) {
member.kick({
reason: `This person was kicked using a bot's moderation system. We are so sorry if this caused problems.`
}).then(() => {
message.reply(`A user been kicked.`)
})
} else {
message.reply(`User not found`);
}
} else {
message.reply(`Please enter a name`)
}}})
bot.on('message', message => {
const arguments = message.content.slice(prefix.length).trim().split(/ +/g);
const commandName = arguments.shift().toLowerCase();
if (message.content.startsWith(prefix) && commandName == "ban") {
if(!message.member.hasPermission("BAN_MEMBERS")) return message.channel.send("Permissions invalid");
const userBan = message.mentions.users.first();
if (userBan) {
var member = message.guild.member(userBan);
if (member) {
member.ban({
reason: `This person was banned using a bot's moderation system. We are so sorry if this caused problems.`
}).then(() => {
message.reply(`a user has been banned!`)
})
} else {
message.reply(`User not found`);
}
} else {
message.reply(`Please enter a name`)
}}})
If you use discord.js v12 or higher, then RichEmbed is now deprecated. Instead, use MessageEmbed