Google Speech + Python + Asterisk
Olá Povo que acompanha o blog 🙂
Ainda falando sobre reconhecimento da fala utilizando o google, enviei uma mensagem na lista AsteriskBrasil onde expressava minhas idéias de como utilizar o serviço de reconhecimento de fala do google em tempo real com o Asterisk, já se passou quase uma semana sem se quer um suspiro de interesse, então resolvi seguir sozinho !
A idéia é utilizar EAGI para controle do canal de entrada de áudio em conjunto com o File Descriptor, o Asterisk entrega o áudio em formato RAW diretamente no File Descriptor 3, então podemos utilizar esta informação da maneira que acharmos conveniente, para este caso a manipulação se torna muito prática, o que me desprende totalmente das APP’s prontas para gravações inseridas no Asterisk Ex. Record, nada melhor do que ser livre para voar, é claro várias análises se tornam possíveis com isso e o leque de aplicações possíveis se tornam infinitas.
Você certamente já pensou em ter um PABX com funcionalidade para reconhecimento da fala então certamente irá precisar partir para soluções cooporativas e caras certo???
A Partir de hoje não !
Tudo que irá precisar é ter internet para acessar o google o Script possue algumas dependencias:
https://github.com/ederwander/Asterisk-Google-Speech-Recognition/blob/master/README
Estou usando novamente o módulo audiolab para efetuar o encode do áudio em FLAC, caso exista alguma dificuldade para a instalação deste módulo poderei pensar em adaptar o código para uso externo do sox ou flac.
Como ele funciona?
- Atende uma ligação
- O usuário tem no máximo 10 segundos para efetuar a fala
- Caso nao encontre atividade de voz encerra com timeout
- Estratégia para atividade de voz verdadeira para os seguintes valores RMS > 15 e Pitch > 75
- Se atividade for encontrada o usuário poderá falar por no máximo 10 segundos
- O script verifica blocos em tempo real com amostras de 1 em 1 segundo e verifica se a fala cessou
- Caso sim o script interrompe a gravação automáticamente e envia o que foi gravado para o google
- Caso não o script continua o seu curso até seu máximo de 10 segundos
- Apos encontrada a resposta da fala no google o script seta a variável “GoogleUtterance”
Telas:
Source em:
https://github.com/ederwander/Asterisk-Google-Speech-Recognition
AGI Portabilidade para números móveis em Asterisk
Postei estes dias um source em python para descobrir a portabilidade de números móveis na comunidade Asterisk e meu email começou a lotar sobre perguntas de como construir um AGI para rotear as chamadas por um gateway GSM etc etc.
Cada um tem um cenário diferente do outro vou postar a essencia do Script em Perl + Agi para descobrir para qual operadora um número móvel pertence a partir disso é simples, mas se precisarem de ajuda para algo estamos ae …
Já tem nego me Perguntado pq nao fez em Python o AGI??
R: Acordei com vontade de fazer em perl …
Script Perl
#!/usr/bin/perl -w
use Asterisk::AGI;
use WWW::Mechanize;
use MIME::Base64;
my $AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
my @operadoras = (“Eder”, “Claro”, “Tim”, “Vivo”, “Telemig”, “Oi”, “Nextel”, “Brasil telecom”, “Sercomtel”, “CTBC”);
my $num_saida = $AGI->get_variable(‘EXTEN’);
$num_saida = substr($num_saida,3,10);
$m = WWW::Mechanize->new();
my $data = decode_base64(‘aHR0cDovL3dlYnNlcnZpY2VzLnR3d3dpcmVsZXNzLmNvbS5ici9yZWx1emNhcC93c3JlbHV6Y2FwL’ . ‘mFzbXg=’);
$m->add_header(Referer => $data);
my $s = $data . “/VerOperadora?celular=55” . $num_saida;
$m->get($s);
$c = $m->content;
$c =~ m/>(\d+)</;
$AGI->exec(“NoOp”,”$num_saida”);
$AGI->exec(“NoOp”,”$operadoras[$1]”);
# O codigo se adapta conforme o cenario de cada um, mudar o DIAL para rotear a saida da operadora em questao
####$AGI->exec(“Dial”,”SIP/MUDE AQUI PARA SUA SAIDA SIP ou GSM ou ZAP ou DAHDI ou UNICALL ou DVG etc etc|10″);
# FIM
Extensions.conf
minha linha para a chamada do AGI de testes
exten => _999.,1,agi,pega.pl
ou seja só discar no seu telefoneIP ou sftphone “999+num_do_celular”
Tela:
UPDATE:
12/03/2014
É incrível a quantidade de emails que recebo pedindo para encontrar meios de mostrar números portados, hoje eu tive um tempinho e escrevi um novo código, se olharem no código vão perceber que eu inclui um proxy para enviar as requisições, o site é bem “esperto” e bloqueia todo o range de IP de sua rede pública se ocorrer muitos requests, (descobri isso da pior maneira enquanto debugava o site), então vocês podem criar uma lista randômica com vários IPs que tenham proxy aberto para enviar as solicitações, código em https://gist.github.com/ederwander/9512693 !
Fui
Eng Eder de Souza
Monitor Realtime + Asterisk
Bom só quem brincou com AMI no Asterisk sabe como é complicado, Eventos jogados na tela nada parece ter sentido uma avalanche de informações sem padrões definidos, construir aplicações genéricas se torna uma missão.
Eu iniciei a pouco mais de dois anos um projeto monitor em Realtime a principio era para monitoramento só para verificar quem estava fazendo ou recebendo ligações, pensei “Moleza Delphi + Socket + AMI”.
Dores e mais dores de cabeça na época tinha um link R2 com uma placa da digium rodando com o Unicall para quem tinha placa E1 Digium era a única saida de conversar com a sinalização R2. Então olhando o retorno do AMI iniciei um esboço de como pegar o retorno no buffer do meu Socket em Delphi 6.0 e montar algo bonitinho para usuários ficarem vendo tudo que acontece de atividade no canal Unicall do Asterisk !!
Então vamos ver o que um core show channels verbose nos retorna !!
Channel Context Extension Prio State Application Data CallerID Duration Accountcode BridgedTo
UniCall/16-1 default 1579 1 Up Bridged Call SIP/6007-00f839c0 80151333623971 SIP/6007-00f839c0
SIP/6007-00f839c0 default 80151333623971 22 Up Dial Unicall/g1/0151333623971 6007 00:02:40 UniCall/16-1
UniCall/14-1 default 1599 1 Up Bridged Call SIP/6004-00d2fe00 80151938622970 SIP/6004-00d2fe00
SIP/6004-00d2fe00 default 80151938622970 22 Up Dial Unicall/g1/0151938622970 6004 00:03:52 UniCall/14-1
UniCall/11-1 default 1599 1 Up Bridged Call SIP/6006-00ea6650 80151335689403 SIP/6006-00ea6650
SIP/6006-00ea6650 default 80151335689403 22 Up Dial Unicall/g1/0151335689403 6006 00:05:18 UniCall/11-1
SIP/6008-00e46a10 default 1 Up Bridged Call UniCall/12-1 1938323241 UniCall/12-1
UniCall/12-1 default 91000 3 Up Queue atendimento|r|||90 1938323241 00:06:10 SIP/6008-00e46a10
UniCall/10-1 default 1599 1 Up Bridged Call SIP/6002-00f034c0 881895124 SIP/6002-00f034c0
SIP/6002-00f034c0 default 881895124 22 Up Dial Unicall/g1/81895124 6002 00:06:37 UniCall/10-1
UniCall/13-1 default 1599 1 Up Bridged Call SIP/6005-00f15800 808007771007 SIP/6005-00f15800
SIP/6005-00f15800 default 808007771007 22 Up Dial Unicall/g1/08007771007 6005 00:09:02 UniCall/13-1
12 active channels
6 active calls
Bagunça !!!!
Então a idéia seria filtrar essa bagunça e procurar por palavras chaves Criando uma funçao Busca para isso !!
Function BuscaTexto(Text,Busca : string) : string;
var n : integer;
begin
for n := 1 to length(Text) do
begin
if Copy(Text,n,length(Busca)) = Busca then
begin
Result := ‘ok’;
RetornoBuscaPos:=n;
end;
end;
end;
Agora eu poderia pegar dentro do Buffer do socket qualquer palavra chave como a “Unicall/g1” e depois caminhar com um ponteiro para recortar isso em qualquer lugar e depois só teria que colocar o valor no GRID.
Entao como ficaria:
if BuscaTexto(Msg,’Unicall/g1/’) = ‘ok’ then
begin
if Copy(Msg,86,RetornoBuscaPos-79) = ‘Unicall’ then
//pega o ramal que originou a chamada
MainForm.StringGrid1.Cells[0,contador]:= Copy(Msg,5,RetornoBuscaPos-82);
//pega o numero discado para fora destino ‘ ‘Unicall/g1/’
MainForm.StringGrid1.Cells[1,contador]:= Copy(Msg,97,RetornoBuscaPos-71);
Extremamente Trabalhoso Marinheiro de Primeira viagem um colega de cuiaba o Juniou tbm embarcou nessa aventura ele mal dormia, por fim segue algumas telas depois de todo o trabalho …
Tela com opção de verificar chamadas recebidas
Assim tudo em AMI eu teria o retorno de 5 em 5 segundos do comando “core show channels verbose” na qual montaria a tela de ligações em um intervalo de 5 em 5 segundos….
Até a Proxima
Eng Eder de Souza