Code Monkey home page Code Monkey logo

alexa.net.apl's People

Contributors

evgeni-nabokov avatar pablobenigno avatar shinya-terasaki avatar stoiveyp avatar troydonanabolic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

alexa.net.apl's Issues

Container item array is serialized as a single item

I created a simple APL document using Amazon Developer console that looks like this:

{
  "type": "APL",
  "version": "1.8",
  "license": "",
  "settings": {},
  "theme": "dark",
  "import": [],
  "resources": [],
  "styles": {},
  "onMount": [],
  "graphics": {},
  "commands": {},
  "layouts": {},
  "mainTemplate": {
    "parameters": [
      "payload"
    ],
    "items": [
      {
        "type": "Container",
        "height": "100vh",
        "width": "100vw",
        "items": [
          {
            "type": "Container",
            "width": "100%",
            "grow": 1,
            "shrink": 1,
            "alignItems": "center",
            "data": "${payload.categories}",
            "numbered": false,
            "items": [
              {
                "type": "Text",
                "text": "${data.name}",
                "color": "blue"
              }
            ]
          }
        ]
      }
    ]
  }
}

In my function code, I'm reading this JSON file and adding to JsonDirective as APLDocument with the code below:

string aplDocumentRaw = File.ReadAllText("./Documents/list-categories.json");
APLDocument aplDocument = JsonConvert.DeserializeObject<APLDocument>(aplDocumentRaw);
var payloadObj = new { categories = categories.Select(category => new { name = category }).ToList() };
response.Response.Directives.Add(new JsonDirective(RenderDocumentDirective.APLDirectiveType)
{
    Properties = new Dictionary<string, object>()
    {
        ["document"] = aplDocument,
        ["datasources"] = payloadObj
    }
});

The problem is, even though items in the original JSON document is an array, it's deserialized as a single item. When I log the entire response before I return I can see it looks like this (redacted for brevity):

"mainTemplate": {
    "parameters": [
        "payload"
    ],
    "items": {
        "type": "Container",
        "items": {
            "type": "Container",
            "alignItems": "center",
            "data": "${payload.categories}",
            "items": {
                "type": "Text",
                "text": "${data.name}",
                "color": "blue"
            },
            "numbered": false,
            "width": "100%",
            "grow": "1",
            "shrink": 1
        },
        "height": "100vh",
        "width": "100vw"
    }
},

Because now items is a single object trying to bind an array causes an error.

Is there a way to deserialize "items" object as an array?

Many thanks for your hard work in putting this library together.

Kind regards,
Volkan

Unable to deserialize sample RenderDocument

If you go here and try the sample "Long text" then export the code.

when you try to deserialize that json you get an error of

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IList`1

for the property "fontWeight" as it is a single element and not a list element.

I tried to puta JsonObject attribute on the class, but it didn't resolve the issue.

Pager

There is an issue in pager, when we set "data" property of pager and assign some datasource and desrialize the json template to RenderDocumentDirective, the data come up as null. Where as in sequence the data come up. I saw the code the "data" property of Pager is different than the "data" property of sequence. I extend the Pager and override the data property and that worked, but can you plz reply if this is a bug or if there is some other technique to use "data" property of pager when deserializing?

AbsoluteDimension inappropriate serialization

Hello,

Thank you for the library. It really makes APL easier for me.

I have an issue on AbsoluteDimension.
AbsoluteDimension is serialized as

"left": {
  "Unit": "vw",
  "Number": 16
}

but it is unlikely compatible with APL. It should be serialized as

"left": "16vw"

I checked with the following code and it worked.

    [JsonConverter(typeof(AbsoluteDimensionExConverter))]
    internal class AbsoluteDimensionEx : AbsoluteDimension
    {
        public AbsoluteDimensionEx(int number, string unit) : base(number, unit)
        {
        }
    }

    class AbsoluteDimensionExConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType) => objectType == typeof(AbsoluteDimensionEx);

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var raw = (string)reader.Value;
            var match = Regex.Match(raw, @"^(?<num\d+>)(?<unit>.+)$");
            if (match.Success)
            {
                return new AbsoluteDimensionEx(int.Parse(match.Groups["num"].Value), match.Groups["unit"].Value);
            }
            return null;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var dim = value as AbsoluteDimensionEx;
            if (dim != null)
                writer.WriteValue($"{dim.Number}{dim.Unit}");
            else
                writer.WriteNull();
        }
    }

BTW, APL likely accepts floating point number for the value.

Setting slot values from UserEventRequest

Hey!

I'm trying to elicit slots manually from the user so that I can also present them with APL documents for each turn to allow them to type the information instead of speak it if they wish. I send an ElicitSlot request and display the APL document which works fine. When the user types a value and presses the button I'm using SendEvent which returns me a UserEvent request which contains the information which they have typed. However I'm a little unsure of how to set the slot value to that of the value the user has entered since I don't have a handle on the Slots dictionary in the UserEvent request.. I guess i could use the session attributes and save it for the next turn until i have all the info but this didn't quite feel right.

I guess i either need to let the ElicitSlot request that the value is coming from either speech or the text input or handle the UserEvent and populate the slot value manually but I'm not too sure how to do either of these.. any ideas?

Not sure if this is a Alexa.NET.APL or Alexa.NET question so sorry if it's not directed at the right place.

ExecuteCommandsDirective Serialization

Hi,
i had problems using ExecuteCommandsDirective with SpeakItem after updating to version 4.0.10 of the APL library. It is also possible that my problem has to do something with a change done by amazon.

I always got an response error when i had just one command added to the ExecuteCommandsDirective. I think the problem is that the Commands enumeration is not serialized as array when there is just one command in it. My Workaround is to add a second SpeakItem command with a not existing componentid property.

Workaround:

{
                "type": "Alexa.Presentation.APL.ExecuteCommands",
                "token": "WasteTipsDirective",
                "commands": [
                    {
                        "type": "SpeakItem",
                        "componentId": "fake"
                    },
                    {
                        "type": "SpeakItem",
                        "align": "center",
                        "componentId": "talker",
                        "highlightMode": "line"
                    }
                ]
            }

NOT WORKING:

{
                "type": "Alexa.Presentation.APL.ExecuteCommands",
                "token": "WasteTipsDirective",
                "commands": {
                    "type": "SpeakItem",
                        "align": "center",
                        "componentId": "talker",
                        "highlightMode": "line"
                }
            }

Style Property of Components

Shouldn't the Style property of Components be a string, since according to their documentation it is supposed to refer to a named style, rather than it being the style object directly. Currently I'm resorting to CustomerComponent with a custom style property which is a string value.

Is there something I've missed?

No ListDataSource

One of the data source types that Alexa supports is "list", and there doesn't seem to be a way to support it currently. Here's a json example of one of the list data source types from their carousel sample:

 {
        "type": "list",
        "listId": "lt2Sample",
        "totalNumberOfItems": 10,
        "hintText": "Try, \"Alexa, select number 1\"",
        "listPage": {
            "listItems": [
                {
                    "listItemIdentifier": "brie",
                    "ordinalNumber": 1,
                    "textContent": {
                        "primaryText": {
                            "type": "PlainText",
                            "text": "Brie"
                        },
                        "secondaryText": {
                            "type": "PlainText",
                            "text": "Origin: France"
                        }
                    },
                    "image": {
                        "contentDescription": null,
                        "smallSourceUrl": null,
                        "largeSourceUrl": null,
                        "sources": [
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/md_brie.png",
                                "size": "small",
                                "widthPixels": 0,
                                "heightPixels": 0
                            },
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/md_brie.png",
                                "size": "large",
                                "widthPixels": 0,
                                "heightPixels": 0
                            }
                        ]
                    },
                    "token": "brie"
                },
                {
                    "listItemIdentifier": "gruyere",
                    "ordinalNumber": 2,
                    "textContent": {
                        "primaryText": {
                            "type": "PlainText",
                            "text": "Gruyere"
                        },
                        "secondaryText": {
                            "type": "RichText",
                            "text": "Origin: Switzerland"
                        }
                    },
                    "image": {
                        "contentDescription": null,
                        "smallSourceUrl": null,
                        "largeSourceUrl": null,
                        "sources": [
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/md_gruyere.png",
                                "size": "small",
                                "widthPixels": 0,
                                "heightPixels": 0
                            },
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/md_gruyere.png",
                                "size": "large",
                                "widthPixels": 0,
                                "heightPixels": 0
                            }
                        ]
                    },
                    "token": "gruyere"
                },
                {
                    "listItemIdentifier": "gorgonzola",
                    "ordinalNumber": 3,
                    "textContent": {
                        "primaryText": {
                            "type": "PlainText",
                            "text": "Gorgonzola"
                        },
                        "secondaryText": {
                            "type": "RichText",
                            "text": "Origin: Italy"
                        }
                    },
                    "image": {
                        "contentDescription": null,
                        "smallSourceUrl": null,
                        "largeSourceUrl": null,
                        "sources": [
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/md_gorgonzola.png",
                                "size": "small",
                                "widthPixels": 0,
                                "heightPixels": 0
                            },
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/md_gorgonzola.png",
                                "size": "large",
                                "widthPixels": 0,
                                "heightPixels": 0
                            }
                        ]
                    },
                    "token": "gorgonzola"
                },
                {
                    "listItemIdentifier": "brie",
                    "ordinalNumber": 1,
                    "textContent": {
                        "primaryText": {
                            "type": "PlainText",
                            "text": "Brie"
                        },
                        "secondaryText": {
                            "type": "PlainText",
                            "text": "Origin: France"
                        }
                    },
                    "image": {
                        "contentDescription": null,
                        "smallSourceUrl": null,
                        "largeSourceUrl": null,
                        "sources": [
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/tl_brie.png",
                                "size": "small",
                                "widthPixels": 0,
                                "heightPixels": 0
                            },
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/tl_brie.png",
                                "size": "large",
                                "widthPixels": 0,
                                "heightPixels": 0
                            }
                        ]
                    },
                    "token": "tl_brie"
                },
                {
                    "listItemIdentifier": "gruyere",
                    "ordinalNumber": 2,
                    "textContent": {
                        "primaryText": {
                            "type": "PlainText",
                            "text": "Gruyere"
                        },
                        "secondaryText": {
                            "type": "RichText",
                            "text": "Origin: Switzerland"
                        }
                    },
                    "image": {
                        "contentDescription": null,
                        "smallSourceUrl": null,
                        "largeSourceUrl": null,
                        "sources": [
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/tl_gruyere.png",
                                "size": "small",
                                "widthPixels": 0,
                                "heightPixels": 0
                            },
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/tl_gruyere.png",
                                "size": "large",
                                "widthPixels": 0,
                                "heightPixels": 0
                            }
                        ]
                    },
                    "token": "tl_gruyere"
                },
                {
                    "listItemIdentifier": "gorgonzola",
                    "ordinalNumber": 3,
                    "textContent": {
                        "primaryText": {
                            "type": "PlainText",
                            "text": "Gorgonzola"
                        },
                        "secondaryText": {
                            "type": "RichText",
                            "text": "Origin: Italy"
                        }
                    },
                    "image": {
                        "contentDescription": null,
                        "smallSourceUrl": null,
                        "largeSourceUrl": null,
                        "sources": [
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/tl_gorgonzola.png",
                                "size": "small",
                                "widthPixels": 0,
                                "heightPixels": 0
                            },
                            {
                                "url": "https://d2o906d8ln7ui1.cloudfront.net/images/tl_gorgonzola.png",
                                "size": "large",
                                "widthPixels": 0,
                                "heightPixels": 0
                            }
                        ]
                    },
                    "token": "tl_gorgonzola"
                }
            ]
        }

Filling ListDataSource with Data

I have a question on how to fill a ListDataSource (which I see has been added fairly recently).
I am currently trying to recreate a Layout I did with the alexa authoring tool in .NET .

So the ListDataSource has different properties like "ListId", while the data is supposed to be stored in the "ListPage", however the ListPage property is readonly and doesn't have a constructor that takes a parameter.
Can you describe me how it is supposed to be used like? Sorry if this is a trivial question I am no programming pro.

public class ListPage
{
public ListPage()
ListItems = new List();

    [JsonProperty("listItems")]
    public List<object> ListItems { get; set; }

}

I guess I could just write my own DataSource type, but I'd rather stick to your classes.

Safe Updates to APL Versions with

Hi,

Our code just broke with a call to skillRequest.APLInterfaceDetails()

The device had updated to APL v1.2 and there was an internal Newtonsoft error mapping 1.2 to the APLDocumentVersions.

As skills can be deployed and device updates can happen post deployment, can this section be made safer, avoiding a republish of the skill with a new Alexa.NET.APL package?

Component should implement IEnumerable<IComponent>

The code example for "Sending a RenderDocument Directive" does not compile because Component does not have a constructor that takes an enumerable.

A better implementation is to make Component implement IEnumerable<IComponent>. This allows the following:

new Container
{
    new Text("APL in C#")
    {
        FontSize = "24dp",
        TextAlign = "Center",
    },
    new Image("https://images.example.com/photos/2143/lights-party-dancing-music.jpg?cs=srgb&dl=cheerful-club-concert-2143.jpg&fm=jpg")
    {
        Width = 400,
        Height = 400,
    },
}

The compiler will "automagically" call Add() for each IComponent. Please check the working example on sharplab.io.

It will also make possible to enumerate the components in the container.

Doco error (very minor)

The sample code under the "Creating a Layout Document" heading has mismatching parenthesis. Took me an embarrassing amount of time to figure out where the parenthesis should be!

Data property on Sequence is a List<object>

Currently, the Sequence component has the Data property defined as APLValue<List<object>>. This will work great when I want to provide the data as a list of objects. But for the scenario where I want to reference a datasource because I'm using a transformer, this won't work because I need to be able to provide a string. Something like this:

  {
      "type": "Sequence",
      "id": "leaderboardSequence",
      "width": "100%",
      "height": "80%",
      "data": "${payload.leaderboardData.properties.listItems}",
      "numbered": true,
      "items": [

Ideally it would be nice to be able to support both a list of objects and a string so I can define this either way.

SetState command

We see that this library doesnt covers all the commands, like i wanted to use SetState command but could not found in the library.

Question: How to use APL and data files from Alexa designer?

I like the strongly-typed way of creating the layout but only being able visualize after deploying makes is very unproductive.

I'm trying to figure out how to use the code sample from the README:

  var directive = new JsonDirective(RenderDocumentDirective.APLDirectiveType);
  directive.Properties.Add("document",aplDocumentJson);

What is aplDocumentJson?

How to send both the APL and the data files?

Question: How to add APL support in Azure Functions?

I have a small voice-only skill and would like to upgrade to use APL.

The current function signature is:

[FunctionName("MyFunction")]
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]SkillRequest req, ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    return req.Request switch
    {
        LaunchRequest _ => new OkObjectResult(ResponseBuilder.Ask("How can I help?", new Reprompt())),

        _ => new OkObjectResult(ResponseBuilder.Empty())
    };
}

Do I only need to change the first parameter type to APLSkillRequest? I tried but didn't work.

To my best understanding, both the code snippets in the README and the sample use AWS.

Alexa headline footer does not work

Footer does not work, in ResponsiveTemplate.cs, possibly the below property needs have it's jsonproperty set to "footerHintText", and also change the property name to FooterHintText ideally too:

[JsonProperty("hintText", NullValueHandling = NullValueHandling.Ignore)]
public APLValue HintText { get; set; }

to

[JsonProperty("footerHintText", NullValueHandling = NullValueHandling.Ignore)]
public APLValue FooterHintText { get; set; }

How to build "Karaoke Mode" and survive

I am using the ssmlToSpeech APLTransformer, therefore I do not need (?) to use ResponseBuilder.Ask or ResponseBuilder.Tell. So, what kind of response I have to build? I am asking because I do not know why my transformation does not work.

"datasources": {
	"article": {
		"type": "object",
		"properties": {
			"title": "...",
			"subtitle": "...",
			"ssml": "<speak>I have a dream that one day this nation will rise up and live out the true meaning of its creed: “We hold these truths to be self-evident, that all men are created equal.</speak>"
		},
		"transformers": [
			{
				"inputPath": "ssml",
				"outputName": "speech",
				"transformer": "ssmlToSpeech"
			},
			{
				"inputPath": "ssml",
				"outputName": "text",
				"transformer": "ssmlToText"
			}
		]
	}
}

When I use an empty Ask, Alexa simply waits for a command. If I send an empty Tell, Alexa shuts down the skill.

APLSupported Can Fail on NULL Object (Context)

Migrating to APLSkillRequest means simplifying code with .APLSupported() rather than
request.Context?.System.Device.SupportedInterfaces.ContainsKey(InterfaceName)

However, in our tests Context can be null which is not handled by APLInterface.cs code because there is no ? null check

Assuming there are valid cases where .Context may be null (and System? and Device?) consider revising the code. See also checks in APLInterfaceDetails()

Events should be an array

Events (onPress in my case) appear to expect an array of actions now, rather than a single object. The documentation doesn't appear to reflect this change in all places, however the APL designer does give warnings when you input something other than an array. The onPress documentation of TouchWrapper does refer to command(s) to execute though. The fix in my case seems to be making it an array of a single object, rather than the single object its self.

Properties that are currently APLAbsoluteDimensionValue prevent using expressions

I've just updated to 4.1.0, and gone from

Top = "{Top}"

to

Top = APLValue.To<APLAbsoluteDimensionValue>("${Top}")

This doesn't work however as the implicit conversion takes the Value property, which is null meaning nothing is output in JSON.

Since APL seems to allow Top (and probably others) to use an expression I guess the type should be something like APLValue<APLAbsoluteDimensionValue>.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.