hutzbot 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2041220becd680d7be9abe4f656037f3c680e483fd6479dd687b460089219f6e
4
+ data.tar.gz: 7213aae4ff4b82d3c1a2b2188c272928e621f67addefa4ba9c48195c3a063e95
5
+ SHA512:
6
+ metadata.gz: 745b62c428bd5070d7d881304c56334b5d6dc5d8a3539573ed87b356cfdd4a0284dcd9fece28677d9dbef82ec1e0f49d39e9e7375d157dd20601658f094eca54
7
+ data.tar.gz: 15dc53c6db2b0a0c795dc58530de3bbfaa1ae5c3a3fee67f15dba2f3314227c004b0f20865ab073bf40d6c0bd1add5c2ba5b91123852a3cff8d23afda600556b
@@ -0,0 +1,206 @@
1
+ require 'hutzbot/version'
2
+ require 'httparty'
3
+
4
+ module Hutzbot
5
+ class APIError < StandardError; end
6
+
7
+ class Response
8
+ attr_accessor :id
9
+ attr_accessor :speaker
10
+ attr_accessor :speaker_name
11
+ attr_accessor :statement
12
+ attr_accessor :metadata
13
+
14
+ def initialize attrs
15
+ @id, @speaker, @speaker_name, @statement, @metadata = *attrs.values_at('id', 'speaker', 'speaker_name', 'statement', 'metadata')
16
+ end
17
+
18
+ def system?
19
+ speaker=='system'
20
+ end
21
+ end
22
+
23
+ class ValidResponse
24
+ attr_accessor :answer
25
+ attr_accessor :response
26
+
27
+ def initialize attrs
28
+ @answer, @response = *attrs.values_at('answer', 'response')
29
+ end
30
+ end
31
+
32
+ class Conversation
33
+ attr_accessor :id
34
+ attr_accessor :current_state
35
+ attr_accessor :taxonomy
36
+ attr_accessor :tagged_document
37
+ attr_accessor :user
38
+ attr_accessor :application
39
+ attr_accessor :responses
40
+ attr_accessor :valid_responses
41
+
42
+ def initialize attrs
43
+ @id, @current_state, @taxonomy, @tagged_document, @user, @application = *attrs.values_at('id', 'current_state', 'taxonomy', 'tagged_document', 'user', 'application')
44
+ @responses = attrs['responses'].map{ |r| Response.new(r) } if attrs['responses']
45
+ @valid_responses = attrs['valid_responses'].map{ |vr| ValidResponse.new(vr) } if attrs['valid_responses']
46
+ end
47
+
48
+ def closed?
49
+ current_state=='closed'
50
+ end
51
+ end
52
+
53
+ class Taxonomy
54
+ attr_accessor :id
55
+ attr_accessor :name
56
+
57
+ def initialize attrs
58
+ @id, @name = *attrs.values_at('id', 'name')
59
+ end
60
+ end
61
+
62
+ class TaggedDocument
63
+ attr_accessor :id
64
+ attr_accessor :title
65
+
66
+ def initialize attrs
67
+ @id, @title = *attrs.values_at('id', 'title')
68
+ end
69
+ end
70
+
71
+
72
+ class Hutzbot
73
+ def initialize logger, host, user, key
74
+ @logger = logger
75
+ @host = host
76
+ @user = user
77
+ @key = key
78
+ @options = { headers: { 'X-User-Email' => @user, 'X-User-Token' => @key, 'Accept' => 'application/json' } }
79
+ end
80
+
81
+ def logger
82
+ @logger
83
+ end
84
+
85
+ def start_conversation
86
+ taxonomy = get_default_taxonomy
87
+ tagged_document = get_default_tagged_document
88
+ conversation = create_conversation({ taxonomy_id: taxonomy.id, tagged_document_id: tagged_document.id })
89
+ end
90
+
91
+ def get_conversations metadata=nil
92
+ request = [@host, 'conversations'].join('/')
93
+ request += "?metadata=#{metadata}" unless metadata.nil?
94
+ response = HTTParty.get(request, @options)
95
+ check_errors response
96
+ JSON.parse(response.body)['conversations'].map{ |c| Conversation.new(c) }
97
+ end
98
+
99
+ def get_conversation id
100
+ response = HTTParty.get("#{@host}/conversations/#{id}", @options)
101
+ check_errors response
102
+ Conversation.new(JSON.parse(response.body))
103
+ end
104
+
105
+ def tag_responses conversation_id, metadata
106
+ response = HTTParty.patch("#{@host}/conversations/#{conversation_id}/tag_responses", @options.merge({ query: { metadata: metadata } }))
107
+ check_errors response
108
+ Conversation.new(JSON.parse(response.body))
109
+ end
110
+
111
+ def add_response conversation_id, answer
112
+ response = HTTParty.patch("#{@host}/conversations/#{conversation_id}/add_response", @options.merge({ query: { answer: answer } }))
113
+ check_errors response
114
+ Conversation.new(JSON.parse(response.body))
115
+ end
116
+
117
+ def get_default_taxonomy
118
+ response = HTTParty.get("#{@host}/taxonomies/default", @options)
119
+ check_errors response
120
+ Taxonomy.new(JSON.parse(response.body))
121
+ end
122
+
123
+ def get_default_tagged_document
124
+ response = HTTParty.get("#{@host}/tagged_documents/default", @options)
125
+ check_errors response
126
+ TaggedDocument.new(JSON.parse(response.body))
127
+ end
128
+
129
+ def create_conversation params
130
+ response = HTTParty.post("#{@host}/conversations", @options.merge({ query: { conversation: params.merge({ application: :email }) } }))
131
+ check_errors response
132
+ Conversation.new(JSON.parse(response.body))
133
+ end
134
+
135
+ def converse metadata, body
136
+ if metadata.nil? || metadata.empty?
137
+ # start a conversation via the API
138
+ logger.info 'Starting a new conversation'
139
+ conversation = start_conversation
140
+ logger.info "Conversation ID: #{conversation.id}"
141
+ else
142
+ logger.info "Finding a conversation by metadata (#{metadata})"
143
+
144
+ # find the conversation by metadata
145
+ conversations = get_conversations metadata
146
+ unless conversations.empty?
147
+ # found a matching conversation
148
+ conversation = conversations.first
149
+ logger.info "Found conversation (#{conversation.id})"
150
+
151
+ # now get the full conversation (more attributes than available in index call)
152
+ conversation = get_conversation conversation.id
153
+
154
+ # get the answer index
155
+ matches = /(-?\d+)/.match(body)
156
+ if matches.nil?
157
+ # invalid answer
158
+ logger.warn("No answer found in body (#{body})")
159
+ else
160
+ answer_index = matches[1].to_i
161
+ logger.info("Found an answer in the message with index #{answer_index} in (#{conversation.valid_responses})")
162
+
163
+ matching_answer = conversation.valid_responses[answer_index-1]
164
+ logger.info("That answer is #{matching_answer.answer} (#{matching_answer.response})")
165
+ conversation = add_response conversation.id, matching_answer.answer
166
+ end
167
+ end
168
+ end
169
+
170
+ if conversation
171
+ logger.info "Preparing response"
172
+ responses = conversation.responses.select{ |r| r.system? && (r.metadata.nil? || r.metadata.empty?) }
173
+ contents = responses.map do |r|
174
+ "<p>#{r.statement}</p>"
175
+ end.join("<br>")
176
+ logger.debug "Response is: #{contents}"
177
+
178
+ logger.info "Preparing prompt"
179
+ prompt = nil
180
+ unless conversation.closed?
181
+ prompt = conversation.valid_responses.map do |valid_response|
182
+ "<li>#{valid_response.response}</li>"
183
+ end.join
184
+ prompt = "<p>Please make your selection: </p><ol>#{prompt}</ol>"
185
+ end
186
+ logger.debug "Prompt is: #{prompt}"
187
+
188
+ return conversation, contents, prompt
189
+ else
190
+ return nil, ""
191
+ end
192
+ end
193
+
194
+ private
195
+ def check_errors response
196
+ case response.code
197
+ when 200..299
198
+ "Success"
199
+ when 400..499
200
+ raise APIError, "HutzbotAPI Error: #{response.code}"
201
+ else
202
+ raise APIError, "HutzbotAPI Error: #{response.code}"
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,3 @@
1
+ module Hutzbot
2
+ VERSION = "0.1.3"
3
+ end
data/lib/hutzbot.rb ADDED
@@ -0,0 +1,5 @@
1
+ Dir[File.join(File.dirname(__FILE__), "hutzbot", "*.rb")].each { |f| require_relative f }
2
+
3
+ module Hutzbot
4
+
5
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hutzbot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Chris Wise
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-02-19 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.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
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: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-mocks
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.8.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.8.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.5.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.5.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: httparty
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.16.4
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.16.4
97
+ description:
98
+ email:
99
+ - cwise@murmurinformatics.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - lib/hutzbot.rb
105
+ - lib/hutzbot/hutzbot.rb
106
+ - lib/hutzbot/version.rb
107
+ homepage: https://github.com/cwise/hutzbot-ruby
108
+ licenses:
109
+ - MIT
110
+ metadata:
111
+ allowed_push_host: https://rubygems.org
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.7.3
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: A Ruby interface to the Hutzbot service
132
+ test_files: []