Cercando software di sintesi vocale alternativi a Festival, ci siamo imbattuti in Swift, un prodotto commerciale della Cepstral software, ma abbordabile (29$), in grado di sintetizzare del testo in modo abbastanza comprensibile e con una voce per niente male.
E’ in grado di dare senso ad una frase, rispettando ed enfatizzando la punteggiatura, se volete provare una demo on line, vi presento vittoria
e’ anche disponibile per il download un trial, che non fa altro che anteporre ad ogni vostra frase il testo “Questa voce non ha una licenza“.
Swift è un tool a riga di comando, perciò facilmente integrabile con Asterisk con qualche semplice agi.
Di recente è stato aperto un Bounty per creare uno script in grado di leggere le email di una persona via telefono, con swift, ma anche con asterisk la cosa e’ molto semplice, eccovi un esempio scritto in perl.
[perl]
#!/usr/bin/perl
#AGI Script that reads back e-mail from an IMAP account.
#Requires the Asterisk::AGI Net::IMAP::Simple, and Email::Simple modules.
#Written by: Black Rathchet (blackratchet@blackratchet.org)
#http://www.oldskoolphreak.com
use Net::IMAP::Simple;
use Email::Simple;
use Asterisk::AGI;
use File::Basename;
use Digest::MD5 qw(md5_hex);
my $server = ‘localhost’; #INSERT YOUR SERVER HERE
my $username = ‘mailuser’; #INSERT YOUR USERNAME HERE
my $password = ‘password’; #INSERT YOUR PASSWORD HERE
sub speak(){
$text = $_[0];
my $hash = md5_hex($text);
my $ttsdir = “/var/lib/asterisk/sounds/tts”;
my $cepoptions = “-p audio/sampling-rate=8000,audio/channels=1″;
my $wavefile = “$ttsdir/tts-$hash.wav”;
unless (-f $wavefile) {
open(fileOUT, “>/var/lib/asterisk/sounds/tts/say-text-$hash.txt”);
print fileOUT “$text”;
close(fileOUT);
my $execf=”/opt/swift/bin/swift -f $ttsdir/say-text-$hash.txt -o $wavefile $cepoptions”;
system($execf);
unlink(”$ttsdir/say-text-$hash.txt”);
}
$filename = ‘tts/’.basename(’tts/’.basename($wavefile,”.wav”));
$AGI->stream_file($filename);
unlink(”$wavefile”);
}
$AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
# Create the object
my $imap = Net::IMAP::Simple->new($server) ||
die “Unable to connect to IMAP: $Net::IMAP::Simple::errstr\n”;
# Log on
if(!$imap->login($username,$password)){
&speak(”Login failed: ” . $imap->errstr . “\n”);
exit(64);
}
# Print the subject’s of all the messages in the INBOX
my $nm = $imap->select(’INBOX’);
$AGI->stream_file(’vm-youhave’);
$AGI->say_number($nm);
#$AGI->stream_file(’vm-INBOX’);
$AGI->stream_file(’vm-messages’);
for(my $i = 1; $i <= $nm; $i++){
my $es = Email::Simple->new(join ”, @{ $imap->top($i) } );
$AGI->stream_file(’vm-message’);
$AGI->say_number($i);
&speak($es->header(’Subject’));
$AGI->stream_file(’vm-from’);
&speak($es->header(’From’));
&speak(”1, Play, 2, Next, Pound, Exit”);
}
$imap->quit;
[/perl]
Come avrete notato il tutto si riduce a queste due righe di codice…
[perl]
my $execf=”/opt/swift/bin/swift -f $ttsdir/say-text-$hash.txt -o $wavefile $cepoptions”;
system($execf);
[/perl]
… piu facile di cosi!!!
Un altro simpatico esempio a scopo didattico effettua una scansione di un ip inputato dalla tastiera del telefono con nmap e ne legge l’output (consiglio di utilizzare la voce inglese per questo, il risultato e’ piu carino).
[perl]
#!/usr/bin/perl
#
# AGI Script that prompts the user for an ip address, scans the ip, and reports back to the user.
#
# Requires the Asterisk::AGI and Nmap::Parser perl modules
#
# Written by: Black Rathchet (blackratchet@blackratchet.org)
use Asterisk::AGI;
use Nmap::Parser;
use File::Basename;
use Digest::MD5 qw(md5_hex);
# speaks a string of text
sub speak(){
$text = $_[0];
my $hash = md5_hex($text);
my $ttsdir = “/var/lib/asterisk/sounds/tts”;
my $cepoptions = “-p audio/sampling-rate=8000,audio/channels=1″;
my $wavefile = “$ttsdir/tts-$hash.wav”;
unless (-f $wavefile) {
open(fileOUT, “>/var/lib/asterisk/sounds/tts/say-text-$hash.txt”);
print fileOUT “$text”;
close(fileOUT);
my $execf=”/opt/swift/bin/swift -f $ttsdir/say-text-$hash.txt -o $wavefile $cepoptions”;
system($execf);
unlink(”$ttsdir/say-text-$hash.txt”);
}
$filename = ‘tts/’.basename(’tts/’.basename($wavefile,”.wav”));
$AGI->stream_file($filename);
unlink(”$wavefile”);
}
$AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
my $finished = 0;
&speak(”Enter the eye-p address you wish to scan.”);
my $ipaddr = ”;
my $x = 0;
# While we don’t have a complete IP address, have the user enter one
# using ‘#’ for ‘.’…
while (!$finished) {
my $input = chr($AGI->wait_for_digit(’5000′));
if ($input =~ /^[0-9\*\#]$/) {
if ($input =~ /^[\*\#]$/) {
$x++;
if ($x > 3) {
$finished = 1;
} else {
$ipaddr .= ‘.’;
}
} else {
$ipaddr .= $input;
}
} else {
#must have timed out
$finished = 1;
}
if ( length($ipaddr) > 14) {
$finished = 1;
}
}
# Double check the address is valid…
if ($ipaddr !~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) {
&speak(”Invalid Address: $ipaddr”);
exit 0;
}
&speak(”Oh ratchet… you know how to push my buttons…”);
&speak(”Please wait”);
# Set up a new Nmap::Parser object
my $np = new Nmap::Parser;
$nmap_exe = ‘/usr/bin/nmap’;
$np->callback(\&host_handler);
# Scan the host given.
$np->parsescan($nmap_exe,’-sT -p1-1023′, $ipaddr);
# Do this after every host scanned
sub host_handler {
my $host_obj = shift; #an instance of Nmap::Parser::Host (for current)
&speak(”Host Found with ” . $host_obj->tcp_port_count() . ” ports open”);
# Make and array of all the ports.
my @ports = $host_obj->tcp_open_ports();
# For every port, speak the port number and service.
foreach $port (@ports){
&speak($host_obj->tcp_service($port)->name. ” on port” . $port);
}
&speak(”Scan complete… Thank you…”);
exit;
}
# If a host was found, we shouldn’t get here.
$AGI->exec(’Festival’, ‘”No host found”‘);
exit;
[/perl]
This post has no comment.