module OpenAI::HTTP

def configure_json_post_request(req, parameters)

def configure_json_post_request(req, parameters)
  req_parameters = parameters.dup
  if parameters[:stream].respond_to?(:call)
    req.options.on_data = to_json_stream(user_proc: parameters[:stream])
    req_parameters[:stream] = true # Necessary to tell OpenAI to stream.
  elsif parameters[:stream]
    raise ArgumentError, "The stream parameter must be a Proc or have a #call method"
  end
  req.headers = headers
  req.body = req_parameters.to_json
end

def conn(multipart: false)

def conn(multipart: false)
  connection = Faraday.new do |f|
    f.options[:timeout] = @request_timeout
    f.request(:multipart) if multipart
    f.use MiddlewareErrors if @log_errors
    f.response :raise_error
    f.response :json
  end
  @faraday_middleware&.call(connection)
  connection
end

def delete(path:)

def delete(path:)
  conn.delete(uri(path: path)) do |req|
    req.headers = headers
  end&.body
end

def get(path:, parameters: nil)

def get(path:, parameters: nil)
  parse_jsonl(conn.get(uri(path: path), parameters) do |req|
    req.headers = headers
  end&.body)
end

def json_post(path:, parameters:, query_parameters: {})

def json_post(path:, parameters:, query_parameters: {})
  conn.post(uri(path: path)) do |req|
    configure_json_post_request(req, parameters)
    req.params = req.params.merge(query_parameters)
  end&.body
end

def multipart_parameters(parameters)

def multipart_parameters(parameters)
  parameters&.transform_values do |value|
    next value unless value.respond_to?(:close) # File or IO object.
    # Faraday::UploadIO does not require a path, so we will pass it
    # only if it is available. This allows StringIO objects to be
    # passed in as well.
    path = value.respond_to?(:path) ? value.path : nil
    # Doesn't seem like OpenAI 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, "", path)
  end
end

def multipart_post(path:, parameters: nil)

def multipart_post(path:, parameters: nil)
  conn(multipart: true).post(uri(path: path)) do |req|
    req.headers = headers.merge({ "Content-Type" => "multipart/form-data" })
    req.body = multipart_parameters(parameters)
  end&.body
end

def parse_jsonl(response)

def parse_jsonl(response)
  return unless response
  return response unless response.is_a?(String)
  # Convert a multiline string of JSON objects to a JSON array.
  response = response.gsub("}\n{", "},{").prepend("[").concat("]")
  JSON.parse(response)
end

def post(path:)

def post(path:)
  parse_jsonl(conn.post(uri(path: path)) do |req|
    req.headers = headers
  end&.body)
end

def to_json_stream(user_proc:)

Returns:
  • (Proc) - An outer proc that iterates over a raw stream, converting it to JSON.

Parameters:
  • user_proc (Proc) -- The inner proc to call for each JSON object in the chunk.
def to_json_stream(user_proc:)
  parser = EventStreamParser::Parser.new
  proc do |chunk, _bytes, env|
    if env && env.status != 200
      raise_error = Faraday::Response::RaiseError.new
      raise_error.on_complete(env.merge(body: try_parse_json(chunk)))
    end
    parser.feed(chunk) do |_type, data|
      user_proc.call(JSON.parse(data)) unless data == "[DONE]"
    end
  end
end

def try_parse_json(maybe_json)

def try_parse_json(maybe_json)
  JSON.parse(maybe_json)
rescue JSON::ParserError
  maybe_json
end

def uri(path:)

def uri(path:)
  if azure?
    base = File.join(@uri_base, path)
    "#{base}?api-version=#{@api_version}"
  elsif @uri_base.include?(@api_version)
    File.join(@uri_base, path)
  else
    File.join(@uri_base, @api_version, path)
  end
end