I have been using Watson Conversation for quite some time. Recently, with the news features, I started using the slot option. I would like to know if it is possible to stop a loop with a counter directly on the tooling. I can stop the loop using a diferent condition on manage handlers, but not with a counter.
Anyone knows how to do that on the the tooling?
So you are in the right area. You use the handlers.
1. Create a context variable called counter and set it to a value of 1. The reason for 1 is that setting it to 0 can make it invisible. Do this in the welcome part.
2. Create your slot. For the example, I am setting the condition as input.text == "go".
3. Set up your slots as normal. Again for the example, I look for $person and $date (#sys-person and #sys-date)
4. In the handler for the first response on "If answer to any prompt is not found and:" set the JSON to:
{
"conditions": "$counter > 3",
"output": {
"text": {
"values": [
"You have gotten the question wrong too many times."
],
"selection_policy": "sequential"
}
},
"context": {
"date": "cancel",
"person": "cancel",
"counter": 99
}
}
This will activate if the handler is hit 3 times. It will set counter to 99 (see later), set the wanted context variables to "cancel" so as to exit the slot.
5. The second response in the handler, set it to this JSON.
{
"output": {},
"context": {
"counter": "<? $counter = $counter + 1 ?>"
}
}
This is your increment for counter.
6. Back to the main part of the slot. In the "Then respond with:", set the condition to:
$date != "cancel" or $person != "cancel"
and set the response to display your values. At this point it should work. However if you try to enter the slot again it will fail. So lets build a handler for that.
7. Create a child node under your slot. Set your slot to "finally jump to" the condition block.
8. In your child node, set the condition to: $counter == 99. For your JSON response put in the following:
{
"context": {
"counter": 1,
"date": null,
"person": null
},
"output": {}
}
This resets the counter, and removes the slot variables. This allows you to re-enter the slot.
Here is an example conversation workspace: https://pastebin.com/caA2gb5u
To follow on from this (not in the example). You can use the individual slot handlers for each context variable to reset the counter in the same way.
Related
I am trying to build a step function that has a choice state based on a map in a result of a dynamo db map. An example result from my dynamo GetItem request would be.
{
"Item": {
"organisationId": {
"S": "Andys-test"
},
"id": {
"S": "Andy2"
},
"states": {
"L": [
{
"M": {
"year": {
"N": "2021"
},
"status": {
"S": "started"
}
}
},
{
"M": {
"year": {
"N": "2022"
},
"status": {
"S": "started"
}
}
}
]
},
},
My condition will be checking the status of the states map against the year 2021. I have attempted to use this JSONPath which from what I can tell is valid, although I am getting nothing in the data flow simulator in the step functions console. I have tried various iterations of the below, with quotes escaped quotes etc and can't get anything to parse the correct value out.
I have been doing this in the input selector as I can see that the result path does not support the [?()] notation.
$.Item.states.L..M[?(#.year.N == 2022) ]
Without an example choice state with some rules, it'll be hard to answer definitively but I think I'm following.
JSONPath with expression filters
I run into this sort of problem more often than I'd like when using JSONPath filter expressions and have to add "helper" tasks to get things moving (wasting valuable state transitions 😣 ).
When you specify a Path that includes a filter expression, the result is always going to be a list (and you won't be able to reference index afterwards either).
ChoiceRules don't really have a comparator that deals with arrays/lists (at least i haven't been able to get it to work, so let me know if you do 😄).
The hack I've found easiest to reason about/maintain is creating a simple Pass Task that "pops" the values I need from the filter expression and then pass that along to the Choice Task.
Here's an example from one of my previous answers (the pattern used in the PassDef task would be defined before your choice task in your scenario, instead of after)
I've found it easier to start with https://jsonpath.herokuapp.com then progress to the data flow simulator. Just remember to always keep in mind whether
you're trying implement a Path or a Reference Path!
I'm trying to use SCC to write some contracts before I rebuild the producer side (there are no existing tests!). The examples around lists and deeper data structures in the documents are a bit thin, so I want to understand if this is feasible, or perhaps I have to drop down to calling a command to make the right assertions.
I'm using the latest version v2.11
So -
Given:
An API that will return a list of objects in its payload. The length of the list will depending on the identity of the client, i.e. client A will get 3 items, client B will get 4 items. The identity of the client isn't of interest here.
When:
A client makes a GET request, passing a querystring parameter for item selection within the list of items
Then:
I want to write a contract that takes input from request and proves that the response contains a list of objects, and the item that matches the selector has a boolean field selected:true, while the rest of the items have selected:false. There's an edge where the selector is wrong and no item is selected.
E.g. For the request GET /someapi?id=bbb
Response
{ foo: xxxy, bar: 123, baz: [
{ id: 'aaa', selected: false, .... },
{ id: 'bbb', selected: true, .... },
{ id: 'ccc', selected: false, .... }
] }
Of course the selected item can be anywhere in the list. So I had in mind an assertion like this pseudo code -
jsonPath('$.baz[?(#.id == fromRequest().query("id"))].selected', byEquality( true ) )
But I can't do that fromRequest() stuff in the JSONPath statement. Right now I guess I could simply have the whole response body as the spec, but that seems unwieldy. If it must be, that's fine I guess.
Any ideas or help appreciated.
My question is : how to append a value given by a user to an entity. The user provided value is dynamic.
The Watson response overwrites the toppings variable with the value given by the user, as you can see in the attached image.
{
"output": {
"text": "I got an order to add one or more toppings.
Adding <?context.toppings.append('toppings')?>.
Toppings to provide: <?entities['toppings']?.toString()?>"
},
"context": {
"toppings": "<? entities['toppings']?.toString()?>"
}
}
You can append to an array with the .append() function.
In your example, the expression "toppings": "<? entities['toppings']?.toString()?>" will overwrite the toppings variable every time this node is processed with the actual recognized entities #toppings. First the the $toppings variable needs to be defined as an array, e.g.:
"context" : {
"toppings" : []
}
Then in context part of a dialog node you can write:
"context" : {
"toppings" : "<?$toppings.append(entities['toppings'].toJsonArray())?>"
}
More info in our doc: Watson Conversation Doc
EDIT: Thinking about this, it is probably not a good idea to have the same name for the entity and for the variable you store it in. :-)
I want to sort events with my json property called "displayOrder". but not on start time.
I have applied eventOrder:"displayOrder" still not sorting based on given input
this means event one should appear first.
here is json
{
"title": "Event two",
"start": "2015-10-01T10:30:00-05:00",
"end": "2015-10-02T17:30:00-05:00",
"displayOrder":"2",
"bookingsAvailable":true,
"description":"We can add description in JSON"
},
{
"title": "Event one",
"start": "2015-10-01T11:30:00-05:00",
"end": "2015-10-01T17:30:00-05:00",
"displayOrder":"1"
}
check image
You will requrie to modify compareSlotSegs(seg1, seg2) inside fullcalendar.js
function compareSlotSegs(seg1, seg2) {
return seg1.originalStart - seg2.originalStart || // earlier start time goes first
(seg2.originalEnd - seg2.originalStart) - (seg1.originalEnd - seg1.originalStart) ||
(seg1.event.displayOrder|| '').localeCompare(seg2.event.displayOrder);
}
compareSegs: function(seg1, seg2) {
return compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs)|| // events with display order
seg1.displayOrder -seg2.displayOrder || // earlier events go first
seg2.eventDurationMS - seg1.eventDurationMS || // tie? longer events go first
seg2.event.allDay - seg1.event.allDay // tie? put all-day events first (booleans cast to 0/1)
}
In the Firebase security rules file, could one effectively use the '.validate' directives to synchronize schema, that is, make sure when one part of the Firebase is modified, another part gets updated as well? Or is this a bad/invalid idea?
Basically what I'm trying to do is create a Todo list app. I want to be able to create tasks in my todo list with specified tags. For each tag in the app, there should be a respective tag child field in the "tags" field in my Firebase backend. The tag field should contain an ordered list of references to tasks in the "tasks" field. So, if a task is created with "#foo" tag, then it's name (id) should be referenced in "tasks/foo". Also, whenever a task is removed, it's reference in each tag should be removed, and when a tag in has no children it should be removed.
To clarify here's an example of the schema:
{
"tasks": {
"-sdjfaowneono": {
"headline": "Get some milk",
"completed": false,
"tags": {
"0": "all",
"1": "shopping"
}
},
"-asdfhsadfsafwirn": {
"headline": "Pick up the kids",
"completed": false,
"tags": {
"0": "all"
}
}
},
"tags": {
"all": {
"0": "-sdjfaowneono",
"1": "-asdfhsadfsafwirn"
},
"shopping": {
"0": "-sdjfaowneono"
}
}
}
Again, if task "-sdjfaowneono" was removed, so would the "shopping" tag be removed.
In conclusion, I need to synchronize the "tags" schema with the "tasks" schema in a specific way. Should I do this synchronization in the Security Rules? Or should I do this at the app level? And if I do it at the app level, there is a risk that the app bugs out and doesn't add/remove a tag which it should, so how do I overcome that?
To use this with security rules, you will need to change one or the other to use the tag id as the key, rather than an array value, since there is no way to specify a wild card or search multiple children to see if one contains the correct value.
So if you changed your "tags" path to look like this:
"tags": {
"all": {
"-sdjfaowneono": true,
"-asdfhsadfsafwirn": true
},
"shopping": {
"-sdjfaowneono": true
}
}
Then you could validate like this:
"tasks": {
"$task": {
"tags": {
"$tag": {
".validate": "root.child('tags/'+newData.val()+'/'+$task).exists()"
}
}
}
}
This uncovers a basic design practice that I've discovered while building with Firebase: I tend to prefer keys to values for storing any sort of foreign key reference.
Also, keep in mind that this only enforces that they match up on write. It does help with deletions since .validate will only run if the value exists.
You could enforce the same behavior on deletions by appending this to the write rule:
".write": " ... && (newData.exists() || !root.child('tags/'+newData.val()+'/'+$task).exists())"