Sapcai 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9e47964ce4e02cec9d7da03829d841a75453b96aa4d6af59f30835a7a019c3cc
4
+ data.tar.gz: 78541aae03f89f1f90269261b68b8c6646da70aad56046e18726b5ad6db67355
5
+ SHA512:
6
+ metadata.gz: c8c6cd91f3ecb5247bdd8569db561cbd5a009b43cf2e3dd227b4252ced1ebfc74eea987915532789fb7e9b38cfe5ee51cbe5ac97e9e6f0dd1977bb897a197c0d
7
+ data.tar.gz: 1220701dc3be3056758d54f3da07dac8785ec839c7a652e8e2b99cbd1525d940edad41bc14df2d3a9c805eb0791b8d5c61e82c3102dc931432583a8082433085
@@ -0,0 +1,26 @@
1
+ # Default
2
+ cache
3
+ log/*.log
4
+ VM/*.log
5
+ tmp/**/*
6
+ public/system/**
7
+ public/uploads/
8
+ db/schema.rb
9
+ dump.rdb
10
+ coverage/
11
+
12
+ # Configuration
13
+ config/application.yml
14
+ config/database.yml
15
+ config/secrets.yml
16
+
17
+ # OS-Generated
18
+ .DS_Store
19
+
20
+ # IDE-Generated
21
+ .idea/
22
+ .bashrc
23
+
24
+ # Misc
25
+ *~
26
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,14 @@
1
+ Metrics/LineLength:
2
+ Max: 9999
3
+ Metrics/MethodLength:
4
+ Max: 9999
5
+ Style/Documentation:
6
+ Enabled: false
7
+ Style/SpaceBeforeBlockBraces:
8
+ EnforcedStyle: no_space
9
+ Style/RedundantSelf:
10
+ Enabled: false
11
+ Style/WordArray:
12
+ Enabled: false
13
+ Style/RaiseArgs:
14
+ EnforcedStyle: compact
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ Sapcai (4.0.0)
5
+ httmultiparty (~> 0.3)
6
+ httparty (~> 0.13)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.4.0)
12
+ awesome_print (1.6.1)
13
+ crack (0.4.3)
14
+ safe_yaml (~> 1.0.0)
15
+ diff-lcs (1.2.5)
16
+ docile (1.3.1)
17
+ hashdiff (0.3.0)
18
+ httmultiparty (0.3.16)
19
+ httparty (>= 0.7.3)
20
+ mimemagic
21
+ multipart-post
22
+ httparty (0.16.3)
23
+ mime-types (~> 3.0)
24
+ multi_xml (>= 0.5.2)
25
+ json (2.1.0)
26
+ mime-types (3.2.2)
27
+ mime-types-data (~> 3.2015)
28
+ mime-types-data (3.2018.0812)
29
+ mimemagic (0.3.2)
30
+ multi_xml (0.6.0)
31
+ multipart-post (2.0.0)
32
+ rspec (3.4.0)
33
+ rspec-core (~> 3.4.0)
34
+ rspec-expectations (~> 3.4.0)
35
+ rspec-mocks (~> 3.4.0)
36
+ rspec-core (3.4.4)
37
+ rspec-support (~> 3.4.0)
38
+ rspec-expectations (3.4.0)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.4.0)
41
+ rspec-mocks (3.4.1)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.4.0)
44
+ rspec-support (3.4.1)
45
+ safe_yaml (1.0.4)
46
+ simplecov (0.16.1)
47
+ docile (~> 1.1)
48
+ json (>= 1.8, < 3)
49
+ simplecov-html (~> 0.10.0)
50
+ simplecov-html (0.10.2)
51
+ webmock (1.24.2)
52
+ addressable (>= 2.3.6)
53
+ crack (>= 0.3.2)
54
+ hashdiff
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ Sapcai!
61
+ awesome_print (~> 1.6)
62
+ rspec (~> 3.4)
63
+ simplecov (~> 0.15)
64
+ webmock (~> 1.24)
65
+
66
+ BUNDLED WITH
67
+ 1.17.1
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 SAP Conversational AI
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,76 @@
1
+
2
+
3
+ [logo]: https://cdn.cai.tools.sap/brand/sapcai/sap-cai-black.svg "SAP Conversational AI"
4
+
5
+ ![alt text][logo]
6
+
7
+ # SAP Conversational AI - SDK Ruby
8
+
9
+ SAP Conversational AI official SDK in Ruby
10
+
11
+ ## Synospis
12
+
13
+ This module is a wrapper around the [SAP Conversational AI](https://cai.tools.sap) API, and allows you to:
14
+ * [Analyse your text](https://github.com/SAPConversationalAI/SDK-Ruby/wiki/01---Analyse-text)
15
+ * [Manage a conversation](https://github.com/SAPConversationalAI/SDK-Ruby/wiki/02---Manage-conversation)
16
+ * [Receive and send messages](https://github.com/SAPConversationalAI/SDK-Ruby/wiki/03---Receive-and-send-messages)
17
+
18
+ ## Installation
19
+
20
+ This gem supports ruby 2.3+.
21
+
22
+ ```bash
23
+ gem install Sapcai
24
+ ```
25
+
26
+ You can now use the SDK in your code. All you need is your bot's token. In case you have enabled our versioning feature in the settings of your bot, you can refer to our [versioning documentation](https://cai.tools.sap/docs/concepts/versioning) to learn how to select the appropriate token for you versions and environments.
27
+
28
+ Using the entire SDK:
29
+ ```ruby
30
+ require 'sapcai'
31
+
32
+ client = Sapcai::Client.new('YOUR_TOKEN')
33
+
34
+ client.request.analyse_text('Hi')
35
+ client.connect.broadcast_message('Hello')
36
+ ```
37
+
38
+ Extracting one single API:
39
+ ```ruby
40
+ require 'sapcai'
41
+
42
+ request = Sapcai::Request.new('YOUR_TOKEN')
43
+ request.analyse_text('Hi')
44
+
45
+ connect = Sapcai::Connect.new('YOUR_TOKEN')
46
+ connect.broadcast_message('Hi')
47
+ ```
48
+
49
+ ## More
50
+
51
+ You can view the whole API reference at [cai.tools.sap/docs/](https://cai.tools.sap/docs/api-reference).
52
+
53
+ You can follow us on Twitter at [@sapcai](https://twitter.com/sapcai) for updates and releases.
54
+
55
+
56
+ ## License
57
+
58
+ Copyright (c) [2019] [SAP Conversational AI](https://cai.tools.sap)
59
+
60
+ Permission is hereby granted, free of charge, to any person obtaining a copy
61
+ of this software and associated documentation files (the "Software"), to deal
62
+ in the Software without restriction, including without limitation the rights
63
+ to tsuse, copy, modify, merge, publish, distribute, sublicense, and/or sell
64
+ copies of the Software, and to permit persons to whom the Software is
65
+ furnished to do so, subject to the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be included in all
68
+ copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
75
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
76
+ SOFTWARE.
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ require_relative '../lib/sapcai'
6
+
7
+ options = {}
8
+ OptionParser.new do |opts|
9
+ opts.banner = "Usage: sapcaicli -[-t]oken TOKEN <--text TEXT | --file FILE>"
10
+
11
+ opts.on('-t', '--token=TOKEN', String, "the request token to use for the call") do |t|
12
+ options[:token] = t
13
+ end
14
+
15
+ opts.on('--text=TEXT', String, 'the text to process') do |t|
16
+ options[:text] = t
17
+ end
18
+
19
+ opts.on('--file=FILE', String, 'the file to process') do |f|
20
+ options[:file] = f
21
+ end
22
+
23
+ opts.on("-h", "--help", "Prints this help") do
24
+ puts opts
25
+ exit
26
+ end
27
+ end.parse!
28
+
29
+ client = Sapcai::Client.new(options[:token])
30
+
31
+ if options[:text]
32
+ response = client.request.analyse_text(options[:text])
33
+ elsif options[:file]
34
+ response = client.request.analyse_file(options[:file])
35
+ else
36
+ raise OptionParser::MissingArgument.new('You need to give either --text or --file')
37
+ end
38
+
39
+ puts response.intent
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+
5
+ require 'json'
6
+ require 'httparty'
7
+ require 'httmultiparty'
8
+
9
+ require 'sapcai/utils'
10
+ require 'sapcai/apis/connect/connect'
11
+ require 'sapcai/apis/request/request'
12
+ require 'sapcai/apis/build/build'
13
+
14
+ module Sapcai
15
+ class Client
16
+ attr_reader :token, :language
17
+
18
+ def initialize(token = nil, language = nil)
19
+ [Sapcai::Request, Sapcai::Connect, Sapcai::Build].each do |api|
20
+ i = api.name.rindex('::')
21
+ name = i.nil? ? api.name : api.name[(i + 2)..-1]
22
+
23
+ self.class.send(:define_method, name.downcase.to_sym, ->{ api.new(token, language) })
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+
3
+ require 'httparty'
4
+
5
+ require_relative 'dialog_response'
6
+ require_relative 'dialog_message'
7
+ require_relative 'dialog_conversation'
8
+
9
+ module Sapcai
10
+ class Build
11
+ attr_reader :token, :language
12
+
13
+ def initialize(token = nil, language = nil)
14
+ @token = token
15
+ @language = language
16
+ end
17
+
18
+ def headers
19
+ { 'Authorization' => "Token #{@token}", 'Content-Type' => 'application/json' }
20
+ end
21
+
22
+ def dialog(msg, conversation_id, language = nil, options = {})
23
+ raise Sapcai::SapcaiError.new('Token is missing') unless @token
24
+
25
+ log_level = options[:log_level] || "info"
26
+ proxy = options[:proxy] || {}
27
+
28
+ language = @language if language.nil?
29
+ body = { message: msg, conversation_id: conversation_id, language: language, log_level: log_level}
30
+ body[:memory] = options[:memory] unless options[:memory].nil?
31
+
32
+ options = { body: body.to_json, headers: self.headers }
33
+ if proxy != {}
34
+ options[:http_proxyaddr] = proxy[:host]
35
+ options[:http_proxyport] = proxy[:port]
36
+ end
37
+ response = HTTParty.post("#{Sapcai::Utils::BUILD_ENDPOINT}/dialog", options)
38
+ raise Sapcai::SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
39
+
40
+ res = JSON.parse(response.body)['results']
41
+ Sapcai::DialogResponse.new(res['messages'], res['conversation'], res['nlp'], res['logs'])
42
+ end
43
+
44
+ def update_conversation(user, bot, version, conversation_id, opts)
45
+ raise Sapcai::SapcaiError.new('Token is missing') unless @token
46
+
47
+ body = opts
48
+
49
+ url = "#{Sapcai::Utils::BUILD_ENDPOINT}/users/#{user}/bots/#{bot}/versions/#{version}/builder/conversation_states/#{conversation_id}"
50
+ response = HTTParty.put(url, body: body.to_json, headers: self.headers)
51
+ raise Sapcai::SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
52
+
53
+ Sapcai::DialogConversation.new(JSON.parse(response.body)['results'])
54
+ end
55
+
56
+ def get_conversation(user, bot, version, conversation_id)
57
+ raise Sapcai::SapcaiError.new('Token is missing') unless @token
58
+
59
+ url = "#{Sapcai::Utils::BUILD_ENDPOINT}/users/#{user}/bots/#{bot}/versions/#{version}/builder/conversation_states/#{conversation_id}"
60
+ response = HTTParty.get(url, headers: self.headers)
61
+ raise Sapcai::SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
62
+
63
+ Sapcai::DialogConversation.new(JSON.parse(response.body)['results'])
64
+ end
65
+
66
+ def delete_conversation(user, bot, version, conversation_id)
67
+ raise Sapcai::SapcaiError.new('Token is missing') unless @token
68
+
69
+ url = "#{Sapcai::Utils::BUILD_ENDPOINT}/users/#{user}/bots/#{bot}/versions/#{version}/builder/conversation_states/#{conversation_id}"
70
+ response = HTTParty.delete(url, headers: self.headers)
71
+ raise Sapcai::SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 204
72
+
73
+ true
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,13 @@
1
+ module Sapcai
2
+ class DialogConversation
3
+ attr_reader :id, :language, :memory, :skill, :skill_occurences
4
+
5
+ def initialize(conv)
6
+ @id = conv['conversation_id'] || conv['id']
7
+ @language = conv['language']
8
+ @memory = conv['memory']
9
+ @skill = conv['skill'] || conv['last_skill']
10
+ @skill_occurences = conv['skill_occurences'] || skill['last_skill_occurences']
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Sapcai
2
+ class DialogMessage
3
+ attr_reader :type, :content
4
+
5
+ def initialize(msg)
6
+ raise Sapcai::SapcaiError('Invalid message format') unless message_is_valid(msg)
7
+ @type = msg['type']
8
+ @content = msg['content']
9
+ end
10
+
11
+ private
12
+
13
+ def message_is_valid(msg)
14
+ msg.is_a?(Hash) && msg.key?('type') && msg.key?('content')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'dialog_message'
2
+ require_relative 'dialog_conversation'
3
+ require_relative '../request/models/response'
4
+ module Sapcai
5
+ class DialogResponse
6
+ attr_reader :messages, :conversation, :nlp, :logs
7
+
8
+ def initialize(messages, conversation, nlp, logs)
9
+ raise Sapcai::SapcaiError("Invalid messages format: #{messages}") unless messages.is_a?(Array)
10
+
11
+ @messages = messages.map{ |m| Sapcai::DialogMessage.new(m) }
12
+ @conversation = DialogConversation.new(conversation)
13
+ @nlp = Response.new('results' => nlp)
14
+ @logs = logs
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'message'
4
+
5
+ module Sapcai
6
+ class Connect
7
+ include Message
8
+
9
+ attr_reader :token, :language
10
+
11
+ def initialize(token = nil, language = nil)
12
+ @token = token
13
+ @language = language
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'models/message'
4
+ require_relative 'utils'
5
+
6
+ module Sapcai
7
+ module Message
8
+ def handle_message(request, &block)
9
+ request.body.rewind if request.body.respond_to?(:rewind)
10
+ body = request.body.is_a?(String) ? request.body : request.body.read
11
+ message = Msg.new(body)
12
+
13
+ yield(message)
14
+ end
15
+
16
+ def send_message(payload, conversation_id, token: nil)
17
+ token ||= @token
18
+ raise SapcaiError.new('Token is missing') if token.nil?
19
+
20
+ response = HTTParty.post(
21
+ "#{Utils::CONVERSATION_ENDPOINT}#{conversation_id}/messages",
22
+ body: { messages: payload.to_json },
23
+ headers: { 'Authorization' => "Token #{token}" }
24
+ )
25
+ raise SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 201
26
+
27
+ response
28
+ end
29
+
30
+ def broadcast_message(payload, token: nil)
31
+ token ||= @token
32
+ raise SapcaiError.new('Token is missing') if token.nil?
33
+
34
+ response = HTTParty.post(
35
+ Utils::MESSAGE_ENDPOINT,
36
+ body: { messages: payload.to_json },
37
+ headers: { 'Authorization' => "Token #{token}" }
38
+ )
39
+ raise SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 201
40
+
41
+ response
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module Sapcai
4
+ class Msg
5
+ attr_reader :content, :type, :conversation_id
6
+
7
+ def initialize(request)
8
+ request = JSON.parse(request)
9
+ request.each do |k, v|
10
+ k = k.gsub(/(.)([A-Z])/, '\1_\2').downcase
11
+ self.instance_variable_set("@#{k}", v)
12
+ self.define_singleton_method(k.to_sym){ v }
13
+ end
14
+
15
+ @conversation_id = request['message']['conversation']
16
+ @content = request['message']['attachment']['content']
17
+ @type = request['message']['attachment']['type']
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ module Sapcai
4
+ class Utils
5
+ # Endpoints
6
+ MESSAGE_ENDPOINT = 'https://api.cai.tools.sap/connect/v1/messages/'.freeze
7
+ CONVERSATION_ENDPOINT = 'https://api.cai.tools.sap/connect/v1/conversations/'.freeze
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ module Sapcai
4
+ class SapcaiError < RuntimeError
5
+ end
6
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'models/response'
4
+ require_relative 'utils'
5
+ require_relative '../errors'
6
+
7
+ module Sapcai
8
+ module Analyse
9
+ def analyse_text(text, token: nil, language: nil)
10
+ token ||= @token
11
+ raise SapcaiError.new('Token is missing') if token.nil?
12
+
13
+ language ||= @language
14
+
15
+ body = { text: text }
16
+ body[:language] = language unless language.nil?
17
+ response = HTTParty.post(
18
+ Utils::REQUEST_ENDPOINT,
19
+ body: body,
20
+ headers: { 'Authorization' => "Token #{token}" }
21
+ )
22
+ raise SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
23
+
24
+ Response.new(JSON.parse(response.body))
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'models/conversation'
4
+ require_relative 'utils'
5
+ require_relative '../errors'
6
+
7
+ module Sapcai
8
+ module Converse
9
+ def converse_text(text, token: nil, language: nil, conversation_token: nil, memory: nil)
10
+ token ||= @token
11
+ raise SapcaiError.new('Token is missing') if token.nil?
12
+
13
+ language ||= @language
14
+
15
+ body = { text: text }
16
+ body[:language] = language unless language.nil?
17
+ body[:conversation_token] = conversation_token unless conversation_token.nil?
18
+ body[:memory] = memory unless memory.nil?
19
+
20
+ response = HTTParty.post(
21
+ Utils::CONVERSE_ENDPOINT,
22
+ body: body,
23
+ headers: { 'Authorization' => "Token #{token}" }
24
+ )
25
+ raise SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
26
+
27
+ Conversation.new(response.body, token)
28
+ end
29
+
30
+ def converse_file(file, token: nil, language: nil, conversation_token: nil, memory: nil)
31
+ token ||= @token
32
+ raise SapcaiError.new('Token is missing') if token.nil?
33
+
34
+ language ||= @language
35
+
36
+ body = { voice: File.new(file) }
37
+ body[:language] = language unless language.nil?
38
+ body[:conversation_token] = conversation_token unless conversation_token.nil?
39
+ body[:memory] = memory unless memory.nil?
40
+ response = HTTMultiParty.post(
41
+ Utils::CONVERSE_ENDPOINT,
42
+ body: body,
43
+ headers: { 'Authorization' => "Token #{token}" }
44
+ )
45
+ raise SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
46
+
47
+ Conversation.new(response.body, token)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Sapcai
4
+ class Action
5
+ attr_reader :slug
6
+ attr_reader :done
7
+ attr_reader :reply
8
+
9
+ def initialize(action)
10
+ @slug = action['slug']
11
+ @done = action['done']
12
+ @reply = action['reply']
13
+ end
14
+
15
+ def done?
16
+ @done
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'action'
4
+ require_relative 'entity'
5
+ require_relative 'intent'
6
+ require_relative '../utils'
7
+
8
+ module Sapcai
9
+ class Conversation
10
+ attr_reader :raw, :uuid, :source, :replies, :action, :next_actions, :memory, :entities, :sentiment, :intents,
11
+ :conversation_token, :language, :processing_language, :version, :timestamp, :status
12
+
13
+ def initialize(response, token)
14
+ @token = token
15
+
16
+ @raw = response
17
+
18
+ response = JSON.parse(response)
19
+ response = response['results']
20
+
21
+ @uuid = response['uuid']
22
+ @source = response['source']
23
+ @replies = response['replies']
24
+ @action = response['action'] ? Action.new(response['action']) : nil
25
+ @next_actions = response['next_actions'].map{ |i| Action.new(i) }
26
+ @sentiment = response['sentiment']
27
+ @memory = response['memory'].reject{ |_, e| e.nil? }.map{ |n, e| Entity.new(n, e) }
28
+ @entities = response['entities'].flat_map{ |n, e| e.map{ |ee| Entity.new(n, ee) } }
29
+ @intents = response['intents'].map{ |i| Intent.new(i) }
30
+ @conversation_token = response['conversation_token']
31
+ @language = response['language']
32
+ @processing_language = response['processing_language']
33
+ @version = response['version']
34
+ @timestamp = response['timestamp']
35
+ @status = response['status']
36
+ end
37
+
38
+ def reply
39
+ @replies.any? ? @replies.first : nil
40
+ end
41
+
42
+ def next_action
43
+ @next_actions.any? ? @next_actions.first : nil
44
+ end
45
+
46
+ def joined_replies(sep = ' ')
47
+ @replies.join(sep)
48
+ end
49
+
50
+ def get_memory(key = nil)
51
+ return @memory if key.nil?
52
+
53
+ @memory.each do |entity|
54
+ return entity if entity.name.casecmp(key.to_s).zero?
55
+ end
56
+
57
+ nil
58
+ end
59
+
60
+ def intent
61
+ @intents.any? ? @intents.first : nil
62
+ end
63
+
64
+ def vpositive?
65
+ @sentiment == Utils::SENTIMENT_VPOSITIVE
66
+ end
67
+
68
+ def positive?
69
+ @sentiment == Utils::SENTIMENT_POSITIVE
70
+ end
71
+
72
+ def neutral?
73
+ @sentiment == Utils::SENTIMENT_NEUTRAL
74
+ end
75
+
76
+ def negative?
77
+ @sentiment == Utils::SENTIMENT_NEGATIVE
78
+ end
79
+
80
+ def vnegative?
81
+ @sentiment == Utils::SENTIMENT_VNEGATIVE
82
+ end
83
+
84
+ def set_memory(memory)
85
+ body = { conversation_token: @conversation_token, memory: memory }
86
+ response = HTTParty.put(
87
+ Utils::CONVERSE_ENDPOINT,
88
+ body: body,
89
+ headers: { 'Authorization' => "Token #{@token}" }
90
+ )
91
+ raise SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
92
+
93
+ response = JSON.parse(response.body)
94
+ response = response['results']
95
+ response['memory'].reject{ |_, e| e.nil? }.map{ |n, e| Entity.new(n, e) }
96
+ end
97
+
98
+ def reset_memory(name = nil)
99
+ body = { conversation_token: @conversation_token }
100
+ body[:memory] = { name => nil } unless name.nil?
101
+
102
+ response = HTTParty.put(
103
+ Utils::CONVERSE_ENDPOINT,
104
+ body: body,
105
+ headers: { 'Authorization' => "Token #{@token}" }
106
+ )
107
+ raise SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
108
+
109
+ response = JSON.parse(response.body)
110
+ response = response['results']
111
+ response['memory'].reject{ |_, e| e.nil? }.map{ |n, e| Entity.new(n, e) }
112
+ end
113
+
114
+ def reset_conversation
115
+ body = { conversation_token: @conversation_token }
116
+ response = HTTParty.delete(
117
+ Utils::CONVERSE_ENDPOINT,
118
+ body: body,
119
+ headers: { 'Authorization' => "Token #{@token}" }
120
+ )
121
+ raise SapcaiError.new(JSON.parse(response.body)['message']) if response.code != 200
122
+
123
+ response = JSON.parse(response.body)
124
+ response = response['results']
125
+ response['memory'].reject{ |_, e| e.nil? }.map{ |n, e| Entity.new(n, e) }
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ module Sapcai
4
+ class Entity
5
+ attr_reader :name
6
+
7
+ def initialize(name, data)
8
+ @name = name
9
+
10
+ data.each_pair do |k, v|
11
+ self.instance_variable_set("@#{k}", v)
12
+ self.define_singleton_method(k.to_sym){ v }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ module Sapcai
4
+ class Intent
5
+ attr_reader :slug
6
+ attr_reader :confidence
7
+
8
+ def initialize(intent)
9
+ @slug = intent['slug']
10
+ @confidence = intent['confidence']
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,119 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'intent'
4
+ require_relative 'entity'
5
+ require_relative '../utils'
6
+
7
+ module Sapcai
8
+ class Response
9
+ attr_reader :raw
10
+ attr_reader :uuid
11
+ attr_reader :source
12
+ attr_reader :intents
13
+ attr_reader :act
14
+ attr_reader :type
15
+ attr_reader :sentiment
16
+ attr_reader :entities
17
+ attr_reader :language
18
+ attr_reader :processing_language
19
+ attr_reader :version
20
+ attr_reader :timestamp
21
+ attr_reader :status
22
+
23
+ def initialize(response)
24
+ @raw = JSON.dump(response)
25
+ response = response['results']
26
+
27
+ @uuid = response['uuid']
28
+ @source = response['source']
29
+ @intents = response['intents'].map{ |i| Intent.new(i) }
30
+ @act = response['act']
31
+ @type = response['type']
32
+ @sentiment = response['sentiment']
33
+ @entities = response['entities'].flat_map{ |n, e| e.map{ |ee| Entity.new(n, ee) } }
34
+ @language = response['language']
35
+ @processing_language = response['processing_language']
36
+ @version = response['version']
37
+ @timestamp = response['timestamp']
38
+ @status = response['status']
39
+ end
40
+
41
+ def intent
42
+ @intents.any? ? @intents.first : nil
43
+ end
44
+
45
+ def get(name)
46
+ @entities.each do |entity|
47
+ return entity if entity.name.casecmp(name.to_s).zero?
48
+ end
49
+
50
+ nil
51
+ end
52
+
53
+ def all(name)
54
+ @entities.select do |entity|
55
+ entity.name.casecmp(name.to_s).zero?
56
+ end
57
+ end
58
+
59
+ def assert?
60
+ @act == Utils::ACT_ASSERT
61
+ end
62
+
63
+ def command?
64
+ @act == Utils::ACT_COMMAND
65
+ end
66
+
67
+ def wh_query?
68
+ @act == Utils::ACT_WH_QUERY
69
+ end
70
+
71
+ def yn_query?
72
+ @act == Utils::ACT_YN_QUERY
73
+ end
74
+
75
+ def abbreviation?
76
+ !@type.index(Utils::TYPE_ABBREVIATION).nil?
77
+ end
78
+
79
+ def entity?
80
+ !@type.index(Utils::TYPE_ENTITY).nil?
81
+ end
82
+
83
+ def description?
84
+ !@type.index(Utils::TYPE_DESCRIPTION).nil?
85
+ end
86
+
87
+ def human?
88
+ !@type.index(Utils::TYPE_HUMAN).nil?
89
+ end
90
+
91
+ def location?
92
+ !@type.index(Utils::TYPE_LOCATION).nil?
93
+ end
94
+
95
+ def number?
96
+ !@type.index(Utils::TYPE_NUMBER).nil?
97
+ end
98
+
99
+ def vpositive?
100
+ @sentiment == Utils::SENTIMENT_VPOSITIVE
101
+ end
102
+
103
+ def positive?
104
+ @sentiment == Utils::SENTIMENT_POSITIVE
105
+ end
106
+
107
+ def neutral?
108
+ @sentiment == Utils::SENTIMENT_NEUTRAL
109
+ end
110
+
111
+ def negative?
112
+ @sentiment == Utils::SENTIMENT_NEGATIVE
113
+ end
114
+
115
+ def vnegative?
116
+ @sentiment == Utils::SENTIMENT_VNEGATIVE
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'analyse'
4
+ require_relative 'converse'
5
+
6
+ module Sapcai
7
+ class Request
8
+ include Converse
9
+ include Analyse
10
+
11
+ attr_reader :token, :language
12
+
13
+ def initialize(token = nil, language = nil)
14
+ @token = token
15
+ @language = language
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module Sapcai
4
+ class Utils
5
+ # Endpoints
6
+ REQUEST_ENDPOINT = 'https://api.cai.tools.sap/v2/request/'.freeze
7
+ CONVERSE_ENDPOINT = 'https://api.cai.tools.sap/v2/converse/'.freeze
8
+
9
+ # Act constants
10
+ ACT_ASSERT = 'assert'.freeze
11
+ ACT_COMMAND = 'command'.freeze
12
+ ACT_WH_QUERY = 'wh-query'.freeze
13
+ ACT_YN_QUERY = 'yn-query'.freeze
14
+
15
+ # Type constants
16
+ TYPE_ABBREVIATION = 'abbr:'.freeze
17
+ TYPE_ENTITY = 'enty:'.freeze
18
+ TYPE_DESCRIPTION = 'desc:'.freeze
19
+ TYPE_HUMAN = 'hum:'.freeze
20
+ TYPE_LOCATION = 'loc:'.freeze
21
+ TYPE_NUMBER = 'num:'.freeze
22
+
23
+ # Sentiment constants
24
+ SENTIMENT_VPOSITIVE = 'vpositive'.freeze
25
+ SENTIMENT_POSITIVE = 'positive'.freeze
26
+ SENTIMENT_NEUTRAL = 'neutral'.freeze
27
+ SENTIMENT_NEGATIVE = 'negative'.freeze
28
+ SENTIMENT_VNEGATIVE = 'vnegative'.freeze
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module Sapcai
4
+ class Utils
5
+ # Versioning
6
+ MAJOR = '4'.freeze
7
+ MINOR = '0'.freeze
8
+ PATCH = '0'.freeze
9
+ VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}".freeze
10
+
11
+ # Endpoints
12
+ TRAIN_ENDPOINT = 'https://api.cai.tools.sap/v2/'.freeze
13
+ CONNECT_ENDPOINT = 'https://api.cai.tools.sap/connect/v1/'.freeze
14
+ HOST_ENDPOINT = 'https://api.cai.tools.sap/host/v1/'.freeze
15
+ MONITOR_ENDPOINT = 'https://api.cai.tools.sap/monitor/v1/'.freeze
16
+ BUILD_ENDPOINT = 'https://api.cai.tools.sap/build/v1'.freeze
17
+ end
18
+ end
File without changes
Binary file
Binary file
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ dir = File.dirname(__FILE__)
4
+ $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir)
5
+
6
+ require 'date'
7
+ require 'lib/sapcai/utils'
8
+
9
+ Gem::Specification.new do |spec|
10
+ spec.name = 'Sapcai'
11
+ spec.version = Sapcai::Utils::VERSION
12
+ spec.date = Date.today
13
+ spec.summary = 'SAP Conversational AI official SDK for Ruby'
14
+ spec.description = 'SAP Conversational AI official SDK for Ruby. Allows you to make requests to your bots.'
15
+ spec.homepage = 'https://github.com/SAPConversationalAI/SDK-ruby'
16
+ spec.license = 'MIT'
17
+ spec.authors = ['SAP CAI team']
18
+ spec.files = `git ls-files -z`.split("\x0").reject{ |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.executables = ['sapcaicli']
20
+ spec.require_paths = ['lib']
21
+ spec.required_ruby_version = '>= 2.2'
22
+
23
+ spec.add_dependency 'httparty', '~> 0.13'
24
+ spec.add_dependency 'httmultiparty', '~> 0.3'
25
+
26
+ spec.add_development_dependency 'rspec', '~> 3.4'
27
+ spec.add_development_dependency 'webmock', '~> 1.24'
28
+ spec.add_development_dependency 'awesome_print', '~> 1.6'
29
+ spec.add_development_dependency 'simplecov', '~> 0.15'
30
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: Sapcai
3
+ version: !ruby/object:Gem::Version
4
+ version: 4.0.0
5
+ platform: ruby
6
+ authors:
7
+ - SAP CAI team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.13'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httmultiparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
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.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.24'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.24'
69
+ - !ruby/object:Gem::Dependency
70
+ name: awesome_print
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.15'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.15'
97
+ description: SAP Conversational AI official SDK for Ruby. Allows you to make requests
98
+ to your bots.
99
+ email:
100
+ executables:
101
+ - sapcaicli
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - ".rubocop.yml"
108
+ - Gemfile
109
+ - Gemfile.lock
110
+ - LICENSE
111
+ - README.md
112
+ - bin/sapcaicli
113
+ - lib/sapcai.rb
114
+ - lib/sapcai/apis/build/build.rb
115
+ - lib/sapcai/apis/build/dialog_conversation.rb
116
+ - lib/sapcai/apis/build/dialog_message.rb
117
+ - lib/sapcai/apis/build/dialog_response.rb
118
+ - lib/sapcai/apis/connect/connect.rb
119
+ - lib/sapcai/apis/connect/message.rb
120
+ - lib/sapcai/apis/connect/models/message.rb
121
+ - lib/sapcai/apis/connect/utils.rb
122
+ - lib/sapcai/apis/errors.rb
123
+ - lib/sapcai/apis/request/analyse.rb
124
+ - lib/sapcai/apis/request/converse.rb
125
+ - lib/sapcai/apis/request/models/action.rb
126
+ - lib/sapcai/apis/request/models/conversation.rb
127
+ - lib/sapcai/apis/request/models/entity.rb
128
+ - lib/sapcai/apis/request/models/intent.rb
129
+ - lib/sapcai/apis/request/models/response.rb
130
+ - lib/sapcai/apis/request/request.rb
131
+ - lib/sapcai/apis/request/utils.rb
132
+ - lib/sapcai/utils.rb
133
+ - misc/.gitkeep
134
+ - misc/logo-inline.png
135
+ - misc/recast-ai-tokens.png
136
+ - recastai.gemspec
137
+ homepage: https://github.com/SAPConversationalAI/SDK-ruby
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '2.2'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.7.6
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: SAP Conversational AI official SDK for Ruby
161
+ test_files: []