まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:tone

先日のブログで、IBM Domino のログを外部の Web API 経由で取得する、という方法を紹介しました:
ノーツの Web エージェントで外部からログを取得する

要は log.nsf には手を付けずに、log.nsf の中身を取得して XML 出力するような API を外部データベースに Web エージェントとして作成して呼び出す、 という内容でした:
2016120302


今回はその応用編です。API でログが取得できるようになったので、その取得したログの(テキストの)内容を更に分析してみます。

今回新たに使う API は Watson Tone Analyzer です:
2016120500


Tone Analyzer は IBM Watson が提供するコグニティブ API の1つで、会話の中で発生する喜び、悲しみ、怒りといった「トーン」をテキストの内容から検出する API です。現在は大きな分類として「感情(怒り:Anger、嫌悪:Disgust、不安:Fear、喜び:Joy、悲しみ:Sadness)」、「社交性(開放性:Openness、誠実性:Conscientiousness、外向性:Extraversion、協調性:Agreeableness、情緒不安定性:Emotional Range)、「文体(分析的:Analytical、確信的:Confident、あいまい:Tentative)」という3種類のトーンを分析します:
2016120501


なお 2016/Dec/05 時点では、この API は日本語テキストには未対応です。なので、日本語の会話テキストをそのまま API のインプットデータに使うことは現時点ではできません。今の段階では使い方も限られてしまいますが、英語テキストを使えばどんな API なのかを確認する程度のことはできると思います。


この API は与えられたテキストをもとに、上記3種類のトーン毎に各要素の割合を識別して結果を 0 から 1 までの数値で返してくれます。結果の判断の方法は一概に言えないのですが、一般的には 0.75 以上であればその要素が表面化していて、0.5 以上の場合は表面化せずにも含まれている(それ以下は要素として見られない)と判断するようです。この辺りの数値結果の考え方について詳しくはこちらを参照ください:
Understand your tone score


というわけで、IBM Domino の log.nsf から取り出したログの英語テキストを、この Tone Analyzer API を使って「IBM Domino はどんな感情のログを吐いているか?」を調べてみることにします。ちなみに PHP 版のソースコードはこちらに公開しておきます:
https://github.com/dotnsf/ToneAnalyzerWithDominoLog

上記リポジトリの内容をダウンロード&展開するかクローンして、credentials.php ファイルの内容を自分の環境(Domino ログを取得する歳の URL と、Tone Analyzer の username 及び password)に合わせて編集します。そして index.php をブラウザから呼びだすと、こんな感じの画面が表示されると思います:
2016120502


index.php の内容を見ていただくとわかりますが、まず前回紹介した内容を使って Domino の log.nsf からログを Web エージェント経由で取得します。そしてその取得したテキストログをまとめて Tone Analyzer へ送り、感情分析結果を取得して、表にしている、というものです。jquery-ui を使って、感情スコアのスライダー表示も実装しています。

この表の部分だけを拡大したものがこちらです:
2016120503


この結果から、0.75 を超えているのは感情の5要素にはありません。機械的なログを分析しているので、これはある意味で正しい結果と考えられます。次に文体の3要素の中では Analytical(分析的)が 0.75 を超えているので、分析的なテキストであったといえます(これもログなのである意味正しいと言えます)。そして社交性の5要素のうちでは Conscientiousness(誠実性)と Emotional Range(情緒不安定性) が 0.75 を超えていました。な、なんかメンヘラっぽいけど、うちの Domino サーバーは大丈夫なんだろうか? (^^;


と、まあ Tone Analyzer はこんな感じで使えます。このブログでは IBM Domino のログを対象に解析していますが、もちろん他のミドルウェアサーバーのログや、テキストを元に解析できます。現状は日本語未対応なのでできることも限られてしまいますが、ある意味今のうちにいい勉強ができるともいえます。

なお、Watson Tone Analyzer はサンプルアプリのサイトから実際にテキストを与えて、感情分析結果を確認することも可能です。試してみたいテキストがあればこちらから確認してみてください:
https://tone-analyzer-demo.mybluemix.net/


IBM Bluemix に最近(2015年7月15日)新しく追加された人工知能サービス Tone Analyzer を紹介します:
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/tone-analyzer.html


Tone Analyzer は入力したテキストの内容を言語解析して、感情やライティングスタイルといった情報を検出して出力してくれる、という API サービスです。2015年7月21日時点ではまだ日本語には対応しておらず、サービス自体も Experimental(試験提供)という扱いです:
2015072101


この API を実際に使って作られたデモサイトがあるので、どういった API なのかはデモサイトを使って紹介します:
https://tone-analyzer-demo.mybluemix.net/


上記サイトにブラウザでアクセスすると "Input Text" と書かれた項目にメールの本文のようなサンプル英文が表示されています。この内容が API に入力するテキストです。このサンプル英文のままでも試せますが、このフィールドは編集可能なので、自分の書いたテキストに変更していただいても構いません。最後に "Analyze" ボタンをクリックします:
2015072102


API が実行され、その結果を視覚化したものが画面下部に出力されます:
2015072104


"JSON" と書かれた箇所をクリックすると、視覚化する前の、API としての実行結果がどんなものであったのかを確認することができます。要は API としては英文をインプットしたと、この JSON がアウトプットされた、ということになります。後はアプリケーションの設計次第でこの JSON をどう見せるのか?という部分を API 利用者の皆さんに作っていただくことになります:
2015072103


これが Watson Tone Analyzer API を使ったアプリケーションの例です。では次にこの API を実際に呼び出すアプリケーションの具体例とそのサンプルコードを紹介します。

まずは Bluemix にログインし、実際のアプリケーションサーバーとなるランタイムを作成します。Tone Analyzer API は REST API なのでプログラミング言語に依存していませんが、今回は Java のサンプルを紹介するので Liberty for Java のランタイムを作成します:
2015072007


アプリ名は適当に(この例では kkimura-java-ta と)付けておきます:
2015072105


ランタイムが作成できたら「概要」メニューから「サービスまたは API の追加」をクリックします:
2015072101


サービスの一覧が表示されます。今回の目的である Tone Analyzer はまだ試験提供のため、標準構成の一覧には表示されません。画面を一番下まですくリロールして "Bluemix Labs Catalog" をクリックして、試験提供サービスの一覧ページに移動します:
2015072102


試験サービスの Watson カテゴリの中に "Tone Analyzer" があるので、これを選択します:
2015072103


Tone Analyzer の説明が表示されます。まだ試験提供のため、今後の仕様変更の可能性があることにご注意ください(という内容が書かれています)。「作成」ボタンをクリックして、ランタイムにこのサービスをバインドします(再ステージングを促すダイアログが表示されたら再ステージングを選択します):
2015072104


バインド後にランタイムの「環境変数」メニューを参照すると、この Tone Analyzer サービスを利用するための認証情報が含まれた JSON テキストを確認することができます:
2015072105


この JSON テキストは以下の様な内容になっているはずです。"url" に API のエンドポイント(のベースとなる)値、そして "username" と "password" にはこの API を利用する際に必要になる認証情報が記載されています。これらの値を後で使います:
{
  "tone_analyzer": [
    {
      "name": "Tone Analyzer-a7",
      "label": "tone_analyzer",
      "plan": "experimental",
      "credentials": {
        "url": "https://gateway.watsonplatform.net/tone-analyzer-experimental/api",
        "username": "(username)",
        "password": "(password)"
      }
    }
  ]
}

実際に API を使う場合の Java コードはこのような感じになります。
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;

public class ToneAnalyzerServlet extends HttpServlet {
  @Override
  protected void doPost( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException{
    String contenttype = "application/json; charset=UTF-8";
    String body = null;
    String out = "";

// Tone Analyzer を使うための username と password(環境変数に書かれているもの) String username = "(username)", password = "(password)"; req.setCharacterEncoding( "UTF-8" ); try{ String _body = req.getParameter( "body" ); if( _body != null && _body.length() > 0 ){ body = _body; } if( body != null ){ HttpClient client = new HttpClient(); byte[] b64data = Base64.encodeBase64( ( username + ":" + password ).getBytes() );
// /v1/tone にテキストをポストする PostMethod post = new PostMethod( "https://gateway.watsonplatform.net/tone-analyzer-experimental/api/v1/tone" ); post.setRequestHeader( "Authorization", "Basic " + new String( b64data ) ); post.setRequestHeader( "Content-Type", "text/plain" ); post.setRequestBody( body ); int sc = client.executeMethod( post ); out = post.getResponseBodyAsString(); // ポスト結果の JSON テキスト //System.out.println( "out = " + out ); } }catch( Exception e ){ e.printStackTrace(); } res.setContentType( contenttype ); res.setCharacterEncoding( "UTF-8" ); res.getWriter().println( out ); } }

肝になっているのは赤字で記載した部分です。Tone Analyzer には何種類かの API がありますが、今回はシンプルにトーン分析を実行する /v1/tone を使った例を紹介しています。この API は非常にシンプルな構成になっており、Content-Type ヘッダ(text/plain)で指定したフォーマットで解析したいテキストを本文としてポストする、というものです。この例では解析テキストを body パラメータで受け取り、その内容を Tone Analyzer の /v1/tone で解析してその結果を受け取って、そのまま出力する、という内容をサーブレット化したサンプルです。

このサーブレットに実際にテキストを渡して実行した結果、ブラウザ画面にはこのようなテキストが表示されます(実際には1行の JSON テキスト文字列が表示されますが、改行を加えて見やすくしています)。これが API の返り値そのものです(赤字は私が加えたコメントです):
{
 "scorecard":"email",
 "children":[
  {
   "name":"Emotion Tone", 感情のトーン
   "id":"emotion_tone",
   "children":[
    {
     "name":"Cheerfulness", (感情の子要素としての)陽気さ
     "id":"Cheerfulness",
     "word_count":44, 44単語使っていた
     "normalized_score":0.47821730244258, 正規化後のスコアは47.82%
     "raw_score":0.009617486338797814, 正規化前のスコアは0.96%
     "linguistic_evidence":[ この陽気さに関する結果のエビデンス
      {
       "evidence_score":0.47821730244258, スコア47.82%
       "word_count":44,
       "correlation":"positive", "positive"に関連している
       "words":[ "surely", "good", ... ] 実際に使われていた単語
      }
     ]
    },
    {
     "name":"Negative", (感情の子要素としての)ネガティブさ
     "id":"Negative",
     "word_count":15, 15単語使っていた
     "normalized_score":0.7486994535519125, 正規化後のスコアは74.87%
     "raw_score":0.0033060109289617485, 正規化前のスコアは0.33%
     "linguistic_evidence":[ このネガティブさに関する結果のエビデンス
      {
       "evidence_score":0.7486994535519125, スコア74.87%
       "word_count":15,
       "correlation":"positive", "positive"に関連している
       "words":[ "lies", "uncomfortable", .. ] 実際に使われていた単語
      }
     ]
    },
    {
     "name":"Anger", (感情の子要素としての)怒り
     "id":"Anger",
     "word_count":0, 0単語使っていた
     "normalized_score":0.0, 正規化後のスコアは0%
     "raw_score":0.0, 正規化前のスコアは0%
     "linguistic_evidence":[ この怒りに関する結果のエビデンス
      {
       "evidence_score":0.0, スコア0%
       "word_count":0,
       "correlation":"positive", 
       "words":[] 実際に使われていた単語(がない)
      }
     ]
    }
   ],
   "word_count":59
  },
  {
   "name":"Writing Tone", ライティングのトーン
   "id":"writing_tone",
   "children":[
    {
     "name":"Analytical", (ライティングの子要素としての)分析要素
     "id":"Analytical",
     "word_count":144, 144単語使っていた
     "normalized_score":0.8802873231049461, 正規化後のスコアは88.03%
     "raw_score":0.0217896174863388, 正規化前のスコアは2.18%
     "linguistic_evidence":[ この分析要素に関する結果のエビデンス
      {
       "evidence_score":0.8802873231049461, スコア88.03%
       "word_count":144,
       "correlation":"positive",
       "words":[ "but", "knowing", .. ] 実際に使われていた単語
      }
     ]
    },
    :    
    :

この辺りのデータフォーマットは正式リリース後にどうなるか、なんとも言えない所ではありますが、とりあえず現時点では上記のようなフォーマットが API の結果として得られるようです。要は入力テキストをいくつかのカテゴリと、その子要素であるサブカテゴリに分けて分析してスコア付けを行い、その結果を返してくれる、という API のようです。



なお、Tone Analyzer API のリファレンスはこちらを参照ください:


このページのトップヘ