interface de voz con rails
Post on 25-May-2015
2.292 Views
Preview:
TRANSCRIPT
RoR puede también hablar: Interface de voz con Rails
Svet Ivantchev, eFabersvet@efaber.net
22 de noviembre de 2007, ConferenciaRails 2007, Madrid
¿Qué es VoIP?
Ejemplos
... y 1000s más
¿Es por dinero?
• Ok, las llamadas VoIP son baratas pero no eso es importante
• Flexibilidad y integración con aplicaciones
Demo
• Consulta de notas por web
• Consulta de notas por teléfono
La voz es una interface más
¿Por qué ahora?
• Web stack (ej: SO, BD, RoR :-))
• VoIP (ej: Asterisk)
• Ancho de banda
• Los IVR dejan mucho que desear
Asterisk (conceptos)
• Centralita Open Source (PBX)
• Protocolos: SIP, IAX
• Proveedores
http://asterisk.org
ComponentesClientes VoIP
Terminación
DID
Red PSTN
SIP, IAX
ZAP
SIP, IAX
SIP, IAX
Asterisk (instalación)compilamos:
$ wget http://downloads.digium.com/pub/ asterisk/releases/asterisk-1.4.13.tar.gz $ tar zxvf asterisk-1.4.13.tar.gz $ cd asterisk-1.4.13 $ ./configure $ make menuselect $ make $ sudo make install $ sudo make samples
comprobamos:
$ sudo asterisk -vvvvvc
voces en castellano: http://www.voipnovatos.es
Asterisk (config)
[pb15]context=demo1type=friendsecret=sekreto42host=dynamiccanreinvite=no
[spa941]context=demo1type=friendsecret=otrapasswhost=dynamiccanreinvite=no
en /etc/asterisk/sip.conf
en /etc/asterisk/extensions.conf
[demo1]
exten => 101,1,Dial(SIP/pb15)
exten => 102,1,Dial(SIP/spa941)
Cliente softphone
Cliente hardware
Números públicos
DID y SIP URI
Demo
• Llamada entre dos números
• Con el número público
Ideas
• Respuesta diferente por horas
• Respuesta diferente en función del CallerID
• Integración con Jabber
• Voicemail
• IVR, colas
• 1000s de cosas mas ...
El dialplan se complica[efmenu]
include => users5xx
include => roomsinclude => efhq
exten => s,1,NoOp(Entering eF main menu for caller ${CALLERID})exten => s,2,Answer
exten => s,3,Wait(2)
exten => s,4,Playback(beep)exten => s,5,Background(${SALUDOEN}enter-ext-of-person)
exten => s,6,Background(beep)exten => s,7,WaitExten(15)
exten => 101,1,Playback(room-service)
exten => 101,2,Goto(efmenu,s,4)exten => 999,1,Goto(svetdisa,s,1)
exten => 999,2,Goto(efmenu,s,4)exten => i,1,Playback(pbx-invalid)
exten => i,2,Goto(efmenu,s,6)
exten => t,1,Playback(vm-goodbye)exten => t,2,Hangup()
...y se hace feoexten => 508,1,Macro(voicemail,SIP/esti)
exten => 509,1,Macro(voicemail,SIP/kolio)
exten => 510,1,Macro(voicemail,SIP/jean)exten => 511,1,Macro(voicemail,SIP/ruben)
exten => 512,1,Macro(voicemail,SIP/inaki)
[macro-voicemail]exten => s,1,Dial(${ARG1},30)
exten => s,2,Goto(s-${DIALSTATUS},1)exten => s-NOANSWER,1,Voicemail(u${MACRO_EXTEN})
exten => s-NOANSWER,n,Hangup()
exten => s-CHANUNAVAIL,1,Playback(unavailable)exten => s-CHANUNAVAIL,n,Hangup()
exten => s-CONGESTION,1,Busy(5)exten => s-CONGESTION,n,Hangup()
exten => s-BUSY,1,Voicemail(b${MACRO_EXTEN})
exten => s-BUSY,n,Hangup()exten => _s-.,1,Goto(s-NOANSWER,1)
AGI y AMI
• Asterisk Gateway Interface
• Asterisk Manager Interface
Alternativas
• Adhearsion
• Telegraph
Adhearsion
• El dialplan escrito en Ruby
• ActiveRecord integrado
• Integración con Rails
• versiones (0.7.7 vs 0.8)
http://adhearsion.com
Adhearsion 1: Hello World
$ sudo gem install adhearsion
$ ahn create hello1
Creating /Users/svet/hello1/config/adhearsion.sqlite3Creating /Users/svet/hello1/config/adhearsion.yml
Creating /Users/svet/hello1/config/database.rbCreating /Users/svet/hello1/config/database.yml
Creating /Users/svet/hello1/config/helpers/drb_server.yml
Creating /Users/svet/hello1/config/helpers/factorial.alien.c.ymlCreating /Users/svet/hello1/config/helpers/growler.yml
Creating /Users/svet/hello1/config/helpers/lookup.ymlCreating /Users/svet/hello1/config/helpers/manager_proxy.yml
Creating /Users/svet/hello1/config/helpers/micromenus/collab.rb
...
Hello World
en /etc/asterisk/extensions.conf
[adhearsion] exten => 101,1,AGI(agi://127.0.0.1)
$ cd hello1
en extensions.rb
dhearsion {
play 'hello-word' }
$ ahn start .
internal {
case extension
when 101...200 employee = User.find_by_extension extension
if employee.busy? then voicemail extension else
dial employee, :for => 10.rings
voicemail unless last_call_successful? end
when 888 play weather_report("Dallas Texas")
when 999 then +joker_voicemail
end}
Adhearsion II: Amazon
require 'amazon/search'
r = Amazon::Search::Request.new( '10N1KX1NVQZ2VXXXXXXX')
begin resp = r.keyword_search( '0596529260', 'books' ) resp.products.each do |p| unless p.availability =~ /not available/ printf( "%s (ASIN %s) -- %s\n", p.product_name, p.asin, p.our_price ) end endrescue puts "No se encuentra."end
$ ruby price2 RESTful Web Services (ASIN 0596529260) -- $26.39
Adhearsion II: Amazonadhearsion { require 'amazon/search' r = Amazon::Search::Request.new( '10N1KX1NVQZ2VXXXXXXX') begin resp = r.keyword_search( extension, 'books' ) resp.products.each do |p| unless p.availability =~ /not available/ play p.our_price end end rescue play "no-info-about-number" end}
voxbone { sleep 2.seconds play "hello-world" isbn = input() require 'amazon/search' r = Amazon::Search::Request.new( '10N1KX1NVQZ2VXXXXXXX') begin resp = r.keyword_search( isbn, 'books' ) resp.products.each do |p| unless p.availability =~ /not available/ play p.our_price end end rescue play "no-info-about-number" end}
Telegraph
• MVC
• respond_to
http://telegraph.rubyforge.org
Telegraph y AGI
exten => 105, 1, AGI(agi://127.0.0.1/my_route?param1=value)
wants.voice do render_voice do |voice| voice.play “hello-world” voice.link_to_dtmf 'bank-lineitem-menu' do link 1, :action=>"new" link 2, :action=>"list" link 3, :action=>"index" end end end
Demo
def show_notas
@alumno = Alumno.find_by_dni(params[:dni])
@notas = @alumno.notas_ultima_evaluacionend
<h1>Consultas</h1>
<ul>
<li> <%= link_to "Faltas", :action=>"faltas" %> </li> <li> <%= link_to "Notas", :action=>"notas" %> </li>
</ul>
<% @notas.each do |nota| %>
<tr>
<td class="list"><%= nota.asignatura %></td> <td class="list"><%= nota.nota %></td>
</tr> <% end %>
<h1>Consultar notas</h1>
<% form_tag '/alumnos/show_notas' do %>
DNI: <%= text_field_tag 'dni' %> <%= submit_tag 'Ver notas' %>
<% end %>
Telegraph$ script/plugin install svn://rubyforge.org/var/svn/telegraph/trunk
en /etc/asterisk/extensions.conf:exten => 777,1, AGI(agi://192.168.1.1:4574/alumnos/index)
en app/controllers/alumnos_controller.rb:def index
respond_to do |wants| wants.html { render }
wants.voice { render_voice { |voice| voice.play_sound "hello-world" }
}
endend
Telegraph: configuración
$ vi config/telegraph.yaml
development: agi_server: 127.0.0.1
agi_port: 4574 ami_server: druby://localhost:9000
outgoing_call_path: /var/spool/asterisk/outgoing
wakeup_call_path: /var/spool/asterisk/wakeups sound_path: /var/lib/asterisk/sounds
recording_path: /var/lib/asterisk/sounds
$ script/agi_server
respond_to
def index
respond_to do |wants|
wants.html { render } wants.voice { render_voice }
end end
$ vi app/views/alumnos/index.voice
voice.play_sound "hello-world"
index
# index.rhtml
<h1>Consultas</h1>
<ul> <li> <%= link_to "Faltas", :action=>"faltas" %> </li>
<li> <%= link_to "Notas", :action=>"notas" %> </li></ul>
# index.voice
voice.play_sound 'thank-you-for-calling'
voice.link_to_dtmf 'presione1-2' do link 1, :controller => "alumnos", :action => "faltas"
link 2, :action => "notas"end
formulario
# notas.rhtml
<h1>Consultar notas</h1>
<% form_tag '/alumnos/show_notas' do %> DNI: <%= text_field_tag 'dni' %>
<%= submit_tag 'Ver notas' %><% end %>
# notas.voice
voice.form :url=>{:controller => 'alumnos', :action=>'show_notas'} do |form| form.numeric_input 'dni', 'dni', :max_digits=>8
end
resultados# show_notas rhtml
<h3>Notas de <%= @alumno.nombre %></h3>
<table class="list"> <% @notas.each do |nota| %>
<tr> <td class="list"><%= nota.asignatura %></td>
<td class="list"><%= nota.nota %></td>
</tr> <% end %>
</table>
# show.voice
@notas.each do |nota|
voice.play nota.asignatura.to_slug voice.play nota.nota
end sleep 2.seconds
voice.play "vm-goodbye"
No hay que pasarse
• Web vs Mobile web vs Voz
• ej: 466453.com
Telegraph con AMI$ script/generate ami_model AMIModel
# environment.rb (user y password en manager.conf):Telegraph::AMIManager.establish_connection!(
:host=> 'your.host.name.com',
:username=>'user', :secret=>'password')
$ script/ami_server
# usar así:
AMIModel.create(:call, :channel=>'SIP/101', :context=>'default', :exten => 'outgoing', :priority=>1)
Links
• http://asterisk.org/
• http://www.voipnovatos.es
• http://www.voip-info.org
• http://adhearsion.com
• http://www.linuxjournal.com/article/9519
• http://telegraph.rubyforge.org
• http://telegraph.rubyforge.org/wiki/wiki.pl?UsingAGI
Q & A
top related