GitHub - csabahenk/chatbladder: A Ruby wrapper for Chatblade

3 min read Original article ↗

A Ruby wrapper for Chatblade.

Why?

Looking for a viable solution for interactive interaction with ChatGPT from terminal.

Why wrap?

There are two kind of interaction models I saw in ChatGPT command line clients:

  1. REPL. However, a REPL is painful without mature line editing capabilities, and these programs have not progressed as far as to have this under their belt.
  2. Direct command line invocation. Popular shells do have sophisticated line editing, but the rudimentary shell "string syntax" makes this style of usage painful whenever punctuation and quotation comes to picture, which is the natural case for natural language.

So the idea came that input for the client could be obtained via another REPL which has a proper solution to the above issues.

Why wrap in Ruby?

Ruby's default REPL, Irb has acquired decent line editing capabilities (via the Reline library). Ruby has rich string literal syntax that allows inputting punctuation and quotation without the need of escaping.

Why wrap Chatblade?

Most ChatGPT clients do not feature session management, ie. able to carry on multiple conversations with ChatGPT and switch between them on demand. Chatblade does have this feature (thanks to yours truly ;)).

Requirements

  • Ruby ≥ 3.0
  • Chatblade ≥ 0.2.1

How?

Basic usage

Fire up with

$ irb -r /<path to chatbladder>/chatbladder.rb

then

gpt = ChatBladder.new api_key: <OPENAI API KEY>
# or
gpt = ChatBladder.new api_key_file: <PATH TO FILE CARRYING API KEY>
# or if you have OPENAI_API_KEY=<KEY> in environment, then just..
gpt = ChatBladder.new

gpt.ask %{ What's the most densely populated city on Earth? }

Session support, pt. 1

ChatBladder support Chatblade's session ops:

gpt.list_sessions
gpt.get_session SESS
gpt.get_session_path SESS
gpt.rename_session SESS, to: NEWSESS
gpt.delete_session SESS
gpt.print_session SESS

Note: these methods stringify the session argument internally, so you can use symbols for convenience.

There are three ways to call #askin session context:

gpt.ask "Some question...", session: SESS
gpt.ask(session: SESS) { "Some question..." }
gpt.ask(SESS) { "Some question..." }

Session support, pt. 2

A session can be set as permanent context, either at instantiation time:

gpt = ChatBladder.new api_key_file: ..., session: SESS

... or later on:

Once this is done, the following invocations work in the context of the preset session:

gpt.get_session
gpt.get_session_path
gpt.rename_session to: NEWSESS
gpt.delete_session
gpt.print_session
gpt.ask "Some question..."

Setting other parameters

Prompt is available as a keyword argument:

gpt.ask(prompt: "Considerate la vostra semenza") { "Some question..." }

Besides, arbitrary chatblade options can be passed; see eg. how to use GPT-4 (-c 4 option).

Set it up permanently for the instance we create:

gpt = ChatBladder.new ..., params: %w[-c 4]

Set it for a single query:

gpt.ask(params: %w[-c 4]) { "Some question..." }

... why?, continued

Why not then did it in just Python? Python has nice REPLs, too.

Ruby's string literal syntax is arguably more convenient for interactive usage than that of Python.

Why did you not then do the whole thing in Ruby? Ruby also has the ruby-openai gem to access the API.

Apart from talking to the OpenAI API, Chatblade implements some nice things, like streaming output and Markdown formatting for terminal. I did not feel like reinventing the wheel in these regards.