memori-client 0.1.8 → 0.2.1

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/backend_overrides.jsonc +4 -0
  3. data/engine_overrides.jsonc +3 -0
  4. data/lib/memori_client/client.rb +49 -0
  5. data/lib/memori_client/client_factory.rb +105 -0
  6. data/lib/memori_client/engine/hmac_helper.rb +1 -1
  7. data/lib/memori_client/http_client.rb +4 -17
  8. data/lib/memori_client/operation.rb +132 -0
  9. data/lib/memori_client/proxy/client.rb +115 -0
  10. data/lib/memori_client/railtie.rb +12 -0
  11. data/lib/memori_client/resource.rb +174 -26
  12. data/lib/memori_client/resource_proxy.rb +25 -0
  13. data/lib/memori_client/response.rb +48 -0
  14. data/lib/memori_client/swagger/get_module_and_method.rb +44 -0
  15. data/lib/memori_client/swagger/process_specification.rb +127 -0
  16. data/lib/memori_client/swagger/schema_store.rb +26 -0
  17. data/lib/memori_client/utils/rails.rb +0 -5
  18. data/lib/memori_client.rb +15 -42
  19. data/lib/tasks/memori_client.rake +8 -0
  20. metadata +19 -53
  21. data/lib/memori_client/backend/resource.rb +0 -39
  22. data/lib/memori_client/backend/resources.rb +0 -16
  23. data/lib/memori_client/backend/v1/asset.rb +0 -120
  24. data/lib/memori_client/backend/v2/action_log.rb +0 -44
  25. data/lib/memori_client/backend/v2/analysis.rb +0 -54
  26. data/lib/memori_client/backend/v2/asset.rb +0 -130
  27. data/lib/memori_client/backend/v2/badge.rb +0 -77
  28. data/lib/memori_client/backend/v2/completion_config.rb +0 -202
  29. data/lib/memori_client/backend/v2/consumption_log.rb +0 -70
  30. data/lib/memori_client/backend/v2/import_export.rb +0 -327
  31. data/lib/memori_client/backend/v2/integration.rb +0 -180
  32. data/lib/memori_client/backend/v2/invitation.rb +0 -252
  33. data/lib/memori_client/backend/v2/memori.rb +0 -954
  34. data/lib/memori_client/backend/v2/memori_list.rb +0 -152
  35. data/lib/memori_client/backend/v2/notification.rb +0 -32
  36. data/lib/memori_client/backend/v2/process.rb +0 -70
  37. data/lib/memori_client/backend/v2/tenant.rb +0 -293
  38. data/lib/memori_client/backend/v2/user.rb +0 -1520
  39. data/lib/memori_client/configuration.rb +0 -20
  40. data/lib/memori_client/engine/resource.rb +0 -13
  41. data/lib/memori_client/engine/resources.rb +0 -21
  42. data/lib/memori_client/engine/v2/chat_log.rb +0 -92
  43. data/lib/memori_client/engine/v2/completion_log.rb +0 -17
  44. data/lib/memori_client/engine/v2/context_var.rb +0 -48
  45. data/lib/memori_client/engine/v2/correlation_pair.rb +0 -99
  46. data/lib/memori_client/engine/v2/custom_dictionary.rb +0 -152
  47. data/lib/memori_client/engine/v2/dialog.rb +0 -223
  48. data/lib/memori_client/engine/v2/event_log.rb +0 -98
  49. data/lib/memori_client/engine/v2/expert_reference.rb +0 -176
  50. data/lib/memori_client/engine/v2/function.rb +0 -220
  51. data/lib/memori_client/engine/v2/intent.rb +0 -336
  52. data/lib/memori_client/engine/v2/localization_key.rb +0 -144
  53. data/lib/memori_client/engine/v2/medium.rb +0 -178
  54. data/lib/memori_client/engine/v2/memori.rb +0 -329
  55. data/lib/memori_client/engine/v2/memory.rb +0 -477
  56. data/lib/memori_client/engine/v2/nlp.rb +0 -137
  57. data/lib/memori_client/engine/v2/person.rb +0 -170
  58. data/lib/memori_client/engine/v2/private/memori.rb +0 -17
  59. data/lib/memori_client/engine/v2/private/memori_block.rb +0 -24
  60. data/lib/memori_client/engine/v2/prompted_question.rb +0 -121
  61. data/lib/memori_client/engine/v2/search.rb +0 -318
  62. data/lib/memori_client/engine/v2/session.rb +0 -80
  63. data/lib/memori_client/engine/v2/stat.rb +0 -20
  64. data/lib/memori_client/engine/v2/topic.rb +0 -88
  65. data/lib/memori_client/engine/v2/unanswered_question.rb +0 -108
  66. data/lib/memori_client/engine/v2/user.rb +0 -152
  67. data/lib/memori_client/engine/v2/web_hook.rb +0 -128
@@ -1,57 +1,205 @@
1
1
  class MemoriClient::Resource
2
- def self.build_arguments(the_binding)
3
- the_binding.local_variables.each_with_object({}) do |key, acc|
4
- value = the_binding.local_variable_get(key)
5
- acc[key] = value
2
+ attr_reader :operations
3
+
4
+ def initialize(key, api_root:, version:)
5
+ @key = key
6
+ @api_root = api_root
7
+ @version = version
8
+ @operations = {}
9
+ end
10
+
11
+ def register_operation(item)
12
+ method_name = item[:method_name]
13
+ @operations[method_name] ||= MemoriClient::Operation.new(item, version: @version, key: @key)
14
+ end
15
+
16
+ def markdown_documentation
17
+ <<~MARKDOWN
18
+ # #{@version}.#{@key.downcase}
19
+
20
+ #{@operations.map { |key, operation| operation.markdown_documentation }.join("\n")}
21
+ MARKDOWN
22
+ end
23
+
24
+ def method_missing(method, *args, &block)
25
+ if @operations.key?(method.to_s)
26
+ invoke_endpoint(method, *args, &block)
27
+ elsif method.to_s.end_with?('_documentation')
28
+ documentation = @operations[method.to_s.chomp('_documentation')]
29
+
30
+ # Add the request body schema to the documentation
31
+ schema_ref = documentation[:spec]['requestBody']['content']['application/json']['schema']['$ref']
32
+ key = schema_ref.split('/').last
33
+ schema = Swagger::SchemaStore.instance.get(key)
34
+ documentation[:request_body_schema] = schema
35
+
36
+ documentation
37
+ else
38
+ super
6
39
  end
7
40
  end
8
41
 
9
- def self.exec_http_request(method, path, args)
10
- headers = args[:headers] || {}
42
+ private
43
+
44
+ def build_path(spec, args)
11
45
  stop = false
12
46
  processed_tokens = []
13
- path.split('/').each do |token|
47
+ spec[:path].split('/').each do |token|
14
48
  break if stop == true
15
49
  if token =~ /^{.*}$/
16
50
  param_name = token.match(/^{(.*)}$/).captures.first
17
- if args[param_name.to_sym].blank?
51
+ param_value = args[param_name.to_sym]
52
+ if param_value.nil? || param_value.empty?
18
53
  stop = true
19
54
  else
20
- processed_tokens << args[param_name.to_sym]
55
+ processed_tokens << param_value
21
56
  end
22
57
  else
23
58
  processed_tokens << token
24
59
  end
25
60
  end
26
61
 
27
- url = processed_tokens.join('/')
28
- url = build_url(url)
62
+ processed_tokens.join('/')
63
+ end
64
+
65
+ def build_url(path)
66
+ [@api_root, path].join('')
67
+ end
68
+
69
+ def invoke_endpoint(method_name, *args, &block)
70
+ operation = @operations[method_name.to_s]
71
+ spec = operation.spec
72
+ parameters, payload = validate_input!(spec, args)
73
+
74
+ path = build_path(spec, parameters)
75
+ headers = args[0][:headers] || {}
76
+ url = build_url(path)
29
77
  http = MemoriClient::HttpClient.new
30
78
 
31
- case method
79
+ http_method = spec[:method]
80
+ case http_method
32
81
  when 'get'
33
- status, body = http.get(url, headers: headers)
82
+ http.get(url, headers: headers)
34
83
  else
35
- status, body = http.send(method, url, payload: args[:payload], headers: headers)
84
+ payload = payload
85
+ http.send(http_method, url, payload: payload, headers: headers)
36
86
  end
37
-
38
- [status, body]
39
87
  end
40
88
 
41
- def self.build_url(_url)
42
- raise NotImplementedError
43
- end
89
+ def validate_input!(spec, args)
90
+ args = [{}] if args.size == 0
91
+ input_payload = args[0][:payload] || {}
92
+ input_parameters = args[0].with_indifferent_access
93
+
94
+ parameters = spec[:spec]['parameters'] || []
44
95
 
45
- def self.validate_payload!(payload, keys:, required:)
46
- bad_names = []
47
- payload.each do |k, v|
48
- unless keys.include?(k.to_s)
49
- bad_names << k
96
+ parameters_map = {}
97
+ required_parameters = []
98
+ parameters.each do |parameter|
99
+ key = parameter['name']
100
+ parameters_map[key] = parameter
101
+ required_parameters << key if parameter['required'] == true
102
+ end
103
+
104
+ missing_parameters = required_parameters - input_parameters.keys
105
+ if missing_parameters.size > 0
106
+ raise ArgumentError.new "Missing required parameters: #{missing_parameters.join(', ')}"
107
+ end
108
+
109
+ unknown_parameters = []
110
+ skippable_parameters = [:payload, :headers, 'payload', 'headers']
111
+ input_parameters.each do |key, value|
112
+ next if skippable_parameters.include?(key)
113
+
114
+ if parameters_map[key].nil?
115
+ unknown_parameters << key
116
+ end
117
+ end
118
+
119
+ if unknown_parameters.size > 0
120
+ raise ArgumentError.new "Unknown parameters: #{unknown_parameters.join(', ')}"
121
+ end
122
+
123
+ # But watch out, payload is not here!
124
+ payload_keys = []
125
+ payload_required_keys = []
126
+ required_keys = []
127
+ if spec[:spec]['requestBody']
128
+ request_body_schema_ref = spec[:spec]['requestBody']['content']['application/json']['schema']['$ref']
129
+ key = request_body_schema_ref.split('/').last
130
+ schema = MemoriClient::Swagger::SchemaStore.instance.get(key)
131
+
132
+ required_keys = schema['required'] || []
133
+
134
+ schema['properties'].each do |key, value|
135
+ required = value['nullable'] == false || required_keys.include?(key)
136
+ payload_keys << key
137
+ payload_required_keys << key if required
50
138
  end
51
139
  end
52
140
 
53
- if bad_names.size > 0
54
- raise ArgumentError.new "Found invalid keys: #{bad_names.join(', ')}"
141
+ missing_payload_keys = payload_required_keys - input_payload.keys
142
+ puts "missing_payload_keys: #{missing_payload_keys} => #{payload_required_keys} - #{input_payload.keys}"
143
+ if missing_payload_keys.size > 0
144
+ raise ArgumentError.new "Missing required payload keys: #{missing_payload_keys.join(', ')}"
55
145
  end
146
+
147
+ [input_parameters, input_payload]
56
148
  end
149
+
150
+ # def self.build_arguments(the_binding)
151
+ # the_binding.local_variables.each_with_object({}) do |key, acc|
152
+ # value = the_binding.local_variable_get(key)
153
+ # acc[key] = value
154
+ # end
155
+ # end
156
+
157
+ # def self.exec_http_request(method, path, args)
158
+ # headers = args[:headers] || {}
159
+ # stop = false
160
+ # processed_tokens = []
161
+ # path.split('/').each do |token|
162
+ # break if stop == true
163
+ # if token =~ /^{.*}$/
164
+ # param_name = token.match(/^{(.*)}$/).captures.first
165
+ # if args[param_name.to_sym].blank?
166
+ # stop = true
167
+ # else
168
+ # processed_tokens << args[param_name.to_sym]
169
+ # end
170
+ # else
171
+ # processed_tokens << token
172
+ # end
173
+ # end
174
+
175
+ # url = processed_tokens.join('/')
176
+ # url = build_url(url)
177
+ # http = MemoriClient::HttpClient.new
178
+
179
+ # case method
180
+ # when 'get'
181
+ # status, body = http.get(url, headers: headers)
182
+ # else
183
+ # status, body = http.send(method, url, payload: args[:payload], headers: headers)
184
+ # end
185
+
186
+ # [status, body]
187
+ # end
188
+
189
+ # def self.build_url(_url)
190
+ # raise NotImplementedError
191
+ # end
192
+
193
+ # def self.validate_payload!(payload, keys:, required:)
194
+ # bad_names = []
195
+ # payload.each do |k, v|
196
+ # unless keys.include?(k.to_s)
197
+ # bad_names << k
198
+ # end
199
+ # end
200
+
201
+ # if bad_names.size > 0
202
+ # raise ArgumentError.new "Found invalid keys: #{bad_names.join(', ')}"
203
+ # end
204
+ # end
57
205
  end
@@ -0,0 +1,25 @@
1
+ module MemoriClient
2
+ class ResourceProxy
3
+ attr_reader :resources
4
+
5
+ def initialize(api_root:, version:)
6
+ @api_root = api_root
7
+ @version = version
8
+ @resources = {}
9
+ end
10
+
11
+ def register_resource(klass)
12
+ @resources[klass] ||= MemoriClient::Resource.new(klass, api_root: @api_root, version: @version)
13
+ end
14
+
15
+ private
16
+
17
+ def method_missing(method, *args, &block)
18
+ if @resources.key?(method.to_s)
19
+ @resources[method.to_s]
20
+ else
21
+ super
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ # Wraps the response from the API
2
+ module MemoriClient
3
+ class Response
4
+ def initialize(response, request: nil)
5
+ @response = response
6
+ @request = request
7
+ end
8
+
9
+ def as_json
10
+ {
11
+ status: status,
12
+ success: success?,
13
+ error: error?,
14
+ parsed_body: parsed_body
15
+ }
16
+ end
17
+
18
+ def status
19
+ @response.code.to_i
20
+ end
21
+
22
+ def success?
23
+ @response.code.to_i == 200
24
+ end
25
+
26
+ def error?
27
+ !success?
28
+ end
29
+
30
+ def parsed_body
31
+ return @parsed_body if @parsed_body
32
+
33
+ body = @response.read_body
34
+
35
+ if @request['Content-Type'] == 'application/json' || @response.content_type == 'application/json'
36
+ if body.nil? || body == ''
37
+ @parsed_body = {}
38
+ else
39
+ @parsed_body = JSON.parse(body)
40
+ end
41
+ else
42
+ @parsed_body = body
43
+ end
44
+
45
+ @parsed_body
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,44 @@
1
+ module MemoriClient
2
+ module Swagger
3
+ class GetModuleAndMethod
4
+ def initialize(namespace, method, path, endpoint_data)
5
+ @endpoint_data = endpoint_data
6
+ @namespace = namespace
7
+ @method = method
8
+ @path = path
9
+ end
10
+
11
+ def call
12
+ # Load using gem path as root
13
+ gem_path = Gem.loaded_specs['memori-client'].full_gem_path
14
+ # Not sure if this is visible after gem release.
15
+ overrides_path = File.join(gem_path, "#{@namespace}_overrides.jsonc")
16
+ if File.exist?(overrides_path)
17
+ overrides = JSON.parse(File.open(overrides_path).read)
18
+ else
19
+ raise "No overrides found for #{@namespace}"
20
+ end
21
+ # overrides = JSON.parse(File.open("#{@namespace}_overrides.jsonc").read)
22
+ key = [@method, @path].join(' ')
23
+ if overrides.key?(key)
24
+ # puts "THERE IS AN OVERRIDE FOR #{key}. Operation id is #{@endpoint_data['operationId']}"
25
+ value = overrides[key]
26
+ return value.split('#')
27
+ end
28
+
29
+ if @endpoint_data.key?('operationId')
30
+ version = @path.split('/').find { |t| t =~ /v\d+/ }
31
+ controller, action = @endpoint_data['operationId'].split('-')
32
+ mod = [
33
+ 'MemoriClient',
34
+ @namespace.titleize,
35
+ version.upcase,
36
+ controller.singularize
37
+ ].join('::')
38
+
39
+ return [mod, action.underscore]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,127 @@
1
+ module MemoriClient
2
+ module Swagger
3
+ class ProcessSpecification
4
+ attr_reader :swagger_spec
5
+ def initialize(uri:, kind:)
6
+ @uri = uri
7
+ @kind = kind
8
+ @result = {}
9
+ @endpoints = {}
10
+ @methods = {}
11
+ @methods_collisions = []
12
+ end
13
+
14
+ def call
15
+ puts "Processing Swagger spec #{@kind} from #{@uri}"
16
+ data = URI.open(@uri).read
17
+ parsed = JSON.parse(data)
18
+ @swagger_spec = parsed
19
+ paths = parsed['paths']
20
+ # routes = collect_routes(paths)
21
+ # puts JSON.pretty_generate(routes)
22
+ paths.each do |path, path_data|
23
+ path_data.each do |method, endpoint|
24
+ module_name, info = analyze_path(method, path, endpoint)
25
+ unless module_name.nil?
26
+ @result[module_name] ||= []
27
+ @result[module_name] << info
28
+ end
29
+ end
30
+ end
31
+
32
+ # Verify collisions
33
+ @methods.keys.sort.each do |m|
34
+ if @methods[m].size > 1
35
+ @methods_collisions << m
36
+ puts "#{m} => #{@methods[m].size}"
37
+ @methods[m].each do |mm|
38
+ puts " - #{mm}"
39
+ end
40
+ end
41
+ end
42
+
43
+ if @methods_collisions.size > 0
44
+ puts "Stopping because we found #{@methods_collisions.size} collisions in ns #{@kind}. Collisions are:"
45
+ @methods_collisions.each do |m|
46
+ puts "Method: #{m}"
47
+ puts @methods[m].join("\n")
48
+ puts '--'
49
+ end
50
+
51
+ raise "Stop"
52
+ end
53
+
54
+ @result
55
+ end
56
+
57
+ private
58
+
59
+ def analyze_path(method, path, endpoint_data)
60
+ re = /\/(memori|api)\/(v\d+)\/.*$/
61
+ version = path.match(re).captures[1].upcase
62
+
63
+ # cleaned_path = get_cleaned_path(path)
64
+
65
+ endpoint_key = [method, path].join(' ')
66
+ @endpoints[endpoint_key] ||= 0
67
+ @endpoints[endpoint_key] += 1
68
+
69
+ module_name, method_name = GetModuleAndMethod.new(@kind, method, path, endpoint_data).call
70
+ return if module_name.nil?
71
+
72
+ method_qname = [module_name, method_name].join('.')
73
+ @methods[method_qname] ||= []
74
+ @methods[method_qname] << endpoint_key
75
+
76
+ params = {}
77
+ unless endpoint_data['parameters'].nil?
78
+ endpoint_data['parameters'].each do |param|
79
+ k = param['name']
80
+ params[k] = param['required'] == true
81
+ end
82
+ end
83
+
84
+ data = {
85
+ method: method,
86
+ version: version,
87
+ path: path,
88
+ module: module_name,
89
+ method_name: method_name,
90
+ params: params,
91
+ request_body: !endpoint_data['requestBody'].nil?,
92
+ summary: endpoint_data['summary'],
93
+ spec: endpoint_data
94
+ }
95
+
96
+ if endpoint_data['requestBody']
97
+ request_body_schema_ref = endpoint_data['requestBody']['content']['application/json']['schema']['$ref']
98
+ key = request_body_schema_ref.split('/').last
99
+ schema = @swagger_spec['components']['schemas'][key]
100
+
101
+ SchemaStore.instance.add(key, schema)
102
+ end
103
+
104
+ [module_name, data]
105
+ end
106
+
107
+ def collect_routes(paths)
108
+ routes = {}
109
+ paths.each do |path, path_data|
110
+ path_data.each do |method, endpoint|
111
+ k = [method, path].join(' ')
112
+
113
+ re = /\/(memori|api)\/(v\d+)\/.*$/
114
+ tag = endpoint['tags'].first.singularize
115
+ puts path.inspect
116
+ version = path.match(re).captures[1].upcase
117
+ next if version == 'v1'
118
+
119
+ main = path.split('/')[3].underscore
120
+ routes[k] = "MemoriClient::#{@kind.titleize}::#{version}::#{tag}##{main}"
121
+ end
122
+ end
123
+ routes
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,26 @@
1
+ # Holds the schema for the swagger spec
2
+ #
3
+ # It is used to validate the payload against the schema
4
+ #
5
+ # It is also used to generate the documentation
6
+
7
+ require 'singleton'
8
+ module MemoriClient
9
+ module Swagger
10
+ class SchemaStore
11
+ include Singleton
12
+
13
+ def initialize
14
+ @schemas = {}
15
+ end
16
+
17
+ def add(key, schema)
18
+ @schemas[key] = schema
19
+ end
20
+
21
+ def get(key)
22
+ @schemas[key]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -11,13 +11,8 @@ module MemoriClient
11
11
 
12
12
  # Determine project root (works in Rails and non-Rails)
13
13
  project_root = if defined?(::Rails)
14
- puts 'here'
15
- puts Dir.pwd
16
- ::Rails.root.to_s
17
- puts 'there'
18
14
  ::Rails.root.to_s
19
15
  else
20
-
21
16
  Dir.pwd
22
17
  end
23
18
 
data/lib/memori_client.rb CHANGED
@@ -1,64 +1,37 @@
1
1
  module MemoriClient
2
- module Backend
3
- module V1
4
-
5
- end
6
-
7
- module V2
8
-
9
- end
10
- end
11
-
12
2
  module Engine
13
- module V1
14
-
15
- end
16
-
17
- module V2
18
- module Private
19
-
20
- end
21
- end
22
3
  end
23
4
 
24
- class << self
25
- # Instantiate the Configuration singleton
26
- # or return it. Remember that the instance
27
- # has attribute readers so that we can access
28
- # the configured values
29
- def configuration
30
- @configuration ||= Configuration.new
31
- end
5
+ module Proxy
6
+ end
32
7
 
33
- # This is the configure block definition.
34
- # The configuration method will return the
35
- # Configuration singleton, which is then yielded
36
- # to the configure block. Then it's just a matter
37
- # of using the attribute accessors we previously defined
38
- def configure
39
- yield(configuration)
40
- end
8
+ module Swagger
41
9
  end
42
10
  end
43
11
 
44
12
  require 'securerandom'
45
13
  require 'uri'
14
+ require 'open-uri'
46
15
  require 'json'
47
16
 
48
17
  if defined?(::Rails)
49
18
  require 'memori_client/utils/rails'
19
+ require 'memori_client/railtie'
50
20
  end
51
21
 
52
- require 'memori_client/configuration'
22
+ require 'memori_client/swagger/process_specification'
23
+ require 'memori_client/swagger/get_module_and_method'
24
+ require 'memori_client/swagger/schema_store'
25
+
26
+ require 'memori_client/client_factory'
27
+ require 'memori_client/client'
53
28
  require "memori_client/http_client"
29
+ require "memori_client/response"
54
30
  require "memori_client/resource"
55
- require "memori_client/backend/resource"
56
- require "memori_client/backend/resources"
31
+ require "memori_client/resource_proxy"
32
+ require "memori_client/operation"
57
33
  require "memori_client/engine/hmac_helper"
58
- require "memori_client/engine/resource"
59
- require "memori_client/engine/resources"
34
+ require "memori_client/proxy/client"
60
35
 
61
- require "memori_client/engine/v2/private/memori"
62
- require "memori_client/engine/v2/private/memori_block"
63
36
 
64
37
 
@@ -0,0 +1,8 @@
1
+ namespace :memori_client do
2
+ namespace :docs do
3
+ desc "Copy MemoriClient documentation to Rails public directory"
4
+ task :copy do
5
+ MemoriClient::Utils::Rails.copy_docs
6
+ end
7
+ end
8
+ end