【Rails】Yahoo! 自然言語理解APIを使って雑談botを作る
Ruby on Railsの学習のため、Twitterのリプライを取得してリプ返を自動生成するWebアプリ「リプ返つらい」を作成しました。ユーザー登録不要で遊べるのでよかったら覗いてみてください。
今回は、リプ返を生成するために用いた「Yahoo! 自然言語理解 API」の使い方をまとめます。
Yahoo! 自然言語理解 APIとは
Yahoo!音声アシストでも使われている自然言語理解Web API。無料で利用可能(ただし、サイト上にYahooのクレジットを表記する必要あり)で、日本語文を解析し、情報の抽出を行うことができます。
公式ドキュメントが少々分かりづらいのですが、要は解析したいテキストをパラメータに含めてリクエストを送ると、API側がテキストの持つ意図などを抽出してレスポンスしてくれるという仕組みです。
出力仕様のひとつにSAY
(自然言語による応答を返す)というものがあったので、この出力を使ってリプ返を自動生成するアプリを実装していきます。
Yahoo! アプリケーション登録
下準備として、Yahoo!デベロッパーネットワークの利用ガイドに沿って、Yahoo! JAPAN IDを取得してから、アプリケーションを登録し、アプリケーションID(Client ID)を発行します。
発行されたアプリケーションID(グレーで塗った部分)を使用します
素のRubyファイルでテスト
Railsに移植する前に、Yahoo 自然言語理解 APIの動作を素のRubyファイルでテストしてみます。
RubyからHTTPリクエストを送るために、net/httpライブラリを読み込んでいます。またレスポンスをjson形式に変換して扱いやすくするために、jsonライブラリも読み込んでいます。
require 'net/http'
require 'json'
yahoo_url = 'https://jlp.yahooapis.jp/NLUService/V1/analyze'
appid = 'アプリケーションID'
# 解析するテキストの取得
puts 'テキストを入力してください'
text = gets
escape_text = URI.escape(text)
# HTTPリクエストを投げてAPIからレスポンスを得る
url = yahoo_url + '?appid=' + appid + '&intext=' + escape_text
uri = URI.parse(url)
response = Net::HTTP.get_response(uri)
# 結果をコンソール画面に出力
puts JSON.parse(response.body)
テキストを入力してください
おはようございます
{"result"=>{"intext"=>"おはようございます\n", "method"=>"SAY",
"param_small_talk_intent"=>"GREETINGS_GOOD_MORNING",
"param_text"=>"おはようございます。今日もよろしくお願いします。", "status"=>"200",
"var_cv1"=>"0.855", "var_intext"=>"おはようございます\n",
"var_intext_normalized"=>"おはようございます\n",
"var_intext_timestamp"=>"1652968396", "var_test_btsc"=>"16"}}
テキストを入力してください
今日の天気は?
{"result"=>{"intext"=>"今日の天気は?\n", "method"=>"WEATHER",
"param_datetime_from"=>"今日", "param_method_subcat"=>"GENERAL",
"status"=>"200", "var_cv1"=>"0.855", "var_intext"=>"今日の天気は?\n",
"var_intext_normalized"=>"今日の天気は\n",
"var_intext_timestamp"=>"1652968429", "var_test_btsc"=>"49"}}
リクエストURLはhttps://jlp.yahooapis.jp/NLUService/V1/analyze
で、必須パラメータはアプリケーションIDを示すappid
と、解析対象のテキストintext
の2つです。
リクエストが成功すると、APIの解析結果をresult
パラメータに含めてレスポンスが返ってきます。
APIの解析結果(応答)にはいくつか種類があり、result
の中のmethod
パラメータを見るとどの種類の応答が返ってきているのかがわかります。
例えば、「おはようございます」という入力にはSAY
(雑談)の応答が返ってきて、「今日の天気は?」という入力にはWEATHER
(天気)の応答が返ってきました。
このmethod
パラメータがSAY
のときだけ、APIによる返事がレスポンスに含まれています。APIによる返事はparam_text
パラメータから取得できます。
「おはようございます」という入力には、「おはようございます。今日もよろしくお願いします。」という返事が返ってきました。きちんと入力テキストの意図を理解して、対応する返事を返してくれています。
今回は自分がもらったリプライに対するリプ返を自動生成したいので、入力テキストはリプライのテキスト本文、出力はmethod
パラメータがSAY
のときはparam_text
を、method
パラメータがSAY
以外のときは返事なし
とすることにします。
Railsで実装する
上記のテストコードをベースに、RailsでWebアプリ化します。作りたいアプリはCRUD機能がいらないためRailsで実装する必要はなかったのですが、一番慣れているフレームワークなのでRailsを使用しました。
Yahoo APIに関する部分だけを抜粋します。
Rails.application.routes.draw do
get 'yahoo/show', to: 'yahoo#show'
end
class YahooController < ApplicationController
require 'net/http'
require 'json'
def show
@text = params[:text]
@reply = get_reply(@text)
end
private
def get_reply(text)
yahoo_url = 'https://jlp.yahooapis.jp/NLUService/V1/analyze'
appid = ENV['YAHOO_APP_ID']
escape_text = URI.escape(text)
url = yahoo_url + '?appid=' + appid + '&intext=' + escape_text
uri = URI.parse(url)
response = Net::HTTP.get_response(uri)
json_response_body = JSON.parse(response.body)
if response.code == '200' && json_response_body['result']['method'] == 'SAY'
json_response_body['result']['param_text']
else
'AIもリプライを思いつきませんでした。自分で考えよう!'
end
end
end
<main class="container">
<div class="row text-center justify-content-center">
<div class="col">
<div class="card text-center">
<div class="card-header">
もらったリプライ
</div>
<div class="card-body">
<p class="card-text"><%= @text %></p>
</div>
</div>
<p></p>
<p>に対するAIのリプ返は…</p>
<p></p>
<div class="card text-center">
<div class="card-header">
AIが自動生成したリプ返
</div>
<div class="card-body">
<h4 class="card-title"><%= @reply %></h4>
<p class="card-text">#リプ返つらい</p>
</div>
</div>
<p></p>
<div>
<% tweettext = "@#{@authorname}さんのツイート%0A「#{@text}」%0A%0AにAIがリプ返!%0A%0A「#{@reply}」%0A%0A" %>
<%= link_to 'AIのリプ返をTwitterで投稿する', "https://twitter.com/intent/tweet?text=#{tweettext}&hashtags=リプ返つらい&url=https://replytsurai.onrender.com/", class: 'btn btn-primary' %>
</div>
</div>
</div>
</main>
前段階でTwitter APIを用いてリプライを取得しておき(Twitter APIに関しては別の記事で解説します)、yahoo
コントローラのshow
アクションに、リプライのテキストをparams[:text]
に入れて渡します。
そしてget_reply
メソッドでYahoo APIを叩いてリプ返を生成し、@reply
に入れてビューファイルに渡します。
テストコードからの主な変更点は2つあり、1つ目はアプリケーションIDを外部から秘匿するために、環境変数ENV['YAHOO_APP_ID']
から呼び出していることです。
開発時のローカル環境では、環境変数の設定は.bash_profileに記述しました。
#.bash_profileをvimで開く
vim ~/.bash_profile
# .bash_profileに下記の一行を追加
export YAHOO_APP_ID='アプリケーションID'
#.bash_profileを反映
source ~/.bash_profile
本番ではrender.comにデプロイしたので、render.comのダッシュボードに環境変数を設定しました。
変更点の2つ目は、get_reply
メソッドの戻り値の部分です。レスポンスコードが200かつmethod
パラメータがSAY
のときはparam_text
パラメータを戻り値とし、そうでないときは返事なし
に該当するテキストを戻り値としています。
このように実装することで、誰でもリプ返を自動生成できるWebアプリが完成しました。
感想
Yahoo APIの内部でどのように返事を生成しているのか、そのアルゴリズムまでは公開されておらず気になるところですが、なかなか味のある返事を返してくれます。独自のカスタムルールも作れるので、簡単なチャットbotなどを作ってみたい方には面白いのではないでしょうか。
Discussion