hutzbot 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/hutzbot/hutzbot.rb +206 -0
- data/lib/hutzbot/version.rb +3 -0
- data/lib/hutzbot.rb +5 -0
- metadata +132 -0
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
|
data/lib/hutzbot.rb
ADDED
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: []
|