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

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
},
});
});

Related

Eslint rule is running multiple times

I'm trying to write an eslint rule that enforces making sure the name property is defined on any classes that extend from other Error/Exception named classes (and fixes them).
As far as I can tell, it works in the astexplorer.net individually, but when I'm running it alongside other rules, it ends up getting ran multiple times, so the name property ends up being repeated multiple times in the resulting "fixed" file.
Is there anything in particular I can do to prevent it being run multiple times? I'm assuming what's happening is that it's inserting my name = 'ClassName';, then prettier is needing to reformat the code, which it does, but then maybe it's re-running my rule? I'm not sure.
Rule/fix code shown below. I've tried things like using *fix and yield, but that doesn't seem to help either (see commented code below, based on information in the eslint documentation)
module.exports = {
meta: {
hasSuggestions: true,
type: 'suggestion',
docs: {},
fixable: 'code',
schema: [], // no options,
},
create: function (context) {
return {
ClassDeclaration: function (node) {
const regex = /.*(Error|Exception)$/;
// If the parent/superClass is has "Error" or "Exception" in the name
if (node.superClass && regex.test(node.superClass.name)) {
let name = null;
const className = node.id.name;
// Test class object name
if (!regex.test(className)) {
context.report({
node: node,
message: 'Error extensions must end with "Error" or "Exception".',
});
}
// Find name ClassProperty
node.body.body.some(function (a) {
if (a.type === 'ClassProperty' && a.key.name === 'name') {
name = a.value.value;
return true;
}
});
// Name property is required
if (!name) {
context.report({
node: node,
message: 'Error extensions should have a descriptive name',
fix(fixer) {
return fixer.replaceTextRange(
[node.body.range[0]+1, node.body.range[0]+1],
`name = '${className}';`
);
},
// *fix(fixer) {
// name = className;
// yield fixer.replaceTextRange(
// [node.body.range[0]+1, node.body.range[0]+1],
// `name = '${className}';`
// );
//
// // extend range of the fix to the range of `node.parent`
// yield fixer.insertTextBefore(node.body, '');
// yield fixer.insertTextAfter(node.body, '');
// },
});
}
}
},
};
},
};
Turns out I had the AST Explorer set to the wrong parser, so it was showing me the wrong string name for the ClassProperty node. I should have been using PropertyDefinition instead.

NestJS/Express: Case-Insensitive Body Fields

I'm struggling to make the fields of my request DTOs case insensitive.
export class ExampleDto {
dateOfBirth?: string
}
Now I want to accept
{ "dateofbirth": "19880101" }
{ "dateOfBirth": "19880101" }
{ "DATEOFBIRTH": "19880101" }
My first thought was to implement a middleware which just looks at the incoming body and "extends it" with lower & upper case mappings for all incoming fields.
But that doesn't meet my requirements due to camel case, which I definitely want to keep as the default.
Any ideas on how to do this?
You could create a custom Pipe where you try the different options and finally return the Dto instance:
export class CaseInsensitiveExampleDtoPipe implements PipeTransform{
transform(body: any, metadata: ArgumentMetadata): ExampleDto {
const dto = new ExampleDto();
dto.dateOfBirth = body.dateOfBirth || body.dateofbirth || body.DATEOFBIRTH;
return dto;
}
In your controller you can then use it as follows:
#UsePipes(new CaseInsensitiveExampleDtoPipe())
async postNewExample(#Body() exampleDto: ExampleDto) {
// ...
}
Since JavaScript properties start existing after their initialization, you cannot "see" the definition of dateOfBirth?: string and therefor you won't be able to match it against the received JSON.
A possible solution for that is to enforce the creation of the properties of all of your DTO's with a constructor:
export class ExampleDto {
dateOfBirth: string
constructor(dateOfBirth: string){
this.dateOfBirth = dateOfBirth;
}
}
Then, you'll be able to iterate over the ExampleDto's properties and match them with a pipe (the received type can be derived from metadata):
#Injectable()
export class IgnoreCasePipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
const dto = new metadata.metatype;
const dtoKeys = Object.getOwnPropertyNames(dto);
Object.keys(value).forEach(key => {
const realKey = dtoKeys.find(dtoKey => dtoKey.toLocaleLowerCase() === key.toLocaleLowerCase());
if (realKey) {
dto[realKey] = value[key];
}
});
return dto;
}
}
Either inject it globally in main.ts or wherever it's needed - just bear in mind that you'll need to create a constructor for each DTO.
Note: this would work for a single-level class. If you want to support something like people: PersonDto[] in your classes then you'll need to recursively find all of the nested keys and match them - something like this.

Issue in giving plurals in Bixby dialogs

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.

How to prevent duplicate action execution in Bixby?

I want to implement a capsule that does a calculation if the user provides the full input necessary for the calculation or asks the user for the necessary input if the user doesn't provide the full input with the very first request. Everything works if the user provides the full request. If the user doesn't provide the full request but Bixby needs more information, I run into some strange behavior where the Calculation is being called more than once and Bixby takes the necessary information for the Calculation from a result of another Calculation, it looks like in the debug graph.
To easier demonstrate my problem I've extended the dice sample capsule capsule-sample-dice and added numSides and numDice to the RollResultConcept, so that I can access the number of dice and sides in the result.
RollResult.model.bxb now looks like this:
structure (RollResultConcept) {
description (The result object produced by the RollDice action.)
property (sum) {
type (SumConcept)
min (Required)
max (One)
}
property (roll) {
description (The list of results for each dice roll.)
type (RollConcept)
min (Required)
max (Many)
}
// The two properties below have been added
property (numSides) {
description (The number of sides that the dice of this roll have.)
type (NumSidesConcept)
min (Required)
max (One)
}
property (numDice) {
description (The number of dice in this roll.)
type (NumDiceConcept)
min (Required)
max (One)
}
}
I've also added single-lines in RollResult.view.bxb so that the number of sides and dice are being shown to the user after a roll.
RollResult.view.bxb:
result-view {
match {
RollResultConcept (rollResult)
}
render {
layout {
section {
content {
single-line {
text {
style (Detail_M)
value ("Sum: #{value(rollResult.sum)}")
}
}
single-line {
text {
style (Detail_M)
value ("Rolls: #{value(rollResult.roll)}")
}
}
// The two single-line below have been added
single-line {
text {
style (Detail_M)
value ("Dice: #{value(rollResult.numDice)}")
}
}
single-line {
text {
style (Detail_M)
value ("Sides: #{value(rollResult.numSides)}")
}
}
}
}
}
}
}
Edit: I forgot to add the code that I changed in RollDice.js, see below:
RollDice.js
// RollDice
// Rolls a dice given a number of sides and a number of dice
// Main entry point
module.exports.function = function rollDice(numDice, numSides) {
var sum = 0;
var result = [];
for (var i = 0; i < numDice; i++) {
var roll = Math.ceil(Math.random() * numSides);
result.push(roll);
sum += roll;
}
// RollResult
return {
sum: sum, // required Sum
roll: result, // required list Roll
numSides: numSides, // required for numSides
numDice: numDice // required for numDice
}
}
End Edit
In the Simulator I now run the following query
intent {
goal: RollDice
value: NumDiceConcept(2)
}
which is missing the required NumSidesConcept.
Debug view shows the following graph, with NumSidesConcept missing (as expected).
I now run the following query in the simulator
intent {
goal: RollDice
value: NumDiceConcept(2)
value: NumSidesConcept(6)
}
which results in the following Graph in Debug view:
and it looks like to me that the Calculation is being done twice in order to get to the Result. I've already tried giving the feature { transient } to the models, but that didn't change anything. Can anybody tell me what's happening here? Am I not allowed to use the same primitive models in an output because they will be used by Bixby when trying to execute an action?
I tried modifying the code as you have but was unable to run the intent (successfully).
BEGIN EDIT
I added the additional lines in RollDice.js and was able to see the plan that you are seeing.
The reason for the double execution is that you ran the intents consecutively and Bixby derived the value of the NumSidesConcept that you did NOT specify in the first intent, from the second intent, and executed the first intent.
You can verify the above by providing a different set of values to NumSidesConcept and NumDiceConcept in each of the intents.
If you had given enough time between these two intents, then the result would be different. In your scenario, the first intent was waiting on a NumSidesConcept to be available, and as soon as the Planner found it (from the result of the second intent), the execution went through.
How can you avoid this? Make sure that you have an input-view for each of the inputs so Bixby can prompt the user for any values that did not come through the NL (or Aligned NL).
END EDIT
Here is another approach that will NOT require changing the RollResultConcept AND will work according to your expectations (of accessing the number of dice and sides in the result-view)
result-view {
match: RollResultConcept (rollResult) {
from-output: RollDice(action)
}
render {
layout {
section {
content {
single-line {
text {
style (Detail_M)
value ("Sum: #{value(rollResult.sum)}")
}
}
single-line {
text {
style (Detail_M)
value ("Rolls: #{value(rollResult.roll)}")
}
}
// The two single-line below have been added
single-line {
text {
style (Detail_M)
value ("Dice: #{value(action.numDice)}")
}
}
single-line {
text {
style (Detail_M)
value ("Sides: #{value(action.numSides)}")
}
}
}
}
}
}
}
Give it a shot and let us know if it works!

Why is the vuex component isn't updated, despite the state updating?

When I load my page, I fetch a list of optboxes items.
Sources
Project's sources are online:
optboxes page ;
store (store, actions, mutations, getters).
optboxes pages
The HTTP request is well send and return adequate data:
created(){
this.getOptboxes();
},
components: {
'optbox': OptboxComponent,
},
methods: {
getOptboxes() {
optboxes.all().then((response) => {
this.setOptboxes(response.data.output);
}).catch(() = > {
this.no_optbox_message = 'there is no optbox';
logging.error(this.$t('optboxes.get.failed'))
});
}
},
vuex: {
actions: { setOptboxes: actions.setOptboxes},
getters: { optboxesList: getters.retrieveOptboxes}
}
I'm iterating over the results as follow:
<div v-for="optbox in optboxesList" class="panel panel-default">
<optbox :optbox="optbox"></optbox>
</div>
Store
const state = {
optboxes: {
/*
'akema': {
hostname: "192.168.2.23",
id: "akema",
printers: [
{
description: "bureau",
destination_port: 9100,
forward: "normal",
hostname: "1.2.3.4",
id: 0,
listening_port: 9102
}
]
}
*/
}
};
Question
If I switch to another pages and come back then the list appear. I also notice that with the Vuex extension I can commit the state and see the changes.
Why are my changes not applied automatically?
I had to change my data structure due to Change Detection Caveats.
Due to limitations of JavaScript, Vue.js cannot detect the following
changes to an Array:
When you directly set an item with the index, e.g. vm.items[0] = {};
When you modify the length of the Array, e.g. vm.items.length = 0.
Store
optboxes is now an array.
const state = {
optboxes:[]
}
Then update my mutations accordingly to edit the array.
Maybe it's an issue of reactivity?! I assume your setOptboxes mutation is not being picked up by vue:
setOptboxes(state, optboxes) {
for (var optbox of optboxes) {
state.optboxes[optbox.id] = optbox;
}
}
You can read about it here:
https://vuejs.org/guide/list.html#Caveats
https://vuejs.org/guide/reactivity.html
The docs solution is to use:
state.optboxes.$set(optbox.id, optbox);
which will trigger a view update.
Using Vue.set dit it for me. Take a look here

Resources