openai 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc9304025c682d75de3129464936ea78f4dd4557eede83d2d7991c5eff42fc12
4
- data.tar.gz: 75a67fb05f17a2c21b6e4921ee4c182148b0946bcbe759943d8ffb1a60198f89
3
+ metadata.gz: 72e52493a36fa127172247c0db2f53153cdbb9ff1f3025d007fe9638e9298a77
4
+ data.tar.gz: 011f3c8fd9b2704f57a65bd406d7ea62efcfe17637c90a95ce3db97c02cfc3a5
5
5
  SHA512:
6
- metadata.gz: dcfa0890195ceaf0518f43383e3b7e1816a3fcba9872f90f2cd9b1966bf67b386c9020363bc43c3958a40caa085d5a1a23517cb8284e556cd0622a9471554e3b
7
- data.tar.gz: 4fac147f449433f8e483646407ea4cba9b3b467b8c0b6e29bc986612f68b20e9adf83964898639f9fdbd3ac0232375d69046c3eb7207ebc9d7052f97c91b4317
6
+ metadata.gz: 7a3dcb467a183d8d7c73b0a3cdc1026e26e07f84957044c4dd7d2ba586fefb68af85aacf092f460005f99191e2ec609b545bf987cec3511538423e4fdcbad768
7
+ data.tar.gz: b71e17545c81c4399bcb485e750f6222d8ca43c1744452e7477aadb988f8eec4dfbfb9aa4b28308d930153f336a77dd4b916add2c4c454c4c78da399cd658848
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ Gemfile.lock
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.6.6
6
+ before_install: gem install bundler -v 2.1.4
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020 TODO: Nilesh Trivedi
3
+ Copyright (c) 2020 Nilesh Trivedi, Erik Berlin
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Openai
1
+ # OpenAI API client library to access GPT-3 in Ruby
2
2
 
3
3
  This is a wrapper for calling OpenAI and GPT-3's HTTP APIs. API docs are available here: https://beta.openai.com/api-docs
4
4
 
@@ -20,19 +20,28 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- ```
24
- require 'openai'
25
- client = Openai::Client.new(pk: "your_public_key", sk: "your_secret_key")
26
- completions = client.completions(prompt: "Have you wondered why", max_tokens: 10)
27
- ```
23
+ ```ruby
24
+ require "openai"
28
25
 
29
- This should return a Hash which is something like:
26
+ openai_client = OpenAI::Client.new(api_key: ENV.fetch("OPENAI_API_KEY"), default_engine: "ada")
30
27
 
31
- ```
32
- => {"id"=>"cmpl-LMDA7GAlzSHvB6ZEUeFwvipv", "object"=>"text_completion", "created"=>1595276408, "model"=>"davinci:2020-05-03", "choices"=>[{"text"=>" airlines charge more for certain seats?\n\nOne", "index"=>0, "logprobs"=>nil, "finish_reason"=>"length"}]}
28
+ # List Engines
29
+ openai_client.engines
33
30
 
31
+ # Retrieve Engine
32
+ openai_client.engine("babbage")
33
+
34
+ # Search
35
+ openai_client.search(documents: ["White House", "hospital", "school"], query: "the president")
36
+
37
+ # Create Completion
38
+ openai_client.completions(prompt: "Once upon a time", max_tokens: 5)
34
39
  ```
35
40
 
41
+ ## TODO
42
+
43
+ * Stream Completion
44
+
36
45
  ## Development
37
46
 
38
47
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile CHANGED
@@ -1,2 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
- task :default => :spec
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -1,29 +1,7 @@
1
+ require "openai/choice"
2
+ require "openai/client"
3
+ require "openai/completion"
4
+ require "openai/engine"
5
+ require "openai/logprobs"
6
+ require "openai/search_result"
1
7
  require "openai/version"
2
- require "httparty"
3
-
4
- module Openai
5
- class Client
6
- BASE_URL = "https://api.openai.com/v1/engines/davinci"
7
-
8
- attr_accessor :pk, :sk
9
-
10
- def initialize(pk:, sk:)
11
- @pk, @sk = pk, sk
12
- end
13
-
14
- def completions(prompt:, max_tokens: 5)
15
- response = HTTParty.post(BASE_URL + "/completions", headers: self.headers, body: {
16
- prompt: prompt,
17
- max_tokens: max_tokens
18
- }.to_json)
19
- return JSON.parse(response.body)
20
- end
21
-
22
- def headers
23
- {
24
- "Content-Type" => "application/json",
25
- "Authorization" => "Bearer #{@sk}"
26
- }
27
- end
28
- end
29
- end
@@ -0,0 +1,3 @@
1
+ module OpenAI
2
+ Choice = Struct.new(:finish_reason, :index, :logprobs, :text, keyword_init: true)
3
+ end
@@ -0,0 +1,139 @@
1
+ require "json"
2
+ require "net/http"
3
+ require "time"
4
+ require "uri"
5
+
6
+ module OpenAI
7
+ class Client
8
+ class Error < RuntimeError
9
+ end
10
+
11
+ LastResponse = Struct.new(:date, :organization, :processing_ms, :request_id, :status_code, :status_message, keyword_init: true)
12
+
13
+ attr_reader :last_response
14
+ attr_writer :api_key
15
+ attr_accessor :default_engine
16
+
17
+ def initialize(api_key:, default_engine: "davinci")
18
+ @api_key = api_key
19
+ @default_engine = default_engine
20
+ end
21
+
22
+ def engine(id = default_engine)
23
+ engine = get("/v1/engines/#{id}")
24
+ Engine.new(**engine)
25
+ end
26
+
27
+ def engines
28
+ engines = get("/v1/engines")
29
+ engines[:data].map do |engine|
30
+ Engine.new(**engine)
31
+ end
32
+ end
33
+
34
+ def completions(prompt: nil, max_tokens: nil, temperature: nil, top_p: nil, n: nil, logprobs: nil, echo: nil, stop: nil, presence_penalty: nil, frequency_penalty: nil, engine: default_engine)
35
+ body = {
36
+ "prompt" => prompt,
37
+ "max_tokens" => max_tokens,
38
+ "temperature" => temperature,
39
+ "top_p" => top_p,
40
+ "n" => n,
41
+ "logprobs" => logprobs,
42
+ "echo" => echo,
43
+ "stop" => stop,
44
+ "presence_penalty" => presence_penalty,
45
+ "frequency_penalty" => frequency_penalty,
46
+ }.compact
47
+
48
+ completion = post("/v1/engines/#{engine}/completions", body: body)
49
+
50
+ choices = completion[:choices]&.map do |choice|
51
+ Choice.new(
52
+ finish_reason: choice[:finish_reason],
53
+ index: choice[:index],
54
+ text: choice[:text],
55
+ logprobs: choice[:logprobs]&.tap do |logprob|
56
+ Logprobs.new(
57
+ text_offset: logprob[:text_offset],
58
+ token_logprobs: logprob[:token_logprobs],
59
+ tokens: logprob[:tokens],
60
+ top_logprobs: logprob[:top_logprobs]
61
+ )
62
+ end
63
+ )
64
+ end
65
+
66
+ Completion.new(
67
+ choices: choices,
68
+ created: completion[:created],
69
+ id: completion[:id],
70
+ model: completion[:model],
71
+ object: completion[:object]
72
+ )
73
+ end
74
+
75
+ def search(documents:, query:, engine: default_engine)
76
+ body = {
77
+ "documents" => documents,
78
+ "query" => query,
79
+ }.compact
80
+
81
+ search_results = post("/v1/engines/#{engine}/search", body: body)
82
+ search_results[:data].map.with_index do |datum, index|
83
+ SearchResult.new(**datum).tap do |result|
84
+ result.text = documents[index]
85
+ end
86
+ end
87
+ end
88
+
89
+ private def get(path)
90
+ uri = URI.parse("https://api.openai.com#{path}")
91
+ req = Net::HTTP::Get.new(uri)
92
+ headers.each do |name, value|
93
+ req[name] = value
94
+ end
95
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
96
+ http.request(req)
97
+ end
98
+ handle_response(response)
99
+ end
100
+
101
+ private def post(path, body: nil)
102
+ uri = URI.parse("https://api.openai.com#{path}")
103
+ req = Net::HTTP::Post.new(uri)
104
+ req.body = body.to_json
105
+ headers.each do |name, value|
106
+ req[name] = value
107
+ end
108
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
109
+ http.request(req)
110
+ end
111
+ handle_response(response)
112
+ end
113
+
114
+ private def handle_response(response)
115
+ date = Time.httpdate(response["date"]) if response["date"]
116
+ organization = response["openai-organization"]
117
+ processing_ms = response["openai-processing-ms"]&.to_i
118
+ request_id = response["x-request-id"]
119
+ status_code = response.code&.to_i
120
+ status_message = response.message
121
+ @last_response = LastResponse.new(date: date, organization: organization, processing_ms: processing_ms, request_id: request_id, status_code: status_code, status_message: status_message)
122
+
123
+ response_body = JSON.parse(response.body, symbolize_names: true)
124
+ case response
125
+ when Net::HTTPSuccess
126
+ response_body
127
+ else
128
+ raise Error, response_body[:error][:message].to_s
129
+ end
130
+ end
131
+
132
+ private def headers
133
+ @headers ||= {
134
+ "Authorization" => "Bearer #{@api_key}",
135
+ "Content-Type" => "application/json",
136
+ }
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,7 @@
1
+ module OpenAI
2
+ Completion = Struct.new(:choices, :created, :id, :model, :object, keyword_init: true) do
3
+ def created_at
4
+ Time.at(created)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module OpenAI
2
+ Engine = Struct.new(:id, :object, :owner, :ready, keyword_init: true)
3
+ end
@@ -0,0 +1,3 @@
1
+ module OpenAI
2
+ Logprobs = Struct.new(:tokens, :token_logprobs, :top_logprobs, :text_offset, keyword_init: true)
3
+ end
@@ -0,0 +1,3 @@
1
+ module OpenAI
2
+ SearchResult = Struct.new(:document, :object, :score, :text, keyword_init: true)
3
+ end
@@ -1,3 +1,3 @@
1
- module Openai
2
- VERSION = "0.1.0"
1
+ module OpenAI
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -1,17 +1,16 @@
1
- lib = File.expand_path("lib", __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "openai/version"
1
+ require_relative "lib/openai/version"
4
2
 
5
3
  Gem::Specification.new do |spec|
6
4
  spec.name = "openai"
7
- spec.version = Openai::VERSION
8
- spec.authors = ["Nilesh Trivedi"]
9
- spec.email = ["git@nileshtrivedi.com"]
5
+ spec.version = OpenAI::VERSION
6
+ spec.authors = ["Nilesh Trivedi", "Erik Berlin"]
7
+ spec.email = ["git@nileshtrivedi.com", "sferik@gmail.com"]
10
8
 
11
- spec.summary = %q{Wrapper for OpenAI / GPT-3's HTTP APIs}
12
- spec.description = %q{Wrapper for OpenAI / GPT-3's HTTP APIs}
9
+ spec.summary = "OpenAI API client library to access GPT-3 in Ruby"
10
+ spec.description = "OpenAI API client library to access GPT-3 in Ruby"
13
11
  spec.homepage = "https://github.com/nileshtrivedi/openai"
14
12
  spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
15
14
 
16
15
  spec.metadata["homepage_uri"] = spec.homepage
17
16
  spec.metadata["source_code_uri"] = "https://github.com/nileshtrivedi/openai"
@@ -19,14 +18,15 @@ Gem::Specification.new do |spec|
19
18
 
20
19
  # Specify which files should be added to the gem when it is released.
21
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
23
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
23
  end
25
24
  spec.bindir = "exe"
26
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
26
  spec.require_paths = ["lib"]
28
27
 
29
- spec.add_development_dependency "bundler", "~> 2.0"
30
- spec.add_development_dependency "rake", "~> 10.0"
31
- spec.add_dependency "httparty", ">= 0.17.0"
28
+ spec.add_development_dependency "bundler", ">= 2"
29
+ spec.add_development_dependency "rake", ">= 10"
30
+ spec.add_development_dependency "rspec", ">= 3.9"
31
+ spec.add_development_dependency "webmock", ">= 3.8"
32
32
  end
metadata CHANGED
@@ -1,65 +1,82 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nilesh Trivedi
8
- autorequire:
8
+ - Erik Berlin
9
+ autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2020-07-20 00:00:00.000000000 Z
12
+ date: 2020-09-17 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
15
16
  requirement: !ruby/object:Gem::Requirement
16
17
  requirements:
17
- - - "~>"
18
+ - - ">="
18
19
  - !ruby/object:Gem::Version
19
- version: '2.0'
20
+ version: '2'
20
21
  type: :development
21
22
  prerelease: false
22
23
  version_requirements: !ruby/object:Gem::Requirement
23
24
  requirements:
24
- - - "~>"
25
+ - - ">="
25
26
  - !ruby/object:Gem::Version
26
- version: '2.0'
27
+ version: '2'
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: rake
29
30
  requirement: !ruby/object:Gem::Requirement
30
31
  requirements:
31
- - - "~>"
32
+ - - ">="
32
33
  - !ruby/object:Gem::Version
33
- version: '10.0'
34
+ version: '10'
34
35
  type: :development
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
38
- - - "~>"
39
+ - - ">="
39
40
  - !ruby/object:Gem::Version
40
- version: '10.0'
41
+ version: '10'
41
42
  - !ruby/object:Gem::Dependency
42
- name: httparty
43
+ name: rspec
43
44
  requirement: !ruby/object:Gem::Requirement
44
45
  requirements:
45
46
  - - ">="
46
47
  - !ruby/object:Gem::Version
47
- version: 0.17.0
48
- type: :runtime
48
+ version: '3.9'
49
+ type: :development
49
50
  prerelease: false
50
51
  version_requirements: !ruby/object:Gem::Requirement
51
52
  requirements:
52
53
  - - ">="
53
54
  - !ruby/object:Gem::Version
54
- version: 0.17.0
55
- description: Wrapper for OpenAI / GPT-3's HTTP APIs
55
+ version: '3.9'
56
+ - !ruby/object:Gem::Dependency
57
+ name: webmock
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '3.8'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '3.8'
70
+ description: OpenAI API client library to access GPT-3 in Ruby
56
71
  email:
57
72
  - git@nileshtrivedi.com
73
+ - sferik@gmail.com
58
74
  executables: []
59
75
  extensions: []
60
76
  extra_rdoc_files: []
61
77
  files:
62
78
  - ".gitignore"
79
+ - ".travis.yml"
63
80
  - Gemfile
64
81
  - LICENSE.txt
65
82
  - README.md
@@ -67,6 +84,12 @@ files:
67
84
  - bin/console
68
85
  - bin/setup
69
86
  - lib/openai.rb
87
+ - lib/openai/choice.rb
88
+ - lib/openai/client.rb
89
+ - lib/openai/completion.rb
90
+ - lib/openai/engine.rb
91
+ - lib/openai/logprobs.rb
92
+ - lib/openai/search_result.rb
70
93
  - lib/openai/version.rb
71
94
  - openai.gemspec
72
95
  homepage: https://github.com/nileshtrivedi/openai
@@ -76,7 +99,7 @@ metadata:
76
99
  homepage_uri: https://github.com/nileshtrivedi/openai
77
100
  source_code_uri: https://github.com/nileshtrivedi/openai
78
101
  changelog_uri: https://github.com/nileshtrivedi/openai/blob/master/changelog.md
79
- post_install_message:
102
+ post_install_message:
80
103
  rdoc_options: []
81
104
  require_paths:
82
105
  - lib
@@ -84,15 +107,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
84
107
  requirements:
85
108
  - - ">="
86
109
  - !ruby/object:Gem::Version
87
- version: '0'
110
+ version: 2.3.0
88
111
  required_rubygems_version: !ruby/object:Gem::Requirement
89
112
  requirements:
90
113
  - - ">="
91
114
  - !ruby/object:Gem::Version
92
115
  version: '0'
93
116
  requirements: []
94
- rubygems_version: 3.0.3
95
- signing_key:
117
+ rubygems_version: 3.1.2
118
+ signing_key:
96
119
  specification_version: 4
97
- summary: Wrapper for OpenAI / GPT-3's HTTP APIs
120
+ summary: OpenAI API client library to access GPT-3 in Ruby
98
121
  test_files: []