LexResponse output does not understand HTML data - html

I'm having a problem trying to get my AWS Lambda function to successfully output a series of HTML links when its running a SQL Query.
private string GetEventSearchResults(ILambdaContext context, List<Event> events, string CustomerNumber)
{
var result = string.Empty;
var link = string.Empty;
if (events.Count > 0)
{
result = $"Events for {CustomerNumber}:";
foreach (var evt in events)
{
link = "http://localhost/event/" + $"{evt.ID}";
result += $"<br>Event: {evt.ID} - Status: {evt.Status}";
}
}
else
{
result = "No Data found matching your query";
}
return result;
}
When this method is called by my Lambda function as a LexResponse,
replyMessage = GetEventSearchResults(context, eventList, query.CustomerNumber);
return Close(
sessionAttributes,
"Fulfilled",
new LexResponse.LexMessage
{
ContentType = "PlainText",
Content = replyMessage
}
);
This response is then rendered in my HTML page by a Javascript function. Relevant portion of the Javascript that renders the response:
function showResponse(lexResponse) {
var conversationDiv = document.getElementById('conversation');
var responsePara = document.createElement("P");
responsePara.className = 'lexResponse';
if (lexResponse.message) {
responsePara.appendChild(document.createTextNode(lexResponse.message));
responsePara.appendChild(document.createElement('br'));
}
if (lexResponse.dialogState === 'ReadyForFulfillment') {
responsePara.appendChild(document.createTextNode(
'Ready for fulfillment'));
// TODO: show slot values
}
conversationDiv.appendChild(responsePara);
conversationDiv.scrollTop = conversationDiv.scrollHeight;
}
However, the output shown by the Lex bot is as shown below:
Lex Bot Output
Can anyone please help me understand what exactly is going on? Is the content type of the Lex Response responsible for this? (there's only plaintext and SSML available for Lex Response so I can't change that)
Also, if possible, can anyone please explain how to fix this if at all possible? Thanks!

Your code is correct and output is also correct.
However the console window is not able to render the HTML part of your result.
The client on which you will deploy the chatbot, is responsible for rendering the output. For example, if you respond with a ResponseCard, console or website will not be able to render it correctly but it will be displayed correctly on Facebook and Slack. So, if you integrate your chatbot on some website it will show the links in your output correctly as you desired.
You can try to integrate your chatbot with Slack or Facebook first, to see the rendering of output.
Hope it helps.

After further trial and error, I managed to get a solution that works for me.
function showResponse(lexResponse) {
var conversationDiv = document.getElementById('conversation');
var responsePara = document.createElement("P");
responsePara.className = 'lexResponse';
if (lexResponse.message) {
var message = lexResponse.message.replace(/"/g, '\'');
responsePara.innerHTML = message;
responsePara.appendChild(document.createElement('br'));
}
conversationDiv.appendChild(responsePara);
conversationDiv.scrollTop = conversationDiv.scrollHeight;
}
By making the LexResponse an Inner HTML, it fixed the markup of the text and thus the link can be seen everytime.

Related

How to get clean json from wikipedia API

I want to get the result from a wikipedia page https://en.wikipedia.org/wiki/February_2 as JSON.
I tried using their API: https://en.wikipedia.org/w/api.php?action=parse&page=February_19&prop=text&formatversion=2&format=json
Though it is giving it as Json format. The content is HTML. I want only the content.
I need a way to get clean result.
If you want plain text without markup, you have first to parse the JSON object and then extract the text from the HTML code:
function htmlToText(html) {
let tempDiv = document.createElement("div");
tempDiv.innerHTML = html;
return tempDiv.textContent || tempDiv.innerText || "";
}
const url = 'https://en.wikipedia.org/w/api.php?action=parse&page=February_19&prop=text&format=json&formatversion=2&origin=*';
$.getJSON(url, function(data) {
const html = data['parse']['text'];
const plainText = htmlToText(html);
const array = [...plainText.matchAll(/^\d{4} *–.*/gm)].map(x=>x[0]);
console.log(array);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Update: I edited the code above according to the comment below. Now the function extracts all the list items putting them into an array.
I guess by clean you mean the source wikitext. In that case you can use the revisions module:
https://en.wikipedia.org/w/api.php?action=query&titles=February_2&prop=revisions&rvprop=content&formatversion=2&format=json
See API:Get the contents of a page and API:Revisions for more info.

Creating a basic chatbar?

Below is old; look at the updated text at the bottom.
So my friends and I use google docs to communicate while in school, and we setup the challenge to create a working and "efficient" chat bar to communicate with better results. I've been around JavaScript for quite some time, but have never fooled around with Google Apps Script before. We are using the document app for our chats; the code I came up with is as below, but I have a few problems with it:
Errors when a user closes it, then goes to Chat -> Open Chat in the toolbar to re-open, saying, "Error encountered: An unexpected error occurred"; does not specify a line or reason
Needs a hidden element somewhere in the document which can allow users to see what others have typed, but that they can't edit without using the chat box (would add event listener to update chat box when text is ammended)
//Main function, ran when the document first opens.
function onOpen() {
var app = UiApp.createApplication(); //Create a Ui App to use for the chat bar
if(getCurrentUser()=="dev1"||getCurrentUser()=="dev2"){ //user-Id's hidden for privacy
DocumentApp.getUi().createMenu('Chat')
.addItem('AutoColor', 'autoColor')
.addItem('Open Chat', 'createChatBox')
.addItem('Elements', 'displayElements') //Hidden as it is not important for regular use
.addItem('MyID', 'showUser')
.addToUi();
}else{
DocumentApp.getUi().createMenu('Chat')
.addItem('AutoColor', 'autoColor')
.addItem('Open Chat', 'createChatBox')
.addToUi();
}
}
//Creates and returns the chats GUI
function createChatBox(){
var app = UiApp.getActiveApplication()
app.setTitle("Chat Bar (not yet working)");
var vPanel = app.createVerticalPanel().setId('chatPanel').setWidth('100%');
var textArea = app.createTextArea().setId('chatBox').setName('chatBox').setReadOnly(true).setText('').setSize('250px', '450px'); //Read only so they can not edit the text, even if it won't affect overall chat
var textBox = app.createTextBox().setId('messageBox').setName('messageBox').setText('Words');
var chatHandler = app.createServerHandler("sayChat").addCallbackElement(textArea).addCallbackElement(textBox);
var chatButton = app.createButton().setId("sayButton").setText("Say!").addMouseUpHandler(chatHandler);
vPanel.add(textArea);
vPanel.add(textBox);
vPanel.add(chatButton);
app.add(vPanel);
DocumentApp.getUi().showSidebar(app);
return app;
}
//The event handler for when the "Say!" (post) button is pressed. Is probably where the conflict stems from.
function sayChat(eventInfo){
var app = UiApp.getActiveApplication();
var parameter = eventInfo.parameter;
app.getElementById("chatBox").setText(parameter.chatBox+"["+getCurrentUser()+"]: "+parameter.messageBox);
app.getElementById("messageBox").setText("");
return app;
}
//A debug function and a function to tell you the unique part of your email (useless, really)
function showUser(){
DocumentApp.getUi().alert("Your userId is: "+getCurrentUser());
}
//Returns the unique part of a person's email; if their email is "magicuser#gmail.com", it returns "magicuser"
function getCurrentUser(){
var email = Session.getActiveUser().getEmail();
return email.substring(0,email.indexOf("#"));
}
//The Auto-color and displayElements methods are hidden as they contain other user-info. They both work as intended and are not part of the issue.
I do not need someone to rewrite the code (although that'd be greatly appreciated!), but instead point out what I'm doing wrong or suggest something to change/add.
Last, before you suggest it, the google docs chat does not work with our computers. It is not the fault of the document, but probably a compatability error with our browser. It is because of this issue that we are going through this fun yet hasty process of making our own chat method.
Update
I decided to give up on my version of the chat using pure Google Apps Script and help improve my friends version using both G-A-S and HTML. I added image thumbnail/linking support with command /img or /image, along with improved time and counter, and some other behind the scenes updates. Here is a quick screenshot of it:
Magnificent chat programmed from scratch, and no buggy update methods, just a casual refresh database to check for messages and set HTML text-area text. No more buggy getText methods. For each new message in the database, whether targeted toward the user or toward everyone in the chat, we load all the database messages up to a limit (50 messages at a time), then display them. The use of HTML in the messages is key to its appearence and features, such as images.
function getChat() {
var chat = "";
var time = getTime();
var username = getCurrentUsername();
var db = ScriptDb.getMyDb();
var query = db.query({time : db.greaterThan(getJoinTime())}).sortBy('time', db.DESCENDING).limit(50);
var flag = query.getSize() % 2 != 0;
while(query.hasNext()) {
var record = query.next();
if(record.showTo == "all" || record.showTo == getCurrentUsername()) {
var text = record.text;
for(var i = 0; i < text.split(" ").length; i++) {
var substr = text.split(" ")[i];
if(substr.indexOf("http://") == 0 || substr.indexOf("https://") == 0) {
text = text.replace(substr, "<a href='" + substr + "'>" + substr + "</a>");
}
}
var message = "<pre style='display:inline;'><span class='" + (flag? "even" : "odd") + "'><b>[" + record.realTime + "]</b>" + text;
message += "</span></pre>";
chat += message;
flag = !flag;
}
}
//DocumentApp.getUi().alert(getTime() - time);
return chat;
}
I am going to re-do his getChat() method to only check for new messages, and not load every message at each refresh.
First thing to to to get rid of your error message is to create the UiApp in the createChat function instead of onOpen.
I also used a client handler to clear the textBox because it's just more efficient. Here is the modified code :
code removed see updates below
As for your second request I'm not sure I understand exactly what you want to do... could you explain more precisely the behavior you expect ? (this is more a comment than an answer but I used the "answer field" to be more readable)
EDIT : I played a little with this code and came to something that -almost- works... it still needs to be improved but it's worth showing how it works.
I used scriptProperties to store the common part of the conversation, I think that's a good approach but the issue it to know when to update its content. Here is the code I have so far, I keep being open to any suggestion/improvement of course.
code removed, new version below
EDIT 2 : here is a version with an auto update that works quite good, the script updates the chat area automatically for a certain time... if no activity then it stops and wait for a user action. please test (using 2 accounts) and let us know what you think.
note I used a checkBox to handler the autoUpdate, I keep it visible for test purpose but of course it could be hidden in a final version.
EDIT 3 : added a message to warn the user when he's been put offline + changed textBox to colored textArea to allow for longer messages + condition to clear the messageBox so that the warning message doesn't go in the conversation. (set the time out to a very short value for test purpose, change the counter value to restore to your needs)
function onOpen() {
if(getCurrentUser()=="dev1"||getCurrentUser()=="dev2"){ //user-Id's hidden for privacy
DocumentApp.getUi().createMenu('Chat')
.addItem('AutoColor', 'autoColor')
.addItem('Open Chat', 'createChatBox')
.addItem('Elements', 'displayElements') //Hidden as it is not important for regular use
.addItem('MyID', 'showUser')
.addToUi();
}else{
DocumentApp.getUi().createMenu('Chat')
.addItem('AutoColor', 'autoColor')
.addItem('Open Chat', 'createChatBox')
.addToUi();
}
}
function createChatBox(){
ScriptProperties.setProperty('chatContent','');
var app = UiApp.createApplication().setWidth(252);
app.setTitle("Chat Bar");
var vPanel = app.createVerticalPanel().setId('chatPanel').setWidth('100%');
var chatHandler = app.createServerHandler("sayChat").addCallbackElement(vPanel);
var textArea = app.createTextArea().setId('chatBox').setName('chatBox').setReadOnly(true).setText('').setSize('250px', '450px');
var textBox = app.createTextArea().setId('messageBox').setName('messageBox').setText('Start chat...').setPixelSize(250,100).setStyleAttributes({'padding':'5px','background':'#ffffcc'}).addKeyPressHandler(chatHandler);
var clearTextBoxClientHandler = app.createClientHandler().forTargets(textBox).setText('');
textBox.addClickHandler(clearTextBoxClientHandler);
var chatButton = app.createButton().setId("sayButton").setText("Say!").addMouseUpHandler(chatHandler);
var chkHandler = app.createServerHandler('autoUpdate').addCallbackElement(vPanel);
var chk = app.createCheckBox().setId('chk').addValueChangeHandler(chkHandler);
vPanel.add(textArea);
vPanel.add(textBox);
vPanel.add(chatButton);
vPanel.add(chk);
app.add(vPanel);
DocumentApp.getUi().showSidebar(app);
return app;
}
function sayChat(e){
var app = UiApp.getActiveApplication();
var user = '['+getCurrentUser()+'] : ';
if(e.parameter.messageBox=="You have been put offline because you didn't type anything for more than 5 minutes..., please click here to refresh the conversation"){
app.getElementById('messageBox').setText('');// clear messageBox
ScriptProperties.setProperty('chatTimer',0);// reset counter
return app;
}
if(e.parameter.source=='messageBox'&&e.parameter.keyCode!=13){return app};
var content = ScriptProperties.getProperty('chatContent');
ScriptProperties.setProperty('chatContent',content+"\n"+user+e.parameter.messageBox)
app.getElementById("chatBox").setText(content+"\n"+user+e.parameter.messageBox+'\n');
app.getElementById('messageBox').setText('');
app.getElementById('chk').setValue(true,true);
ScriptProperties.setProperty('chatTimer',0);
return app;
}
function autoUpdate(){
var app = UiApp.getActiveApplication();
var content = ScriptProperties.getProperty('chatContent');
var counter = Number(ScriptProperties.getProperty('chatTimer'));
++counter;
if(counter>20){
app.getElementById('chk').setValue(false);
app.getElementById('messageBox').setText("You have been put offline because you didn't type anything for more than 5 minutes..., please click here to refresh the conversation");
return app;
}
ScriptProperties.setProperty('chatTimer',counter);
var content = ScriptProperties.getProperty('chatContent');
app.getElementById("chatBox").setText(content+'*'); // the * is there only for test purpose
app.getElementById('chk').setValue(false);
Utilities.sleep(750);
app.getElementById('chk').setValue(true,true).setText('timer = '+counter);
return app;
}
function showUser(){
DocumentApp.getUi().alert("Your userId is: "+getCurrentUser());
}
function getCurrentUser(){
var email = Session.getEffectiveUser().getEmail();
return email.substring(0,email.indexOf("#"));
}

innerHTML call to receive a url

I am trying to make a call so that when a title of a video is clicked on in my playlist, it will call back a particular videos url to be shown in the metadata field box that I have created.
So far I am getting results but the function below that I am using is giving me rmtp url's like this:
(rtmp://brightcove.fcod.llnwd.net/a500/d16/&mp4:media/1978114949001/1978114949001_2073371902001_How-to-Fish-the-Ice-Worm.mp4&1358870400000&7b1c5b2e65a7c051419c7f50bd712b1b
)
Brightcove has said to use (FLVURL&media_delivery=http).
I have tried every way I know of to put a media delivery in my function but always come up with nothing but the rmtp or a blank.
Can you please help with the small amount of code I have shown. If I need to show more that is not a problem. Thanks
function showMetaData(idx) {
$("tr.select").removeClass("select");
$("#tbData>tr:eq("+idx+")").addClass("select");
var v = oCurrentVideoList[idx];
//URL Metadata
document.getElementById('divMeta.FLVURL').innerHTML = v.FLVURL;
Here is my Population call for my list.
//For PlayList by ID
function buildMAinVideoList() {
//Wipe out the old results
$("#tbData").empty();
console.log(oCurrentMainVideoList);
oCurrentVideoList = oCurrentMainVideoList;
// Display video count
document.getElementById('divVideoCount').innerHTML = oCurrentMainVideoList.length + " videos";
document.getElementById('nameCol').innerHTML = "Video Name";
//document.getElementById('headTitle').innerHTML = title;
document.getElementById('search').value = "Search Videos";
document.getElementById('tdMeta').style.display = "block";
document.getElementById('searchDiv').style.display = "inline";
document.getElementById('checkToggle').style.display = "inline";
$("span[name=buttonRow]").show();
$(":button[name=delFromPlstButton]").hide();
//For each retrieved video, add a row to the table
var modDate = new Date();
$.each(oCurrentMainVideoList, function(i,n){
modDate.setTime(n.lastModifiedDate);
$("#tbData").append(
"<tr style=\"cursor:pointer;\" id=\""+(i)+"\"> \
<td>\
<input type=\"checkbox\" value=\""+(i)+"\" id=\""+(i)+"\" onclick=\"checkCheck()\">\
</td><td>"
+n.name +
"</td><td>"
+(modDate.getMonth()+1)+"/"+modDate.getDate()+"/"+modDate.getFullYear()+"\
</td><td>"
+n.id+
"</td><td>"
+((n.referenceId)?n.referenceId:'')+
"</td></tr>"
).children("tr").bind('click', function(){
showMetaData(this.id);
})
});
//Zebra stripe the table
$("#tbData>tr:even").addClass("oddLine");
//And add a hover effect
$("#tbData>tr").hover(function(){
$(this).addClass("hover");
}, function(){
$(this).removeClass("hover");
});
//if there are videos, show the metadata window, else hide it
if(oCurrentMainVideoList.length > 1){showMetaData(0);}
else{closeBox("tdMeta");}
}
If looking for HTTP paths, when the API call to Brightcove is correct you won't see the rtmp:// urls.
Since you're getting the rtmp URLs, this verifies you're using an API token with URL access, which is good. A request like this should return the playlist and the http URLs (insert your token and playlist ID).
http://api.brightcove.com/services/library?command=find_playlist_by_id&token={yourToken}&playlist_id={yourPlaylist}&video_fields=FLVURL&media_delivery=http
This API test tool can help build the queries for you, and show the expected results:
http://opensource.brightcove.com/tool/api-test-tool
I'm not seeing what would be wrong in your code, but in case you haven't tried this already, debugging in the browser can help you confirm the API results being returned, without having to access it via code. This help you root out any issues with the code you're using to access the values, vs problems with the values themselves. This is an overview on step-debugging in Chrome if you haven't used this before:
https://developers.google.com/chrome-developer-tools/docs/scripts-breakpoints

Accessing DOM object properties from Chrome's content script

I ran into a strange problem with a content script. The content script is defined as "run_at" : "document_end" in the manifest. After a page is loaded the script inserts an object tag into the page (if the tag with predefined id does not exist yet), and sets some properties in it, such as type, width, height, innerHTML, and title. All works fine here.
function checkForObject()
{
var obj = document.getElementById("unique_id");
if(obj == null)
{
var d = document.createElement("object");
d.id = "unique_id";
d.width = "1";
d.height = "1";
d.type = "application/x-y-z";
d.title = "1000";
d.style.position = "absolute";
d.style.left = "0px";
d.style.top = "0px";
d.style.zIndex = "1";
document.getElementsByTagName("body")[0].appendChild(d);
}
}
checkForObject();
I see the new object in the page html-code with proper values in its properties.
Some time later I need to read the title property of the object in the same content script. The code is simple:
function ReadTitle()
{
var obj = document.getElementById("unique_id");
var value = obj.title; // breakpoint
console.log(value);
// TODO: want to use proper title value here
}
The function is called from background.html page:
chrome.tabs.onActivated.addListener(
function(info)
{
chrome.tabs.executeScript(info.tabId, {code: 'setTimeout(ReadTitle, 250);'});
});
Unfortunately, in ReadTitle I'm getting not what I expect. Instead of current value of the title I see the logged value is:
function title() { [native code] }
If I set a breakpoint at the line marked by // breakpoint comment, I see in the watcher that all object properties including the title are correct. Nevertheless, the variable value gets the abovementioned descriptive string.
Apparently, I have missed something simple, but I can't figure it out.
The answer. It was a bug in the npapi plugin, which hosts the object of used type. My apologies for all who have read the question with intention to help.
The NPAPI plugin used in the object erroneously reported title as supported method.

Integrate Facebook Credits with AS3-SDK

I’m trying to integrate Facebook Credits as a paying method using the as3-sdk. I managed to get “earn_credits” and “buy_credits” working. However the third and most important option, “buy_item”, doesn’t show up the pay dialog. Somehow the connection to the callback.php seems the reason for the issue. Note: I have typed in the callback URL in my apps settings, so I didn’t forget that. I use the example php file from the Facebook Developer docs.
This is my as3 code.
public static function buyItem ():void
{
var theAction:String = "buy_item";
var order_info:Object = { "item_id":"1a" };
var jOrder:String = JSON.encode(order_info);
var data:Object = {
action:theAction,
order_info:jOrder,
dev_purchase_params: {"oscif":true}
};
Facebook.ui("pay", data, purchaseCallback);
}
I think the json encoding might be the problem, but i'm not sure.
I use the example php file from the Facebook Developer docs (excerpt):
<?php
$app_secret = '***********************';
// Validate request is from Facebook and parse contents for use.
$request = parse_signed_request($_POST['signed_request'], $app_secret);
// Get request type.
// Two types:
// 1. payments_get_items.
// 2. payments_status_update.
$request_type = $_POST['method'];
// Setup response.
$response = '';
if ($request_type == 'payments_get_items') {
// Get order info from Pay Dialog's order_info.
// Assumes order_info is a JSON encoded string.
$order_info = json_decode($request['credits']['order_info'], true);
// Get item id.
$item_id = $order_info['item_id'];
// Simulutates item lookup based on Pay Dialog's order_info.
if ($item_id == '1a') {
$item = array(
'title' => '100 some game cash',
'description' => 'Spend cash in some game.',
// Price must be denominated in credits.
'price' => 1,
'image_url' => '**********************/banner1.jpg',
);
// Construct response.
$response = array(
'content' => array(
0 => $item,
),
'method' => $request_type,
);
// Response must be JSON encoded.
$response = json_encode($response);
}
Any help, is really appreciated.
Okay so I cannot confirm that this works but according to this forum, it does:
var title:String = "TITLE FOO";
var desc:String = "FOO";
var price:String = "200";
var img_url:String = [some image url];
var product_url:String = [some product url];
// create order info object
var order_info:Object = {
"title":title,
"description":desc,
"price":price,
"image_url":img_url,
"product_url":product_url
};
// calling the API ...
var obj:Object = {
method: 'pay.prompt',
order_info: order_info,
purchase_type: 'item',
credits_purchase: false
};
Facebook.ui('pay', obj, callbackFunction);
I see that this example differs from yours slightly on the AS3 side so hopefully this nfo will help you resolve your problem. I realize that this isn't the best way to go about answering questions but I can see after a couple of days on here, no one has a answered you so I figured anything could help at this point. :)
Thank you #Ascension Systems!
This worked out well and is much better than creating a pop-up via html, and using navigateToURL etc...
One caveat though, which caused your solution not to work for me initially:
If you are relying on the callback.php sample provided by Facebook ( at the end of this page: http://developers.facebook.com/docs/credits/callback/ ), then you need to add this tag to your order_info object:
var item_id:String = "1a";
var order_info:Object = {
"title":title,
"description":desc,
"price":price,
"image_url":img_url,
"product_url":product_url,
"item_id":item_id
};
Without item_id defined, the if statement in Facebook's callback.php ( if ($item_id == '1a') ... ) will fail, and you'll get an unpleasant window: "App Not Responding
The app you are using is not responding. Please try again later."