AreYouFreeBusy / AlexaSkillsKit.NET

.NET library that simplifies Alexa skills development; same object model as Amazon's AlexaSkillsKit for Java
MIT License
212 stars 99 forks source link

EchoShow - display.TemplateVersion #56

Closed ghost closed 6 years ago

ghost commented 6 years ago

ElvenMonky or anyone.

Based on the new code you have put together... I realize its not been completely merged, but I am trying to use it. Wondering if you could provide c# example of using context to get the Display templateversion value ... is 1 if display is supported.

Trying using your new code and receive a null?

If I do something like... it works fine. But I would like to use the defined objects

JObject contextJObject = JObject.Parse(context.ToString());

        string tmpVersion = (string)requestJsonContext["System"]["Device"]["SupportedInterfaces"]["Display"]["TemplateVersion"];

Can someone tell me the most efficient way to do this?

public override SpeechletResponse OnIntent(IntentRequest request, Session session, Context context) {

        JObject requestJsonContext = JObject.FromObject(context);

        JObject requestSystem = requestJsonContext["System"].Value<JObject>();

        JObject requestDevice = requestSystem["Device"].Value<JObject>();

        JObject requestSupportedInterfaces = requestDevice["SupportedInterfaces"].Value<JObject>();

        JObject requestDisplay = requestSupportedInterfaces["Display"].Value<JObject>();

       DisplayInterface display = DisplayInterface.FromJson(requestDevice);  //gives NULL

Thanks in advance, Peter

ElvenMonky commented 6 years ago

Ok, from first attempt I can't find any official information from Amazon about DisplayInterface object structure. From this post it looks like that empty json object has to be accepted. I found the "templateversion" property only in official Java library and it seems that they handle null values by replacing with defaults (which are "1.0"). You can do same thing I guess.

ElvenMonky commented 6 years ago

In Java library they've also added new Display.ElementSelected request. I'm not sure what we should do with these undocumented features.

ghost commented 6 years ago

I have taken the original library and refactored for my own use. Unfortunately, this means having to maintain and add new functionality when it comes out. This is why I took a look at what you had done.

I have two code examples here. One uses the BodyTemplate2, the Other ListTemplate2 Each make use of the Display.ElementSelected for making selections on the screen.

In the second Skill I have the code where I verify if display is available (EchoShow) Here is some of the code. When I tried doing similar things with the new version you posted I was getting null values.

***Happy to discuss more if you are interested.....

        Display display = new Display();
        display = context.System.Device.SupportedInterfaces.Display;

        if (display != null)
        {
            if (!string.IsNullOrEmpty(display.TemplateVersion) == true)
            {
                session.Attributes["displaySupported"] = "YES";
           }

1st if (!string.IsNullOrEmpty(session.Attributes["displaySupported"]) == true) { if (session.Attributes["displaySupported"] == "YES") { SimpleCard card = new SimpleCard(); card.Title = String.Format(speechletText + " - {0}", "Alexa Skill"); card.Subtitle = String.Format(speechletText + " - {0}", "Driving Permit Practice Test"); card.Content = String.Format(speechletText + " - {0}", output);

                        // Create the SSML text output.
                        SsmlOutputSpeech speech = new SsmlOutputSpeech();
                        speech.Ssml = output.ToString();

                        // Create the speechlet response.
                        SpeechletResponse response = new SpeechletResponse();
                        response.ShouldEndSession = shouldEndSession;
                        response.OutputSpeech = speech;
                        response.Card = null;

                        if (!String.IsNullOrEmpty(repromptText))
                        {
                            PlainTextOutputSpeech speech2 = new PlainTextOutputSpeech();
                            speech2.Text = "Please say my topic is, then say your selected topic or click on your desired Topic";
                            Reprompt reprompt = new Reprompt();
                            reprompt.OutputSpeech = speech2;
                            response.Reprompt = reprompt;
                        }

                        IList<AlexaSkillsKit.UI.EchoShowUI.Directive> listDirectiveTest = new List<AlexaSkillsKit.UI.EchoShowUI.Directive>();
                        AlexaSkillsKit.UI.EchoShowUI.Directive directiveTest = new AlexaSkillsKit.UI.EchoShowUI.Directive();
                        AlexaSkillsKit.UI.EchoShowUI.Image backgroundTest = new AlexaSkillsKit.UI.EchoShowUI.Image();
                        IList<AlexaSkillsKit.UI.EchoShowUI.Source> backgroundSourcesTest = new List<AlexaSkillsKit.UI.EchoShowUI.Source>();
                        directiveTest.Type = "Display.RenderTemplate";

                        //If you want an overlay of text on top of a background image, you must include the overlay in the image itself. A 70% opacity black layer is recommended for optimal contrast.
                        // With the backgroundImage field, the display size is the same as for the Echo Show screen: 1024px x 600px.
                        AlexaSkillsKit.UI.EchoShowUI.Source backgroundSource = new AlexaSkillsKit.UI.EchoShowUI.Source();
                        backgroundSource.Url = apiURL + "images/Love_New_York.png"; // "URL for the background image - must be secure (https)";
                        backgroundSource.Size = "MEDIUM";
                        backgroundSource.heightPixels = 1024;
                        backgroundSource.widthPixels = 600;

                        //primaryContentTest.Text = "Welcome to the <b>New York State DMV</b> <u>Permit Practice Test</u> Alexa Skill. <br/><br/> With this skill you can: " +
                        //"<b>Take True and False Questions</b> to prepare for your drivers permit test.<br/>";
                        //primaryContentTest.Type = "RichText";

                        //secondaryContentTest.Text = "To Begin the test, please <b>Say Practice Test</b>.";
                        //secondaryContentTest.Type = "RichText";

                        var lsttemplate1 = new Template
                        {
                            Title = "NYS Department of Motor Vehicles - Permit Test Skill",
                            Token = "ListTemplate2",
                            BackButton = BackButtonVisibility.Hidden,
                            Type = "ListTemplate2",
                            BackgroundImage = new AlexaSkillsKit.UI.EchoShowUI.Image
                            {
                                ContentDescription = "I Love New York",
                                Sources = new List<AlexaSkillsKit.UI.EchoShowUI.Source>
                                    {
                                        new AlexaSkillsKit.UI.EchoShowUI.Source { Url=apiURL + "images/Love_New_York.png",
                                        Size = ImageSize.Medium,
                                         heightPixels=1024,
                                         widthPixels=600
                                        }
                                    }
                            },

                            //Must make dynamic from DB
                            //Must pass in 
                            //templateTest.Token = "PermitTestTopicSelectionIntent,Topics";  //Intent & SLot Name & value
                            //See above for action tag and how it was done.. then the display elemented selected will need to change.

                            listItems = new List<ListItem>
                                {
                                    new ListItem
                                    {
                                        Token="DMV,PermitTestTopicSelectionIntent,Topics,Traffic",
                                        textContent = new TemplateContent
                                        {
                                            primaryText = new TemplateText
                                            {
                                                Text="<font size='3'>Traffic</font> <br/> Control",
                                                Type=TextType.Rich
                                            },
                                            secondaryText = new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            },
                                            tertiaryText=new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            }
                                        },
                                        Image = new TemplateImage
                                        {
                                            Sources = new List<ImageSource>{new ImageSource
                                            {
                                                Url= apiURL + "images/trafficcontrol.png",
                                                 Height=280,
                                                 Width=280,
                                                 Size="SMALL"
                                            }},
                                            ContentDescription = "Traffic Control"
                                        }
                                    },
                                    new ListItem
                                    {
                                        Token="DMV,PermitTestTopicSelectionIntent,Topics,Intersection",
                                        textContent = new TemplateContent
                                        {
                                            primaryText = new TemplateText
                                            {
                                                Text="<font size='3'>Intersection</font> <br/> and Turns",
                                                Type=TextType.Rich
                                            },
                                            secondaryText = new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            },
                                            tertiaryText=new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            }
                                        },
                                        Image = new TemplateImage
                                        {
                                            Sources = new List<ImageSource>{new ImageSource
                                            {
                                                Url= apiURL + "images/intersections.png",
                                                 Height=280,
                                                 Width=280,
                                                 Size="SMALL"
                                            }},
                                            ContentDescription = "Intersection and Turns"
                                        }
                                    },
                                    new ListItem
                                    {
                                        Token="DMV,PermitTestTopicSelectionIntent,Topics,Passing",
                                        textContent = new TemplateContent
                                        {
                                            primaryText = new TemplateText
                                            {
                                                Text="<font size='3'>Passing</font> <br/>",
                                                Type=TextType.Rich
                                            },
                                            secondaryText = new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            },
                                            tertiaryText=new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            }
                                        },
                                        Image = new TemplateImage
                                        {
                                            Sources = new List<ImageSource>{new ImageSource
                                            {
                                                Url= apiURL + "images/passing.png",
                                                 Height=280,
                                                 Width=280,
                                                 Size="SMALL"
                                            }},
                                            ContentDescription = "Passing"
                                        }
                                    },
                                    new ListItem
                                    {
                                        Token="DMV,PermitTestTopicSelectionIntent,Topics,Parallel",
                                        textContent = new TemplateContent
                                        {
                                            primaryText = new TemplateText
                                            {
                                                Text="<font size='3'>Parallel</font> <br/>Parking",
                                                Type=TextType.Rich
                                            },
                                            secondaryText = new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            },
                                            tertiaryText=new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            }
                                        },
                                        Image = new TemplateImage
                                        {
                                            Sources = new List<ImageSource>{new ImageSource
                                            {
                                                Url= apiURL + "images/parallel.png",
                                                 Height=280,
                                                 Width=280,
                                                 Size="SMALL"
                                            }},
                                            ContentDescription = "Parallel Parking"
                                        }
                                    },
                                    new ListItem
                                    {
                                        Token="DMV,PermitTestTopicSelectionIntent,Topics,Defensive",
                                        textContent = new TemplateContent
                                        {
                                            primaryText = new TemplateText
                                            {
                                                Text="<font size='3'>Defensive</font> <br/>Driving",
                                                Type=TextType.Rich
                                            },
                                            secondaryText = new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            },
                                            tertiaryText=new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            }
                                        },
                                        Image = new TemplateImage
                                        {
                                            Sources = new List<ImageSource>{new ImageSource
                                            {
                                                Url= apiURL + "images/defensive.png",
                                                 Height=280,
                                                 Width=280,
                                                 Size="SMALL"
                                            }},
                                            ContentDescription = "Defensive Driving"
                                        }
                                    },
                                    new ListItem
                                    {
                                        Token="DMV,PermitTestTopicSelectionIntent,Topics,Alcohol",
                                        textContent = new TemplateContent
                                        {
                                            primaryText = new TemplateText
                                            {
                                                Text="<font size='3'>Alcohol and </font> <br/>Other Drugs",
                                                Type=TextType.Rich
                                            },
                                            secondaryText = new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            },
                                            tertiaryText=new TemplateText
                                            {
                                                Text=string.Empty,
                                                Type=TextType.Plain
                                            }
                                        },
                                        Image = new TemplateImage
                                        {
                                            Sources = new List<ImageSource>{new ImageSource
                                            {
                                                Url= apiURL + "images/alcohol.png",
                                                 Height=280,
                                                 Width=280,
                                                 Size="SMALL"
                                            }},
                                            ContentDescription = "Alcohol and Other Drugs"
                                        }
                                    }
                                }
                        };

                        directiveTest.Template = lsttemplate1;
                        listDirectiveTest.Add(directiveTest);

                        AlexaSkillsKit.UI.EchoShowUI.Directive directiveTest2 = new AlexaSkillsKit.UI.EchoShowUI.Directive();
                        directiveTest2.Type = "Hint";
                        AlexaSkillsKit.UI.EchoShowUI.RenderHint hint = new RenderHint();
                        hint.Type = "PlainText";
                        hint.Text = "Ask NY Motor Vehicles for Practice Test";
                        directiveTest2.Hint = hint;

                        listDirectiveTest.Add(directiveTest2);
                        response.Directives = listDirectiveTest;

                        //string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(response);

                        return response;
                    }

2nd

private SpeechletResponse CancelOrStopIntentHandler(IntentRequest request, Session session, Context context) { var output = new StringBuilder(""); var outputCard = new StringBuilder();

        string repromptText = "";
        bool shouldEndSession = true;

        output.AppendFormat("Thank you for using the  <break time='0.1s'/> Alexa Skill. <break time='0.3s'/> ");
        output.AppendFormat("Let's chat again soon! ");

        outputCard.Append("Thank you for using the  Alexa Skill. Let's chat again soon!" + ".\n\n");
        output.Append("</speak>");

        // Perhaps check if the entry exists so as not to cause an error.
        Display display = new Display();
        display = context.System.Device.SupportedInterfaces.Display;

        if (display != null)
        {
            if (!string.IsNullOrEmpty(display.TemplateVersion) == true)
            {
                session.Attributes["displaySupported"] = "YES";
            }
            else
            {
                session.Attributes["displaySupported"] = "NO";
            }
        }
        else
        {
            session.Attributes["displaySupported"] = "NO";
        }

        if (!string.IsNullOrEmpty(session.Attributes["displaySupported"]) == true)
        {
            if (session.Attributes["displaySupported"] == "YES")
            {
                SimpleCard card = new SimpleCard();
                card.Title = String.Format(speechletText + " - {0}", "Stop Alexa Skill");
                card.Subtitle = String.Format(speechletText + " - {0}", "Citizen Skills");
                card.Content = String.Format(speechletText + " - {0}", output);

                // Create the plain text output.
                // PlainTextOutputSpeech speech = new PlainTextOutputSpeech();

                // Create the SSML text output.
                SsmlOutputSpeech speech = new SsmlOutputSpeech();
                speech.Ssml = output.ToString();

                // Create the speechlet response.
                SpeechletResponse response = new SpeechletResponse();
                response.ShouldEndSession = shouldEndSession;
                response.OutputSpeech = speech;
                response.Card = null;

                if (!String.IsNullOrEmpty(repromptText))
                {
                    PlainTextOutputSpeech speech2 = new PlainTextOutputSpeech();
                    speech2.Text = repromptText;
                    Reprompt reprompt = new Reprompt();
                    reprompt.OutputSpeech = speech2;
                    response.Reprompt = reprompt;
                }

                /* Create a directive for Echo Show (example)
                 * This can be separeted so it can be easier to create
                 * a Show Directive where you can only need to write 
                 * the important information
                 */
                IList<AlexaSkillsKit.UI.EchoShowUI.Directive> listDirectiveTest = new List<AlexaSkillsKit.UI.EchoShowUI.Directive>();
                AlexaSkillsKit.UI.EchoShowUI.Directive directiveTest = new AlexaSkillsKit.UI.EchoShowUI.Directive();
                Template templateTest = new Template();
                AlexaSkillsKit.UI.EchoShowUI.Image backgroundTest = new AlexaSkillsKit.UI.EchoShowUI.Image();
                AlexaSkillsKit.UI.EchoShowUI.Image imageTest = new AlexaSkillsKit.UI.EchoShowUI.Image();

                IList<AlexaSkillsKit.UI.EchoShowUI.Source> backgroundSourcesTest = new List<AlexaSkillsKit.UI.EchoShowUI.Source>();
                IList<AlexaSkillsKit.UI.EchoShowUI.Source> imageSourcesTest = new List<AlexaSkillsKit.UI.EchoShowUI.Source>();

                directiveTest.Type = "Display.RenderTemplate";
                //Display.RenderTemplate
                /*
                 * 
                 * 
                 * 

                 The values for size are listed in the following table.
                Property    Description Recommended Size (in pixels)
                Width x Height
                X_SMALL Displayed within extra small containers 480 x 320
                SMALL   Displayed within small containers   720 x 480
                MEDIUM  Displayed within medium containers  960 x 640
                LARGE   Displayed within large containers   1200 x 800
                X_LARGE Displayed within extra large containers 1920 x 1280

                */

                //                    {
                //                        "directives": [
                //                          {
                //      "type": "Hint",
                //                            "hint": {
                //        "type": "PlainText",
                //                              "text": "string"
                //      }
                //}
                //  ]
                //}

                //If you want an overlay of text on top of a background image, you must include the overlay in the image itself. A 70% opacity black layer is recommended for optimal contrast.
                // With the backgroundImage field, the display size is the same as for the Echo Show screen: 1024px x 600px.
                AlexaSkillsKit.UI.EchoShowUI.Source backgroundSource = new AlexaSkillsKit.UI.EchoShowUI.Source();
                backgroundSource.Url = apiURL + "images/Love_New_York.png"; // "URL for the background image - must be secure (https)";
                backgroundSource.Size = "MEDIUM";
                backgroundSource.heightPixels = 1024;
                backgroundSource.widthPixels = 600;

                //BodyTemplate2(image right) 340 x 340
                //BodyTemplate3(image left)  340 x 340
                //BodyTemplate6(full - screen image with text overlay) 340 x 340
                AlexaSkillsKit.UI.EchoShowUI.Source imageSource = new AlexaSkillsKit.UI.EchoShowUI.Source();
                imageSource.Url = apiURL + "images/stop_cancel.png"; // "URL for the main image - must be secure (https)";
                imageSource.Size = "SMALL";
                imageSource.heightPixels = 600;
                imageSource.widthPixels = 415;

                backgroundSourcesTest.Add(backgroundSource);
                imageSourcesTest.Add(imageSource);

                backgroundTest.ContentDescription = "I love New York";
                backgroundTest.Sources = backgroundSourcesTest;

                imageTest.ContentDescription = "Stop";
                imageTest.Sources = imageSourcesTest;

                TextContent textContentTest = new TextContent();
                MainContentText primaryContentTest = new MainContentText();
                MainContentText secondaryContentTest = new MainContentText();
                MainContentText tertiaryContentTest = new MainContentText();

                primaryContentTest.Text = "Thank you for using the Alexa Skill. <br/><br/>" +
                "Let's chat again soon!";

                primaryContentTest.Type = "RichText";

                secondaryContentTest.Text = "";
                secondaryContentTest.Type = "RichText";

                tertiaryContentTest.Text = "";
                tertiaryContentTest.Type = "RichText";

                textContentTest.PrimaryText = primaryContentTest;
                textContentTest.SecondaryText = secondaryContentTest;
                textContentTest.TertiaryText = tertiaryContentTest;

                templateTest.Title = "Alexa Skill Stop";
                templateTest.BackButton = "HIDDEN";
                templateTest.BackgroundImage = backgroundTest;
                templateTest.Image = imageTest;
                templateTest.Type = "BodyTemplate2";
                templateTest.Token = "";
                templateTest.TextContent = textContentTest;

                directiveTest.Template = templateTest;

                listDirectiveTest.Add(directiveTest);

                AlexaSkillsKit.UI.EchoShowUI.Directive directiveTest2 = new AlexaSkillsKit.UI.EchoShowUI.Directive();
                directiveTest2.Type = "Hint";
                AlexaSkillsKit.UI.EchoShowUI.RenderHint hint = new RenderHint();
                hint.Type = "PlainText";
                hint.Text = "Ask for Practice Test";
                directiveTest2.Hint = hint;
                listDirectiveTest.Add(directiveTest2);

                response.Directives = listDirectiveTest;

                //
                //string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(response);
                //
                return response;
            }
        }

        return BuildSpeechletResponseSSML2_img("Help", "Help Public SKills", output.ToString(), outputCard.ToString(), shouldEndSession, repromptText, "HelpSM.png", "HelpLG.png");
    }
ElvenMonky commented 6 years ago

Well, I've just enabled Display Interface for my skill and tested it with Service Simulator. Following request was produced:

{
  "session": { ... },
  "request": { ... },
  "context": {
    "System": {
      "application": { ... },
      "user": { ... },
      "device": {
        "supportedInterfaces": {
          "Display": {
            "templateVersion": "1",
            "markupVersion": "1"
          }
        }
      }
    }
  },
  "version": "1.0"
}

and (context.System.Device.SupportedInterfaces["Display"] as DisplayInterface).TemplateVersion successfully returned "1" for me.

In spite of "templateVersion" attribute being currently mentioned by official documentation I suspect some tools can still return "Display": {} as an indication of Display interface support. What tools or devices do you use to send requests to your skill and could you provide the "supportedInterfaces" object contents from received JSON?

In a mean time, i believe, "Display": {} has to be handled as if

"Display": {
  "templateVersion": "1",
  "markupVersion": "1"
}

was sent, so I will modify PR #53 accordingly.

ElvenMonky commented 6 years ago

Also, while I now see that there is some official documentation about Display.ElementSelected, it lacks proper parameters description and has no information whether session object is available with this request, and nothing about desired skill response.

petersantiago commented 6 years ago

Hello! I decided to try and use the library to stream a video. As I said above, I have a working library - minus video and did not want to keep updating on my own. Looking to convert to use latest. For testing I typically test from the device using Visual Studio in Debug mode. If you have any simpler methods, I would be open to suggestions. Do you have an example streaming a video?

Thanks so much! Willing to share the library I have modified if it can help anyone with the listTemplate and Display.ElementSelected. I have used it extensively for both BodyTemplate and ListTemplate.

The code is not working as expected. For one thing, the "type": "VideoApp.Launch", is not being passed in the request?

Expected Response from Amazon: { "version": "1.0", "sessionAttributes": null, "response": { "outputSpeech": null, "card": null, "directives": [ { "type": "VideoApp.Launch", "videoItem": { "source": "https://alexaskillskitmentor20171206110854.azurewebsites.net/video/SampleVideo_1280x720_1mb.mp4", "metadata": { "title": "Title for Sample Video", "subtitle": "Secondary Title for Sample Video"
} } }
], "reprompt": null } }

Response Coming from the Library called below:

{ "version": "1.0", "response": { "speechletResponse": { "directives": [ { "videoItem": { "source": "https://aaaaaaa20171206110854.azurewebsites.net/video/SampleVideo_1280x720_1mb.mp4", "metadata": { "title": "pjs1", "subtitle": "pjs2" } } }, { "template": { "title": { "richText": "ny mentor" }, "backButtonBehavior": "VISIBLE" } } ] } }, "sessionAttributes": { "intentSequence": "GetVideoResponseIntent", "displaySupported": "YES" } }

Here is the source:

private SpeechletResponse GetVideoResponseHandler(IntentRequest request, Session session, Context context) { // Create the speechlet response. SpeechletResponse response = new SpeechletResponse(); //response.ShouldEndSession = null; The shouldEndSession parameter must not be included in the response, even if the value is set to null. response.OutputSpeech = null; response.Card = null;

        string display = (context.System.Device.SupportedInterfaces["Display"] as DisplayInterface).TemplateVersion;

        if (display != null)
        {
            if (!string.IsNullOrEmpty(display) == true)
            {
                session.Attributes["displaySupported"] = "YES";
            }
            else
            {
                session.Attributes["displaySupported"] = "NO";
            }
        }
        else
        {
            session.Attributes["displaySupported"] = "NO";
        }

        if (!string.IsNullOrEmpty(session.Attributes["displaySupported"]) == true)
        {
            if (session.Attributes["displaySupported"] == "YES")
            {
                IList<AlexaSkillsKit.Speechlet.Directive> listDirectiveTestA = new List<AlexaSkillsKit.Speechlet.Directive>();
                AlexaSkillsKit.Speechlet.Directive directiveTest = BuildEchoShowVideoAppResponse("pjs1", "pjs2", apiURL + "video/SampleVideo_1280x720_1mb.mp4");
                listDirectiveTestA.Add(directiveTest);

                response.Directives = listDirectiveTestA;

                 //use to see the result
                //string jsonString1 = Newtonsoft.Json.JsonConvert.SerializeObject(response);

                return response;
            }
        }
        return response;
    }
ElvenMonky commented 6 years ago

Thanks for your effort in applying and testing my changes! Usually, I use Postman to send requests to service locally.

Could you, please, share contents of BuildEchoShowVideoAppResponse method? From your previous code I can see that you had your own AlexaSkillsKit.UI.EchoShowUI.Directive implementation, where you needed to set value for Type field explicitly. Might it be an issue, explaining results you've got above?

I've tried your code with

public Directive BuildEchoShowVideoAppResponse(string title, string subtitle, string source) {
    return new AlexaSkillsKit.Interfaces.VideoApp.Directives.VideoAppLaunchDirective {
        VideoItem = new AlexaSkillsKit.Interfaces.VideoApp.VideoItem {
            Source = source,
            Metadata = new AlexaSkillsKit.Interfaces.VideoApp.VideoItemMetadata {
                Title = title,
                Subtitle = subtitle
            }
        }
    };
}

and response was as expected:

{
    "response": {
        "directives": [
            {
                "videoItem": {
                    "source": "https://aaa.azurewebsites.net/video/SampleVideo_1280x720_1mb.mp4",
                    "metadata": {
                        "title": "pjs1",
                        "subtitle": "pjs2"
                    }
                },
                "type": "VideoApp.Launch"
            }
        ]
    },
    "sessionAttributes": {
        "intentSequence": "GetVideoResponseIntent"
    },
    "version": "1.0"
}
petersantiago commented 6 years ago

Hi, I appreciate your feedback and enjoy testing this project. You have done excellent work!!

Are you using this version of the LIB? https://github.com/ElvenMonky/AlexaSkillsKit.NET

I am using this library. The old code I demonstrated in a few previous email used my edited version (ECHOSHOW.UI.

I am using the one from the link above.

However...using the library gives an error....in the Session Management... Object Reference Not set on the request.Intent.Slots.Values. foreach (var slot in request.Intent.Slots.Values)

I do think calling " DoSessionManagement(request as IntentRequest, session);" at top of DoProcessRequest is causing issue??

private string DoProcessRequest(SpeechletRequestEnvelope requestEnvelope) { var session = requestEnvelope.Session; var context = requestEnvelope.Context; var request = requestEnvelope.Request; ISpeechletResponse response = null;

        // Do session management prior to calling OnSessionStarted and OnIntentAsync 
        // to allow dev to change session values if behavior is not desired
        DoSessionManagement(request as IntentRequest, session);

        if (requestEnvelope.Session.IsNew) {
            OnSessionStarted(
                new SessionStartedRequest(request.RequestId, request.Timestamp, request.Locale), session);
        }

private void DoSessionManagement(IntentRequest request, Session session) { if (request == null) return;

        if (session.IsNew) {
            session.Attributes[Session.INTENT_SEQUENCE] = request.Intent.Name;
        }
        else {
            // if the session was started as a result of a launch request 
            // a first intent isn't yet set, so set it to the current intent
            if (!session.Attributes.ContainsKey(Session.INTENT_SEQUENCE)) {
                session.Attributes[Session.INTENT_SEQUENCE] = request.Intent.Name;
            }
            else {
                session.Attributes[Session.INTENT_SEQUENCE] += Session.SEPARATOR + request.Intent.Name;
            }
        }

            // Auto-session management: copy all slot values from current intent into session
            **foreach (var slot in request.Intent.Slots.Values)**
            {
                session.Attributes[slot.Name] = slot.Value;
            }

    }

Thanks!!

Peter

petersantiago commented 6 years ago

Using the Simulator with Amazon..... Using the library noted above

public Directive BuildEchoShowVideoAppResponse(string title, string subtitle, string source) { return new AlexaSkillsKit.Interfaces.VideoApp.Directives.VideoAppLaunchDirective { VideoItem = new AlexaSkillsKit.Interfaces.VideoApp.VideoItem { Source = source, Metadata = new AlexaSkillsKit.Interfaces.VideoApp.VideoItemMetadata { Title = title, Subtitle = subtitle } } }; }

private SpeechletResponse GetVideoResponseHandler(IntentRequest request, Session session, Context context) { // Create the speechlet response. SpeechletResponse response = new SpeechletResponse(); //response.ShouldEndSession = null; The shouldEndSession parameter must not be included in the response, even if the value is set to null. response.OutputSpeech = null; response.Card = null;

        string display = (context.System.Device.SupportedInterfaces["Display"] as DisplayInterface).TemplateVersion;

        if (display != null)
        {
            if (!string.IsNullOrEmpty(display) == true)
            {
                session.Attributes["displaySupported"] = "YES";
            }
            else
            {
                session.Attributes["displaySupported"] = "NO";
            }
        }
        else
        {
            session.Attributes["displaySupported"] = "NO";
        }

        if (!string.IsNullOrEmpty(session.Attributes["displaySupported"]) == true)
        {
            if (session.Attributes["displaySupported"] == "YES")
            {
                IList<AlexaSkillsKit.Speechlet.Directive> listDirectiveTestA = new List<AlexaSkillsKit.Speechlet.Directive>();
                AlexaSkillsKit.Speechlet.Directive directiveTest = BuildEchoShowVideoAppResponse("pjs1", "pjs2", apiURL + "video/SampleVideo_1280x720_1mb.mp4");
                listDirectiveTestA.Add(directiveTest);

                response.Directives = listDirectiveTestA;

                string jsonString1 = Newtonsoft.Json.JsonConvert.SerializeObject(response);

                return response;
            }
        }
        return response;
    }

Service Request Created { "session": { "new": true, "sessionId": "SessionId.6ad4c67b-b63c-442a-ad0c-446890f400d0", "application": { "applicationId": "amzn1.ask.skill.5d2da8bf-a2b4-45d4-bca4-0aae9da61130" }, "attributes": {}, "user": { "userId": "amzn1.ask.account.AGZDL3SKZORNYERRFCWVMBRPPX6TVQKHYEB4SJP75MSEHN7EXTMCTNXSPESYWDNLW53KQHT72CMRG3Q5V24H23L66QER6MP433LZ3ZZMUFNPTFKWYB3FK7FDGJHXXVB3KQFGHLSZQBF5HP26EYENLRZMDSKFOGDFIVRNYSNEAX4PZUVI4KRGTITOEP7BEOHZDPYTOAJD55JHSEI" } }, "request": { "type": "IntentRequest", "requestId": "EdwRequestId.31e4b09b-633c-48b7-b599-c4051b4d07d3", "intent": { "name": "GetVideoResponseIntent", "slots": {} }, "locale": "en-US", "timestamp": "2017-12-11T11:03:23Z" }, "context": { "AudioPlayer": { "playerActivity": "IDLE" }, "System": { "application": { "applicationId": "amzn1.ask.skill.5d2da8bf-a2b4-45d4-bca4-0aae9da61130" }, "user": { "userId": "amzn1.ask.account.AGZDL3SKZORNYERRFCWVMBRPPX6TVQKHYEB4SJP75MSEHN7EXTMCTNXSPESYWDNLW53KQHT72CMRG3Q5V24H23L66QER6MP433LZ3ZZMUFNPTFKWYB3FK7FDGJHXXVB3KQFGHLSZQBF5HP26EYENLRZMDSKFOGDFIVRNYSNEAX4PZUVI4KRGTITOEP7BEOHZDPYTOAJD55JHSEI" }, "device": { "supportedInterfaces": { "Display": { "templateVersion": "1", "markupVersion": "1" } } } } }, "version": "1.0" }

Service Response Created { "version": "1.0", "response": { "speechletResponse": { "directives": [ { "videoItem": { "source": "https://alexaskillskitmentor20171206110854.azurewebsites.net/video/SampleVideo_1280x720_1mb.mp4", "metadata": { "title": "pjs1", "subtitle": "pjs2" } } }, { "template": { "title": { "richText": "ny mentor" }, "backButtonBehavior": "VISIBLE" } } ] } }, "sessionAttributes": { "intentSequence": "GetVideoResponseIntent", "displaySupported": "YES" } }

This is not proper? For the error from the previous method, I added a simply try catch to bypass when Object Reference Null on Slots (Allows for testing to show results)

Thanks again!!

petersantiago commented 6 years ago

Please forget last messages. Using the ECHO SHOW itself it works. Simulator provides an odd response.

In debug mode, I can grab value using ECHOSHOW and is proper and shows video. {"response":{"directives":[{"videoItem":{"source":"https://alexaskillskitmentor20171206110854.azurewebsites.net/video/SampleVideo_1280x720_1mb.mp4","metadata":{"title":"pjs1","subtitle":"pjs2"}},"type":"VideoApp.Launch"}]},"sessionAttributes":{"intentSequence":"GetVideoResponseIntent","displaySupported":"YES"},"version":"1.0"} POST /alexa/sample-session HTTP/1.1

However the issue with the SLOTS will cause error?

Are you using this version of the LIB? https://github.com/ElvenMonky/AlexaSkillsKit.NET

I am using this library. The old code I demonstrated in a few previous email used my edited version (ECHOSHOW.UI.

I am using the one from the link above.

However...using the library gives an error....in the Session Management... Object Reference Not set on the request.Intent.Slots.Values. foreach (var slot in request.Intent.Slots.Values)

I do think calling " DoSessionManagement(request as IntentRequest, session);" at top of DoProcessRequest is causing issue??

Thanks again!!

petersantiago commented 6 years ago

I also check the AppID in my code, not sure where in the current library it does that? I handle it in the Speechlet.CS in my edited version.

public virtual HttpResponseMessage GetResponse(HttpRequestMessage httpRequest) {

/////////////////////////////////////////// // check app id--- add back for after the demo ////////////////////////////////////////// if (alexaRequest != null) { if (!SpeechletRequestTimestampVerifier.VerifyApplicationIdHeader(alexaRequest)) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidAppId; } }

Thanks again!

Peter

petersantiago commented 6 years ago

Here is how I have done it... Modified SpeechletRequestValidationResult.cs added InvalidAppId = 32

namespace AlexaSkillsKit.Authentication { [Flags] public enum SpeechletRequestValidationResult { OK = 0, NoSignatureHeader = 1, NoCertHeader = 2, InvalidSignature = 4, InvalidTimestamp = 8, InvalidJson = 16, InvalidAppId = 32 } }

Modified SpeechletRequestTimestampVerifier.cs and added the method VerifyApplicationIdHeader Added a DEV and PROD application ID so I can test different versions of Azure API

public static bool VerifyApplicationIdHeader(SpeechletRequestEnvelope alexaRequest) {

        string mode = ConfigurationManager.AppSettings["mode"];
        string alexaApplicationId = "dev";

        if (mode != "dev")
        {
            alexaApplicationId = ConfigurationManager.AppSettings["AlexaApplicationIdPROD"];
        }
        else
        {
            alexaApplicationId = ConfigurationManager.AppSettings["AlexaApplicationId"];
        }

        return alexaRequest.Session.Application.Id.Equals(alexaApplicationId);
    }

In the Speechlet.CS check

/////////////////////////////////////////// // check app id--- add back for after the demo ////////////////////////////////////////// if (alexaRequest != null) { if (!SpeechletRequestTimestampVerifier.VerifyApplicationIdHeader(alexaRequest)) { validationResult = validationResult | SpeechletRequestValidationResult.InvalidAppId; } }

ElvenMonky commented 6 years ago

Regarding your second question, currently Application Id is not verified by a library. Note, that Session object is only included in standard requests. So, I'd recommend using alexaRequest.Context.System.Application.Id to verify Application Id.

You are absolutely right, that (DoSessionManagement and some other places in code) for non-standard requests will throw NullReferenceException when accessing Session object, which is null. I'll take an action to fix it. As for request.Intent.Slots.Values, it can only throw if mandatory "slots" field is absent from the Intent object, which I believe is incorrect request syntax.

petersantiago commented 6 years ago

Thank you so much! I have modified the code and is working properly. I have another question. Looking to use the HintDirective. I am getting error that Hint is Null?

Any help would be greatly appreciated!

Have defined the following:

               IList<Directive> listDirectiveTest = new List<Directive>();
                DisplayRenderTemplateDirective directiveTest = new DisplayRenderTemplateDirective();
                DisplayTemplate templateTest = new DisplayTemplate();
                DisplayImage backgroundTest = new DisplayImage();
                DisplayImage imageTest = new DisplayImage();

                directiveTest.Template = templateTest;
                listDirectiveTest.Add(directiveTest);

                HintDirective directiveTest2 = new HintDirective();
                **directiveTest2.Hint.Type = TextField.TextTypeEnum.PlainText;**
                directiveTest2.Hint.Text = "Open NY Mentor";
                listDirectiveTest.Add(directiveTest2);
                response.Directives = listDirectiveTest;

Peter

ElvenMonky commented 6 years ago

Well, should be also directiveTest2.Hint = new TextField(); or directiveTest2.Hint = new TextField { Text = "Open NY Mentor" }

ghost commented 6 years ago

Thank you! Appreciate it.
Can share completed project as sample once complete.

Peter

stefann42 commented 6 years ago

@ElvenMonky does release v1.6.0 resolve this issue?

ElvenMonky commented 6 years ago

Yes, the issue was resolved