Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,3 @@ jobs:

- name: Run tests
run: ./scripts/test

2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.0.1-alpha.0"
".": "0.1.0-alpha.1"
}
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Changelog

## 0.1.0-alpha.1 (2025-03-13)

Full Changelog: [v0.0.1-alpha.0...v0.1.0-alpha.1](https://github.com/openai/openai-ruby/compare/v0.0.1-alpha.0...v0.1.0-alpha.1)

### Features

* support streaming uploads ([#1](https://github.com/openai/openai-ruby/issues/1)) ([8d5317a](https://github.com/openai/openai-ruby/commit/8d5317a4a3035e24de78d226658a821a8893a283))


### Bug Fixes

* enums should only coerce matching symbols into strings ([#3](https://github.com/openai/openai-ruby/issues/3)) ([0f4c842](https://github.com/openai/openai-ruby/commit/0f4c842a52c679ab0793fcdc32e5555fbbea4178))


### Chores

* improve documentation ([d9ce7ce](https://github.com/openai/openai-ruby/commit/d9ce7cedcc96ea81529fbaabf18dcab871dd412f))
* improve rbi typedef for page classes ([#6](https://github.com/openai/openai-ruby/issues/6)) ([3450adf](https://github.com/openai/openai-ruby/commit/3450adf1f6af58b6626e874866276414b71dcf22))
* **internal:** remove extra empty newlines ([#7](https://github.com/openai/openai-ruby/issues/7)) ([8ce4f87](https://github.com/openai/openai-ruby/commit/8ce4f87ca9496143d8c85000b0fb1f8b00eedea6))
* more accurate generic params for stream classes ([#8](https://github.com/openai/openai-ruby/issues/8)) ([c83ab37](https://github.com/openai/openai-ruby/commit/c83ab3717be335b49ef38663b759d14c92841f5c))
* refactor BasePage to have initializer ([#5](https://github.com/openai/openai-ruby/issues/5)) ([43e80fa](https://github.com/openai/openai-ruby/commit/43e80fa252a9b1ae4d5c219dd9d346f0b0c3194f))
* remove stale thread local checks ([#4](https://github.com/openai/openai-ruby/issues/4)) ([69e8be8](https://github.com/openai/openai-ruby/commit/69e8be897fe8cff1ed9b0ea7ef53a759a9a089ff))
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GIT
PATH
remote: .
specs:
openai (0.0.1.pre.alpha.0)
openai (0.1.0.pre.alpha.1)
connection_pool

GEM
Expand Down
1 change: 1 addition & 0 deletions lib/openai.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require "etc"
require "json"
require "net/http"
require "pathname"
require "rbconfig"
require "securerandom"
require "set"
Expand Down
29 changes: 25 additions & 4 deletions lib/openai/base_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ def type_info(spec)
type_info(spec.slice(:const, :enum, :union).first&.last)
in Proc
spec
in OpenAI::Converter | Class
in OpenAI::Converter | Class | Symbol
-> { spec }
in true | false
-> { OpenAI::BooleanModel }
in NilClass | true | false | Symbol | Integer | Float
in NilClass | Integer | Float
-> { spec.class }
end
end
Expand All @@ -82,6 +82,13 @@ def coerce(target, value)
case target
in OpenAI::Converter
target.coerce(value)
in Symbol
case value
in Symbol | String if (val = value.to_sym) == target
val
else
value
end
in Class
case target
in -> { _1 <= NilClass }
Expand Down Expand Up @@ -140,6 +147,13 @@ def try_strict_coerce(target, value)
case target
in OpenAI::Converter
target.try_strict_coerce(value)
in Symbol
case value
in Symbol | String if (val = value.to_sym) == target
[true, val, 1]
else
[false, false, 0]
end
in Class
case [target, value]
in [-> { _1 <= NilClass }, _]
Expand Down Expand Up @@ -367,7 +381,14 @@ class << self
#
# @return [Symbol, Object]
#
def coerce(value) = (value.is_a?(String) ? value.to_sym : value)
def coerce(value)
case value
in Symbol | String if values.include?(val = value.to_sym)
val
else
value
end
end

# @!parse
# # @private
Expand All @@ -388,7 +409,7 @@ def try_strict_coerce(value)
return [true, value, 1] if values.include?(value)

case value
in String if values.include?(val = value.to_sym)
in Symbol | String if values.include?(val = value.to_sym)
[true, val, 1]
else
case [value, values.first]
Expand Down
21 changes: 12 additions & 9 deletions lib/openai/base_page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,17 @@

alias_method :enum_for, :to_enum

# @!parse
# # @private
# #
# # @param client [OpenAI::BaseClient]
# # @param req [Hash{Symbol=>Object}]
# # @param headers [Hash{String=>String}, Net::HTTPHeader]
# # @param page_data [Object]
# #
# def initialize(client:, req:, headers:, page_data:); end
# @private
#
# @param client [OpenAI::BaseClient]
# @param req [Hash{Symbol=>Object}]
# @param headers [Hash{String=>String}, Net::HTTPHeader]
# @param page_data [Object]
#
def initialize(client:, req:, headers:, page_data:)

Check warning on line 57 in lib/openai/base_page.rb

View workflow job for this annotation

GitHub Actions / lint

Lint/UnusedMethodArgument: Unused method argument - `headers`.

Check warning on line 57 in lib/openai/base_page.rb

View workflow job for this annotation

GitHub Actions / lint

Lint/UnusedMethodArgument: Unused method argument - `page_data`.
@client = client
@req = req
super()
end
end
end
40 changes: 20 additions & 20 deletions lib/openai/base_stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,17 @@ module OpenAI
#
# messages => Array
# ```
class BaseStream
# @private
#
# @param model [Class, OpenAI::Converter]
# @param url [URI::Generic]
# @param status [Integer]
# @param response [Net::HTTPResponse]
# @param messages [Enumerable]
module BaseStream
# @return [void]
#
def initialize(model:, url:, status:, response:, messages:)
@model = model
@url = url
@status = status
@response = response
@messages = messages
@iterator = iterator
end
def close = OpenAI::Util.close_fused!(@iterator)

# @private
#
# @return [Enumerable]
#
private def iterator = (raise NotImplementedError)

# @return [void]
#
def close = OpenAI::Util.close_fused!(@iterator)

# @param blk [Proc]
#
# @return [void]
Expand All @@ -60,5 +43,22 @@ def for_each(&)
def to_enum = @iterator

alias_method :enum_for, :to_enum

# @private
#
# @param model [Class, OpenAI::Converter]
# @param url [URI::Generic]
# @param status [Integer]
# @param response [Net::HTTPResponse]
# @param messages [Enumerable]
#
def initialize(model:, url:, status:, response:, messages:)
@model = model
@url = url
@status = status
@response = response
@messages = messages
@iterator = iterator
end
end
end
6 changes: 1 addition & 5 deletions lib/openai/cursor_page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
# @return [Boolean]
attr_accessor :has_more

# rubocop:disable Lint/UnusedMethodArgument
# @private
#
# @param client [OpenAI::BaseClient]
Expand All @@ -39,8 +38,7 @@
# @param page_data [Hash{Symbol=>Object}]
#
def initialize(client:, req:, headers:, page_data:)
@client = client
@req = req
super
model = req.fetch(:model)

case page_data
Expand All @@ -55,10 +53,8 @@
else
end
end
# rubocop:enable Lint/UnusedMethodArgument

# @return [Boolean]
#
def next_page?
has_more
end
Expand All @@ -68,7 +64,7 @@
#
def next_page
unless next_page?
raise RuntimeError.new("No more pages available. Please check #next_page? before calling ##{__method__}")

Check warning on line 67 in lib/openai/cursor_page.rb

View workflow job for this annotation

GitHub Actions / lint

Layout/LineLength: Line is too long. [113/110]
end

req = OpenAI::Util.deep_merge(@req, {query: {after: data&.last&.id}})
Expand Down
6 changes: 1 addition & 5 deletions lib/openai/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class Page
# @return [String]
attr_accessor :object

# rubocop:disable Lint/UnusedMethodArgument
# @private
#
# @param client [OpenAI::BaseClient]
Expand All @@ -39,8 +38,7 @@ class Page
# @param page_data [Array<Object>]
#
def initialize(client:, req:, headers:, page_data:)
@client = client
@req = req
super
model = req.fetch(:model)

case page_data
Expand All @@ -55,10 +53,8 @@ def initialize(client:, req:, headers:, page_data:)
else
end
end
# rubocop:enable Lint/UnusedMethodArgument

# @return [Boolean]
#
def next_page?
false
end
Expand Down
51 changes: 23 additions & 28 deletions lib/openai/pooled_net_requester.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@
#
# @option request [Hash{String=>String}] :headers
#
# @param blk [Proc]
#
# @return [Net::HTTPGenericRequest]
#
def build_request(request)
def build_request(request, &)
method, url, headers, body = request.fetch_values(:method, :url, :headers, :body)
req = Net::HTTPGenericRequest.new(
method.to_s.upcase,
Expand All @@ -62,14 +64,16 @@
headers.each { req[_1] = _2 }

case body
in nil

Check warning on line 67 in lib/openai/pooled_net_requester.rb

View workflow job for this annotation

GitHub Actions / lint

Lint/EmptyInPattern: Avoid `in` branches without a body.
in String
req.body = body
req["content-length"] ||= body.bytesize.to_s unless req["transfer-encoding"]
req.body_stream = OpenAI::Util::ReadIOAdapter.new(body, &)
in StringIO
req.body = body.string
in IO
body.rewind
req.body_stream = body
req["content-length"] ||= body.size.to_s unless req["transfer-encoding"]
req.body_stream = OpenAI::Util::ReadIOAdapter.new(body, &)
in IO | Enumerator
req["transfer-encoding"] ||= "chunked" unless req["content-length"]
req.body_stream = OpenAI::Util::ReadIOAdapter.new(body, &)
end

req
Expand All @@ -81,33 +85,16 @@
# @param url [URI::Generic]
# @param blk [Proc]
#
private def with_pool(url, &blk)
private def with_pool(url, &)
origin = OpenAI::Util.uri_origin(url)
th = Thread.current
key = :"#{object_id}-#{self.class.name}-connection_in_use_for_#{origin}"

if th[key]
tap do
conn = self.class.connect(url)
return blk.call(conn)
ensure
conn.finish if conn&.started?
end
end

pool =
@mutex.synchronize do
@pools[origin] ||= ConnectionPool.new(size: Etc.nprocessors) do
@pools[origin] ||= ConnectionPool.new(size: @size) do
self.class.connect(url)
end
end

pool.with do |conn|
th[key] = true
blk.call(conn)
ensure
th[key] = nil
end
pool.with(&)
end

# @private
Expand All @@ -128,14 +115,17 @@
#
def execute(request)
url, deadline = request.fetch_values(:url, :deadline)
req = self.class.build_request(request)

eof = false
finished = false
enum = Enumerator.new do |y|
with_pool(url) do |conn|
next if finished

req = self.class.build_request(request) do
self.class.calibrate_socket_timeout(conn, deadline)
end

self.class.calibrate_socket_timeout(conn, deadline)
conn.start unless conn.started?

Expand Down Expand Up @@ -168,8 +158,13 @@
[response, (response.body = body)]
end

def initialize
# @private
#
# @param size [Integer]
#
def initialize(size: Etc.nprocessors)
@mutex = Mutex.new
@size = size
@pools = {}
end
end
Expand Down
4 changes: 3 additions & 1 deletion lib/openai/stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ module OpenAI
#
# messages => Array
# ```
class Stream < OpenAI::BaseStream
class Stream
include OpenAI::BaseStream

# @private
#
# @return [Enumerable]
Expand Down
Loading
Loading