Reconociendo comandos

Al desarrollar bots para Telegram y otros mensajeros, periódicamente surge la tarea de reconocer y cumplir las solicitudes expresadas en lenguaje humano. Es esta "característica", según algunas opiniones, la principal diferencia entre bots y aplicaciones de línea de comandos. Debajo del corte, se describe un marco patentado para ejecutar comandos de voz arbitrarios. Las descripciones de conceptos clave van acompañadas de ejemplos en el idioma Kotlin.





Tomemos representaciones semánticas normalizadas como base para el reconocimiento de voz. Su elección se debe principalmente a la simplicidad y facilidad de implementación. Comencemos con lo básico, un ejemplo de las fuentes del marco:





/**      */
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) }
      
      



Ahora tenemos la capacidad de definir representaciones semánticas normalizadas predefinidas en forma de objetos:





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



El marco los pone en línea con los tokens de las frases entrantes, y la oración comienza a verse así:





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



Nos hemos ocupado del reconocimiento de voz. El código del tokenizador se adjunta en el repositorio disponible al final del artículo. Pasemos a ejecutar los comandos del discurso. Y aquí es donde comienza lo más interesante: el framework permite que cada representación semántica cuelgue el comportamiento especificado. Nuevamente, el ejemplo más simple de cómo reconocer una solicitud de ayuda en dos 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