module Indico

Constants

CLIENT_TO_SERVER
SERVER_TO_CLIENT
VERSION

Attributes

cloud_protocol[RW]
config[RW]

Public Class Methods

analyze_image(face, apis = IMAGE_APIS, config = nil) click to toggle source
# File lib/indico.rb, line 165
def self.analyze_image(face, apis = IMAGE_APIS, config = nil)
  api_hash = {'apis' => apis}
  multi(preprocess(face, 48, false), "image", apis, IMAGE_APIS, config ? config.update(api_hash) : api_hash)
end
analyze_text(text, apis = TEXT_APIS, config = nil) click to toggle source
# File lib/indico.rb, line 170
def self.analyze_text(text, apis = TEXT_APIS, config = nil)
  api_hash = {'apis' => apis}
  multi(text, "text", apis, TEXT_APIS, config ? config.update(api_hash) : api_hash)
end
api_key() click to toggle source
# File lib/indico.rb, line 13
def self.api_key
  config['auth']
end
api_key=(api) click to toggle source
# File lib/indico.rb, line 17
def self.api_key=(api)
  config['auth'] = api
end
array_contains_float(array, dimens) click to toggle source
# File lib/indico/image.rb, line 80
def self.array_contains_float(array, dimens)
    # Determines whether or not the array contains floats
    if not array.is_a?(Array)
        return array.class == Float
    end
    elem = array[0]
    (0..dimens.size - 2).each do |i|
        elem = elem[0]
    end

    return elem.class == Float
end
collections(config = nil) click to toggle source
# File lib/indico.rb, line 175
def self.collections(config = nil)
  Indico.api_handler(nil, 'custom', config, 'collections')
end
content_filtering(image, config = nil) click to toggle source
# File lib/indico.rb, line 161
def self.content_filtering(image, config = nil)
  api_handler(preprocess(image, 128, true), 'contentfiltering', config)
end
emotion(text, config = nil) click to toggle source
# File lib/indico.rb, line 68
def self.emotion(text, config = nil)
  api_handler(text, 'emotion', config)
end
facial_features(image, config = nil) click to toggle source
# File lib/indico.rb, line 141
def self.facial_features(image, config = nil)
  api_handler(preprocess(image, 48, false), 'facialfeatures', config)
end
facial_localization(image, config = nil) click to toggle source
# File lib/indico.rb, line 145
def self.facial_localization(image, config = nil)
  api_handler(preprocess(image, false, false), 'faciallocalization', config)
end
fer(image, config = nil) click to toggle source
# File lib/indico.rb, line 136
def self.fer(image, config = nil)
  size = (config != nil and config["detect"] == true) ? false : 48
  api_handler(preprocess(image, size, false), 'fer', config)
end
get_dimension(array) click to toggle source
# File lib/indico/image.rb, line 75
def self.get_dimension(array)
    return [] unless array.is_a?(Array)
    return [array.size] + get_dimension(array[0])
end
get_rgb(value) click to toggle source
# File lib/indico/image.rb, line 93
def self.get_rgb(value)
    # Returns Integer encoding of RGB value used by ChunkyPNG
    return [
        ChunkyPNG::Color.r(value),
        ChunkyPNG::Color.g(value),
        ChunkyPNG::Color.b(value)
    ]
end
handle_image_input(str, size, min_axis) click to toggle source
# File lib/indico/image.rb, line 39
def self.handle_image_input(str, size, min_axis)
    # Handles string input
    if File.file?(str)
        # Handling File Inputs
        begin
            image = ChunkyPNG::Image.from_file(str)
            if min_axis
                image = self.min_resize(image, size)
            else
                image = image.resize(size, size)
            end
            image = image.to_data_url.gsub("data:image/png;base64," ,"")
        rescue
            File.open(str, 'r') do |file|
                image = Base64.encode64(file.read)
            end
        end
    elsif str =~ /\A#{URI::regexp}\z/
        image = str
    else
        begin
            image = ChunkyPNG::Image.from_data_url("data:image/png;base64," + str.gsub("data:image/png;base64," ,""))
            if min_axis
                image = self.min_resize(image, size)
            else
                image = image.resize(size, size)
            end
            image = image.to_data_url.gsub("data:image/png;base64," ,"")
        rescue
            image = str
        end
    end

    return image
end
handle_multi(results) click to toggle source
# File lib/indico/multi.rb, line 71
def self.handle_multi(results)
  converted_results = Hash.new
  results.each do |key, value|
    if value.is_a?(Hash) && value.has_key?("results")
      converted_results[key] = value["results"]
    else
      raise IndicoError, 'unexpected result from ' + key + '. ' + value.fetch("error", "")
    end
  end
  converted_results
end
image_features(image, config = {}) click to toggle source
# File lib/indico.rb, line 149
def self.image_features(image, config = {})
  unless config.key?('v') or config.key?('version')
    config['version'] = "3"
  end
  api_handler(preprocess(image, 512, true), 'imagefeatures', config)
end
image_recognition(image, config = nil) click to toggle source
# File lib/indico.rb, line 156
def self.image_recognition(image, config = nil)
  api_handler(preprocess(image, 144, true), 'imagerecognition', config)
end
intersections(data, apis = nil, config = nil) click to toggle source
# File lib/indico/multi.rb, line 44
def self.intersections(data, apis = nil, config = nil)

  if apis == nil
    fail "Argument 'apis' must be provided"
  end

  api_types = apis.map { |api| API_TYPES[api] }

  if !apis.is_a? Array or apis.length != 2
    fail "Argument 'apis' must be of length 2"
  elsif data.is_a? Array and data.length < 3
    fail "At least 3 examples are required to use the intersections api"
  elsif api_types[0] != api_types[1]
    fail "Both 'apis' must accept the same kind of input to use the intersections api."
  end

  if config.nil?
    config = {}
  end

  self.validate_apis(apis)
  config['apis'] = apis
  response = api_handler(data, "apis/intersections", config)
  return response

end
keywords(text, config = nil) click to toggle source
# File lib/indico.rb, line 76
def self.keywords(text, config = nil)
  if !config
    config = {}
  end
  if !config.key?(:v) and !config.key?(:version)
    config['version'] = "2"
  end
  if config.key?(:language) and config[:language] != "english"
    config['version'] = "1"
  end
  api_handler(text, 'keywords', config)

end
language(text, config = nil) click to toggle source
# File lib/indico.rb, line 64
def self.language(text, config = nil)
  api_handler(text, 'language', config)
end
min_resize(decoded_image, size) click to toggle source
# File lib/indico/image.rb, line 25
def self.min_resize(decoded_image, size)
    img_size = [decoded_image.width, decoded_image.height]
    min_idx, max_idx = img_size[0] < img_size[1] ? [0, 1] : [1, 0]
    aspect = img_size[max_idx] / Float(img_size[min_idx])
    if aspect > 10
        warn("An aspect ratio greater than 10:1 is not recommended")
    end
    size_arr = [0, 0]
    size_arr[min_idx] = size
    size_arr[max_idx] = Integer(size * aspect)
    image = decoded_image.resize(size_arr[0], size_arr[1])
    return image
end
multi(data, type, apis, allowed, batch = false, config) click to toggle source
# File lib/indico/multi.rb, line 32
def self.multi(data, type, apis, allowed, batch = false, config)

  if config.nil?
    config = {}
  end

  self.validate_apis(apis, type, allowed)
  config['apis'] = apis
  response = api_handler(data, batch ? "apis/batch" : "apis", config)
  return handle_multi(response)
end
organizations(text, config = {}) click to toggle source
# File lib/indico.rb, line 114
def self.organizations(text, config = {})
  if not (config.key?('v') or config.key?('version'))
    config['version'] = "2"
  end
  api_handler(text, "organizations", config)
end
pdf_extraction(pdf, config = {}) click to toggle source
# File lib/indico.rb, line 132
def self.pdf_extraction(pdf, config = {})
  api_handler(preprocess_pdf(pdf), "pdfextraction", config)
end
people(text, config = {}) click to toggle source
# File lib/indico.rb, line 107
def self.people(text, config = {})
  if not (config.key?('v') or config.key?('version'))
    config['version'] = "2"
  end
  api_handler(text, "people", config)
end
personality(text, config = nil) click to toggle source
# File lib/indico.rb, line 47
def self.personality(text, config = nil)
  api_handler(text, 'personality', config)
end
personas(text, config = {}) click to toggle source
# File lib/indico.rb, line 51
def self.personas(text, config = {})
  config['persona'] = true
  api_handler(text, 'personality', config)
end
places(text, config = {}) click to toggle source
# File lib/indico.rb, line 121
def self.places(text, config = {})
  if not (config.key?('v') or config.key?('version'))
    config['version'] = "2"
  end
  api_handler(text, "places", config)
end
political(text, config = nil) click to toggle source
# File lib/indico.rb, line 29
def self.political(text, config = nil)
  if !config
    config = {}
  end
  if !config.key?(:v) and !config.key?(:version)
    config['version'] = "2"
  end
  api_handler(text, 'political', config)
end
posneg(*args) click to toggle source
# File lib/indico.rb, line 39
def self.posneg(*args)
  sentiment(*args)
end
preprocess(image, size, min_axis) click to toggle source
# File lib/indico/image.rb, line 6
def self.preprocess(image, size, min_axis)
    if image.class == Array
        # Batch Request
        im_array = Array.new

        # process each image
        image.each do |_image|
            im_array.push(preprocess(_image, size, min_axis))
        end

        return im_array
    elsif image.class != String
        raise Exception.new("Image input must be filename or base64 string")
    end

    # Resize and export base64 encoded string
    return handle_image_input(image, size, min_axis)
end
preprocess_pdf(pdf) click to toggle source
# File lib/indico/pdf.rb, line 4
def self.preprocess_pdf(pdf)
    if pdf.class == Array
        # Batch Request
        pdf_array = Array.new

        # process each image
        pdf.each do |_pdf|
            pdf_array.push(preprocess_pdf(_pdf))
        end

        return pdf_array
    elsif pdf.class != String
        raise Exception.new("PDF input must be filename, url or base64 string")
    end

    begin
        return Base64.encode64(File.read(pdf))
    rescue
        # likely a url or a base64 encoded string already
        return pdf
    end
end
private_cloud() click to toggle source
# File lib/indico.rb, line 21
def self.private_cloud
  config['cloud']
end
private_cloud=(cloud) click to toggle source
# File lib/indico.rb, line 25
def self.private_cloud=(cloud)
  config['cloud'] = cloud
end
relevance(text, queries, config = nil) click to toggle source
# File lib/indico.rb, line 90
def self.relevance(text, queries, config = nil)
  if config.nil?
    config = Hash.new()
  end
  config[:queries] = queries
  config[:synonyms] = false
  return api_handler(text, 'relevance', config)
end
sentiment(text, config = nil) click to toggle source
# File lib/indico.rb, line 43
def self.sentiment(text, config = nil)
  api_handler(text, 'sentiment', config)
end
sentiment_hq(text, config = nil) click to toggle source
# File lib/indico.rb, line 60
def self.sentiment_hq(text, config = nil)
  api_handler(text, 'sentimenthq', config)
end
summarization(text, config = {}) click to toggle source
# File lib/indico.rb, line 128
def self.summarization(text, config = {})
  api_handler(text, "summarization", config)
end
text_features(text, config = nil) click to toggle source
# File lib/indico.rb, line 99
def self.text_features(text, config = nil)
  if config.nil?
    config = Hash.new()
  end
  config[:synonyms] = false
  return api_handler(text, 'textfeatures', config)
end
text_tags(text, config = nil) click to toggle source
# File lib/indico.rb, line 72
def self.text_tags(text, config = nil)
  api_handler(text, 'texttags', config)
end
twitter_engagement(text, config = nil) click to toggle source
# File lib/indico.rb, line 56
def self.twitter_engagement(text, config = nil)
  api_handler(text, 'twitterengagement', config)
end
validate_apis(apis, type="api", allowed=CLIENT_TO_SERVER.keys) click to toggle source
# File lib/indico/multi.rb, line 24
def self.validate_apis(apis, type="api", allowed=CLIENT_TO_SERVER.keys)
  apis.each { |api|
    if not allowed.include? api
      fail  api + " is not a valid api for " + type + " requests. Please use: " + allowed.join(", ")
    end
  }
end

Private Class Methods

add_api_key_to_header(api_key) click to toggle source
# File lib/indico/helper.rb, line 97
def self.add_api_key_to_header(api_key)
  headers = HEADERS
  headers['X-ApiKey'] = api_key
  headers
end
api_handler(data, api, config, method='predict') click to toggle source
# File lib/indico/helper.rb, line 14
def self.api_handler(data, api, config, method='predict')
  server = nil
  api_key = nil
  version = nil

  d = {}
  if data != nil
    d['data'] = data
  end

  if !(api == "custom" && method == "add_data")
    if api != "apis/intersections" and data.class == Array
      api += "/batch"
    end
  else
    if data.class == Array and data[0].class == Array
      api += "/batch"
    end
  end

  api += (method != "predict" ? ("/" + method) : "")

  if config
    server = config.delete('cloud')
    api_key = config.delete('api_key')
    apis = config.delete('apis')
    version = config.delete('version')
    d = d.merge(config)
  end

  api_key = (api_key or Indico.config['auth'])
  server = (server or Indico.config['cloud'])

  if api_key.nil?
    raise ArgumentError, 'api key is required'
  end

  url_params = Array.new
  if apis
    url_params.push(['apis', apis.join(",")])
  end
  if version
    url_params.push(['version', version])
  end
  url_params = URI.encode_www_form(url_params)
  url = url_join(server, api) + "?" + url_params

  response = make_request(url, JSON.dump(d),
                          add_api_key_to_header(api_key))

  response.each_header do |key, value|
    if key.downcase == 'x-warning'
      warn value
    end
  end

  results = JSON.parse(response.body)
  if results.key?('error')
    fail IndicoError, results['error']
  else
    results['results']
  end
end
find_config_files() click to toggle source
# File lib/indico/settings.rb, line 89
def self.find_config_files()
  # Provides a list of paths to search for indicorc files
  localPath = File.join(Dir.pwd, ".indicorc")
  globalPath = File.join(Dir.home, ".indicorc")
  return [globalPath, localPath]
end
load_config() click to toggle source
# File lib/indico/settings.rb, line 122
def self.load_config()
  # Finds, loads, and simplifies all configuration types
  paths = self.find_config_files()
  config_file = self.load_config_files(paths)
  env_vars = self.load_environment_vars()
  config = self.merge_config(config_file, env_vars)
  return self.simplify_config(config)
end
load_config_files(filenames) click to toggle source
# File lib/indico/settings.rb, line 75
def self.load_config_files(filenames)
  # Given a list of filenames, build up an ini file config
  master_ini = self.new_config()

  for filename in filenames
    ini = IniFile.load(filename)
    if not ini then
      next
    end
    master_ini = self.merge_config(master_ini, ini)
  end
  return master_ini
end
load_environment_vars() click to toggle source
# File lib/indico/settings.rb, line 96
def self.load_environment_vars()
  # Load environment variables into same format as INI file reader
  return {'auth' => {'api_key' => ENV["INDICO_API_KEY"]},
            'private_cloud' => {'cloud' => ENV["INDICO_CLOUD"]}}
end
make_request(url, data_dict, headers) click to toggle source
# File lib/indico/helper.rb, line 78
def self.make_request(url, data_dict, headers)
  uri = URI(url)

  http = Net::HTTP.new(uri.host, uri.port)

  if url.index('https') == 0
    http.use_ssl = true
  end

  request = Net::HTTP::Post.new(uri.request_uri)
  request.body = data_dict

  headers.each do |key, val|
    request[key] = val
  end

  http.request(request)
end
merge_config(prev_config, new_config) click to toggle source
# File lib/indico/settings.rb, line 62
def self.merge_config(prev_config, new_config)
  # Merge two configurations, giving precedence to the second
  if self.valid_auth(new_config)
    prev_config['auth'] = new_config['auth']
  end

  if self.valid_cloud(new_config)
    prev_config['private_cloud'] = new_config['private_cloud']
  end

  return prev_config
end
new_config() click to toggle source
# File lib/indico/settings.rb, line 102
def self.new_config()
  # Makes a new, empty config object
  new_config = Hash.new
  new_config['auth'] = false
  new_config['cloud'] = false
  return new_config
end
simplify_config(config) click to toggle source
# File lib/indico/settings.rb, line 110
def self.simplify_config(config)
  # Goes from nested representation to flatter version
  new_config = self.new_config()
  if self.valid_auth(config)
    new_config['auth'] = config['auth']['api_key']
  end
  if self.valid_cloud(config)
    new_config['cloud'] = config['private_cloud']['cloud']
  end
  return new_config
end
url_join(root, api) click to toggle source
# File lib/indico/helper.rb, line 6
def self.url_join(root, api)
  if !root
    'https://apiv2.indico.io/' + api
  else
    Indico.cloud_protocol + root + '.indico.domains/' + api
  end
end
valid_auth(config) click to toggle source
# File lib/indico/settings.rb, line 50
def self.valid_auth(config)
  # Does a config hashmap have a valid auth definition?
  return config['auth'] &&
         config['auth']['api_key']
end
valid_cloud(config) click to toggle source
# File lib/indico/settings.rb, line 56
def self.valid_cloud(config)
  # Does a config hashmap have a valid private cloud definition?
  return config['private_cloud'] &&
         config['private_cloud']['cloud']
end