multiwoven-integrations 0.15.10 → 0.15.11

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
2
  SHA256:
3
- metadata.gz: 0bd4700c4c04ca8b4c67a3fe775104f2081e3fce2dc8628936cac70b60cb3fe4
4
- data.tar.gz: e1cf0405a0d0775638f3e27d0c1d3babb21d2bca2f2b806363b908cb07370508
3
+ metadata.gz: 47ebb726bc626f15a399cb9f1b94f594efa9b4fb75df06482014f10e37e9f6aa
4
+ data.tar.gz: 429e1a5d6f20f8445c9ef1fd6ecc9073443d97b9d8572c4224d871d4826c9fb7
5
5
  SHA512:
6
- metadata.gz: 52e96a9dd052cfb7b99af82d49cc910dc03698cbb4b406554280c507d8f3c7e8260aa4397522fc6547a306c9e4e80954aee44d6e640d311dc143f0918beb9f5c
7
- data.tar.gz: 46073602a80873d3ed517e0e6b8296951fe810b5be48002ec89e537b5c0adf2db2bd0b721db326402a8b1207addf6d630d8194e9e5e613b9bbb3b2a7d51a1343
6
+ metadata.gz: 9a2757cadcb8754020f92c4a9503eb27418c5408eda08bc90baadf2d055c2d6cdb6a0877a8a0e744ecf0cafa578d1397efcc53f9c8ef13903dde6b77d22f1029
7
+ data.tar.gz: 054cb615fe6ccb54536648970ae365a7ec6326ed037d9f2fe2592ba0197d8c9dc87fc165bc89790df2d98fed8542cadfb9a98095ad84097fe963e584e8dec137
@@ -3,40 +3,14 @@
3
3
  module Multiwoven
4
4
  module Integrations::Core
5
5
  class HttpClient
6
+ extend HttpHelper
6
7
  class << self
7
8
  def request(url, method, payload: nil, headers: {}, config: {})
8
9
  uri = URI(url)
9
- http = Net::HTTP.new(uri.host, uri.port)
10
- http.use_ssl = (uri.scheme == "https")
11
-
12
- # Set timeout if provided
13
- if config[:timeout]
14
- timeout_value = config[:timeout].to_f
15
- http.open_timeout = timeout_value
16
- http.read_timeout = timeout_value
17
- end
18
-
10
+ http = configure_http(uri, config)
19
11
  request = build_request(method, uri, payload, headers)
20
12
  http.request(request)
21
13
  end
22
-
23
- private
24
-
25
- def build_request(method, uri, payload, headers)
26
- request_class = case method.upcase
27
- when Constants::HTTP_GET then Net::HTTP::Get
28
- when Constants::HTTP_POST then Net::HTTP::Post
29
- when Constants::HTTP_PUT then Net::HTTP::Put
30
- when Constants::HTTP_PATCH then Net::HTTP::Patch
31
- when Constants::HTTP_DELETE then Net::HTTP::Delete
32
- else raise ArgumentError, "Unsupported HTTP method: #{method}"
33
- end
34
-
35
- request = request_class.new(uri)
36
- headers.each { |key, value| request[key] = value }
37
- request.body = payload.to_json if payload && %w[POST PUT PATCH].include?(method.upcase)
38
- request
39
- end
40
14
  end
41
15
  end
42
16
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Multiwoven
4
+ module Integrations::Core
5
+ module HttpHelper
6
+ def build_request(method, uri, payload, headers)
7
+ request_class = case method.upcase
8
+ when Constants::HTTP_GET then Net::HTTP::Get
9
+ when Constants::HTTP_POST then Net::HTTP::Post
10
+ when Constants::HTTP_PUT then Net::HTTP::Put
11
+ when Constants::HTTP_PATCH then Net::HTTP::Patch
12
+ when Constants::HTTP_DELETE then Net::HTTP::Delete
13
+ else raise ArgumentError, "Unsupported HTTP method: #{method}"
14
+ end
15
+
16
+ request = request_class.new(uri)
17
+ headers.each { |key, value| request[key] = value }
18
+ request.body = payload.to_json if payload && %w[POST PUT PATCH].include?(method.upcase)
19
+ request
20
+ end
21
+
22
+ def configure_http(uri, config)
23
+ http = Net::HTTP.new(uri.host, uri.port)
24
+ http.use_ssl = (uri.scheme == "https")
25
+
26
+ if config[:timeout]
27
+ timeout_value = config[:timeout].to_f
28
+ http.open_timeout = timeout_value
29
+ http.read_timeout = timeout_value
30
+ end
31
+
32
+ http
33
+ end
34
+ end
35
+ end
36
+ end
@@ -39,6 +39,28 @@ module Multiwoven
39
39
  # Appending the LIMIT and OFFSET clauses to the SQL query
40
40
  "#{sql_query} LIMIT #{limit} OFFSET #{offset}"
41
41
  end
42
+
43
+ def send_request(options = {})
44
+ Multiwoven::Integrations::Core::HttpClient.request(
45
+ options[:url],
46
+ options[:http_method],
47
+ payload: options[:payload],
48
+ headers: options[:headers],
49
+ config: options[:config]
50
+ )
51
+ end
52
+
53
+ def send_streaming_request(options = {})
54
+ Multiwoven::Integrations::Core::StreamingHttpClient.request(
55
+ options[:url],
56
+ options[:http_method],
57
+ payload: options[:payload],
58
+ headers: options[:headers],
59
+ config: options[:config]
60
+ ) do |chunk|
61
+ yield chunk if block_given? # Pass each chunk for processing (streaming response)
62
+ end
63
+ end
42
64
  end
43
65
  end
44
66
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Multiwoven
4
+ module Integrations::Core
5
+ class StreamingHttpClient
6
+ extend HttpHelper
7
+ class << self
8
+ def request(url, method, payload: nil, headers: {}, config: {})
9
+ uri = URI(url)
10
+ http = configure_http(uri, config)
11
+ request = build_request(method, uri, payload, headers)
12
+ http.request(request) do |response|
13
+ response.read_body do |chunk|
14
+ yield chunk if block_given? # Pass each response chunk
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Multiwoven
4
4
  module Integrations
5
- VERSION = "0.15.10"
5
+ VERSION = "0.15.11"
6
6
 
7
7
  ENABLED_SOURCES = %w[
8
8
  Snowflake
@@ -5,24 +5,17 @@ module Multiwoven::Integrations::Source
5
5
  include Multiwoven::Integrations::Core
6
6
  class Client < SourceConnector
7
7
  def check_connection(connection_config)
8
- connection_config = connection_config.with_indifferent_access
9
- url_host = connection_config[:url_host]
10
- http_method = connection_config[:http_method]
11
- headers = connection_config[:headers]
12
- payload = JSON.parse(connection_config[:request_format])
13
- config = connection_config[:config]
14
- config[:timeout] ||= 30
15
- response = send_request(url_host, http_method, payload, headers, config)
16
- if success?(response)
17
- success_status
18
- else
19
- failure_status(nil)
20
- end
8
+ connection_config = prepare_config(connection_config)
9
+ response = send_request(
10
+ url: connection_config[:url_host],
11
+ http_method: connection_config[:http_method],
12
+ payload: JSON.parse(connection_config[:request_format]),
13
+ headers: connection_config[:headers],
14
+ config: connection_config[:config]
15
+ )
16
+ success?(response) ? success_status : failure_status(nil)
21
17
  rescue StandardError => e
22
- handle_exception(e, {
23
- context: "HTTP MODEL:CHECK_CONNECTION:EXCEPTION",
24
- type: "error"
25
- })
18
+ handle_exception(e, { context: "HTTP MODEL:CHECK_CONNECTION:EXCEPTION", type: "error" })
26
19
  failure_status(e)
27
20
  end
28
21
 
@@ -31,40 +24,66 @@ module Multiwoven::Integrations::Source
31
24
  catalog = build_catalog(catalog_json)
32
25
  catalog.to_multiwoven_message
33
26
  rescue StandardError => e
34
- handle_exception(e, {
35
- context: "HTTP MODEL:DISCOVER:EXCEPTION",
36
- type: "error"
37
- })
27
+ handle_exception(e, { context: "HTTP MODEL:DISCOVER:EXCEPTION", type: "error" })
38
28
  end
39
29
 
40
30
  def read(sync_config)
41
- connection_config = sync_config.source.connection_specification
42
- connection_config = connection_config.with_indifferent_access
31
+ connection_config = prepare_config(sync_config.source.connection_specification)
32
+ stream = connection_config[:is_stream] ||= false
43
33
  # The server checks the ConnectorQueryType.
44
34
  # If it's "ai_ml," the server calculates the payload and passes it as a query in the sync config model protocol.
45
35
  # This query is then sent to the AI/ML model.
46
- payload = JSON.parse(sync_config.model.query)
47
- run_model(connection_config, payload)
36
+ payload = parse_json(sync_config.model.query)
37
+
38
+ if stream
39
+ run_model_stream(connection_config, payload) { |message| yield message if block_given? }
40
+ else
41
+ run_model(connection_config, payload)
42
+ end
48
43
  rescue StandardError => e
49
- handle_exception(e, {
50
- context: "HTTP MODEL:READ:EXCEPTION",
51
- type: "error"
52
- })
44
+ handle_exception(e, { context: "HTTP MODEL:READ:EXCEPTION", type: "error" })
53
45
  end
54
46
 
55
47
  private
56
48
 
49
+ def prepare_config(config)
50
+ config.with_indifferent_access.tap do |conf|
51
+ conf[:config][:timeout] ||= 30
52
+ end
53
+ end
54
+
55
+ def parse_json(json_string)
56
+ JSON.parse(json_string)
57
+ rescue JSON::ParserError => e
58
+ handle_exception(e, { context: "HTTP MODEL:PARSE_JSON:EXCEPTION", type: "error" })
59
+ {}
60
+ end
61
+
57
62
  def run_model(connection_config, payload)
58
- connection_config = connection_config.with_indifferent_access
59
- url_host = connection_config[:url_host]
60
- headers = connection_config[:headers]
61
- config = connection_config[:config]
62
- http_method = connection_config[:http_method]
63
- config[:timeout] ||= 30
64
- response = send_request(url_host, http_method, payload, headers, config)
63
+ response = send_request(
64
+ url: connection_config[:url_host],
65
+ http_method: connection_config[:http_method],
66
+ payload: payload,
67
+ headers: connection_config[:headers],
68
+ config: connection_config[:config]
69
+ )
65
70
  process_response(response)
66
71
  rescue StandardError => e
67
- handle_exception(e, context: "HTTP MODEL:RUN_MODEL:EXCEPTION", type: "error")
72
+ handle_exception(e, { context: "HTTP MODEL:RUN_MODEL:EXCEPTION", type: "error" })
73
+ end
74
+
75
+ def run_model_stream(connection_config, payload)
76
+ send_streaming_request(
77
+ url: connection_config[:url_host],
78
+ http_method: connection_config[:http_method],
79
+ payload: payload,
80
+ headers: connection_config[:headers],
81
+ config: connection_config[:config]
82
+ ) do |chunk|
83
+ process_streaming_response(chunk) { |message| yield message if block_given? }
84
+ end
85
+ rescue StandardError => e
86
+ handle_exception(e, { context: "HTTP MODEL:RUN_STREAM_MODEL:EXCEPTION", type: "error" })
68
87
  end
69
88
 
70
89
  def process_response(response)
@@ -74,16 +93,15 @@ module Multiwoven::Integrations::Source
74
93
  else
75
94
  create_log_message("HTTP MODEL:RUN_MODEL", "error", "request failed: #{response.body}")
76
95
  end
96
+ rescue StandardError => e
97
+ handle_exception(e, { context: "HTTP MODEL:PROCESS_RESPONSE:EXCEPTION", type: "error" })
77
98
  end
78
99
 
79
- def send_request(url, http_method, payload, headers, config)
80
- Multiwoven::Integrations::Core::HttpClient.request(
81
- url,
82
- http_method,
83
- payload: payload,
84
- headers: headers,
85
- config: config
86
- )
100
+ def process_streaming_response(chunk)
101
+ data = JSON.parse(chunk)
102
+ yield [RecordMessage.new(data: data, emitted_at: Time.now.to_i).to_multiwoven_message] if block_given?
103
+ rescue StandardError => e
104
+ handle_exception(e, { context: "HTTP MODEL:PROCESS_STREAMING_RESPONSE:EXCEPTION", type: "error" })
87
105
  end
88
106
  end
89
107
  end
@@ -19,10 +19,17 @@
19
19
  "title": "URL",
20
20
  "order": 1
21
21
  },
22
+ "is_stream": {
23
+ "type": "boolean",
24
+ "title": "Streaming Enabled",
25
+ "description": "Enables data streaming for such as chat, when supported by the model. When true, messages and model data are processed in chunks for immediate delivery, enhancing responsiveness. Default is false, processing only after the entire response is received.",
26
+ "default": false,
27
+ "order": 2
28
+ },
22
29
  "headers": {
23
30
  "title": "HTTP Headers",
24
31
  "description": "Custom headers to include in the HTTP request. Useful for authentication, content type specifications, and other request metadata.",
25
- "order": 2,
32
+ "order": 3,
26
33
  "additionalProperties": {
27
34
  "type": "string"
28
35
  },
@@ -42,21 +49,21 @@
42
49
  "order": 0
43
50
  }
44
51
  },
45
- "order": 3
52
+ "order": 4
46
53
  },
47
54
  "request_format": {
48
55
  "title": "Request Format",
49
56
  "description": "Sample Request Format",
50
57
  "type": "string",
51
58
  "x-request-format": true,
52
- "order": 4
59
+ "order": 5
53
60
  },
54
61
  "response_format": {
55
62
  "title": "Response Format",
56
63
  "description": "Sample Response Format",
57
64
  "type": "string",
58
65
  "x-response-format": true,
59
- "order": 5
66
+ "order": 6
60
67
  }
61
68
  }
62
69
  }
@@ -52,7 +52,9 @@ require_relative "integrations/protocol/protocol"
52
52
  require_relative "integrations/core/base_connector"
53
53
  require_relative "integrations/core/source_connector"
54
54
  require_relative "integrations/core/destination_connector"
55
+ require_relative "integrations/core/http_helper"
55
56
  require_relative "integrations/core/http_client"
57
+ require_relative "integrations/core/streaming_http_client"
56
58
  require_relative "integrations/core/query_builder"
57
59
 
58
60
  # Source
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multiwoven-integrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.10
4
+ version: 0.15.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Subin T P
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-12-09 00:00:00.000000000 Z
11
+ date: 2024-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -580,9 +580,11 @@ files:
580
580
  - lib/multiwoven/integrations/core/destination_connector.rb
581
581
  - lib/multiwoven/integrations/core/fullrefresher.rb
582
582
  - lib/multiwoven/integrations/core/http_client.rb
583
+ - lib/multiwoven/integrations/core/http_helper.rb
583
584
  - lib/multiwoven/integrations/core/query_builder.rb
584
585
  - lib/multiwoven/integrations/core/rate_limiter.rb
585
586
  - lib/multiwoven/integrations/core/source_connector.rb
587
+ - lib/multiwoven/integrations/core/streaming_http_client.rb
586
588
  - lib/multiwoven/integrations/core/utils.rb
587
589
  - lib/multiwoven/integrations/destination/airtable/client.rb
588
590
  - lib/multiwoven/integrations/destination/airtable/config/catalog.json