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 +4 -4
- data/lib/multiwoven/integrations/core/http_client.rb +2 -28
- data/lib/multiwoven/integrations/core/http_helper.rb +36 -0
- data/lib/multiwoven/integrations/core/source_connector.rb +22 -0
- data/lib/multiwoven/integrations/core/streaming_http_client.rb +21 -0
- data/lib/multiwoven/integrations/rollout.rb +1 -1
- data/lib/multiwoven/integrations/source/http_model/client.rb +63 -45
- data/lib/multiwoven/integrations/source/http_model/config/spec.json +11 -4
- data/lib/multiwoven/integrations.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47ebb726bc626f15a399cb9f1b94f594efa9b4fb75df06482014f10e37e9f6aa
|
4
|
+
data.tar.gz: 429e1a5d6f20f8445c9ef1fd6ecc9073443d97b9d8572c4224d871d4826c9fb7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 =
|
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
|
@@ -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
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
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 =
|
47
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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":
|
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":
|
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":
|
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":
|
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.
|
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-
|
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
|