Issue in giving plurals in Bixby dialogs - bixby

I had a question regarding plurals in dialog.
Let's say I have a structure
structure (MyStructure) {
property (MyConcept) {
type {EnumConcept} max (Many)
}
}
And a Value dialog for it:
dialog (Value) {
match: MyConcept(this)
if (this == 'ABC') {
switch(plural(this)) {
case (One) { template("single1") }
default { template ("plural1") }
}
}
if (this == 'DEF') {
switch(plural(this)) {
case (One) { template("single2") }
default { template ("plural2") }
}
}
}
By using
Code:
#{value(myStructure.myConcept.plural('Many'))}
I am able to get "plural1" or "plural2" when myStructure has below values and size of myConcept is 1:
myStructure = [
{ myConcept: ABC },
{ myConcept: ABC },
{ myConcept: ABC },
{ myConcept: ABC }
]
When size of myConcept is 2 and myStructure has below values,
myStructure = [
{ myConcept: ABC },
{ myConcept: ABC },
{ myConcept: DEF },
{ myConcept: DEF }
]
using the Code:
#{value(myStructure.myConcept.plural('Many'))}
is giving NLG as
"single1 and single2"
What I want in the NLG:
"plural1 and plural2"
Can someone please help us in giving proper plural NLG for each element of the unique "myConcept" present in the list of "myStructure"?
What I want is to apply plurality to each individual value of an array.
size(myStructure.myConcept) = 2.
I want to apply plural to both the values of myConcept.
I do not think in dialogs we have an for-each kind of thing available.

It's a little hard to tell what's going on in the code above. If this answer isn't helpful, consider sharing the full source code somewhere for live debugging.
You can try something like
#{value(myStructure.myConcept.plural(plural(myStructure.myConcept))}
The docs has an example like:
#{concept(restaurantStyle.plural(plural(restaurant)))}
Source: https://bixbydevelopers.com/dev/docs/reference/ref-topics/el-ref#node-evaluation-functions in the plural(node) section.

Related

GraphiQL on Orchard-Core: "where" and "filter" does not work

I am trying to understand how to query with GraphiQL on Orchard-Core and I am facing some problems which I cannot fix:
I am trying to implement an extremelly simple query:
query MyQuery ($myDesc: String) {
product (where: {description: $myDesc}) {
description
}
}
When I try to play the query I receive the following error:
{
"errors": [
{
"message": "Argument \"where\" has invalid value {description: $myDesc}.\nIn field \"description\": Unknown field.",
"locations": [
{
"line": 17,
"column": 11
}
],
"extensions": {
"code": "5.3.3.1"
}
}
]
}
It says that 'Field "description" is not defined by type "productWhereInput"'
I need to apply to the products a bunch of filters to give me the result I want, but none of them are working.
I have also tried to use "filter" instead of "where", but then I get another error:
'Unknown argument "filter" on field "Query.product".'
Looking to some documentations it doesn't seem to be so hard to use GraphiQL, but when I try to write the code in the way I find it on the docs it give me errors after errors here on Orchard-Core.
There are only limited number of default implemented where filters. By the error you get you didn't implement WhereInputObjectGraphType for your part.
One way is to create yessql MapIndex on fields you want to be able to query.
I'll assume Description is TextField.
So first create ProductPartIndex class as YesSQL MapIndex, that will map Description of every ContentItem with ProductPart.
After that you need to connect index with GraphQL WhereInputObjectType.
public class ProductInputObjectType : WhereInputObjectGraphType<ProductPart>
{
public ProductInputObjectType(IStringLocalizer<ProductInputObjectType> S)
{
AddScalarFilterFields<StringGraphType>("description", S["product description"]);
}
}
public class ProductPartIndexAliasProvider : IIndexAliasProvider
{
private static readonly IndexAlias[] _aliases = new[]
{
new IndexAlias
{
Alias = "ProductPart",
Index = nameof(ProductPartIndex),
IndexType = typeof(ProductPartIndex)
}
};
public IEnumerable<IndexAlias> GetAliases()
{
return _aliases;
}
}
[RequireFeatures("OrchardCore.Apis.GraphQL")]
public class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddInputObjectGraphType<ProductPart, ProductInputObjectType>();
services.AddTransient<IIndexAliasProvider, ProductPartIndexAliasProvider>();
services.AddWhereInputIndexPropertyProvider<ProductPartIndex>();
}
}
This is adhoc code, didn't test it. Everything in here is altered version of AliasPart from source code.

Check if one list contains element from the other in groovy

i have 2 list
List<Car> cars
List<Car> filteredCars
and in cars
{
{
"uuid":"1234",
"name": "A"
},
{
"uuid":"2222",
"name": "B"
}
}
and in filteredCars
{
{
"uuid":"1234",
"name": "A"
},
{
"uuid":"3333",
"name": "C"
}
}
Now i want to add add filteredCars in cars by and then car should contains there object only (A,B,C)
i am try to implement this using groovy closure
filteredCars.each {
if (!cars.contains(it)) {
cars.add(it)
}
}
and but by using this it added the duplicate objects
Any efficeent way to implement this in groovy without using two nested loops?
Depending on your list objects/maps there your approach would only work if the objects themself are compareable (which they are most likely not). So it might be easier to just build an index of the known items for a quick lookup. E.g.
def knownCarsIds = cars*.uuid.toSet()
Then only add if such an id ist not known:
...
if (!knownCarIds.contains(it.uuid)
...

How do I pass Javascript Object to Bixby's Action Output?

I am building an app that search for anime quotes. So, I have the following data, which is 331 Objects (which I call them 'Quote Cards') long and so it will also be updated in future as I add more and more quotes. The problem I having is in creating concepts for JS's array items such as keywords, and imageTag. and also the the character names which are listed as property. I am also willing to change the output as long as I can keep category, and keywords array items. Those are necessary for my quote cards
[
{
$id: "Cold_Souls_1",
animeTitle: "Fullmetal Alchemist Brotherhood",
animePoster:{
referenceImage: 'https://qph.fs.quoracdn.net/main-qimg-da58c837c7197acf364cb2ada34fc5fb.webp',
imageTags: ["Grey","Yellow","Blue","Metal Body","Machine", "Robot","Yellow Hair Boy"],
},
animeCharacters:{
"Edward Elric": [
{
quote: "A lesson without pain is meaningless. For you cannot gain something without sacrificing something else in return. But once you have recovered it and made it your own... You will gain an irreplaceable Fullmetal heart.",
keywords: ["lesson", "pain", "return", "meaningless", "gain","sacrificing", "recover"],
category: "Life Lesson"
}
]
}
},....................
]
In Bixby, you would model a structure that represents the JSON response.
structure (Anime) {
description (The output of your action)
property (title) {
type(viv.core.Text)
visibility (Private)
}
property (poster){
type(AnimePoster)
visibility (Private)
}
property (characters) {
type (AnimeCharacter)
max (Many)
visibility (Private)
}
}
structure (AnimePoster) {
property (referenceImage) {
type (viv.core.Text)
visibility (Private)
}
property (imageTags) {
type (viv.core.Text)
max (Many)
visibility (Private)
}
}
structure (AnimeCharacter) {
property (name) {
type (viv.core.Text)
visibility (Private)
}
property (quote) {
type (viv.core.Text)
visibility (Private)
}
property (keywords) {
type (viv.core.Text)
max (Many)
visibility (Private)
}
property (category) {
type (viv.core.Text)
visibility (Private)
}
}
In your javascript file, you process the JSON structure of animes
// listOfAnimes is the JSON object described in the question
var animes = [];
listOfAnimes.forEach((anime) => {
var characterNames = Object.keys(anime.animeCharacters);
var characters = [];
Object.keys(anime.animeCharacters).forEach((key) => {
characters.push({
name: key,
quote: anime.animeCharacters[key][0].quote, // * warning, can be many
category: anime.animeCharacters[key][0].category// * warning, can be many
});
});
animes.push( {
$id: anime.$id,
title: anime.title,
characters: characters,
poster: {
referenceImage: anime.animePoster.referenceImage,
imageTags: anime.animePoster.imageTags
},
});
});

Best way to navigate throught a JSON in Node while validating the path

I'm trying to get some info out of a API call in Nodejs, structured something like a JSON:
{
"generated":"2019-11-04T09:34:11+00:00",
"event":{
"id":"19040956",
"start_":"2019-11-16T11:30:00+00:00",
"event_context":{
"sport":{
"id":"1",
"name":"Soccer"
}
}
}
}
I'm not sure about the presence of none of these fields(Json could be incomplete).
Is there a better way to get the value of "name" in JSON.event.event_context.sport.name without an ugly if to not get errors like "cannot get field 'sport' of undefined"?
Currently, I'm doing
if(json.event && json.event.event_context && json.event.event_context.sport) {
return json.event.event_context.sport.name;
}
Is there a better way?
Thank you!
what do you mean by saying "I'm not sure about the presence of none of these fields"?
i don't understand what your'e trying to achieve.
Looks like there is also an interesting package that will allow more conditions on searching json :
https://www.npmjs.com/package/jspath
let getNested = (path, obj) => {
return path.split(".").reduce( getPath, obj);
}
let getPath = (path, key) => {
return (path && path[key]) ? path[key] : null
}
let test = {
"foo": "bar",
"baz": { "one": 1, "two": ["to", "too", "two"] },
"event": { "event_context": { "sport": { "name": "soccer" } } }
}
console.log(getNested("none", test))
console.log(getNested("baz.one", test))
console.log(getNested("baz.two", test))
console.log(getNested("event.event_context.sport.name", test))
You can use lodash get to get a potentially deeply-nested value, and also specify a default in case it doesnt exist.
Example
const _ = require('lodash');
const my_object = {
"generated":"2019-11-04T09:34:11+00:00",
"event":{
"id":"19040956",
"start_":"2019-11-16T11:30:00+00:00",
"event_context":{
"sport":{
"id":"1",
"name":"Soccer"
}
}
};
_.get(my_object, 'event.event_context.sport.name'); // "Soccer"
_.get(my_object, 'event.event_context.sport.nonExistentField', 'default val'); // "default val"
Article: https://medium.com/#appi2393/lodash-get-or-result-f409e73e018b
You can check by using a function to check object keys like :
function checkProperty(checkObject, checkstring){
if(!checkstring)
return false;
var propertiesKeys = checkstring.split('.');
propertiesKeys.forEach(element => {
if(!checkObject|| !checkObject.hasOwnProperty(element)){
return false;
} else {
checkObject= checkObject[element];
}
})
return true;
};
var objectToCheck = {
"generated":"2019-11-04T09:34:11+00:00",
"event":{
"id":"19040956",
"start_":"2019-11-16T11:30:00+00:00",
"event_context":{
"sport":{
"id":"1",
"name":"Soccer"
}
}
}
}
if (checkProperty(objectToCheck ,'event.event_context.sport.name'))
console.log('object to find is : ', objectToCheck .event.event_context.sport.name;)
Yeah there are better ways!
For example, you could use lodash's get() method to reach a nested value.
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// => 3
But there is also a native solution.
Currently (11.2019) only Babel can handle this.
I am speaking of Optional chaining. It's new in the Ecmascript world.
Why I like it? Look here!
// Still checks for errors and is much more readable.
const nameLength = db?.user?.name?.length;
What happens when db, user, or name is undefined or null? With the optional chaining operator, JavaScript initializes nameLength to undefined instead of throwing an error.
If you are using Babel as a compiler then you could use it now.
Related link: https://v8.dev/features/optional-chaining

How can I let the user give NL input when showing them an input-view?

I have a capsule that calculates something based on user input. The user needs to tell my capsule an originating country (FromCountryConcept), destination country (ToCountryConcept), and a text (LetterContentConcept). Since the country concepts are enum, the input-view for those are simple selection-of. For the input-view for the text I use a textarea. All of the code is below and available on github in this repository: SendLetter-Bixby
When the user uses the Bixby Views to give the required input to Bixby everything works as expected.
How can I let the user provide input to the shown input-view using (spoken or typed) NL input?
My action SendLetter.model.bxb looks like this:
action (SendLetter) {
description (Sends a Letter from one country to another and calculates the cost based on the letter content length.)
type (Calculation)
collect {
input (fromCountry) {
type (FromCountryConcept)
min (Required)
max (One)
default-init {
intent {
goal: FromCountryConcept
value-set: FromCountryConcept {
FromCountryConcept(Germany)
FromCountryConcept(South Korea)
FromCountryConcept(USA)
FromCountryConcept(Spain)
FromCountryConcept(Austria)
FromCountryConcept(France)
}
}
}
}
input (toCountry) {
type (ToCountryConcept)
min (Required)
max (One)
default-init {
intent {
goal: ToCountryConcept
value-set: ToCountryConcept {
ToCountryConcept(Austria)
ToCountryConcept(South Korea)
ToCountryConcept(USA)
ToCountryConcept(Spain)
ToCountryConcept(Germany)
ToCountryConcept(France)
}
}
}
}
input (letterContent) {
type (LetterContentConcept)
min (Required)
max (One)
}
}
output (SendLetterResponseConcept)
}
The input-view for the country concepts FromCountry_Input.view.bxb looks like this (ToCountry_Input.view.bxb is equivalent):
input-view {
match: FromCountryConcept(this)
message {
template ("Select the country this letter will be sent from")
}
render {
selection-of (this) {
where-each (fromCountry) {
// default-layout used
}
}
}
}
The input-view for the text I want the user to be able to input is in LetterContent_Input.view.bxb:
input-view {
match: LetterContentConcept(this)
message {
template ("Write the content of the letter.")
}
render {
form {
on-submit {
goal: LetterContentConcept
value {
viv.core.FormElement(letterContent)
}
}
elements {
textarea {
id (letterContent)
label ("Letter Content")
type (LetterContentConcept)
value ("#{value(this)}")
}
}
}
}
}
You're at a prompting moment, so you need to add prompt training.
This will allow the user to use NL to respond to your prompt.
In the training tab, it looks like this:
https://bixbydevelopers.com/dev/docs/dev-guide/developers/training.intro-training#add-training-examples-for-prompts

Resources