wit_bot 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/CODE_OF_CONDUCT.md +49 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +95 -0
  7. data/Rakefile +2 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/bin/wit +74 -0
  11. data/examples/simple.rb +14 -0
  12. data/examples/thread.rb +24 -0
  13. data/lib/wit_bot.rb +53 -0
  14. data/lib/wit_bot/configuration.rb +9 -0
  15. data/lib/wit_bot/errors/low_confidence_error.rb +16 -0
  16. data/lib/wit_bot/errors/wit_bot_error.rb +3 -0
  17. data/lib/wit_bot/errors/wit_error.rb +9 -0
  18. data/lib/wit_bot/models/context.rb +23 -0
  19. data/lib/wit_bot/models/context_entities.rb +18 -0
  20. data/lib/wit_bot/models/message.rb +41 -0
  21. data/lib/wit_bot/models/message_thread.rb +30 -0
  22. data/lib/wit_bot/models/outcome.rb +31 -0
  23. data/lib/wit_bot/models/state.rb +20 -0
  24. data/lib/wit_bot/models/wit/base.rb +101 -0
  25. data/lib/wit_bot/models/wit/entity.rb +40 -0
  26. data/lib/wit_bot/models/wit/entity/entity_model.rb +21 -0
  27. data/lib/wit_bot/models/wit/entity/entity_value.rb +20 -0
  28. data/lib/wit_bot/models/wit/expression.rb +31 -0
  29. data/lib/wit_bot/models/wit/intent.rb +48 -0
  30. data/lib/wit_bot/models/wit/intent/intent_expressions.rb +12 -0
  31. data/lib/wit_bot/models/wit/intent/intent_meta.rb +18 -0
  32. data/lib/wit_bot/requests/message_request.rb +7 -0
  33. data/lib/wit_bot/requests/models/entities_request.rb +7 -0
  34. data/lib/wit_bot/requests/models/expressions_request.rb +7 -0
  35. data/lib/wit_bot/requests/models/intents_request.rb +7 -0
  36. data/lib/wit_bot/requests/models/wit_model_request.rb +32 -0
  37. data/lib/wit_bot/requests/wit_request.rb +16 -0
  38. data/lib/wit_bot/requests/wit_request_sender.rb +18 -0
  39. data/lib/wit_bot/version.rb +3 -0
  40. data/wit_bot.gemspec +28 -0
  41. metadata +263 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 860c744638b8b4e301e8c388d038d32f8e7cd8fc
4
+ data.tar.gz: 4d6c170e3506b97235a9184e7e70a420aae94926
5
+ SHA512:
6
+ metadata.gz: 3edd3cd3d85269c77a4035fe9c095435b7ace28508231379207868aadc218ca4b69d9a0f2a18415afb788aef6ec062e30f844230b515a54f18f5a80de6a5c41c
7
+ data.tar.gz: be861fdb6a7761e56fc20cd5ae71fc037807d5b305c6f21732c375fc420dcab6a1a6691022bac3fe5888d29aa8d471f371b9d3c0d013d619ce6ed29455f056d5
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea/*
11
+ .rbenv-vars
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at ben@bensites.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wit_bot.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Ben!
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,95 @@
1
+ # WitBot
2
+
3
+ A better [wit.ai] client for Ruby. Written in Ruby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'wit_bot'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install wit_bot
20
+
21
+ ## Usage
22
+
23
+ Start a REPL:
24
+
25
+ ```bash
26
+ $ wit
27
+ ```
28
+
29
+ or use with STDIO
30
+
31
+ ```bash
32
+ $ wit --input --json
33
+ ```
34
+
35
+ or use programmatically
36
+
37
+ 1. Configure WitBot with your access token:
38
+
39
+ ```ruby
40
+ WitBot.configure do |c|
41
+ c.token = ENV['WIT_AI_TOKEN']
42
+ end
43
+ ```
44
+
45
+ 2. Create a message:
46
+
47
+ ```ruby
48
+ message = WitBot.create_message 'This is a cool test'
49
+ ```
50
+
51
+ 3. And send it:
52
+
53
+ ```ruby
54
+ message.send
55
+ ```
56
+
57
+ 4. Get the outcome:
58
+
59
+ ```ruby
60
+ outcome = message.outcome
61
+ ```
62
+
63
+ 5. Get the intent and the entities:
64
+
65
+ ```ruby
66
+ intent = outcome.intent #=> WitBot::WitModel::Intent
67
+ entities = outcome.entities #=> {role => #<WitBot::WitModel::Entity>}
68
+ ```
69
+
70
+ 6. Get the intent name:
71
+
72
+ ```ruby
73
+ intent.name #=> "Test"
74
+ ```
75
+
76
+ More information on the [GitHub wiki][wiki].
77
+
78
+ ## Development
79
+
80
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
81
+
82
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
83
+
84
+ ## Contributing
85
+
86
+ Bug reports and pull requests are welcome on GitHub at https://github.com/penne12/wit_bot. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
87
+
88
+
89
+ ## License
90
+
91
+ The gem is available as open source under the terms of the [MIT License].
92
+
93
+ [wit.ai]: https://wit.ai/
94
+ [wiki]: https://github.com/penne12/wit_bot/wiki
95
+ [MIT License]: http://opensource.org/licenses/MIT
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/wit_bot'
4
+
5
+ WitBot.configure do |c|
6
+ c.token = ENV['WIT_ACCESS_TOKEN'] # Create a wit bot and set the token here
7
+ end
8
+
9
+ def reload!
10
+ WitBot.load
11
+ end
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/wit ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'awesome_print'
4
+ require 'optparse'
5
+ require 'json'
6
+ require 'wit_bot'
7
+
8
+ access_token = ENV['WIT_ACCESS_TOKEN']
9
+ repl = true
10
+ $output = :ap
11
+
12
+ OptionParser.new do |opts|
13
+ opts.banner = 'Usage: wit [options]'
14
+
15
+ opts.on('-t', '--token TOKEN', 'Access Token') { |v| access_token = v }
16
+ opts.on('-i', '--input', "Don't start a REPL - read from standard input.") { |v| repl = !v }
17
+ opts.on('-j', '--json', 'Respond with raw json') { |v| $output = :json if v }
18
+ end.parse!
19
+
20
+ unless access_token
21
+ puts <<-EOS
22
+ An access token was not provided.
23
+ Please restart the Wit REPL with an access token:
24
+
25
+ wit -t [access_token]
26
+
27
+ or with the ENV var WIT_ACCESS_TOKEN
28
+ EOS
29
+
30
+ exit 1
31
+ end
32
+
33
+
34
+ WitBot.configure do |c|
35
+ c.token = access_token
36
+ end
37
+
38
+ thread = WitBot.thread
39
+
40
+ def output_outcome(outcome)
41
+ if $output == :json
42
+ puts JSON.dump outcome.raw
43
+ else
44
+ ap outcome, {raw: true}
45
+ end
46
+ end
47
+
48
+ if repl
49
+ begin
50
+ puts 'Starting Wit REPL:'
51
+ loop.each_with_index do |i|
52
+ print "wit:#{i}> "
53
+
54
+ input = gets.chomp
55
+
56
+ message = thread.create_message input
57
+ message.send
58
+
59
+ output_outcome message.outcome
60
+ end
61
+ rescue Interrupt
62
+ puts 'Exitting...'
63
+ exit 0
64
+ end
65
+ else
66
+ ARGV.clear
67
+
68
+ ARGF.each do |line|
69
+ message = thread.create_message line.chomp
70
+ message.send
71
+
72
+ output_outcome message.outcome
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'awesome_print'
4
+ require 'wit_bot'
5
+
6
+ WitBot.configure do |c|
7
+ c.token = ENV['WIT_ACCESS_TOKEN'] # Create a wit bot and set the token here
8
+ end
9
+
10
+ message = WitBot.create_message 'This is a cool test' # Create a message.
11
+ message.send # Send it.
12
+
13
+ outcome = message.outcome # Get the outcome
14
+ ap outcome, {raw: true} # Print it.
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'awesome_print'
4
+ require 'wit_bot'
5
+
6
+ WitBot.configure do |c|
7
+ c.token = ENV['WIT_ACCESS_TOKEN'] # Create a wit bot and set the token here
8
+ end
9
+
10
+ thread = WitBot.thread # Create a new thread
11
+
12
+ message = thread.create_message 'This is a cool test' # Create a normal message on the thread
13
+
14
+ message.send # Send that normal message
15
+
16
+ thread.context.state = 'how_cold' # Set the state to ask the user how cold the test really is.
17
+
18
+ message = thread.create_message '32 degrees' # Create a message on the thread
19
+
20
+ message.send # Send the message
21
+
22
+ outcome = message.outcome # Get the outcome
23
+
24
+ ap outcome, {raw: true} # Print the outcome
@@ -0,0 +1,53 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'active_support/core_ext/module/attribute_accessors'
3
+ require 'http'
4
+ require 'require_all'
5
+
6
+ module WitBot
7
+ class << self
8
+ # @return [Configuration]
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+ alias :config :configuration
13
+
14
+ def request_sender
15
+ @request_sender ||= WitRequestSender.new
16
+ end
17
+
18
+ def reset_request_sender
19
+ @request_sender.close
20
+ @request_sender = WitRequestSender.new
21
+ end
22
+
23
+ def reset
24
+ @configuration = Configuration.new
25
+ end
26
+
27
+ def configure
28
+ yield configuration
29
+ end
30
+
31
+ def http
32
+ request_sender.http
33
+ end
34
+
35
+ def thread
36
+ MessageThread.new
37
+ end
38
+
39
+ def create_message(text)
40
+ thread.create_message text
41
+ end
42
+
43
+ def load
44
+ warn_level = $VERBOSE
45
+ $VERBOSE = nil
46
+ result = load_rel 'wit_bot'
47
+ $VERBOSE = warn_level
48
+ result
49
+ end
50
+ end
51
+ end
52
+
53
+ WitBot.load
@@ -0,0 +1,9 @@
1
+ class Configuration
2
+ attr_accessor :token, :host, :minimum_confidence, :version
3
+ def initialize
4
+ @token = nil
5
+ @host = 'https://api.wit.ai'
6
+ @minimum_confidence = 0
7
+ @version = "20160313"
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module WitBot
2
+ class LowConfidenceError < WitBotError
3
+ attr_reader :outcome, :message, :confidence, :minimum_confidence
4
+
5
+ def initialize(outcome, minimum_confidence=config.minimum_confidence)
6
+ @outcome = outcome
7
+ @message = outcome.message
8
+ @confidence = outcome.confidence
9
+ @minimum_confidence = minimum_confidence
10
+ end
11
+
12
+ def to_s
13
+ "Confidence (#{confidence}) is lower then the minimum (#{minimum_confidence})"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module WitBot
2
+ class WitBotError < StandardError; end
3
+ end
@@ -0,0 +1,9 @@
1
+ module WitBot
2
+ class WitError < WitBotError
3
+ attr_reader :status
4
+
5
+ def initialize(status)
6
+ @status = status
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ module WitBot
2
+ class Context
3
+ attr_accessor :state, :reference_time, :location
4
+ attr_writer :hash, :entities
5
+
6
+ def empty?
7
+ as_json.empty?
8
+ end
9
+
10
+ def entities
11
+ @entities ||= ContextEntities.new
12
+ end
13
+
14
+ def as_json
15
+ h = {}
16
+ h[:state] = state if state
17
+ h[:reference_time] = reference_time.iso8601 if reference_time
18
+ h[:entities] = entities if @entities
19
+ h[:location] = location if location
20
+ h
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ module WitBot
2
+ class ContextEntities
3
+ def initialize
4
+ @hash = {}
5
+ end
6
+ def [](entity)
7
+ @hash[entity]
8
+ end
9
+ def []=(entity, value, expressions=[value])
10
+ @hash[entity] = value.is_a?(EntityValue) ? value : EntityValue.new(value, expressions)
11
+ end
12
+ def as_json
13
+ @hash.map do |id, values|
14
+ {id: id, values: values}
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,41 @@
1
+ module WitBot
2
+ class Message
3
+ attr_reader :thread, :text, :_text, :id, :sent, :_outcomes, :outcomes
4
+
5
+ def initialize(thread=WitBot.thread, text, id: SecureRandom.uuid)
6
+ @thread = thread
7
+ @text = text
8
+ @_text = nil
9
+ @id = id
10
+ @sent = false
11
+ @outcomes = @_outcomes = nil
12
+ end
13
+
14
+ def params(p=nil)
15
+ params = {
16
+ q: text,
17
+ msg_id: id,
18
+ thread_id: thread.id
19
+ }
20
+ params[:context] = JSON.dump thread.context.as_json unless thread.context.empty?
21
+ p ? params.merge(p) : params
22
+ end
23
+
24
+ def send(n=1, keep_context=true)
25
+ response = MessageRequest.new.request(self, n)
26
+
27
+ @sent = true
28
+ message.thread.reset_context unless keep_context
29
+
30
+ @_text = response['_text']
31
+ @_outcomes = response['outcomes']
32
+ @outcomes = @_outcomes.each_with_index.map { |outcome, i| Outcome.new self, outcome, i }
33
+
34
+ self
35
+ end
36
+
37
+ def outcome
38
+ outcomes.first
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,30 @@
1
+ module WitBot
2
+ class MessageThread
3
+ attr_reader :id, :messages
4
+
5
+ def initialize(id=SecureRandom.uuid)
6
+ @id = id
7
+ @messages = {}
8
+ end
9
+
10
+ def message(id)
11
+ messages[id]
12
+ end
13
+
14
+ def messages_list
15
+ messages.values
16
+ end
17
+
18
+ def create_message(text, id=SecureRandom.uuid)
19
+ WitBot::Message.new self, text, id: id
20
+ end
21
+
22
+ def context
23
+ @context ||= Context.new
24
+ end
25
+
26
+ def reset_context
27
+ @context = Context.new
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module WitBot
2
+ class Outcome
3
+ attr_reader :message, :raw, :_text, :confidence, :intent, :entities
4
+
5
+ def initialize(message, raw, i=0)
6
+ @message = message
7
+ @raw = raw.with_indifferent_access
8
+
9
+ @confidence = @raw[:confidence]
10
+ @_text = @raw[:_text]
11
+
12
+ @intent = WitModel::Intent.find raw[:intent]
13
+ @entities = @raw[:entities].each.inject({}) do |entities, entity_info|
14
+ role, all = entity_info
15
+ all = all.map { |data| WitModel::Entity.find(data[:entity], create: false).model role, data }
16
+
17
+ data = all.shift
18
+ data.others = all
19
+
20
+ entities[role] = data
21
+ entities
22
+ end
23
+
24
+ raise LowConfidenceError self if i == 0 && low_confidence?
25
+ end
26
+
27
+ def low_confidence?
28
+ @confidence < WitBot.config.minimum_confidence
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module WitBot
2
+ class State
3
+ cattr_reader :states
4
+ attr_reader :state
5
+
6
+ @@states = {}
7
+
8
+ def initialize(state)
9
+ @state = state
10
+ @@states[state] = self
11
+ end
12
+
13
+ def self.find(state)
14
+ @@states[state] || State.new(state)
15
+ end
16
+
17
+ alias :to_s :state
18
+ alias :as_json :state
19
+ end
20
+ end
@@ -0,0 +1,101 @@
1
+ module WitBot
2
+ module WitModel
3
+ class Base
4
+ attr_reader :id
5
+
6
+ @@changeable_attrs = []
7
+ @@changeable_attrs_only = {}
8
+ @@server_attrs = []
9
+ @@server_attrs_only = {}
10
+
11
+ def initialize(id, request=false, *args)
12
+ @id = id
13
+
14
+ @delete_listeners = []
15
+
16
+ get if request
17
+ end
18
+
19
+ class << self
20
+ def all
21
+ @all ||= REQUEST.new.get.map{|data| from_response_data data}
22
+ end
23
+
24
+ def get(model: nil)
25
+ if model.respond_to? :get
26
+ model.get
27
+ else
28
+ self.class.new id, request: true
29
+ end
30
+ end
31
+
32
+ protected
33
+
34
+ def changeable_attr(*attrs, only: nil)
35
+ attr_accessor *attrs
36
+ (only ? @@changeable_attrs : @@changeable_attrs_only[only] ||= []).concat attrs
37
+ end
38
+
39
+ def server_attr(*attrs, only: nil)
40
+ attr_reader *attrs
41
+ (only ? @@server_attrs : @@server_attrs_only[only] ||= []).concat attrs
42
+ end
43
+ end
44
+
45
+ def create
46
+ _response = request.create
47
+
48
+ if self.respond_to? :process_create_response, true
49
+ self.process_create_response(_response) do |response|
50
+ from_response_data response
51
+ end
52
+ else
53
+ from_response_data _response
54
+ end
55
+ end
56
+
57
+ def delete
58
+ request.delete
59
+
60
+ @delete_listeners.all?{|listener| listener.call self}
61
+ end
62
+
63
+ def get(data: request.get(all: false))
64
+ from_response_data data
65
+ end
66
+
67
+ def on_delete(&listener)
68
+ @delete_listeners << listener
69
+ end
70
+
71
+ def to_h(include_id=true, method=caller[0])
72
+ attrs = @@changeable_attrs + (@@changeable_attrs_only[method] || [])
73
+
74
+ hash = {}
75
+ hash[:id] = id if include_id
76
+
77
+ attrs.inject(hash) do |h, v|
78
+ h[v] = self.send v if self.send v
79
+ end
80
+ end
81
+ alias :to_hash :to_h
82
+ alias :as_json :to_h
83
+
84
+ def from_response_data(response, method=caller[0])
85
+ response = response.with_indifferent_access
86
+
87
+ variables = (@@server_attrs_only[method] || []) + @@server_attrs + @@changeable_attrs
88
+
89
+ variables.each do |attr|
90
+ if (value = response[attr])
91
+ processor = "process_#{attr}".to_sym
92
+
93
+ value = self.send processor, value if self.respond_to? processor, true
94
+
95
+ instance_variable_set "@#{attr}", value
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,40 @@
1
+ module WitBot
2
+ module WitModel
3
+ class Entity < Base
4
+ changeable_attr :doc, :values
5
+ server_attr :uuid, :builtin, :id
6
+ server_attr :lang, :closed, :exotic, only: :create
7
+
8
+ alias_method :name, :id
9
+
10
+ @@entities = {}
11
+
12
+ def initialize(id, doc=false, values=nil, request: false)
13
+ super
14
+ @doc = doc
15
+ @values = values
16
+ @uuid = nil
17
+
18
+ @@entities[name] = self
19
+ end
20
+
21
+ def model(role, data)
22
+ EntityModel.new self, role, data
23
+ end
24
+
25
+ def self.find(name, create=true)
26
+ @@entities[name] || create && Entity.new(id: name, request: true)
27
+ end
28
+
29
+ protected
30
+
31
+ def process_values(values)
32
+ values.map{|v| EntityValue.new v}
33
+ end
34
+
35
+ def request
36
+ EntitiesRequest.new(model: self)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ module WitBot
2
+ class EntityModel
3
+ attr_accessor :others
4
+ attr_reader :entity, :role, :raw
5
+
6
+ def initialize(entity, role, raw)
7
+ @entity = entity
8
+ @role = role
9
+ @raw = raw.with_indifferent_access
10
+
11
+ @value = case @raw[:type].to_sym
12
+ when :value
13
+
14
+ else
15
+ @raw[:value]
16
+ end
17
+
18
+ @others = []
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module WitBot
2
+ class EntityValue
3
+ attr_accessor :value, :expressions
4
+
5
+ def initialize(value, expressions=[value])
6
+ if value.is_a? Hash
7
+ hash = value.with_indifferent_access
8
+ @value = hash[:value]
9
+ @expressions = hash[:expressions]
10
+ else
11
+ @value = value
12
+ @expressions = expressions
13
+ end
14
+ end
15
+
16
+ def to_h
17
+ {value: value, expressions: expressions}
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module WitBot
2
+ class Expression
3
+ attr_accessor :intent, :body
4
+
5
+ def initialize(intent, body, request: false)
6
+ @intent = intent
7
+ @body = body.is_a?(Hash) ? body.with_indifferent_access[:body] : body
8
+ create if request
9
+ end
10
+
11
+ def create
12
+ request.create
13
+ intent.get
14
+ end
15
+
16
+ def delete
17
+ request.delete
18
+ intent.get
19
+ end
20
+
21
+ def to_h
22
+ {body: body}
23
+ end
24
+ alias :as_json :to_h
25
+
26
+ protected
27
+ def request
28
+ ExpressionsRequest.new model: self
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,48 @@
1
+ module WitBot
2
+ module WitModel
3
+ class Intent < Base
4
+ changeable_attr :name, :doc, :metadata
5
+ changeable_attr :expressions, :meta, only: :create
6
+ server_attr :id, :expressions
7
+
8
+ @@intents = {}
9
+
10
+ def initialize(id, doc: nil, metadata: nil, expressions: [], states: [], meta: {states: []}, request: false)
11
+ super
12
+
13
+ @name = id
14
+ @doc = doc
15
+ @metadata = metadata
16
+
17
+ meta[:states].concat states
18
+
19
+ @expressions = process_expressions expressions
20
+ @meta = process_meta meta
21
+
22
+ @@intents[@name] = self
23
+ end
24
+
25
+ def self.find(name)
26
+ @@intents[name] || self.new(name, request: true)
27
+ end
28
+
29
+ protected
30
+
31
+ def process_expressions(expressions)
32
+ IntentExpressions.new self, expressions
33
+ end
34
+
35
+ def process_meta(meta)
36
+ IntentMeta.new **meta.symbolize_keys
37
+ end
38
+
39
+ def process_create_response(response)
40
+ response.each{ |r| yield r }
41
+ end
42
+
43
+ def request
44
+ IntentsRequest.new(model: self)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,12 @@
1
+ module WitBot
2
+ class IntentExpressions < Array
3
+ def initialize(intent, *expressions)
4
+ @intent = intent
5
+ super expressions.flatten!.map{|i| Expression.new @intent, i}
6
+ end
7
+
8
+ def create(body, request: true)
9
+ self << Expression.new(@intent, body, request: request)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ module WitBot
2
+ class IntentMeta
3
+ attr_reader :states
4
+
5
+ def initialize(states: [])
6
+ @states = states.map{ |state| State.find state }
7
+ end
8
+
9
+ def self.from_states(*states)
10
+ self.new states: states
11
+ end
12
+
13
+ def to_h
14
+ {states: states}
15
+ end
16
+ alias :to_hash :to_h
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module WitBot
2
+ class MessageRequest < WitRequest
3
+ def request(message, n)
4
+ super http.get '/message', params: message.params(n: n)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module WitBot
2
+ class EntitiesRequest < WitModelRequest
3
+ def model_path
4
+ '/entities'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module WitBot
2
+ class ExpressionsRequest < WitModelRequest
3
+ def model_path
4
+ "/intents/#{@model.intent.name}/expressions"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module WitBot
2
+ class IntentsRequest < WitModelRequest
3
+ def model_path
4
+ '/intents'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ module WitBot
2
+ class WitModelRequest < WitRequest
3
+ attr_reader :model
4
+
5
+ def model_path; end
6
+
7
+ def individual_model_path
8
+ "#{model_path}/#{@model.name || @model.id}"
9
+ end
10
+
11
+ def initialize(model: nil)
12
+ @model = model
13
+ end
14
+
15
+ def get(all: true)
16
+ path = all ? model_path : individual_model_path
17
+ request http.get path
18
+ end
19
+
20
+ def create
21
+ request http.post(model_path, json: model.as_json)
22
+ end
23
+
24
+ def update
25
+ request http.put(model_path, json: model.as_json)
26
+ end
27
+
28
+ def delete
29
+ request http.delete("#{model_path}/#{model.name}")
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ module WitBot
2
+ class WitRequest
3
+ def http
4
+ WitBot.http
5
+ end
6
+
7
+ def request(request=http)
8
+ if request.code.between? 200, 299
9
+ request.parse.with_indifferent_access
10
+ else
11
+ response = request.parse.with_indifferent_access
12
+ raise WitError.new(response[:status]), (response[:error] || response[:body])
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module WitBot
2
+ class WitRequestSender
3
+
4
+ def initialize
5
+ @http = HTTP[
6
+ Accept: "application/vnd.wit.#{WitBot.config.version}+json",
7
+ Authorization: "Bearer #{WitBot.config.token}"
8
+ ]
9
+ .persistent(WitBot.config.host)
10
+ end
11
+ def http
12
+ @http
13
+ end
14
+ def close
15
+ @http.close
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module WitBot
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wit_bot/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'wit_bot'
8
+ spec.version = WitBot::VERSION
9
+ spec.authors = ['Ben (@penne12_)']
10
+ spec.email = ['ben@bensites.com']
11
+
12
+ spec.summary = %q{A better wit.ai client for Ruby. Written in Ruby.}
13
+ spec.description = `cat README.md`
14
+ spec.homepage = 'http://bensites.com/wit_bot'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.executables = ['wit']
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.11"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_dependency "http", "~> 1.0.2"
25
+ spec.add_dependency "activesupport", "~> 4.2.6"
26
+ spec.add_dependency "require_all", "~> 1.3.3"
27
+ spec.add_dependency "awesome_print", "~> 1.6.1"
28
+ end
metadata ADDED
@@ -0,0 +1,263 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wit_bot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben (@penne12_)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: http
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.0.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 4.2.6
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 4.2.6
69
+ - !ruby/object:Gem::Dependency
70
+ name: require_all
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.3.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.3.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: awesome_print
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.6.1
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.6.1
97
+ description: |-
98
+ # WitBot
99
+
100
+ A better [wit.ai] client for Ruby. Written in Ruby.
101
+
102
+ ## Installation
103
+
104
+ Add this line to your application's Gemfile:
105
+
106
+ ```ruby
107
+ gem 'wit_bot'
108
+ ```
109
+
110
+ And then execute:
111
+
112
+ $ bundle
113
+
114
+ Or install it yourself as:
115
+
116
+ $ gem install wit_bot
117
+
118
+ ## Usage
119
+
120
+ Start a REPL:
121
+
122
+ ```bash
123
+ $ wit
124
+ ```
125
+
126
+ or use with STDIO
127
+
128
+ ```bash
129
+ $ wit --input --json
130
+ ```
131
+
132
+ or use programmatically
133
+
134
+ 1. Configure WitBot with your access token:
135
+
136
+ ```ruby
137
+ WitBot.configure do |c|
138
+ c.token = ENV['WIT_AI_TOKEN']
139
+ end
140
+ ```
141
+
142
+ 2. Create a message:
143
+
144
+ ```ruby
145
+ message = WitBot.create_message 'This is a cool test'
146
+ ```
147
+
148
+ 3. And send it:
149
+
150
+ ```ruby
151
+ message.send
152
+ ```
153
+
154
+ 4. Get the outcome:
155
+
156
+ ```ruby
157
+ outcome = message.outcome
158
+ ```
159
+
160
+ 5. Get the intent and the entities:
161
+
162
+ ```ruby
163
+ intent = outcome.intent #=> WitBot::WitModel::Intent
164
+ entities = outcome.entities #=> {role => #<WitBot::WitModel::Entity>}
165
+ ```
166
+
167
+ 6. Get the intent name:
168
+
169
+ ```ruby
170
+ intent.name #=> "Test"
171
+ ```
172
+
173
+ More information on the [GitHub wiki][wiki].
174
+
175
+ ## Development
176
+
177
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
178
+
179
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
180
+
181
+ ## Contributing
182
+
183
+ Bug reports and pull requests are welcome on GitHub at https://github.com/penne12/wit_bot. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
184
+
185
+
186
+ ## License
187
+
188
+ The gem is available as open source under the terms of the [MIT License].
189
+
190
+ [wit.ai]: https://wit.ai/
191
+ [wiki]: https://github.com/penne12/wit_bot/wiki
192
+ [MIT License]: http://opensource.org/licenses/MIT
193
+ email:
194
+ - ben@bensites.com
195
+ executables:
196
+ - wit
197
+ extensions: []
198
+ extra_rdoc_files: []
199
+ files:
200
+ - ".gitignore"
201
+ - CODE_OF_CONDUCT.md
202
+ - Gemfile
203
+ - LICENSE.txt
204
+ - README.md
205
+ - Rakefile
206
+ - bin/console
207
+ - bin/setup
208
+ - bin/wit
209
+ - examples/simple.rb
210
+ - examples/thread.rb
211
+ - lib/wit_bot.rb
212
+ - lib/wit_bot/configuration.rb
213
+ - lib/wit_bot/errors/low_confidence_error.rb
214
+ - lib/wit_bot/errors/wit_bot_error.rb
215
+ - lib/wit_bot/errors/wit_error.rb
216
+ - lib/wit_bot/models/context.rb
217
+ - lib/wit_bot/models/context_entities.rb
218
+ - lib/wit_bot/models/message.rb
219
+ - lib/wit_bot/models/message_thread.rb
220
+ - lib/wit_bot/models/outcome.rb
221
+ - lib/wit_bot/models/state.rb
222
+ - lib/wit_bot/models/wit/base.rb
223
+ - lib/wit_bot/models/wit/entity.rb
224
+ - lib/wit_bot/models/wit/entity/entity_model.rb
225
+ - lib/wit_bot/models/wit/entity/entity_value.rb
226
+ - lib/wit_bot/models/wit/expression.rb
227
+ - lib/wit_bot/models/wit/intent.rb
228
+ - lib/wit_bot/models/wit/intent/intent_expressions.rb
229
+ - lib/wit_bot/models/wit/intent/intent_meta.rb
230
+ - lib/wit_bot/requests/message_request.rb
231
+ - lib/wit_bot/requests/models/entities_request.rb
232
+ - lib/wit_bot/requests/models/expressions_request.rb
233
+ - lib/wit_bot/requests/models/intents_request.rb
234
+ - lib/wit_bot/requests/models/wit_model_request.rb
235
+ - lib/wit_bot/requests/wit_request.rb
236
+ - lib/wit_bot/requests/wit_request_sender.rb
237
+ - lib/wit_bot/version.rb
238
+ - wit_bot.gemspec
239
+ homepage: http://bensites.com/wit_bot
240
+ licenses:
241
+ - MIT
242
+ metadata: {}
243
+ post_install_message:
244
+ rdoc_options: []
245
+ require_paths:
246
+ - lib
247
+ required_ruby_version: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - ">="
250
+ - !ruby/object:Gem::Version
251
+ version: '0'
252
+ required_rubygems_version: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: '0'
257
+ requirements: []
258
+ rubyforge_project:
259
+ rubygems_version: 2.4.5
260
+ signing_key:
261
+ specification_version: 4
262
+ summary: A better wit.ai client for Ruby. Written in Ruby.
263
+ test_files: []