Giter Site home page Giter Site logo

algorithmia-ruby's Introduction

The Algorithmia Ruby Client

The Algorithmia Ruby client is a wrapper for making calls to the Algorithmia API and Data API.

With Algorithmia, you can leverage algorithms written in any language by including them in your Ruby project with a simple API call! Browse the collection of algorithms available on Algorithmia.com.

Getting started

The Algorithmia ruby client is available on rubygems. Simply add gem 'algorithmia' to your application's Gemfile and run bundle install.

Then create an Algorithmia client and authenticate with your API key:

require 'algorithmia'

client = Algorithmia.client('YOUR_API_KEY')

You are now ready to call algorithms.

Calling algorithms

The following examples of calling algorithms are organized by type of input/output which vary between algorithms.

Note: a single algorithm may have different input and output types, or accept multiple types of input, so consult the algorithm's description for usage examples specific to that algorithm.

Text input/output

Call an algorithm with text input by simply passing a string into its pipe method. If the algorithm output is text, then the result field of the response will be a string.

algo = client.algo('demo/Hello/0.1.1')
puts algo.pipe('HAL 9000').result
# -> Hello HAL 900

JSON input/output

Call an algorithm with JSON input by simply passing in a type that can be serialized to JSON, like an Array or Hash. For algorithms that return JSON, the result field of the response will be the appropriate deserialized type.

algo = client.algo('WebPredict/ListAnagrams/0.1.0')
result = algo.pipe(["transformer", "terraforms", "retransform"]).result
# -> ["transformer","retransform"]

Alternatively, if your input is already serialized to JSON, you may call pipe_json:

algo = client.algo('WebPredict/ListAnagrams/0.1.0')
result = algo.pipe_json('["transformer", "terraforms", "retransform"]').result
# -> ["transformer","retransform"]

Binary input/output

Call an algorithm with Binary input by passing an ASCII-8BIT-encoded string into the pipe method. Similarly, if the algorithm response is binary data, then the result field of the response will be an ASCII-8BIT string. In practice, this involves working with methods like IO.binread and IO.binwrite.

input = File.binread("/path/to/bender.png")
result = client.algo("opencv/SmartThumbnail/0.1").pipe(input).result
# -> [ASCII-8BIT string of binary data]

Error handling

API errors and Algorithm exceptions will be raised when calling pipe:

client.algo('util/whoopsWrongAlgo').pipe('Hello, world!')
# -> Algorithmia::Errors::NotFoundError: algorithm algo://util/whoopsWrongAlgo not found

And you can rescue Algorithm errors separate from other errors:

begin
  client.algo('demo/Hello').pipe('world!')
rescue Algorithmia::Errors::AlgorithmError => e
  puts "Algorithm Error: #{e.message}"
  puts e.stacktrace
rescue => e
  puts "Error: #{e.message}"
end

Request options

The client exposes options that can configure algorithm requests. This includes support for changing the timeout or indicating that the API should include stdout in the response.

algo = client.algo('demo/Hello/0.1.1').set(timeout: 10, stdout: true)
response = algo.pipe('HAL 9000')
stdout = response.stdout

Note: stdout: true is ignored if you do not have access to the algorithm source.

Working with data

The Algorithmia Java client also provides a way to manage both Algorithmia hosted data and data from Dropbox or S3 accounts that you've connected to you Algorithmia account.

This client provides a DataFile type (generally created by client.file(uri)) and a DataDir type (generally created by client.dir(uri)) that provide methods for managing your data.

Create directories

Create directories by instantiating a DataDirectory object and calling create:

client.dir("data://.my/robots").create
client.dir("dropbox://robots").create

Upload files to a directory

Upload files by calling put on a DataFile object, or by calling putFile on a DataDirectory object.

robots = client.dir("data://.my/robots")

# Upload local file
robots.put_file("/path/to/Optimus_Prime.png")
# Write a text file
robots.file("Optimus_Prime.txt").put("Leader of the Autobots")
# Write a binary file
robots.file("Optimus_Prime.key").put([71, 101, 101, 107].pack('C*'))

Download contents of file

Download files by calling get or get_file on a DataFile object:

# Download file and get the file handle
t800File = client.file("data://.my/robots/T-800.png").get_file

# Get file's contents as a string
t800Text = client.file("data://.my/robots/T-800.txt").get

# Get file's contents as JSON
t800JsonString = client.file("data://.my/robots/T-800.txt").get
t800Json =  JSON.parse(t800JsonString)

# Get file's contents as a byte array
t800Bytes = client.file("data://.my/robots/T-800.png").get

Delete files and directories

Delete files and directories by calling delete on their respective DataFile or DataDirectory object. DataDirectories take an optional force parameter that indicates whether the directory should be deleted if it contains files or other directories.

client.file("data://.my/robots/C-3PO.txt").delete

client.dir("data://.my/robots").delete(false)

List directory contents

Iterate over the contents of a directory using the iterated returned by calling each, each_directory, or each_file on a DataDirectory object. If no block is given to the method, an enumerator will be returned.

# List top level directories
client.dir("data://.my").each_dir do |dir|
    puts "Directory " + dir.data_uri
end

# List files in the 'robots' directory
client.dir("data://.my/robots").each_file do |file|
    puts "File " + file.data_uri
end

# Iterate all directory contents
client.dir("dropbox://").each do |item|
    puts file.data_uri
end

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

algorithmia-ruby's People

Contributors

alexpjohnson avatar anowell avatar jakemuntarsi avatar jamesatha avatar kennydaniel avatar peckjon avatar phoffer avatar pmcq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

algorithmia-ruby's Issues

Need to be able to change base_uri

2 related points:

  1. base URI shouldn't include /v1 but rather default to https://api.algorithmia.com. This is consistent with other clients and is especially helpful in the 2nd point:
  2. We need to expose base_uri, so that it can be modified for pointing the client at test, local, enterprise, or other environments using the same client.

algorithm errors should raise exceptions

I didn't spend enough time characterizing this, but wanted to file it for tracking/followup. It seems like most non-200 responses raise exceptions just fine, but an algorithm that returns an error doesn't seem to raise an exception, and at least at first glance I failed to figure out how to extract the error message (short of just printing the entire response object)

File saving in ruby 2.7 is showing "warning: URI.escape is obsolete"

The actual problem seems to be URI.encode, which is an alias for URI.escape. I think this could be changed to just CGI.encode the file name in lines 51 and 70 of lib/algorithmia/data_directory. I'll research further and open a PR as soon as possible, but could use some feedback on this if possible.

`basename` returns a string instead of `Pathname`

This caught me by surprise because I tried comparing a DataFile.basename with a local Pathname.basename and they weren't equal when I expected them to be because DataObject.basename returns a String but the std library's Pathname.basename returns a Pathname

json gem version

Hi. Are having some problems with the JSON gem and algorithmia, version 2.01 (and all others). In Ruby json-gem 2.04 is default, but the requirement here is json 1.8.6. There seems to be a conflict of some sort however:

usr/local/rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby/2.4.0/rubygems/specification.rb:2302:in `raise_if_conflicts': Unable to activate algorithmia-1.0.1, because json-2.0.2 conflicts with json (~> 1.8) (Gem::ConflictError)

Is it necessary to require 1.8, or could it be jumped to at least 2.0.2 so this doesn't happen? Don't know how to solve the problem otherwise, it occurs on an Ubuntu machine 14.04 LTS. I know it's a rather old distro, but its the one C9.io runs on and that's what I'm working on.

Error messages in API response are not surfaced by Requester

Problem Description

When an algorithm developer attempts to invoke another algorithm with an improperly configured client:

client = Algorithmia.client('<api key>')
client.algo('example/algo').pipe(input)

The API returns an appropriately descriptive error message in its response:

{
    "error": {
        "message": "invalid authorization: api keys are not allowed within algorithms"
    }
}

That tells the algorithm developer that API keys are not to be used within algorithms.

However, the algorithmia-ruby library does not surface this message. Instead, it raises an exception with a rather misleading message:

Error: The request you are making requires authorization. Please check that you have permissions & that you've set your API key.
/opt/algorithm/vendor/bundle/ruby/2.2.0/gems/algorithmia-1.0.1/lib/algorithmia/requester.rb:92:in `check_for_errors'
# ...

Cause

Requester#check_for_errors intends to surface the API response error message, as can be seen on line 87:

message = response.dig("error", "message") if response.is_a?(Hash)

However, the response object returned is a HTTParty::Response object. This HTTParty::Response object is returned by the delegated get, post, put, head, and delete within Requester

Note that while the HTTParty::Response responds to Hash-like methods due to internal method_missing delegation, is_a? Hash will evaluate to false.

Additional Concern

Even if we were to remove a Hash type check, we must be careful. Hash#dig was added in Ruby 2.3; and the Algorithmia developer platform runs on Ruby 2.2. Therefore Hash#dig is not available to algorithm developers and will raise an error if invoked within an algorithm.

Solution

There are a few possible solutions. First, we should remove the Hash type check. Additionally, we should either find a way other than Hash#dig to retrieve the error message, or we should specify a required ruby version in the gem specification for this library.

Also, it may make sense to add a regression test to exercise this code path such that it doesn't resurface in the future.

pipe_json should explicitly set Content-Type

pipe_json should explicitly set Content-Type to application/json, however in skimming a little deeper, Http.post will try to do .to_json on it if that header is present, and that would escape the string incorrectly. So, I don't think it's quite as simple as just setting Content-Type to fix. Off the top of my head, this may need some sort of change to Http or perhaps just parsing the json_string before calling post (a bit redundant to deserialize and reserialize, but at least it would verify the string was valid JSON)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.