🗂

RailsアプリへのNatural Language API(自然言語処理)の追加

2023/10/01に公開

目標

Googleの提供している Natural Language API(自然言語処理)をPFに追加する。
具体的には、実装済みのコメント部分に、検閲機能を追加する。

前提

コメント機能を実装済み
APIキーを取得済み
キーの制限設定を変更済み
詳細はこちら
https://zenn.dev/airiin/articles/d1d80f3e842646

設定関係

1.config/application.rbの編集

13行目に以下のコードを記述する。

config.paths.add 'lib', eager_load: true

config.paths.add 'lib'
libディレクトリ内のコードも自動ロードされるように設定。

eager_load: true
libディレクトリのコードを「eager load(先行読み込み)」するように設定。

2.コメントモデルにカラムを追加する

ターミナル
$ rails g migration AddScoreToComments 'score:decimal{5,3}'
$ rails db:migrate

'score:decimal{5,3}'
この部分は、実際に追加するカラムについての情報。
score: カラム名。
decimal{5,3}: カラムの型。decimal は小数点を持つ数値を保存するための型。
{5,3} の部分は、小数点を含む全体で5桁、小数点以下3桁までを意味している。例えば、99.999 などの値を保存することができる。

3.lib/language.rb の作成

libディレクトリ内に、language.rbを作成する。

lib/language.rb
require 'base64'
require 'json'
require 'net/https'

module Language
  class << self
    def get_data(text)
      # APIのURL作成
      api_url = "https://language.googleapis.com/v1/documents:analyzeSentiment?key=#{ENV['API_KEY']}"
      # APIリクエスト用のJSONパラメータ
      params = {
        document: {
          type: 'PLAIN_TEXT',
          content: text
        }
      }.to_json
      # Google Cloud Natural Language APIにリクエスト
      uri = URI.parse(api_url)
      https = Net::HTTP.new(uri.host, uri.port)
      https.use_ssl = true
      request = Net::HTTP::Post.new(uri.request_uri)
      request['Content-Type'] = 'application/json'
      response = https.request(request, params)
      # APIレスポンス出力
      response_body = JSON.parse(response.body)
      if (error = response_body['error']).present?
        raise error['message']
      else
        response_body['documentSentiment']['score']
      end
    end
  end
end

require ...
必要なライブラリの読み込み。

base64
base64とは、64進数のこと。すべてのデータをアルファベット(a~z, A~z)と数字(0~9)、一部の記号(+,/)の64文字で表すエンコード方式。

json
JavaScript Object Notationの略。軽量なデータ交換をおこなうためのフォーマット。

net/https
https通信。Google Cloud Natural Language APIはHTTPSで通信するため、この設定が必要。

module Language
moduleを定義。

class << self
この中で定義されるメソッドがクラスメソッドとして扱われることを意味する。

def get_data(text)
ge_dataメソッドの定義。テキストを受け取り、APIにリクエストを行い、感情分析の結果を返される。

api_url = ...
Google Cloud Natural Language APIのURLを定義。APIキーは環境変数から取得している。

params = { ... } .to_json
リクエスト用のJSONパラメータを作成。テキストのタイプを PLAIN_TEXT(純粋なテキスト形式)、内容として text(引数) を指定。Google Cloud Natural Language APIは、JSON形式でデータを受け取るため、.to_jsonで変換が必要。

uri = URI.parse(api_url)
URI.parseメソッドを使用して、api_url文字列を解析してURIオブジェクトに変換。

https = Net::HTTP.new(uri.host, uri.port)
Net::HTTP.newメソッドを使用して、新しいHTTPセッションを開始。このセッションの対象となるサーバーのホスト名とポート番号は、先ほどのuriオブジェクトから取得。

https.use_ssl = true
HTTPSを使用するための設定。Google Cloud Natural Language APIはHTTPSで通信するため、この設定が必要。

request = Net::HTTP::Post.new(uri.request_uri)
新しいPOSTリクエストを作成。のリクエストの対象となるURIのパス部分は、uri.request_uriで取得。

request['Content-Type'] = 'application/json'
HTTPヘッダのContent-Typeをapplication/jsonに設定。リクエストボディの内容がJSON形式であることをAPIサーバーに伝えるためのもの。

response = https.request(request, params)
実際にHTTPリクエストを送信。第一引数は、先ほど作成したPOSTリクエストオブジェクトであり、第二引数は、リクエストボディの内容(この場合、JSON形式の文字列)。APIサーバーからのHTTPレスポンスを返す。

response_body = JSON.parse(response.body)
Google Cloud Natural Language APIからのレスポンスの本文(response.body)をJSON.parseメソッドを使用して、Rubyのハッシュオブジェクト(response_body)に変換。
APIからの応答は通常JSON形式であり、このメソッドを使うことでプログラム内で簡単にデータにアクセスすることができる。

if (error = response_body['error']).present? ... end
エラーがある場合は、エラーメッセージをraiseして例外として投げる。エラーがない場合は、ドキュメントの感情のスコアを返す。

コメント検閲機能の実装

comments_controller
...
  def create
    comment = Comment.new(comment_params)
    comment.user_id = current_user.id
    comment.review_id = params[:comment][:review_id]
    comment.score = Language.get_data(comment_params[:comment])
    if comment.save
      @review = comment.review
      @review.create_notification_by(current_user)
    else
      flash[:alert] = comment.errors.full_messages.join(", ")
      redirect_back(fallback_location: root_path)
    end
  end
...

コメントの作成時に、scoreの値も保存する。

index.html.erb
<% if comment.score < -0.8 %>
  <p class="translatable-text mt-2"><small class="text-secondary">※非常にネガティブなコメントです。トラブル回避のため、不要な場合は削除することを推奨します※</small></p>
<% end %>

参考にさせていただいた記事

https://qiita.com/ren0826jam/items/a251069e7aef703687b0
https://cloudapi.kddi-web.com/magazine/json-javascript-object-notation
https://qiita.com/seisonshi/items/c23c0154c45ccbfa9999

Discussion