Hello AI world with Ruby!
Tags: openai, ruby, langchain
Published: 2024-01-13 07:08:02

{% youtube QhiKOhzuYr0 %}

In this tutorial, we'll delve into creating your first AI-powered apps using Ruby, Langchain.rb library and OpenAI's GPTPT-4 API.

## Objective

We'll create a terminal-based chatbot that allows you to OpenAI'S GPT-4. This chatbot will be able to process user inputs and generate relevant, context-aware responses.

1. First, we'll need to create a ruby file. Let's call this chat.rb

2. What we want to do next is import the necessary libraries

```
require "openai"
require "langchain"
require "reline"
```

- **OpenAI**: The openai library is a Ruby client for interacting with OpenAI's API.

- **Langchain**: Langchain is a Ruby library designed for building language applications. 

- **reline**: Reline is a Ruby library used for readline-compatible input in command-line applications.

3. Create an instance of `Langchain::LLM::OpenAI`. This class is a wrapper around OpenAI's API, specifically tailored for language models (LLMs).

**Side Note**: The great thing with Langchain.rb is it supports other models, too, offering flexibility to switch between different AI models based on requirements.

4. Chat Interaction
```
# What we'll do next is to Define a method to prompt for and handle user messages
def prompt_for_message
  # Print instructions for multiline input
  puts "(multiline input; type 'end' on its own line when done. or exit to exit)"

  # Read multiline input from the user, checking if the last word is a termination keyword
  user_message = Reline.readmultiline("Question: ", true) do |multiline_input|
    last = multiline_input.split.last # Get the last word of the input
    DONE.include?(last) # Check if the last word is a termination keyword
  end

  # Return a no-operation symbol if there is no user message
  return :noop unless user_message

  # Process the multiline input to handle the termination keyword
  lines = user_message.split("\n")
  if lines.size > 1 && DONE.include?(lines.last)
    # Remove the "done" keyword from the message
    user_message = lines[0..-2].join("\n")
  end

  # Check if the user wants to exit the program
  return :exit if DONE.include?(user_message.downcase)

  # Return the processed user message
  user_message
end
```

The method `prompt_for_message`, handles multiline user inputs and implements commands for ending the input or exiting the program. The commands are: "done", "end", "eof", and "exit".

5. Interactive Loop
```
# Our next step is to create infinite loop to continuously handle user input
begin
  loop do
    user_message = prompt_for_message # We get the user message using the defined method above

    # Handle different cases of user message
    case user_message
    when :noop # If no operation, continue to the next iteration of the loop
      next
    when :exit # If exit, break the loop to end the program
      break
    end

    # Using Langchain's instance method 'message, we send the user message to OpenAI and print the OpenAI's response
    puts chat.message(user_message)
  end
# Lastly, we handle the Interrupt exception to gracefully exit the program if interrupted (e.g., Ctrl+C)
rescue Interrupt
  exit 0
end
```

The code continuously fetches user messages and uses `chat.message` to obtain and display responses from the AI, creating a dynamic conversation flow.

## Full code of chatbot.rb

```
require "openai"
require "langchain"
require "reline"

Langchain.logger.level = :info

openai = Langchain::LLM::OpenAI.new(
  api_key: ENV["OPENAI_API_KEY"], # Use the OpenAI API key from the environment variable
  llm_options: {}, # Options for the language learning model (empty in this case)
  default_options: { chat_completion_model_name: "gpt-4" } # Set GPT-4 as the default chat model
)

chat = Langchain::Conversation.new(llm: openai)
chat.set_context("You are a chatbot from the future") # Set the context of the conversation

DONE = %w[done end eof exit].freeze

puts "Welcome to the chatbot from the future!"

def prompt_for_message
  puts "(multiline input; type 'end' on its own line when done. or exit to exit)"

  user_message = Reline.readmultiline("Question: ", true) do |multiline_input|
    last = multiline_input.split.last # Get the last word of the input
    DONE.include?(last) # Check if the last word is a termination keyword
  end

  return :noop unless user_message

  lines = user_message.split("\n")
  if lines.size > 1 && DONE.include?(lines.last)
    user_message = lines[0..-2].join("\n")
  end

  return :exit if DONE.include?(user_message.downcase)

  user_message
end

begin
  loop do
    user_message = prompt_for_message

    case user_message
    when :noop
      next
    when :exit
      break
    end
    puts chat.message(user_message)
  end

rescue Interrupt
  exit 0
end
```