Search code examples
ruby-on-railsrubyopenai-apichatgpt-api

ruby-openai api gem in Ruby on Rails: how to implement a streaming conversation?


Openai provides an api which allows you to implement AI services such as ChaGPT or DAL-E. For Ruby on Rails application, and there are couple of gems available, obe of them being ruby-openai.

It works very well, but the only problem is that it doesn't come with the stream conversation feature, meaning that you can only send one question request at a time without any history tracking of the conversation. In other words, the api forgets every question you asked after having sent the reply.

So how can we fix this?


Solution

  • Basically you need to implement the whole behaviour yourself. Here are all the implementation step, including the implementation of the dal-e ai with a response with several pictures rather then just one.

    You can also find my whole repository HERE and clone the app!!!

    IMPLEMENTING A STREAM CONVERSATION FEATURE

    Basic implementation

    Check out Doug Berkley's Notion Page for basic implementation of the API

    Implement a streaming conversation

    By default the openai gem does not come with that feature, hence having to implement it yourself

    1. Create your database with 3 tables (conversations, questions, answers) with thw following sctructure:
    # schema.rb
    ActiveRecord::Schema[7.0].define(version: 2023_05_29_194913) do
      create_table "answers", force: :cascade do |t|
        t.text "content"
        t.integer "question_id", null: false
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
        t.index ["question_id"], name: "index_answers_on_question_id"
      end
    
      create_table "conversations", force: :cascade do |t|
        t.text "initial_question"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
        t.text "historic"
      end
    
      create_table "questions", force: :cascade do |t|
        t.text "content"
        t.integer "conversation_id", null: false
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
        t.index ["conversation_id"], name: "index_questions_on_conversation_id"
      end
    
      add_foreign_key "answers", "questions"
      add_foreign_key "questions", "conversations"
    end
    
    1. Routes
    Rails.application.routes.draw do
      root "pages#home" # supposes that you have a pages controller with a home action
      resources :conversations, only: [:create, :show]
      post "question", to: "conversations#ask_question"
    end
    
    1. Home page view (with just a button that redirects to the create conversation action -- see bellow)
    <h1>Let's talk</h1>
    <%= button_to "Create New Conversation", conversations_path, method: :post, class: "btn btn-primary my-3" %>
    
    1. Controller app/controllers/conversations_controller.rb
    class ConversationsController < ApplicationController
      def create
        @convo = Conversation.create
        redirect_to conversation_path(@convo)
      end
    
      def show
        @convo = Conversation.find(params[:id])
      end
    
      def ask_question
        @question = Question.new(content: params[:entry])
        conversation = Conversation.find(params[:conversation])
        @question.conversation = conversation
        @question.save
        if conversation.historic.nil?
          response = OpenaiService.new(params[:entry]).call 
          conversation.historic = "#{@question.content}\n#{response}"
        else
          response = OpenaiService.new("#{conversation.historic}\n#{params[:entry]}").call
          conversation.historic += "\n#{@question.content}\n#{response}"
        end
        conversation.save
        @answer = Answer.create(content: response, question: @question)
        redirect_to conversation_path(conversation)
      end
    end
    
    1. Show page app/views/conversations/show.html.erb
    <h1>This is your conversation</h1>
    <p>Ask your question</p>
    <form action="<%= question_path %>", method="post">
      <input type="hidden" name="conversation" value="<%= @convo.id %>">
      <textarea rows="5" cols="33" name="entry"></textarea>
      <input type="submit" class="btn btn-primary">
    </form>
    
    <br>
    
    <ul>
      <% @convo.questions.each do |question| %>
        <li>
          Q: <%= question.content.capitalize %> <%= "?" if question.content.strip.last != "?" %>
        </li>
        <li>
          A: <%= question.answers.first.content %>
        </li>
      <% end %>
    </ul>
    
    <%= link_to "Back", root_path %>
    
    
    1. rails s and test :)

    Resources:

    Going Further: