Reconhecendo comandos

Ao desenvolver bots para o Telegram e outros mensageiros, a tarefa de reconhecer e atender solicitações expressas em linguagem humana surge periodicamente. É esse "recurso", de acordo com algumas opiniões, a principal diferença entre os bots e os aplicativos de linha de comando. Abaixo do corte, uma estrutura proprietária para executar comandos de voz arbitrários é descrita. As descrições dos conceitos-chave são acompanhadas por exemplos na linguagem Kotlin.





Vamos tomar representações semânticas normalizadas como base para o reconhecimento de voz. Sua escolha se deve principalmente à simplicidade e facilidade de implementação. Vamos começar com o básico, um exemplo das fontes do framework:





/**      */
typealias Rule = (String) -> Boolean

/**    */
open class Semnorm(vararg val rules: Rule)

/**       */
fun stem(vararg stems: String): Rule = { stems.any(it::startsWith) }

/**        */
fun word(vararg words: String): Rule = { words.any(it::equals) }

/**      */
fun String.matches(norm: Semnorm) = norm.rules.any { it(this) }
      
      



Agora temos a capacidade de definir representações semânticas normalizadas predefinidas na forma de objetos:





object Day : Semnorm(stem("day", "", "", "", "", ""))
      
      



A estrutura os coloca em linha com os tokens das frases recebidas, e a frase começa a ficar assim:





assertThat(
  "   5 ".tokenize(), 
  equalTo(
   listOf(
     Token("", Ban), 
     Token("", null),
     Token("", null), 
     Token("5", Number),
     Token("", Minute)
   )
  )
)
      
      



Já tratamos do reconhecimento de voz. O código do tokenizer está anexado no repositório disponível no final do artigo. Vamos prosseguir para a execução dos comandos da fala. E é aqui que começa a coisa mais interessante: o framework permite que cada representação semântica bloqueie o comportamento especificado. Novamente, o exemplo mais simples de como reconhecer um pedido de ajuda em dois idiomas:





object Help : ExecutableSemnorm(stem(
  "", "", "", "help", 
  "rule", "faq", "start", "",
)) {
  override fun execute(bot: Bot, m: Message) {
    val faq = message.from.relatedFaq()
    bot.sendMessage(m.chat.id, faq)
  }
}
      
      



, ? , , , , :





object Ban : DurableSemonrm(stem(
  "ban", "block", "mute", "", "",
  "", "", "",
)) {
  override fun execute(
    bot: Bot, attackerMessage: Message, duration: Duration) {

    val victimMessage = attackerMessage.replyToMessage
    val victimId = victimMessage.from.id
    val untilSecond = now().epochSecond + duration.inWholeSeconds

    bot.restrictChatMember(
      attackerMessage.chat.id, victimId, untilSecond)
  }
}
      
      



? , . , :





object Week : Semnorm(stem("week", "")) {
  override fun toDuration(number: Long) = 
    days(number) * 7
}
      
      



, :





class DurableSemnorm(vararg rules: Rule) : ExecutableSemnorm(*rules) {

  final override fun execute(
    token: Iterator<Token>, bot: Bot, m: Message) = 
      execute(bot, message, token.parseDuration())

  abstract fun execute(bot: Bot, m: Message, duration: Duration)
}
      
      



, . . , , Github.








All Articles