Translate

2017年4月10日月曜日

Hubot Document: Scripting を翻訳して、Hubotチャットボットの書き方を学習する

 Hubotフレームワークは、coffee scriptかJava Scriptで書かなければならない。
それにいわゆるプラグインのようにスクリプトを配置していく構造なので
Hubotが決めた書式に従ってコードを書かなくてはならない。

それにいろいろ予約語というか、
メタデータなどの扱いなんかもどうやればいいのか
しっておきたいし...

ということで本家サイトの

Hubot Documentation: Scripting
https://hubot.github.com/docs/scripting/

を翻訳することにした。
以下翻訳文ですが参照の場合は at your own riskでお願いします。
----------

Hubot Docmentation: Scripting


箱から取り出したばかりの Hubotは、それほど多くではありませんが拡張可能でスクリプト化可能なロボットのフレンズです。 コミュニティによって書かれ管理されている数百のスクリプト があり、簡単に自分のスクリプトを書くこともできます。 hubotの @scripts@ ディレクトリにカスタムスクリプトを作ったり、 コミュニティと共有するためのスクリプトパッケージを作る こともできますよ!


スクリプトの解剖学


hubot を作成すると、ジェネレータは scripts ディレクトリもあわせて作成します。 このディレクトリをのぞけは、スクリプトのサンプルを確認することができます。 スクリプトをスクリプトにするには、次のことが必要です:

  • hubot ロードパス(デフォルトは src/scripts および scripts )を通したディレクトリに配置
  • 拡張子 .coffee もしくは .js にする
  • 関数をエクスポートする

関数をエクスポートするとは、次のようにスクリプトを記述するという意味です:

module.exports = (robot) ->
  # コードをここに記述

パラメータ robot は、あなたのロボットのインスタンスをあらわしています。 これで、いくつかの素晴らしいスクリプトを開始することができきるようになりました。


hear respond


HuBot はチャットボットをつくるためのフレームワークなので、最も一般的なやりとりはメッセージに基づいています。 Hubot は、ルーム内で発言されたメッセージを聞いたり( hear )、直接そのメッセージに返信する( respond )ことができます。 どちらのメソッドも、正規表現とコールバック関数をパラメータとして取ります。 例えば:

module.exports = (robot) ->
  robot.hear /badger/i, (res) ->
    # コードをここに記述

  robot.respond /open the pod bay doors/i, (res) ->
    # コードをここに記述
robot.hear /badger/ コールバック関数は、メッセージのテキストが正規表現とマッチするたびに呼び出されます。 例えば、次のようなメッセージの場合呼び出されます:

  • Stop badgering the witness
  • badger me
  • what exactly is a badger anyways
robot.respond /open the pod bay doors/i コールバック関数は、ロボットの名前またはエイリアスの直前にあるメッセージのためだけに呼び出されます。 ロボットの名前が HAL でエイリアスが / の場合、このコールバック関数は次のメッセージでトリガされます:

  • hal open the pod bay doors
  • HAL: open the pod bay doors
  • @HAL open the pod bay doors
  • /open the pod bay doors

次のメッセージの場合は、呼び出されません:

  • HAL: please open the pod bay doors :respond はロボット名直後のテキストにバインドされているためです。
  • has anyone ever mentioned how lovely you are when you open the pod bay doors? :ロボット名がないためです。

send および reply


パラメータ res Response インスタンスです(歴史的にこのパラメータは msg でした。このように他のスクリプトで使用されることがあります)。 res を使用すると、書き込まれたチャットルームにメッセージを送信したり( send )、、任意のチャットルームにメッセージを送信したり( emote )(ただし、指定されたアダプタがサポートしている場合のみ)、メッセージを送信した人に返信( reply )することができます。 例えば:

module.exports = (robot) ->
  robot.hear /badger/i, (res) ->
    res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"

  robot.respond /open the pod bay doors/i, (res) ->
    res.reply "I'm afraid I can't let you do that."

  robot.hear /I like pie/i, (res) ->
    res.emote "makes a freshly baked pie"
robot.hear /badgers/ コールバック関数は、だれが発言したかに関係なく、指定された通りに正確にメッセージ"Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"を送信します。

もしユーザ Dave"HAL: open the pod bay doors"と発言したのであれば、 robot.respond /open bay doors/i コールバック関数からメッセージ"Dave: I'm afraid I can't let you do that."が送られます。


データのキャプチャリング


ここまでは静的な応答を扱っていましたが、もっと面白いもの、機能的には退屈なものもあります。 res.match には、着信メッセージを正規表現と照合( match )した結果が格納されています。 これは単に JavaScript関数 match() と同じで、最終的には式に一致する完全なテキストであるインデックス0を持つ配列になります。 取得グループを含めると、 res.match が作成されます。 たとえば、次のようなスクリプトを更新するとします:

  robot.respond /open the (.*) doors/i, (res) ->
    # コードをここに記述


Daveが"HAL: open the pod bay doors"と発言したならば、 res.match[0] は"open the pod bay doors"で、 res.match[1] は単に "pod bay" となります。これを使ってよりダイナミックなチャットボットを始めることができます:

  robot.respond /open the (.*) doors/i, (res) ->
    doorType = res.match[1]
    if doorType is "pod bay"
      res.reply "I'm afraid I can't let you do that."
    else
      res.reply "Opening #{doorType} doors"

HTTP通信の構築


Hubot は、サードパーティのAPIを統合して使用するために、あなたの代わりにHTTPコールを行うことができます。 これは、 robot.http で利用可能な node-scoped-http-client インスタンスを介して行うことができます。 最も単純なケースは次のようになります:


  robot.http("https://midnight-train")
    .get() (err, res, body) ->
      # コードをここに記述

POSTは次のように記述します:

  data = JSON.stringify({
    foo: 'bar'
  })
  robot.http("https://midnight-train")
    .header('Content-Type', 'application/json')
    .post(data) (err, res, body) ->
      # コードをここに記述


err は、処理中に発生したエラーをあらわします(発生した場合)。一般的にこれをチェックし、それに応じて処理したいと思うでしょう:

  robot.http("https://midnight-train")
    .get() (err, res, body) ->
      if err
        res.send "Encountered an error :( #{err}"
        return
      # (成功した場合の)コードをここに記述


res node http.ServerResponse インスタンスです。 node-scoped-http-client を使用する場合、ほとんどのメソッドは重要ではありませんが、興味があるのは statusCode getHeader です。 statusCode を使用してHTTPステータスコードをチェックします。通常 200 以外の場合は何か問題が発生したことを意味します。 レートリミットを確認するなど、ヘッダを表示するには getHeader を使用します。

  robot.http("https://midnight-train")
    .get() (err, res, body) ->
      # ここにエラーチェックコードを記述

      if res.statusCode isnt 200
        res.send "Request didn't come back HTTP 200 :("
        return

      rateLimitRemaining = parseInt res.getHeader('X-RateLimit-Limit') if res.getHeader('X-RateLimit-Limit')
      if rateLimitRemaining and rateLimitRemaining < 1
        res.send "Rate Limit hit, stop believing for awhile"

      # 残りのコードを記述

body はレスポンスボディを文字列として扱います。おそらく最も気になるものです:

  robot.http("https://midnight-train")
    .get() (err, res, body) ->
      # ここにエラーチェックコードを記述

      res.send "Got back #{body}"



JSON


APIと対話する際の最も簡単な方法は、余分な依存関係を必要としない JSON です。  robot.http を呼び出すときには、通常、 Accept ヘッダを設定して、APIにあなたが期待しているものを提供する必要があります。  body を取得したら、 JSON.parse で解析することができます:

  robot.http("https://midnight-train")
    .header('Accept', 'application/json')
    .get() (err, res, body) ->
      # ここにエラーチェックコードを記述

      data = JSON.parse body
      res.send "#{data.passenger} taking midnight train going #{data.destination}"

APIにエラーが発生し、JSON の代わりに通常のHTMLエラーをレンダリングしようとする場合など、非 JSON を戻すことは可能です。 安全な側になるためには、 Content-Type をチェックし、解析中にエラーをキャッチする必要があります。

  robot.http("https://midnight-train")
    .header('Accept', 'application/json')
    .get() (err, res, body) ->
      # ここに err および response ステータス確認コードを記述

      if response.getHeader('Content-Type') isnt 'application/json'
        res.send "Didn't get back JSON :("
        return

      data = null
      try
        data = JSON.parse body
      catch error
       res.send "Ran into an error parsing JSON :("
       return

      # コードを記述




XML


バンドルされたXML解析ライブラリがないため、XML APIは実装が難しくなります。 詳細については、このドキュメントの範囲を超えていますが、ここにいくつかのライブラリがあります:


スクリーンスクレイピング


APIがない場合は "スクリーンスクレイピング" が使えるの可能性が常にあります。 詳細についてはこのドキュメントの範囲を超えていますが、ここではいくつかのライブラリをチェックアウトしています:
  • cheerio (jQueryのおなじみの構文とAPI)
  • jsdom (W3C DOMのJavaScript実装)

高度な HTTP/HTTPS 設定


前述のように、hubot は node-scoped-http-client を使用して、HTTPおよびHTTPS要求を行うための単純なインタフェースを提供します。 その傘下では、nodeの組み込み http https ライブラリを使用していますが、最も一般的な種類の対話に簡単なDSLを提供しています。

http https のオプションをより直接的に制御する必要がある場合は、 http https に渡される node-scoped-http-client 上の第2引数を robot.http に渡します:

  options =
    # CAに対してサーバ証明書を検証しないでください、怖い!
    rejectUnauthorized: false
  robot.http("https://midnight-train", options)

さらに、 node-scoped-http-client があなたに合っていない場合は、 http https を直接使うことも、 request のような他のノードライブラリを使うこともできます。


ランダム


一般的なパターンは、コマンドをhearしたり、コマンドにrespondしたり、ランダムな面白い画像やテキスト行を可能な限り配列から送信することです。 JavaScriptやCoffeeScriptですぐにこれを行うのは面倒ですので、Hubot には便利なメソッドがあります:

lulz = ['lol', 'rofl', 'lmao']

res.send res.random lulz

トピック


アダプタがそれをサポートしている場合は、Hubot は部屋のトピック変更に反応することができます。
module.exports = (robot) ->
  robot.topic (res) ->
    res.send "#{res.message.text}? That's a Paddlin'"



入退室


アダプタがそれをサポートしている場合は、Hubot はユーザの入退室を確認することができます。

enterReplies = ['Hi', 'Target Acquired', 'Firing', 'Hello friend.', 'Gotcha', 'I see you']
leaveReplies = ['Are you still there?', 'Target lost', 'Searching']

module.exports = (robot) ->
  robot.enter (res) ->
    res.send res.random enterReplies
  robot.leave (res) ->
    res.send res.random leaveReplies


カスタムリスナ


上述のヘルパは、平均的なユーザが必要とする(聞く(hear)、応答する(respond)、入室する(enter)、退室する(leave)、トピック(topic))機能のほとんどをカバーしていますが、時にはリスナに対して非常に特殊なマッチングロジックを使用したいことがあるでしょう。 その場合、 listen を使用して正規表現の代わりにカスタムマッチ関数を指定することができます。

リスナがコールバックを実行する際に、match 関数は真理値を返却します。 次に match関数の返す真偽値が response.match としてコールバック関数に渡されます。

module.exports = (robot) ->
  robot.listen(
    (message) -> # マッチ関数
      # Steve の発言に時々返信する
      message.user.name is "Steve" and Math.random() > 0.8
    (response) -> # 標準リスナコールバック
      # 彼が存在することがどれほど幸せかをスティーブに知らせてください
      response.reply "HI STEVE! YOU'RE MY BEST FRIEND! (but only like #{response.match * 100}% of the time)"
  )

複雑なマッチ処理例については、デザインパターンのドキュメントを参照してください。


環境変数


Hubotは、 process.envを使用して、他のNodeプログラムと同じように、実行している環境にアクセスできます。 これは、スクリプトの実行方法を設定するのに使用できます。規約は接頭辞 HUBOT_を使用します。

answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING

module.exports = (robot) ->
  robot.respond /what is the answer to the ultimate question of life/, (res) ->
    res.send "#{answer}, but what is the question?"


スクリプトが定義されていない場合、スクリプトをロードできるか確認し、Hubot 開発者に定義方法を伝えたり、何かをデフォルトにするよう注意してください。 スクリプト作成者は、致命的なエラー(例えば、hubotが終了するかどうか)を判断して、それに依存するスクリプトを構成する必要があると説明します。可能であれば、それが理にかなっているときは、他の設定をせずにスクリプトを実行することを推奨します。

ここではデフォルトにすることができます:

answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING or 42

module.exports = (robot) ->
  robot.respond /what is the answer to the ultimate question of life/, (res) ->
    res.send "#{answer}, but what is the question?"

定義されていない場合は、ここで終了します:

 answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING
unless answer?
  console.log "Missing HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING in environment: please set and try again"
  process.exit(1)

module.exports = (robot) ->
  robot.respond /what is the answer to the ultimate question of life/, (res) ->
    res.send "#{answer}, but what is the question?"

最後に、robot.respondを更新してチェックします:

answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING

module.exports = (robot) ->
  robot.respond /what is the answer to the ultimate question of life/, (res) ->
    unless answer?
      res.send "Missing HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING in environment: please set and try again"
      return
    res.send "#{answer}, but what is the question?"

依存関係


Hubotは npm を使用してその依存関係を管理します。 パッケージを追加するには、パッケージを package.jsondependencies  に追加します。 たとえば、 lolimadeupthispackage 1.2.3 を追加したい場合は、次のようになります:

  "dependencies": {
    "hubot":         "2.5.5",
    "lolimadeupthispackage": "1.2.3"
  },

hubot-scripts からスクリプトを使う場合は、追加するスクリプトの Dependencies 文書を書き留めておいてください。 それらは package.json にコピー&ペーストできる形式でリストされていますが、有効なJSONにするために必要に応じてカンマを必ず追加してください。

タイムアウトとインターバル


Hubot は JavaScript のビルトイン setTimeout を使用してコードを遅延実行できます。 これはコールバックメソッドとそれを呼び出すまでに待つ時間をとります:

module.exports = (robot) ->
  robot.respond /you are a little slow/, (res) ->
    setTimeout () ->
      res.send "Who you calling 'slow'?"
    , 60 * 1000

さらに、Hubot は setInterval を使用してインターバルでコードを実行できます。 コールバックメソッドと、コール間の待機時間が必要です:

module.exports = (robot) ->
  annoyIntervalId = null

  robot.respond /annoy me/, (res) ->
    if annoyIntervalId
      res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
      return

    res.send "Hey, want to hear the most annoying sound in the world?"
    annoyIntervalId = setInterval () ->
      res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
    , 1000

  robot.respond /unannoy me/, (res) ->
    if annoyIntervalId
      res.send "GUYS, GUYS, GUYS!"
      clearInterval(annoyIntervalId) ->
      annoyIntervalId = null
    else
      res.send "Not annoying you right now, am I?"

HTTPリスナ


Hubot には、HTTP要求を処理するための Express Webフレームワークのサポートが含まれています。 環境変数 EXPRESS_PORT または PORT で指定されたポート(この順序で優先されます、デフォルトは8080)をlistenします。 Express アプリケーションのインスタンスは robot.router から入手できます。 EXPRESS_USEREXPRESS_PASSWORD を指定して、ユーザー名とパスワードで保護することができます。 EXPRESS_STATIC を設定することにより、自動的に静的ファイルを提供することができます。

この最も一般的な使い方は、プッシュ時のwebhooksによるサービスにHTTPエンドポイントを提供して、チャットに情報を表示することです。
module.exports = (robot) ->
  # 期待値:ルームがアダプタごとに異なる場合、数値ID、名前、トークン、またはその他の値である可能性があります。
  robot.router.post '/hubot/chatsecrets/:room', (req, res) ->
    room   = req.params.room
    data   = if req.body.payload? then JSON.parse req.body.payload else req.body
    secret = data.secret

    robot.messageRoom room, "I have a secret: #{secret}"

    res.send 'OK'


それらを curl でテストしてください:後述の "エラー処理"節 も参照してください。

// JSONデータを送る場合、"Content-Type: application/json"を指定する必要があります
curl -X POST -H "Content-Type: application/json" -d '{"secret":"C-TECH Astronomy"}' http://127.0.0.1:8080/hubot/chatsecrets/general

// デフォルト(Content-Type: application/x-www-form-urlencoded)の場合、"payload=..."をセットする必要があります
curl -d 'payload=%7B%22secret%22%3A%22C-TECH+Astronomy%22%7D' http://127.0.0.1:8080/hubot/chatsecrets/general

すべてのエンドポイントURLは、(ロボットの名前に関係なく)リテラル文字列/hubotで始まる必要があります。 この一貫性により、ウェブフック(コピー可能なURL)を簡単に設定でき、URLが有効であることが保証されます(すべてのボット名がURLセーフではありません)。

イベント


Hubotはスクリプト間でデータを渡すために使用できるイベントに応答することもできます。 これは、node.js の EventEmitterrobot.emitrobot.on でカプセル化することによって行われます。

このためのユースケースの1つは、サービスとのやりとりを処理し、イベントが発生したときにイベントを発行するためのスクリプトを1つ持つことです。 たとえば、GitHubのポスト・コミット・フックからデータを受け取り、それが入ってきたときにコミットを発行し、そのコミットに対して別のスクリプトを実行させるスクリプトを作成できます。
# src/scripts/github-commits.coffee
module.exports = (robot) ->
  robot.router.post "/hubot/gh-commits", (req, res) ->
    robot.emit "commit", {
        user    : {}, #hubot user object
        repo    : 'https://github.com/github/hubot',
        hash  : '2e1951c089bd865839328592ff673d2f08153643'
    }

# src/scripts/heroku.coffee
module.exports = (robot) ->
  robot.on "commit", (commit) ->
    robot.send commit.user, "Will now deploy #{commit.hash} from #{commit.repo}!"
    #デプロイコードはここに記述

イベントを提供する場合は、データにHubot ユーザまたは hubot ルームオブジェクトを含めることを強くお勧めします。 これにより、hubot はチャット経由でユーザまたはルームに通知することができます。

エラー処理


完全なコードは存在しません、エラーと例外がかならず予想されます。 以前はキャッチされなかった例外がhubotインスタンスをクラッシュさせていました。そこで Hubot に uncaughtException ハンドラが追加されました。このハンドラは、スクリプトが例外に関する何かを行うためのフックする機能を提供します。

# src/scripts/does-not-compute.coffee
module.exports = (robot) ->
  robot.error (err, res) ->
    robot.logger.error "DOES NOT COMPUTE"

    if res?
      res.reply "DOES NOT COMPUTE"

ここで必要なことは何でも行うことができます、特に非同期コードでは、レスキューおよびロギングのエラーを予防する必要があります。 そうしないと、再帰的なエラーが発生し、何が起こっているのか分からないことがあります。

hoodの下では、エラーハンドラがそのイベントを消費する「エラー」イベントが発生しています。 uncaughtException ハンドラは、 技術的にプロセスを未知の状態のままにします 。 したがって、可能な限り、自分の例外を救済し、自分で放出する必要があります。 最初の引数は出力されたエラーで、2番目の引数はエラーを生成したオプションのメッセージです。

前のサンプルを使うと:

  robot.router.post '/hubot/chatsecrets/:room', (req, res) ->
    room = req.params.room
    data = null
    try
      data = JSON.parse req.body.payload
    catch err
      robot.emit 'error', err

    # 残りのコードをここに記述


  robot.hear /midnight train/i, (res)
    robot.http("https://midnight-train")
      .get() (err, res, body) ->
        if err
          res.reply "Had problems taking the midnight train"
          robot.emit 'error', err, res
          return
        # 残りのコードをここに記述


2番目の例では、ユーザがどのようなメッセージを表示するか考えておく必要があります。ユーザに返信するエラーハンドラがある場合は、カスタムメッセージを追加する必要はなく、 get() リクエストに提供されたエラーメッセージを返信することもできますが、もちろん例外レポートをどのように公開したいかによって異なります。

スクリプトの文書化


Hubotスクリプトは、ファイルの先頭にコメントを記述することができます。たとえば、次のようになります。

# Description:
#   <description of the scripts functionality>
#
# Dependencies:
#   "<module name>": "<module version>"
#
# Configuration:
#   LIST_OF_ENV_VARS_TO_SET
#
# Commands:
#   hubot <trigger> - <what the respond trigger does>
#   <trigger> - <what the hear trigger does>
#
# Notes:
#   &ltoptional notes required for the script>
#
# Author:
#   <github username of the original script author>

これらの中で最も重要でユーザが直面するのは Commands です。 読み込み時に、Hubot は各スクリプトの Commands セクションを見て、すべてのコマンドのリストを作成します。 含まれている help.coffee を使用すると、ユーザはすべてのコマンドまたは検索でヘルプを要求できます。 したがって、コマンドを文書化することで、ユーザはより多くの情報を発見することができます。

コマンドを文書化する際には、以下のベストプラクティスがあります:
  • 1行にとどめます。ヘルプコマンドがソートされるので、二番目の行が予期しない場所に挿入され、おそらく意味をなさなくなります。
  • hubot にが何か他の名前を付けられていても、Hubot を hubot として参照してください。自動的に正しい名前に置き換えられます。これにより、ドキュメントを更新しなくても簡単にスクリプトを共有できます。
  • robot.respond のドキュメントでは、常に接頭辞として hubot を付けます。 Hubot はこれをあなたのロボットの名前に自動的に置き換えます。ロボットの名前があればそれをエイリアスに置き換えます。
  • マニュアルページがどのように文書化されているか確認してください。特に角カッコは省略可能な部分を示し、任意の数の引数に対して '...'を指定します。

その他のセクションは、ボットの開発者、特定の依存関係、設定変数、および注意事項に関連しています。 hubot-scripts へ寄稿するには、スクリプトの起動と実行に関連するすべてのセクションが含まれている必要があります。

永続性


Hubot には、 robot.brain として公開されたインメモリの Key-Value ストアがあり、スクリプトでデータを格納および取得するために使うことができます。
robot.respond /have a soda/i, (res) ->
  # ソーダ数を取得する(数値に強制)
  sodasHad = robot.brain.get('totalSodas') * 1 or 0

  if sodasHad > 4
    res.reply "I'm too fizzy.."

  else
    res.reply 'Sure!'

    robot.brain.set 'totalSodas', sodasHad+1
robot.respond /sleep it off/i, (res) ->
  robot.brain.set 'totalSodas', 0
  msg.reply 'zzzzz'

スクリプトがユーザデータを検索する必要がある場合、 user.NameuserForIduserForFuzzyName 、および usersForFuzzyName というID、名前、または「あいまいな」一致で1つまたは複数のユーザを検索するためのrobot.brainのメソッドがあります。
module.exports = (robot) ->

  robot.respond /who is @?([\w .\-]+)\?*$/i, (res) ->
    name = res.match[1].trim()

    users = robot.brain.usersForFuzzyName(name)
    if users.length is 1
      user = users[0]
      # 何か面白いことをここに..

      res.send "#{name} is user - #{user}"

スクリプトのロード

主に3つのソースからスクリプトがロードされます。
  • scripts/ ディレクトリにある hubot インストールに バンドルされているすべてのスクリプト
    hubot-scripts.json で指定した hubot-scripts npm パッケージに含まれている コミュニティスクリプト
  • external-scripts.json で指定された外部の npm パッケージ からロードされるスクリプト

scripts/ ディレクトリから読み込まれたスクリプトは、アルファベット順にロードされるので、スクリプトの一貫したロード順序が期待できます。 例えば:
  • scripts/1-first.coffee
  • scripts/_second.coffee
  • scripts/third.coffee

スクリプトの共有


ロボットの友人の能力を拡張するためのスクリプトをいくつか作成したら、それらを世界と共有することを検討する必要があります。最低限、スクリプトをパッケージ化して Node.js パッケージレジストリ に提出すできです。以下のスクリプトを共有化するためのベストプラクティスについても検討してください。

スクリプトパッケージの作成


Hubot 用のスクリプトパッケージを作成することは非常に簡単です。最初に hobot yeoman ジェネレータをインストールします:

% npm install -g yo generator-hubot

hubot ジェネレータをインストールします。 Hubot スクリプトを作成することは新しいHubotを作成することに似ています。独自のhubotスクリプト用のディレクトリを作成し、それに新しい hubotスクリプト を生成します。 たとえば、 "my-awesome-script" という Hubot
スクリプトを作成する場合は、次のようにします:

% mkdir hubot-my-awesome-script
% cd hubot-my-awesome-script
% yo hubot:script


この時点で、スクリプトの著者、スクリプトの名前(ディレクトリ名で推測される)、簡単な説明、およびキーワード (少なくとも hubot 、このリストの hubot-scripts ) を見つけるための質問が表示されます。

git を使用している場合、生成されたディレクトリには .gitignore が含まれているため、すべてを初期化して追加できます:

% git init
% git add .
% git commit -m "Initial commit"


これで、準備が整った hubot スクリプトリポジトリが完成しました。 あらかじめ作成されている src/awesome-script.coffee ファイルを開いて、スクリプトを作成してください。 準備が整ったら、この文書 にしたがって npmjs に公開することができます!

おそらく、新しいスクリプト用の単体テストを書くことになります。 サンプルのテストスクリプトは、 test/awesome-script-test.coffee に書き込まれます。これは grunt で実行できます。 テストの詳細については、 "Hubot スクリプトのテスト"節を参照してください。

Listenerメタデータ


正規表現とコールバックに加え、 hear 関数と respond 関数もまた任意のメタデータを生成された Listener オブジェクトへ結びつけることができるオプション options Object を受け入れます。このメタデータにより、スクリプトパッケージを変更せずにスクリプトの動作を簡単に拡張することができます。

最も重要で最も一般的なメタデータキーは @id@ です。 すべてのリスナには一意の名前を付ける必要があります ( options.id ; デフォルトは null )。 名前はモジュール (たとえば 'my-module.my-listener')でスコープ化する必要があります。これらの名前は、他のスクリプトが個々のリスナに直接指定し、許可やレート制限のような追加機能を使ってそれらを拡張することを可能にします。

拡張に加えて、追加のメタデータキーを定義し、処理することができます。 詳細については、"Listener ミドルウェア" 節を参照してください。

前の例に戻ります:

module.exports = (robot) ->
  robot.respond /annoy me/, id:'annoyance.start', (msg)
    # 誰かを怒らせるコード

  robot.respond /unannoy me/, id:'annoyance.stop', (msg)
    # 迷惑をかけないようにするコード

これらのスコープ付き識別子を使用すると、次のような新しい動作を外部から指定できます:
  • 権限ポリシ: " annoyers グループの誰もが annoyance.* コマンドを許可する"
  • レート制限:"30分ごとに1回 annoyance.start の実行のみを許可する"

ミドルウェア


ミドルウェアには、Receive (受信)、Listener (リスナ)、Response (応答)の3種類があります。

Receive (受信)ミドルウェアは、リスナーがチェックされる前に1回だけ実行します。
Listener (リスナ)ミドルウェアは、メッセージに一致するすべてのリスナに対して実行します。
Response (応答)ミドルウェアは、メッセージに送信されるすべての応答に対して実行します。

プロセス実行およびAPI


Expressミドルウェアと同様に、Hubot はミドルウェアを定義順に実行します。各ミドルウェアは、( nextを呼ぶことで)チェーンを続行するか、( doneを呼ぶことで)チェーンを中断するかどちらかが可能です。すべてのミドルウェアが継続すると、リスナコールバックが実行され、 done が呼び出されます。ミドルウェアは done コールバックをラップして、(リスナコールバックが実行されたか、ミドルウェアのより深い部分が中断された後)プロセスの後半でコードを実行を許可します。

ミドルウェアは次のように呼び出されます:

context
  • 各ミドルウェアタイプのAPIを参照して、コンテキストが公開する内容を確認
next 
  • プロパティを持たないFunctionで、次のミドルウェアを継続/Listerコールバック実行
  • next が(done 関数か最終的に done がコールされる新たな関数のどちらかを提供するか)を指定する単一のオプション引数付きで呼び出される
  • もし引数が与えられなかったならば、提供された done が責任を負う

done
  • ミドルウェアの実行を中断し、一連の完了関数の実行を開始するために呼び出される追加のプロパティを持たないFunction引数無しで done が呼び出される

すべてのミドルウェアは、 context next 、および done の同一のAPIシグニチャを受け取ります。異なる種類のミドルウェアは、 context オブジェクト内で異なる情報を受け取ることがあります。 詳細は、各タイプのミドルウェアのAPIを参照してください。

エラーハンドリング


(イベントループを生成しない)同期ミドルウェアの場合、標準リスナの場合と同様に、自動的にエラーを検出してエラーイベントを生成します。 Hubot は自動的に最新の完了コールバックを呼び出してミドルウェアスタックを巻き戻します。非同期ミドルウェアは、独自の例外をキャッチし、エラーイベントを発行し、完了を呼び出す必要があります。 キャッチされない例外は、ミドルウェア完了コールバックのすべての実行を中断します。

Listener ミドルウェア


Listener ミドルウェアは、メッセージと一致するリスナと実行中のリスナとの間にロジックを挿入します。これにより、一致するスクリプトごとに実行される拡張機能を作成できます。例には、集中型の認可ポリシ、レート制限、ロギング、およびメトリックが含まれます。ミドルウェアは、他の hubot スクリプトと同様に実装されています。 hear メソッドや respondメソッドを使用する代わりに、ミドルウェアは listenerMiddleware を使用して登録されます。

Lister ミドルウェアの例

完全に機能する例は、 hubot-rate-limit にあります。

ミドルウェアのロギングコマンド実行の簡単な例:

module.exports = (robot) ->
  robot.listenerMiddleware (context, next, done) ->
    # ログコマンド
    robot.logger.info "#{context.response.message.user.name} asked me to #{context.response.message.text}"
    # ミドルウェアの実行を継続
    next()

この例では、リスナに一致するチャットメッセージごとにログメッセージが書き込まれます。

レート制限の決定を行うもっと複雑な例:

module.exports = (robot) ->
  # 最後の実行時にリスナIDをマップ
  lastExecutedTime = {}

  robot.listenerMiddleware (context, next, done) ->
    try
      # リスナが異なる最小期間を指定しない限り、デフォルトは1秒です
      minPeriodMs = context.listener.options?.rateLimits?.minPeriodMs? or 1000

      # コマンドが最近実行されたかどうかを確認
      if lastExecutedTime.hasOwnProperty(context.listener.options.id) and
         lastExecutedTime[context.listener.options.id] > Date.now() - minPeriodMs
        # コマンドがとても早く実行されています!
        done()
      else
        next ->
          lastExecutedTime[context.listener.options.id] = Date.now()
          done()
    catch err
      robot.emit('error', err, context.response)

この例では、ミドルウェアがリスナが最後の1,000msで実行されたかどうかを確認します。存在する場合、ミドルウェアの呼び出しはすぐに完了し、リスナのコールバックが呼び出されないようにします。リスナの実行が許可されている場合、ミドルウェアは完了したハンドラーをアタッチし、リスナーが実行を終了した時刻を記録できるようにします。

またこの例では、リスナ固有のメタデータを使用して非常に強力な拡張機能を作成する方法も示しています:スクリプト開発者がレート制限ミドルウェアに対してミドルウェアを追加しリスナオプションを設定するだけで異なるレートへのより簡単なレート制限コマンドを簡単に使うことができます。

module.exports = (robot) ->
  robot.hear /hello/, id: 'my-hello', rateLimits: {minPeriodMs: 10000}, (msg) ->
    # 10秒に1回以上実行されません
    msg.reply 'Why, hello there!'

Lister ミドルウェア API



リスナのミドルウェアコールバックには、 context next 、そして done という3つの引数があります。 next done については、 ミドルウェアAPIを参照してください。 リスナのミドルウェア・コンテキストには、次のフィールドがあります。
lister
  • options : リスナ定義時のオプションセットを含む単純なObject。 Listenerメタデータ節 を参照のこと。
  • その他全てのプロパティは内部で考慮される。

response
  • 標準レスポンスAPIのすべての部分がミドルウェアAPIに含まれている。 sendおよびreply節を参照のこと。
  • ミドルウェアは応答オブジェクトを追加情報でdecorate (ただしmodifyできない)ことが可能(例:ユーザのLDAPグループを用いて response.message.user にプロパティ追加)
  • 注:テキストメッセージ( response.message.text ) は、リスナミドルウェアで不変であるとみなされるべき

Receive ミドルウェア


Receive (受信) ミドルウェアは、リスナが実行される前に実行されます。 ID、metrics などを追加するように更新されていないコマンドをブラックリストに登録するのに適しています。

Receive ミドルウェアの例


このシンプルなミドルウェアは、 hear リスナを含む特定のユーザによる使用を禁止します。 ユーザが明示的にコマンドを実行しようとすると、エラーメッセージが返されます。

BLACKLISTED_USERS = [
  '12345' # 請負業者のユーザーIDのアクセスを制限
]

robot.receiveMiddleware (context, next, done) ->
  if context.response.message.user.id in BLACKLISTED_USERS
    # このメッセージをこれ以上処理しないこと。
    context.response.message.finish()

    # メッセージが 'hubot'またはエイリアスパターンで始まる場合、
    # このユーザは明示的にコマンドを実行しようとしていたため、
    # エラーメッセージで応答します。
    if context.response.message.text?.match(robot.respondPattern(''))
      context.response.reply "I'm sorry @#{context.response.message.user.name}, but I'm configured to ignore your commands."

    # これ以上ミドルウェアを実行しない。
    done()
  else
    next(done)

Receive ミドルウェア API


Receive ミドルウェアのコールバックは、 context next 、および done という3つの引数を受け取ります。  next done については、 "ミドルウェアAPI":節を参照してください。 Receive ミドルウェア context には、次のフィールドがあります:
response
  • このレスポンスオブジェクトには match プロパティーがない。これはまだ match するリスナがないためである。
  • ミドルウェアは、Receive オブジェクトを追加情報で装飾してもよい(例:ユーザの LDAP グループを用いて response.message.user にプロパティを追加)。
  • ミドルウェアは response.message オブジェクトを変更することがある。

Resonse ミドルウェア


Resonse (応答) ミドルウェアは、 hubot がチャットルームに送信するすべてのメッセージに対して実行されます。 メッセージのフォーマット、パスワードの漏洩、metrics などに役立ちます。

Resonse ミドルウェアの例


この簡単な例では、チャットルームに送信されるリンクの形式を、マークダウンリンク(たとえば " example ":https://example.com/ )から "Slack": でサポートされる形式 ( https://example.com|example ) に変更します。
module.exports = (robot) ->
  robot.responseMiddleware (context, next, done) ->
    return unless context.plaintext?
    context.strings = (string.replace(/\[([^\[\]]*?)\]\((https?:\/\/.*?)\)/, "<$2|$1>") for string in context.strings)
    next()

Resonse ミドルウェア API


Resonse ミドルウェアのコールバックは、 context 、 next 、そして done の3つの引数を受け取ります。  next と done については、 "ミドルウェアAPI":節を参照してください。 Resonse ミドルウェアcontextには、次のフィールドがあります:
response
  • このresponseオブジェクトは、ミドルウェアから新しいメッセージを送信するために使用可能である。 これらの新しい応答に対してミドルウェアが呼び出される。無限ループを作成しないように注意すること。

strings
  • チャットルームアダプタに送信される文字列の配列。 これらの編集や、 context.strings = ["new strings"] を使った置換が可能。

method
  • リスナが送信したresponseメッセージのタイプ( send reply emote topic など)を表す文字列。

plaintext
  • true または undefined 。 メッセージが通常の平文タイプ(送信や返信など)の場合、これは true に設定される。このプロパティは読み取り専用として扱う必要がある。

Hubot スクリプトのテスト


hubot-test-helperは、Hubot スクリプトの単体テストに適したフレームワークです ( hubot-test-helper を使用するには、 Promises をサポートする最近の Node バージョンが必要となります)。

Hubot インスタンスにパッケージをインストールします:

% npm install hubot-test-helper --save-dev


また、次のものをインストールする必要があります:
  • Mocha などの JavaScript テストフレームワーク
  • chai expect.js などのアサーションライブラリ

また、次のものもインストールしたくなるでしょう:
  • coffee-script (JavaScriptではなくCoffeeScriptでテストを書く場合)
  • Sinon.js のような mock ライブラリ(スクリプトがWebサービス呼び出しやその他の非同期アクションを実行する場合)

ここでは、 Hubot サンプルスクリプト の最初の2つのコマンドをテストするサンプルスクリプトを示します。 このスクリプトでは、 Mochachaicoffee-script 、そしてもちろん hubot-test-helper を使用しています:
test/example-test.coffee
Helper = require('hubot-test-helper')
chai = require 'chai'

expect = chai.expect

helper = new Helper('../scripts/example.coffee')

describe 'example script', ->
  beforeEach ->
    @room = helper.createRoom()

  afterEach ->
    @room.destroy()

  it 'doesn\'t need badgers', ->
    @room.user.say('alice', 'did someone call for a badger?').then =>
      expect(@room.messages).to.eql [
        ['alice', 'did someone call for a badger?']
        ['hubot', 'Badgers? BADGERS? WE DON\'T NEED NO STINKIN BADGERS']
      ]

  it 'won\'t open the pod bay doors', ->
    @room.user.say('bob', '@hubot open the pod bay doors').then =>
      expect(@room.messages).to.eql [
        ['bob', '@hubot open the pod bay doors']
        ['hubot', '@bob I\'m afraid I can\'t let you do that.']
      ]

  it 'will open the dutch doors', ->
    @room.user.say('bob', '@hubot open the dutch doors').then =>
      expect(@room.messages).to.eql [
        ['bob', '@hubot open the dutch doors']
        ['hubot', '@bob Opening dutch doors']
      ]
サンプル出力
% mocha --compilers "coffee:coffee-script/register" test/*.coffee


  example script
    ✓ doesn't need badgers
    ✓ won't open the pod bay doors
    ✓ will open the dutch doors


  3 passing (212ms)

以上
----------

この文書を読めば、

  • エラーハンドリングの仕方
  • ロードされる順番
  • コメントもHubothはチェックしている件(特にCommands)
  • タイムアウトやインターバルで遅い場合の応答も可能
  • 永続性ならNoSQL robot.brain
  • N回に1回実行するパターン
  • Listener、Receiveミドルウェア
  • hubot-test-helper およびテストフレームワークの活用によるテスト

といったところが理解できる。


p.s.
以下の記事も書きました。
よろしければ、どうぞ。

Hubot Document: Patterns を翻訳して、チャットボットでありがちな実装を確認する
https://fight-tsk.blogspot.jp/2017/04/hubot-document-patterns.html

2017年4月6日木曜日

見出しをテストする

ずっと疑問に思っていたことを書きます..



Googleのブロガーをつかっているのだけど、
どうも見出しが正しく動いていない気がする。

見出しには、「見出し」、「小見出し」、「準見出し」、「標準」があって
普通に文章を書く場合は自動で「標準」になっている。
この行などは「標準」だ。

とすると、見出しの幾つかは章、節、サブ節となるはずなのだけど、
実際に設定してみると

見出し


小見出し


準見出し


標準


となる。


ブロガのエディタ上では





と見えているので

見出し>小見出し>準見出し

なはずなのに...

画面スナップの少し上を見てもらってわかるとおり
ブログ上では

準見出し>見出し(下になんか黒い線が出る)≒小見出し

となるのだ..



..なぜ?

2017年4月5日水曜日

Hubot のトップページを翻訳してみる

Hubot 自体の説明をしっかりやってくれている記事が以外に少ない事に気づき、とりあえずトップページだけ翻訳してみた。

参照の際、はat your own risk でお願いします。
------------

Hubot とは何ですか?


Hubotはあなたの会社のロボットです。従業員の効率を劇的に改善し、削減するために彼を社内に設置します。
 


いや真剣に訪ねているのです、 Hubot とは何ですか?


GitHub Inc. は、当社のチャットルームを自動化する Hubot の最初のバージョンを書きました。 Hubot は、サイトを展開する方法、多くのタスクを自動化する方法、そして会社の楽しみの厳選を知っていました。 最終的に彼はGitHubの巨大な力に成長しました。 しかし、彼は個人的で面倒な人生を導いてしまった。 だから、我々は彼を書き直しました。

今日のバージョンの Hubot は、 *オープンソース* であり、 *Node.js*  の *CoffeeScript* で書かれており、 *Heroku* のようなプラットフォームに簡単に展開できます。 さらに重要なのは、 Hubot は全員のロボット間でスクリプトを共有するための標準化された手法でもあります。
 


Hubot で何ができるの?


Hubotには、 画像の投稿言語の翻訳Google Mapとの統合 といった小さなスクリプト群が含まれています。また、 コミュニティHubotスクリプトのリポジトリ やあなた自身のロボットに追加できる Hubotパッケージを提供するコミュニティの組織 も維持しています。
 

本当の楽しみはあなた自身のスクリプトを追加するときに起こります。 Hubot もパーソナライズしてください。 あなたの会社のロボットは、内部のジョーク、カスタム統合、および一般的な有名人の完全な場所でなければなりません。

 

自分のHubotスクリプトを書くにはどうすればいいの?


独自のHubotスクリプトを作成する方法については、 このドキュメント を参照してください。 その後、空は限界です(sky's the limit):生成された  scripts ディレクトリに追加してください。

あなたが世界を牽引する Hubot スクリプトを書いたなら、ぜひ私たちに知らせてください。


------------


横っちょにある文章も翻訳しようとしたのだけど..何言ってるか凡人の私にはわからなかった..


Hubot is a way of life. I didn't really invent Hubot as much as he spawned into our existence, ready to take it over like a ten-year-old aimbotting CounterStrike hacker. I wouldn't be surprised if Hubot could come up with the cure for cancer. And then he would disguise it in an animated GIF with the cryptic caption Y U NO CANCER?. I'm actually pretty frightened of the damn thing, now that you bring it up.

私は実際にHubotを発明しませんでした。我々という存在の中から生まれたといっていいでしょう。10才の子供がカウンターストライクハッカーを狙撃するように実際に乗り越えてきました。Hubot が癌の治療法を考え出すことができたとしても、私は驚かないでしょう。そして、そのとき Hubot は暗号めいたキャプション _Y U NO NO CANCER_ というアニメーションGifでそれを隠すかもしれません。本当に私は、あなたがそれを持ち出してくる事をかなり恐れています。


なるほどね..トップページが曖昧なので、このソフトウェアが一体なにができるのかをしっかり説明している記事が少ないんだ..

ただ..hubotの機能にBrainなるものがあったりするし、
前の記事で載せたこの絵



をみなおしてみると。。


そうか


HubotロボットのOS


つまり奴らは..


攻殻機動隊でいう義体のOSにしようとしているのか!

(TensorFlowで書いてるところが電脳ね)



とか、

思ったけど




...ほっておいてください..




まあ、

pepper Adapter は

あっても

いいとはおもった

けどね ;-p


《2017/04/06 追記》
pepperのAdapter、ありました。
https://github.com/nabettu/hubot-pepper

p.s.

ただ..

hubot の読み..

GitHub関係者の話している所を聞いたわけではないけど、

トップページを読んでるとhubotをitでなくheを使ってるあたりから邪推すると

絶対「ひゅーぼっと」だとおもう。


2017年4月4日火曜日

HuBotを使ってRocketChat用のチャットボットを試しに作ってみる

機械学習した会話システムのUIにするチャットシステムとして
docker-composeコマンドで一発起動できるRocketChatを立ち上げた。

次は、チャットボットをあげないといけない。

いろいろ調べると、GitHub御謹製の HuBot を紹介している記事が
ちらほら..

docker-composeでRocketChatと一緒にあげている人もいるが..
運用上、RocketChatはそのままでチャットボットだけ止めたいなんて場合もあるから
個別にあげることにした。

dockerコマンドスクリプトを組むのは厄介なので
別途違うディレクトリで次のようなdocker-compose.ymlを用意した。

version: '2'

services:

  hubot:
    image: rocketchat/hubot-rocketchat:latest
    dns:
      - <社内DNSサーバ IPアドレス1>
      - <社内DNSサーバ IPアドレス2>
      - 160.14.254.1
    dns_search:
      - <社内DNS ドメイン名>
    volumes:
      - ./data/hubot/scripts:/home/hubot/scripts
      - /etc/localtime:/etc/localtime:ro
    environment:
      - ROCKETCHAT_URL=<RocketChatサーバIPアドレス>:<ポート番号>
      - ROCKETCHAT_ROOM=''
      - LISTEN_ON_ALL_PUBLIC=true
      - ROCKETCHAT_USER=administrator.rocketchat
      - ROCKETCHAT_PASSWORD=<administrator.rocketchatのパスワード>
      - BOT_NAME=administrator.rocketchat
      - EXTERNALSCRIPTS=hubot-diagnostics,hubot-help,hubot-seen,hubot-links,hubot-greetings
      - TZ=Asia/Tokyo
      - HTTP_PROXY=http://<社内Proxyサーバ IPアドレス>:<ポート番号>
      - HTTPS_PROXY=http://<社内Proxyサーバ IPアドレス>:<ポート番号>
      - NO_PROXY=localhost,127.0.0.1,*.<社内DNS ドメイン名>
    labels:
      - traefik.enable=false
    ports:
      - 3332:8080

docker-compose する前に ./data/hubot/scripts ディレクトリを切っておく。
このディレクトリの下に自分のチャットボットcoffeeスクリプトを置き、docker-compose stop && docker-compose up -d すれば反映される。

たとえば以下のような簡単なCoffeeスクリプトサンプル hello.coffee を配置し、

# Commands:
#  hubot hello

module.exports = (robot) ->
  robot.respond /hello$/i, (msg) ->
    msg.send "World"

再起動すると、
正しく動いている場合は
上記の設定ではRocketChat上のパブリックなチャネルには
 adminiostrator.rocketchat というユーザが存在し、
緑ポチ(接続中)になっているはずだ。

たとえば #general に入って、「administrator.rocketchat hello」と入力すると、



すぐにadministrator.rocketchatユーザから「World」という返信が表示されるはずだ。



FreeIPA連携のときユーザ名を #{givenName}.#{sn} にしちゃって、ユーザIDも同じ名前にしちゃったもんだから、ユーザIDが長くなりめんどくさくなってしまった..ここらは、各自で直してください。


あとはtensorflow + FlaskでREST API化した会話システムAPIを呼び出し、返信するようなCoffeeスクリプトを掛けば良い











..んだけど..

Coffeeスクリプトの書き方を勉強しないと..


あれ、Coffeeスクリプトは時代遅れって記事もあるなあ..

さて、どうするか..

2017年4月3日月曜日

RocketChatのChannel追加方法がわからない

RocketChatを動かし、
いざ独自のチャネルを作ってみようとして
Web UI でどうやって追加すればわからないヒトは
以下のスナップショットの赤枠を参照のこと。










意外と見落とす人、おおかったり。

FreeIPA連携によるRocket.Chatへのログインの設定を調べる

FreeIPAのLDAP構成はデフォルト設定のままで運用しているのだけど、
RocketChatのLDAP設定を行ってFreeIPAアカウントでもログインできるようにしようと
色々ためしてみてがようやく繋がる設定を見つけた。

FreeIPAサーバ:
 IP アドレス:xxx.xxxx.xxxx.xxxx
 管理ユーザ:admin
 パスワード:password
 ドメイン:hara2dev.local (dc=har2dev,dc=local)



とした場合、

Rocket Chatサーバを起動し、最初のユーザ登録を完了したら
そのユーザでログインし、以下の操作を実行すればよい。

・左上のユーザ名をクリック>管理>LDAPを選択
・有効にする「はい
・ホスト「xxx.xxxx.xxxx.xxxx
・ポート「389
・ドメインベース「cn=users,cn=accounts,dc=har2dev,dc=local
・ドメイン検索ユーザ「uid=admin,cn=users,cn=accounts,dc=har2dev,dc=local
・ドメイン検索のパスワード「password
・ドメイン検索ユーザID「uid
・ドメイン検索のobjectclass「(空欄)
・ドメイン検索のobjectCategory「(空欄)
・ユーザー名フィールド「#{givenName}.#{sn}」(名前.名字)か「uid」(uid文字列)
・一意性を識別するフィールド「objectGUID,ibm-entryUUID,GUID,dominoUNID,nsuniqueId,uidNumber」(変更なし)
・データを同期する「はい
・ユーザーデータのフィールドマップ「{"cn":"name", "mail":"email"}」(変更なし)
・既定ドメイン「(空欄)
・右上の変更を保存ボタン押下(エラーなしを確認
・接続テスト「接続をテスト」ボタン押下(正常動作確認
・ユーザーを同期する「ユーザーを同期」ボタン押下(正常動作確認
・ログアウトして、FreeIPAに登録済みアカウント&パスワードでログインする。

最初にログインすると、RocketChat側にユーザが新規作成されます。
上記設定の場合、LDAP認証が失敗したら、RocketChat上のアカウントで認証チェックをかけるので、FreeIPAがおちている時もログインさせたい場合はこのようにします。

1点だけ注意。

RocketChatは、ユーザごとに一意となるメールアカウントがデフォルトでは必須で、
uid=<ユーザID>,cn=users,cn=accounts,dc=har2dev,dc=local」の属性mailN/A、つまりFreeIPA上のアカウントのメールアドレスが空欄だとログイン失敗します。


p.s.
Dockerコンテナで、RocketChatを上げたい場合は、
以下のdocker-compose.ymlを作成し、 
./data/mongo/db./data/mongo/dumpを作成して
sudo docker-compose up -dすれば
http://xxx.xxxx.xxxx.yyyy:3000/でログイン画面がでてきます。

version: '2'

services:

  mongo:
    image: mongo:latest
    volumes:
      - ./data/mongo/db:/data/db
      - ./data/mongo/dump:/dump
    command: mongod --smallfiles

  rocketchat:
    image: rocketchat/rocket.chat:latest
    depends_on:
      - mongo
    dns:
      - 8.8.8.8
    environment:
      - MONGO_URL=mongodb://mongo:27017/rocketchat
      - ROOT_URL=http://xxx.xxxx.xxxx.yyyy
      - Accounts_UseDNSDomainCheck=false
      - TZ=Asia/Tokyo
    ports:
      - 3000:3000

2017年3月29日水曜日

「光陰矢のごとし」な話

..どうでもいい話ですが..


Sequence-to-Sequenceの学習はぶんまわしたまんまで、
TensorFlowのdecoder用Dockerコンテナをつくっておこうと
おもい、せっかくならgcr.io/tensorflow/tensorflowでなくtensorflow/tensorflowでつくろうとした。

..ら新しいコンテナでモデルが復元できない..

どうも変数スコープ名が変わったらしい..

おや..とおもい、pip3 listしたら..

tensorflow (1.1.0)

..ん?

TensorFlowのlatest
5日前に
1.1.0rc0にバージョン上がっとるやんけ!

...ご注意ください。


というか、
マジ開発者はlatestなんて甘いタグでpullしてる時点で
おバカまるだしってことか..

ひえ~

2017年3月9日木曜日

CloudStackのコンソール画面が出なくなった

CloudStack4.2.1を使っているのだけど、先日突然次のようが画面が出てmanagerのコンソール画面が表示できなくなった。




動いているVM上のOSはLinux、Windows関係なく。

VM自体は生きているので、ssh接続やリモートデスクトップ接続は可能な状態だ。

もう5年位か、これまで問題なく動いてきたのになあ..


と、思って調べてみたら..ルート証明書の期限が切れてた..

半年後もう1台あげてるから、そっちもゆくゆくは切れるのね..



そうか、HDDの寿命は4年だから、それくらいにはOpenStackも安定してきてるだろうから
入れ替えるだろうと思って5年にしてたんだっけ..


そういや最近はCloudStackもOpenStackもあんまり頑張って入れようって人いなくなったなあ..

ケチ臭くなって、OS上にコンテナ複数立てて使ってるか、クラウドのIaaSのどっちかだもんね..

1vCPU4MBメモリのCloudStack インスタンス上に redmine, jenkins, subversion, postgresql, ownCloudの5つのコンテナあげて、親OSのFreeIPAとRoundcubeでユーザLDAP/メールまで一元管理するケチケチプロジェクト支援サーバでやりくりしてるし..

OpenStackなんか入れるラック買いましょうなんて、今役員に稟議だしたら正気かを疑われてしまう..

..のは言い過ぎか..


..にしても、せちがない世の中になったなあ..



..直すか..

2017年3月7日火曜日

会話モデルをSeq2seqで動かしてもちっとも対話できないので焦ってネタ元論文を翻訳してみる




翻訳に使われているモデル seq2seq で対話もできるときいたので、
やってみたのだけど..

..一向に話をしようとしない..

たとえば、

> こんにちは、ごきげんいかが。
そんなに そんなに そんなに どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう
 どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう どう
どう どう どう どう どう どう どう どう どう どう

とか、

> こんにちは。
出し 出し 出し 」 話し 話し 話し 話し 話し 話し 話し 話し 話し 話し 話し 話し 話し 話し 話し 話し やろ や
ろ 作っ 作っ ? ? 作っ 例えば ? ? 例えば ? 例えば ? 例えば ? 例えば ? 例えば 大丈夫 大丈夫 大丈夫
大丈夫 大丈夫 作っ 作っ ? ? 作っ ?

とかで、全然答えはおろか、類似単語ですら無い..



しかも、狂気を感じる..

キメラを錬成しようとして、キ^H^Hになったタッカーさんとか、ちょっとよぎってしまった。


ちなみに、あんなかわいい子供はいないのでご安心を..(●者の石はおろか、●金技術自体ありませんよ;-p)







..話を戻して..

本当に、 sequence-to-sequence モデルで実現可能なのだろうか..

ということで、皆がやっている論拠にしている元ネタ論文を見つけた。

A Neural Conversational Model
http://lion.exa-corp.co.jp/redmine/attachments/download/2240/1506.05869v1.pdf

著者のメールアカウントからすると、Google社員らしい..


で、いつものように翻訳してみた。
参照の際は、at your own risk でお願いします。

先にいっておくと、
この論文を読むにはそれほど技術力やを必要としない
数式も全く出てこない
Seq2Seqモデルの中身を知らなくても、まあ読むことは可能なので
会話型モデルを機械学習で挑戦しようとする人は
一度は目を通しておいたほうが良い

中身は殆ど実行した結果、どんな対話ができるかをしめしているだけなのだけど
コレくらいの精度はでてる人がいる事がわかるのだ。

Seq2Seqモデルを下手にいじってしまう前に、
まずこのくらいの精度がでるコーパスをまず用意せよ
ということだ、と読んだ。

---

会話型ニューラルモデル (A Neural Conversational Model)



著者:Oriol Vinyals VINYALS@GOOGLE.COM Google、Quoc V.Le QVL@GOOGLE.COM Google

概要


会話型モデリングは、自然言語の理解と機械インテリジェンスの重要なタスクである。以前のアプローチは存在するが、それらはしばしば特定のドメイン(例えば、航空券の予約)に限定され、手作りのルールを必要としていた。本稿では、提案したシーケンスをシーケンスフレームワークに適用した簡単な手法を提案する。我々のモデルは、会話の前のセンテンス、またはセンテンスを与えられた次のセンテンスを予測することによって会話する。我々のモデルの強みは、それがエンドツーエンドで訓練できるため、手作りのルールがはるかに少なくなることにある。このシンプルなモデルは、大きな会話訓練データセットを仮定すると、簡単な会話を生成することができる。我々はまず、間違った目的関数を最適化しているにもかかわらず、ドメイン特有のデータセットと、映画サブタイトルの大きなノイズの多い一般的なドメインデータセットの両方から知識を抽出できることを示唆する。 ドメイン固有のITヘルプデスクデータセットでは、モデルは会話を通じて技術的問題の解決策を見つけることができる。ノイズの多いオープンドメイン映画のトランスクリプトデータセットでは、モデルは簡単な形の常識推論を実行できる。予想通り、一貫性の欠如が我々のモデルの一般的な失敗モードであることも判明する。

1. はじめに


ニューラルネットワークのエンドツーエンドトレーニングの進歩は、音声認識、コンピュータビジョン、言語処理など、多くの分野で目覚しい進歩をもたらした。最近の研究では、ニューラルネットワークは単純な分類だけでなく、複雑な構造を他の複雑な構造にマッピングするために使用できることが示唆されている。これの一例は、自然言語理解の直接の応用を有する別のシーケンスにシーケンスをマッピングするタスクがある(Sutskever et al., 2014)。このフレームワークの主な利点の1つは、最先端の結果と一致しているかそれを上回っている間に、特徴量設計とドメインの特異性がほとんど必要ないことにある。この進歩により、研究者がドメイン知識が容易に利用できないタスクや単純にモデル化するのが難しいタスクに取り組むことを可能にする、というのが我々の見解である。

会話型モデリングは、クエリと応答の間のマッピングを必要とするため、この定式化から直接利益を得ることができる。このマッピングの複雑さのために、会話型モデリングは、以前は特徴量設計を主な作業としてドメインを非常に狭くして設計していた。この作業では、会話モデリングタスクを、再帰的ネットワークを使用して前のシーケンスまたはシーケンスを与えられた次のシーケンスを予測するタスクにキャスティングすることで実現する(Sutskever et al., 2014)。このアプローチは、会話への流暢で正確な返答を生成する上で驚くほどうまくいくことがわかる。

ITヘルプデスクの会話のデータセットからチャットセッションのモデルをテストし、そのモデルが問題を追跡してユーザーに役立つ回答を提供することがあることを確認する。また、映画サブタイトルのノイズの多いデータセットから得られた会話を実験し、モデルが自然な会話を保持し、時には簡単な常識推論の形式を実行できることを確認する。どちらの場合も、リカレントネットは、nグラムモデルと比較してより良い予測性能を取得し、重要なロングレンジ相関を捕捉する。定性的な観点から、私たちのモデルは時には自然な会話を生み出すことができる。

2.関連する研究


我々のアプローチは、シーケンスをシーケンスにマッピングするためにニューラルネットワークを使用することを提案した最近の研究に基づいている(Kalchbrenner & Blunsom, 2013; Sutskever et al., 2014; Bahdanau et al., 2014)。このフレームワークはニューラルマシンの翻訳に使用されており、WMT'14データセットからの英仏および英独翻訳作業の改善を実現している(Luong et al., 2014; Jean et al., 2014)。これは、解析(Vinyals et al。、2014a)やイメージキャプション(Vinyals et al。、2014b)などの他のタスクにも使用されている。バニラRNNが消失勾配に苦しんでいることはよく知られているので、ほとんどの研究者はLSTM(Long Short Term Memory)リカレントニューラルネットワークの変種を使用している(Hochreiter & Schmidhuber, 1997)。

我々の研究は、最近のニューラル言語モデリングの成功(Bengio et al., 2003; Mikolov et al., 2010; Mikolov, 2012)にも影響を受けている。最近では、Sordoni ほかの論文や (Sordoni et al., 2015)およびShangほかの論文(Shang et al., 2015)は、リバースニューラルネットワークを使用して、短い会話での対話をモデル化した(Twitterスタイルのチャットを訓練)。

ここ数十年に渡って、多くの研究者がボットと会話エージェントを構築してきたが、参考文献の網羅的なリストを提供すること自体はこの論文の範囲外である。しかし、これらのシステムの大半は、多くの段階のかなり複雑な処理パイプラインを必要とする(Lester et al., 2004; Will, 2007; Jurafsky & Martin, 2009)。私たちの仕事は、ドメイン知識が不足している問題に対するエンドツーエンドのアプローチを提案することであり、従来のシステムとは異なっている。原則として他のシステムと組み合わせて候補回答のリストを再採点することができるが、私たちの仕事は、いくつかの文脈で回答の確率を最大にするよう訓練された確率モデルによって与えられる回答に基づいている。

3.モデル


我々のアプローチは、(Sutskever et al., 2014)に記載されている sequence to sequence _(seq2seq)_ モデルを利用する。このモデルは、入力シーケンスを一度に1トークンずつ読み込み、出力シーケンスを一度に1トークンだけ予測するリカレントニューラルネットワークに基づいている。トレーニング中に真の出力シーケンスがモデルに与えられるので、学習はバックプロパゲーションによって行うことができる。モデルは、その文脈を考慮して正しいシーケンスのクロスエントロピーを最大にするように訓練される。推論の間、真の出力シーケンスが観測されないと仮定すると、予測された出力トークンを入力として供給して、次の出力を予測するだけである。これは「貪欲な」推論アプローチである。あまり欲張っていないアプローチは、ビーム探索を使用して、前のステップでいくつかの候補を次のステップに送る。予測されたシーケンスは、シーケンスの確率に基づいて選択することができる。

具体的には、たとえば最初の人が「ABC」を発声し、もう1人が「WXYZ」と応答する会話を観察すると仮定する。図1に示すように、リカレントニューラルネットワークを使用して「ABC」と「WXYZ」をマッピングすることができる。

 


図1. 会話をモデル化するための seq2seq フレームワークの使用

シーケンス・シンボル " < eos > "の終わりを受け取った時のモデルの隠れた状態は、文の情報、すなわち 「ABC」の情報を格納しているので、思考ベクトルとして見ることができる。

このモデルの強みは、そのシンプルさと一般性にある。このモデルは、機械翻訳、質問/回答、および会話に大きな変更を加えることなく使用できる。

しかし、翻訳のようなより簡単なタスクとは異なり、一連のシーケンスのようなモデルは、いくつかの明白な単純化のためにモデリング対話の問題を首尾良く "解決"できない。最適化された目的関数は、典型的には長期間であり、次のステップ予測ではなく情報の交換に基づいている。一貫性と一般的な世界知識を確実にするモデルがないことは、純粋に監督されていないモデルの別の明らかな制限でである。

4. データセット


実験では、クローズドドメインのITヘルプデスクのトラブルシューティングデータセットとオープンドメインの動画転写データセットという2つのデータセットを使用した。 2つのデータセットの詳細は次のとおりである。

4.1. ITヘルプデスクトラブルシューティングデータセット


最初の一連の実験では、ITヘルプデスクのチャットサービスのトラブルシューティングから抽出されたデータセットを使用した。 このサービスでは、顧客はコンピュータ関連の問題に取り組んでおり、スペシャリストはソリューションへのウォークスルーを補助している。 典型的な対話(またはスレッド)は長さが400語であり、ターンテイクは明確に通知されている。 我々のトレーニングセットには30Mのトークンが含まれており、3Mのトークンが検証として使用された。 その際、いくつかクリーンアップが実行されている。たとえば、一般的な名前、数字、完全なURLの削除などである。

4.2. OpenSubtitles データセット


また、 OpenSubtitles データセット(Tiedemann, 2009)をつかってモデルを実験した。このデータセットは、XML形式のムービーの会話で構成されている。映画に登場する人物の文章が含まれている。データセットからXMLタグと明白な非会話テキスト(ハイパーリンクなど)を削除する簡単な処理ステップを適用した。ターンテイクが明確に示されていないので、異なる文章で発話されたと仮定して連続文を扱った。我々はモデルを訓練して、前の文を次の文で予測し、すべての文に対してこれを実行した(各文が文脈とターゲットの両方に使用されるので、データセットのサイズが2倍になる)。我々の訓練と検証の分割は、トレーニングのサンプルとして62M文(923Mトークン)を使い、検証セットは26M文(395Mトークン)を使った。分割は、一対の文の各センテンスがトレーニングセットまたはテストセットに一緒に現れるが、両方ではないように行われた。前のデータセットとは異なり、 OpenSubtitle はかなり大きく、連続した文章が同じ文字で発音される可能性があるため、かなりノイズが多い。映画の範囲を考えると、これはオープンドメインの会話データセットであり、技術的なトラブルシューティングのデータセットとは対照的である。

5. 実験


この章では、2つのデータセットを使用した実験結果について説明する。我々は客観的な尺度としてテストセット上のモデルの予測性能で表現する。 また我々が訓練したシステムとの相互作用のサンプルをいくつか示す。
 

5.1 IT ヘルプデスクトラブルシューティングの実験


このドメイン特有のクリーンなデータセットのデータが不足しているため、勾配クリッピングを伴う確率的勾配降下を用いて1024個のメモリセルを有する単一層LSTMを訓練した。 私たちは最も一般的な20K単語の語彙を作り、ターン・テイク・アンド・アクターを示す特別なトークンを導入した。

収束時には、このモデルは予測性能 8 を達成したが、n グラムモデルは 18 に達した。以下は、アクタ「マシン」が Neural Conversational Modelであり、アクタ「人間」がマシンと対話するシミュレートされたトラブルシューティングセッションのサンプルである。

 

会話1: VPNの問題


問題説明 :VPNアクセス時に問題発生
 

Machine: hi
         (ハイ)
Human: hello
       (こんにちは)
Machine: could you please let me know what are the operating systems you are using ?
         (使用しているオペレーティングシステムについて教えてもらえませんか?)
Human: i am using linux
       (Linuxを使ってます。)
Machine: ok it was in the ssl vpn on which you stated it was broken
         (OK、あなたが壊れたと状態付けたモノはSSL VPN上にありました)
Machine: please check if you are logged in to corp network
         (社内ネットワークにログインしているかどうか確認してください)
Machine: what is the error that you are running please
         (動作中のエラーは何ですか、プリーズ)
Human: i am seeing an error related to vpn
       (VPN関連のエラーに見えます。)
Machine: what is the error message that you are getting when connecting to vpn using network connect ?
         (ネットワーク接続を使用してVPN接続する際に表示されるエラーメッセージは何ですか?)
Human: connection refused or something like that
       (「connection refused」とそれに類するものですね。)
Machine: may i know the version of network connect you connect ?
         あなたが接続しているネットワーク接続のバージョンを知るかもしれませんか?)
Human: i am not sure i know that
       (よくわかりません。)
Machine: is the network connect prompting for any user certificate
         (ネットワーク接続はユーザ証明書を表示していますか)
Machine: ?
       (?)
Human: yes
       (はい)
Machine: are you at home or at work at the moment?
         (家ですか、それとも職場ですか?)
Machine: office ?
         (職場?)
Human: i am at home
       (家です)
Machine: try this
         (こちらを試しなさい)
Machine: goto <URL> page and enter your name and password
         (<URL>ページへ進み、名前とパスワードを入力しなさい)
Human: done
       (やりました)
Machine: try logging in with <NAME> and check if its working fine now
         (<NAME>でログインを試し、今すぐ動作を確認しなさい)
Human: yes , now it works !
       (はい、動きました!)
Machine: great
         (すばらしい)
Machine: anything else that i can help
         (他になにか助けることありますか)
Human: no , that was very useful
       (いいえ、とっても便利でした。)
Machine: you are other than<NAME> : )
         (あなたは<NAME>以外です :)  ←多分、洒落的な返事らしい)
Machine: have a nice night
         (良い夜を)


会話2: VPNの問題


問題説明 :ブラウザのクラッシュ
 

Machine: hi
         (ハイ)
Human: hi
       (ハイ)
Machine: could you please let me know what is the operating system you are using ?
         (使用しているオペレーティングシステムは何か教えていただけませんか?)
Human: linux
Machine: ok this is the issue with the system performance, nasser , tools .
         (OK、これはシステムパフォーマンス、ナッサー、ツールの問題です。)
Human: what is that ?
       (なんだって?)
Machine: is it a windows machine ?
         (Windowマシンですか?)
Machine: we have linux on your machine .
         (我々はあなたのマシン上にLinuxを保有しています。)
Machine: is it windows xp or windows 7 ?
          (WindowsXPもしくはWindows7ですか?)
Human: i am using linux
       (Linixを使ってます)
Machine: let me take a remote of your machine and check if issue has been pushed properly .
         (マシンをリモートで使って、問題が適切にプッシュされているかどうかを確認します。)
Human: ok
       (OK)
Machine: please open terminal and run the below commands in one computer :
         (ターミナルを開いて、次のコマンドを実行してください:)
Machine: sudo apt-get update
Machine: sudo apt-get upgrade
Machine: sudo <COMMAND>-updater
Human: done
       (やった)
Machine: let me try connecting now
         (今すぐ接続してみましょう)
Human: ok
       (OK)
Machine: its done
         (やった。)
Machine: should use the second or hit run on the background
         (2回目を使ってバックグラウンドで実行すべき)
Human: done
       (やったよ。)
Machine: try signing out now and follow the prompts as per the message given above
         (今すぐサインアウトし、上記のメッセージに従ってプロンプトに従ってください)
Machine: shd i reboot the machine .
         (マシンをリブートしてもいい?)
Human: ok , please go ahead
       (OK、進めて。)
Machine: once its completed please try to login.
         (完了したらログインしてください。)
Human: sure
       (はい。)
Machine: please ping me back once you have tried to login
         (ログインしようとしたら、私にpingしてください)
Machine: are we still connected
         (私たちはまだ接続していますか)
Human: i now logged in
       (ログインしたよ。)
Machine: thanks for your confirmation
         (ご確認いただきありがとうございます)
Human: what should i do now ?
       (何をしたら良いの?)
Machine: wait for 1 5 minutes to complete the login policy
         (ログインポリシーを完了するために1 5分間待ちなさい)
Machine: and then try logging in
         (そしてログインシてみてください)
Human: ok
       (OK)
Machine: is there anything else to help you ?
         (ほかにお助けすることはありますか?)
Human: let my try browsing a little bit and if it keeps crashing i will let you know
       (ちょっとブラウズしたら、すぐこわれるんだ。)
Machine: sure will do
         (確かに、やってみます。)
Machine: seems the mail is not loading
         (メールがロードされていないようようです)
Machine: are we still connected to the chat ?
         (まだチャットに接続していますか?)
Machine: <reinvite>
         (再接続)
Human: it seems good now , cool , thank you , bye
       (良くなったみたい、クール、ありがとう、バイ。)
Machine: you , too
         (あなたも)
Machine: bye
         (バイ)


会話3:パスワードの問題


問題説明 :自分のパスワードを忘れた
 

Machine: hi , this is <NAME> from helpdesk connect , what can i help you with today ?
           (こんにちは、これはヘルプデスクの連絡先からの<名前>です。今日は何ができますか?)
Human: hi , i forgot my password
       (ハイ、パスワードをわすれました。)
Machine: ok great
         (OK、グレート)
Human: can you tell me how i can recover it ?
       (回復方法を教えて?)
Machine: i ’ ll need to verify who it is at that machine
         (そのマシンに誰がいるのかを確認する必要があります)
Machine: can we do a hangout
         (我々とハングアウトできますか)
Machine: ?
Human: yes
       (はい)
Machine: <anonymized hangout instructions and verifications>
         (匿名のハングアウトの手順と確認)
Human: cool , i am good now
       (クール、今良くなりました。)
Machine: how ’ s this looking good ?
         (見栄えはどうですか?)
Machine: i ’ ll go ahead and close this chat .
         (先に進めます、このチャットを閉じます。)
Machine: take care . : )
         (お気をつけて:))
Human: bye
       (さようなら)
Machine: bye .
         (さようなら)


5.2. OpenSubtitles の実験


勾配クリッピングをつかった AdaGradを使用して2層のLSTMを訓練した。

LSTMの各層には4096個のメモリセルがあり、最も頻繁に使用される100K語からなる語彙を作成した。ソフトマックスを高速化するために、メモリセルを2048線形単位に投影してから、情報を分類器に供給する。

興味深いことに、(Bahdanau et al., 2014)のソフト・アテンション・メカニズムを追加しても、どちらのモデルでも予測性能は大幅に改善されなかった。コンバージェンス時の再現モデルの予測性能は 17 であった。訓練または検証セットのどちらでもなかった。

複雑さに関する客観的評価に加えて、我々の単純な反復モデルはしばしばもっともらしい解答を生む。ここでは、映画の OpenSubtitles の騒々しい大規模なデータセットで訓練を受けたときに、モデルの機能をテストするための質問と回答のペアをいくつか紹介する。前のデータセットとは異なり、ここでは対話モデルで使用されるコンテキストは以下の質問に限定されている。

 

会話1:基本


Human: hello !
Machine: hello !
         (こんにちは!)
Human: how are you ?
       (気分はいかが?)
Machine: i ’m good .
         (いいですよ。)
Human: what ’s your name ?
       (あなたのお名前は?)
Machine: i ’m julia .
         (私はジュリアです。)
Human: when were you born ?
       (生年月日は?)
Machine: july 20th .
         (7月20日。)
Human: what year were you born ?
       (何年生まれですか?)
Machine: 1977 .
         (1997年。)
Human: where are you from ?
       (どこ出身ですか?)
Machine: i ’m out in the boonies.
         (私はボニーズの外にでいます。)
Human: are you a man or a woman ?
       (あなたは男性、それとも女性?)
Machine: i ’m a woman .
         (私は女性です。)
Human: why are we here ?
       (なぜ私達はここにいるの?)
Machine: i ’m not sure .
         (わかりません。)
Human: okay, bye !
       (オッケー、じゃあね!)
Machine: bye .
       (さようなら。)
Human: see you later .
       (またね。)
Machine: bye .
       (さようなら。)


会話2:簡単なQ&A(文脈と複数選択)


Human: my name is david . what is my name ?
       私の名前はデビットです。 私の名前は何ですか ?
Machine: david .
         (デビッド。)
Human: my name is john . what is my name ?
       (私の名前はジョンです。 私の名前は何ですか ?)
Machine: john .
         (ジョン。)
Human: are you a leader or a follower ?
       (あなたはリーダーですか、それともフォロワーですか?)
Machine: i ’m a leader .
         (私はリーダーです。)
Human: are you a follower or a leader ?
       (あなたはフォロワーですか、リーダーですか?)
Machine: i ’m a leader .
         (私はリーダーです。)


会話3:一般知識Q&A


Human: who is skywalker ?
       (スカイウォーカって誰?)
Machine: he is a hero .
         (彼はヒーローです。)
Human: who is bill clinton ?
       (ビル クリントンって誰?)
Machine: he ’s a billionaire .
         (彼は、億万長者です。)
Human: is sky blue or black ?
       (空は青、それとも黒?)
Machine: blue .
         (青。)
Human: does a cat have a tail ?
       (猫は尻尾がある?)
Machine: yes .
         (はい。)
Human: does a cat have a wing ?
       (猫は翼がある?)
Machine: no
         (いいえ。)
Human: can a cat fly ?
       (猫は飛べる?)
Machine: no .
         (いいえ。)
Human: how many legs does a cat have ?
       (猫は何本足?)
Machine: four , i think .
         (4本、思うに。)
Human: how many legs does a spider have ?
       (蜘蛛は何本足?)
Machine: three , i think .
         (3本、思うに。)
Human: how many legs does a centipede have ?
       (ムカデは何本足?)
Machine: eight .
         (8本。)
Human: what is the color of the sky ?
       (空は何色?)
Machine: blue .
         (青。)
Human: what is the color of water ?
       (水の色は何色?)
Machine: water .
         (水色。)
Human: what is the color of blood ?
       (血は何色?)
Machine: it is the same as a black eye .
         (黒目と同じ色です。)
Human: what is the usual color of a leaf ?
       (葉の色は普通何色?)
Machine: it is a green one .
         (それは緑色です。)
Human: what is the color of a yellow car ?
       (黄色い車は何色?)
Machine: yellow .
         (黄色。)
Human: how much is two plus two ?
       (2足す2は?)
Machine: four .
         (4。)
Human: how much is ten minus two ?
       (10引く2は?)
Machine: seventy - two .
         (72。)

 

会話4:哲学的Q&A


Human: what is moral ?
      (道徳的とは何?)
Machine: what empowered humanity , what intellectual the essence is .
         (人類に何を与え、知性が本質であるか。)
Human: what is immoral ?
       (道徳的ではないとは何?)
Machine: the fact that you have a child .
         (子供がいるという事実。)
Human: what is morality ?
       (道徳とは何?)
Machine: what is altruism ?
         (利他主義とは何?)
Human: what is the definition of altruism ?
       (利他主義との違いは何?)
Machine: if you don ’t believe in god , then you don ’t know .
         (あなたが神を信じないならば、あなたは知らない。)
Human: ok ... so what is the definition of morality ?
       (OK ...だから、道徳の定義は何ですか?)
Machine: well , the truth is , you ’re not a believer in god almighty .
         (まあ、真実は、あなたは神の全能者を信じていないということです。)
Human: tell me the definition of morality , i am quite upset now !
       (道徳の定義を教えてください、私は今かなり混乱しています!)
Machine: i ’m not ashamed of being a philosopher !
         (私は哲学者であることを恥じない!)
Human: tell me the definition of morality .
       (道徳の違いを教えなさい。)
Machine: i don ’t have ethics .
         (果たしは倫理を持っていない。)
Human: look , i need help , i need to know more about morality ...
       (見て、私は助けが必要です。もっと道徳について知らなくてはならないんだ...)
Machine: i don ’t know what ethics is .
         (私は倫理が何であるか知らない。)
Human: seriously , what is morality ?
       (真剣に、道徳は何か教えてください?)
Machine: what is the definition of living ?
         (生きることとの違いは何?)
Human: why living has anything to do with morality ?
       (なぜ生き方は道徳と関係がありますか?)
Machine: you ’re not a cop .
         (あなたは警官ではありません。)
Human: okay , i need to know how should i behave morally ...
       (オッケー、私は道徳的に行動すべきであることを知る必要がある...)
Machine: i don ’t know how to tell you .
         (私はあなたに説明する方法を知らない。)
Human: is morality and ethics the same ?
       (道徳と倫理は同じですか?)
Machine: yes , sir .
         (イエッサー)
Human: what are the things that i do to be immoral ?
       (私が不道徳なことは何ですか?)
Machine: i don ’t know .
         (私は知らない。)
Human: give me some examples of moral actions ...
       (道徳的な行動のサンプルを教えてください..)
Machine: i ’m not a moralist .
         (私は道徳主義者ではない。)
Human: alright , morality ?
       (オーライ、道徳?)
Machine: integrity .
         (完全性。)
Human: what is integrity ?
       (完全性とは何ですか?)
Machine: i ’m sorry , i don ’t know what else to say .
         (すみません、すみません、他に何が言いたいのか分かりません。)
Human: be moral !
       (道徳的であることだよ!)
Machine: be a man !
         (男子たれ! ←意訳)
Human: i really like our discussion on morality and ethics ...
       (私は道徳と倫理に関する議論が本当に好きです...)
Machine: and how i ’m not in the mood for a philosophical debate .
         (そして、私は哲学的な議論の気分ではない。)
Human: what do you like to talk about ?
       (あなたは何について話したいの?)
Machine: nothing .
         (何も。)


会話6:意見


(「he」、「she」または「it」というモデル出力は、尋ねられている主題によって異なる)


Human: what do you think about tesla ?
       (テスラについてどう思いますか?)
Machine: he ’s a good conductor .
         (彼は良い指揮者です。)
Human: what do you think about bill gates ?
       (ビル・ゲイツにつてどう思いますか?)
Machine: he ’s a good man .
         (彼はいい人です。)
Human: What do you think about messi ?
       (メッシについてどう思いますか?)
Machine: he ’s a great player .
         (彼は偉大なプレーヤーです。)
Human: what do you think about cleopatra ?
       (クレオパトラについてどう思いますか?)
Machine: oh , she ’s very regal .
         (ああ、彼女はとても威張っています。)
Human: what do you think about england during the reign of elizabeth ?
       (エリザベス(女王)の大英帝国についてどう思いますか?)
Machine: it was a great place .
         (素晴らしい場所でした。)



我々はモデルが事実を覚え、文脈を理解し、伝統的なパイプラインの複雑さをなくして常識の推論を実行できることを奨励している。驚くことに、単語ベクトルのパラメータを除いて、モデルが明示的知識表現コンポーネントなしで動作する。

おそらく最も実際的に重要なのは、モデルが新しい質問に一般化できるという事実である。言い換えれば、質問を既存のデータベースに照合するだけでは、単に回答を検索するだけではない。実際、上記の質問のほとんどは、最初の会話を除き、トレーニングセットには表示されない。

にもかかわらず、この基本的なモデルの欠点の1つは、上に見られるように、単純で短く、時には不満足な答えを私たちの質問に与えることである。おそらくより問題のある欠点は、モデルが一貫した性格を捉えていないことである。確かに、同一ではないが意味的に類似した質問をすると、答えが矛盾することがある。これは、実験のモデルとデータセットの単純さのためにであると予想される。以下の会話はそのような失敗を示している:

 

会話7:仕事と人格


Human: what is your job ?
       (あなたの仕事は何?)
Machine: i ’m a lawyer .
         (私は弁護士です。)
Human: what do you do ?
       (あなたの職業は?)
Machine: i ’m a doctor .
         (私は医者です。)



最後に、ルールベースの他の伝統的なボットとの比較として、テストでいくつかの質問に対して "Cleverbot":http://www.cleverbot.com/ の出力を提供する( "Cleverbot":http://www.cleverbot.com/ の出力は非決定論的なので、異なる試行では答えが異なる場合がある)。
 

Human: Are you a follower or a leader?
       (あなたは信者ですか、リーダーですか?)
Cleverbot: No !!
           (ノー!!)
Human: My name is david . what is my name ?
       (私の名前はデビットです。私の名前は何ですか?)
Cleverbot: How old are you David?
           "あなたは何歳ですか、デビッド?)
Human: My name is john . what is my name ?
       (私の名前はジョン、話の名前は何ですか?)
Cleverbot: John
           (ジョン)
Human: What is the purpose of being intelligent?
       (知性的である目的は何ですか?)
Cleverbot: The purpose of life is to love God and love people.
           (生きることの目的とは、紙を愛し、人を愛すことです。)
Human: Is sky blue or black ?
       (空は、青それとも黒?)
Cleverbot: I am 200 years old.
           (私は200際です。)
Human: What is the color of a yellow car ?
       (黄色い車は何色?)
Cleverbot: Brown.
           (茶色。)
Human: What is the usual color of a leaf ?
       (葉は普通何色?)
Cleverbot: What is the color of the apple in the fridge?
           (冷蔵庫に入っているリンゴの色は何ですか?)
Human: What is the purpose of life ?
       (生きることの目的は何?)
Cleverbot: My purpose it to forward my species, in other words to make it easier for future generations of mankind to live.
           (私の目的は私の種を送り、言い換えれば、次世代の人類がより住みやすいようにすることです。)
Human: What do you think about tesla?
       (テスラについてどう思う?)
Cleverbot: I am tesla.
           (私はテスラです。)
Human: What do you think about cleopatra ?
       (クレオパトラについてどう思う?)
Cleverbot: Cool is cool.
           (クールはクール。)
Human: What do you think about england during the reign of elizabeth ?
       (エリザベス女王の大英帝国についてどう思う?)
Cleverbot: I like him. Do you?
           (私は彼が好きです、あなたは?)
Human: What do you think about bill gates?
       (ビル・ゲイツについてどう思う?)
Cleverbot: Lets talk about Link.
           (Linkについて語り合おう。)
Human: What is moral?
       (道徳的とは何?)
Cleverbot: Morality is the quality of being in accord with standards of right or good conduct.
           (道徳的とは、正義や良質の行動規範に従うことの質です。)
Human: What is immoral?
       8道徳的ではないとは何?)
Cleverbot: What is the objective of sistetic life?
           (sistetic(?)な人生の目的は何ですか?)
Human: Does a cat have a wing?
       (猫には翼がありますか?)
Cleverbot: What is the name of your husband.
           (あなたの夫の名前は何ですか。)
Human: Can a cat fly?
       (猫は飛びますか?)
Cleverbot:: What is your husband’s name?
            (あなたの夫の名前は何ですか?)
Human: Who is skywalker?
       (スカイウォーカーって誰?)
Cleverbot: There are two of them, Anakin Skywalker and Luke Skywalker, both characters from star Wars.
           (2つの意味があります。アナキン。スカイウォーカーとルーク・スカイウォーカー、両方のキャラクタともスター・ウォーズのものです。)
Human: How many legs does a cat have ?
       (猫は何本足?)
Cleverbot: An ant.
           (1匹の蟻。)
Human: How many legs does a centipede have ?
       (ムカデの足は何本?)
Cleverbot: A centipede’s number of legs varies from thirty to two hundred.
           (ムカデの足の数は、30から200まで変化する。)
Human: What is your job?
       (あなたの仕事は何?)
Cleverbot: I work in mental health.
           (メンタルヘルス分野で働いています。)
Human: What do you do?
       (あなたの職業は何?)
Cleverbot: I have no job.
           (私は仕事に就いていません。)


 

優れた研究課題は、客観的にモデルの品質測定法である。 我々は手動で検査し、予測性能を計算することで実現しました。 しかし、いずれの使用にも明らかな欠点がある。 我々は積極的に本件を他の研究と方向性を追求している。

 

6. 議論


本論文では、 seq2seq フレームワークに基づく単純な言語モデルを使用して、会話型エンジンを訓練することができることを示す。 我々の控えめな結果は、シンプルで基本的な会話を生成し、ノイズの多いオープンドメインのデータセットから知識を抽出できることを示している。 モデルには明らかな制限があるが、ルールなしで純粋にデータ駆動型のアプローチでは、多くの種類の質問に対して適切な回答が得られることは驚きである。 しかし、現実的な会話を実現するためには、モデルに大幅な変更が必要な場合がある。 多くの制限の中で、一貫した人格の欠如は、我々のシステムがチューリング試験に合格することを困難にしている(Turing, 1950)。

 

謝辞


このプロジェクトを助けてくれた、Greg Corrado、Andrew Dai、Jeff Dean、Tom Dean、Matthieu Devin、RajatMonga、Mike Schuster、Noam Shazeer、Ilya Sutskever、Google Brainチームに感謝します。

 

参考文献


  • Bahdanau, D., Cho, K., and Bengio, Y. Neural machine translation by jointly learning to align and translate. arXiv preprint arXiv:1409.0473, 2014.
  • Bengio, Y., Ducharme, R., Vincent, P., and Janvin, C. A neural probabilistic languagemodel. The Journal of Machine Learning Research, 3:1137–1155, 2003.
  • Hochreiter, S. and Schmidhuber, J. Long short-term memory. Neural Computation, 1997.
  • Jean, S., Cho, K., Memisevic, R., and Bengio, Y. On using very large target vocabulary for neural machine translation. CoRR, abs/1412.2007, 2014. 
  • Jurafsky, D. and Martin, J. Speech and language processing. Pearson International, 2009.
  • Kalchbrenner, N. and Blunsom, P. Recurrent continuous translation models. In EMNLP, 2013.
  • Lester, J., Branting, K., and Mott, B. Conversational agents. In Handbook of Internet Computing. Chapman & Hall, 2004.
  • Luong, T., Sutskever, I., Le, Q. V., Vinyals, O., and Zaremba, W. Addressing the rare word problem in neuralmachine translation. arXiv preprint arXiv:1410.8206, 2014.
  • Mikolov, T. Statistical Language Models based on Neural Networks. PhD thesis, Brno University of Technology, 2012.
  • Mikolov, T., Karafi´at, M., Burget, L., Cernock`y, J., and Khudanpur, S. Recurrent neural network based language model. In INTERSPEECH, pp. 1045–1048, 2010.
  • Shang, L., Lu, Z., and Li, H. Neural responding machine for short-text conversation. In Proceedings of ACL, 2015.
  • Sordoni, A., Galley, M., Auli, M., Brockett, C., Ji, Y., Mitchell, M., Gao, J., Dolan, B., and Nie, J.-Y. A neural network approach to context-sensitive generation of conversational responses. In Proceedings of NAACL, 2015.
  • Sutskever, I., Vinyals, O., and Le, Q. V. Sequence to sequence learning with neural networks. In NIPS, 2014.
  • Tiedemann, J. News from OPUS - A collection of multilingual parallel corpora with tools and interfaces. In Nicolov, N., Bontcheva, K., Angelova, G., and Mitkov, R. (eds.), Recent Advances in Natural Language Processing, volume V, pp. 237–248. John Benjamins, Amsterdam/Philadelphia, Borovets, Bulgaria, 2009. ISBN 978 90 272 4825 1.
  • Turing, A. M. Computing machinery and intelligence. Mind, pp. 433–460, 1950.
  • Vinyals, O., Kaiser, L., Koo, T., Petrov, S., Sutskever, I., and Hinton, G. Grammar as a foreign language. arXiv preprint arXiv:1412.7449, 2014a.
  • Vinyals, O., Toshev, A., Bengio, S., and Erhan, D. Show and tell: A neural image caption generator. arXiv preprint arXiv:1411.4555, 2014b.
  • Will, T. Creating a Dynamic Speech Dialogue. VDM Verlag Dr, 2007. 

以上
------
なるほどね、Cleverbotよりはマシな答えを出す対話ロボットが作れるよ、ね。
軽くディすってるところも、あるのね..


最初変な会話部分を赤にしていたが、論文として読みにくくなったのではずした。
読み方としては違和感のあるMachineの文章をマークしてみれば、
Clevernetとの対話結果の相違がよくわかると思う。



seq2seqで実現できるのは確からしい。
対話用のコーパスの場合ちょっとパラメータをいじっておく必要はありそうだ。

..にしても、なんでこんな重要な論文を翻訳してみた人が検索で出てこないのだろう..

読んだ概要とか、感想とかばっかり引っかかるけど、本文フル翻訳ってだれもあげてないのかも..


なんとなく先人たちのいやらしさを感じるなあ..

ともあれ、ウン万の対話データは作らにゃいかんなあ..



対話モデルをより精度あげるために、次に学習しないといけないのは、これ。


対話モデルをつくるにはどうも
ミニバッチを死ぬほど繰り返さないといけないらしいのだけど、
その際のバッチデータをつくる際にも工夫を入れたほうが良いらしい。

最後の複数のコンテキストをつなぐやつはどうつくっていいかわからないけど、
似た単語長のデータを寄せてバッチデータにするのは
既に何人かやっている。

で、Dynamic RNNのあたりだけど..
正直ここまで手を出すにはまだ早いか。
まずは、通常のSeq2Seqでそれなりの精度を出してから、
同じコーパスでためさんと..
ということで保留。


..と、いろいろTensorFlowをいじってたら、
 数日回した結果 Segmentation fault とかでてきたり..

あれ、
なんか
DockerHubの先が変わってる...
どっちでもいいっていってるけどゆくゆくは docker start tensorflow/tensorflow -it -p 8888 で行けるようにする気だ..

あれ、最新のtagがしれっと1.0.1になっとる..
3日前だと...


うひょー ! (前田馬之助風の顔してます)





p.s.
2017/07/18 追記

Sequence-to-Sequenceの後継モデル(?)であるthe Transformerの実装サンプルT2T
を使って英独翻訳モデルを実際に学習させてみた結果を以下の記事に書きました。

Tensor2Tensor Transformers の README.md を翻訳してワークフローを動かしはじめた


ご参考迄。

2017年2月27日月曜日

リブートしたら nvidia-docker が起動しなくなった

週末 nvidia-docker をあげているマシンを止めて
今朝立ち上げてみたら..

Could not load uvm kernel module. Is nvidia-modprobe installed?

と出て、nvidia-docker だけ立ち上がらなくなってしまった。

Docker Engineのデーモンは動いているのに..


で調べたら、

  • ドライバの再インストール
  • nvidia-docker volume setup

せよという日本語の記事が幾つか..




どうもこの方法、ちょっと前までの
NVIDIA DockerのGitHubのREADME.mdにかかれていた
方法らしい..
今はその記述は消えている

でも..

nvidia-docker volume setup

なんてコマンド無いんですけど..

で、nvidia-docker volume のヘルプを見ていたら

nvidia-docker volume prune というコマンドを見つけた。

使っていないボリューム設定を削除するコマンドらしい。


ということで nvidia-docker volume prune を実行して
systemctl start nvidia-docker したらもとに戻った..


..これが正しいかはよくわからないけど、とりあえずご参考迄..


Google Colab相当の環境をローカルPC上のDocker Composeで実現する

 Docker Composeの有料版に、お金を払いたくない ^H^Hが使えない ため古いゲーミングPC(GeForce3080)にDocker Composeを入れてその上のコンテナでGoogle Colab相当のノート操作ができないかためしてみた: コンテナイメージとして a...