falawin.rb
2011-02-02 13:03:56
2011-02-02 12:29:26
Autor: Sony Santos
http://gigawiki.com/sony/falawin-rb
Permalink: http://gigawiki.com/943
categ = script; linguagem = ruby; projeto = Reconhecimento de fala; sistema = windows
#
# Sistema de reconhecimento de fala. Idioma português brasileiro.
# Mostra um menu de opções e cola o resultado no aplicativo em uso.
# Feito para windows (testado no Windows Seven). Licença: Domínio público.
# (c) 2011 Sony Fermino dos Santos - http://gigawiki.com/sony/
# Fornecido sem quaisquer garantias e responsabilidades.
# Use por sua conta e risco.
# Veja instruções de uso em http://gigawiki.com/sony/reconhecimento-de-fala
#
# Este é meu primeiro trabalho em Ruby.
#
# Parte destes comentários foi redigida verbalmente com este programa.

puts "Iniciando reconhecimento de fala!"

require 'thread'

# codificação utf8 <-> iso_8859-1
# inspirado em http://forum.rubyonbr.org/forums/1/topics/507 (by Ronie Uliana)
class String
  def utf8_decode
    array_utf8 = self.unpack('U*')
    array_enc = []
    array_utf8.each do |num|
      if num <= 0xFF
        array_enc << num
      else
        array_enc.concat "&\#\#{num};".unpack('C*')
      end
    end
    array_enc.pack('C*')
  end

  def utf8_decode!
    self.replace(self.utf8_decode)
  end

  def utf8_encode
    self.unpack('C*').pack('U*')
  end

  def utf8_encode!
    self.replace(self.utf8_encode)
  end
end

def ignora(motivo, opcoes)
  # loga motivo
  puts "\nIgnorando: #{motivo}\nOpcoes:"
  opcoes.each {|o| puts "    '#{o}'"}
end

# abre comunicação com o Julius
puts "Abrindo comunicacao com o Julius..."
f = IO.popen("julius.bat -C opcoes.jconf 2>nul:", "r+")

# ignora primeira frase (que é vazia), enquanto espera o Julius ficar pronto
f.readpartial(4096)

# thread para ler o Julius em paralelo, enquanto a principal aguarda todas as opções.
lin = ''
mutex = Mutex.new      # mutex p/ lin
termina = false

thread = Thread.new do
  while not termina
    linha = f.readpartial(4096)
    mutex.synchronize do
      lin += linha
    end
  end
end

at_exit do
  # fecha a outra thread e o pipe.
  print "\nTerminando... "
  termina = true
  f.write "Termina\n"
  f.close
  puts "Ok!"
end

while true
  print "\nAguardando frase... "
  linhas = linha = ''
  
  # espera chegarem as opções do Julius
  while true

    mutex.synchronize do
      linha = lin
      lin = ''
    end
    
    if linha != ''
      # estão chegando linhas
      linhas += linha
      sleep 0.01
      next
    elsif linhas == ''
      # ainda não veio nada
      sleep 0.2
      next
    else
      # acabaram de vir as linhas!
      break
    end
  end
  
  print "Ok!"
  
  # separa as frases candidatas
  opcoes = linhas.scan(/sentence\d+.(.*)/).collect!{|e| e[0]}

  # ignora a respiração
  opcoes.each {|s| s.strip!; s.utf8_decode!}
  if opcoes.include? 'há um ano'
    ignora 'respiracao', opcoes
    next
  end
  
  # monta um menu com as opções, e cola o resultado na aplicação corrente
  # monta opções de comando
  op_cmd = ''
  tamanho = 0
  opcoes.each do |opcao|
    if !opcao.empty?
      # tira espaços repetidos
      opcao.squeeze!(' ')
      op_cmd += " \"#{opcao}\""
      tamanho += opcao.length
    end
  end

  # na escolha da frase pode haver ruídos
  # se o tamanho total for pequeno, ignora.
  if tamanho < 50
    ignora "tamanho insuficiente: " + tamanho.to_s, opcoes
    next
  end
  
  # mostra a primeira opção para identificar o texto
  puts " - " + opcoes[0]
  
  # monta comando do menu

  # comando se o autohotkey estiver instalado (no vista):
  # comando = "\"c:\program Files\AutoHotkey\AutoHotkey.exe\" menu.ahk " + op_cmd

  # comando para uso com menu.exe:
  comando = "menu " + op_cmd

  # executa o comando
  print "Lancando o menu... "
  system(comando)
  puts "Ok!"
end
blog comments powered by Disqus
Login:
Senha:
Para logar, você precisa ter o Javascript habilitado.