module Datarobot::AiApi

Public Class Methods

add_headers(request, additional_headers={}) click to toggle source

Adds default headers to a net http request @param [Net::HTTP::*] request The net/http request to add the headers to @param [Hash] additional_headers Will overwrite defaults @return [Net::Http::*] returns an aribitrary request type (GET/POST/etc.)

# File lib/datarobot/ai_api.rb, line 43
def self.add_headers(request, additional_headers={})
  request["User-Agent"] = "datarobot-ai/ruby"
  request["Content-Type"] = "application/json"
  request["Authorization"] = "Bearer #{@@api_key}"
  additional_headers.each do |k, v|
    request[k] = v
  end
  request
end
api_key() click to toggle source
# File lib/datarobot/ai_api.rb, line 15
def self.api_key; @@api_key end
api_key=(v;) click to toggle source
# File lib/datarobot/ai_api.rb, line 16
def self.api_key= v; @@api_key = v end
configure!(api_key: '', base_url: nil) click to toggle source

Sets global API key @param [String] api_key The api key to use for authentication @return [Datarobot::AiApi]

# File lib/datarobot/ai_api.rb, line 21
def self.configure!(api_key: '', base_url: nil)
  @@api_key = api_key
  @@base_url = base_url if base_url
  self
end
create(name: 'New AI') click to toggle source

Creates an AI

@param [String] name The ID of the AI to retrieve

@return [Datarobot::AiApi::AI]

# File lib/datarobot/ai_api/ai.rb, line 44
def self.create(name: 'New AI')
  Datarobot::AiApi.request_endpoint('/aiapi/ais/', method: 'post', body: { name: name }) do |data|
    ai_data = Datarobot::AiApi.get(data["links"]["result"])
    new(ai_data)
  end
end
delete(id) click to toggle source

Deletes an AI. Returns `nil` if the action was successful. Will raise an error if the action was unsuccessful

@param [String] id The ID of the AI to delete

@return [nil]

# File lib/datarobot/ai_api/ai.rb, line 57
def self.delete(id)
  Datarobot::AiApi.request_endpoint("/aiapi/ais/#{id}", method: "delete")
end
determine_error(response_obj) click to toggle source

Uses request data to determin error classes Only raises values. Will never return

# File lib/datarobot/ai_api.rb, line 146
def self.determine_error(response_obj)
  parsed = JSON.parse(response_obj.body)
  msg = parsed["error"] || parsed["message"]
  case response_obj.code
  when "403"
    raise Datarobot::AiApi::UnauthorizedError, msg
  when "404"
    raise Datarobot::AiApi::NotFoundError, msg
  else
    raise Datarobot::AiApi::ApiError, msg
  end
end
determine_object(url) click to toggle source

Given an arbitrary url, return the correct AiApi object @param [String] url @return [Datarobot::AiApi::*]

# File lib/datarobot/ai_api.rb, line 162
def self.determine_object(url)
  case url
  when /\/ais/
    Datarobot::AiApi::AI
  when /\/datasets/
    Datarobot::AiApi::Dataset
  when /\/learningSessions/
    Datarobot::AiApi::LearningSession
  when /\/outputs/
    Datarobot::AiApi::Output
  when /\/status/
    Datarobot::AiApi::Task
  when /\/deployment/
    Datarobot::AiApi::Deployment
  end
end
find(id) { |data| ... } click to toggle source

Retrieves an AI given an ID.

@param [String] id The ID of the AI to retrieve

@return [Datarobot::AiApi::AI]

# File lib/datarobot/ai_api/ai.rb, line 28
def self.find(id, &block)
  raise Datarobot::AiApi::NotFoundError, "Cannot find AI with id: nil" if id.nil?
  Datarobot::AiApi.request_endpoint("/aiapi/ais/#{id}") do |data|
    if block_given?
      yield data
    else
      self.new(data)
    end
  end
end
get(bare_uri, &block) click to toggle source

Gets a bare uri. Useful for requests with `result` objects @param [String] bare_uri @param [Block] block passed to `handle_response`

# File lib/datarobot/ai_api.rb, line 72
def self.get(bare_uri, &block)
  with_https(bare_uri) do |uri, http|
    request = Net::HTTP::Get.new(uri)
    request = add_headers(request)

    response = http.request(request)
    handle_response(response, &block)
  end
end
handle_response(response) { |data| ... } click to toggle source

Common error handling and response parsing @yield [data] Yields the parsed json response if there is one @return nil if body is empty @return [Hash] data Parsed json response if no block is provided

# File lib/datarobot/ai_api.rb, line 101
def self.handle_response(response, &block)
  if response.code.to_i < 300
    return nil if response.body.to_s.empty?
    data = JSON.parse(response.body)
    if block_given?
      yield data
    else
      data
    end
  else
    determine_error(response)
  end
end
new(options = {}) click to toggle source

Given a parsed response body from the API, will create a new AI object

# File lib/datarobot/ai_api/ai.rb, line 62
def initialize(options = {})
  # Suppresses warnings about uninitialized variables
  @id = nil
  @name = nil
  @dataset_count = nil
  @output_count = nil
  @learning_session_count = nil

  set_from_options(options)
  @outputs = nil
end
ping() click to toggle source

Checks the `ping` endpoint. Useful for debugging @return [Hash]

# File lib/datarobot/ai_api.rb, line 29
def self.ping
  request_endpoint('/aiapi/ping')
end
ping_me() click to toggle source

Checks the `ping/me` endpoint. Useful for debugging authentication @return [Hash]

# File lib/datarobot/ai_api.rb, line 35
def self.ping_me
  request_endpoint('/aiapi/ping/me')
end
request_endpoint(endpoint, method: 'get', body: {}, headers: {}, params: {}, &block) click to toggle source

Makes a request to the given endpoint @param [String] endpoint The url path to the endpoint @param [String] method The HTTP method to make the request with @param [Hash] body JSON body. Only used in put and post requests @param [Hash] headers Additional headers to add to request @param [Hash] params Additoinal url parameters to add @return Delegates return values to `handle_response`

# File lib/datarobot/ai_api.rb, line 122
def self.request_endpoint(endpoint, method: 'get', body: {}, headers: {}, params: {}, &block)
  uri_str = "#{@@base_url}#{endpoint}"
  with_https(uri_str, params) do |uri, http|
    case method.downcase
    when 'put'
      request = Net::HTTP::Put.new(uri.request_uri)
      request.body = JSON.dump(body)
    when 'delete'
      request = Net::HTTP::Delete.new(uri.request_uri)
    when 'post'
      request = Net::HTTP::Post.new(uri.request_uri)
      request.body = JSON.dump(body)
    else
      request = Net::HTTP::Get.new(uri)
    end
    request = add_headers(request, headers)

    response = http.request(request)
    handle_response(response, &block)
  end
end
upload_to_endpoint(endpoint, file_path, &block) click to toggle source

Converts a file into an octet stream, and uploads it to given endpoint @param [String] endpoint The endpoint to upload the file to @param [String] file_path Path to local file for upload @return Delegates return values to `handle_response`

# File lib/datarobot/ai_api.rb, line 86
def self.upload_to_endpoint(endpoint, file_path, &block)
  uri = "#{@@base_url}#{endpoint}"
  with_https(uri) do |uri, http|
    request = Net::HTTP::Post::Multipart.new uri.request_uri, "file" => UploadIO.new(file_path, "application/octet-stream")
    request["User-Agent"] = "datarobot-ai/ruby"
    request["Authorization"] = "Bearer #{@@api_key}"
    response = http.request(request)
    handle_response(response, &block)
  end
end
with_https(uri, params={}) { |uri, http| ... } click to toggle source

Make a request with https. This is a helper method to avoid having to write net/http boilerplate @param [String] uri The uri to make the request to @param [Hash] params Additoinal params to add to the request. Will overwrite params in the query string of the given uri

@yield [uri, http] Yields the https request with the parsed uri and http object

# File lib/datarobot/ai_api.rb, line 60
def self.with_https(uri, params={})
  uri = URI.parse(uri)
  existing_params = CGI::parse(uri.query.to_s)
  uri.query = URI.encode_www_form(existing_params.merge params)
  Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
    yield uri, http
  end
end

Public Instance Methods

add_dataset(dataset_id) click to toggle source

Adds a dataset to the AI. Raises an error on failure. Returns true on success

@param [String] dataset_id The ID of the dataset to add @return [Bool] true

# File lib/datarobot/ai_api/ai.rb, line 140
def add_dataset(dataset_id)
  Datarobot::AiApi.request_endpoint("/aiapi/ais/#{@id}/datasets", method: 'post', body: { datasetId: dataset_id })
  true
end
add_learning_session(session_id) click to toggle source

Adds a learning session to the AI. Raises an error on failure. Returns true on success

@param [String] session_id The ID of the learning session to add @return [Bool] true

# File lib/datarobot/ai_api/ai.rb, line 150
def add_learning_session(session_id)
  Datarobot::AiApi.request_endpoint("/aiapi/ais/#{@id}/learningSessions", method: 'post', body: { learningSessionId: session_id })
  true
end
datasets() click to toggle source

Lists all the datasets associated with the AI as a paginated resource

@return [Datarobot::AiApi::Page(Datarobot::AiApi::Dataset)]

# File lib/datarobot/ai_api/ai.rb, line 103
def datasets
  Datarobot::AiApi.request_endpoint("/aiapi/datasets?aiId=#{@id}") do |data|
    data["aiId"] = @id
    Datarobot::AiApi::Page.new(Datarobot::AiApi::Dataset, data)
  end
end
find_output(name) click to toggle source

Finds an output by name

@param [String] name The name of the output associated with this AI that you want to find @return [Datarobot::AiApi::Output]

# File lib/datarobot/ai_api/ai.rb, line 115
def find_output(name)
  # TODO: Update this when AI API supports CGI escaped URIs
  #
  # This code was lifted from source of erb method:
  # https://apidock.com/ruby/v2_6_3/ERB/Util/url_encode
  #
  # URI.escape is deprecated because it does not encode url control
  # characters, thus making it a potential security issue and CGI.escape
  # substitutes whitespace with a + which is correct, but unsupported by
  # the AI API
  encoded_name = name.gsub(/[^a-zA-Z0-9_\-.~]/) { |m|
    sprintf("%%%02X", m.unpack1("C"))
  }

  Datarobot::AiApi.request_endpoint("/aiapi/ais/#{@id}/outputs/#{encoded_name}") do |data|
    data["aiId"] = @id
    Datarobot::AiApi::Output.new(data)
  end
end
outputs() click to toggle source

Lists all the outputs associated with the AI as a paginated resource

@return [Datarobot::AiApi::Page(Datarobot::AiApi::Output)]

# File lib/datarobot/ai_api/ai.rb, line 93
def outputs
  Datarobot::AiApi.request_endpoint("/aiapi/ais/#{@id}/outputs") do |data|
    data["aiId"] = @id
    Datarobot::AiApi::Page.new(Datarobot::AiApi::Output, data)
  end
end
predict(target, data={}) click to toggle source

Predicts a target feature given a data hash

@param target The target feature to predict @param data The remaining features used to predict target feature

# File lib/datarobot/ai_api/ai.rb, line 173
def predict(target, data={})
  output = outputs.find { |o| o.target == target }

  raise NotFoundError, "No output with target #{target.inspect} found AI with ID #{@id.inspect}" if output.nil?

  deployment_id = output.source["deploymentId"]
  key = output.source["datarobot-key"]
  Datarobot::AiApi.request_endpoint(
    "/predApi/v1.0/deployments/#{deployment_id}/predictions/",
    method: 'post',
    body: [ data ],
    headers: {"datarobot-key" => key}
  ) do |data|
    Datarobot::AiApi::Page.new(Datarobot::AiApi::Prediction, data)
  end
end
set_from_options(options = {}) click to toggle source

Takes a response body from the API. Will set all AI attributes from the response body

@param [Hash] options A parsed response body @return [void]

# File lib/datarobot/ai_api/ai.rb, line 79
def set_from_options(options = {})
  # one-liner replacement for `stringify_keys`
  options = options.collect{|k,v| [k.to_s, v]}.to_h

  @output_count = options.dig("outputCount") || @output_count
  @dataset_count = options.dig("datasetCount") || @dataset_count
  @learning_session_count = options.dig("learningSessionCount") || @learning_session_count
  @name = options.dig("name") || @name
  @id = options.dig("id") || @id
end
train(target, file_path) click to toggle source

Trains an AI on the given target with the data in the file at the given path. Returns true if successful. Raises an error otherwise

@param [String] target The target to train the AI on @return [Bool] true

# File lib/datarobot/ai_api/ai.rb, line 160
def train(target, file_path)
  dataset = Datarobot::AiApi::Dataset.create_from_file(file_path)
  add_dataset(dataset.id)
  learning_session = Datarobot::AiApi::LearningSession.create(dataset_id: dataset.id, target: target)
  add_learning_session(learning_session.id)
  Datarobot::AiApi::Output.create(ai_id: @id, learning_session_id: learning_session.id, output_name: "#{@name} output")
  true
end