A serverless app that texts me positive COVID-19 news
Tags: twiliohackathon, azure, serverless, csharp
Published: 2020-04-08 22:16:37

# About

I built a serverless application that sends me a positive news story related to COVID-19 every morning before I wake up, via SMS.

During this ongoing pandemic, my problem has been too much news consumption, and a lot of it impacts me negatively. I figured now would be an excellent opportunity to create something that brings a little positivity into my day.

# Category

Interesting Integrations.

# Github repo

{% github madebygps/daily-positive-news-sms-serverless no-readme%}

# Video on how to get the project working locally (text instructions provided below if you prefer that)

{% youtube 6RruTysrm58 %}

# 👩🏽‍💻 How to setup code environment

[Follow this tutorial and you will install VS Code and the necessary Azure extensions needed.](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code?pivots=programming-language-csharp)

# 🛠 Setup API keys and credentials

You will need:
- [TwilioSid, TwilioAuthToken, TwilioPhoneNumber](https://www.twilio.com/docs/usage/tutorials/how-to-use-your-free-trial-account)
- [Azure account, CognitiveServicesEndpoint and TextAnalyticsApiKeyCredential](https://docs.microsoft.com/en-us/azure/cognitive-services/text-analytics/quickstarts/text-analytics-sdk?tabs=version-3&pivots=programming-language-csharp) Use the Free - Web/Container plan, it contains the features we need, at a free tier, [more info here](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/text-analytics/)
- [NewsApiKey](https://newsapi.org/docs/get-started)

# 📦 Packages used

These should be included in the project when you clone it, however, if there is some error, you can reinstall them.

### [Twilio](https://www.twilio.com/docs/sms/quickstart/csharp-dotnet-core])

[Install via .NET CLI](https://docs.microsoft.com/en-us/nuget/consume-packages/install-use-packages-dotnet-cli)
```shell
dotnet add package Twilio
```
Use
```csharp
using Twilio;
using Twilio.Rest.Api.V2010.Account;
```

### [TextAnalytics v3 preview](https://www.nuget.org/packages/Azure.AI.TextAnalytics/1.0.0-preview.3)

[Install via .NET CLI](https://docs.microsoft.com/en-us/nuget/consume-packages/install-use-packages-dotnet-cli)
```shell
dotnet add package Azure.AI.TextAnalytics --version 1.0.0-preview.3
```
Use
```csharp
using Azure.AI.TextAnalytics;
```
# 🔑 How to setup local.settings.json

I've excluded my local.settings.json file for obvious reasons. Make sure to include these records in there once you have them.

[Microsoft timezone documentation](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc749073(v=ws.10)?WT.mc_id=personal-blog-marouill#time-zones)

```json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "<replace_with_your_webjobsstorage>",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "TextAnalyticsApiKeyCredential":"<replace>",
    "CognitiveServicesEndpoint":"<replace>",
    "TwilioSid":"<replace>",
    "TwilioAuthToken":"<replace>",
    "NewsApiKey":"<replace>",
    "TwilioPhoneNumber":"<replace>",
    "MyPhoneNumber":"<replace_with_number_you_ant_to_send_sms_to>",
    "WEBSITE_TIME_ZONE":"<replace_with_your_timezone"
  }
}
```

# ⚡️ How to execute locally

In VS code, select the run Tab on the left, then hit the Play button on the top.

![How to run](https://raw.githubusercontent.com/madebygps/daily-positive-news-sms-serverless/master/pngs/howtorun.png "How to run")

## What is RunOnStartUp?
The app will run once since the 
```csharp
RunOnStartup=true
```
is set to true. Before deploying to production, [remove this.](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=csharp#configuration)

# 📳 Demo

You will get a text to the number you put into your local.settings.json

![SMS text](https://raw.githubusercontent.com/madebygps/daily-positive-news-sms-serverless/master/pngs/msg3.png "SMS text")

In the VS code console output, you will also see the story it sent you.

![Console output](https://raw.githubusercontent.com/madebygps/daily-positive-news-sms-serverless/master/pngs/console.png "Console output")

You will also see it in your [Twilio SMS dashboard](https://www.twilio.com/console/sms)

![Twilio dash](https://raw.githubusercontent.com/madebygps/daily-positive-news-sms-serverless/master/pngs/twiliodash.png "Twilio dash")

# 🚀 How to deploy to Azure

[Here is a written tutorial on how to Publish a Function to Azure](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code?pivots=programming-language-csharp#publish-the-project-to-azure)

[My Youtube video also shows how to do this.](https://youtu.be/6RruTysrm58?t=435)

Make sure to remove RunOnStartUp in the trigger or set to false. See this [Microsoft doc](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=csharp#configuration)

# ⏰ Change what time the app runs

This line here has the CRON expression

```csharp
public static void Run([TimerTrigger("0 30 6 * * *", RunOnStartup=true)]TimerInfo myTimer, ILogger log)
```

If you would like to change the time, change the expression part, [here are some examples.](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=csharp#ncrontab-expressions)
```csharp
"0 30 6 * * *"
```

# 🖼 MMS capabilities

Since I am in the US, I can send images to my phone number, [more info here](https://www.twilio.com/docs/sms/tutorials/how-to-send-sms-messages-csharp?code-sample=code-send-a-message-with-an-image-url&code-language=C%23&code-sdk-version=5.x), that is done in the send message method


```csharp
static void SendMessage (string fromNumber, string toNumber, string articleUrl, string articleTitle, string imageUrl )
```

Feel free to remove this if you are outside of US or Canada.

If the image has no article URL, it will default to a [stock photo I got from Unsplash](https://unsplash.com/photos/WYd_PkCa1BY)

# 🗞 Fine-tune your newsfeed

You can fine tune the JSON returned from News API with [these parameters](https://newsapi.org/docs/endpoints/everything) simply add/remove/edit the variables of the newsAPIEndpointURL
```csharp

// NEWS API Search parameters and URL
string searchKeyword = "Covid";
string sortBy = "relevancy";
string pageSize = "100";
string searchLanguage = "en";
string fromDate = DateTime.Today.AddDays (-1).ToString ("yyyy-MM-dd");
var newAPIEndpointURL = $"https://newsapi.org/v2/everything?from={fromDate}&sortBy={sortBy}&pageSize={pageSize}&language={searchLanguage}&q={searchKeyword}&apiKey={newsApiKey}";
```
# 👷🏽‍♀️ Known issues and areas of improvement

- Some of the stories sent are not necessarily positive, but since they contain words like "tests positive" or "better" they are returned as a positive sentiment. Tweaks to the sentiment labeling method and exploring more of text analytics could better this. I've added some examples below.

- I haven't been programming for very long so I know I might not be following best practices (OOP design and error handling), I will try to improve that as I get more practice and experience.

- I was getting this [Twilio error](https://www.twilio.com/docs/api/errors/11751) with certain articles, due to their image size, I implemented a method to check the article image size 
```csharp
static double GetMediaFileSize (string imageUrl) {
            var fileSizeInMegaByte = 0.0;
            var webRequest = HttpWebRequest.Create (imageUrl);
            webRequest.Method = "HEAD";

            using (var webResponse = webRequest.GetResponse ()) {
                var fileSize = webResponse.Headers.Get ("Content-Length");
                fileSizeInMegaByte = Math.Round (Convert.ToDouble (fileSize) / 1024.0 / 1024.0, 2);
            }

            return fileSizeInMegaByte;
        }
```
in case the image is larger than 4.9MB, I set the article image to a default image that I know is correctly sized. An improvement here would be to resize the image instead of changing to a default one. 

# 💙 Thanks to 

- The amazing community at [Dev.to](https://dev.to) and [Twilio](https://twilio.com). Here is the [link to the hackathon post](https://dev.to/devteam/announcing-the-twilio-hackathon-on-dev-2lh8) if you'd also like to participate (Do it 😊).
- Powered by [newsapi.org](https://NewsApi.org)
- Twilio for providing credits to work on this project
- Stock newspaper photo from [AbsolutVision](https://unsplash.com/photos/WYd_PkCa1BY)

# 👀 More examples

![msg5](https://raw.githubusercontent.com/madebygps/daily-positive-news-sms-serverless/master/pngs/msg5.png "MSG5")
![msg6](https://raw.githubusercontent.com/madebygps/daily-positive-news-sms-serverless/master/pngs/msg6.png "MSG6")
![msg6](https://raw.githubusercontent.com/madebygps/daily-positive-news-sms-serverless/master/pngs/msg9.png "MSG9")