JeanCarl's Adventures

Sentiment Bowl

February 07, 2016 |

The Super Bowl is happening this afternoon in the San Francisco Bay Area. There’s going to be (already is) a lot of activity on social media, with fans rooting for their favorite team to win the trophy. Fans on Twitter usually choose to positively support their team with words of encouragement, or talk negatively to the other team.

Photo

So which team has the more positive fans? Seems like a pretty simple problem to figure out. I created simple web app I call the Sentiment Bowl using the positive tweets being made around the two twitter handles @broncos (Denver Broncos) and the @panthers (Carolina Panthers). Using the Insights for Twitter service on IBM Bluemix, the score is settled based on how many positive tweets each team is mentioned in. You can find the running application at http://sentimentbowl.mybluemix.net

Photo

To get started, sign up for a free Bluemix account. Click on the Catalog link in the upper right corner of the dashboard.

We’ll use Node-RED, one of my favorite services in Bluemix because it has a graphical interface that makes prototyping quick and easy. Click on the Node-RED Starter under the Boilerplates section.

Photo

Give the application a name and a host. If you choose myapp, your application will be available at http://myapp.mybluemix.net.

Photo

The application will begin staging. Once it is running, click on the Overview link in the left sidebar. We want to add the Insights for Twitter service. Click on Add a Service or API.

Photo

Scroll down the catalog to the Data and Analytics section and choose the Insights for Twitter service.

Photo

Click on the Create button to create and bind the service to your application.

Photo

You’ll be prompted to restage the application. Click on Restage.

Photo

Once the application is running, click on Environment Variables. Copy the URL value under the twitterinsights.credentials.url property. Save this for later when we configure the application.

Photo

Visit the URL of your application. This is the homepage of Node-RED. Click on the red button labeled Go to your Node-RED flow editor.

Photo

On the left side is a palette of nodes that perform different actions. Some have a grey circle on the left, where you can connect inputs, and/or a grey circle on the right, where you connect outputs. Click and drag your cursor from output circles to input circles to create what are called flows.

Photo

To save you some time, you can import the nodes and the complete application. Click on the menu button in the top right corner. Click on Import and then Clipboard.

Photo

Copy the following JSON into the textbox:

[{"id":"5aeae2c1.f445cc","type":"inject","z":"4686641b.b9799c","name":"init","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":true,"x":153,"y":112,"wires":[["2dac8fd8.260108"]]},{"id":"9e50786.586cc88","type":"http request","z":"4686641b.b9799c","name":"","method":"GET","ret":"obj","url":"","x":417.5,"y":180,"wires":[["1cd41739.28a8f9"]]},{"id":"1cd41739.28a8f9","type":"function","z":"4686641b.b9799c","name":"","func":"context.global.team1Score = parseInt(msg.payload.search.results);\n","outputs":1,"noerr":0,"x":588.5,"y":179.5,"wires":[[]]},{"id":"5c6649b9.b4ed8","type":"http request","z":"4686641b.b9799c","name":"","method":"GET","ret":"obj","url":"","x":416,"y":243.5,"wires":[["be20cbcb.312ab8"]]},{"id":"be20cbcb.312ab8","type":"function","z":"4686641b.b9799c","name":"","func":"context.global.team2Score = parseInt(msg.payload.search.results);\n","outputs":1,"noerr":0,"x":586,"y":243,"wires":[[]]},{"id":"37bfe23b.c0e266","type":"function","z":"4686641b.b9799c","name":"","func":"return {\n    url: context.global.serviceUrl+':443/api/v1/messages/count?q='+context.global.team1Twitter+'%20sentiment%3Apositive%20posted%3A'+context.global.sentimentStartTime+','+context.global.sentimentEndTime\n}\n","outputs":1,"noerr":0,"x":268.5,"y":180,"wires":[["9e50786.586cc88"]]},{"id":"7b70c516.380f54","type":"inject","z":"4686641b.b9799c","name":"","topic":"","payload":"","payloadType":"date","repeat":"60","crontab":"","once":true,"x":119.5,"y":180,"wires":[["37bfe23b.c0e266","ce7dcbc8.e820a8"]]},{"id":"5a803eb4.708c98","type":"http response","z":"4686641b.b9799c","name":"","x":734,"y":374,"wires":[]},{"id":"f44030b2.e6cfc8","type":"http in","z":"4686641b.b9799c","name":"","url":"/","method":"get","swaggerDoc":"","x":128,"y":374,"wires":[["e60c9676.ac66e8"]]},{"id":"ce7dcbc8.e820a8","type":"function","z":"4686641b.b9799c","name":"","func":"return {\n    url: context.global.serviceUrl+':443/api/v1/messages/count?q='+context.global.team2Twitter+'%20sentiment%3Apositive%20posted%3A'+context.global.sentimentStartTime+','+context.global.sentimentEndTime\n}\n","outputs":1,"noerr":0,"x":267.5,"y":242,"wires":[["5c6649b9.b4ed8"]]},{"id":"e60c9676.ac66e8","type":"function","z":"4686641b.b9799c","name":"","func":"msg.payload = {};\n\nif(context.global.team1Score > context.global.team2Score) {\n    msg.payload.headline = context.global.team1Name+' lead '+context.global.team2Name+' '+Math.max(context.global.team1Score, context.global.team2Score)+'-'+Math.min(context.global.team1Score, context.global.team2Score);\n    msg.payload.team1 = context.global.team1Logo;\n} else if(context.global.team1Score < context.global.team2Score) {\n    msg.payload.headline = context.global.team2Name+' lead '+context.global.team1Name+' '+Math.max(context.global.team1Score, context.global.team2Score)+'-'+Math.min(context.global.team1Score, context.global.team2Score);\n    msg.payload.team1 = context.global.team2Logo;\n} else {\n    msg.payload.headline = context.global.team1Name+' tied '+context.global.team2Name+' at '+context.global.team1Score;\n    msg.payload.team1 = context.global.team1Logo;\n    msg.payload.team2 = context.global.team2Logo;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":345,"y":374,"wires":[["8fda4fd2.3f95b"]]},{"id":"8fda4fd2.3f95b","type":"template","z":"4686641b.b9799c","name":"","field":"payload","fieldType":"msg","format":"handlebars","template":"<html>\n    <head>\n        <title>Sentiment Bowl 2016</title>\n        <style>\n            img { max-width: 200px }\n            body { font-family: Arial }\n        </style>\n    </head>\n    <body>\n        <center>\n            <h2>{{payload.headline}}</h2>\n            <img src=\"{{payload.team1}}\" />\n            {{#payload.team2}}\n                <img src=\"{{payload.team2}}\" />\n            {{/payload.team2}}\n            \n            \n        </center>\n        <footer style=\"position: absolute; bottom: 10px; text-align: center; width: 100%\">Powered by <a href=\"http://nodered.org\" target=\"_blank\">Node-RED</a> running on <a href=\"http://bluemix.net\" target=\"_blank\">IBM Bluemix</a>, using <a href=\"https://console.ng.bluemix.net/catalog/services/insights-for-twitter/\" target=\"_blank\">Insights for Twitter</a></footer>\n    </body>\n</html>","x":520,"y":374,"wires":[["5a803eb4.708c98"]]},{"id":"2dac8fd8.260108","type":"function","z":"4686641b.b9799c","name":"Set Config","func":"context.global.serviceUrl = 'https://1abc2345-defg-6789-h012-34f5678i9012:ab0c1defgh@cdeservice.mybluemix.net';\ncontext.global.sentimentStartTime = '2016-02-07T23:30:00Z';\ncontext.global.sentimentEndTime = '2016-02-08T03:30:00Z';\n\ncontext.global.team1Twitter = '@broncos';\ncontext.global.team1Name = 'Denver Broncos';\ncontext.global.team1Logo = 'https://pbs.twimg.com/profile_images/554750999852642304/fpZDS_N_.png';\n\ncontext.global.team2Twitter = '@panthers';\ncontext.global.team2Name = 'Carolina Panthers';\ncontext.global.team2Logo = 'https://pbs.twimg.com/profile_images/692843341415735297/hm2Vrex6.jpg';","outputs":1,"noerr":0,"x":357,"y":112,"wires":[[]]}]

Double click on the node labeled Set Config. Replace the URL in context.global.serviceUrl with the URL you copied earlier from the Environment Variables. This will use the Insights for Twitter Bluemix service you created earlier.

Photo

Click on Deploy and visit your application’s URL again. You should see a webpage similar to this.

Photo

You can customize the Twitter handles and the time range (change the context.global.sentimentEndTime value if the game goes into overtime and click Deploy to the save the changes). For the big game, I’ve used the kickoff time of 3:30 Pacific.

So who do you think will win the Sentiment bowl on Sunday?