Japanese plugin dev 5 3 - Hiranyaloka/Documentation GitHub Wiki
これまでMT内部での機能拡張、外観変更などを題材にしてきました。
今回は外部Web APIを使ってMTを拡張する方法を解説します。
まずWeb APIですが、あるURLに決められた方法でアクセスすると、決められた動作を行い、仕様に沿った応答を返す仕組みです。MTで言えば、トラックバックや、XML-RPC、Atom API などが挙げられます。
こういったWeb APIはインターネット上に数多く存在し、クローズドのものからオープンなものまであり、利用が可能です。
こういったMT以外のWeb APIを外部Web APIとここでは呼ぶこととします。
- プラグイン設定からYahoo! Japan アプリケーションID(api_id)を設定できる
- エントリーの保存時にコールバックをフック(POST SAVE)
- api_idが設定されていない場合、なにもせず処理を抜ける
- 「タイトル」、「本文」、「続き」をまとめ、api_idと一緒にYahoo! Japan キーフレーズ抽出 API にアクセスする
- XMLで応答が返るのでパースしキーワードとスコアを取得する
- スコアが50以上のものを、そのエントリーのタグとして自動的に追加する
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パーサーで応答を解析し利用します。
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
- ハンドラは
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::UserAgent
とHTTP::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
に設定されるのはScore
とKeyphrase
を要素に持つハッシュの配列のリファレンス
-
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
から取得 -
$score
がTAG_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
今回の作例はいかがでしたでしょうか?外部Web APIと連携させる事でMTの機能がさらに強化できる事を分かって頂けたと思います。
作例にはYahoo! JapanのAPIから応答が無かった場合や、XMLのパースに問題があった場合などの処理が入っていません。また、一度設定されたタグは編集によって本文などから削除されても自動的にタグ一覧からは削除されない、などの問題も残っています。外部Web APIとの連携は、そういった「エラー」が発生する事を前提にプログラムを行わないとブログ記事が保存できない、予期しないエラーが発生する、などの問題にもなります。今回は例という事でそこまで実装していませんが、プラグイン開発を行う際はそういった面もフォローして実装する事が必要になります。
世界にはもっと多くのWeb APIが存在しています。そういったWeb APIを探して気に入ったら、プラグイン化してMTの機能拡張をしてみてはいかがでしょうか?
- プラグイン開発のためのファーストステップ
- レジストリ、YAMLについて
- 環境変数について
- プラグインのローカライゼーションについて
- テストドリブンでのプラグインの開発について
- グローバル・モディファイアプラグインの開発について
- ファンクションタグ プラグインの開発について
- ブロックタグ プラグインの開発について
- コンディショナルタグ プラグインの開発について
- プラグインのデバッグ
- プラグインの設定方法
- コールバックとフックポイント
- スケジュールタスクの開発
- MTオブジェクトの利用方法
- 独自オブジェクトの作成
- 新規アプリケーションの作成
- Transformerプラグインの開発
- 管理画面のメニュー修正
- リストアクションの追加
- 動作モードの追加とモーダルウィンドウの表示
- 外部Web APIとの連携
- 権限とロール