Japanese plugin dev 5 3

uehatsu edited this page May 9, 2011 · 7 revisions

外部Web APIとの連携

はじめに

これまでMT内部での機能拡張、外観変更などを題材にしてきました。

今回は外部Web APIを使ってMTを拡張する方法を解説します。

外部Web APIとは?

まずWeb APIですが、あるURLに決められた方法でアクセスすると、決められた動作を行い、仕様に沿った応答を返す仕組みです。MTで言えば、トラックバックや、XML-RPC、Atom API などが挙げられます。

こういったWeb APIはインターネット上に数多く存在し、クローズドのものからオープンなものまであり、利用が可能です。

こういったMT以外のWeb APIを外部Web APIとここでは呼ぶこととします。

外部Web APIと連携するプラグインの開発

仕様

  • プラグイン設定からYahoo! Japan アプリケーションID(api_id)を設定できる
  • エントリーの保存時にコールバックをフック(POST SAVE)
    • api_idが設定されていない場合、なにもせず処理を抜ける
    • 「タイトル」、「本文」、「続き」をまとめ、api_idと一緒にYahoo! Japan キーフレーズ抽出 API にアクセスする
    • XMLで応答が返るのでパースしキーワードとスコアを取得する
    • スコアが50以上のものを、そのエントリーのタグとして自動的に追加する

Yahoo! Japan キーフレーズ抽出 API

Yahoo Japan の Web API を利用するにはアプリケーションIDを取得する必要があります。アプリケーションIDの取得にはYahoo! Japan IDが必要で取得していない場合は取得してください。アプリケーションIDは Yahoo! Japan デベロッパーネットワーク から取得できます。

Yahoo! Japan デベロッパーネットワークのページには多くの Web API が紹介されていますが、今回は キーフレーズ抽出API を利用します。

詳細は省きますが、この Web API に対象となるテキストを投稿すると日本語文を解析し、特徴的な表現(Keyphrase)と重要度を示す目安の値(Score)をXMLかJSON、PHP Serialize形式で値を返します。

今回はXML(デフォルト)の応答を使い、XMLパーサーで応答を解析し利用します。

config.yaml

id: MyPlugin17
key: MyPlugin17
name: <__trans phrase="Sample Plugin API">
version: 1.0
description: <__trans phrase="_PLUGIN_DESCRIPTION">
author_name: <__trans phrase="_PLUGIN_AUTHOR">
author_link: http://www.example.com/about/
doc_link: http://www.example.com/docs/
l10n_class: MyPlugin17::L10N

system_config_template: yahoo_japan_api_id_setting.tmpl
settings:
    yahoo_japan_api_id:
        default:
        scope: system

callbacks:
    MT::App::CMS::cms_post_save.entry: $MyPlugin17::MyPlugin17::Callbacks::post_save_entry

解説

  • プラグイン設定(システム)のテンプレートは yahoo_japan_api_id_setting.tmpl
  • プラグイン設定 settings
    • 設定名: yahoo_japan_api_id
      • デフォルト値:(空)
      • 表示:システム
  • コールバックのフックポイントは MT::App::CMS::cms_post_save.entry ブログ記事の保存後
    • ハンドラは $MyPlugin17::MyPlugin17::Callbacks::post_save_entry

Callbacks.pm

package MyPlugin17::Callbacks;
use strict;

use constant YAHOO_API_URI => 'http://jlp.yahooapis.jp/KeyphraseService/V1/extract';
use constant TAG_SCORE => 50;

sub post_save_entry {
    my ($cb, $app, $obj, $org_obj) = @_;
    my $plugin = MT->component('MyPlugin17');

    my $api_id = $plugin->get_config_value('yahoo_japan_api_id', 'system');
    return 1 unless $api_id;

    require LWP::UserAgent;
    require HTTP::Request::Common;

    my $text = $obj->title . ' ' . $obj->text . ' ' . $obj->text_more;
    my %data = ( 'appid' => $api_id,
                 'sentence' => $text,
               );
    my $req = HTTP::Request::Common::POST(YAHOO_API_URI, [%data]);
    my $ua = LWP::UserAgent->new;
    my $res = $ua->request($req);

    require XML::Simple;
    my $results = XML::Simple::XMLin($res->content)->{'Result'};

    my @tags = ();
    foreach my $i (0..$#$results) {
        my $result = $results->[$i];
        my $score = $result->{'Score'};
        my $keyphrase = $result->{'Keyphrase'};
        push(@tags, $keyphrase) if $score >= TAG_SCORE;
    }
    return 1 unless @tags;

    $obj->add_tags(@tags);
    $obj->save
        or die $obj->errstr;
}

1;

解説

package MyPlugin17::Callbacks;
use strict;
  • パッケージ宣言と use strict;
use constant YAHOO_API_URI => 'http://jlp.yahooapis.jp/KeyphraseService/V1/extract';
use constant TAG_SCORE => 50;
  • YAHOO_API_URI : キーフレーズ抽出 API のエンドポイントのURIの定数宣言
  • TAG_SCORE : タグとして追加するスコアの下限の定数宣言
sub post_save_entry {
    my ($cb, $app, $obj, $org_obj) = @_;
    my $plugin = MT->component('MyPlugin17');
  • ハンドラ関数の関数宣言
  • 引数(コールバック、アプリケーション情報、保存オブジェクト、保存前オブジェクト)
  • プラグインオブジェクトの取得(プラグイン:MyPlugin17)
    my $api_id = $plugin->get_config_value('yahoo_japan_api_id', 'system');
    return 1 unless $api_id;
  • システムプラグイン設定から yahoo_japan_api_id$api_id として取得
  • yahoo_japan_api_id が設定されていない場合、処理を抜ける
    require LWP::UserAgent;
    require HTTP::Request::Common;

    my $text = $obj->title . ' ' . $obj->text . ' ' . $obj->text_more;
    my %data = ( 'appid' => $api_id,
                 'sentence' => $text,
               );
    my $req = HTTP::Request::Common::POST(YAHOO_API_URI, [%data]);
    my $ua = LWP::UserAgent->new;
    my $res = $ua->request($req);
  • LWP::UserAgentHTTP::Request::Common の利用宣言
  • 「タイトル」「本文」「続き」を結合し、 $text に代入
  • %data$api_id$text を設定
  • POSTリクエストを HTTP::Request::Common::POST で作成し、 $req に代入
  • LWP::UserAgent オブジェクトを $ua として作成
  • リクエストを行い、結果を $res に代入
    require XML::Simple;
    my $results = XML::Simple::XMLin($res->content)->{'Result'};
  • XML::Simple の利用宣言
  • リクエスト結果のコンテント( $res->content )を XML::Simple::XMLin() でパースし、 Result 要素を取得
    • $results に設定されるのは ScoreKeyphrase を要素に持つハッシュの配列のリファレンス
    my @tags = ();
    foreach my $i (0..$#$results) {
        my $result = $results->[$i];
        my $score = $result->{'Score'};
        my $keyphrase = $result->{'Keyphrase'};
        push(@tags, $keyphrase) if $score >= TAG_SCORE;
    }
    return 1 unless @tags;
  • @tags を追加するタグを設定する配列として準備
  • foreach 文で $results をループ処理
  • 処理対象の $result を取得
  • $score$keyphrase$result から取得
  • $scoreTAG_SCORE (50) 以上であれば @tags$keyphrase をpush
  • @tags が空だったら処理を抜ける
    $obj->add_tags(@tags);
    $obj->save
        or die $obj->errstr;
  • ブログ記事オブジェクト( $obj )の add_tags 関数に @tags を渡す
    • add_tags 関数は渡されたタグの配列のうち、ブログ記事に設定されていないタグを設定
  • タグを改変したブログ記事オブジェクトを保存

このような処理により、タグを自動生成します。

ファイルの配置

$MT_DIR/
|__ plugins/
   |__ MyPlugin17/
      |__ config.yaml
      |__ lib/
      |  |_ MyPlugin17/
      |     |__ Callbacks.pm
      |     |__ L10N.pm
      |     |_ L10N/
      |     |  |_ en_us.pm
      |     |  |_ ja.pm
      |__ tmpl/
         |_ yahoo_japan_api_id_setting.tmpl

プラグインダウンロード

MyPlugin17.zip(3.21KB)

まとめ

今回の作例はいかがでしたでしょうか?外部Web APIと連携させる事でMTの機能がさらに強化できる事を分かって頂けたと思います。

作例にはYahoo! JapanのAPIから応答が無かった場合や、XMLのパースに問題があった場合などの処理が入っていません。また、一度設定されたタグは編集によって本文などから削除されても自動的にタグ一覧からは削除されない、などの問題も残っています。外部Web APIとの連携は、そういった「エラー」が発生する事を前提にプログラムを行わないとブログ記事が保存できない、予期しないエラーが発生する、などの問題にもなります。今回は例という事でそこまで実装していませんが、プラグイン開発を行う際はそういった面もフォローして実装する事が必要になります。

世界にはもっと多くのWeb APIが存在しています。そういったWeb APIを探して気に入ったら、プラグイン化してMTの機能拡張をしてみてはいかがでしょうか?

プラグイン開発ガイド インデックス

  1. プラグイン開発のためのファーストステップ
  2. レジストリ、YAMLについて
  3. 環境変数について
  4. プラグインのローカライゼーションについて
  5. テストドリブンでのプラグインの開発について
  6. グローバル・モディファイアプラグインの開発について
  7. ファンクションタグ プラグインの開発について
  8. ブロックタグ プラグインの開発について
  9. コンディショナルタグ プラグインの開発について
  10. プラグインのデバッグ
  11. プラグインの設定方法
  12. コールバックとフックポイント
  13. スケジュールタスクの開発
  14. MTオブジェクトの利用方法
  15. 独自オブジェクトの作成
  16. 新規アプリケーションの作成
  17. Transformerプラグインの開発
  18. 管理画面のメニュー修正
  19. リストアクションの追加
  20. 動作モードの追加とモーダルウィンドウの表示
  21. 外部Web APIとの連携
  22. 権限とロール
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.