From dadad2b96f63dfe320e040aebd7ee11062e9b32d Mon Sep 17 00:00:00 2001
From: Matheus Faria <matheus.sousa.faria@gmail.com>
Date: Wed, 24 Jan 2018 11:15:28 -0200
Subject: [PATCH] Extracting natural related code to external file

Signed-off-by: Matheus Faria <matheus.sousa.faria@gmail.com>
Signed-off-by: Eduardo Nunes <eduardonunes2525@gmail.com>
---
 .hubot_history           |   1 -
 launch.sh                |  16 ---
 scripts/bot/brain.coffee | 180 +++++++++++++++++++++++++++++++++
 scripts/bot/index.coffee | 209 ++-------------------------------------
 4 files changed, 189 insertions(+), 217 deletions(-)
 delete mode 100644 .hubot_history
 delete mode 100755 launch.sh
 create mode 100644 scripts/bot/brain.coffee

diff --git a/.hubot_history b/.hubot_history
deleted file mode 100644
index 1385f26..0000000
--- a/.hubot_history
+++ /dev/null
@@ -1 +0,0 @@
-hey
diff --git a/launch.sh b/launch.sh
deleted file mode 100755
index c920a94..0000000
--- a/launch.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-export HUBOT_ADAPTER=rocketchat
-export HUBOT_OWNER=RocketChat
-export HUBOT_NAME='CatBot'
-export HUBOT_DESCRIPTION="Processamento de linguagem natural com hubot"
-export ROCKETCHAT_URL=https://chat.dorgam.it
-export ROCKETCHAT_ROOM=GENERAL
-export RESPOND_TO_DM=true
-export RESPOND_TO_LIVECHAT=true
-export ROCKETCHAT_USER=catbot
-export ROCKETCHAT_PASSWORD='botPassword'
-export ROCKETCHAT_AUTH=password
-export HUBOT_LOG_LEVEL=debug
-export HUBOT_CORPUS='catbot-en.yml'
-export HUBOT_LANG='en'
-bin/hubot -a rocketchat
diff --git a/scripts/bot/brain.coffee b/scripts/bot/brain.coffee
new file mode 100644
index 0000000..e7510b1
--- /dev/null
+++ b/scripts/bot/brain.coffee
@@ -0,0 +1,180 @@
+fs = require 'fs'
+path = require 'path'
+natural = require 'natural'
+
+brain = {}
+
+lang = (process.env.HUBOT_LANG || 'en')
+
+PorterStemmer = natural.PorterStemmer
+if lang != 'en'
+  PorterStemmer = require '../../node_modules/natural/lib/natural/stemmers/porter_stemmer_' + lang + '.js'
+
+events = {}
+nodes = {}
+error_count = 0
+err_nodes = 0
+
+eventsPath = path.join __dirname, '..', 'events'
+for event in fs.readdirSync(eventsPath).sort()
+  events[event.replace /\.coffee$/, ''] = require path.join eventsPath, event
+
+classifyInteraction = (interaction, classifier) ->
+  if Array.isArray interaction.expect
+    for doc in interaction.expect
+      if interaction.multi == true
+        classifier.addDocument(doc, interaction.name+'|'+doc)
+      else
+        classifier.addDocument(doc, interaction.name)
+
+    if Array.isArray interaction.next?.interactions
+      interaction.next.classifier = new natural.LogisticRegressionClassifier(PorterStemmer)
+      for nextInteractionName in interaction.next.interactions
+        nextInteraction = global.config.interactions.find (n) ->
+          return n.name is nextInteractionName
+        if not nextInteraction?
+          console.log 'No valid interaction for', nextInteractionName
+          continue
+        classifyInteraction nextInteraction, interaction.next.classifier
+      interaction.next.classifier.train()
+
+    if interaction.multi == true
+      interaction.classifier = new natural.LogisticRegressionClassifier(PorterStemmer)
+      for doc in interaction.expect
+        interaction.classifier.addDocument(doc, doc)
+      interaction.classifier.train()
+
+brain.train = () ->
+  console.log 'Processing interactions'
+  console.time 'Processing interactions (Done)'
+
+  global.nodes = {}
+  global.classifier = new natural.LogisticRegressionClassifier(PorterStemmer)
+
+  for interaction in global.config.interactions
+    {name, event} = interaction
+    global.nodes[name] = new events[event] interaction
+    # count error nodes
+    if name.substr(0,5) == "error"
+      err_nodes++
+    if interaction.level != 'context'
+      classifyInteraction interaction, global.classifier
+
+  global.classifier.train()
+
+  console.timeEnd 'Processing interactions (Done)'
+
+setContext = (res, context) ->
+  key = 'context_'+res.envelope.room+'_'+res.envelope.user.id
+  console.log 'set context', context
+  res.robot.brain.set(key, context)
+
+getContext = (res) ->
+  key = 'context_'+res.envelope.room+'_'+res.envelope.user.id
+  return res.robot.brain.get(key)
+
+isDebugMode = (res) ->
+  key = 'configure_debug-mode_'+res.envelope.room
+  return (res.robot.brain.get(key) == 'true')
+
+getDebugCount = (res) ->
+  key = 'configure_debug-count_'+res.envelope.room
+  return if res.robot.brain.get(key) then res.robot.brain.get(key) - 1 else false
+
+buildClassificationDebugMsg = (res, classifications) ->
+  list = ''
+  debugCount = getDebugCount(res)
+
+  if debugCount
+    classifications = classifications[0..debugCount]
+
+  for classification, i in classifications
+    list = list.concat 'Label: ' + classification.label + ' Score: ' + classification.value + '\n'
+
+  newMsg = {
+    channel: res.envelope.user.roomID,
+    msg: "Classifications considered:",
+    attachments: [{
+        text: list
+    }]
+  }
+
+  return newMsg
+
+incErrors = (res) ->
+  key = 'errors_'+res.envelope.room+'_'+res.envelope.user.id
+  errors = res.robot.brain.get(key) or 0
+  errors++
+  console.log 'inc errors ', errors
+  res.robot.brain.set(key, errors)
+  return errors
+
+clearErrors = (res) ->
+  console.log 'clear errors'
+  key = 'errors_'+res.envelope.room+'_'+res.envelope.user.id
+  res.robot.brain.set(key, 0)
+
+brain.processMessage = (res, msg) ->
+  context = getContext(res)
+  currentClassifier = global.classifier
+  trust = global.config.trust
+  interaction = undefined
+  debugMode = isDebugMode(res)
+  console.log 'context ->', context
+
+  if context
+    interaction = global.config.interactions.find (interaction) -> interaction.name is context
+    if interaction? and interaction.next?.classifier?
+      currentClassifier = interaction.next.classifier
+
+      if interaction.next.trust?
+        trust = interaction.next.trust
+
+  classifications = currentClassifier.getClassifications(msg)
+
+  console.log 'classifications ->', classifications[0..4]
+
+  if debugMode
+    newMsg = buildClassificationDebugMsg(res, classifications)
+    robot.adapter.chatdriver.customMessage(newMsg);
+
+  if classifications[0].value >= trust
+    clearErrors res
+    [node_name, sub_node_name] = classifications[0].label.split('|')
+    console.log({node_name, sub_node_name})
+    int = global.config.interactions.find (interaction) ->
+      interaction.name is node_name
+    if int.classifier?
+      subClassifications = int.classifier.getClassifications(msg)
+  else
+    if Array.isArray interaction?.next?.error
+      error_count = incErrors res
+      error_node_name = interaction.next.error[error_count - 1]
+      if not error_node_name?
+        clearErrors res
+        error_node_name = interaction.next.error[0]
+    else if interaction?.next?
+      setContext(res, undefined)
+      return brain.processMessage(res, msg)
+    else
+      error_count = incErrors res
+      if error_count > err_nodes
+        clearErrors res
+      error_node_name = "error-" + error_count
+
+  currentInteraction = global.config.interactions.find (interaction) ->
+    interaction.name is node_name or interaction.name is error_node_name
+
+  if not currentInteraction?
+    clearErrors res
+    return console.log 'Invalid interaction ['+node_name+']'
+
+  if currentInteraction.context == 'clear'
+    setContext(res, undefined)
+  else if node_name?
+    setContext(res, node_name)
+
+  currentNode = global.nodes[node_name or error_node_name]
+  currentNode.process.call @, res, msg, subClassifications
+
+module.exports = brain
diff --git a/scripts/bot/index.coffee b/scripts/bot/index.coffee
index 77f7ecf..0687466 100644
--- a/scripts/bot/index.coffee
+++ b/scripts/bot/index.coffee
@@ -1,30 +1,10 @@
-fs = require 'fs'
-path = require 'path'
-natural = require 'natural'
-
-lang = (process.env.HUBOT_LANG || 'en')
-
-if lang == "en"
-  PorterStemmer = require path.join '..', '..', 'node_modules', 'natural', 'lib',
-   'natural', 'stemmers', 'porter_stemmer.js'
-else
-  PorterStemmer = require path.join '..', '..', 'node_modules', 'natural', 'lib',
-    'natural', 'stemmers', 'porter_stemmer_' + lang + '.js'
-
-debug_mode = ((process.env.HUBOT_NATURAL_DEBUG_MODE == 'true') || false)
-
-config = {}
-events = {}
-nodes = {}
-error_count = 0
-err_nodes = 0
+require 'coffeescript/register'
 
-{ regexEscape, loadConfigfile } = require path.join '..', 'lib', 'common.coffee'
-{ getUserRoles, checkRole } = require path.join '..', 'lib', 'security.coffee'
+path = require 'path'
 
-eventsPath = path.join __dirname, '..', 'events'
-for event in fs.readdirSync(eventsPath).sort()
-  events[event.replace /\.coffee$/, ''] = require path.join eventsPath, event
+{regexEscape, loadConfigfile} = require '../lib/common'
+{getUserRoles, checkRole} = require '../lib/security'
+brain = require './brain'
 
 typing = (res, t) ->
   res.robot.adapter.callMethod 'stream-notify-room',
@@ -56,89 +36,6 @@ sendWithNaturalDelay = (msgs, elapsed = 0) ->
       cb?()
   , delay
 
-# setUserName = (res, name) ->
-# 	res.robot.adapter.callMethod 'livechat:saveInfo',
-# 		_id: res.envelope.user.id
-# 		name: name
-# 	,
-# 		_id: res.envelope.room
-# #
-
-classifyInteraction = (interaction, classifier) ->
-  if Array.isArray interaction.expect
-    for doc in interaction.expect
-      if interaction.multi == true
-        classifier.addDocument(doc, interaction.name + '|' + doc)
-      else
-        classifier.addDocument(doc, interaction.name)
-
-    if Array.isArray interaction.next?.interactions
-      interaction.next.classifier = new natural.LogisticRegressionClassifier(PorterStemmer)
-      for nextInteractionName in interaction.next.interactions
-        nextInteraction = global.config.interactions.find (n) ->
-          return n.name is nextInteractionName
-        if not nextInteraction?
-          console.log 'No valid interaction for', nextInteractionName
-          continue
-        classifyInteraction nextInteraction, interaction.next.classifier
-      interaction.next.classifier.train()
-
-    if interaction.multi == true
-      interaction.classifier = new natural.LogisticRegressionClassifier(PorterStemmer)
-      for doc in interaction.expect
-        interaction.classifier.addDocument(doc, doc)
-      interaction.classifier.train()
-
-setContext = (res, context) ->
-  key = 'context_' + res.envelope.room + '_' + res.envelope.user.id
-  console.log 'set context', context
-  res.robot.brain.set(key, context)
-
-getContext = (res) ->
-  key = 'context_' + res.envelope.room + '_' + res.envelope.user.id
-  return res.robot.brain.get(key)
-
-isDebugMode = (res) ->
-  key = 'configure_debug-mode_' + res.envelope.room
-  return (res.robot.brain.get(key) == 'true')
-
-getDebugCount = (res) ->
-  key = 'configure_debug-count_' + res.envelope.room
-  return if res.robot.brain.get(key) then res.robot.brain.get(key) - 1 else false
-
-buildClassificationDebugMsg = (res, classifications) ->
-  list = ''
-  debugCount = getDebugCount(res)
-
-  if debugCount
-    classifications = classifications[0..debugCount]
-
-  for classification, i in classifications
-    list = list.concat 'Label: ' + classification.label + ' Score: ' + classification.value + '\n'
-
-  newMsg = {
-    channel: res.envelope.user.roomID,
-    msg: "Classifications considered:",
-    attachments: [{
-        text: list
-    }]
-  }
-
-  return newMsg
-
-incErrors = (res) ->
-  key = 'errors_' + res.envelope.room + '_' + res.envelope.user.id
-  errors = res.robot.brain.get(key) or 0
-  errors++
-  console.log 'inc errors ', errors
-  res.robot.brain.set(key, errors)
-  return errors
-
-clearErrors = (res) ->
-  console.log 'clear errors'
-  key = 'errors_' + res.envelope.room + '_' + res.envelope.user.id
-  res.robot.brain.set(key, 0)
-
 module.exports = (_config, robot) ->
   global.config = _config
 
@@ -151,95 +48,7 @@ module.exports = (_config, robot) ->
     robot.logger.warning 'No trust level configured.'
     return
 
-  classifier = new natural.LogisticRegressionClassifier(PorterStemmer)
-
-  global.train = () ->
-    console.log 'Processing interactions'
-    console.time 'Processing interactions (Done)'
-
-    global.nodes = {}
-    global.classifier = new natural.LogisticRegressionClassifier(PorterStemmer)
-
-    for interaction in global.config.interactions
-      { name, event } = interaction
-      global.nodes[name] = new events[event] interaction
-      # count error nodes
-      if name.substr(0, 5) == "error"
-        err_nodes++
-      if interaction.level != 'context'
-        classifyInteraction interaction, global.classifier
-      console.log('\tProcessing interaction: ' + name)
-
-    console.log 'Training Hubot (This could be take a while...)'
-    global.classifier.train()
-    console.log '\n'
-
-    console.timeEnd '\nProcessing interactions (Done)'
-
-  global.train()
-
-  processMessage = (res, msg) ->
-    context = getContext(res)
-    currentClassifier = global.classifier
-    trust = global.config.trust
-    interaction = undefined
-    debugMode = isDebugMode(res)
-    console.log 'context ->', context
-
-    if context
-      interaction = global.config.interactions.find (interaction) -> interaction.name is context
-      if interaction? and interaction.next?.classifier?
-        currentClassifier = interaction.next.classifier
-
-        if interaction.next.trust?
-          trust = interaction.next.trust
-
-    classifications = currentClassifier.getClassifications(msg)
-
-    console.log 'classifications ->', classifications[0..4]
-
-    if debugMode
-      newMsg = buildClassificationDebugMsg(res, classifications)
-      robot.adapter.chatdriver.customMessage(newMsg)
-
-    if classifications[0].value >= trust
-      clearErrors res
-      [node_name, sub_node_name] = classifications[0].label.split('|')
-      console.log({ node_name, sub_node_name })
-      int = global.config.interactions.find (interaction) ->
-        interaction.name is node_name
-      if int.classifier?
-        subClassifications = int.classifier.getClassifications(msg)
-    else
-      if Array.isArray interaction?.next?.error
-        error_count = incErrors res
-        error_node_name = interaction.next.error[error_count - 1]
-        if not error_node_name?
-          clearErrors res
-          error_node_name = interaction.next.error[0]
-      else if interaction?.next?
-        setContext(res, undefined)
-        return processMessage(res, msg)
-      else
-        error_count = incErrors res
-        if error_count > err_nodes
-          clearErrors res
-        error_node_name = "error-" + error_count
-
-    currentInteraction = global.config.interactions.find (interaction) ->
-      interaction.name is node_name or interaction.name is error_node_name
-
-    if not currentInteraction?
-      clearErrors res
-      return console.log 'Invalid interaction [' + node_name + ']'
-
-    if currentInteraction.context == 'clear'
-      setContext(res, undefined)
-    else if node_name?
-      setContext(res, node_name)
-
-    currentNode = global.nodes[node_name or error_node_name]
-    currentNode.process.call @, res, msg, subClassifications
+  brain.train()
 
   robot.hear /(.+)/i, (res) ->
     res.sendWithNaturalDelay = sendWithNaturalDelay.bind(res)
@@ -249,7 +58,7 @@ module.exports = (_config, robot) ->
     # check if robot should respond
     if res.envelope.user.roomType in ['c', 'p']
       if (res.message.text.match new RegExp('\\b' + res.robot.name + '\\b', 'i')) or (res.message.text.match new RegExp('\\b' + res.robot.alias + '\\b', 'i'))
-        processMessage res, msg
+        brain.processMessage res, msg
         # TODO: Add engaged user conversation recognition/tracking
-    else if res.envelope.user.roomType in ['d', 'l']
-      processMessage res, msg
+    else if res.envelope.user.roomType in ['d','l']
+      brain.processMessage res, msg
-- 
GitLab