<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rubyroid Labs</title>
    <description>The latest articles on DEV Community by Rubyroid Labs (@rubyroidlabs1).</description>
    <link>https://dev.to/rubyroidlabs1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F581492%2F78d8fdc6-589c-466d-bd35-959ad68c13c6.png</url>
      <title>DEV Community: Rubyroid Labs</title>
      <link>https://dev.to/rubyroidlabs1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rubyroidlabs1"/>
    <language>en</language>
    <item>
      <title>How To Use ChatGPT API in Your Business in 2023</title>
      <dc:creator>Rubyroid Labs</dc:creator>
      <pubDate>Thu, 20 Jul 2023 12:02:23 +0000</pubDate>
      <link>https://dev.to/rubyroidlabs1/how-to-use-chatgpt-api-in-your-business-in-2023-41h0</link>
      <guid>https://dev.to/rubyroidlabs1/how-to-use-chatgpt-api-in-your-business-in-2023-41h0</guid>
      <description>&lt;p&gt;These days, businesses are constantly thinking about how to use the ChatGPT API to the best of their (and its) ability.&lt;/p&gt;

&lt;p&gt;The fact that OpenAI has recently released an API that is 10x times cheaper in price than their flagship GPT-3.5 model has also led to the emergence of numerous applications in various industries.&lt;/p&gt;

&lt;p&gt;Since 2013, Rubyroid Labs has developed over 300 software development projects, including those that required OpenAI integration. If you are looking for a partner to integrate OpenAI into your Ruby on Rails application, &lt;a href="https://rubyroidlabs.com/contact"&gt;contact us right away.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we share insights on how to use Chat GPT API for various business cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ChatGPT API?
&lt;/h2&gt;

&lt;p&gt;After the launch of chatbot, developers one by one tried to figure out “does ChatGPT have an API?” And if so, “is ChatGPT API free?”&lt;/p&gt;

&lt;p&gt;In March 2023, OpenAI made its API available to developers. The ChatGPT API is a language processing tool built on GPT technology. Recently, the company released its GPT-4 model, the latest version of the AI tool. It’s available through a waiting list only (as is its API). Currently, those waiting for GPT-4 can use the ChatGPT-3 model for projects. If you are wondering how to use GPT-3 API, you need to get an API key via the official website.&lt;/p&gt;

&lt;p&gt;If comparing ChatGPT vs ChatGPT API, think of it like this: the latter was designed primarily for businesses with specific features in mind that they wish to implement.&lt;/p&gt;

&lt;p&gt;ChatGPT is scalable and can handle large amounts of data. The API comes with a variety of SDKs and libraries to help developers integrate the model into their applications.&lt;/p&gt;

&lt;p&gt;What’s more, developers can use the API to train their own models and customize the behavior of those models to their unique requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Top 5 Chat GPT API Use Cases
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iK9-ePx7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnkwd1z5gqi4exmeisif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iK9-ePx7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnkwd1z5gqi4exmeisif.png" alt="Image description" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rubyroidlabs.com/blog/2023/04/how-to-use-chatgpt-api/"&gt;Read the full blog post &lt;/a&gt;&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>openai</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to build an AI chatbot with Ruby on Rails and ChatGPT</title>
      <dc:creator>Rubyroid Labs</dc:creator>
      <pubDate>Thu, 20 Jul 2023 09:58:05 +0000</pubDate>
      <link>https://dev.to/rubyroidlabs/how-to-build-an-ai-chatbot-with-ruby-on-rails-and-chatgpt-4c7a</link>
      <guid>https://dev.to/rubyroidlabs/how-to-build-an-ai-chatbot-with-ruby-on-rails-and-chatgpt-4c7a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In today's fast-paced world, businesses are confronted with the daunting task of delivering accurate and prompt responses to user inquiries. Whether it's assisting customers, sharing technical documentation, or simply exchanging knowledge, the need for a dependable and efficient system to address user questions has become absolutely vital. And that's where the incredible power of an AI chatbot, fueled by a specialized knowledge base, comes into play.&lt;/p&gt;

&lt;p&gt;With a track record of over 300 software development projects, including several that involved OpenAI integration, &lt;a href="https://rubyroidlabs.com/" rel="noopener noreferrer"&gt;Rubyroid Labs&lt;/a&gt; has been a trusted name since 2013. If you're seeking a reliable partner to seamlessly integrate ChatGPT into your Ruby on Rails application, &lt;a href="https://rubyroidlabs.com/contact" rel="noopener noreferrer"&gt;contact us&lt;/a&gt; today. &lt;/p&gt;

&lt;p&gt;An AI chatbot that can answer questions based on a specific knowledge base is a valuable asset for organizations looking to automate customer interactions and improve overall user experiences. Unlike more general-purpose chatbots, these knowledge-based chatbots are designed to provide precise and contextually relevant responses by leveraging a curated knowledge base of information.&lt;/p&gt;

&lt;p&gt;The beauty of this approach lies in the ability to tailor the chatbot's responses to a specific domain or topic. By creating a knowledge base that encompasses relevant information about products, services, policies, or any other subject, the chatbot becomes an invaluable resource for users seeking specific information.&lt;/p&gt;

&lt;p&gt;Use-cases for such knowledge-based chatbots are plentiful. For instance, an e-commerce company can build a chatbot that assists customers with product inquiries, availability, and shipping details. Similarly, educational institutions can employ chatbots to answer frequently asked questions about courses, admissions, and campus facilities. In addition, there are many other cases, some of which are listed in our other &lt;a href="https://rubyroidlabs.com/blog/2023/04/how-to-use-chatgpt-api/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our case, we were asked to develop a chatbot for legal consulting. Therefore, it should base its answers only on the provided knowledgebase, and the answers should be very specific. The knowledgebase consists of 1 billion words. We faced many challenges, and with this article we will show you how we solved them.&lt;/p&gt;

&lt;p&gt;Throughout this article, we'll guide you through the process of setting up a Ruby on Rails project, integrating ChatGPT, and building the functionality to retrieve and utilize the knowledgebase to answer user questions. By the end, you'll have the necessary skills to develop your own knowledge-based chatbot tailored to your organization's specific domain or topic that empowers users to obtain precise and relevant answers based on the specific knowledgebase you provide.&lt;/p&gt;

&lt;p&gt;For the sake of this example, we are going to embed information from the&lt;a href="https://rubyroidlabs.com" rel="noopener noreferrer"&gt; RubyroidLabs&lt;/a&gt; website, thereby the AI chatbot can answer questions about the company.&lt;/p&gt;

&lt;p&gt;There is what we are going to build:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsrzldyz1q9hzxfanorx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsrzldyz1q9hzxfanorx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s get to this solution step by step.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Initialize Ruby on Rails project with PostgreSQL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check environment&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ruby --version # ruby 3.2.2
rails --version # Rails 7.0.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize Rails project (&lt;a href="https://dev.toInitialize%20Rails%20project%20(docs)"&gt;docs&lt;/a&gt;)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails new my_gpt --database=postgresql --css=tailwind
cd my_gpt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setup database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The best way to install PostgreSQL on your MacOS is not to install it at all. Instead, just run a docker container with a required PostgreSQL version. We will use &lt;a href="https://hub.docker.com/r/ankane/pgvector/tags" rel="noopener noreferrer"&gt;ankane/pgvector&lt;/a&gt;image, therefore we will have &lt;a href="https://github.com/pgvector/pgvector#docker" rel="noopener noreferrer"&gt;pgvector extension&lt;/a&gt; preinstalled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres --name my_gpt_postgres ankane/pgvector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this to &lt;code&gt;config/database.yml&lt;/code&gt; to the default or &lt;code&gt;development&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default: &amp;amp;default
  host: localhost
  username: postgres
  password: postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then initialize the database structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rake db:create
rake db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run the app&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./bin/dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup PGVector
&lt;/h2&gt;

&lt;p&gt;We will use the gem &lt;a href="https://github.com/ankane/neighbor" rel="noopener noreferrer"&gt;neighbor&lt;/a&gt; to work with PGVector. If you run PostgreSQL with Docker as described above, there is no need to install and build PGVector extension. So you can move on to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle add neighbor
rails generate neighbor:vector
rake db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup OpenAI
&lt;/h2&gt;

&lt;p&gt;To make OpenAI API calls, we will use &lt;a href="https://github.com/alexrudall/ruby-openai" rel="noopener noreferrer"&gt;ruby-openai&lt;/a&gt; gem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle add ruby-openai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;config/initializers/openai.rb&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OpenAI.configure do |config|
  config.access_token =  Rails.application.credentials.openai.access_token
  config.organization_id = Rails.application.credentials.openai.organization_id
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your OpenAI API key to the credentials. You can find them in your &lt;a href="https://platform.openai.com/account/api-keys" rel="noopener noreferrer"&gt;OpenAI account&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails credentials:edit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openai:
  access_token: xxxxx
  organization_id: org-xxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build a simple chat with &lt;a href="https://hotwired.dev/" rel="noopener noreferrer"&gt;Hotwired&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Create Questions controller &lt;code&gt;app/controllers/questions_controller.rb:&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class QuestionsController &amp;lt; ApplicationController
  def index
  end

  def create
    @answer = "I don't know."
  end

  private

  def question
    params[:question][:question]
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add routes to &lt;code&gt;config/routes.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resources :questions, only: [:index, :create]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create chat layout in &lt;code&gt;app/views/questions/index.html.erb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="w-full"&amp;gt;
  &amp;lt;div class="h-48 w-full rounded mb-5 p-3 bg-gray-100"&amp;gt;
    &amp;lt;%= turbo_frame_tag "answer" %&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;%= turbo_frame_tag "new_question", target: "_top" do %&amp;gt;
    &amp;lt;%= form_tag questions_path, class: 'w-full' do |f| %&amp;gt;
      &amp;lt;input type="text"
             class="w-full rounded"
             name="question[question]"
             placeholder="Type your question"&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Display the answer with turbo stream. Create file &lt;code&gt;app/views/questions/create.turbo_stream.erb&lt;/code&gt; and fill it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;%= turbo_stream.update('answer', @answer) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done 🎉 Open &lt;a href="http://localhost:3000/questions" rel="noopener noreferrer"&gt;http://localhost:3000/questions&lt;/a&gt;and check it out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71z7bbpoxbwt62ms1idr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71z7bbpoxbwt62ms1idr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prototype
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Chat API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s start with the simplest and the most obvious implementation - provide all our data to ChatGPT and ask it to base its answer only on the provided data. The trick here is “say ‘I don't know’ if the question can't be answered based on the context.”&lt;br&gt;
So let’s copy all data from the &lt;a href="https://rubyroidlabs.com/services" rel="noopener noreferrer"&gt;services&lt;/a&gt; page and attach it as a context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;context = &amp;lt;&amp;lt;~LONGTEXT
  RubyroidLabs custom software development services. We can build a website, web application, or mobile app for you using Ruby on Rails. We can also check your application for bugs, errors and inefficiencies as part of our custom software development services.

  Services:
  * Ruby on Rails development. Use our Ruby on Rails developers in your project or hire us to review and refactor your code.
  * CRM development. We have developed over 20 CRMs for real estate, automotive, energy and travel companies.
  * Mobile development. We can build a mobile app for you that works fast, looks great, complies with regulations and drives your business.
  * Dedicated developers. Rubyroid Labs can boost your team with dedicated developers mature in Ruby on Rails and React Native, UX/UI designers, and QA engineers.
  * UX/UI design. Rubyroid Labs can create an interface that will engage your users and help them get the most out of your application.
  * Real estate development. Rubyroid Labs delivers complex real estate software development services. Our team can create a website, web application and mobile app for you.
  * Technology consulting. Slash your tech-related expenses by 20% with our help. We will review your digital infrastructure and audit your code, showing you how to optimize it.
LONGTEXT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The message to ChatGPT is composed like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;message_content = &amp;lt;&amp;lt;~CONTENT
  Answer the question based on the context below, and
  if the question can't be answered based on the context,
  say \\"I don't know\\".

  Context:
  #{context}

  ---

  Question: #{question}
CONTENT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then make an API request to ChatGPT:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openai_client = OpenAI::Client.new
response = openai_client.chat(parameters: {
  model: "gpt-3.5-turbo",
  messages: [{ role: "user", content: message_content }],
  temperature: 0.5,
})
@answer = response.dig("choices", 0, "message", "content")

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauy697wyljfrgv0bngoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauy697wyljfrgv0bngoy.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F197572l83yhs3r0dhfll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F197572l83yhs3r0dhfll.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deal-breaker&lt;br&gt;
The thing is that each Chat API or Completion API has &lt;a href="https://platform.openai.com/docs/models/gpt-3-5" rel="noopener noreferrer"&gt;limits&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdr2rm6ffcqly95nqbxgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdr2rm6ffcqly95nqbxgs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For gpt-3.5-turbo, it’s 4,096 tokens by default. Let’s measure how many tokens our data consist of with &lt;a href="https://platform.openai.com/tokenizer" rel="noopener noreferrer"&gt;OpenAI Tokenizer&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fea38y53xjjyrn78x3k2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fea38y53xjjyrn78x3k2r.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s only 276 tokens, not a lot. However, it’s only from one page. In total, we have 300K tokens of data.&lt;br&gt;
What if we switch to &lt;code&gt;gpt-4-32k&lt;/code&gt;? It can process up to 32,768 tokens! Let’s assume that it’s enough for our purposes. What’s the price for one request going to be? GPT-4 with 32K context &lt;a href="https://openai.com/pricing" rel="noopener noreferrer"&gt;costs&lt;/a&gt; $0.06 / 1K tokens. Thus it’s $2+ per request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5jmvzo5cp2uh7uj78xo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5jmvzo5cp2uh7uj78xo.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here Embedding come into play.&lt;/p&gt;
&lt;h2&gt;
  
  
  Embeddings
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Data Chunks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To fit the limits or not spend all budget to 32K requests, let’s provide ChatGPT with the most relevant data. To do so, let’s split all data into small chunks and store it in the PostgreSQL database:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5ucazxm0towuxdp395q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5ucazxm0towuxdp395q.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, based on the user’s question, we need to find the most relevant chunk in our database. Here Embeddings API can help us. It gets a text and returns a vector (array of 1536 numbers).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrmwzpy2c5g62qnv6r5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrmwzpy2c5g62qnv6r5p.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thus, we generate a vector for each chunk via Embeddings API and save it to DB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;response = openai_client.embeddings(
  parameters: {
    model: 'text-embedding-ada-002',
    input: 'Rubyroid Labs has been on the web and mobile...'
  }
)

response.dig('data', 0, 'embedding') # [0.0039921924, -0.01736092, -0.015491072, ...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s how our database looks now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqox817yirlnyjn9qqsg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqox817yirlnyjn9qqsg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails g model Item page_name:string text:text embedding:vector{1536}
rake db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CreateItems &amp;lt; ActiveRecord::Migration[7.0]
  def change
    create_table :items do |t|
      t.string :page_name
      t.text :text
      t.vector :embedding, limit: 1536

      t.timestamps
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Item &amp;lt; ApplicationRecord
  has_neighbors :embedding
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rake task (&lt;code&gt;lib/tasks/index_data.rake&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATA = [
  ['React Native Development', 'Rubyroid Labs has been on the web and mobile...'],
  ['Dedicated developers', 'Rubyroid Labs can give you a team of dedicated d...'],
  ['Ruby on Rails development', 'Rubyroid Labs is a full-cycle Ruby on Rails...'],
  # ...
]

desc 'Fills database with data and calculate embeddings for each item.'
task index_data: :environment do
  openai_client = OpenAI::Client.new

  DATA.each do |item|
    page_name, text = item

    response = openai_client.embeddings(
      parameters: {
        model: 'text-embedding-ada-002',
        input: text
      }
    )

    embedding = response.dig('data', 0, 'embedding')

    Item.create!(page_name:, text:, embedding:)

    puts "Data for #{page_name} created!"
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run rake task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rake index_data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vector&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is a vector? Simply, a vector is a tuple, or in other words, an array of numbers. For example, [2, 3] . In two-dimensional space, it can refer to a dot on the scalar plane:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36j04jocn7jz5p9bpw2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36j04jocn7jz5p9bpw2z.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Euclidean_vector" rel="noopener noreferrer"&gt;2d vector&lt;/a&gt; on the scalar plane&lt;/p&gt;

&lt;p&gt;The same applies to three and more dimensional spaces:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foj6gcldb1lwpqpqu102e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foj6gcldb1lwpqpqu102e.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we had 2d vectors, not 1536d vectors, we could display them on the scalar plane like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oxnv5ujdx5j2d4d5tg2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oxnv5ujdx5j2d4d5tg2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to find the most relevant chunks
&lt;/h2&gt;

&lt;p&gt;So, the app receives the following question: “How long has RubyroidLabs been on the mobile software market?”. Let’s calculate its vector as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;response = openai_client.embeddings(
  parameters: {
    model: 'text-embedding-ada-002',
    input: 'How long has RubyroidLabs been on the mobile software market?'
  }
)

response.dig('data', 0, 'embedding') # [0.009017303, -0.016135506, 0.0013286859, ...]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And display it on the scalar plane:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b1w1e4iasdtqkdntle1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b1w1e4iasdtqkdntle1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can mathematically find the nearest vectors. No AI is needed for this task. That’s what we previously set up PGVector for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nearest_items = Item.nearest_neighbors(
  :embedding, question_embedding,
  distance: "euclidean"
)
context = nearest_items.first.text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, just put this context to the Chat API as we already did previously. &lt;em&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;message_content = &amp;lt;&amp;lt;~CONTENT
  Answer the question based on the context below, and
  if the question can't be answered based on the context,
  say \\"I don't know\\".

  Context:
  #{context}

  ---

  Question: #{question}
CONTENT

# a call to Chat API


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here it is 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzr2zf0f9ud9z2mbh90h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzr2zf0f9ud9z2mbh90h.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our chat answers are based on all the information we provided. Moreover, it almost doesn’t spend additional money per question but provides a better answer. However, you have to pay once for calculating embeddings when initializing the database. For 300K tokens with Ada v2, it &lt;a href="https://openai.com/pricing" rel="noopener noreferrer"&gt;costs&lt;/a&gt; just $0.03.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv5b0akey7rwlqrmqy2br.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv5b0akey7rwlqrmqy2br.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rubyroid Labs collaborates with businesses all around the world to integrate OpenAI into their activities. If you want to alter your chatbot or other conversational interface, please &lt;a href="https://rubyroidlabs.com/contact" rel="noopener noreferrer"&gt;contact us.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Summary&lt;br&gt;
Let’s wrap it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Split the data you have into small chunks. Calculate an embedding for each chunk.&lt;/li&gt;
&lt;li&gt;Save chunks with corresponding embeddings to a vector DB, e.g., PostgreSQL plus PGVector.&lt;/li&gt;
&lt;li&gt;The app initialization is done. Now you can receive a question from a user. Calculate embedding for this question.&lt;/li&gt;
&lt;li&gt;Get a chunk from the DB with the nearest vector to the questions vector.&lt;/li&gt;
&lt;li&gt;Send a question to Chat API, providing the chunk from the previous step.&lt;/li&gt;
&lt;li&gt;Get an answer from Chat API and display it to the user 🎉&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhz12tgk72gwjf2vjop6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhz12tgk72gwjf2vjop6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The complete chat logic extracted to a separate class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# frozen_string_literal: true

class AnswerQuestion
  attr_reader :question

  def initialize(question)
    @question = question
  end

  def call
    message_to_chat_api(&amp;lt;&amp;lt;~CONTENT)
      Answer the question based on the context below, and
      if the question can't be answered based on the context,
      say \\"I don't know\\".

      Context:
      #{context}

      ---

      Question: #{question}
    CONTENT
  end

  private

  def message_to_chat_api(message_content)
    response = openai_client.chat(parameters: {
      model: 'gpt-3.5-turbo',
      messages: [{ role: 'user', content: message_content }],
      temperature: 0.5
    })
    response.dig('choices', 0, 'message', 'content')
  end

  def context
    question_embedding = embedding_for(question)
    nearest_items = Item.nearest_neighbors(
      :embedding, question_embedding,
      distance: "euclidean"
    )
    context = nearest_items.first.text
  end

  def embedding_for(text)
    response = openai_client.embeddings(
      parameters: {
        model: 'text-embedding-ada-002',
        input: text
      }
    )

    response.dig('data', 0, 'embedding')
  end

  def openai_client
    @openai_client ||= OpenAI::Client.new
  end
end

# AnswerQuestion.new("Yours question..").call

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What else can be done to improve answers quality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chunk size. Find the best size for a data chunk. You can try splitting them into small ones, get the closest N from the database and connect them to one context. Conversely, you can try to create big chunks and retrieve only the one - the closest.&lt;/li&gt;
&lt;li&gt;Context length. With gpt-3.5-turbo you can send 4,096 tokens. With gpt-3.5-turbo-16k - 16,384 tokens. With gpt-4-32k up to 32,768 tokens. Find whatever fits your needs.&lt;/li&gt;
&lt;li&gt;Models. There are a slew of AI models that you can use for Embeddings or Chat. In this example, we used gpt-3.5-turbo for Chat and text-embedding-ada-002 for Embeddings. You can try different ones.&lt;/li&gt;
&lt;li&gt;Embeddings. OpenAI Embeddings API is not the only way to calculate embeddings. There are plenty of other open-source and proprietary models that can calculate embeddings.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>openai</category>
      <category>chatgpt</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
