Статьи

Чат бот, сценаристы и обучение разработчиков Орфография

Несколько строк сценария, которые помогут разработчикам освоить орфографию

В  нашей удаленной компании  мы активно используем инструменты для обмена текстовыми сообщениями, мы пробовали Skype, затем HipChat и  Slack,  которые мы используем до сих пор. Одна из самых крутых возможностей Slack — это возможность сценариев. Более того, Github построил  Hubot  — бота, запускающего наши скрипты. Его можно легко интегрировать со Slack. Вы развертываете бота на Heroku, помещаете пользовательские скрипты в соответствующую директорию и все.

Идея

Некоторое время мы используем Slack, и я планировал поиграть с пользовательскими скриптами с самого начала Slack в SoftwareMill. Тем не менее, у меня не было достаточно хороших идей, чтобы я хотел реализовать их сразу. Так было до прошлой недели, когда я заметил, что мы делаем довольно много орфографических ошибок. И когда вы часто видите слова, написанные с ошибкой, ваш внутренний «правильный или нет» детектор начинает теряться — вы больше не уверены, должно ли это слово быть написано так или иначе. Поэтому я решил написать скрипт, который постарается обнаружить такие ошибки, исправить их и аккуратно прокомментировать 🙂

вступление

Но сначала позвольте мне кратко описать анатомию сценария Hubot. Он может быть написан на JavaScript или CoffeeScript и должен реализовывать хотя бы один из двух методов:

    module.exports = (robot) ->
      robot.hear <regexp>, (msg) ->
        # Code reacting on any message written in any chat room that matches <regexp>
        msg.send 'Example response to chat room'

      robot.respond <regexp>, (msg) ->
        # Code reacting on any message written to our bot that matches <regexp>
        msg.send 'Example response 2 to chat room'

Поскольку мы заинтересованы в просмотре каждой комнаты (канала), мы будем играть только с помощью   метода прослушивания .

Итерация 1

Вначале я хотел реализовать что-то простое, чтобы проверить, работает ли моя идея, и посмотреть, легко ли написать и запустить собственный скрипт на Hubot. И после этого я мог бы сделать свой сценарий более сложным и т. Д. Итак, сначала я создал что-то вроде этого:

module.exports = (robot) ->
  robot.hear prepareErrorDetectingRegEx(), (msg) ->
    author = msg.message.user.name
    grammarFailure = msg.match[1]
    exclamationSentence = msg.random messages
    msg.send  '@' + author + ', ' + exclamationSentence + '! It should be *' + errors[grammarFailure.toLowerCase().trim()] + '*'

prepareErrorDetectingRegEx = () ->
  errorWords = []
  for k, v of errors
    errorWords.push k
  joinedErrors = errorWords.join('|')
  errorDetectingRegex = new RegExp('.*(' + joinedErrors + ').*', 'i');
  return errorDetectingRegex

# key-value pair where key is an error and value contains correct word
errors =
  'wziąść'  : 'wziąć'
  'wziasc'  : 'wziąć'
  'wziaśc'  : 'wziąć'
  'wziasć'  : 'wziąć'
  'pokarze' : 'pokażę'
  'pokarzę' : 'pokażę'
  'żądzić'  : 'rządzić'
  'żadzić'  : 'rządzić'
  'żadzic'  : 'rządzić'
  'ządzic'  : 'rządzić'

messages = ['come on', 'gimme a break', 'are you serious?'] # for a Polish list of 'gentle' messages check source code (link at the end of the post) 🙂

Точка входа в наш скрипт находится в   функции robot.hear . Мы создаем regEx в prepareErrorDetectingRegEx,  который загружает все  ошибки  и  создает комбинацию  ИЛИ  со всеми возможными ошибками. Это регулярное выражение сначала казалось нормальным, но потом оказалось не таким идеальным 🙂

Когда любой текст, написанный в чате, соответствует нашему шаблону, мы знаем, что у нас есть «жертва». Теперь мы можем извлечь имя автора, найти правильную версию слова и подготовить полный ответ, например:

@user, gimme a break! It should be <correctVersionOfWordWrittenInBold>

Итерация 2

После первого выпуска пришло время протестировать сценарий на производстве и посмотреть, как он работает с сообщениями, отправленными в течение обычного рабочего дня. И, конечно же , оказалось, что многие распространенные ошибки отсутствуют в  ошибках  объекта , но и то, что первый вариант регулярного выражения далека от совершенства. Он обнаруживал ошибки в правильно написанных словах, например, если у нас была пара ‘eror’: ‘error’, он запускал также сообщения типа ‘abcEror’ или ‘erorSomething’.

Это можно исправить с помощью новой улучшенной проверки шаблонов только для отдельных слов (или начала / конца предложения)

prepareErrorDetectingRegEx = ->
  errorWords = []
  for k, v of errors
    errorWords.push k

  joinedErrors = errorWords.join('|')
  new RegExp '(^|\\s)(' + joinedErrors + ')($|\\s)', 'i'

Это была первая проблема, вторая была скорее на уровне кода: на польском языке у нас есть такие национальные символы, как «ąęłśćżźóń», но некоторые люди пишут слова без них. И чтобы поймать все возможные комбинации, каждое слово должно было быть добавлено к  ошибкам  во многих версиях. Ниже вы можете увидеть пример списка только с тремя ошибками, но для использования всех комбинаций требуется 10 записей:

errors =
  'wziąść'  : 'wziąć'
  'wziasc'  : 'wziąć'
  'wziaśc'  : 'wziąć'
  'wziasć'  : 'wziąć'
  'pokarze' : 'pokażę'
  'pokarzę' : 'pokażę'
  'żądzić'  : 'rządzić'
  'żadzić'  : 'rządzić'
  'żadzic'  : 'rządzić'
  'ządzic'  : 'rządzić'

Этот подход утомителен, но также гораздо более подвержен ошибкам. Чтобы упростить добавление записей, мне нужно немного упростить алгоритм. И когда я обсуждал это со  Сзимано,  он предложил сначала убрать все символы польского языка, а затем применить regEx для выявления ошибок. Такой подход был очень прост в реализации: сначала мы принимаем все сообщения , используя  /.*/  рисунка, а затем заменить все национальные символы с их стандартными версиями:

replacePolishChars = (text) ->
    text.toLowerCase()
      .replace('ą', 'a')
      .replace('ć', 'c')
      .replace('ę', 'e')
      .replace('ł', 'l')
      .replace('ń', 'n')
      .replace('ó', 'o')
      .replace('ś', 's')
      .replace('ż', 'z')
      .replace('ź', 'z')

Now we don’t have all those different combination of one error word and our example errors list looks much simpler:

errors =
  'wziasc'  : 'wziąć'
  'pokarze' : 'pokażę'
  'zadzic'  : 'rządzić'

Backlog

So after two iterations we have a stable script doing what we want and keeping our orthography skills sharp. Complete source code is available at GitHub.

But as we are using this script, some new ideas started appearing and landed in my backlog for future versions:

  • Store most often misspelled words in a database

  • Store users making most mistakes and print ‘hall of fame’ table

  • Allow user to add new entries to errors directly from chat rooms

Summary

As you can see, scripting in text communicators like Slack or HipChat is really powerful and easy to deploy tool, you are only limited by your creativity. And you don’t need hundreds line of codes to write something useful.

Further reading: Hubot Scripting Guide