transcribeme 0.0.5.beta → 1.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d18167f14ce8f645d7f14e325cd349fea1b9b51e
4
- data.tar.gz: 652690384aee25eefb17ac89fd80a960be137e8c
3
+ metadata.gz: 220bcd847b3e0b90afbbea5f779e59705c7952ea
4
+ data.tar.gz: c6e5d50a3297e6b5756bb5e8d0f0185a6d94b1dc
5
5
  SHA512:
6
- metadata.gz: 01fab4ab2552a0fab7c778f9a71f11ba2dbce1670c621f58d6af6b7f951c2aad70c88c5c924a39668d03c83ea07b11e3317f3b428a9a33ad6bdf335e3ab799b2
7
- data.tar.gz: 77adffb1e925a81b7505a7693c8e24b61d20a04496480ba20de0269a3be138c987c83d02c73d8d3b109f95ea4b20cdac66f1c9738e8ac02527e14bcf1c0f094d
6
+ metadata.gz: a3ef2f1b18f139220c0096da77af39089707c4544afdda70dd03e854bdd4e8a46302ca108e2435960333b2c5221a7e48c9989eacbe5c9d5942e17d93f8edbc23
7
+ data.tar.gz: 6526240aafff85c06311693037ad10f3b5a8a09d285652cb53886f53426ad2e444e1b97a6c83d223dacc0a441f29a2130112faa09e32bf0381cc5ad1dd8e1401
Binary file
data.tar.gz.sig CHANGED
Binary file
data/.gitignore CHANGED
@@ -7,7 +7,8 @@
7
7
  Gemfile.lock
8
8
  InstalledFiles
9
9
  _yardoc
10
- coverage
10
+ coverage/
11
+ coverage/*
11
12
  doc/
12
13
  lib/bundler/man
13
14
  pkg
@@ -0,0 +1,22 @@
1
+ TrailingWhitespace:
2
+ Enabled: false
3
+
4
+ LineLength:
5
+ Enabled: false
6
+
7
+ StringLiterals:
8
+ Enabled: false
9
+
10
+ EmptyLines:
11
+ Enabled: false
12
+
13
+ AllCops:
14
+ Includes:
15
+ - Rakefile
16
+ - config.ru
17
+ Excludes:
18
+ - db/schema.rb
19
+ - db/migrate/**
20
+ - bin/**
21
+ - config/**
22
+ - script/**
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - 1.9.2
6
+ - jruby-19mode
7
+ - rbx-19mode
8
+ - jruby-head
data/Gemfile CHANGED
@@ -3,7 +3,12 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in transcribeme-api.gemspec
4
4
  gemspec
5
5
 
6
-
7
- group :development, :tools do
6
+ group :development, :test do
8
7
  gem 'pry'
8
+ gem 'rubocop'
9
+ gem 'guard-rspec'
10
+ gem 'guard-yard'
11
+ gem 'guard-rubocop'
12
+ gem 'terminal-notifier-guard'
13
+ gem 'coveralls', require: false
9
14
  end
@@ -0,0 +1,35 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
25
+
26
+ guard :rubocop do
27
+ watch(%r{.+\.rb$})
28
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
29
+ end
30
+
31
+ guard 'yard' do
32
+ watch(%r{app/.+\.rb})
33
+ watch(%r{lib/.+\.rb})
34
+ watch(%r{ext/.+\.c})
35
+ end
data/README.md CHANGED
@@ -6,10 +6,19 @@
6
6
  [![Code Climate](https://codeclimate.com/github/tuttinator/transcribeme.png)](https://codeclimate.com/github/tuttinator/transcribeme)
7
7
 
8
8
 
9
- ### THIS IS STILL IN BETA
9
+ ### Description
10
10
 
11
+ This gem is a Ruby wrapper for the TranscribeMe SOAP API, built on Savon, and includes some extra dangly bits for uploading to Windows Azure Blob storage.
11
12
 
12
- This gem is a Ruby wrapper for the TranscribeMe SOAP API, built on Savon
13
+ The DSL may change before 1.0.0 stable is released.
14
+
15
+ Changes from prior 1.0.0 include bringing the Ruby method names in line with the actual SOAP action names.
16
+
17
+ This gem wants to make it easy for you. If you call the 'sign_in' method before initializing a session then we all know you meant to. We'll jump right in there and initialize it for you.
18
+
19
+ ## Prerequisites
20
+
21
+ This gem relies on FFMPEG for determining the duration of audio (and video) files. The TranscribeMe SOAP API leaves it as the client's responsibility for determining the duration of files being uploaded.
13
22
 
14
23
  ## Installation
15
24
 
@@ -37,11 +46,31 @@ The documentation can be [browsed online](http://rubydoc.info/github/tuttinator/
37
46
 
38
47
  ## Roadmap
39
48
 
40
- - [ ] Write specs
41
- - [ ] Set up Travis-CI and document supported Ruby versions
42
- - [ ] Investigate Windows Azure Blob storage file upload
43
- - [ ] Document SOAP calls and error messages
44
- - [ ] Complete YARD documentation
49
+ Version 1.0.0 stable
50
+
51
+ - [ ] Write specs
52
+ - [ x ] Set up Travis-CI and document supported Ruby versions
53
+ - [ x ] Investigate Windows Azure Blob storage file upload
54
+ - [ x ] Include Excon for Windows Azure Blob storage
55
+ - [ x ] Base64 decrypt transcription results
56
+ - [ ] Document SOAP calls and error messages
57
+ - [ ] Complete YARD documentation
58
+ - [ ] Include option (default)
59
+ - [ ] Validations for GUIDs
60
+ - [ ] Exceptions for error handling (about 50%)
61
+ - [ ] Modelling Recording objects, particularly better describing recording status
62
+
63
+ Version 1.1.0
64
+
65
+ - [ ] Create a CLI interface
66
+
67
+ RubyMotion
68
+
69
+ - [ ] A RubyMotion fork (transcribeme-motion), wrapped in BubbleWrap's HTTP DSL (watch this space)
70
+
71
+ REST API Wrapper
72
+
73
+ - [ ] A Sinatra RESTful wrapper around the SOAP operations for your own personal REST API middleman, with JSON-ic magic at your fingertips. JSON was always my favourite Argonaut.
45
74
 
46
75
  ## Contributing
47
76
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new
5
5
 
6
- task :default => :spec
7
- task :test => :spec
6
+ task default: :spec
7
+ task test: :spec
@@ -1,37 +1,5 @@
1
- require 'transcribeme/version'
2
-
3
- module TranscribeMe
4
- module API
5
-
6
- WSDL = "http://transcribeme-api.cloudapp.net/PortalAPI.svc?wsdl=wsdl0"
7
- ENDPOINT = "http://transcribeme-api.cloudapp.net/PortalAPI.svc"
8
- NAMESPACE = "http://TranscribeMe.API.Web"
9
- NAMESPACE_IDENTIFIER = :tns # any identifier can be used
10
-
11
- SOAP_ENVELOPE = ["soapenv:Envelope", { "xmlns:soapenv" => "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:#{NAMESPACE_IDENTIFIER}" => NAMESPACE }]
12
-
13
- def self.construct_xml(soap_method, options = {})
14
- Builder::XmlMarkup.new.tag!(*SOAP_ENVELOPE) do |xml|
15
- xml.tag!("soapenv:Body") do |xml|
16
- xml.tag!("#{NAMESPACE_IDENTIFIER}:#{soap_method}") do |xml|
17
- options.each do |key, value|
18
- xml.tag!("#{NAMESPACE_IDENTIFIER}:#{key}") { |xml| xml.text! value }
19
- end
20
- end
21
- end
22
- end
23
- end
24
-
25
- end
26
- end
27
-
28
1
  require 'savon'
29
-
30
- require 'transcribeme/api/client'
31
- require 'transcribeme/api/customer_login'
32
- require 'transcribeme/api/session'
33
- require 'transcribeme/api/recordings'
34
- require 'transcribeme/api/submission'
35
- require 'transcribeme/api/submission_with_promocode'
36
- require 'transcribeme/api/check_transcription_ready'
37
- require 'transcribeme/api/upload_url'
2
+ require 'streamio-ffmpeg'
3
+ require 'excon'
4
+ require 'transcribeme/version'
5
+ require 'transcribeme/api/client'
@@ -1,16 +1,34 @@
1
+ # TranscribeMe
1
2
  module TranscribeMe
3
+ # API module
2
4
  module API
3
-
5
+ # API Client with methods for interacting with the SOAP API
4
6
  class Client
5
7
 
6
- attr_accessor :session_id
7
- attr_reader :savon, :session_expiry_time
8
-
8
+ # Public: Returns the session id of the current session
9
+ attr_reader :session_id
10
+ # Public: Returns the expiry time of the current session
11
+ attr_reader :session_expiry_time
12
+ # Public: Returns the underlining Savon object
13
+ attr_reader :savon
14
+
15
+ WSDL = 'http://transcribeme-api.cloudapp.net/PortalAPI.svc?wsdl=wsdl0'
16
+ ENDPOINT = 'http://transcribeme-api.cloudapp.net/PortalAPI.svc'
17
+ NAMESPACE = 'http://TranscribeMe.API.Web'
18
+
19
+ # Public: Initializes the API Client class
20
+ #
9
21
  def initialize
10
- @savon = ::Savon.client(wsdl: WSDL, endpoint: ENDPOINT, namespace: NAMESPACE, soap_version: 1)
22
+ # Note: Deliberately disabling the verbose Savon logging
23
+ @savon = ::Savon.client(endpoint: ENDPOINT, namespace: NAMESPACE,
24
+ soap_version: 1, wsdl: WSDL, log: false)
11
25
  end
12
26
 
13
- def initialize_session!
27
+ # Public: Initializes a session on the API server and stores
28
+ # the expiry time and the session_id in instance variables
29
+ #
30
+ # Returns the session_id GUID
31
+ def initialize_session
14
32
  response = @savon.call :initialize_session
15
33
  # Without ActiveSupport
16
34
  # 1.hour.from_now is 3600 seconds from Time.now
@@ -18,69 +36,201 @@ module TranscribeMe
18
36
  @session_id = response.body[:initialize_session_response][:initialize_session_result]
19
37
  end
20
38
 
21
- def login_with(username, password)
39
+ # Public: Calls the 'SignIn' SOAP action
40
+ #
41
+ # username - a String which corresponds to a TranscribeMe Portal
42
+ # account username which can be any valid email address
43
+ # password - a String which is the portal account password
44
+ #
45
+ # Returns a GUID of the Customer ID
46
+ def sign_in(username, password)
22
47
 
23
- initialize_session! unless session_valid?
48
+ # If #login_with is called before we have a session_id instance variable
49
+ # then call initialize_session
50
+ initialize_session unless session_valid?
24
51
 
52
+ # Use Savon to call the 'SignIn' SOAP action
25
53
  response = @savon.call :sign_in,
26
- message: { "wsdl:sessionID" => @session_id,
27
- "wsdl:username" => username,
28
- "wsdl:password" => password }
54
+ message: { 'wsdl:sessionID' => @session_id,
55
+ 'wsdl:username' => username,
56
+ 'wsdl:password' => password }
29
57
 
30
- @customer_login_id = response.body[:sign_in_response][:sign_in_result]
58
+ error_message = response.body[:sign_in_response][:error_message]
59
+
60
+ raise error_message if error_message
31
61
 
62
+ # Assign the customer_login_id variable to the string in the SOAP response
63
+ @customer_login_id = response.body[:sign_in_response][:sign_in_result]
32
64
  end
33
65
 
66
+ # Public: Calls the 'GetCustomerRecordings' SOAP Action
67
+ #
68
+ # requires the user to be logged in
69
+ #
70
+ # Returns an Array of Hashes of with the properties of recording objects
34
71
  def get_recordings
35
- # raise "Login first!" unless @customer_login_id
72
+ # raise 'Login first!' unless @customer_login_id
36
73
 
37
74
  response = @savon.call :get_customer_recordings,
38
- message: { "wsdl:sessionID" => session_id }
75
+ message: { 'wsdl:sessionID' => session_id }
39
76
 
40
77
  @recordings = response.body[:get_customer_recordings_response][:get_customer_recordings_result][:recording_info]
41
78
  end
42
79
 
80
+ # Public: Calls the 'GetUploadUrl' SOAP Action
81
+ #
82
+ # Returns the upload url as a String
43
83
  def get_upload_url
44
- # raise "Login first!" unless @customer_login_id
84
+ # raise 'Login first!' unless @customer_login_id
45
85
 
46
86
  response = @savon.call :get_upload_url,
47
- message: { "wsdl:sessionID" => @session_id }
87
+ message: { 'wsdl:sessionID' => @session_id }
48
88
 
49
89
  @upload_url = response.body[:get_upload_url_response][:get_upload_url_result]
90
+ end
50
91
 
92
+ # Public: uploads to Azure Blob Storage and commits the upload to
93
+ # the TranscribeMe SOAP API
94
+ #
95
+ # file_path - a String with the path to the actual file
96
+ # options - a Hash with these keys:
97
+ # :multiple_speakers - Boolean (default is true)
98
+ # :duration - Float
99
+ # :description - String
100
+ #
101
+ # Returns the response as a Hash
102
+ def upload(file_path, options = {})
103
+
104
+ # If not logged in, raise this exception
105
+ raise 'Login first!' unless @customer_login_id
106
+
107
+ # Extract options from the options hash
108
+ multiple_speakers = options[:multiple_speakers] || true
109
+ description = options[:description]
110
+ file_name = File.basename(file_path)
111
+ file_format = File.extname(file_path)
112
+ file_size = File.stat(file_path).size
113
+ # Use the duration if provided in the options hash
114
+ duration = options[:duration] || ::FFMPEG::Movie.new(file_path).duration
115
+
116
+ # Use the last upload url, or grab a new one
117
+ @upload_url ||= get_upload_url
118
+
119
+ # Create a connection to the upload url
120
+ connection = Excon.new(@upload_url)
121
+ # Upload to
122
+ connection.put(headers: { "x-ms-blob-type" => "BlockBlob",
123
+ "x-ms-date" => Time.now.to_s,
124
+ "Content-Length" => file_size}, body: File.read(file_path))
125
+
126
+ # Post to the
127
+ response = @savon.call :commit_upload, message: { "wsdl:sessionID" => @session_id,
128
+ "wsdl:url" => @upload_url,
129
+ "wsdl:name" => file_name,
130
+ "wsdl:description" => description,
131
+ "wsdl:duration" => duration,
132
+ "wsdl:source" => "Ruby API Client",
133
+ "wsdl:format" => file_format,
134
+ "wsdl:isMultipleSpeakers" => multiple_speakers }
135
+
136
+ # Set the upload url to nil so that we don't reuse it
137
+ @upload_url = nil
138
+
139
+ response
51
140
  end
52
141
 
53
- def submit_recording(recording)
54
- # initialize_session! unless @session.try :valid?
55
- Submission.new(@session.session_id, recording, @savon).submit!
142
+ # Public: Calls the 'TranscribeRecording' SOAP Action
143
+ #
144
+ # recording_id - a String in GUID format
145
+ #
146
+ # Returns the SOAP response Hash
147
+ def transcribe_recording(recording_id)
148
+ # initialize_session unless @session.try :valid?
149
+
150
+ response = @savon.call :transcribe_recording,
151
+ message: { 'wsdl:sessionID' => @session_id,
152
+ 'wsdl:recordingId' => recording_id }
153
+
154
+ response.body[:transcribe_recording_response][:transcribe_recording_result]
56
155
  end
57
156
 
58
- def submit_recording_with_promocode(recording, promocode)
59
- # initialize_session! unless @session.try :valid?
60
- SubmissionWithPromocode.new(@session.session_id, recording, promocode, @savon).submit!
157
+ # Public: Calls the 'TranscribeRecordingWithPromoCode' SOAP Action
158
+ #
159
+ # recording_id - a String in GUID format
160
+ # promocode - a String
161
+ #
162
+ # Returns the SOAP response Hash
163
+ def transcribe_recording_using_promocode(recording_id, promocode)
164
+ # initialize_session unless @session.try :valid?
165
+
166
+ response = @savon.call :transcribe_recording_using_promocode,
167
+ message: { 'wsdl:sessionID' => @session_id,
168
+ 'wsdl:recordingId' => recording_id,
169
+ 'wsdl:promoCode' => promocode }
170
+
171
+ response.body[:transcribe_recording_using_promocode_response][:transcribe_recording_using_promocode_result]
61
172
  end
62
173
 
63
- def get_status(recording_id)
64
- # raise "Login first!" unless @customer_login_id
65
- CheckTranscriptionReady.new(@session.session_id, recording_id, @savon).check!
174
+ # Public: Calls the 'GetRecordingInfo' SOAP Action
175
+ #
176
+ # recording_id - a String in GUID format
177
+ #
178
+ # Returns the SOAP response Hash
179
+ def get_recording_info(recording_id)
180
+ response = @savon.call :get_recording_info,
181
+ message: { 'wsdl:sessionID' => @session_id,
182
+ 'wsdl:recordingID' => recording_id }
183
+ response.body[:get_recording_info_response][:get_recording_info_result]
66
184
  end
67
185
 
68
- def logout!
69
- # raise "Login first!" unless @customer_login_id
70
- FinalizeSession.new(@session.session_id, @savon).submit!
186
+ # Public: Calls the 'GetTranscription' SOAP Action to allow for
187
+ # downloading of transcriptions
188
+ #
189
+ # recording_id - a String in GUID format
190
+ # format - a Symbol - either :text, :rtf, :pdf, :html
191
+ #
192
+ # Returns the file data in a String to write to a file (decoded from Base64.)
193
+ def get_transcription(recording_id, format = :text)
194
+ format_type = case format
195
+ when :text
196
+ "Text"
197
+ else
198
+ format.to_s.upcase
199
+ end
200
+
201
+ response = @savon.call :get_transcription, message: { 'wsdl:sessionID' => @session_id,
202
+ 'wsdl:recId' => recording_id,
203
+ 'wsdl:formattingType' => format_type }
204
+
205
+ error_message = response.body[:get_transcription_response][:error_message]
206
+ raise error_message if error_message
207
+
208
+ transcription = response.body[:get_transcription_response][:get_transcription_result]
209
+
210
+ raise "Transcription unable to be downloaded" if transcription.nil?
211
+
212
+ Base64.decode64(transcription)
213
+ end
214
+
215
+ # Public: Calls the 'FinalizeSession' SOAP Action to close
216
+ # the session on the server
217
+ #
218
+ # Returns the SOAP response Hash
219
+ def finalize_session
220
+ @savon.call :finalize_session,
221
+ message: { 'wsdl:sessionID' => @session_id }
71
222
  end
72
223
 
73
224
  private
74
225
 
226
+ # Private: Checks if the session expiry time has passed
227
+ #
228
+ # Returns a Boolean
75
229
  def session_valid?
76
- if @session_expiry_time
77
- @session_expiry_time > Time.now
78
- end
230
+ @session_expiry_time > Time.now if @session_expiry_time
79
231
  end
80
232
 
81
-
82
-
83
233
  end
84
234
 
85
235
  end
86
- end
236
+ end