Skip to content

Commit

Permalink
Merge pull request #2 from alexrudall/0.1.0
Browse files Browse the repository at this point in the history
MVP library!
  • Loading branch information
alexrudall committed Jul 18, 2023
2 parents 6f661c8 + a774026 commit 9417473
Show file tree
Hide file tree
Showing 14 changed files with 321 additions and 28 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Initialise repository.

## [0.1.0] - 2023-07-18

### Changed

- Got the gem working with the API. MVP
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
anthropic (0.0.0)
anthropic (0.1.0)
faraday (>= 1)
faraday-multipart (>= 1)

Expand Down
44 changes: 29 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/alexrudall/anthropic/blob/main/LICENSE.txt)
[![CircleCI Build Status](https://circleci.com/gh/alexrudall/anthropic.svg?style=shield)](https://circleci.com/gh/alexrudall/anthropic)

Use the [Anthropic API](https://anthropic.com/blog/anthropic-api/) with Ruby! 🤖❤️
Use the [Anthropic API](https://docs.anthropic.com/claude/reference/getting-started-with-the-api) with Ruby! 🌌❤️

This is very much a WIP and probably doesn't work as I don't have access to the Anthropic API as yet, but it will get a lot better once I do! Hopefully very soon :D
You can apply for access to the API [here](https://docs.anthropic.com/claude/docs/getting-access-to-claude).

[Ruby AI Builders Discord](https://discord.gg/k4Uc224xVD)

Expand Down Expand Up @@ -40,8 +40,7 @@ require "anthropic"

## Usage

- Get your API key from [https://platform.anthropic.com/account/api-keys](https://platform.anthropic.com/account/api-keys)
- If you belong to multiple organizations, you can get your Organization ID from [https://platform.anthropic.com/account/org-settings](https://platform.anthropic.com/account/org-settings)
- Get your API key from [https://console.anthropic.com/account/keys](https://console.anthropic.com/account/keys)

### Quickstart

Expand All @@ -67,26 +66,27 @@ Then you can create a client like this:
client = Anthropic::Client.new
```

#### Custom timeout or base URI
#### Change version or timeout

You can change to a different dated version (different from the URL version which is just `v1`) of Anthropic's API by passing `anthropic_version` when initializing the client. If you don't the default latest will be used, which is "2023-06-01". [More info](https://docs.anthropic.com/claude/reference/versioning)

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.

```ruby
client = Anthropic::Client.new(
access_token: "access_token_goes_here",
request_timeout: 240
anthropic_version: "2023-01-01", # Optional
request_timeout: 240 # Optional
)
```

or when configuring the gem:
You can also set these keys when configuring the gem:

```ruby
Anthropic.configure do |config|
config.access_token = ENV.fetch("ANTHROPIC_API_KEY")
config.anthropic_version = "2023-01-01" # Optional
config.request_timeout = 240 # Optional
config.extra_headers = {
"X-Proxy-Refresh": "true"
} # Optional
end
```

Expand All @@ -95,16 +95,30 @@ end
Hit the Anthropic API for a completion:

```ruby
response = client.completions(
response = client.complete(
parameters: {
model: "claude-2",
prompt: "Once upon a time",
max_tokens: 5
prompt: "How high is the sky?",
max_tokens_to_sample: 5
})
puts response["choices"].map { |c| c["text"] }
# => [", there lived a great"]
puts response["completion"]
# => " The sky has no definitive"
```

Note that all requests are prepended by this library with

`\n\nHuman: `

and appended with

`\n\nAssistant:`

so whatever prompt you pass will be sent to the API as

`\n\nHuman: How high is the sky?\n\nAssistant:`

This is a requirement of [the API](https://docs.anthropic.com/claude/reference/complete_post).

## Development

After checking out the repo, run `bin/setup` to install dependencies. You can run `bin/console` for an interactive prompt that will allow you to experiment.
Expand Down
2 changes: 1 addition & 1 deletion anthropic.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
spec.authors = ["Alex"]
spec.email = ["alexrudall@users.noreply.github.com"]

spec.summary = "Anthropic API + Ruby! 🤖❤️"
spec.summary = "Anthropic API + Ruby! 🌌❤️"
spec.homepage = "https://github.com/alexrudall/anthropic"
spec.license = "MIT"
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
Expand Down
9 changes: 4 additions & 5 deletions lib/anthropic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@

require_relative "anthropic/http"
require_relative "anthropic/client"
require_relative "anthropic/files"
require_relative "anthropic/finetunes"
require_relative "anthropic/images"
require_relative "anthropic/models"
require_relative "anthropic/version"

module Anthropic
Expand All @@ -15,15 +11,18 @@ class ConfigurationError < Error; end

class Configuration
attr_writer :access_token
attr_accessor :api_version, :organization_id, :uri_base, :request_timeout, :extra_headers
attr_accessor :anthropic_version, :api_version, :extra_headers, :organization_id,
:request_timeout, :uri_base

DEFAULT_API_VERSION = "v1".freeze
DEFAULT_ANTHROPIC_VERSION = "2023-06-01".freeze
DEFAULT_URI_BASE = "https://api.anthropic.com/".freeze
DEFAULT_REQUEST_TIMEOUT = 120

def initialize
@access_token = nil
@api_version = DEFAULT_API_VERSION
@anthropic_version = DEFAULT_ANTHROPIC_VERSION
@organization_id = nil
@uri_base = DEFAULT_URI_BASE
@request_timeout = DEFAULT_REQUEST_TIMEOUT
Expand Down
15 changes: 13 additions & 2 deletions lib/anthropic/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,19 @@ def initialize(access_token: nil, organization_id: nil, uri_base: nil, request_t
Anthropic.configuration.extra_headers = extra_headers
end

def completions(parameters: {})
Anthropic::Client.json_post(path: "/completions", parameters: parameters)
def complete(parameters: {})
parameters[:prompt] = wrap_prompt(prompt: parameters[:prompt])
Anthropic::Client.json_post(path: "/complete", parameters: parameters)
end

private

def wrap_prompt(prompt:, prefix: "\n\nHuman: ", suffix: "\n\nAssistant:")
return if prompt.nil?

prompt.prepend(prefix) unless prompt.start_with?(prefix)
prompt.concat(suffix) unless prompt.end_with?(suffix)
prompt
end
end
end
6 changes: 3 additions & 3 deletions lib/anthropic/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,16 @@ def uri(path:)
def headers
{
"Content-Type" => "application/json",
"Authorization" => "Bearer #{Anthropic.configuration.access_token}",
"Anthropic-Organization" => Anthropic.configuration.organization_id
"x-api-key" => Anthropic.configuration.access_token,
"Anthropic-Version" => Anthropic.configuration.anthropic_version
}.merge(Anthropic.configuration.extra_headers)
end

def multipart_parameters(parameters)
parameters&.transform_values do |value|
next value unless value.is_a?(File)

# Doesn't seem like Anthropic need mime_type yet, so not worth
# Doesn't seem like Anthropic needs mime_type yet, so not worth
# the library to figure this out. Hence the empty string
# as the second argument.
Faraday::UploadIO.new(value, "", value.path)
Expand Down
2 changes: 1 addition & 1 deletion lib/anthropic/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Anthropic
VERSION = "0.0.0".freeze
VERSION = "0.1.0".freeze
end
30 changes: 30 additions & 0 deletions spec/anthropic/client/complete_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
RSpec.describe Anthropic::Client do
describe "#complete" do
context "with a prompt and max_tokens", :vcr do
let(:prompt) { "How high is the sky?" }
let(:max_tokens) { 5 }

let(:response) do
Anthropic::Client.new.complete(
parameters: {
model: model,
max_tokens_to_sample: max_tokens,
prompt: prompt
}
)
end
let(:text) { response.dig("choices", 0, "text") }
let(:cassette) { "#{model} complete #{prompt}".downcase }

context "with model: claude-2" do
let(:model) { "claude-2" }

it "succeeds" do
VCR.use_cassette(cassette) do
expect(response["completion"].empty?).to eq(false)
end
end
end
end
end
end
58 changes: 58 additions & 0 deletions spec/anthropic_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
RSpec.describe Anthropic do
it "has a version number" do
expect(Anthropic::VERSION).not_to be nil
end

describe "#configure" do
let(:access_token) { "abc123" }
let(:api_version) { "v2" }
let(:organization_id) { "def456" }
let(:custom_uri_base) { "ghi789" }
let(:custom_request_timeout) { 25 }
let(:extra_headers) { { "User-Agent" => "Anthropic Ruby Gem #{Anthropic::VERSION}" } }

before do
Anthropic.configure do |config|
config.access_token = access_token
config.api_version = api_version
config.organization_id = organization_id
config.extra_headers = extra_headers
end
end

it "returns the config" do
expect(Anthropic.configuration.access_token).to eq(access_token)
expect(Anthropic.configuration.api_version).to eq(api_version)
expect(Anthropic.configuration.organization_id).to eq(organization_id)
expect(Anthropic.configuration.uri_base).to eq("https://api.anthropic.com/")
expect(Anthropic.configuration.request_timeout).to eq(120)
expect(Anthropic.configuration.extra_headers).to eq(extra_headers)
end

context "without an access token" do
let(:access_token) { nil }

it "raises an error" do
expect { Anthropic::Client.new.complete }.to raise_error(Anthropic::ConfigurationError)
end
end

context "with custom timeout and uri base" do
before do
Anthropic.configure do |config|
config.uri_base = custom_uri_base
config.request_timeout = custom_request_timeout
end
end

it "returns the config" do
expect(Anthropic.configuration.access_token).to eq(access_token)
expect(Anthropic.configuration.api_version).to eq(api_version)
expect(Anthropic.configuration.organization_id).to eq(organization_id)
expect(Anthropic.configuration.uri_base).to eq(custom_uri_base)
expect(Anthropic.configuration.request_timeout).to eq(custom_request_timeout)
expect(Anthropic.configuration.extra_headers).to eq(extra_headers)
end
end
end
end
33 changes: 33 additions & 0 deletions spec/compatibility_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
RSpec.describe "compatibility" do
context "for moved constants" do
describe "::Ruby::Anthropic::VERSION" do
it "is mapped to ::Anthropic::VERSION" do
expect(Ruby::Anthropic::VERSION).to eq(Anthropic::VERSION)
end
end

describe "::Ruby::Anthropic::Error" do
it "is mapped to ::Anthropic::Error" do
expect(Ruby::Anthropic::Error).to eq(Anthropic::Error)
expect(Ruby::Anthropic::Error.new).to be_a(Anthropic::Error)
expect(Anthropic::Error.new).to be_a(Ruby::Anthropic::Error)
end
end

describe "::Ruby::Anthropic::ConfigurationError" do
it "is mapped to ::Anthropic::ConfigurationError" do
expect(Ruby::Anthropic::ConfigurationError).to eq(Anthropic::ConfigurationError)
expect(Ruby::Anthropic::ConfigurationError.new).to be_a(Anthropic::ConfigurationError)
expect(Anthropic::ConfigurationError.new).to be_a(Ruby::Anthropic::ConfigurationError)
end
end

describe "::Ruby::Anthropic::Configuration" do
it "is mapped to ::Anthropic::Configuration" do
expect(Ruby::Anthropic::Configuration).to eq(Anthropic::Configuration)
expect(Ruby::Anthropic::Configuration.new).to be_a(Anthropic::Configuration)
expect(Anthropic::Configuration.new).to be_a(Ruby::Anthropic::Configuration)
end
end
end
end
48 changes: 48 additions & 0 deletions spec/fixtures/cassettes/claude-2_complete_how_high_is_the_sky_.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9417473

Please sign in to comment.