48
RoR puede también hablar: Interface de voz con Rails Svet Ivantchev, eFaber [email protected] 22 de noviembre de 2007, ConferenciaRails 2007, Madrid

Interface de Voz con Rails

Embed Size (px)

Citation preview

Page 1: Interface de Voz con Rails

RoR puede también hablar: Interface de voz con Rails

Svet Ivantchev, [email protected]

22 de noviembre de 2007, ConferenciaRails 2007, Madrid

Page 2: Interface de Voz con Rails

¿Qué es VoIP?

Page 3: Interface de Voz con Rails

Ejemplos

... y 1000s más

Page 4: Interface de Voz con Rails

¿Es por dinero?

• Ok, las llamadas VoIP son baratas pero no eso es importante

• Flexibilidad y integración con aplicaciones

Page 5: Interface de Voz con Rails

Demo

• Consulta de notas por web

• Consulta de notas por teléfono

La voz es una interface más

Page 6: Interface de Voz con Rails

¿Por qué ahora?

• Web stack (ej: SO, BD, RoR :-))

• VoIP (ej: Asterisk)

• Ancho de banda

• Los IVR dejan mucho que desear

Page 7: Interface de Voz con Rails

Asterisk (conceptos)

• Centralita Open Source (PBX)

• Protocolos: SIP, IAX

• Proveedores

http://asterisk.org

Page 8: Interface de Voz con Rails

ComponentesClientes VoIP

Terminación

DID

Red PSTN

SIP, IAX

ZAP

SIP, IAX

SIP, IAX

Page 9: Interface de Voz con Rails

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

Page 10: Interface de Voz con Rails

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)

Page 11: Interface de Voz con Rails

Cliente softphone

Page 12: Interface de Voz con Rails

Cliente hardware

Page 13: Interface de Voz con Rails

Números públicos

Page 14: Interface de Voz con Rails

DID y SIP URI

Page 15: Interface de Voz con Rails

Demo

• Llamada entre dos números

• Con el número público

Page 16: Interface de Voz con Rails

Ideas

• Respuesta diferente por horas

• Respuesta diferente en función del CallerID

• Integración con Jabber

• Voicemail

• IVR, colas

• 1000s de cosas mas ...

Page 17: Interface de Voz con Rails

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()

Page 18: Interface de Voz con Rails

...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)

Page 19: Interface de Voz con Rails

AGI y AMI

• Asterisk Gateway Interface

• Asterisk Manager Interface

Page 20: Interface de Voz con Rails

Alternativas

• Adhearsion

• Telegraph

Page 21: Interface de Voz con Rails

Adhearsion

• El dialplan escrito en Ruby

• ActiveRecord integrado

• Integración con Rails

• versiones (0.7.7 vs 0.8)

http://adhearsion.com

Page 22: Interface de Voz con Rails

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

...

Page 23: Interface de Voz con Rails

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 .

Page 24: Interface de Voz con Rails
Page 25: Interface de Voz con Rails

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}

Page 26: Interface de Voz con Rails

Adhearsion II: Amazon

Page 27: Interface de Voz con Rails

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

Page 28: Interface de Voz con Rails

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}

Page 29: Interface de Voz con Rails
Page 30: Interface de Voz con Rails
Page 31: Interface de Voz con Rails

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}

Page 32: Interface de Voz con Rails

Telegraph

• MVC

• respond_to

http://telegraph.rubyforge.org

Page 33: Interface de Voz con Rails

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

Page 34: Interface de Voz con Rails

Demo

Page 35: Interface de Voz con Rails
Page 36: Interface de Voz con Rails
Page 37: Interface de Voz con Rails

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 %>

Page 38: Interface de Voz con Rails

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

Page 39: Interface de Voz con Rails

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

Page 40: Interface de Voz con Rails

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"

Page 41: Interface de Voz con Rails

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

Page 42: Interface de Voz con Rails

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

Page 43: Interface de Voz con Rails

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"

Page 44: Interface de Voz con Rails
Page 45: Interface de Voz con Rails

No hay que pasarse

• Web vs Mobile web vs Voz

• ej: 466453.com

Page 46: Interface de Voz con Rails

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)

Page 48: Interface de Voz con Rails

Q & A