Skip to content

Instantly share code, notes, and snippets.

@DogAndCode
Forked from alexrudall/#ChatGPT Streaming.md
Created June 10, 2023 05:12
Show Gist options
  • Select an option

  • Save DogAndCode/103464f3a13bb9196353d3a79f9edd15 to your computer and use it in GitHub Desktop.

Select an option

Save DogAndCode/103464f3a13bb9196353d3a79f9edd15 to your computer and use it in GitHub Desktop.
ChatGPT streaming with ruby-openai, Rails 7, Hotwire, Turbostream, Sidekiq and Tailwind!

How to add ChatGPT streaming to your Ruby on Rails 7 app!

First, add the ruby-openai gem! Needs to be at least version 4. Add Sidekiq too.

# Gemfile
gem "ruby-openai", "~> 4.0.0"

# Simple, efficient background processing using Redis.
# https://github.com/sidekiq/sidekiq
gem "sidekiq", "~> 7.0.9"

Install Redis on your machine.

brew install redis

Add Redis and Sidekiq to your Procfile so they run when you run bin/dev.

# Procfile.dev
web: bin/rails db:seed && bin/rails server -p 3000
css: bin/rails tailwindcss:watch
sidekiq: bundle exec sidekiq -c 2
queue: redis-server

Add your secret OpenAI token to your .env file. Get one from OpenAI here.

OPENAI_ACCESS_TOKEN=abc123

Add the rest of the code, full example files below!

# Controllers.
app/controllers/chats_controller.rb
app/controllers/messages_controller.rb

# Sidekiq job to stream the data from the OpenAI API.
app/jobs/get_ai_response.rb

# Migrations

# Models

# Views
# db/migrate/20230427131800_create_chats.rb
class CreateChats < ActiveRecord::Migration[7.0]
def change
create_table :chats do |t|
t.belongs_to :user, null: false, foreign_key: true
t.timestamps
end
end
end
# db/migrate/20230427131900_create_messages.rb
class CreateMessages < ActiveRecord::Migration[7.0]
def change
create_table :messages do |t|
t.references :chat, null: false, foreign_key: true
t.integer :role, null: false, default: 0
t.string :content, null: false
t.timestamps
end
end
end
# app/controllers/chats_controller.rb
class ChatsController < ApplicationController
before_action :authenticate_user!
before_action :set_chat, only: %i[show]
def show
respond_with(@chat)
end
def create
@chat = Chat.create(user: current_user)
respond_with(@chat)
end
private
def set_chat
@chat = Chat.find(params[:id])
end
end
# app/jobs/get_ai_response.rb
class GetAiResponse < SidekiqJob
def perform(chat_id)
chat = Chat.find(chat_id)
call_openai(chat: chat)
end
private
def call_openai(chat:)
message = chat.messages.create(role: "assistant", content: "")
message.broadcast_created
OpenAI::Client.new.chat(
parameters: {
model: "gpt-3.5-turbo",
messages: Message.for_openai(chat.messages),
temperature: 0.1,
stream: stream_proc(message: message)
}
)
end
def stream_proc(message:)
proc do |chunk, _bytesize|
new_content = chunk.dig("choices", 0, "delta", "content")
message.update(content: message.content + new_content) if new_content
end
end
end
# app/controllers/messages_controller.rb
class MessagesController < ApplicationController
include ActionView::RecordIdentifier
before_action :authenticate_user!
def create
@message = Message.create(message_params.merge(chat_id: params[:chat_id], role: "user"))
GetAiResponse.perform_async(@message.chat_id)
respond_to do |format|
format.turbo_stream
end
end
private
def message_params
params.require(:message).permit(:content)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment