Skip to content

Instantly share code, notes, and snippets.

@jweir
Created November 29, 2023 18:37
Show Gist options
  • Save jweir/57c4e1c305e0aefabc9e8da609314f71 to your computer and use it in GitHub Desktop.
Save jweir/57c4e1c305e0aefabc9e8da609314f71 to your computer and use it in GitHub Desktop.
Ruby interface to OpenAI
#! /usr/bin/env ruby
# frozen_string_literal: true
require_relative 'ai'
bot = OpenAIChatbot.new(ENV.fetch('OPENAI_API_KEY', nil))
bot.read_input
#! /usr/bin/env ruby
# frozen_string_literal: true
require 'readline'
require 'httparty'
require 'json'
# nodoc
class OpenAIChatbot
include HTTParty
GPT = 'gpt-3.5-turbo'
GPT4X = 'gpt-4'
GPT4 = 'gpt-4-1106-preview'
# Command takes a func (lambda) and help
# Help describes what the command will do
Command = Data.define(:func, :help)
CMDS = {
'GPT' => Command.new(->(o, _input) { o.model = GPT }, 'Sets the model to GPT'),
'GPT3_16' => Command.new(->(o, _input) { o.model = GPT3_16 }, 'Sets the model to GPT 3.5 16K'),
'GPT4' => Command.new(->(o, _input) { o.model = GPT4 }, 'Sets the model to GPT4'),
'+' => Command.new(->(o, input) { o.prompt File.read(input) }, 'Reads a file and
sets the prompt to its contents'),
'!' => Command.new(->(o, _input) { o.messages = [] }, 'Clears the chat history'),
':' => Command.new(lambda { |o, input|
x = `#{input}`
puts "```#{x}```"
o.prompt(x)
}, 'Run the command and add the out to the prompt.'),
'mt:' => Command.new(lambda { |o, input|
o.max_tokens = input.to_i
puts "max_tokens: #{o.max_tokens}"
}, 'Sets the maximum number of tokens'),
'exit' => Command.new(->(_, _) { exit }, 'Exits the chatbot'),
'quit' => Command.new(->(_, _) { exit }, 'Exits the chatbot'),
'info' => Command.new(->(o, _) { puts o.model }, 'Prints the model info'),
'?' => Command.new(->(_, _) { puts(CMDS.map { |k, v| "#{k}: #{v.help}" }) }, 'Displays a list of
available commands')
}.freeze
attr_accessor :messages, :model, :max_tokens
def initialize(api_key)
@api_key = api_key
@messages = [{ role: 'system', content: 'General questions' }]
@max_tokens = 800
@model = GPT4
end
def headers
{
authorization: "Bearer #{@api_key}",
'Content-Type': 'application/json'
}
end
def post
url = 'https://api.openai.com/v1/chat/completions'
self.class.post url, {
headers:,
body: JSON.generate({
model: @model,
max_tokens: @max_tokens,
temperature: 0,
messages: @messages
})
}
end
def iterate(input)
cmd, *words = input.split(' ')
x = CMDS[cmd]
if x
x.func.call self, words.join(' ')
nil
elsif input.empty?
puts ''
print_response(post)
puts ''
else
prompt input
end
end
def prompt(input)
@messages = @messages << { role: 'user', content: input }
end
def print_response(resp)
if resp['choices']
puts wrap_word(resp['choices'].first['message']['content'])
else
puts resp
end
end
def read_input
while (buf = Readline.readline('> ', true))
iterate buf
end
end
def wrap_word(input_string, given_width = 80)
# <default value> to be replaced with an integer by user
array_of_characters = input_string.split('')
output_string = []
counter_variable = 0
array_of_characters.each do |character|
# first check if the original character is a carriage return.
# If so, reset the counter variable.
if character == "\n"
counter_variable = 0
# if not, check if the counter is greater than the desired width,
# also checking if the original character is a space.
# if so, replace it with a carriage return.
elsif counter_variable >= given_width && character == ' '
character = "\n"
counter_variable = 0
end
output_string << character
counter_variable += 1
end
output_string.join('').to_s
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment