I am currently building a custom skill for Alexa in Java.
I want Alexa to set an appointment using an existing Exchange Server.
For the appointment I want Alexa to check wether a name, a date and a time are given by the user. I do so using if-statements like:
if(date.getValue() == null) {
return askResponse("Please give a date in order to create an appointment")
What happens is Alexa asks for the missing slot but when I answer the skill just quits. I don't know how to have Alexa recognize my response.
Code is as follows:
public SpeechletResponse getTerminResponse(Slot name, Slot date, Slot time, Session session, IntentRequest request) throws Exception {
if(time.getValue() == null) {
return askResponse("Please insert time");
} else if (date.getValue() == null) {
return askResponse("Please insert date");
} else if (name.getValue() == null) {
return askResponse("Please insert name");
} else {
try {
String[] datumArray = date.getValue().split("-");
String[] zeitArray = time.getValue().split(":");
Date startDate = new Date((Integer.parseInt(datumArray[0])-1900), (Integer.parseInt(datumArray[1])-1), (Integer.parseInt(datumArray[2])), (Integer.parseInt(zeitArray[0])), (Integer.parseInt(zeitArray[1])), 0);
Date endDate = new Date((Integer.parseInt(datumArray[0])-1900), (Integer.parseInt(datumArray[1])-1), (Integer.parseInt(datumArray[2])), (Integer.parseInt(zeitArray[0]))+1, (Integer.parseInt(zeitArray[1])), 0);
System.out.println(startDatum.toString());
System.out.println(endDatum.toString());
ExchangeHelper eh = new ExchangeHelper();
eh.createMeeting(name.getValue(), "Test", startDate, endDate);
return getTellSpeechletResponse("Appointment created successfully");
} catch (Exception e) {
System.out.println(e);
return askResponse("Failed to create appointment");
}
}
}
Here is my Interaction Model
Any help would be highly appreciated since I have been researching documentations and examples for days and I just can not get it to work.
Best regards
Can you give the code for getTellSpeechletResponse?
According to the picture you attached you are using the "new" Dialog model so that Amazon collect all the slots for you intent.
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/dialog-interface-reference#directives
Most probably you forgot to send back the DelegateDirective (via speechletResponse.setDirectives(...)) to amazon to tell Alexa to take care for collecting the slot values. But this only can be answered if you send the code. I would also like to see an Dialog Java example by amazon but haven't found yet.
If you are using this dialog model you also don't need the if elses as alexa recognize itself which slots are missing. You have to mark this "Is this slot required to fulfill the intent" with yes in the interaction model. Than you also don't need to create own ask responses but just to give utterances in interaction model for your 4 slots.
Related
I am using the latest Java Realm local database backing a mobile app.
I have a Profile class and a Contact class in the app. Each Profile object can be associated with one or more Contact objects.
Upon startup, I want to reconcile against a similar Profile/Contact list on my website to insure that the mobile app is using the latest/greatest definition of the Profile/Contact relationship.
After validating the Profile during login, I then query the website to get the list of Contact email addresses associated with the Profile. I now need to do the following:
For each Contact email address in the list from the website, make sure that the local Realm Contact object shows as "connected" to the Profile object.
For each Contact object NOT in the list from the website, make sure that the local Realm Contact object shows as "not connected" to the Profile object.
So what I'm doing is after login, executing an AsyncTask that:
try {
realm.beginTransaction();
RealmResults<Contact> contactResults;
contactResults = realm.where(Contact.class).findAll();
if ( contactResults.size() == 0 ) {
// Nothing to do
return false;
}
// First set everything as not connected, then set only those passed in as connected
contactResults.setBoolean(IS_CONNECTED, false);
// Now update just the email addresses passed in as connected
contactResults = realm.where(Contact.class).in(EMAIL_ADDRESS, emailList.toArray(new String[0])).findAll();
if ( contactResults.size() > 0) {
contactResults.setBoolean(IS_CONNECTED, true);
}
//TODO - what if an item passed in is not yet in Contact list?
success = true;
} catch (Exception e) {
Timber.d("Exception resetting contacts status: %s", e.getMessage());
} finally {
if (success) {
realm.commitTransaction();
} else {
realm.cancelTransaction();
}
}
How I've done the first two pieces of work seem ok to me - as this app won't be scaling to thousands of "friends", resetting the contact to FALSE for everyone then to TRUE for the current set retrieved from the website is doable.
However, the third piece has me stumped - is there a single call I can make to identify which, if any, of the email addresses in the passed array aren't actually in my Contact object RealmResults and therefore need to be added as new objects?
Seems inefficient to loop through that list and check each one, one at a time, particularly since I've already performed two queries.
The only solution I've come up with so far is this:
try {
realm.beginTransaction();
fullContactResults = realm.where(Contact.class).findAll();
if ( fullContactResults.size() > 0 ) {
// First set everything as not connected, then set only those passed in as connected
fullContactResults.setBoolean(IS_CONNECTED, false);
}
// Now for each item in the list we were passed in find it and update it, or add it.
for ( String data : contactData ) {
Contact c = null;
String[] contactStruct = data.split(BODY_COMPONENTS_SEPARATOR);
RealmResults<Contact> partialContactResults = realm.where(Contact.class)
.equalTo(EMAIL_ADDRESS, contactStruct[CONNECTION_EMAIL_ELE])
.findAll();
if (partialContactResults.size() > 0 ) {
c = partialContactResults.first();
} else {
// Need to add the contact
c = realm.createObject(Contact.class, UUID.randomUUID().toString());
}
c.setConnected(true);
c.setDisplayName(contactStruct[CONNECTION_FIRSTNAME_ELE] + " " + contactStruct[CONNECTION_LASTNAME_ELE]);
c.setEmailAddress(contactStruct[CONNECTION_EMAIL_ELE]);
}
success = true;
} catch (Exception e) {
Timber.d("Exception resetting contacts status: %s", e.getMessage());
} finally {
if (success) {
realm.commitTransaction();
} else {
realm.cancelTransaction();
}
}
Which does a loop and either updates or inserts.
Any better way?
I am doing a notification on my app and I am using firestore. My problem is I want to send a notification to the user when the snapshotlistener detect a newly added data to the database But when I open the app it will show the existing notification right away even though i did not added a new data. I need some conditions where I can only get the newly added data or if there's something lacking in my database data that will need in order to overcome this issue. Below is my databse structure.
db.collection("Buyers")
.document(userID)
.collection("Notifications")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot snapshots, #Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.e(LOG_DB, e.toString());
return;
}
for (DocumentChange dc : snapshots.getDocumentChanges()) {
if (dc.getType() == DocumentChange.Type.ADDED) {
String title = dc.getDocument().getData().get("notificationTitle").toString();
String body = dc.getDocument().getData().get("notificationBody").toString();
//Method to set Notifications
getNotification(title, body);
}
}
}
});
If you just want to send notifications, you can use Firebase Cloud Messages which may provide the functionality you are trying to implement yourself.
https://firebase.google.com/docs/cloud-messaging
If you want to send a Notification after data is changed in your Firestore you can use FireStore Triggers (https://firebase.google.com/docs/functions/firestore-events) and send a Notification via a firebase function call (Send push notifications using Cloud Functions for Firebase)
I had a similar issue and this is how I solved it:
Get a count of your current items added and save in Shared Preferences
Upon opening the app get the current count of items and compare with the saved number in shared preferences
Set a condition where if the current count of item is more than the saved number in shared preferences, the notification is called.
I am able to get what I want but I am not sure if this is the right way to do this.
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, -5);
Date before = calendar.getTime();
Calendar calendar1 = Calendar.getInstance();
Date until = calendar1.getTime();
for (DocumentChange dc : snapshots.getDocumentChanges()) {
Date date = (Date) dc.getDocument().getData().get("notificationDate");
if (dc.getType() == DocumentChange.Type.ADDED) {
if (!before.after(date) && !until.before(date)){
Log.d("life", "Data: "+date);
String title = dc.getDocument().getData().get("notificationTitle").toString();
String body = dc.getDocument().getData().get("notificationBody").toString();
getNotification(title, body);
}
}
}
What i have done here was I retrieve the current and the current time minus 5 mins.(You can choose how many delayed the mins you want) then made a condition where it must only show the notifications within the 5mins delayed date.
Note:
I know this was not the proper practice but this gets the result that I want. If you didn't want my answer please let me know and post your own answer so I can acknowledge your answer.
I am building a custom Alexa skill
In which I can ask the name of User and repeat it. (Working fine).
Now, the next part is to confirm the name of the user.
Alexa: "Please confirm your name!"<br>
User:"-"
Alexa: "Please confirm your name!"<br>
User: "No"
Alexa: "Please confirm your name!"<br>
**User: "Yes I confirm"**
End.
Now I am trying to achieve the above behaviour, as
Alexa should prompt "Please confirm your name!" on every 10 seconds until the user Responds
"Yes, I confirm".
I have checked the API documentation but not able to find any Intent related to this case.
Please share some info or solution.
Repromting every 10 seconds when the user doesn't responds, not sure if we can do.
But we can achieve the Yes/No part. One way of doing this is by using the state. Here in this example, I am using the node-cache module for state management.
Consider the below intent named "ConfirmationQuestionIntent". It sets the state to "confirm-name".
const ConfirmationQuestionIntentHandler = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === "IntentRequest" &&
handlerInput.requestEnvelope.request.intent.name === "ConfirmationQuestionIntent"
);
},
handle(handlerInput) {
const speechText = "Please confirm your name as 'John'.";
myCache.set('state','confirm-name');
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.getResponse();
}
};
Now, enable/Add two BuiltIn intents, AMAZON.YesIntent and AMAZON.NoIntent.
Consider the AMAZON.NoIntent below,
In the handler function. it checks if there is any state with the name "confirm-name". If it is present, it responds with "Please confirm your name as 'John'." and if not then responds with the default response.
const NoBuiltInIntent = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === "IntentRequest" &&
handlerInput.requestEnvelope.request.intent.name === "AMAZON.NoIntent"
);
},
handle(handlerInput) {
const state = myCache.get("state");
let speechText = "I didn't get this!. Could you please rephrase.";
if(state === "confirm-name") speechText = "Please confirm your name as 'John'.";
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.getResponse();
}
};
Consider the AMAZON.YesIntent below,
In the handle function, it checks if there is any state named "confirm-name". If it is, then it responds back with "Thanks for the confirmation" and deletes the state from the cache. If not then it asks the user to rephrase.
const YesBuiltInIntent = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === "IntentRequest" &&
handlerInput.requestEnvelope.request.intent.name === "AMAZON.YesIntent"
);
},
handle(handlerInput) {
const state = myCache.get("state");
let speechText = "I didn't get this!. Could you please rephrase.";
if(state === "confirm-name") speechText = "Thanks for the confirmation.";
myCache.del('state');
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.getResponse();
}
};
So, you can use "State" to identify in which scenario the user is responding to and then provide the right response.
I am afraid it is not possible to make Alexa ask the question every 10 seconds untill the user confirm.
I suppose you are using confirmSlotDirective to confirm the name of the user.
confirmSlotDirective or simply any confirmation directive in Alexa works with words that only agree or disagree with the confirmation message. e.g. YES/NO
Solution:
1) If you have already asked for the name of the user (e.g. 'John'), do not ask it again. Simply make Alexa to say:
Alexa: "Your name is John, right?" Or "You said John? please confirm?"
User: can say Yes/No to confirm.
Note: Alexa only recognizes a limited set of international names.
2) Better way to get user's name is using Alexa's Customer Profile Api, so you won't have to worry about Alexa not able to recognize name let alone the confirmation of user's name.
Hi i am trying to create meeting in lotus notes using java.i am able to send a meeting invite to the recipients.But when i send a meeting the options available to the chair and the recipients are the same.(options like accept,decline).But the options for the chair and the recipients should be different.can anyone please tell how to do this?
public DocumentKey save(final Session session, final Database db, boolean send,
String moveToFolder) throws NotesException, Io Exception {
//setBody(null);
Document doc = null;
RichTextItem rti = null;
try {
doc = db.createDocument();
db.getView(ServiceConstants.MEETINGS);
// Here i am setting all the properties for that document.
// I cant post that code as it has
// over 100 properties, so more than 100 lines of code
rti = doc.createRichTextItem(ServiceConstants.BODY);
rti.appendText(getBody());
if ((attachment != null) && (attachment.length > 0)) {
for (int i = 0; i < attachment.length; i++) {
attachment[i].save(rti);
}
}
doc.save(true, true, true);
if (send) {
doc.send();
}
if (!isBlank(moveToFolder)) {
doc.putInFolder(moveToFolder, true);
}
setKey(new DocumentKey(doc.getNoteID()));
} finally {
Helper.cleanupIfNeeded(rti);
Helper.cleanupIfNeeded(doc);
}
return getKey();
}
To successfully schedule a meeting, you need to follow the calendaring and scheduling schema
In short: A meeting has to be created in the chair's mail file and the invitations have to be responses (doc.MakeResponse(...)) to that main document and sent via mail. The "ApptUnid"- item ties them all together.
Read the documentation in the link, it is very good
If you are using Notes / Domino 9.0 or greater, you should consider using the lotus.domino.NotesCalendar interface and its related interfaces. These relatively new interfaces let you create, read and update calendar entries using iCalendar format.
Here's some sample code:
// Get the NotesCalendar object from the database
NotesCalendar notesCalendar = session.getCalendar(database);
if ( notesCalendar == null ) {
throw new Exception("Cannot open calendar.");
}
// Create a meeting in iCalendar format
String ical = iCalendarMeeting();
// Create the meeting on the Notes calendar
NotesCalendarEntry entry = notesCalendar.createEntry(ical);
This code creates an instance of NotesCalendar from an instance of Database. Then it gets the representation of a meeting in iCalendar format (the iCalendarMeeting method is not shown). Finally, it calls NotesCalendar.createEntry() to create the meeting. The createEntry method places the meeting on the organizer's calender and sends an invitation to all attendees.
I have written an Apex Scheduler class to send an email when a colleagues Birthday is 2 days away. I have created a contact with a birthday 2 days away. The contact's birthday is the July 29, 2012. Today's date is July 27, 2012.
I'm stuck. I don't get an error message or anything. I have scheduled the class to run today at 12. I didn't get an email (either telling me it was someone's birthday (success) or an error message from Salesforce telling me my code could not run (failure)
To trouble shoot, I also tried if (contact.Next_Birthday__c = : system.Today().addDays(2)) for the email method and got an incompatible types error. Next_Birthday__c is a date field, so I'm unsure of why the types are incompatible or why this SOQL statement doesn't work.
Any advice would be appreciated. Here is my code.
global class BirthdayNameOptions implements Schedulable{
global void execute (SchedulableContext ctx)
{
sendBirthdayEmail();
}
public void sendBirthdayEmail()
{
for(Contact con : [SELECT Name FROM Contact WHERE Next_Birthday__c = : system.Today().addDays(2)])
{
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setTemplateId('00XJ0000000M31w');
mail.setTargetObjectId('005J0000000');
mail.setSaveAsActivity(false);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail });
}
}
}
I believe you want to set the targetObjectId of your outbound email message to the Contact whose birthday it is, rather than hardcoding it...the value 005J0000000 in your code doesn't seem to be a valid ID either, which could be causing you to not receive the email. For testing purposes you'd want to make sure the Contact record's email is set to yours, so you receive the notification. Also, you only get 10 calls to Messaging.sendEmail() per execution, so I bulkified this a bit for you. Give this a shot:
global class BirthdayNameOptions implements Schedulable {
global void execute (SchedulableContext ctx) {
sendBirthdayEmail();
}
public void sendBirthdayEmail() {
List<Messaging.SingleEmailMessage> mails = new List<Messaging.SingleEmailMessage>();
for ( Contact con : [SELECT Id, Name FROM Contact WHERE Next_Birthday__c = : system.Today().addDays(2)] ) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setTemplateId('00XJ0000000M31w');
mail.setTargetObjectId(con.Id);
mail.setSaveAsActivity(false);
mails.add(mail);
}
if ( mails.size() > 0 )
Messaging.sendEmail(mails, false);
}
}