openai 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []