voicebase-client-ruby 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3dff5518b93777f4361ef5ae09534b24f26b81fd
4
+ data.tar.gz: a7b02a83c9ec5b4bca5da34213544f7049e45395
5
+ SHA512:
6
+ metadata.gz: 722c6172937548128010286413d6a684a1ab6507812a6213091246fe2af74d45fb5fe8eaf9468d4865e1e3510365eea5049931b90a91de21f1635dc4faf58c6f
7
+ data.tar.gz: 4472a71f64fd1bdd655c2396161da6b0afbfa0046cc6a03ad105a4ee99cbfe15ffd62fe67324d6f8b9ac88b0eab6cb3e6033c69de4c075d505221f0b11d72ed0
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
11
+ /.idea/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ voicebase-client-ruby
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.4
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.4
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in voicebase-client-ruby.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2016 User Testing, Inc.
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5
+ and associated documentation files (the "Software"), to deal in the Software without restriction,
6
+ including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or substantial
11
+ portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
14
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
16
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
17
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # Voicebase Client Ruby
2
+
3
+ This is a Ruby client to the VoiceBase API Version [1.x](http://www.voicebase.com/developers/), see [API documentation](https://s3.amazonaws.com/vb-developers/VB-api-devguide-v1.1.5.pdf), and [2.x](https://apis.voicebase.com). Some portions of this gem were derived from [voicebase-client-ruby](https://github.com/popuparchive/voicebase-client-ruby).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'voicebase-client-ruby', github: "usertesting/voicebase-client-ruby"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ ## Usage
18
+
19
+ ### VoiceBase API V1.x:
20
+
21
+ An example to authenticate with v1 and upload a video file.
22
+
23
+ ```ruby
24
+ require 'voicebase'
25
+
26
+ client = VoiceBase::Client.new({
27
+ api_version: "1.1",
28
+ auth_key: "my-voicebase-key",
29
+ auth_secret: "my-voicebase-secret",
30
+ })
31
+
32
+ client.upload_media({
33
+ media_url: "http://my.media-example.com/media1.mp4",
34
+ title: "My fancy media",
35
+ transcription_type: 'machine',
36
+ external_id: 'abcd1234',
37
+ machine_ready_callback: "http://my.example.com/success",
38
+ error_callback: "http://my.example.com/error"
39
+ })
40
+
41
+ response = get_transcript(external_id: 'abcd1234' format: "json")
42
+ if response.success?
43
+ transcript_json = JSON.parse(response.transcript)
44
+ end
45
+
46
+ ```
47
+
48
+ For VoiceBase API V2.x:
49
+
50
+ ```ruby
51
+ require 'voicebase'
52
+
53
+ client = VoiceBase::Client.new({
54
+ api_version: "2.0.beta",
55
+ auth_key: "my-voicebase-key",
56
+ auth_secret: "my-voicebase-secret",
57
+ })
58
+
59
+ client.upload_media({
60
+ media_url: "http://my.media-example.com/media1.mp4",
61
+ configuration: {
62
+ transcripts: {
63
+ engine: "premium"
64
+ },
65
+ publish: {
66
+ callbacks: [{
67
+ url: "https://example.org/callback",
68
+ method: "POST",
69
+ include: ["transcripts", "keywords", "topics", "metadata"]
70
+ }]
71
+ }
72
+ }
73
+ })
74
+
75
+ client.get_transcript({
76
+ media_id: "3b5c78e2-868c-4ce7-a0db-087a02db4042"
77
+ }, {'Accept' => 'text/srt'})
78
+
79
+ ...
80
+ ```
81
+
82
+ ## Development
83
+
84
+ 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.
85
+
86
+ 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](https://rubygems.org).
87
+
88
+ ## Contributing
89
+
90
+ Bug reports and pull requests are welcome on GitHub at https://github.com/usertesting/voicebase-client-ruby.
91
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "voicebase/client/ruby"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/voicebase.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'json'
2
+ require 'uri'
3
+ require 'httparty'
4
+ require 'active_support/core_ext/module'
5
+
6
+ require "voicebase/version"
7
+ require "voicebase/helpers"
8
+
9
+ require "voicebase/v1"
10
+ require "voicebase/v2"
11
+
12
+ require "voicebase/client"
13
+ require "voicebase/client/token"
14
+ require "voicebase/response"
15
+
16
+ require "voicebase/json"
17
+ require "voicebase/json/word"
18
+
19
+ module VoiceBase
20
+ class AuthenticationError < StandardError; end
21
+ class ArgumentError < StandardError; end
22
+ end
@@ -0,0 +1,41 @@
1
+ module VoiceBase
2
+ class Client
3
+ include HTTParty
4
+
5
+ attr_accessor :args
6
+ attr_accessor :api_host
7
+ attr_accessor :api_endpoint
8
+ attr_accessor :api_version
9
+ attr_accessor :debug
10
+ attr_accessor :user_agent
11
+ attr_accessor :cookies
12
+ attr_accessor :locale
13
+ attr_accessor :token
14
+
15
+ # E.g. "request_status" -> "requestStatus"
16
+ def self.camelize_name(snake_cased_name)
17
+ snake_cased_name.to_s.camelize(:lower)
18
+ end
19
+
20
+ def initialize(args = {})
21
+ @args = args
22
+ @api_version = args[:api_version] || ENV.fetch('VOICEBASE_API_VERSION', '1.1')
23
+ @auth_key = args[:auth_key] || ENV['VOICEBASE_API_KEY']
24
+ @auth_secret = args[:auth_secret] || ENV['VOICEBASE_API_SECRET']
25
+ @debug = !!args[:debug]
26
+ @user_agent = args[:user_agent] || "usertesting-client/#{VoiceBase::version}"
27
+ @locale = args[:locale] || 'en' # US English
28
+
29
+ if @api_version.to_f < 2.0
30
+ self.extend(VoiceBase::V1::Client)
31
+ else
32
+ self.extend(VoiceBase::V2::Client)
33
+ end
34
+ end
35
+
36
+ def uri
37
+ @api_host + @api_endpoint
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,16 @@
1
+ module VoiceBase
2
+ class Client::Token
3
+ attr_accessor :token, :created_at, :timeout
4
+
5
+ def initialize(token, timeout = Float::INFINITY)
6
+ raise VoiceBase::AuthenticationError, "Authentication token cannot be empty" unless token
7
+ @token = token
8
+ @created_at = Time.now
9
+ @timeout = timeout
10
+ end
11
+
12
+ def expired?
13
+ Time.now > created_at + (timeout / 1000.to_f)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ module VoiceBase
2
+ module Helpers
3
+ def self.included(base)
4
+ base.send :extend, ClassMethods
5
+ base.send :include, InstanceMethods
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ # E.g. "request_status" -> "requestStatus"
11
+ def camelize_name(snake_cased_name)
12
+ snake_cased_name.to_s.camelize(:lower)
13
+ end
14
+
15
+ end
16
+
17
+ module InstanceMethods
18
+
19
+ def camelize_name(snake_cased_name)
20
+ self.class.camelize_name(snake_cased_name)
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,89 @@
1
+ module VoiceBase
2
+ class JSON
3
+ include Enumerable
4
+
5
+ class ParseError < StandardError; end
6
+
7
+ class << self
8
+
9
+ def parse(input, options = {})
10
+ @debug = options.fetch(:debug, false)
11
+ if input.is_a?(String)
12
+ parse_string(input)
13
+ elsif input.is_a?(::File)
14
+ parse_file(input)
15
+ else
16
+ raise "Invalid input. Expected a String or File, got #{input.class.name}."
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def parse_file(json_file)
23
+ parse_string ::File.open(json_file, 'rb') { |f| json_file.read }
24
+ end
25
+
26
+ def parse_string(json_string_data)
27
+ result = new
28
+
29
+ json_hash_data = ::JSON.parse(json_string_data)
30
+ raise ParseError, "Invalid format" unless json_hash_data.is_a?(Array)
31
+ json_hash_data.each_with_index do |word_hash, index|
32
+ word = Word.new(word_hash)
33
+ result.words << word unless word.empty?
34
+
35
+ %w(p c s e w).each do |field|
36
+ if word.send(field).nil?
37
+ word.error = "#{index}, Invalid formatting of #{field}, [#{word_hash[field]}]"
38
+ $stderr.puts word.error if @debug
39
+ end
40
+ end
41
+ end
42
+ result
43
+ end
44
+ end
45
+
46
+ attr_writer :words
47
+
48
+ def initialize(word_array = nil)
49
+ raise StandardError, "Must be initialized with words." if word_array.is_a?(Array) && !words.all? {|w| w.is_a?(VoiceBase::JSON::Word)}
50
+ @words = word_array || []
51
+ end
52
+
53
+ def words
54
+ @words ||= []
55
+ end
56
+
57
+ def errors
58
+ @words.map {|w| w.error if w.error}.compact
59
+ end
60
+
61
+ def each(&block)
62
+ @words.each {|word| block.call(word)}
63
+ end
64
+
65
+ def gt(start_time)
66
+ VoiceBase::JSON.new(select {|w| w.start_time > start_time})
67
+ end
68
+
69
+ def gteq(start_time)
70
+ VoiceBase::JSON.new(select {|w| w.start_time >= start_time})
71
+ end
72
+
73
+ def lt(start_time)
74
+ VoiceBase::JSON.new(select {|w| w.start_time < start_time})
75
+ end
76
+
77
+ def lteq(start_time)
78
+ VoiceBase::JSON.new(select {|w| w.start_time <= start_time})
79
+ end
80
+
81
+ def to_a
82
+ @words
83
+ end
84
+
85
+ def to_json
86
+ map {|w| w.to_hash}.to_json
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,63 @@
1
+ module VoiceBase
2
+ class JSON::Word
3
+ attr_accessor :sequence
4
+ attr_accessor :start_time
5
+ attr_accessor :end_time
6
+ attr_accessor :confidence
7
+ attr_accessor :word
8
+ attr_accessor :error
9
+ attr_accessor :metadata
10
+
11
+ alias_method :p, :sequence
12
+ alias_method :p=, :sequence=
13
+ alias_method :c, :confidence
14
+ alias_method :c=, :confidence=
15
+ alias_method :s, :start_time
16
+ alias_method :s=, :start_time=
17
+ alias_method :e, :end_time
18
+ alias_method :e=, :end_time=
19
+ alias_method :w, :word
20
+ alias_method :w=, :word=
21
+ alias_method :m, :metadata
22
+ alias_method :m=, :metadata=
23
+
24
+ def initialize(options={})
25
+ options.each do |k,v|
26
+ self.send("#{k}=",v)
27
+ end
28
+ end
29
+
30
+ def clone
31
+ clone = VoiceBase::JSON::Word.new
32
+ clone.sequence = sequence
33
+ clone.start_time = start_time
34
+ clone.end_time = end_time
35
+ clone.confidence = confidence
36
+ clone.error = error
37
+ clone.word = word
38
+ clone.metadata = metadata
39
+ clone
40
+ end
41
+
42
+ def ==(word)
43
+ self.sequence == word.sequence &&
44
+ self.start_time == word.start_time &&
45
+ self.end_time == word.end_time &&
46
+ self.confidence == word.confidence &&
47
+ self.word == word.word &&
48
+ self.metadata == word.metadata
49
+ end
50
+
51
+ def empty?
52
+ sequence.nil? && start_time.nil? && end_time.nil? && (word.nil? || word.empty?)
53
+ end
54
+
55
+ def to_hash
56
+ {"p": sequence, "c": confidence, "s": start_time, "e": end_time, "w": word}
57
+ end
58
+
59
+ def to_json
60
+ {"p": sequence, "c": confidence, "s": start_time, "e": end_time, "w": word}.to_json
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,35 @@
1
+ module VoiceBase
2
+ class Response
3
+ include Helpers
4
+ attr_accessor :http_response
5
+
6
+ delegate :code, :body, :headers, :message, to: :http_response, allow_nil: true
7
+
8
+ def initialize(http_response, api_version = "1.1")
9
+ @http_response = http_response
10
+ if api_version.to_f < 2
11
+ self.extend(VoiceBase::V1::Response)
12
+ else
13
+ self.extend(VoiceBase::V2::Response)
14
+ end
15
+ end
16
+
17
+ def ok?
18
+ http_response.code && http_response.code >= 200 && http_response.code < 300
19
+ end
20
+
21
+ # E.g.
22
+ #
23
+ # @response.request_status is derived from the
24
+ # response hash 'statusMessage' key, or
25
+ # @response.status_message from 'statusMessage'
26
+ #
27
+ def method_missing(method, *args, &block)
28
+ if result = http_response.parsed_response[camelize_name(method)]
29
+ result
30
+ else
31
+ super
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,6 @@
1
+ module VoiceBase
2
+ module V1; end
3
+ end
4
+
5
+ require "voicebase/v1/client"
6
+ require "voicebase/v1/response"
@@ -0,0 +1,92 @@
1
+ module VoiceBase
2
+ module V1
3
+ module Client
4
+ include Helpers
5
+
6
+ TOKEN_TIMEOUT_IN_MS = 1440
7
+ PARAM_NORMALIZATION = {"Url" => "URL", "Id" => "ID", "Callback" => "CallBack"}
8
+ ACTIONS = ['uploadMedia', 'getTranscript', 'deleteFile', 'getFileStatus']
9
+
10
+ def self.extended(client, args = {})
11
+ client.api_host = client.args[:api_host] || ENV.fetch('VOICEBASE_V1_API_HOST', 'https://api.voicebase.com')
12
+ client.api_endpoint = client.args[:api_endpoint] || ENV.fetch('VOICEBASE_V1_API_ENDPOINT', '/services')
13
+ end
14
+
15
+ def authenticate!
16
+ response = VoiceBase::Response.new(
17
+ self.class.post(uri,
18
+ query: {
19
+ version: @api_version, apiKey: @auth_key,
20
+ password: @auth_secret, action: 'getToken',
21
+ timeout: TOKEN_TIMEOUT_IN_MS
22
+ }), api_version)
23
+ @token = Token.new(response.token, TOKEN_TIMEOUT_IN_MS)
24
+ rescue NoMethodError => ex
25
+ raise VoiceBase::AuthenticationError, response.status_message
26
+ end
27
+
28
+ # E.g. @client.upload_media media_url: "https://ut.aws.amazon.com/..."
29
+ def method_missing(method, args, &block)
30
+ if actions.include?(camelize_name(method)) && args.size > 0
31
+ post camelize_keys(args).merge({action: camelize_name(method)})
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def post(query_params, headers = {})
40
+ query = default_query(query_params)
41
+
42
+ puts "post #{uri} #{query.inspect}, #{default_headers(headers).inspect}" if debug
43
+ VoiceBase::Response.new(self.class.post(uri,
44
+ query: query, headers: default_headers(headers)), api_version)
45
+ end
46
+
47
+ def actions
48
+ ACTIONS
49
+ end
50
+
51
+ def default_query(params = {})
52
+ params = params.reverse_merge({version: @api_version,
53
+ apiKey: @auth_key, password: @auth_secret,
54
+ lang: locale})
55
+
56
+ # authenticate using token or key/password?
57
+ if token && !token.expired?
58
+ params.merge!({token: token.token})
59
+ else
60
+ params.merge!({apiKey: @auth_key, password: @auth_secret})
61
+ end
62
+
63
+ params
64
+ end
65
+
66
+ def default_headers(headers = {})
67
+ {'User-Agent' => @user_agent, 'Accept' => 'application/json',
68
+ 'Cookie' => @cookies}.reject {|k, v| v.blank?}.merge(headers)
69
+ end
70
+
71
+ def camelize_keys(params)
72
+ params.inject({}) {|r, e| r[camelize_and_normalize_name(e.first)] = e.last; r }
73
+ end
74
+
75
+ # Parameters are camelized and normalized
76
+ # according to VoiceBase API.
77
+ #
78
+ # E.g.
79
+ #
80
+ # :media_url -> "mediaURL"
81
+ # :external_id -> "externalID"
82
+ # :error_callback -> "errorCallBack"
83
+ #
84
+ def camelize_and_normalize_name(snake_cased_name)
85
+ result = Client.camelize_name(snake_cased_name.to_s)
86
+ PARAM_NORMALIZATION.each {|k, v| result.gsub!(/#{k}/, v) }
87
+ result
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,24 @@
1
+ module VoiceBase
2
+ module V1
3
+ module Response
4
+ def self.extended(response)
5
+ end
6
+
7
+ def success?
8
+ ok? && request_status == "SUCCESS"
9
+ end
10
+
11
+
12
+ def transcript_ready?
13
+
14
+ # this was added because with the V1 API, a value in the returned JSON indicates both a
15
+ # successful HTTP request, but also a ready transcript. With V2, there's no JSON value
16
+ # to indicate status. Instead, the HTTP status code indicates request status, and
17
+ # the state becoming "finished" indicates the transcript it ready.
18
+
19
+ success?
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ module VoiceBase
2
+ module V2; end
3
+ end
4
+
5
+ require "voicebase/v2/client"
6
+ require "voicebase/v2/response"
@@ -0,0 +1,233 @@
1
+ module VoiceBase
2
+ module V2
3
+ module Client
4
+ BOUNDARY = "0123456789ABLEWASIEREISAWELBA9876543210"
5
+ MULTIPART_CONTENT_TYPE = "multipart/form-data; boundary=#{BOUNDARY}"
6
+
7
+ def self.extended(client, args = {})
8
+ client.api_host = client.args[:host] || ENV.fetch('VOICEBASE_V2_API_HOST', 'https://apis.voicebase.com')
9
+ client.api_endpoint = client.args[:api_endpoint] || ENV.fetch('VOICEBASE_V2_API_ENDPOINT', '/v2-beta')
10
+ end
11
+
12
+ def authenticate!
13
+ auth = {:username => @auth_key, :password => @auth_secret}
14
+ response = VoiceBase::Response.new(
15
+ self.class.get(
16
+ uri + '/access/users/admin/tokens',
17
+ basic_auth: auth,
18
+ headers: {
19
+ 'User-Agent' => @user_agent,
20
+ 'Accept' => 'application/json'
21
+ }
22
+ ), api_version)
23
+ @token = VoiceBase::Client::Token.new(response.tokens.try(:first).try(:[], 'token'))
24
+ rescue NoMethodError => ex
25
+ raise VoiceBase::AuthenticationError, response.status_message
26
+ end
27
+
28
+ def upload_media(args = {}, headers = {})
29
+
30
+ media_url = require_media_file_or_url(args)
31
+
32
+ form_args = {
33
+ 'media' => media_url,
34
+ 'configuration' => {
35
+ 'configuration' => {
36
+ 'executor' => 'v2'
37
+ }
38
+ }
39
+ }
40
+
41
+ # external ID is only partially supported in the V2 API (can't get plain text transcripts or delete media)
42
+ if args[:external_id]
43
+ form_args.merge!({
44
+ 'metadata' => {
45
+ 'metadata' => {
46
+ 'external' => {
47
+ 'id' => "#{args[:external_id]}"
48
+ }
49
+ }
50
+ }
51
+ })
52
+ end
53
+
54
+ response = self.class.post(
55
+ uri + '/media',
56
+ headers: multipart_headers(headers),
57
+ body: multipart_query(form_args)
58
+ )
59
+
60
+ VoiceBase::Response.new(response, api_version)
61
+ end
62
+
63
+ # I presume this method exists for parity with the V1 API however it is not used by the Orders app
64
+ def get_media(args = {}, headers = {})
65
+ raise ArgumentError, "Missing argument :media_id" unless args[:media_id]
66
+ url = if args[:media_id]
67
+ uri + "/media/#{args[:media_id]}"
68
+ elsif args[:external_id]
69
+ uri + "/media?externalID=#{args[:external_id]}"
70
+ else
71
+ raise ArgumentError, "Missing argument :media_url or :media_file"
72
+ end
73
+ if args[:external_id]
74
+ uri + "/media?externalID=#{args[:external_id]}"
75
+ else
76
+ raise ArgumentError, "Missing argument :external_id"
77
+ end
78
+
79
+ VoiceBase::Response.new(self.class.get(
80
+ url, headers: default_headers(headers)
81
+ ), api_version)
82
+ end
83
+
84
+ def get_json_transcript(args, headers)
85
+ url = if args[:media_id]
86
+ uri + "/media/#{args[:media_id]}"
87
+ else
88
+ raise ArgumentError, "Missing argument :media_id"
89
+ end
90
+
91
+ response = self.class.get(
92
+ url,
93
+ headers: default_headers(headers)
94
+ )
95
+
96
+ VoiceBase::Response.new(response, api_version)
97
+ end
98
+
99
+ def get_text_transcript(args, headers)
100
+ url = if args[:media_id]
101
+ uri + "/media/#{args[:media_id]}/transcripts/latest"
102
+ else
103
+ raise ArgumentError, "Missing argument :media_id"
104
+ end
105
+
106
+ headers.merge!({ 'Accept' => 'text/plain' })
107
+
108
+ response = self.class.get(
109
+ url,
110
+ headers: default_headers(headers)
111
+ )
112
+
113
+ response.parsed_response
114
+ end
115
+
116
+ def get_transcript(args = {}, headers = {})
117
+ if args[:format] == "txt"
118
+ get_text_transcript(args, headers)
119
+ else
120
+ get_json_transcript(args, headers)
121
+ end
122
+ end
123
+
124
+ # is this used?
125
+ def get_media_progress(args = {}, headers = {})
126
+ raise ArgumentError, "Missing argument :media_id" unless args[:media_id]
127
+ VoiceBase::Response.new(self.class.get(
128
+ uri + "/media/#{args[:media_id]}/progress",
129
+ headers: default_headers(headers)
130
+ ), api_version)
131
+ end
132
+
133
+ def delete_file(args = {}, headers = {})
134
+ url = if args[:media_id]
135
+ uri + "/media/#{args[:media_id]}"
136
+ else
137
+ raise ArgumentError, "Missing argument :media_id"
138
+ end
139
+
140
+ response = self.class.delete(
141
+ url,
142
+ headers: default_headers(headers)
143
+ )
144
+
145
+ VoiceBase::Response.new(response, api_version)
146
+ end
147
+
148
+ private
149
+
150
+ def default_headers(headers = {})
151
+ authenticate! unless token
152
+ headers = {'Authorization' => "Bearer #{token.token}",
153
+ 'User-Agent' => user_agent}.reject {|k, v| v.blank?}.merge(headers)
154
+ puts "> headers\n> #{headers}" if debug
155
+ headers
156
+ end
157
+
158
+ def multipart_headers(headers = {})
159
+ default_headers(headers.merge({'Content-Type' => MULTIPART_CONTENT_TYPE}))
160
+ end
161
+
162
+ def multipart_query(params)
163
+ fp = []
164
+
165
+ params.each do |k, v|
166
+ if v.respond_to?(:path) and v.respond_to?(:read) then
167
+ fp.push(FileParam.new(k, v.path, v.read))
168
+ elsif v.is_a?(Hash)
169
+ fp.push(HashParam.new(k, v))
170
+ else
171
+ fp.push(StringParam.new(k, v))
172
+ end
173
+ end
174
+
175
+ query = fp.map {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--"
176
+ puts "> multipart-query\n> #{query}" if debug
177
+ query
178
+ end
179
+
180
+ def require_media_file_or_url(args = {})
181
+ media = if args[:media_url]
182
+ args[:media_url]
183
+ elsif args[:media_file]
184
+ args[:media_file]
185
+ else
186
+ raise ArgumentError, "Missing argument :media_url or :media_file"
187
+ end
188
+ end
189
+
190
+ class StringParam
191
+ attr_accessor :k, :v
192
+
193
+ def initialize(k, v)
194
+ @k, @v = k, v
195
+ end
196
+
197
+ def to_multipart
198
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(k.to_s)}\"\r\n\r\n#{v}\r\n"
199
+ end
200
+ end
201
+
202
+ class HashParam
203
+ attr_accessor :k, :v
204
+
205
+ def initialize(k, v)
206
+ @k, @v = k, v
207
+ end
208
+
209
+ def to_multipart
210
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(k.to_s)}\"\r\n\r\n#{v.to_json}\r\n"
211
+ end
212
+ end
213
+
214
+ # Formats the contents of a file or string for inclusion with a multipart
215
+ # form post
216
+ class FileParam
217
+ attr_accessor :k, :filename, :content
218
+
219
+ def initialize(k, filename, content)
220
+ @k, @filename, @content = k, filename, content
221
+ end
222
+
223
+ def to_multipart
224
+ # If we can tell the possible mime-type from the filename, use the
225
+ # first in the list; otherwise, use "application/octet-stream"
226
+ mime_type = MIME::Types.type_for(filename)[0] || MIME::Types["application/octet-stream"][0]
227
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(k.to_s)}\"; filename=\"#{ filename }\"\r\n" +
228
+ "Content-Type: #{ mime_type.simplified }\r\n\r\n#{ content }\r\n"
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,38 @@
1
+ module VoiceBase
2
+ module V2
3
+ module Response
4
+
5
+ TRANSCRIPT_READY_STATUS = "finished".freeze
6
+
7
+ def success?
8
+
9
+ # for the V1 API this indicates both a successful HTTP status code and a values of "SUCCESS" in the
10
+ # returned JSON. with V2, there is no "SUCCESS" value. The combined use was split, adding
11
+ # #transcript_ready? to both interfaces.
12
+
13
+ ok?
14
+ end
15
+
16
+ def media_id
17
+ voicebase_response['mediaId']
18
+ end
19
+
20
+ def transcript_ready?
21
+ voicebase_response['media']['status'].casecmp(TRANSCRIPT_READY_STATUS) == 0
22
+ end
23
+
24
+ def transcript
25
+ # this retrieves the JSON transcript only
26
+ # the plain text transcript is a plain text non-JSON response
27
+ voicebase_response['media']['transcripts']['latest']['words']
28
+ end
29
+
30
+ private
31
+
32
+ def voicebase_response
33
+ http_response.parsed_response
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,5 @@
1
+ module VoiceBase
2
+ VERSION = "1.0.14"
3
+
4
+ def self.version; VERSION; end
5
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'voicebase/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "voicebase-client-ruby"
8
+ spec.version = VoiceBase::version
9
+ spec.authors = ["Jerry Hogsett"]
10
+ spec.email = ["jerry@usertesting.com"]
11
+
12
+ spec.summary = %q{Ruby client for VoiceBase API Version 1.x and 2.x.}
13
+ spec.description = %q{Ruby client for VoiceBase API Version 1.x and 2.x that will make both API versions available at the same time.}
14
+ spec.homepage = "https://github.com/usertesting/voicebase-client-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.11"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_development_dependency "timecop", "~> 0.8"
26
+
27
+ spec.add_dependency "httparty"
28
+ spec.add_dependency "activesupport"
29
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: voicebase-client-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.14
5
+ platform: ruby
6
+ authors:
7
+ - Jerry Hogsett
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: timecop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: httparty
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Ruby client for VoiceBase API Version 1.x and 2.x that will make both
98
+ API versions available at the same time.
99
+ email:
100
+ - jerry@usertesting.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - ".ruby-gemset"
108
+ - ".ruby-version"
109
+ - ".travis.yml"
110
+ - Gemfile
111
+ - LICENSE
112
+ - README.md
113
+ - Rakefile
114
+ - bin/console
115
+ - bin/setup
116
+ - lib/voicebase.rb
117
+ - lib/voicebase/client.rb
118
+ - lib/voicebase/client/token.rb
119
+ - lib/voicebase/helpers.rb
120
+ - lib/voicebase/json.rb
121
+ - lib/voicebase/json/word.rb
122
+ - lib/voicebase/response.rb
123
+ - lib/voicebase/v1.rb
124
+ - lib/voicebase/v1/client.rb
125
+ - lib/voicebase/v1/response.rb
126
+ - lib/voicebase/v2.rb
127
+ - lib/voicebase/v2/client.rb
128
+ - lib/voicebase/v2/response.rb
129
+ - lib/voicebase/version.rb
130
+ - voicebase-client-ruby.gemspec
131
+ homepage: https://github.com/usertesting/voicebase-client-ruby
132
+ licenses:
133
+ - MIT
134
+ metadata: {}
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubyforge_project:
151
+ rubygems_version: 2.4.8
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: Ruby client for VoiceBase API Version 1.x and 2.x.
155
+ test_files: []