File Coverage

blib/lib/WebService/Speechmatics.pm
Criterion Covered Total %
statement 36 89 40.4
branch 0 12 0.0
condition 0 15 0.0
subroutine 12 18 66.6
pod 6 6 100.0
total 54 140 38.5


line stmt bran cond sub pod time code
1             package WebService::Speechmatics;
2             $WebService::Speechmatics::VERSION = '0.01';
3 1     1   395 use 5.010;
  1         2  
  1         27  
4 1     1   360 use Moo 1.006;
  1         9305  
  1         4  
5 1     1   1445 use JSON qw/ decode_json /;
  1         1  
  1         4  
6 1     1   100 use Carp qw/ croak /;
  1         1  
  1         39  
7 1     1   3 use File::Basename qw/ basename /;
  1         1  
  1         37  
8 1     1   3 use Scalar::Util qw/ reftype /;
  1         1  
  1         44  
9              
10 1     1   302 use WebService::Speechmatics::User;
  1         2  
  1         27  
11 1     1   323 use WebService::Speechmatics::Job;
  1         2  
  1         27  
12 1     1   406 use WebService::Speechmatics::Submission;
  1         1  
  1         25  
13 1     1   271 use WebService::Speechmatics::Speaker;
  1         2  
  1         20  
14 1     1   263 use WebService::Speechmatics::Word;
  1         2  
  1         24  
15 1     1   271 use WebService::Speechmatics::Transcript;
  1         2  
  1         652  
16              
17             my $BASE_URL = 'https://api.speechmatics.com/v1.0';
18             my $default_ua = sub {
19             require LWP::UserAgent;
20             require HTTP::Request::Common;
21             require IO::Socket::SSL;
22              
23             return LWP::UserAgent->new();
24             };
25              
26             my $get = sub {
27             my $self = shift;
28             my $path = shift;
29             my $url = $self->base_url.$path.'?auth_token='.$self->token;
30              
31             # TODO handle failure by throwing an exception here
32             return $self->ua->get($url);
33             };
34              
35             has token => (is => 'ro', required => 1);
36             has ua => (is => 'ro', required => 1, default => $default_ua);
37             has base_url => (is => 'ro', required => 1, default => sub { $BASE_URL });
38             has user_id => (is => 'ro', required => 1);
39             has lang => (is => 'ro', required => 1);
40             has callback => (is => 'ro');
41             has notification => (is => 'ro', default => sub { 'none' });
42              
43             sub user
44             {
45 0     0 1   my $self = shift;
46 0           my $response = $self->$get('/user/'.$self->user_id);
47 0           my $userdata = decode_json($response->content);
48              
49 0           return WebService::Speechmatics::User->new($userdata->{user});
50             }
51              
52             sub balance
53             {
54 0     0 1   my $self = shift;
55 0           my $user = $self->user;
56              
57 0           return $user->balance;
58             }
59              
60             sub jobs
61             {
62 0     0 1   my $self = shift;
63 0           my $response = $self->$get('/user/'.$self->user_id.'/jobs');
64 0           my $jobsdata = decode_json($response->content);
65              
66 0           return map { WebService::Speechmatics::Job->new($_) }
  0            
67 0           @{ $jobsdata->{jobs} };
68             }
69              
70             sub job
71             {
72 0     0 1   my $self = shift;
73 0           my $id = shift;
74 0           my $response = $self->$get('/user/'.$self->user_id.'/jobs/'.$id);
75 0           my $jobdata = decode_json($response->content);
76              
77 0           return WebService::Speechmatics::Job->new($jobdata->{job});
78             }
79              
80             sub submit_job
81             {
82 0     0 1   my $self = shift;
83 0           my $argref = shift;
84              
85 0 0         if (not defined reftype($argref)) {
    0          
86 0           $argref = { filename => $argref };
87             }
88             elsif (reftype($argref) ne 'HASH') {
89 0           croak "You can either pass a filename or a hashref to submit_job()";
90             }
91              
92 0 0         if (not exists $argref->{filename}) {
93 0           croak "you must pass a filename";
94             }
95              
96 0   0       my $lang = $argref->{lang}
      0        
97             // $self->lang
98             // croak "You must specify the language with 'lang'";
99              
100 0   0       my $callback = $argref->{callback}
101             // $self->callback;
102              
103 0           my $url = sprintf('%s/user/%d/jobs/?auth_token=%s',
104             $self->base_url,
105             $self->user_id,
106             $self->token,
107             );
108 0           my @args = (
109             data_file => [$argref->{filename}],
110             model => $lang,
111             );
112              
113 0 0         if (defined $callback) {
114 0           push(@args, notification => 'callback',
115             callback => $callback);
116             }
117             else {
118 0   0       push(@args, notification => $argref->{notification}
119             // $self->notification);
120             }
121              
122 0           my $request = HTTP::Request::Common::POST(
123             $url,
124             Content_Type => 'form-data',
125             Content => \@args,
126             );
127              
128 0           my $response = $self->ua->request($request);
129              
130 0 0 0       if (!defined($response) || !$response->is_success) {
131 0           croak "failed to submit job\n",
132             "HTTP status code: ", $response->code;
133             }
134              
135 0           return WebService::Speechmatics::Submission->new(
136             decode_json($response->content)
137             );
138             }
139              
140             sub transcript
141             {
142 0     0 1   my $self = shift;
143 0           my $id = shift;
144 0           my $path = sprintf('/user/%d/jobs/%d/transcript', $self->user_id, $id);
145 0           my $response = $self->$get($path);
146 0           my $txdata = decode_json($response->content);
147              
148 0           print STDERR "RESPONSE: ", $response->content, "\n";
149              
150 0 0         if (exists $txdata->{job}) {
151 0           my $job = WebService::Speechmatics::Job->new($txdata->{job});
152 0           my @speakers = map { WebService::Speechmatics::Speaker->new($_) }
  0            
153 0           @{ $txdata->{speakers} };
154 0           my @words = map { WebService::Speechmatics::Word->new($_) }
  0            
155 0           @{ $txdata->{words} };
156 0           return WebService::Speechmatics::Transcript->new(
157             job => $job,
158             speakers => \@speakers,
159             words => \@words,
160             );
161             }
162             else {
163 0           return;
164             }
165             }
166              
167             1;
168              
169             =head1 NAME
170              
171             WebService::Speechmatics - ALPHA interface to speech-to-text API from speechmatics.com
172              
173             =head1 SYNOPSIS
174              
175             use WebService::Speechmatics;
176              
177             my $sm = WebService::Speechmatics->new(
178             user_id => 42,
179             token => '...THISISNOTREALLYMYAPITOKEN...',
180             lang => 'en-GB',
181             );
182             my $response = $sm->submit_job('foobar.wav');
183              
184             # wait a bit
185              
186             $transcript = $sm->transcript($response->id);
187              
188             =head1 DESCRIPTION
189              
190             This module provides an interface to the
191             L
192             L for
193             converting speech audio to text.
194              
195             B: please note that this is very much a work in progress,
196             and all aspects of the interface may change in the future.
197             I've only played with the service so far. Happy to hear suggestions
198             for this module's interface. My current thoughts are in C.
199              
200             Before using this module you need to register with
201             L,
202             which will provide you with a user id (integer) and a token
203             to use with the API (a string of random characters).
204              
205             After submitting a speech audio file, you can either poll until it has
206             been converted to text (or failed), or you can provide a callback URL
207             and Speechmatics will POST the result to your URL.
208              
209             =head2 Specifying language
210              
211             Whenever you submit a transcription job, you must specify the suspected
212             language (of the speaker(s) in the audio). Right now that can be one of
213              
214             en-GB UK English
215             en-US American English
216              
217             You can either specify the language every time you submit a transcription
218             job, or you can specify it when to instantiate this module,
219             as in the SYNOPSIS.
220              
221              
222             =head1 METHODS
223              
224             =head2 new
225              
226             The following attributes can be passed to the constructor:
227              
228             =over 4
229              
230             =item * token - the API token on registering with Speechmatics.
231              
232             =item * user_id - the integer user id which you also get from Speechmatics.
233              
234             =item * lang - the suspected language of the speaker, described above.
235              
236             =item * callback - a URL which transcripts should be POSTed back to.
237              
238             =item * notification - if you set this to 'email' then you'll get an email
239             sent to you when jobs are completed. Defaults to 'none'.
240              
241             =back
242              
243             The B and B attributes are required, but the others are
244             optional, as they can be specified on a per-job basis as well.
245              
246             =head2 submit_job
247              
248             There are two ways to submit a job. The simplest is where you just
249             pass the name / path for an audio file:
250              
251             $speechmatics->submit_job('i-have-a-dream.wav');
252              
253             To submit jobs this way, you must specify the language by passing B
254             to the constructor.
255              
256             You can also provide additional attributes by passing a hash ref:
257              
258             $speechmatics->submit_job({
259             filename => 'i-have-a-dream.wav',
260             lang => 'en-GB',
261             notification => 'email',
262             });
263              
264             =head2 jobs
265              
266             Returns a list of your jobs, each of which is an instance of
267             L,
268             which has attributes named exactly the same as the fields given
269             in the Speechmatics API documentation.
270              
271             =head2 balance
272              
273             Returns an integer, which is the number of Speechmatics credits
274             you have left in your account.
275              
276             =head2 transcript
277              
278             Returns an instance of L,
279             or C if the job is still in progress. This has three attributes:
280              
281             =over 4
282              
283             =item * job - instance of L with details
284             of the job which produced this transcription.
285              
286             =item * speakers - an array ref of speakers, which will currently
287             always contain the single dominant speaker.
288              
289             =item * words - an array ref of L.
290             Each instance has attributes named exactly as in the Speechmatics API doc.
291              
292             =back
293              
294             Here's a simple example how you might submit a job for transcription,
295             then dispay the converted text:
296              
297             my $sm = WebService::Speechmatics->new( ... );
298             my $response = $sm->submit_job('sample.wav');
299              
300             # wait
301              
302             my $transcript = $sm->transcript($response->id);
303             my @words = map { $_->name } @{ $transcript->words };
304              
305             print "you said: @words\n";
306              
307             =head1 SEE ALSO
308              
309             L - home page for Speechmatics
310              
311             L - the official documentation
312             for the Speechmatics API.
313              
314             =head1 REPOSITORY
315              
316             L
317              
318             =head1 AUTHOR
319              
320             Neil Bowers Eneilb@cpan.orgE
321              
322             =head1 COPYRIGHT AND LICENSE
323              
324             This software is copyright (c) 2015 by Neil Bowers .
325              
326             This is free software; you can redistribute it and/or modify it under
327             the same terms as the Perl 5 programming language system itself.
328              
329             =cut
330