👌

[ chatGPT / Rails ] OpenAIを使用してchatbotを入れる方法

2023/04/10に公開

chatGPTのAPIでbottomくんの実装

OpenAIのAPIを使用して、
Railsアプリケーションにチャットボットを実装する手順を解説していきます!!
私自身は以下のようにしましたヾ(๑╹◡╹)ノ"

今回はDBに保存しない方法です。

実装の準備をしよう

実装の前に、APIキーが必要になるので、取得から行っていきます。
(もしgoogleアカウントがなければ、作成が必要です)
【OpenAI APIキーを取得する】

  • OpenAIのWebサイトにアクセスし、APIキーを取得する。
    1.最初の画面入ったら...[Developers]の中のOverviewを押す。
  1. この画面に遷移するので,自分の右上のアイコンを押して[View API key]をクリック。

  2. そうすると以下の画面に遷移するから、[create new secret key]をクリック

これで完成。

実装していく!

今回の大まかな実装手順は以下の通りです。

  1. openAIのgemをインストール*
  2. チャットボット用のコントローラーを作成
  3. Viewの作成
  4. コントローラーのアクション作成

上記した通り、DBには保存しないのでモデルは作成しません!

1. openAIのgemをインストール
RailsアプリケーションのGemfileに以下のコードを追加し、bundle installを実行。

gem "ruby-openai"

2. チャットボット用のコントローラーを作成
Railsアプリケーション内に、チャットボット用のコントローラーを作成していきます。
=> rails g controller chatbots

※中身は後ほど記入していきます。

3. Viewの作成
チャットボットの画面を表示するためのビューファイルを作成します。

viewの全貌
<!-- Chat Modal -->
<div class="chat modal fade" id="chat-modal" tabindex="-1" role="dialog" aria-labelledby="chat-modal-title" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="chat-modal-title">ボットちゃん</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">×</span>
        </button>
      </div>
      <div class="chat__body modal-body">
        <div id="chat-messages" class="chat__messages" style="height: 400px; max-height: 400px; overflow-y: scroll;">
          <%# Controllerからくるデータがメッセージで表示される部分。 scriptの`$('#chat-messages').prepend(responseMessage, inputMessage);`部分 %>
        </div>
        <form id="chat-form" class="chat__form">
          <input type="text" class="form-control chat__input" id="chat-input" placeholder="聞きたい内容を入力してください。">
          <div class="input-group-append">
            <button type="submit" id="chat-btn" class="chat__submit">送る</button>
            <div class="spinner-border text-primary d-none" id="chat-loader" role="status">
              <span class="sr-only">Loading...</span>
            </div>
          </div>
        </form>
      </div>
    </div>
  </div>
</div>
<script>
  $(document).ready(function () {
      $('#chat-form').submit(function (event) {
        // デフォルトform eventを消す
          event.preventDefault();
          // InputのValue(Chatbotにタイピングしたワード)を取る
          const input = $('#chat-input').val();
          // d-none: display: none → bootstrap
          // chat-btnにd-noneを追加する→ボタンを消す
          $('#chat-btn').addClass('d-none');
          // chat-loaderに設定されてるd-noneを消す→ローディングを出す
          $('#chat-loader').removeClass('d-none');

          // /chatbots (routes.rbに記述)
          // inputはcontroller.rbに記述)
          $.post('/chatbots', {input: input})
              // controllerで成功した時はこちにくる
              // data.responseにはcontrollerのactionでreturn jsonするところに記述してるデータが入る。
              .done(function (data) {
                  //     respond_to do |format|
                  //       format.json { render json: { response: response.dig("choices", 0, "message", "content") } }
                  //     end
                  // responseは結局content!
                  const response = data.response;
                  // controllerのactionから来たデータを利用してtagを作る
                  const responseMessage = '<div class="chat__message chat__message--bot"><i class="fas fa-robot chat__bot-icon"></i><p class="alert alert-success" role="alert">' + response + '</p></div>';
                  // inputは自分が送信したテキスト→メッセージのように自分のもはる
                  const inputMessage = '<div class="chat__message chat__message--user"><p class="alert alert-info" role="alert">' + input + '</p></div>';
                  // append (入れること)の逆バージョン = prepend -> jQueryのみ
                  $('#chat-messages').prepend(responseMessage, inputMessage);
                  // 自分が送信した内容をInput Tagから消す
                  $('#chat-input').val('');
                  // ローディングを消す
                  $('#chat-loader').addClass('d-none');
                  // ボタンを表示する
                  $('#chat-btn').removeClass('d-none');
              })
              // controllerで失敗した時はこちにくる
              .fail(function (xhr, status, error) {
                  console.log("Error:", error)
                  // Display input and response in chat-messages div
                  const responseMessage = '<div class="chat__message chat__message--bot alert alert-danger" role="alert"><i class="fas fa-robot chat__bot-icon"></i><p>' + error + '</p></div>';
                  const inputMessage = '<div class="chat__message chat__message--user alert alert-info" role="alert"><p>' + input + '</p></div>';

                  $('#chat-messages').prepend(responseMessage, inputMessage);
                  // Clear input field
                  $('#chat-loader').addClass('d-none');
                  $('#chat-btn').removeClass('d-none');
              })
      });
  });
</script>
  • コメントアウトで補足は書いて行った
  • が、ここで問題になったのが、csrf tokenの問題!!!!
    これに関してはコントローラーの方で記述します。

4. コントローラーのアクション作成
OpenAIのAPIを使用して、チャットボットの応答を生成するためのコードをコントローラーに実装。
以下のようなコードをコントローラーに追加します。

  • 参考はopenAI:Docsですのでこちらもご覧ください!
class ChatbotsController < ApplicationController
  #csrf tokenの問題で追記コード
  protect_from_forgery

  def create
    input = params[:input]
    client = OpenAI::Client.new(access_token: ENV["OPENAI_ACCESS_TOKEN"])
    # Define logic to generate response based on user input
    # https://platform.openai.com/docs/api-reference/chat/create
    response = client.chat(
      parameters: {
        model: "gpt-3.5-turbo", # Required. # 使用するGPT-3のエンジンを指定
        messages: [{ role: "system", content: "You are a helpful assistant. response to japanese" }, { role: "user", content: input }], # Required.
        temperature: 0.7, # 応答のランダム性を指定
        max_tokens: 200,  # 応答の長さを指定
      },
    )

    respond_to do |format|
      format.json { render json: { response: response.dig("choices", 0, "message", "content") } }
    end
  end
end
  • client = OpenAI::Client.new(access_token: ENV["OPENAI_ACCESS_TOKEN"])
    => ここは、最初に作成したAPI keyを入れます。OPENAI_ACCESS_TOKENと変数を作成したので、
    .envファイルを作成してその中に以下のように記述する必要があります。
# .env
OPENAI_ACCESS_TOKEN = APIkey
  • このresponse=...中で必須記述なのが、
    コマンとアウトで #Requiredとつけmodelとmessage.
    => modelは使用するGPT-3のエンジンを指定。現在は"gpt-3.5-turbo"が主流!
    => message部分は、自由に設定できます。
    role: (和訳:役割) にはsystem, user, assistant3つある。
    [ system: botを設定する時 / user: UserのChat / assistant: BotのChat ]
    content: (和訳: 内容)
     最初の{role: "system", content: "内容"}で返信するボットちゃんの設定をした!

ここでは、content: "You are a helpful assistant. response to japanese"としたが、
猫設定にすると...

かわいいね。笑

  • Ruby on Railでhtmlのformを使用すると、csrf問題発生するからコントローラーの方でprotect_from_forgeryを書いた。
  • protect_from_forgery について

protect_from_forgeryとは:

  • Ruby on Railsのセキュリティ機能の1つであり、デフォルトで有効になっている。

  • この機能を使用することで、アプリケーションがCSRF(クロスサイトリクエストフォージェリ)攻撃に対して保護される。

  • CSRF攻撃は、上記した通り、攻撃者が不正なリクエストを送信し、ユーザーが知らぬうちに操作を実行させる攻撃で、protect_from_forgeryは、アプリケーション内で送信されたリクエストのCSRFトークンを自動的に検証し、トークンが一致しない場合はエラーを発生させることで、この攻撃を防止する。

  • protect_from_forgeryは、Railsアプリケーションのコントローラーで自動的に有効になっており、
    デフォルトではフォーム送信時に生成されるCSRFトークンを使用してリクエストを検証します。

  • protect_from_forgeryは、アプリケーションがセキュアであることを保証する上で非常に重要な機能。
    しかし、誤った設定や使用方法がある場合には、アプリケーションのパフォーマンスに影響を与えることがある。
    適切に使用し、必要に応じて設定をカスタマイズすることが重要。

以上で完成!!!!!

Discussion