1
0

【GPT✖️Rails】GPTのAPIをRailsで使ってみた

Last updated at Posted at 2024-09-13

はじめに

こんにちは、エンジニア3年目の嶋田です。
この記事を開いていただきありがとうございます!

今回の記事では、RailsアプリケーションでGPT APIを利用する方法についてまとめました。
AIがますます注目される中、GPT APIをアプリケーションに統合して自然な会話や高度なテキスト生成を行うことが可能です。

この技術は、テキスト要約、質問応答、自然な会話生成などに応用できます。
今回は、私自身が業務で取り組んだ実装方法の一例を少し変えて、実例を用いながら
RailsアプリケーションにGPTを統合する際の基本的な実装方法を紹介していきます!

私も実際に実装する上で勉強になったので備忘録としてまとめました。
参考にしていただければ幸いです。

目次

GPT APIとは

GPT APIとは、OpenAIが提供する高度な言語モデル(GPTシリーズ)を外部から利用できるAPIです。このAPIを利用することで、アプリケーションでテキスト生成、要約、翻訳、質問応答などを行うことが可能です。

GPT APIはREST形式で、POSTリクエストを送信し、JSON形式の応答を受け取ります。利用できるモデルには複数のバージョンがあり、主に最新のGPT-4や、安価で高速なGPT-3.5が使われています。

詳しくはこちら👉 OpenAI API Documentation

RailsでAPIを利用するための準備

APIキーの取得

まず、GPT APIを使用するためには、OpenAIからAPIキーを取得する必要があります。
公式サイトでアカウントを作成し、APIキーを取得してください。

次に、RailsアプリケーションでAPIキーをどのように管理するかを決定します。主に以下の2つの方法があります。

  1. .envファイルを使用する方法
  2. Railsのcredentialsを使用する方法

この2つの方法について、メリット・デメリットを踏まえながら、それぞれの手順を説明します。

.envファイルでの管理

Railsで環境変数を管理するためには、dotenv-railsというGemを使用して、.envファイルを活用する方法があります。これは開発初期の段階では簡単にセットアップできるため、よく使われる手法です。

メリット

  • セットアップが非常に簡単で、環境変数の追加や変更が手軽です。
  • 環境ごとに異なる.envファイルを用意することで、開発環境や本番環境を簡単に切り替えられます。

デメリット

  • .envファイルは誤って漏洩するリスクがあり、セキュリティ面では脆弱です。
  • 本番環境では.envファイルを管理する手間がかかり、漏洩リスクが高まる可能性があります。

手順

1. Gemfileにdotenv-railsruby-openaiを追加

gem 'dotenv-rails'
gem 'ruby-openai'
  • dotenv-railsは、Railsで環境変数を管理するためのGemです。これを使うことで、環境ごとに異なる設定を簡単に行えます。
  • ruby-openaiは、OpenAIのAPIにアクセスするための公式Rubyクライアントです。このGemを使って、APIとやり取りできます。
    - README

2. .envファイルにAPIキーを追加

プロジェクトのルートに.envファイルを作成し、APIキーを追加します。

OPENAI_API_KEY=your_openai_api_key_here

3. config/initializers/openai.rbでAPIキーを読み込む

APIキーを使用して、OpenAI APIクライアントを初期化するための処理を行います。

require 'openai'

OpenAI.configure do |config|
  config.access_token = ENV['OPENAI_API_KEY']
  config.log_errors = true
end

これにより、.envファイルに保存されたAPIキーを使用してOpenAIのクライアントを初期化します。

credentialsでの管理

credentialsを使用する方法は、APIキーやその他の機密情報を暗号化して安全に管理するための方法です。Railsの標準機能として提供されており、セキュリティ面で非常に優れています。

メリット

  • APIキーが暗号化されるため、セキュリティが高く、情報漏洩のリスクが低いです。
  • Railsの標準機能として一貫して利用でき、変更履歴や管理がシンプルです。

デメリット

  • rails credentials:editコマンドを使うため、設定がやや複雑で、チーム内での共有や変更時に手間がかかることがあります。
  • 複数の環境(開発・本番)に対応する際、少し手間が増えます。

手順

1. エディタの設定

まず、rails credentials:editコマンドを実行するためには、環境変数EDITORまたはVISUALに使用するテキストエディタを設定する必要があります。以下のようにコマンドを実行して設定してください。

  • nanoを使用する場合:

    EDITOR="nano" bin/rails credentials:edit
    
  • Vimを使用する場合:

    EDITOR="vim" bin/rails credentials:edit
    

2. APIキーを追加

エディタが開いたら、次のようにAPIキーを追加してください。config/credentials.yml.encに追記されます。

openai:
  development:
    api_key: your_openai_dev_key_here
  production:
    api_key: your_openai_prod_key_here

3. Gemfileにruby-openaiを追加

RailsアプリケーションでOpenAIを使用するために、Gemfileに以下を追加しbundle installを実行します。

gem 'ruby-openai'


#### 4. **`config/initializers/openai.rb`でAPIキーを読み込む**
APIキーを使用して、OpenAI APIクライアントを初期化するための処理を行います。
```ruby
require 'openai'

OpenAI.configure do |config|
  config.access_token = Rails.application.credentials.openai[Rails.env.to_sym][:api_key]
  config.log_errors = true
end

.envファイルとcredentialsの比較

管理方法 メリット デメリット
.envファイル セットアップが簡単で、開発環境での運用に便利。 セキュリティリスクがある。ファイルの漏洩や誤操作に注意が必要。
credentials 機密情報が暗号化されるため、セキュリティが非常に強い。 設定や変更時にコマンドが必要で、複数環境の設定に手間がかかる。

credentialsはセキュリティを重視する本番環境での運用に適しており、dotenv-railsを使用した.envファイルは開発環境や簡易なプロジェクトに適しています。どちらを選ぶかは、プロジェクトの規模や運用方針に応じて決定してください。


要約生成機能の実装

ここからは、GPT APIを使ってURLの内容を要約する機能を実装していきます。

1. ルーティング設定

まず、config/routes.rbでルーティングを設定します。

Rails.application.routes.draw do
  get 'summary/new', to: 'summary#new', as: 'new_summary'
  post 'summary/create', to: 'summary#create', as: 'create_summary'
  root 'summary#new'
end

2. フォームクラスの作成

次に、app/forms/summary_form.rbでフォームオブジェクトを作成し、要約生成のロジックを定義します。

class SummaryForm
  include ActiveModel::Model

  attr_accessor :url, :result

  def initialize(params)
    @url = params[:url]
    @result = nil
  end

  def generate_summary
    prompt = build_prompt_from_url
    @result = generate_results(prompt)
    @result.present?
  end

  private

  def build_prompt_from_url
    <<~PROMPT
      以下のURLの内容を要約してください。
      URL: #{@url}
      要約を3つのポイントに分けて、簡潔にまとめてください。
    PROMPT
  end

  def generate_results(prompt)
    GptService.new(prompt).call
  rescue StandardError => e
    errors.add(:base, "要約生成に失敗しました: #{e.message}")
    nil
  end
end

3. サービスクラスの作成

次に、app/services/gpt_service.rbでGPT APIにリクエストを送信し、要約を生成するクラスを実装します。
※ エラーメッセージはユーザーに合わせて変えて下さい。

class GptService
  def initialize(prompt)
    @prompt = prompt
  end

  def call
    client = OpenAI::Client.new
    response = client.chat(
      parameters: {
        model: 'gpt-3.5-turbo',
        messages: [{ role: 'user', content: @prompt }]
      }
    )

    if response['choices'] && response['choices'].any?
      response['choices'][0]['message']['content']
    else
      'GPTからの応答がありません'
    end
  rescue OpenAI::Error => e
    handle_openai_error(e)
  rescue StandardError => e
    "システムエラーが発生しました。エラー内容: #{e.message}"
  end

  def handle_openai_error(error)
    case error
    when OpenAI::QuotaExceededError
      'GPTのクォータが超過しました。プランと請求情報を確認してください。'
    when OpenAI::AuthenticationError
      'GPTへの認証に失敗しました。APIキーを確認してください。'
    when OpenAI::ConnectionError
      'GPTサーバーとの通信に失敗しました。インターネット接続を確認してください。'
    else
      "OpenAIのエラーが発生しました: #{error.message}"
    end
  end
end

4. コントローラーの作成

app/controllers/summary_controller.rbで、フォームからの入力を処理し、要約結果を表示します。

class SummaryController < ApplicationController
  def new
  end

  def create
    url = params[:url]
    summary_form = SummaryForm.new(url:)

    if summary_form.generate_summary
      session[:summary_result] = summary_form.result
      redirect_to new_summary_path, notice: '要約が正常に作成されました'
    else
      flash[:alert] = '要約作成に失敗しました'
      redirect_to new_summary_path
    end
  end
end

5. ビューの作成

app/views/summary/new.html.erbで、ユーザーがURLを入力するフォームと結果表示を作成します。

<div class="wrapper">
  <h1 class="summary-title">サイト要約生成</h1>

  <%= form_with url: create_summary_path, method: :post, class: "summary-form" do %>
    <div class="form-group">
      <div class="input-group">
        <%= text_field_tag :url, params[:url], placeholder: "要約したいサイトのURLを入力してください", class: "url-input" %>
        <%= submit_tag "要約を生成", class: "submit-button" %>
      </div>
    </div>
  <% end %>

  <% if session[:summary_result].present? %>
    <h2 class="summary-result-title">要約結果</h2>
    <div class="summary-result-container">
      <ul class="summary-result">
        <% session[:summary_result].split(/\r?\n/).each do |item| %>
          <li><%= item.strip %></li>
        <% end %>
      </ul>
    </div>
    <% session.delete(:summary_result) %>
  <% end %>
</div>

スタイルの設定

最後に、画面のスタイルを設定します。

.wrapper {
  width: 80%;
  max-width: 900px;
  margin: 0 auto;
  padding: 20px;
  box-sizing: border-box;
  border: 1px solid #ddd;
  border-radius: 10px;
  background-color: #f9f9f9;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.summary-title {
  text-align: center;
  margin-top: 30px;
  margin-bottom: 30px;
  font-size: 24px;
}

.input-group {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  width: 100%;
}

.url-input {
  flex-grow: 1;
  padding: 10px;
  border-radius: 5px;
  border: 1px solid #ccc;
}

.submit-button {
  padding: 10px 20px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.summary-result-title {
  text-align: center;
  margin-top: 100px;
  margin-bottom: 30px;
  font-size: 20px;
}

.summary-result-container {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
}

.summary-result {
  background-color: #fff;
  padding: 15px;
  border-radius: 5px;
  border: 1px solid #ccc;
  width: 100%;
  line-height: 1.6;
  font-size: 1.1em;
}

完成画面

完成画面.png

まとめ

最後までお付き合いいただきありがとうございました。
この記事では、RailsアプリケーションにGPT APIを統合し、入力したURLの内容を要約する機能の実装方法を解説しました。GPT APIを使うことで、テキスト生成や要約機能を簡単にアプリケーションに統合できるため、さまざまなプロジェクトで応用できます。今後AIを実装する機会は増えていくかもしれないので、もっといい方法があればコメントにて教えて下さい。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0