In Alexa, how do I define slot defaults in my Intent code? - go

I have one intent in my lambda function. I am trying to fill 4 slots, 3 of which are required. In my tests it seems like I have to set the Assignee field to a default or something fails in my actual handler which happens after the else statement below. Here's how I'm currently defining the defaults:
if strings.ToUpper(request.DialogState) == "STARTED" {
log.Println("DialogState == STARTED")
// Pre-fill slots: update the intent object with slot values for which
// you have defaults, then return Dialog.Delegate with this updated intent
// in the updatedIntent property.
slots := make(map[string]alexa.IntentSlot)
slots["Summary"] = alexa.IntentSlot{
Name: "Summary",
Value: "",
ConfirmationStatus: "NONE",
}
slots["TicketType"] = alexa.IntentSlot{
Name: "TicketType",
Value: "",
ConfirmationStatus: "NONE",
}
slots["Project"] = alexa.IntentSlot{
Name: "Project",
Value: "",
ConfirmationStatus: "NONE",
}
slots["Assignee"] = alexa.IntentSlot{
Name: "Assignee",
Value: "tcheek",
ConfirmationStatus: "NONE",
}
i := &alexa.Intent{
Name: "OpenTicketIntent",
ConfirmationStatus: "NONE",
Slots: slots,
}
response.AddDialogDirective("Dialog.Delegate", "", "", i)
response.ShouldSessionEnd = false
log.Println("DialogState has exited STARTED")
} else if strings.ToUpper(request.DialogState) != "COMPLETED" {
log.Println("DialogState == IN PROGRESS")
// return a Dialog.Delegate directive with no updatedIntent property.
response.ShouldSessionEnd = false
response.AddDialogDirective("Dialog.Delegate", "", "", nil)
log.Println("DialogState has exited IN PROGRESS")
} else {
I have also tried setting just the Assignee field as a default, like this:
slots := make(map[string]alexa.IntentSlot)
slots["Assignee"] = alexa.IntentSlot{
Name: "Assignee",
Value: "tcheek",
ConfirmationStatus: "NONE",
}
i := &alexa.Intent{
Name: "OpenTicketIntent",
ConfirmationStatus: "NONE",
Slots: slots,
}
response.AddDialogDirective("Dialog.Delegate", "", "", i)
In this scenario I get the following lambda function response in the simulator:
{
"body": {
"version": "1.0",
"response": {
"directives": [
{
"type": "Dialog.Delegate",
"updatedIntent": {
"name": "OpenTicketIntent",
"confirmationStatus": "NONE",
"slots": {
"Assignee": {
"name": "Assignee",
"value": "tcheek",
"confirmationStatus": "NONE"
}
}
}
}
],
"shouldEndSession": false
}
}
}
The problem is that once I ask it to open a bug ticket (which maps to the intent with the "Open a {ticketType} ticket" utterance), it gives the response that "There was a problem with the requested skill's response".
Am I wrong to think that setting defaults is necessary? Am I setting defaults incorrectly?

As per my knowledge in response, u need to include all slots. As here the intent name and slots match then only you'll get the correct response

Related

How to restructure data

I have a data of this format.
type PartsInfo struct {
Parts map[string]struct {
City string `yaml:"city"`
Services map[string]struct {
Disabled bool `yaml:"disabled"`
} `yaml:"services"`
} `yaml:"parts"`
}
I want to convert it into this format:
map[service]map[city][]parts where only not disabled status services need to be added. I have been trying different combinations but cant get it just the way i want.
I guess one thing I am not sure of is the destination format. Should I be using the map[service]map[city][]parts format, or would a struct be better ? I do not see how, but I have been told before the best way to pass data in go is using structs, not maps. Is that correct?
Is this what you want?
Go Playground: https://play.golang.org/p/N8mkD5pt1pD
package main
import "fmt"
type PartitionData struct {
Partitions map[string]Partition `yaml:"parts"`
}
type Partition struct {
City string `yaml:"city"`
Services map[string]map[string]struct {
Disabled bool `yaml:"disabled"`
} `yaml:"services"`
}
var testData = PartitionData{
Partitions: map[string]Partition{
"partition1": {City: "c1", Services: map[string]map[string]struct{
Disabled bool `yaml:"disabled"`
}{
"service1":{
"1":{
Disabled: true,
},
"2":{
Disabled: true,
},
},
"service2":{
"1":{
Disabled: true,
},
"2":{
Disabled: true,
},
},
}},
"partition2": {City: "c1", Services: map[string]map[string]struct{
Disabled bool `yaml:"disabled"`
}{
"service1":{
"1":{
Disabled: true,
},
"2":{
Disabled: true,
},
},
"service2":{
"1":{
Disabled: true,
},
"2":{
Disabled: true,
},
},
}},
},
}
func main() {
res:= make(map[string]map[string][]Partition)
for _,part := range testData.Partitions{
for serviceName :=range part.Services{
if _,found := res[serviceName];!found {
res[serviceName] = make(map[string][]Partition)
}
if _,found := res[serviceName][part.City];!found {
res[serviceName][part.City] = make([]Partition,0)
}
res[serviceName][part.City] = append(res[serviceName][part.City], part)
}
}
fmt.Println(res)
}

Expressing a complex structure in Terraform and reading it in Go

Note: edited after a comment from #JimB
I am trying to build a new Terraform provider in Go. The resource that I need is a bit complex. It includes structures, arrays within structures, arrays and structures within arrays. When I run Terraform, it gives me errors, for example:
panic: Error reading level config: '' expected type 'string', got unconvertible type 'map[string]interface {}'. I can't figure out what I am doing wrong.
When I make the structures simple enough, they do work, but I need this resource and I'm sure there's a way to do it, and I'm just missing something perhaps trivial.
-- Here's the Terraform structure:
resource "struct" "my-struct-1" {
name = "MyFile"
complexstruct = [{
onebool = true
onearray = [{
name = "name-1"
value = "value-1"
}, {
name = "name-2"
value = "value-2"
}]
internalstruct = [{
attr1 = false
attr2 = "attribute"
}]
}]
array = [
{
attrib1 = "attrib1.1"
attrib2 = false
attrib3 = "attrib1.3"
},
{
attrib1 = "attrib2.1"
attrib2 = true
attrib3 = "attrib2.3"
}
]
}
-- Here is the Schema definition in go, as simplified as I could make it:
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"complexstruct": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"onebool": {
Type: schema.TypeBool,
Optional: true,
},
"onearray": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
},
"value": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
"internalstruct": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"attr1": {
Type: schema.TypeBool,
Optional: true,
},
"attr2": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
},
},
"array": {
Type: schema.TypeList,
Optional: true,
Elem: map[string]*schema.Schema{
"attrib1": {
Type: schema.TypeString,
Optional: true,
},
"attrib2": {
Type: schema.TypeBool,
Optional: true,
},
"attrib3": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
----- And lastly, here's the code that I am trying to use (however, I think the problem is before it starts with the code itself):
fname := d.Get("name").(string)
d.SetId(fname)
if _, ok := d.GetOk("complexstruct"); ok {
fc := d.Get("complexstruct").([]map[string]interface{})
myBool := fc[0]["onebool"].(bool)
myArray := fc[0]["onearray"].([]map[string]interface{})
type fcS struct {
Name string `json:"name"`
Value string `json:"value"`
}
fcs := make([]fcS, len(myArray))
for ifc := range myArray {
fcs[ifc].Name = myArray[ifc]["name"].(string)
fcs[ifc].Value = myArray[ifc]["value"].(string)
}
myInternalStruct := fc[0]["internalstruct"].([]map[string]interface{})
type misS struct {
Attr1 bool `json:"attr1"`
Attr2 string `json:"attr2"'`
}
var mis misS
mis.Attr1 = myInternalStruct[0]["attr1"].(bool)
mis.Attr2 = myInternalStruct[0]["attr2"].(string)
type myWholeStruct struct {
MyBool bool `json:"onebool"`
MyArray []fcS `json:"onearray"`
MyInter misS `json:"internalstruct"`
}
outp := myWholeStruct{
myBool,
fcs,
mis,
}
o, _ := json.Marshal(outp)
writeStringToFile(string(o), fname, false)
}
Well, I expect the create function to create a file with the name taken from the name attribute, and the data a JSON representation of the values of the other Terraform attributes. Instead I am getting errors as specified above.

loopback REST API filter by nested data

I would like to filter from REST API by nested data. For example this object:
[
{
"name": "Handmade Soft Fish",
"tags": "Rubber, Rubber, Salad",
"categories": [
{
"name": "women",
"id": 2,
"parent_id": 0,
"permalink": "/women"
},
{
"name": "kids",
"id": 3,
"parent_id": 0,
"permalink": "/kids"
}
]
},
{
"name": "Tasty Rubber Soap",
"tags": "Granite, Granite, Chair",
"categories": [
{
"name": "kids",
"id": 3,
"parent_id": 0,
"permalink": "/kids"
}
]
}
]
is comming by GET /api/products?filter[include]=categories
and i would like to get only products which has category name "women". How do this?
LoopBack does not support filters based on related models.
This is a limitation that we have never had bandwidth to solve, unfortunately :(
For more details, see the discussion and linked issues here:
Filter on level 2 properties: https://github.com/strongloop/loopback/issues/517
Filter by properties of related models (use SQL JOIN in queries): https://github.com/strongloop/loopback/issues/683
Maybe you want to get this data by the Category REST API. For example:
GET /api/categories?filter[include]=products&filter[where][name]=woman
The result will be a category object with all products related. To this, will be necessary declare this relation on the models.
Try like this.It has worked for me.
const filter = {
where: {
'categories.name': {
inq: ['women']**strong text**
}
}
};
Pass this filter to request as path parameters and the request would be like bellow
GET /api/categoriesfilter=%7B%22where%22:%7B%categories.name%22:%7B%22inq%22:%5B%women%22%5D%7D%7D%7D
Can you share how it looks like without filter[include]=categorie, please ?
[edit]
after a few questions in comment, I'd build a remote method : in common/models/myModel.js (inside the function) :
function getItems(filter, categorieIds = []) {
return new Promise((resolve, reject) => {
let newInclude;
if (filter.hasOwnProperty(include)){
if (Array.isArray(filter.include)) {
newInclude = [].concat(filter.include, "categories")
}else{
if (filter.include.length > 0) {
newInclude = [].concat(filter.include, "categories");
}else{
newInclude = "categories";
}
}
}else{
newInclude = "categories";
}
myModel.find(Object.assign({}, filter, {include: newInclude}))
.then(data => {
if (data.length <= 0) return resolve(data);
if (categoriesIds.length <= 0) return resolve(data);
// there goes your specific filter on categories
const tmp = data.filter(
item => item.categories.findIndex(
categorie => categorieIds.indexOf(categorie.id) > -1
) > -1
);
return resolve(tmp);
})
}
}
myModel.remoteMethod('getItems', {
accepts: [{
arg: "filter",
type: "object",
required: true
}, {
arg: "categorieIds",
type: "array",
required: true
}],
returns: {arg: 'getItems', type: 'array'}
});
I hope it answers your question...

Loopback : Validate model from another model is not returning proper error message

I am validating model from another model like below
Model.addFavorite = function (data, callbackFn) {
if (data) {
var faviroteModel = this.app.models.Favorite;
var objFavorite = new faviroteModel(data);
objFavorite.isValid(function (isValid) {
if (isValid) {
callbackFn(null, objFavorite);
}
else {
callbackFn(objFavorite.errors);
}
});
}
else callbackFn("Post data required", {});
}
If i do this then I am getting error like below
{
"error": {
"statusCode": 500,
"t": [
"is not a valid date"
]
}
}
It should be with error message like below
{
"error": {
"statusCode": 422,
"name": "ValidationError",
"message": "The `Favorite` instance is not valid. Details: `t` is not a valid date (value: Invalid Date).",
"details": {
"context": "Favorite",
"codes": {
"t": [
"date"
]
},
"messages": {
"t": [
"is not a valid date"
]
}
}
}
}
Can anyone tell me what am i missing here.
How can i achieve this.
https://github.com/strongloop/loopback-datasource-juggler/blob/master/lib/validations.js#L843
You might run into situations where you need to raise a validation
error yourself, for example in a "before" hook or a custom model
method.
if (model.isValid()) {
return callback(null, { success: true });
}
// This line shows how to create a ValidationError
var err = new MyModel.ValidationError(model);
callback(err);
}

Variable mirroring other ones

So I have created a simple chat bot, and I'm having trouble with one of it's commands, /resetall. It is supposed to change every users values to the values of the user "default". However, it seems that default is causing all values to change by 2.
"data": {
"user": {
"bob": {
"admin": "true",
"consecutiveCommands": "0",
"nickname": "",
"sentMessages": "2"
},
"default": {
"admin": "true",
"consecutiveCommands": "0",
"nickname": "",
"sentMessages": "2"
},
"me": {
"admin": "true",
"consecutiveCommands": "0",
"nickname": "",
"sentMessages": "2"
},
"total": {
"admin": "true",
"consecutiveCommands": "0",
"nickname": "",
"sentMessages": "2"
}
},
"chat": {
"commandSender": "me",
"lastImage": "",
"lastMessage": "/pong",
"lastSender": "me",
"lastTimestamp": "11:59",
"wasCommand": "true"
}
}
and my go code:
// each incoming message
type Message struct {
Message string
From string
Chat string
Timestamp string
IsCommand bool
}
//adds one to a string
func addOne(s string) string {
i, _ := strconv.Atoi(s)
return strconv.Itoa(i + 1)
}
//counts messages sent
func messageCounter(data map[string]Chat, event *Message) map[string]Chat {
//counts messages sent by user
data[event.Chat].Data.User[event.From]["sentMessages"] = addOne(data[event.Chat].Data.User[event.From]["sentMessages"])
data[event.Chat].Data.User["total"]["sentMessages"] = addOne(data[event.Chat].Data.User["total"]["sentMessages"])
return data
}
//sets variables for future use / other functions
func eventRecorder(data map[string]Chat, event *Message) map[string]Chat {
if !event.IsCommand {
data[event.Chat].Data.Chat["lastMessage"] = event.Message
data[event.Chat].Data.Chat["lastSender"] = event.From
data[event.Chat].Data.Chat["lastTimestamp"] = event.Timestamp
data[event.Chat].Data.Chat["wasCommand"] = "false"
} else {
data[event.Chat].Data.Chat["wasCommand"] = "true"
data[event.Chat].Data.Chat["commandSender"] = event.From
}
return data
}
//supposed to set all users data to the default user
func resetall(event *Message, data map[string]Chat) (error, map[string]Chat) {
default_user := data[event.Chat].Data.User["default"]
if data[event.Chat].Data.User[event.From]["admin"] == "true" {
for user, _ := range data[event.Chat].Data.User {
if user != "default" {
data[event.Chat].Data.User[user] = default_user
print(user + "\n")
}
}
return nil, data
}
return errors.New("don't have permission")), data
}
func main() {
processingFuncs := []func(map[string]Chat, *Message) map[string]Chat{
messageCounter,
eventRecorder,
}
data, _ := readsettings() //reads the data from a json file
event := &Message{"/resetall", "me", "chat123", "11:59", false}
if strings.Split(event.Message, " ")[0] == "/resetall" {
event.IsCommand = true
_, data = resetall(event, data)
fmt.Println("success")
}
for _, processingFunc := range processingFuncs {
processingFunc(data, event)
}
writesettings(data) //writes the data to a json file
}
So if I set everyone's message counter to 0 and run it, it sets every single user's message counter to 2 (including default). Each time I run it, the value increases by 2. Can anyone help explain why this is happening
this line to copy the user
data[event.Chat].Data.User[user] = default_user
made a reference to it, I don't know why I didn't spot it earlier. I replaced it with this code
for k, v := range data[event.Chat].Data.User["default"] {
data[event.Chat].Data.User[user][k] = v
}
and it worked perfectly.

Resources