先日朝日新聞社によって長文要約APIがリリースされました。要約をAPIで取得できるという点が面白いと感じたので、このブログ(blog.3qe.us)の記事を閲覧したときに自動的に要約を見られるような仕組みを作ってみようと思い、1週間ちょっとかかってしまいましたが動くものができたので紹介します。
記事冒頭に要約コーナーを出現させる
この仕組みによって、記事の冒頭に要約コーナーが勝手に出現して要約を表示します。
いくつかの記事では既に生成ができていますが、API自体は1日に20回までの制限があるので、全ての記事にはまだ行き渡っていません。
まだ要約が生成されていない記事にはpreparing abstract
という文言が表示されます。
句読点の問題かちょっと要約が怪しいところもありますが、おおむね正しい要約を表示しているようです。
仕組みの解説
まずアーキテクチャはこちらです。
いくつかのパートに分かれているのでそれぞれ見ていきます。
今回はLambdaの実装言語にRubyを使いました。HTMLパーサがあり、若干慣れているためです。
HTML / JS部
はてなブログには記事の直前にHTMLを挿入する仕組みがあるので、ここにscriptタグとJavascriptを仕込みます。
スクリプトは、fetch APIにより、閲覧中の記事のURLを僕が作成したAPIに渡し、要約を受け取ったら動的に要素を生成してタイトル下に挿入させます。
閲覧中の記事のURLはクエリパラメータを除いた形にしています。
API部
APIは基本的にAWSの仕組みの上に構築しました。API Gatewayがリクエストを受け取り、記事のURLを前段のLambdaに転送します。また、API GatewayにはCORS
(オリジン間リソース共有 (CORS) - HTTP | MDN)
まわりの面倒も見てもらいます。
前段のLambda
前段のLambdaは、API Gatewayからリクエストを受け取ると、既に要約が生成されていないかを確認します。要約はDynamoDBに保管しています。
要約が既に存在していればそれをそのまま返し、存在していなければ要約を生成してもらうためにSQSにenqueueします。
前段のLambdaのコードはいちおう公開しています。
SQS
SQSは後段のLambdaとつながっています。SQSはLambdaを直列に1つずつ起動します。SQSを間に噛ませている理由は、前段のLambdaにすぐリクエストを返してもらうためですが、存在感はちょっと薄めです。
後段のLambda
後段のLambdaの仕事は、記事の内容を取得し、朝日新聞社の長文要約APIにアクセスして要約を生成してもらい、その結果をDynamoDBに格納すること、そしてリクエスト数が超過した場合はサーキットブレーカ(一定の条件になると動作停止するような仕組み)を開放動作することです。
Lambdaはまず、DynamoDBに特定のレコードを問い合わせ、「次にAPIが使えるようになるのがいつか」というレコードを取り出そうとします。レコードが存在していなければ制限を超過していないと判断して次の処理に進みますが、存在している場合は現在時刻との照合を行い、到達しているかどうか確認します。到達していれば次の処理に進みますが、到達していなければここで処理は中断します*1。
サーキットブレーカの確認が終わると、Lambdaは記事の内容を取得します。ブログの記事にアクセスし、Nokogiriを使ってHTMLをパースし、記事本文のテキストだけを抜き出します。
記事本文のテキストの取得が完了すると、実際にAPIに対してリクエストを発行します。数秒かかって結果がJSONで返されるので、ここから要約部分を取り出してDynamoDBに格納します。
ここで1日20回の上限に抵触した場合はHTTP 429 Too Many Requestsが返されます。この場合はサーキットブレーカを開放動作するため、次にAPIが使えるようになる時間をDynamoDBに書き込んでおきます。今のところ現在時刻+1日を書き込んでいます。
後段のLambdaには記事取得とAPIリクエストのためにインターネットアクセスが必要になるため、VPCやサブネットを設定しています。
後段のLambdaのコードはいちおう公開しています。
DynamoDB
DynamoDBには以下のカラムを用意しています。
url
記事のURLを格納するstatus
記事の取得状況を格納する (done
/enqueued
)abstract
APIから返ってきた要約を保存する
感想
完璧ではないのですが、だいたい動くものができたので満足しています。どのくらいおカネがかかるかがちょっと心配です。今はリトライの仕組みが無く、要約APIが上限に到達したときに処理していた記事はそのまま放置されてしまうため、もし時間があったらリトライまわりの仕組みを作ろうかなと思います。
ちょっと考え方を変えると、要約の結果がおかしいときは元の日本語もおかしいはずなのでちゃんとした日本語を書くモチベーションが高まる。
Appendix
APIのプレスリリースはこちらです。
API自体の解説はこちらです。
*1:リトライ処理は時間があるときに実装したいです