Ruby GigaChat

Gem Version GitHub license

Installation

Bundler

Add this line to your application's Gemfile:

gem "gigachat"

And then execute:

$ bundle install

Gem install

Or install with:

$ gem install gigachat

and require with:

require "gigachat"

Usage

Get your API key from developers.sber.ru

Quickstart

For a quick test you can pass your token directly to a new client:

client = GigaChat::Client.new(
  api_type: "GIGACHAT_API_CORP", # or GIGACHAT_API_PERS, GIGACHAT_API_B2B
  client_base64: "Yjgy...VhYw==" # your authorization data
)

With Config

For a more robust setup, you can configure the gem with your API keys, for example in an gigachat.rb initializer file. Never hardcode secrets into your codebase - instead use something like dotenv to pass the keys safely into your environments.

GigaChat.configure do |config|
  config.api_type = "GIGACHAT_API_CORP" # or GIGACHAT_API_PERS, GIGACHAT_API_B2B
  config.client_base64 = ENV.fetch("GIGACHAT_CLIENT_KEY")
end

Then you can create a client like this:

client = GigaChat::Client.new

You can still override the config defaults when making new clients; any options not included will fall back to any global config set with GigaChat.configure. e.g. in this example the api_type, etc. will fallback to any set globally using GigaChat.configure, with only the client_base64 overridden:

client = GigaChat::Client.new(client_base64: "secret_token_goes_here")

Custom timeout or base URI

The default timeout for any request using this library is 120 seconds. You can change that by passing a number of seconds to the request_timeout when initializing the client. You can also change the base URI used for all requests, eg. to use observability tools like Helicone, and add arbitrary other headers:

client = GigaChat::Client.new(
    client_base64: "secret_token_goes_here",
    uri_base: "https://oai.hconeai.com/",
    uri_auth: "https://localhost:5362/",
    request_timeout: 240,
    extra_headers: {
      "X-Proxy-TTL" => "43200",
      "X-Proxy-Refresh": "true",
    }
)

or when configuring the gem:

GigaChat.configure do |config|
    config.client_base64 = ENV.fetch("GIGACHAT_CLIENT_KEY")
    config.log_errors = true # Optional
    config.uri_base = "https://oai.hconeai.com/" # Optional
    config.request_timeout = 240 # Optional
    config.extra_headers = {
      "X-Proxy-TTL" => "43200",
      "X-Proxy-Refresh": "true"
    } # Optional
end

Extra Headers per Client

You can dynamically pass headers per client object, which will be merged with any headers set globally with GigaChat.configure:

client = GigaChat::Client.new(client_base64: "secret_token_goes_here")
client.add_headers("X-Proxy-TTL" => "43200")

Logging

Errors

By default, gigachat does not log any Faraday::Errors encountered while executing a network request to avoid leaking data (e.g. 400s, 500s, SSL errors and more - see here for a complete list of subclasses of Faraday::Error and what can cause them).

If you would like to enable this functionality, you can set log_errors to true when configuring the client:

  client = GigaChat::Client.new(log_errors: true)
Faraday middleware

You can pass Faraday middleware to the client in a block, eg. to enable verbose logging with Ruby's Logger:

  client = GigaChat::Client.new do |f|
    f.response :logger, Logger.new($stdout), bodies: true
  end

Counting Tokens

GigaChat parses prompt text into tokens, which are words or portions of words. (These tokens are unrelated to your API access_token.) Counting tokens can help you estimate your costs. It can also help you ensure your prompt text size is within the max-token limits of your model's context window, and choose an appropriate max_tokens completion parameter so your response will fit as well.

To estimate the token-count of your text:

GigaChat.rough_token_count("Your text")

If you need a more accurate count, try tiktoken_ruby.

Models

There are different models that can be used to generate text. For a full list and to retrieve information about a single model:

client.models.list
client.models.retrieve(id: "GigaChat-Pro")

Chat

GPT is a model that can be used to generate text in a conversational style. You can use it to generate a response to a sequence of messages:

response = client.chat(
    parameters: {
        model: "GigaChat-Pro", # Required.
        messages: [{ role: "user", content: "Hello!"}], # Required.
        temperature: 0.7,
    })
puts response.dig("choices", 0, "message", "content")
# => "Hello! How may I assist you today?"

Streaming Chat

You can stream from the API in realtime, which can be much faster and used to create a more engaging user experience. Pass a Proc (or any object with a #call method) to the stream parameter to receive the stream of completion chunks as they are generated. Each time one or more chunks is received, the proc will be called once with each chunk, parsed as a Hash. If OpenAI returns an error, ruby-openai will raise a Faraday error.

client.chat(
    parameters: {
        model: "GigaChat-Pro", # Required.
        messages: [{ role: "user", content: "Describe a character called Anna!"}], # Required.
        temperature: 0.7,
        update_interval: 1,
        stream: proc do |chunk, _bytesize|
            print chunk.dig("choices", 0, "delta", "content")
        end
    })
# => "Anna is a young woman in her mid-twenties, with wavy chestnut hair that falls to her shoulders..."

Functions

You can describe and pass in functions and the model will intelligently choose to output a JSON object containing arguments to call them - eg., to use your method get_current_weather to get the weather in a given location. Note that tool_choice is optional, but if you exclude it, the model will choose whether to use the function or not (see here).


def get_current_weather(location:, unit: "fahrenheit")
  # Here you could use a weather api to fetch the weather.
  "The weather in #{location} is nice 🌞 #{unit}"
end

messages = [
  {
    "role": "user",
    "content": "What is the weather like in San Francisco?",
  },
]

response =
  client.chat(
    parameters: {
      model: "GigaChat-Pro",
      messages: messages,  # Defined above because we'll use it again
      tools: [
        {
          type: "function",
          function: {
            name: "get_current_weather",
            description: "Get the current weather in a given location",
            parameters: {  # Format: https://json-schema.org/understanding-json-schema
              type: :object,
              properties: {
                location: {
                  type: :string,
                  description: "The city and state, e.g. San Francisco, CA",
                },
                unit: {
                  type: "string",
                  enum: %w[celsius fahrenheit],
                },
              },
              required: ["location"],
            },
          },
        }
      ],
      function_call: "none"  # Optional, defaults to "auto"
                               # Can also put "none" or specific functions, see docs
    },
  )

Embeddings

You can use the embeddings endpoint to get a vector of numbers representing an input. You can then compare these vectors for different inputs to efficiently check how similar the inputs are.

response = client.embeddings(
    parameters: {
        model: "GigaChat",
        input: "The food was delicious and the waiter..."
    }
)

puts response.dig("data", 0, "embedding")
# => Vector representation of your embedding

Image Generation

Errors

HTTP errors can be caught like this:

  begin
    GigaChat::Client.new.models.retrieve(id: "GigaChat")
  rescue Faraday::Error => e
    raise "Got a Faraday error: #{e}"
  end

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/alexrudall/ruby-openai. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Ruby OpenAI project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.