In this video, I build a chat application similar to ChatGPT by relying heavily on Claude 3.5 Sonnet. I wanted to let loose and give yet another example of what LLMs are capble of doing with the help of a thoughtful prompter.


Our initial prompt to kick us off 🙌🏾

I want to generate a Rails application that is a clone of ChatGPT. Start with the commands I should run to get the initial rails app up and running and then tell me what models, routes, controllers I should create.

Setting Up the Rails Application

We started by creating a new Rails application with SQLite as the database:

gem install rails
rails new chatgpt_clone
cd chatgpt_clone
rails db:create

Adding Necessary Gems

We updated the Gemfile to include the required gems:

gem 'ruby-openai', '~> 4.0.0'
gem 'dotenv-rails', groups: [:development, :test]

After updating the Gemfile, we ran bundle install to install the new gems.

Setting Up Environment Variables

To securely store our OpenAI API key, we created a .env file in the root of our project:

OPENAI_API_KEY=sk-your_actual_api_key_here_without_quotes

We also ensured that .env was added to our .gitignore file to keep the API key secret.

Creating the Chat Model

We generated a Chat model to store our conversations:

rails generate model Message content:text role:string
rails db:migrate

Implementing the Controller

We created a ChatsController to handle the interaction with OpenAI:

class ChatsController < ApplicationController
  def index
    @messages = Message.all
    @message = Message.new
  end

  def create
    @message = Message.new(message_params)
    if @message.save
      # Here you would integrate with an AI service to get a response
      ai_response = "This is a placeholder AI response."
      Message.create(content: ai_response, role: 'assistant')
      redirect_to chats_path
    else
      render :index, status: :unprocessable_entity
    end
  end

  private

  def message_params
    params.require(:message).permit(:content).merge(role: 'user')
  end
end

Setting Up Routes

We updated our config/routes.rb file:

Rails.application.routes.draw do
  root 'chats#index'
  resources :chats, only: [:index, :create]
end

Creating the View

We created a simple view in app/views/chats/index.html.erb to interact with our chat application.

<div class="chat-container">
  <div class="messages">
    <% @messages.each do |message| %>
      <div class="message <%= message.role %>">
        <%= message.content %>
      </div>
    <% end %>
  </div>
  
  <%= form_with(model: @message, url: chats_path, local: true) do |f| %>
    <%= f.text_area :content, placeholder: "Type your message..." %>
    <%= f.submit "Send" %>
  <% end %>
</div>

Sprinkle in some css ✨

.chat-container {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.messages {
  height: 400px;
  overflow-y: scroll;
  border: 1px solid #ccc;
  padding: 10px;
  margin-bottom: 20px;
}

.message {
  margin-bottom: 10px;
  padding: 5px;
  border-radius: 5px;
}

.user {
  background-color: #e6f2ff;
  text-align: right;
}

.assistant {
  background-color: #f0f0f0;
  text-align: left;
}

form {
  display: flex;
}

textarea {
  flex-grow: 1;
  margin-right: 10px;
}

Troubleshooting

During the development process, we encountered a few issues:

  1. Uninitialized constant ChatsController::OpenAI: We resolved this by properly requiring the ‘openai’ gem in our controller.

  2. Faraday::UnauthorizedError: This was due to an authentication issue with the OpenAI API. We double-checked our API key and ensured it was being loaded correctly from the .env file.

  3. Environment Variable Loading: We made sure to properly set up the dotenv-rails gem to load our environment variables.

That’s it!

Doing this speed run was a fun and useful exercise. I’m throughly impressed by Claude’s abiltiy to generate Rails code.