miércoles, 19 de septiembre de 2012

Interacción con Voz y Texto

Esta semana la entrada trata de realizar una especie de juego/aplicación donde se pueda interactuar con ella mediante voz o texto.

Para el uso de la voz se puede realizar mediante comando ("predefinidos") y para el texto de igual forma, buscando siempre que el uso de estos "comandos" sean de una manera muy natural. Esto puede ayudar a minimizar la curva de aprendizaje de los usuarios, omitiendoles el paso en el que tienen que memorizar los "comandos" que se usan y que acción realiza cada uno.

Mediante el uso de la voz, a mi parecer resulta mas natural decir: "izquierda" y que cierto objeto en el juego se mueva hacia ese lado.
Mientras que en el texto, resulta mas comodo/natural escribir: "más rápido", que "aumentar la velocidad x veces".

Voz
Mi elección(la principal) fue la de mover cierto objeto, mediante el uso de la voz.

La parte del juego esta desarrollada con Pilas Engine (el motor que utilice en la entrada anterior) y prácticamente es lo mismo, solo cambia en la situación de que:
  • Los actores son diferentes, se agregaron un chango y platanos.
  • Ahora solo se mueve el chango.
  • Existen 2 tipos de colisiones, cuando choca con los platanos y cuando choca con las bombas.
  • Al chocar con los platanos, se los "come" y el chango se ríe.
  • Al chocar con las bombas, éstas "explotan" y el chango grita.

Para el apartado de la voz, me apoyé de la librería PySpeech, que hace uso del motor de reconocimiento de voz incluido en Windows (por lo que solo trabaja bajo Windows, una desventaja).
  • Por si les interesa probarla, les dejo el enlace para su descarga e instalación aquí. (en la página dice que solo funciona bajo python 2.4 o 2.5, pero yo estoy trabajando con python 2.6).
 
 Ya que se hace uso del motor de voz de Windows, tambien toca realizar la configuración de este para que trabaje de manera correcta, esto si no habían usado anteriormente esta herramienta.

Al parecer la combinación de esta librería y el motor de voz de Windows realizan un trabajo muy eficiente (tiene algunas deficiencias muy mínimas), tomando en cuenta que la mayoria de los programas/aplicaciones que usan apartados para el reconocimiento de voz estan entrenados o implementados para escuchar comandos en inglés, esta combinación resulto ser muy buena.


En el programa el uso que se le da a esta librería es:
  • Escuchar algún "comando" y pasarlo a texto, tambien hay la posibilidad de que la aplicación repita el comando que se dijo.
 
Ya después mediante condiciones, se valida el comando y la acción que se va a realizar, en este caso mover el chango en 4 direcciones por toda la ventana de la aplicación (actualizando los valores de las coordenadas de la posición del chango).

Aquí les dejo el código:

import pilas

import speech
import random

def comer(mono, banana):
 mono.sonreir()
 banana.eliminar()

def explotar(mono, bomba):
 mono.gritar()
 bomba.explotar()
 bomba.eliminar()

def comando_voz():
 comando = speech.input("Diga algo!!")
 print comando
 speech.say("You said, %s" % comando)
 return comando 

def movimiento(mono):
 comando = "nada"
 x = 0
     y = 0
 while (comando != "Salir"):
  comando = comando_voz()
  if (comando == "Uno"):
   mono.y = (y+5)
   y = mono.y
  elif (comando == "Dos"):
   mono.y = (y-5)
   y = mono.y
  elif (comando == "Izquierda"):
   mono.x = (x-5)
   x = mono.x
  elif (comando == "Derecha"):
   mono.x = (x+5)
   x = mono.x
  elif (comando == "Salir"):
   print "Saliendo.... "
   pilas.terminar()   
  else:
   print "Comando desconocido!!.."    

def main():

 bananas = []
 bombas = []

 pilas.iniciar()

 mono = pilas.actores.Mono()
 mono.x = 0
 mono.y = 0

 cantidad = 5
 for i in range(cantidad):
  bomba = pilas.actores.Bomba() #se crean las bombas
  bomba.x = random.randrange(-200, +200) #coordenadas aleatorias en x
  bomba.y = random.randrange(-200, +200) #coordenadas aleatorias en y
  bombas.append(bomba)  #se agregan las bombas al grupo 
  banana = pilas.actores.Banana() #se crean las bananas
  banana.x = random.randrange(-200, +200) #coordenadas aleatorias en x
  banana.y = random.randrange(-200, +200) #coordenadas aleatorias en y
  bananas.append(banana)  #se agregan las bananas al grupo
 
 mono.aprender(pilas.habilidades.Arrastrable)
 pilas.mundo.colisiones.agregar(mono, bananas, comer)
 pilas.mundo.colisiones.agregar(mono, bombas, explotar)

 movimiento(mono) 
 
 pilas.ejecutar()
 
main()



Un incoveniente con el que me tope (muy desagradable) fue el de que al tratar de usar la palabra/comando "arriba" o "abajo", el motor de voz lo interpreata como "activar la ventana que se encuentra por encima o por abajo de la ventana actual" por lo que la acción de mover al chango hacia arriba/abajo no se puede completar.

Debido a esto me vi en la necesidad de cambiar los comandos "Arriba/Abajo" por "Uno/Dos" respectivamente.

El video en esta parte va quedar pendiente, debido a que al ejecutar el juego y el programa de grabación la computadora se cuelga y no responde. (Más abajo pondre un video de esto mismo, pero ingresando los comandos por texto).

Texto
Esto lo realice antes de comenzar con la parte de la voz, lo hice a manera de checar como podía actualizar los valores de las coordenadas para la posición dle chango, ya después le agregue más cosillas.
Prácticamente esta versión hace lo mismo que la comentada arriba, solo con la diferencia de que los comandos se ingresan mediante texto (algo simple), tratandolo en cierta medida de hacerlo lo más natural posible.

Aquí esta el código:

import pilas
import random

def comer(mono, banana):
 mono.sonreir()
 banana.eliminar()

def explotar(mono, bomba):
 mono.gritar()
 bomba.explotar()
 bomba.eliminar()

def movimiento(mono):
 comando = "nada"
 comandos1 = ["arriba", "up", "y+", "subir", "lado1"]
 comandos2 = ["abajo", "down", "y-", "bajar", "lado2"]
 comandos3 = ["izquierda", "izq", "x-", "left", "lado3"]
 comandos4 = ["derecha", "der", "x+", "rigth", "lado4"]
 comandos5 = ["salir", "exit", "quit", "fin", "end"]

 x = 0
     y = 0
 while (comando != "Salir"):

  comando = raw_input("Diga algo!!  ") 

  if (comando in comandos1 ):
   mono.y = (y+5)
   y = mono.y
  elif (comando  in comandos2 ):
   mono.y = (y-5)
   y = mono.y
  elif (comando  in comandos3 ):
   mono.x = (x-5)
   x = mono.x
  elif (comando  in comandos4 ):
   mono.x = (x+5)
   x = mono.x
  elif (comando  in comandos5 ):
   print "Saliendo.... "
   pilas.terminar()   
  else:
   print "Comando desconocido!!.."    

def main():
 bananas = []
 bombas = []
 
        pilas.iniciar()
 
        mono = pilas.actores.Mono()
 mono.x = 0
 mono.y = 0

 cantidad = 5
 for i in range(cantidad):
  bomba = pilas.actores.Bomba() #se crean las bombas
  bomba.x = random.randrange(-200, +200) #coordenadas aleatorias en x
  bomba.y = random.randrange(-200, +200) #coordenadas aleatorias en y
  bombas.append(bomba)  #se agregan las bombas al grupo 
  banana = pilas.actores.Banana() #se crean las bananas
  banana.x = random.randrange(-200, +200) #coordenadas aleatorias en x
  banana.y = random.randrange(-200, +200) #coordenadas aleatorias en y
  bananas.append(banana)  #se agregan las bananas al grupo
 
 mono.aprender(pilas.habilidades.Arrastrable)
 pilas.mundo.colisiones.agregar(mono, bananas, comer)
 pilas.mundo.colisiones.agregar(mono, bombas, explotar)

 movimiento(mono) 
 
 pilas.ejecutar()

main()



En esta versión hay un poco más de libertad en los comando, estan almacenados en listas.
Una buena idea sería la de capturar el comando que ingrese el usuario y después dividirlo en palabras, posteriormente checar si una palabra de esas esta en las listas de los comandos soportados, pero eso no lo agregue ya que mi prioridad era la de la voz.

Aquí dejo el video, un poco lento y trabado, pero aquí esta:



__________________________________________________________________________________
Enlaces útiles:

1 comentario:

  1. Faltó lo de aportación al proyecto grupal y tu ortografía se podría mejorar. 6 pts.

    ResponderEliminar