wit 3.4.0 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b70a97f9ec0b2c9b01f49983870ae7981cd0ca9a
4
- data.tar.gz: a575cf16cc6fd9ae10ce374617364c6edc6ea80a
2
+ SHA256:
3
+ metadata.gz: 1a15b6f521d5b67b3c2d512e1ea9262ef4b1e39109e22eb9822a10aabe8e7b34
4
+ data.tar.gz: 6fd43d27a1edc8ccba793c45ca0fac4e90f9c27d265b3a105135e1bfb85b707e
5
5
  SHA512:
6
- metadata.gz: 2f8a5583c0e72f940c9b7eff2c2cbcf31103b309ba040049b6f68bef599df4b14264fe99a5c18314c5202db928408157ad7d1bb38cef47bedce0bd46830bac09
7
- data.tar.gz: 58496e8a8bcb1f0c3183e00a611f713740932b2afbb2418534e244596dc303a1265a5681dbcb711907265283681e460c42094ba474573a27351d95369ba422e3
6
+ metadata.gz: eed12472514c8efdcbf6716b637aed58820dd98c437703566c027a10b57dca54877011d02dbc173e326aad8f7fa6a7d6c28ca499161070a73b913e73d840b650
7
+ data.tar.gz: 6d6f64a64117a9fd39ba9eb6074e3b7dc17bad80e48382930ea21f4584b2a1c96b5289df4ffdc6623ab8691d10c4af515f112551fd8e787184dec83e8fa01091
@@ -0,0 +1,9 @@
1
+ **Do you want to request a *feature*, report a *bug*, or ask a *question* about wit-ruby?**
2
+
3
+ **What is the current behavior?**
4
+
5
+ **If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.**
6
+
7
+ **What is the expected behavior?**
8
+
9
+ **If applicable, what is the App ID where you are experiencing this issue? If you do not provide this, we cannot help.**
data/CHANGES.md CHANGED
@@ -1,6 +1,52 @@
1
+ ## v7.0.0
2
+ - Updated API version to latest: `20200513`. Browse the latest HTTP API documentation [here](https://wit.ai/docs/http/20200513#get__message_link).
3
+ - Added intents and traits CRUD methods.
4
+ - More consistent, transparent naming of entities methods.
5
+
6
+ ## v6.0.0
7
+ The most important change is the removal of `.converse()` and `.run_actions()`. Follow the migration tutorial [here](https://github.com/wit-ai/wit-stories-migration-tutorial), or [read more here](https://wit.ai/blog/2017/07/27/sunsetting-stories).
8
+
9
+ ### Breaking changes
10
+
11
+ - `converse` and `run_actions` are removed
12
+ - updated and added new examples that leverage the /message API
13
+
14
+ ## v5.0.0
15
+
16
+ - `converse` and `run_actions` are deprecated
17
+ - `interactive` now calls `message`
18
+
19
+ ### Breaking changes
20
+ - Renamed WitException to Wit::Error
21
+ - Changed Wit::Error to inherit from StandardError instead of Exception
22
+ - Moved constants inside Wit namespace
23
+ - Moved #req and #validate_actions to private methods within Wit namespace
24
+
25
+ ## v4.1.0
26
+
27
+ - `converse` now takes `reset` as optional parameter.
28
+
29
+ ### Breaking changes
30
+
31
+ - `run_actions` now resets the last turn on new messages and errors.
32
+
33
+ ## v4.0.0
34
+
35
+ After a lot of internal dogfooding and bot building, we decided to change the API in a backwards-incompatible way. The changes are described below and aim to simplify user code and accommodate upcoming features.
36
+
37
+ See `./examples` to see how to use the new API.
38
+
39
+ ### Breaking changes
40
+
41
+ - `say` renamed to `send` to reflect that it deals with more than just text
42
+ - Removed built-in actions `merge` and `error`
43
+ - Actions signature simplified with `request` and `response` arguments
44
+ - INFO level replaces LOG level
45
+
1
46
  ## v3.4
2
47
 
3
48
  - allows for overriding API version, by setting `WIT_API_VERSION`
49
+ - `interactive()` mode
4
50
  - warns instead of throwing when validating actions
5
51
 
6
52
  ### breaking
@@ -0,0 +1,76 @@
1
+ # Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to make participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, sex characteristics, gender identity and expression,
9
+ level of experience, education, socio-economic status, nationality, personal
10
+ appearance, race, religion, or sexual identity and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies within all project spaces, and it also applies when
49
+ an individual is representing the project or its community in public spaces.
50
+ Examples of representing a project or community include using an official
51
+ project e-mail address, posting via an official social media account, or acting
52
+ as an appointed representative at an online or offline event. Representation of
53
+ a project may be further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at <opensource-conduct@fb.com>. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72
+
73
+ [homepage]: https://www.contributor-covenant.org
74
+
75
+ For answers to common questions about this code of conduct, see
76
+ https://www.contributor-covenant.org/faq
@@ -0,0 +1,34 @@
1
+ # Contributing to wit-ruby
2
+
3
+ We want to make contributing to this project as easy and transparent as
4
+ possible.
5
+
6
+ ## Pull Requests
7
+ We actively welcome your pull requests.
8
+
9
+ 1. Fork the repo and create your branch from `master`.
10
+ 2. If you've added code that should be tested, add tests.
11
+ 3. If you've changed APIs, update the documentation.
12
+ 4. Ensure the test suite passes.
13
+ 5. If you haven't already, complete the Contributor License Agreement ("CLA").
14
+
15
+ ## Contributor License Agreement ("CLA")
16
+
17
+ In order to accept your pull request, we need you to submit a CLA. You only need
18
+ to do this once to work on any of Facebook's open source projects.
19
+
20
+ Complete your CLA here: <https://code.facebook.com/cla>
21
+
22
+ ## Issues
23
+
24
+ We use GitHub issues to track public bugs. Please ensure your description is
25
+ clear and has sufficient instructions to be able to reproduce the issue.
26
+
27
+ Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
28
+ disclosure of security bugs. In those cases, please go through the process
29
+ outlined on that page and do not file a public issue.
30
+
31
+ ## License
32
+
33
+ By contributing to wit-ruby, you agree that your contributions will be licensed
34
+ under the LICENSE file in the root directory of this source tree.
data/README.md CHANGED
@@ -21,7 +21,7 @@ gem install wit-*.gem
21
21
  Run in your terminal:
22
22
 
23
23
  ```bash
24
- ruby examples/quickstart.rb <your_token>
24
+ ruby examples/basic.rb <your_token>
25
25
  ```
26
26
 
27
27
  See the `examples` folder for more examples.
@@ -31,117 +31,157 @@ See the `examples` folder for more examples.
31
31
  ### Overview
32
32
 
33
33
  `wit-ruby` provides a Wit class with the following methods:
34
- * `message` - the Wit [message API](https://wit.ai/docs/http/20160330#get-intent-via-text-link)
35
- * `converse` - the low-level Wit [converse API](https://wit.ai/docs/http/20160330#converse-link)
36
- * `run_actions` - a higher-level method to the Wit converse API
34
+ * `message` - the Wit [message API](https://wit.ai/docs/http/20200513#get-intent-via-text-link)
37
35
  * `interactive` - starts an interactive conversation with your bot
38
36
 
39
37
  ### Wit class
40
38
 
41
- The Wit constructor takes the following parameters:
42
- * `access_token` - the access token of your Wit instance
43
- * `actions` - the `Hash` with your actions
39
+ The Wit constructor takes a `Hash` with the following symbol keys:
40
+ * `:access_token` - the access token of your Wit instance
44
41
 
45
- The `actions` `Hash` has action names as keys, and action implementations as values.
46
- Action names are symbols, and action implementations are lambda functions (not `Proc`).
47
- You need to provide at least an implementation for the special actions `:say`, `:merge` and `:error`.
48
-
49
- A minimal `actions` `Hash` looks like this:
42
+ A minimal example looks like this:
50
43
  ```ruby
51
- actions = {
52
- :say => -> (session_id, context, msg) {
53
- p msg
54
- },
55
- :merge => -> (session_id, context, entities, msg) {
56
- return context
57
- },
58
- :error => -> (session_id, context, error) {
59
- p error.message
60
- },
61
- }
44
+ require 'wit'
45
+
46
+ client = Wit.new(access_token: access_token)
47
+ client.message('set an alarm tomorrow at 7am')
62
48
  ```
63
49
 
64
- A custom action takes the following parameters:
65
- * `session_id` - a unique identifier describing the user session
66
- * `context` - the `Hash` representing the session state
50
+ ### .message()
51
+
52
+ The Wit [message API](https://wit.ai/docs/http/20200513#get-intent-via-text-link).
53
+
54
+ Takes the following parameters:
55
+ * `msg` - the text you want Wit.ai to extract the information from
67
56
 
68
57
  Example:
69
58
  ```ruby
70
- require 'wit'
71
- client = Wit.new access_token, actions
59
+ rsp = client.message('what is the weather in London?')
60
+ puts("Yay, got Wit.ai response: #{rsp}")
72
61
  ```
73
62
 
74
- ### Logging
63
+ ### .interactive()
75
64
 
76
- Default logging is to `STDOUT` with `INFO` level.
65
+ Starts an interactive conversation with your bot.
77
66
 
78
- You can setup your logging level as follows:
67
+ Example:
79
68
  ```ruby
80
- Wit.logger.level = Logger::WARN
69
+ client.interactive
81
70
  ```
82
- See the [Logger class](http://ruby-doc.org/stdlib-2.1.0/libdoc/logger/rdoc/Logger.html) docs for more information.
83
71
 
84
- ### message
72
+ ### CRUD operations for intents
73
+ `payload` in the parameters is a hash containing API arguments.
85
74
 
86
- The Wit [message API](https://wit.ai/docs/http/20160330#get-intent-via-text-link).
75
+ #### .get_intents()
76
+ Returns a list of available intents for the app.
77
+ See [GET /intents](https://wit.ai/docs/http/20200513#get__intents_link).
87
78
 
88
- Takes the following parameters:
89
- * `msg` - the text you want Wit.ai to extract the information from
79
+ #### .get_intent(intent)
80
+ Returns all available information about an intent.
81
+ See [GET /intents/:intent](https://wit.ai/docs/http/20200513#get__intents__intent_link).
90
82
 
91
- Example:
92
- ```ruby
93
- resp = client.message 'what is the weather in London?'
94
- p "Yay, got Wit.ai response: #{resp}"
95
- ```
83
+ #### .post_intents(payload)
84
+ Creates a new intent.
85
+ See [POST /intents](https://wit.ai/docs/http/20200513#post__intents_link).
96
86
 
97
- ### run_actions
87
+ #### .delete_intents(intent)
88
+ Permanently deletes the intent.
89
+ See [DELETE /intents/:intent](https://wit.ai/docs/http/20200513#delete__intents__intent_link).
98
90
 
99
- A higher-level method to the Wit converse API.
91
+ ### CRUD operations for entities
92
+ `payload` in the parameters is a hash containing API arguments.
100
93
 
101
- Takes the following parameters:
102
- * `session_id` - a unique identifier describing the user session
103
- * `message` - the text received from the user
104
- * `context` - the `Hash` representing the session state
105
- * `max_steps` - (optional) the maximum number of actions to execute (defaults to 5)
94
+ #### .get_entities()
95
+ Returns a list of available entities for the app.
96
+ See [GET /entities](https://wit.ai/docs/http/20200513#get--entities-link)
106
97
 
107
- Example:
108
- ```ruby
109
- session = 'my-user-session-42'
110
- context0 = {}
111
- context1 = client.run_actions session, 'what is the weather in London?', context0
112
- p "The session state is now: #{context1}"
113
- context2 = client.run_actions session, 'and in Brussels?', context1
114
- p "The session state is now: #{context2}"
115
- ```
98
+ #### .post_entities(payload)
99
+ Creates a new entity with the given attributes.
100
+ See [POST /entities](https://wit.ai/docs/http/20200513#post--entities-link)
116
101
 
117
- ### converse
102
+ #### .get_entity(entity)
103
+ Returns all the information available for an entity.
104
+ See [GET /entities/:entity](https://wit.ai/docs/http/20200513#get--entities-:entity-link)
118
105
 
119
- The low-level Wit [converse API](https://wit.ai/docs/http/20160330#converse-link).
106
+ #### .put_entities(entity, payload)
107
+ Updates an entity with the given attributes.
108
+ See [PUT /entities/:entity](https://wit.ai/docs/http/20200513#put--entities-:entity-link)
120
109
 
121
- Takes the following parameters:
122
- * `session_id` - a unique identifier describing the user session
123
- * `msg` - the text received from the user
124
- * `context` - the `Hash` representing the session state
110
+ #### .delete_entities(entity)
111
+ Permanently removes the entity.
112
+ See [DELETE /entities/:entity](https://wit.ai/docs/http/20200513#delete--entities-:entity-link)
125
113
 
126
- Example:
127
- ```ruby
128
- resp = client.converse 'my-user-session-42', 'what is the weather in London?', {}
129
- p "Yay, got Wit.ai response: #{resp}"
130
- ```
114
+ #### .post_entities_keywords(entity, payload)
115
+ Adds a possible value into the list of keywords for the keywords entity.
116
+ See [POST /entities/:entity/keywords](https://wit.ai/docs/http/20160526#post--entities-:entity-id-values-link)
131
117
 
118
+ #### .delete_entities_keywords(entity, keyword)
119
+ Deletes a keyword from the entity.
120
+ See [DELETE /entities/:entity/keywords/:keyword](https://wit.ai/docs/http/20200513#delete--entities-:entity-keywords-link)
132
121
 
133
- ### interactive
122
+ #### .post_entities_keywords_synonyms(entity, keyword, payload)
123
+ Creates a new synonym for the keyword of the entity.
124
+ See [POST /entities/:entity/keywords/:keyword/synonyms](https://wit.ai/docs/http/20200513#post--entities-:entity-keywords-:keyword-synonyms-link)
134
125
 
135
- Starts an interactive conversation with your bot.
126
+ #### delete_entities_keywords_synonyms(entity, keyword, synonym)
127
+ Deletes a synonym of the keyword of the entity.
128
+ See [DELETE /entities/:entity/keywords/:keyword/synonyms/:synonym](https://wit.ai/docs/http/20200513#delete--entities-:entity-keywords-:keyword-synonyms-link)
129
+
130
+ ### CRUD operations for traits
131
+ `payload` in the parameters is a hash containing API arguments.
132
+
133
+ #### .get_traits()
134
+ Returns a list of available traits for the app.
135
+ See [GET /traits](https://wit.ai/docs/http/20200513#get__traits_link).
136
+
137
+ #### .get_trait(trait)
138
+ Returns all available information about a trait.
139
+ See [GET /traits/:trait](https://wit.ai/docs/http/20200513#get__traits__trait_link).
140
+
141
+ #### .post_traits(payload)
142
+ Creates a new trait.
143
+ See [POST /traits](https://wit.ai/docs/http/20200513#post__traits_link).
144
+
145
+ #### .post_traits_values(trait, payload)
146
+ Adds a new value to an existing trait.
147
+ See [POST /traits/:trait/values](https://wit.ai/docs/http/20200513#post__traits__trait_values_link).
148
+
149
+ #### .delete_traits_values(trait, value)
150
+ Permanently deletes a value of an existing trait.
151
+ See [POST /traits/:trait/values](https://wit.ai/docs/http/20200513#delete__traits__trait_values_link).
152
+
153
+ #### .delete_traits(trait)
154
+ Permanently deletes the trait.
155
+ See [DELETE /traits/:trait](https://wit.ai/docs/http/20200513#delete__traits__trait_link).
136
156
 
137
- Example:
138
- ```ruby
139
- client.interactive
140
- ```
141
157
 
142
158
  See the [docs](https://wit.ai/docs) for more information.
143
159
 
160
+ ### Logging
161
+
162
+ Default logging is to `STDOUT` with `INFO` level.
163
+
164
+ You can setup your logging level as follows:
165
+ ```ruby
166
+ Wit.logger.level = Logger::WARN
167
+ ```
168
+ See the [Logger class](http://ruby-doc.org/stdlib-2.1.0/libdoc/logger/rdoc/Logger.html) docs for more information.
144
169
 
145
170
  ## Thanks
146
171
 
147
172
  Thanks to [Justin Workman](http://github.com/xtagon) for releasing a first version in October 2013. We really appreciate!
173
+
174
+
175
+ ## License
176
+
177
+ The license for wit-ruby can be found in LICENSE file in the root directory of this source tree.
178
+
179
+
180
+ ## Terms of Use
181
+
182
+ Our terms of use can be found at https://opensource.facebook.com/legal/terms.
183
+
184
+
185
+ ## Privacy Policy
186
+
187
+ Our privacy policy can be found at https://opensource.facebook.com/legal/privacy.
@@ -0,0 +1,14 @@
1
+ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2
+
3
+ require 'wit'
4
+
5
+ if ARGV.length == 0
6
+ puts("usage: #{$0} <wit-access-token>")
7
+ exit 1
8
+ end
9
+
10
+ access_token = ARGV[0]
11
+ ARGV.shift
12
+
13
+ client = Wit.new(access_token: access_token)
14
+ client.interactive
@@ -0,0 +1,56 @@
1
+ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2
+
3
+ require 'wit'
4
+
5
+ if ARGV.length == 0
6
+ puts("usage: #{$0} <wit-access-token>")
7
+ exit 1
8
+ end
9
+
10
+ access_token = ARGV[0]
11
+ ARGV.shift
12
+
13
+ # Celebrities example
14
+ # See https://wit.ai/aleka/wit-example-celebrities/
15
+
16
+ def first_entity_resolved_value(entities, entity)
17
+ return nil unless entities.has_key? entity
18
+ val = entities[entity][0]['resolved']['values'][0]
19
+ return nil if val.nil?
20
+ return val
21
+ end
22
+
23
+ def first_trait_value(traits, trait)
24
+ return nil unless traits.has_key? trait
25
+ val = traits[trait][0]['value']
26
+ return nil if val.nil?
27
+ return val
28
+ end
29
+
30
+ def handle_message(response)
31
+ greetings = first_trait_value(response['traits'], 'wit$greetings')
32
+ celebrity = first_entity_resolved_value(response['entities'], 'wit$notable_person:notable_person')
33
+
34
+ case
35
+ when celebrity
36
+ return wikidata_description(celebrity)
37
+ when greetings
38
+ return "Hi! You can say something like 'Tell me about Beyonce'"
39
+ else
40
+ return "Um. I don't recognize that name. " \
41
+ "Which celebrity do you want to learn about?"
42
+ end
43
+ end
44
+
45
+ def wikidata_description(celebrity)
46
+ return "I recognize #{celebrity['name']}" unless celebrity.dig('external', 'wikidata')
47
+ wikidata_id = celebrity.fetch('external').fetch('wikidata')
48
+ api = URI("https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&ids=#{wikidata_id}&props=descriptions&languages=en")
49
+ rsp = Net::HTTP.get_response(api)
50
+ wikidata = JSON.parse(rsp.body)
51
+ description = wikidata['entities'][wikidata_id]['descriptions']['en']['value']
52
+ return "ooo yes I know #{celebrity['name']} -- #{description}"
53
+ end
54
+
55
+ client = Wit.new(access_token: access_token)
56
+ client.interactive(method(:handle_message))
@@ -1,18 +1,26 @@
1
+ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2
+
1
3
  require 'wit'
2
4
 
3
- # Joke example
4
- # See https://wit.ai/patapizza/example-joke
5
+ if ARGV.length == 0
6
+ puts("usage: #{$0} <wit-access-token>")
7
+ exit 1
8
+ end
9
+
10
+ access_token = ARGV[0]
11
+ ARGV.shift
5
12
 
6
- access_token = 'YOUR_ACCESS_TOKEN'
13
+ # Joke example
14
+ # See https://wit.ai/aleka/wit-example-joke-bot/
7
15
 
8
- def first_entity_value(entities, entity)
9
- return nil unless entities.has_key? entity
10
- val = entities[entity][0]['value']
16
+ def first_value(obj, key)
17
+ return nil unless obj.has_key? key
18
+ val = obj[key][0]['value']
11
19
  return nil if val.nil?
12
- return val.is_a?(Hash) ? val['value'] : val
20
+ return val
13
21
  end
14
22
 
15
- all_jokes = {
23
+ $all_jokes = {
16
24
  'chuck' => [
17
25
  'Chuck Norris counted to infinity - twice.',
18
26
  'Death once had a near-Chuck Norris experience.',
@@ -26,28 +34,25 @@ all_jokes = {
26
34
  ],
27
35
  }
28
36
 
29
- actions = {
30
- :say => -> (session_id, context, msg) {
31
- p msg
32
- },
33
- :merge => -> (session_id, context, entities, msg) {
34
- context.delete 'joke'
35
- context.delete 'ack'
36
- category = first_entity_value entities, 'category'
37
- context['category'] = category unless category.nil?
38
- sentiment = first_entity_value entities, 'sentiment'
39
- context['ack'] = sentiment == 'positive' ? 'Glad you liked it.' : 'Hmm.' unless sentiment.nil?
40
- return context
41
- },
42
- :error => -> (session_id, context, error) {
43
- p error.message
44
- },
45
- :'select-joke' => -> (session_id, context) {
46
- context['joke'] = all_jokes[context['cat'] || 'default'].sample
47
- return context
48
- },
49
- }
50
- client = Wit.new access_token, actions
37
+ def handle_message(response)
38
+ entities = response['entities']
39
+ traits = response['traits']
40
+ get_joke = first_value(traits, 'getJoke')
41
+ greetings = first_value(traits, 'wit$greetings')
42
+ category = first_value(entities, 'category:category')
43
+ sentiment = first_value(traits, 'wit$sentiment')
44
+
45
+ case
46
+ when get_joke
47
+ return $all_jokes[category || 'default'].sample
48
+ when sentiment
49
+ return sentiment == 'positive' ? 'Glad you liked it.' : 'Hmm.'
50
+ when greetings
51
+ return 'Hey this is joke bot :)'
52
+ else
53
+ return 'I can tell jokes! Say "tell me a joke about tech"!'
54
+ end
55
+ end
51
56
 
52
- session_id = 'my-user-id-42'
53
- client.run_actions session_id, 'tell me a joke about tech', {}
57
+ client = Wit.new(access_token: access_token)
58
+ client.interactive(method(:handle_message))
data/lib/wit.rb CHANGED
@@ -1,154 +1,186 @@
1
+ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2
+
1
3
  require 'json'
2
4
  require 'logger'
3
5
  require 'net/http'
4
6
  require 'securerandom'
5
7
 
6
- WIT_API_HOST = ENV['WIT_URL'] || 'https://api.wit.ai'
7
- WIT_API_VERSION = ENV['WIT_API_VERSION'] || '20160516'
8
- DEFAULT_MAX_STEPS = 5
8
+ class Wit
9
+ class Error < StandardError; end
9
10
 
10
- class WitException < Exception
11
- end
11
+ WIT_API_HOST = ENV['WIT_URL'] || 'https://api.wit.ai'
12
+ WIT_API_VERSION = ENV['WIT_API_VERSION'] || '20200513'
13
+ LEARN_MORE = 'Learn more at https://wit.ai/docs/quickstart'
12
14
 
13
- def req(access_token, meth_class, path, params={}, payload={})
14
- uri = URI(WIT_API_HOST + path)
15
- uri.query = URI.encode_www_form params
15
+ def initialize(opts = {})
16
+ @access_token = opts[:access_token]
16
17
 
17
- request = meth_class.new uri
18
- request['authorization'] = 'Bearer ' + access_token
19
- request['accept'] = 'application/vnd.wit.' + WIT_API_VERSION + '+json'
20
- request.add_field 'Content-Type', 'application/json'
21
- request.body = payload.to_json
18
+ if opts[:logger]
19
+ @logger = opts[:logger]
20
+ end
21
+ end
22
22
 
23
- Net::HTTP.start uri.host, uri.port, {:use_ssl => uri.scheme == 'https'} do |http|
24
- rsp = http.request request
25
- raise WitException.new "HTTP error code=#{rsp.code}" unless rsp.code.to_i <= 200
26
- json = JSON.parse rsp.body
27
- raise WitException.new "Wit responded with an error: #{json['error']}" if json.has_key? 'error'
28
- json
23
+ def logger
24
+ @logger ||= begin
25
+ x = Logger.new(STDOUT)
26
+ x.level = Logger::INFO
27
+ x
28
+ end
29
29
  end
30
- end
31
30
 
32
- def validate_actions(actions)
33
- learn_more = 'Learn more at https://wit.ai/docs/quickstart'
34
- Wit.logger.warn 'The second parameter should be a Hash' unless actions.is_a? Hash
35
- [:say, :merge, :error].each do |action|
36
- Wit.logger.warn "The #{action} action is missing. #{learn_more}" unless actions.has_key? action
37
- end
38
- actions.each_pair do |k, v|
39
- Wit.logger.warn "The '#{k}' action name should be a symbol" unless k.is_a? Symbol
40
- Wit.logger.warn "The '#{k}' action should be a lambda function" unless v.respond_to? :call and v.lambda?
41
- Wit.logger.warn "The \'say\' action should take 3 arguments: session_id, context, msg. #{learn_more}" if k == :say and v.arity != 3
42
- Wit.logger.warn "The \'merge\' action should take 4 arguments: session_id, context, entities, msg. #{learn_more}" if k == :merge and v.arity != 4
43
- Wit.logger.warn "The \'error\' action should take 3 arguments: session_id, context, error. #{learn_more}" if k == :error and v.arity != 3
44
- Wit.logger.warn "The '#{k}' action should take 2 arguments: session_id, context. #{learn_more}" if k != :say and k != :merge and k != :error and v.arity != 2
45
- end
46
- return actions
47
- end
31
+ def message(msg, n=nil, verbose=nil)
32
+ params = {}
33
+ params[:q] = msg unless msg.nil?
34
+ params[:n] = n unless n.nil?
35
+ params[:verbose] = verbose unless verbose.nil?
36
+ res = req(logger, @access_token, Net::HTTP::Get, '/message', params)
37
+ return res
38
+ end
48
39
 
49
- class Wit
50
- class << self
51
- attr_writer :logger
52
-
53
- def logger
54
- @logger ||= begin
55
- $stdout.sync = true
56
- Logger.new(STDOUT)
57
- end.tap { |logger| logger.level = Logger::INFO }
40
+ def interactive(handle_message=nil, context={})
41
+ while true
42
+ print '> '
43
+ msg = STDIN.gets.strip
44
+ if msg == ''
45
+ next
46
+ end
47
+
48
+ begin
49
+ if handle_message.nil?
50
+ puts(message(msg))
51
+ else
52
+ puts(handle_message.call(message(msg)))
53
+ end
54
+ rescue Error => exp
55
+ logger.error("error: #{exp.message}")
56
+ end
58
57
  end
58
+ rescue Interrupt => _exp
59
+ puts
59
60
  end
60
61
 
61
- def initialize(access_token, actions)
62
- @access_token = access_token
63
- @actions = validate_actions actions
62
+ def get_intents
63
+ req(logger, @access_token, Net::HTTP::Get, "/intents")
64
64
  end
65
65
 
66
- def logger
67
- self.class.logger
66
+ def get_intent(intent)
67
+ req(logger, @access_token, Net::HTTP::Get, "/intents/#{URI.encode(intent)}")
68
68
  end
69
69
 
70
- def message(msg)
71
- logger.debug "Message request: msg=#{msg}"
72
- params = {}
73
- params[:q] = msg unless msg.nil?
74
- res = req @access_token, Net::HTTP::Get, '/message', params
75
- logger.debug "Message response: #{res}"
76
- return res
70
+ def post_intents(payload)
71
+ req(logger, @access_token, Net::HTTP::Post, "/intents", {}, payload)
77
72
  end
78
73
 
79
- def converse(session_id, msg, context={})
80
- logger.debug "Converse request: session_id=#{session_id} msg=#{msg} context=#{context}"
81
- raise WitException.new 'context should be a Hash' unless context.is_a? Hash
82
- params = {}
83
- params[:q] = msg unless msg.nil?
84
- params[:session_id] = session_id
85
- res = req @access_token, Net::HTTP::Post, '/converse', params, context
86
- logger.debug "Converse response: #{res}"
87
- return res
74
+ def delete_intents(intent)
75
+ req(logger, @access_token, Net::HTTP::Delete, "/intents/#{URI.encode(intent)}")
88
76
  end
89
77
 
90
- def run_actions_(session_id, message, context, max_steps, user_message)
91
- raise WitException.new 'max iterations reached' unless max_steps > 0
78
+ def get_entities
79
+ req(logger, @access_token, Net::HTTP::Get, "/entities")
80
+ end
92
81
 
93
- rst = converse session_id, message, context
94
- raise WitException.new 'couldn\'t find type in Wit response' unless rst.has_key? 'type'
82
+ def post_entities(payload)
83
+ payload = payload.map {|k, v| [(k.to_sym rescue k), v]}.to_h.reject{ |k| ![:name, :roles, :lookups, :keywords].include?(k) }
84
+ validate_payload payload
85
+ req(logger, @access_token, Net::HTTP::Post, "/entities", {}, payload)
86
+ end
95
87
 
96
- type = rst['type']
88
+ def get_entity(entity)
89
+ req(logger, @access_token, Net::HTTP::Get, "/entities/#{URI.encode(entity)}")
90
+ end
97
91
 
98
- return context if type == 'stop'
99
- if type == 'msg'
100
- raise WitException.new 'unknown action: say' unless @actions.has_key? :say
101
- msg = rst['msg']
102
- logger.info "Executing say with: #{msg}"
103
- @actions[:say].call session_id, context.clone, msg
104
- elsif type == 'merge'
105
- raise WitException.new 'unknown action: merge' unless @actions.has_key? :merge
106
- logger.info 'Executing merge'
107
- context = @actions[:merge].call session_id, context.clone, rst['entities'], user_message
108
- if context.nil?
109
- logger.warn 'missing context - did you forget to return it?'
110
- context = {}
111
- end
112
- elsif type == 'action'
113
- action = rst['action'].to_sym
114
- raise WitException.new "unknown action: #{action}" unless @actions.has_key? action
115
- logger.info "Executing action #{action}"
116
- context = @actions[action].call session_id, context.clone
117
- if context.nil?
118
- logger.warn 'missing context - did you forget to return it?'
119
- context = {}
120
- end
121
- elsif type == 'error'
122
- raise WitException.new 'unknown action: error' unless @actions.has_key? :error
123
- logger.info 'Executing error'
124
- @actions[:error].call session_id, context.clone, WitException.new('Oops, I don\'t know what to do.')
125
- else
126
- raise WitException.new "unknown type: #{type}"
127
- end
128
- return run_actions_ session_id, nil, context, max_steps - 1, user_message
92
+ def put_entities(entity, payload)
93
+ payload = payload.map {|k, v| [(k.to_sym rescue k), v]}.to_h.reject{ |k| ![:name, :roles, :lookups, :keywords].include?(k) }
94
+ validate_payload payload
95
+ req(logger, @access_token, Net::HTTP::Put, "/entities/#{URI.encode(entity)}", {}, payload)
129
96
  end
130
97
 
131
- def run_actions(session_id, message, context={}, max_steps=DEFAULT_MAX_STEPS)
132
- raise WitException.new 'context should be a Hash' unless context.is_a? Hash
133
- return run_actions_ session_id, message, context, max_steps, message
98
+ def delete_entities(entity)
99
+ req(logger, @access_token, Net::HTTP::Delete, "/entities/#{URI.encode(entity)}")
134
100
  end
135
101
 
136
- def interactive(context={}, max_steps=DEFAULT_MAX_STEPS)
137
- session_id = SecureRandom.uuid
102
+ def post_entities_keywords(entity, payload)
103
+ payload = payload.map {|k, v| [(k.to_sym rescue k), v]}.to_h.reject{ |k| ![:keyword, :synonyms].include?(k) }
104
+ validate_payload payload
105
+ req(logger, @access_token, Net::HTTP::Post, "/entities/#{URI.encode(entity)}/keywords", {}, payload)
106
+ end
138
107
 
139
- while true
140
- print '> '
141
- msg = gets.strip
108
+ def delete_entities_keywords(entity, keyword)
109
+ req(logger, @access_token, Net::HTTP::Delete, "/entities/#{URI.encode(entity)}/keywords/#{URI.encode(keyword)}")
110
+ end
142
111
 
143
- begin
144
- context = run_actions(session_id, msg, context, max_steps)
145
- rescue WitException => exp
146
- p exp.message
147
- end
112
+ def post_entities_keywords_synonyms(entity, keyword, payload)
113
+ payload = payload.map {|k, v| [(k.to_sym rescue k), v]}.to_h.reject{ |k| ![:synonym].include?(k) }
114
+ validate_payload payload
115
+ req(logger,@access_token, Net::HTTP::Post, "/entities/#{URI.encode(entity)}/keywords/#{URI.encode(keyword)}/synonyms", {}, payload)
116
+ end
117
+
118
+ def delete_entities_keywords_synonyms(entity, keyword, synonym)
119
+ req(logger,@access_token, Net::HTTP::Delete, "/entities/#{URI.encode(entity)}/keywords/#{URI.encode(keyword)}/synonyms/#{URI.encode(synonym)}")
120
+ end
121
+
122
+ def get_traits
123
+ req(logger, @access_token, Net::HTTP::Get, "/traits")
124
+ end
125
+
126
+ def get_trait(trait)
127
+ req(logger, @access_token, Net::HTTP::Get, "/traits/#{URI.encode(trait)}")
128
+ end
129
+
130
+ def post_traits(payload)
131
+ req(logger, @access_token, Net::HTTP::Post, "/traits", {}, payload)
132
+ end
133
+
134
+ def post_traits_values(trait, payload)
135
+ req(logger, @access_token, Net::HTTP::Post, "/traits/#{URI.encode(trait)}/values", {}, payload)
136
+ end
137
+
138
+ def delete_traits_values(trait, value)
139
+ req(logger, @access_token, Net::HTTP::Delete, "/traits/#{URI.encode(trait)}/values/#{URI.encode(value)}")
140
+ end
141
+
142
+ def delete_traits(trait)
143
+ req(logger, @access_token, Net::HTTP::Delete, "/traits/#{URI.encode(trait)}")
144
+ end
145
+
146
+ private
147
+
148
+ def validate_payload(payload)
149
+ key_types = {
150
+ id: String,
151
+ name: String,
152
+ roles: Array,
153
+ lookups: Array,
154
+ keywords: Array,
155
+ }
156
+ payload.each do |k, v|
157
+ raise Error.new("#{k.to_s} in request body must be #{key_types[k].to_s} type") unless key_types[k] == v.class
148
158
  end
149
- rescue Interrupt => _exp
150
- puts
151
159
  end
152
160
 
153
- private :run_actions_
161
+ def req(logger, access_token, meth_class, path, params={}, payload={})
162
+ uri = URI(WIT_API_HOST + path)
163
+ uri.query = URI.encode_www_form(params)
164
+
165
+ logger.debug("#{meth_class} #{uri}")
166
+
167
+ request = meth_class.new(uri)
168
+ request['authorization'] = 'Bearer ' + access_token
169
+ request['accept'] = 'application/vnd.wit.' + WIT_API_VERSION + '+json'
170
+ request.add_field 'Content-Type', 'application/json'
171
+ request.body = payload.to_json
172
+
173
+ Net::HTTP.start(uri.host, uri.port, {:use_ssl => uri.scheme == 'https'}) do |http|
174
+ rsp = http.request(request)
175
+ if rsp.code.to_i != 200
176
+ raise Error.new("HTTP error code=#{rsp.code}")
177
+ end
178
+ json = JSON.parse(rsp.body)
179
+ if json.is_a?(Hash) and json.has_key?('error')
180
+ raise Error.new("Wit responded with an error: #{json['error']}")
181
+ end
182
+ logger.debug("#{meth_class} #{uri} #{json}")
183
+ json
184
+ end
185
+ end
154
186
  end
@@ -1,7 +1,8 @@
1
+ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = 'wit'
3
- s.version = '3.4.0'
4
- s.date = Date.today.to_s
5
+ s.version = '7.0.0'
5
6
  s.summary = 'Ruby SDK for Wit.ai'
6
7
  s.description = 'Ruby SDK for Wit.ai'
7
8
  s.authors = ['The Wit Team']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wit
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 7.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Wit Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-23 00:00:00.000000000 Z
11
+ date: 2020-05-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby SDK for Wit.ai
14
14
  email: help@wit.ai
@@ -16,14 +16,19 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - ".github/ISSUE_TEMPLATE.md"
19
20
  - ".gitignore"
20
21
  - CHANGES.md
22
+ - CODE_OF_CONDUCT.md
23
+ - CONTRIBUTING.md
21
24
  - Gemfile
22
25
  - LICENSE
23
26
  - README.md
27
+ - examples/basic.rb
28
+ - examples/celebrities.rb
24
29
  - examples/joke.rb
25
- - examples/quickstart.rb
26
- - examples/template.rb
30
+ - examples/wit-example-celebrities.zip
31
+ - examples/wit-example-joke-bot.zip
27
32
  - lib/wit.rb
28
33
  - wit.gemspec
29
34
  homepage: https://wit.ai
@@ -45,8 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
45
50
  - !ruby/object:Gem::Version
46
51
  version: '0'
47
52
  requirements: []
48
- rubyforge_project:
49
- rubygems_version: 2.4.5
53
+ rubygems_version: 3.1.3
50
54
  signing_key:
51
55
  specification_version: 4
52
56
  summary: Ruby SDK for Wit.ai
@@ -1,37 +0,0 @@
1
- require 'wit'
2
-
3
- # Quickstart example
4
- # See https://wit.ai/l5t/Quickstart
5
-
6
- access_token = ARGV.shift
7
- unless access_token
8
- puts 'usage: ruby examples/quickstart.rb <access-token>'
9
- exit
10
- end
11
-
12
- def first_entity_value(entities, entity)
13
- return nil unless entities.has_key? entity
14
- val = entities[entity][0]['value']
15
- return nil if val.nil?
16
- return val.is_a?(Hash) ? val['value'] : val
17
- end
18
-
19
- actions = {
20
- :say => -> (session_id, context, msg) {
21
- p msg
22
- },
23
- :merge => -> (session_id, context, entities, msg) {
24
- loc = first_entity_value entities, 'location'
25
- context['loc'] = loc unless loc.nil?
26
- return context
27
- },
28
- :error => -> (session_id, context, error) {
29
- p error.message
30
- },
31
- :'fetch-weather' => -> (session_id, context) {
32
- context['forecast'] = 'sunny'
33
- return context
34
- },
35
- }
36
- client = Wit.new access_token, actions
37
- client.interactive
@@ -1,19 +0,0 @@
1
- require 'wit'
2
-
3
- access_token = 'YOUR_ACCESS_TOKEN'
4
-
5
- actions = {
6
- :say => -> (session_id, context, msg) {
7
- p msg
8
- },
9
- :merge => -> (session_id, context, entities, msg) {
10
- return context
11
- },
12
- :error => -> (session_id, context, error) {
13
- p error.message
14
- },
15
- }
16
- client = Wit.new access_token, actions
17
-
18
- session_id = 'my-user-id-42'
19
- client.run_actions session_id, 'your message', {}