openai 0.1.0 → 0.3.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: 6ee67a9b3d968722ffe2901e657fb79d3b07f0b3e67f0fd61e4b07735c1c5743
4
+ data.tar.gz: 878ef00970a2fbcbdafd07976771b8c37115e5a2d4bf25741858e2608783a58d
5
5
  SHA512:
6
- metadata.gz: dcfa0890195ceaf0518f43383e3b7e1816a3fcba9872f90f2cd9b1966bf67b386c9020363bc43c3958a40caa085d5a1a23517cb8284e556cd0622a9471554e3b
7
- data.tar.gz: 4fac147f449433f8e483646407ea4cba9b3b467b8c0b6e29bc986612f68b20e9adf83964898639f9fdbd3ac0232375d69046c3eb7207ebc9d7052f97c91b4317
6
+ metadata.gz: c598a3ae743d03d52127897c4bce139d8ce57f853b3f9f091438003fde3c78c22c4356ef8c32fce7961da5f3b18df1a610306031922778d53bf802d1157dac62
7
+ data.tar.gz: 68d607a2a3e618db3e3f9c49b6eaae56efb0496ce63051609c837cde318df4308213cb1b13c8228f3a33643dd4e088ed79ab988c2c6215672096bd2f157c9b0d
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ Gemfile.lock
data/.travis.yml ADDED
@@ -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
data/LICENSE.txt CHANGED
@@ -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
@@ -0,0 +1,3 @@
1
+ module OpenAI
2
+ Choice = Struct.new(:finish_reason, :index, :logprobs, :text, keyword_init: true)
3
+ end
@@ -0,0 +1,140 @@
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, best_of: 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
+ "best_of" => best_of,
47
+ }.compact
48
+
49
+ completion = post("/v1/engines/#{engine}/completions", body: body)
50
+
51
+ choices = completion[:choices]&.map do |choice|
52
+ Choice.new(
53
+ finish_reason: choice[:finish_reason],
54
+ index: choice[:index],
55
+ text: choice[:text],
56
+ logprobs: choice[:logprobs]&.tap do |logprob|
57
+ Logprobs.new(
58
+ text_offset: logprob[:text_offset],
59
+ token_logprobs: logprob[:token_logprobs],
60
+ tokens: logprob[:tokens],
61
+ top_logprobs: logprob[:top_logprobs]
62
+ )
63
+ end
64
+ )
65
+ end
66
+
67
+ Completion.new(
68
+ choices: choices,
69
+ created: completion[:created],
70
+ id: completion[:id],
71
+ model: completion[:model],
72
+ object: completion[:object]
73
+ )
74
+ end
75
+
76
+ def search(documents:, query:, engine: default_engine)
77
+ body = {
78
+ "documents" => documents,
79
+ "query" => query,
80
+ }.compact
81
+
82
+ search_results = post("/v1/engines/#{engine}/search", body: body)
83
+ search_results[:data].map.with_index do |datum, index|
84
+ SearchResult.new(**datum).tap do |result|
85
+ result.text = documents[index]
86
+ end
87
+ end
88
+ end
89
+
90
+ private def get(path)
91
+ uri = URI.parse("https://api.openai.com#{path}")
92
+ req = Net::HTTP::Get.new(uri)
93
+ headers.each do |name, value|
94
+ req[name] = value
95
+ end
96
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
97
+ http.request(req)
98
+ end
99
+ handle_response(response)
100
+ end
101
+
102
+ private def post(path, body: nil)
103
+ uri = URI.parse("https://api.openai.com#{path}")
104
+ req = Net::HTTP::Post.new(uri)
105
+ req.body = body.to_json
106
+ headers.each do |name, value|
107
+ req[name] = value
108
+ end
109
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
110
+ http.request(req)
111
+ end
112
+ handle_response(response)
113
+ end
114
+
115
+ private def handle_response(response)
116
+ date = Time.httpdate(response["date"]) if response["date"]
117
+ organization = response["openai-organization"]
118
+ processing_ms = response["openai-processing-ms"]&.to_i
119
+ request_id = response["x-request-id"]
120
+ status_code = response.code&.to_i
121
+ status_message = response.message
122
+ @last_response = LastResponse.new(date: date, organization: organization, processing_ms: processing_ms, request_id: request_id, status_code: status_code, status_message: status_message)
123
+
124
+ response_body = JSON.parse(response.body, symbolize_names: true)
125
+ case response
126
+ when Net::HTTPSuccess
127
+ response_body
128
+ else
129
+ raise Error, response_body[:error][:message].to_s
130
+ end
131
+ end
132
+
133
+ private def headers
134
+ @headers ||= {
135
+ "Authorization" => "Bearer #{@api_key}",
136
+ "Content-Type" => "application/json",
137
+ }
138
+ end
139
+ end
140
+ 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.3.0".freeze
3
3
  end
data/lib/openai.rb CHANGED
@@ -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
data/openai.gemspec CHANGED
@@ -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.3.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: 2023-02-07 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.2.33
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: []