line
stmt
bran
cond
sub
pod
time
code
1
#!/usr/bin/perl
2
#-------------------------------------------------------------------------------
3
# Select AWS Polly speakers with specified characteristics
4
# Philip R Brenan at gmail dot com, Appa Apps Ltd, 2017
5
#-------------------------------------------------------------------------------
6
7
package Aws::Polly::Select;
8
require v5.16.0;
9
1
1
630
use warnings FATAL => qw(all);
1
7
1
37
10
1
1
13
use strict;
1
4
1
31
11
1
1
15
use Carp;
1
3
1
89
12
1
1
839
use Data::Table::Text qw(:all);
1
69860
1
372
13
1
1
7
use Data::Dump qw(dump);
1
2
1
31
14
1
1
4
use utf8;
1
2
1
4
15
16
our $VERSION = '20171217';
17
18
BEGIN
19
1
1
151
{my @fields = qw(Gender Id LanguageCode LanguageName Name Written Country); # Field names
20
21
1
2
for my $field(@fields) # Generate methods to get attributes from each speaker
22
{package Aws::Polly::Select::Speaker;
23
7
596
Data::Table::Text::genLValueScalarMethods($field);
24
}
25
26
1
86
for my $field(@fields) # Generate methods that get all the values of each attribute of each speaker
27
7
15
{my $s = <<'END';
28
sub XXX {&fieldValues("XXX")}
29
END
30
7
42
$s =~ s(XXX) ($field)gs;
31
7
0
0
331
eval $s;
0
1
0
0
1
1
0
6
1
1
0
5
1
1
0
7
1
0
0
4
0
1
0
0
1
7
32
7
50
1344
$@ and confess $@;
33
}
34
}
35
36
sub fieldValues($) # All the values a specified field can take
37
5
5
0
14
{my ($field) = @_;
38
5
10
my %l;
39
5
8
my @s = @{&speakerDetails};
5
10
40
5
19
for my $speaker(@s)
41
260
50
449
{if (my $v = $speaker->{$field})
42
260
431
{$l{$v}++
43
}
44
}
45
5
321
sort keys %l;
46
}
47
48
#-------------------------------------------------------------------------------
49
# Select speakers
50
#-------------------------------------------------------------------------------
51
52
sub speaker(@) # Select speakers by fields
53
5
5
0
13
{my (%selection) = @_; # Selection fields: name=>"regular expression" where the field of that name must match the regular expression regardless of case
54
5
10
my @s;
55
5
7
for my $speaker(@{&speakerDetails}) # Check each speaker
5
5
56
260
268
{my $m = 1; # Speaker matches so far
57
260
344
for my $field(keys %selection) # Continue with the speaker as long as they match on all the supplied fields - these fields are our shorter simpler names not AWS's longer more complicated names
58
458
100
605
{last unless $m;
59
342
356
my $r = $selection{$field}; # Regular expression to match
60
342
359
my $v = $speaker->{$field}; # Value of this field for this speaker
61
342
50
425
confess "No such field: $field" unless $v;
62
342
690
$m = $v =~ m/$r/; # Case insensitive
63
}
64
260
100
423
push @s, $speaker if $m; # Exclude potential speaker unless they match all valid fields
65
}
66
5
129
sort {$a->Id cmp $b->Id} @s
52
933
67
}
68
69
#-------------------------------------------------------------------------------
70
# Blessed speaker details
71
#-------------------------------------------------------------------------------
72
73
sub speakerDetails
74
12
12
0
22
{my $s = &speakerDetailsFromAWS;
75
12
35
for(@$s)
76
{package Aws::Polly::Select::Speaker;
77
624
12259
bless $_;
78
624
8555
($_->Written) = split /-/, $_->LanguageCode; # Add written code
79
}
80
$s
81
12
279
}
82
83
#-------------------------------------------------------------------------------
84
# Speaker ids as a hash
85
#-------------------------------------------------------------------------------
86
87
sub speakerIds
88
2
2
1
5
{my $s = speakerDetails;
89
2
3
+{map{$_->Id => $_} @$s}
104
1582
90
}
91
92
#-------------------------------------------------------------------------------
93
# Speaker details from AWS via:
94
# renewSpeakerDetailsButOnlyWhenAWSChangesTheListOfSpeakers()
95
#-------------------------------------------------------------------------------
96
97
sub speakerDetailsFromAWS
98
{[
99
12
12
0
835
{ Gender => "Female",
100
Id => "Gwyneth",
101
LanguageCode => "cy-GB",
102
LanguageName => "Welsh",
103
Name => "Gwyneth",
104
},
105
{
106
Gender => "Female",
107
Id => "Naja",
108
LanguageCode => "da-DK",
109
LanguageName => "Danish",
110
Name => "Naja",
111
},
112
{
113
Gender => "Male",
114
Id => "Mads",
115
LanguageCode => "da-DK",
116
LanguageName => "Danish",
117
Name => "Mads",
118
},
119
{
120
Gender => "Female",
121
Id => "Vicki",
122
LanguageCode => "de-DE",
123
LanguageName => "German",
124
Name => "Vicki",
125
},
126
{
127
Gender => "Female",
128
Id => "Marlene",
129
LanguageCode => "de-DE",
130
LanguageName => "German",
131
Name => "Marlene",
132
},
133
{
134
Gender => "Male",
135
Id => "Hans",
136
LanguageCode => "de-DE",
137
LanguageName => "German",
138
Name => "Hans",
139
},
140
{
141
Gender => "Male",
142
Id => "Russell",
143
LanguageCode => "en-AU",
144
LanguageName => "Australian English",
145
Name => "Russell",
146
},
147
{
148
Gender => "Female",
149
Id => "Nicole",
150
LanguageCode => "en-AU",
151
LanguageName => "Australian English",
152
Name => "Nicole",
153
},
154
{
155
Gender => "Female",
156
Id => "Emma",
157
LanguageCode => "en-GB",
158
LanguageName => "British English",
159
Name => "Emma",
160
},
161
{
162
Gender => "Male",
163
Id => "Brian",
164
LanguageCode => "en-GB",
165
LanguageName => "British English",
166
Name => "Brian",
167
},
168
{
169
Gender => "Female",
170
Id => "Amy",
171
LanguageCode => "en-GB",
172
LanguageName => "British English",
173
Name => "Amy",
174
},
175
{
176
Gender => "Male",
177
Id => "Geraint",
178
LanguageCode => "en-GB-WLS",
179
LanguageName => "Welsh English",
180
Name => "Geraint",
181
},
182
{
183
Gender => "Female",
184
Id => "Aditi",
185
LanguageCode => "en-IN",
186
LanguageName => "Indian English",
187
Name => "Aditi",
188
},
189
{
190
Gender => "Female",
191
Id => "Raveena",
192
LanguageCode => "en-IN",
193
LanguageName => "Indian English",
194
Name => "Raveena",
195
},
196
{
197
Gender => "Female",
198
Id => "Joanna",
199
LanguageCode => "en-US",
200
LanguageName => "US English",
201
Name => "Joanna",
202
},
203
{
204
Gender => "Female",
205
Id => "Salli",
206
LanguageCode => "en-US",
207
LanguageName => "US English",
208
Name => "Salli",
209
},
210
{
211
Gender => "Male",
212
Id => "Matthew",
213
LanguageCode => "en-US",
214
LanguageName => "US English",
215
Name => "Matthew",
216
},
217
{
218
Gender => "Female",
219
Id => "Kimberly",
220
LanguageCode => "en-US",
221
LanguageName => "US English",
222
Name => "Kimberly",
223
},
224
{
225
Gender => "Female",
226
Id => "Kendra",
227
LanguageCode => "en-US",
228
LanguageName => "US English",
229
Name => "Kendra",
230
},
231
{
232
Gender => "Male",
233
Id => "Justin",
234
LanguageCode => "en-US",
235
LanguageName => "US English",
236
Name => "Justin",
237
},
238
{
239
Gender => "Male",
240
Id => "Joey",
241
LanguageCode => "en-US",
242
LanguageName => "US English",
243
Name => "Joey",
244
},
245
{
246
Gender => "Female",
247
Id => "Ivy",
248
LanguageCode => "en-US",
249
LanguageName => "US English",
250
Name => "Ivy",
251
},
252
{
253
Gender => "Male",
254
Id => "Enrique",
255
LanguageCode => "es-ES",
256
LanguageName => "Castilian Spanish",
257
Name => "Enrique",
258
},
259
{
260
Gender => "Female",
261
Id => "Conchita",
262
LanguageCode => "es-ES",
263
LanguageName => "Castilian Spanish",
264
Name => "Conchita",
265
},
266
{
267
Gender => "Female",
268
Id => "Penelope",
269
LanguageCode => "es-US",
270
LanguageName => "US Spanish",
271
Name => "Penélope,",
272
},
273
{
274
Gender => "Male",
275
Id => "Miguel",
276
LanguageCode => "es-US",
277
LanguageName => "US Spanish",
278
Name => "Miguel",
279
},
280
{
281
Gender => "Female",
282
Id => "Chantal",
283
LanguageCode => "fr-CA",
284
LanguageName => "Canadian French",
285
Name => "Chantal",
286
},
287
{
288
Gender => "Male",
289
Id => "Mathieu",
290
LanguageCode => "fr-FR",
291
LanguageName => "French",
292
Name => "Mathieu",
293
},
294
{
295
Gender => "Female",
296
Id => "Celine",
297
LanguageCode => "fr-FR",
298
LanguageName => "French",
299
Name => "Céline",
300
},
301
{
302
Gender => "Male",
303
Id => "Karl",
304
LanguageCode => "is-IS",
305
LanguageName => "Icelandic",
306
Name => "Karl",
307
},
308
{
309
Gender => "Female",
310
Id => "Dora",
311
LanguageCode => "is-IS",
312
LanguageName => "Icelandic",
313
Name => "Dóra",
314
},
315
{
316
Gender => "Male",
317
Id => "Giorgio",
318
LanguageCode => "it-IT",
319
LanguageName => "Italian",
320
Name => "Giorgio",
321
},
322
{
323
Gender => "Female",
324
Id => "Carla",
325
LanguageCode => "it-IT",
326
LanguageName => "Italian",
327
Name => "Carla",
328
},
329
{
330
Gender => "Male",
331
Id => "Takumi",
332
LanguageCode => "ja-JP",
333
LanguageName => "Japanese",
334
Name => "Takumi",
335
},
336
{
337
Gender => "Female",
338
Id => "Mizuki",
339
LanguageCode => "ja-JP",
340
LanguageName => "Japanese",
341
Name => "Mizuki",
342
},
343
{
344
Gender => "Female",
345
Id => "Seoyeon",
346
LanguageCode => "ko-KR",
347
LanguageName => "Korean",
348
Name => "Seoyeon",
349
},
350
{
351
Gender => "Female",
352
Id => "Liv",
353
LanguageCode => "nb-NO",
354
LanguageName => "Norwegian",
355
Name => "Liv",
356
},
357
{
358
Gender => "Male",
359
Id => "Ruben",
360
LanguageCode => "nl-NL",
361
LanguageName => "Dutch",
362
Name => "Ruben",
363
},
364
{
365
Gender => "Female",
366
Id => "Lotte",
367
LanguageCode => "nl-NL",
368
LanguageName => "Dutch",
369
Name => "Lotte",
370
},
371
{
372
Gender => "Female",
373
Id => "Maja",
374
LanguageCode => "pl-PL",
375
LanguageName => "Polish",
376
Name => "Maja",
377
},
378
{
379
Gender => "Male",
380
Id => "Jan",
381
LanguageCode => "pl-PL",
382
LanguageName => "Polish",
383
Name => "Jan",
384
},
385
{
386
Gender => "Female",
387
Id => "Ewa",
388
LanguageCode => "pl-PL",
389
LanguageName => "Polish",
390
Name => "Ewa",
391
},
392
{
393
Gender => "Male",
394
Id => "Jacek",
395
LanguageCode => "pl-PL",
396
LanguageName => "Polish",
397
Name => "Jacek",
398
},
399
{
400
Gender => "Female",
401
Id => "Vitoria",
402
LanguageCode => "pt-BR",
403
LanguageName => "Brazilian Portuguese",
404
Name => "Vitória",
405
},
406
{
407
Gender => "Male",
408
Id => "Ricardo",
409
LanguageCode => "pt-BR",
410
LanguageName => "Brazilian Portuguese",
411
Name => "Ricardo",
412
},
413
{
414
Gender => "Female",
415
Id => "Ines",
416
LanguageCode => "pt-PT",
417
LanguageName => "Portuguese",
418
Name => "Inês",
419
},
420
{
421
Gender => "Male",
422
Id => "Cristiano",
423
LanguageCode => "pt-PT",
424
LanguageName => "Portuguese",
425
Name => "Cristiano",
426
},
427
{
428
Gender => "Female",
429
Id => "Carmen",
430
LanguageCode => "ro-RO",
431
LanguageName => "Romanian",
432
Name => "Carmen",
433
},
434
{
435
Gender => "Female",
436
Id => "Tatyana",
437
LanguageCode => "ru-RU",
438
LanguageName => "Russian",
439
Name => "Tatyana",
440
},
441
{
442
Gender => "Male",
443
Id => "Maxim",
444
LanguageCode => "ru-RU",
445
LanguageName => "Russian",
446
Name => "Maxim",
447
},
448
{
449
Gender => "Female",
450
Id => "Astrid",
451
LanguageCode => "sv-SE",
452
LanguageName => "Swedish",
453
Name => "Astrid",
454
},
455
{
456
Gender => "Female",
457
Id => "Filiz",
458
LanguageCode => "tr-TR",
459
LanguageName => "Turkish",
460
Name => "Filiz",
461
},
462
];
463
}
464
465
#-------------------------------------------------------------------------------
466
# Test
467
#-------------------------------------------------------------------------------
468
469
sub test
470
1
50
1
0
514
{eval join('', ) || die $@
1
1
53139
1
7
1
187
471
}
472
473
test unless caller();
474
475
# Documentation
476
#extractDocumentation unless caller;
477
478
#-------------------------------------------------------------------------------
479
# Export
480
#-------------------------------------------------------------------------------
481
482
require Exporter;
483
484
1
1
6
use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
1
2
1
105
485
486
@ISA = qw(Exporter);
487
@EXPORT = qw();
488
@EXPORT_OK = qw();
489
%EXPORT_TAGS = (all=>[@EXPORT, @EXPORT_OK]);
490
491
1;
492
493
=pod
494
495
=encoding utf-8
496
497
=head1 Name
498
499
Aws::Polly::Select - Select AWS Polly speakers with specified characteristics
500
501
=head1 Synopsis
502
503
use Aws::Polly::Select;
504
505
my ($speaker) = Aws::Polly::Select::speaker
506
LanguageCode => qr(us)i,
507
Gender => qr(female)i,
508
LanguageName => qr(Spanish)i;
509
510
ok $speaker->Id eq q(Penelope);
511
512
=head1 Description
513
514
Aws::Polly::Select::speaker(key=>qr(value), ...)
515
516
Returns zero or more Amazon Web Services Polly speaker definitions which match
517
the hash of characteristics provided. Each hash B must name one of the
518
Bs given below, the value for the key should be a regular expression to
519
select against the possible B listed beside each key. Please take care
520
with the case of the values or use B to make the selection case
521
insensitive.
522
523
KEY VALUES
524
525
Gender Female Male
526
527
Id Aditi Amy Astrid Brian Carla Carmen Celine Chantal Conchita
528
Cristiano Dora Emma Enrique Ewa Filiz Geraint Giorgio Gwyneth Hans Ines Ivy
529
Jacek Jan Joanna Joey Justin Karl Kendra Kimberly Liv Lotte Mads Maja Marlene
530
Mathieu Matthew Maxim Miguel Mizuki Naja Nicole Penelope Raveena Ricardo Ruben
531
Russell Salli Seoyeon Takumi Tatyana Vicki Vitoria
532
533
LanguageCode cy-GB da-DK de-DE en-AU en-GB en-GB-WLS en-IN en-US es-ES es-US
534
fr-CA fr-FR is-IS it-IT ja-JP ko-KR nb-NO nl-NL pl-PL pt-BR pt-PT ro-RO ru-RU
535
sv-SE tr-TR
536
537
LanguageName Australian English Brazilian Portuguese British English Canadian
538
French Castilian Spanish Danish Dutch French German Icelandic Indian English
539
Italian Japanese Korean Norwegian Polish Portuguese Romanian Russian Swedish
540
Turkish US English US Spanish Welsh Welsh English
541
542
Written cy da de en es fr is it ja ko nb nl pl pt ro ru sv tr
543
544
The above Bs can be used as methods to get the corresponding B's
545
from each speaker defintion returned by L.
546
547
ok $speaker->LanguageCode eq q(es-US);
548
549
=head2 speakerIds()
550
551
Use speakerIds() to get a hash of speaker details by speaker id:
552
553
my $speaker = Aws::Polly::Select::speakerIds->{Vicki};
554
555
is_deeply $speaker,
556
{Gender => "Female",
557
Id => "Vicki",
558
LanguageCode => "de-DE",
559
LanguageName => "German",
560
Name => "Vicki",
561
Written => "de",
562
};
563
564
Each of the fields describing a speaker may be accessed as a method, for example:
565
566
ok $speaker->Gender eq "Female";
567
ok $speaker->LanguageName eq "German";
568
ok $speaker->Written eq "de";
569
570
=head1 Installation
571
572
Standard Module::Build process for building and installing modules:
573
574
perl Build.PL
575
./Build
576
./Build test
577
./Build install
578
579
=head1 Author
580
581
philiprbrenan@gmail.com
582
583
http://www.appaapps.com
584
585
=head1 Copyright
586
587
Copyright (c) 2017 Philip R Brenan.
588
589
This module is free software. It may be used, redistributed and/or modified
590
under the same terms as Perl itself.
591
592
=cut
593
594
__DATA__