C#을 이용한 Azure Text Analytics API / Sentiment Analysis 예제

Azure 가 제공하는 Cognitive Service 중에 Text Analytics API 는 텍스트에 포함된 감정을 추측할 수 있는 독특한 API를 제공해준다. 예를 들어, “I had a wonderful experience! The rooms were wonderful and the staff was helpful.” 라는 문장을 보면 해당 표현이 긍정적임을 직관적으로 이해할 수 있는 데, 해당 문장에 대한 sentiment에 대한 분석을 해당 API를 통해 요청한다면, 0부터 1사이의 값으로 긍정적인지 부정적인지를 답해준다. 상위의 예에 해당하는 결과는 0.96으로 매우 긍정적이라고 알려준다 (여러 가지 언어를 제공하지만, 한글은 아직 지원하지 않고 있다).

이런 시나리오를 생각해 본적이 있는가? 예를 들어 우리가 흔히 접하는 일부 뉴스들에 대해서 얼마나 부정적인 기사들이 많이 언급되는 가를 Sentiment Analysis API로 분석한다면 어떨까? 다음은 그와 같은 예제를 어떻게 구현할 수 있을지 소개하고자 한다.

Azure subscription이 있다면, Azure Portal(https://portal.azure.com)에 들어가서 New > AI+ Cognitive Services 를 클릭하면, Text Analytics API를 생성할 수 있다. 리소스가 생성이 되면, resource management에서 Keys 를 확인할 수 있는 데, 해당 key를 일단 확보해 둔다. 이는 API를 호출할 때 필요하다. 대부분의 cognitive service 는 이와 유사하게 리소스를 만들고, key를 확보한 후에 API 호출 시 HTTP header에 해당 key를 포함하여 전송함으로써 응답을 받을 수 있다.

코드는 아래와 같은 pattern 이다.

 var uri = "https://eastasia.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment";
var json = "{\"documents\": [{\"id\": \"1\",\"text\": \"" + node._summary + "\"}]}";
 
var client = new HttpClient();
 
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "1234567890abcdefghijklmnopqrstuv");  // 32자리 key
 
HttpResponseMessage response;
 
byte[] byteData = Encoding.UTF8.GetBytes(json);
 
using (var content = new ByteArrayContent(byteData))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    using (response = await client.PostAsync(uri, content))
    {
 
        var result = await response.Content.ReadAsStringAsync();
 
        var body = JsonConvert.DeserializeObject<SentimentBatchResult>(result);
        if (body != null)
        {
            if (body.Documents != null)
            {
                foreach (var document in body.Documents)
                {
                    Console.WriteLine("Subject: {0}, Sentiment Score: {1:0.00}",
                        node._subject.ToString(), document.Score);
                }
            }
        }
    }
}

몇 가지 언급하자면, Ocp-Apim-Subscription-Key 는 미리 언급했던 azure portal에서 얻어지 key값을 header에 넣어 전송하기 위해 필요한 항목이다. node._summary 는 뉴스 기사의 요약본 문자열이고, Sentiment API를 통해서 긍부정 여부를 확인할 것이다. Sentiment API를 통해서 전달받은 결과는 json 형태로 전달받을 것이고, deserialize를 위해서 사용하는 SentimentBatchResult type은 nuget package를 통해서 Microsoft.Azure.CognitiveServices.Language preview 버전을 설치하여 이용하였다.

테스트를 위한 뉴스 요약본은 다음과 같이 간단하게 얻어서 테스트할 수 있다.

 using (WebClient client = new WebClient())
{
    string data = client.DownloadString(_url);
 
    Rss20FeedFormatter rss = new Rss20FeedFormatter();
    rss.ReadFrom(XmlReader.Create(new StringReader(data)));
 
    SyndicationFeed feed = rss.Feed;
 
    foreach (SyndicationItem item in feed.Items)
    {
        string subject = item.Title.Text;
 
        if (item.Summary != null)
        {
 
            string t = item.Summary.Text;
            t = Regex.Replace(t, @"<.+?>", String.Empty);
            t = WebUtility.HtmlDecode(t);
 
            //Console.WriteLine($"{t}");
            _list.Add(new ListNode(subject, t));
        }
    }
}

예를 들어, _url 은 https://news.google.com/news/rss/search/section/q/Korean%2BBusiness%2Banalysis/Korean%2BBusiness%2Banalysis?hl=en\&gl=US\&ned=u
와 같이 입력하여 Korean business analysis 라는 키워드로 검색한 영어 기사를 RSS로 간단히 받았으며, 뉴스 요약본을 추출하여 Sentiment API로 긍부정을 확인하기 위한 텍스트로 사용하였다.

테스트를 해보면, 기대한 만큼 분석 결과가 유용하지 않을 수도 있다. 아래와 같이 뉴스 subject과 score값을 출력하여 해당 뉴스의 요약본이 나타내고 있는 긍부정을 확인할 수 있다. 대부분이 0.5이고 3개정도의 기사만 긍정적이라고 표시하고 부정적인 기사는 없는 것으로 보이는 데, 뉴스의 텍스트가 대부분 팩트의 전달을 목적으로 하다 보니 감정적으로 건조해서 그럴 수도 있겠다 싶다.