rag-ruby 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/lib/rag_ruby/configuration.rb +4 -1
- data/lib/rag_ruby/embedders/cohere.rb +4 -1
- data/lib/rag_ruby/embedders/openai.rb +33 -13
- data/lib/rag_ruby/generators/openai.rb +45 -22
- data/lib/rag_ruby/loaders/url.rb +4 -2
- data/lib/rag_ruby/pipeline.rb +6 -2
- data/lib/rag_ruby/rails/indexable.rb +4 -2
- data/lib/rag_ruby/version.rb +1 -1
- data/lib/rag_ruby.rb +3 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2b029b1c946d1f57c25b9098864b13297520b56e8970e4882e54684a09f2bbc1
|
|
4
|
+
data.tar.gz: ff6367e701579b6e93bca9d9c4c2f58d686d9af400e974bd1627936cd80f95e5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 266712e7a269d2de55c13cc64b47309501692c2b3476d757095708b1ba0bcbf107cb278e20cdab527e216ba97776ae957927827a2d9ea8e32dc9a6b6b84caa1d
|
|
7
|
+
data.tar.gz: 91e1297be5d3e35dd7d9b119391e38a1c4507727144cfd88f5ade6ba334a6d4103a2b70c4a6869e9262899aab066e6323c36ce7ea234a0486ff0f11b0fb2c857
|
|
@@ -26,13 +26,16 @@ module RagRuby
|
|
|
26
26
|
}.freeze
|
|
27
27
|
|
|
28
28
|
attr_accessor :loader_instance, :embedder_instance, :store_instance, :generator_instance,
|
|
29
|
-
:chunk_size, :chunk_overlap, :chunk_strategy
|
|
29
|
+
:chunk_size, :chunk_overlap, :chunk_strategy,
|
|
30
|
+
:http_timeout, :read_timeout
|
|
30
31
|
|
|
31
32
|
def initialize
|
|
32
33
|
@callbacks = Hash.new { |h, k| h[k] = [] }
|
|
33
34
|
@chunk_size = 1000
|
|
34
35
|
@chunk_overlap = 200
|
|
35
36
|
@chunk_strategy = :recursive_character
|
|
37
|
+
@http_timeout = 30
|
|
38
|
+
@read_timeout = 60
|
|
36
39
|
end
|
|
37
40
|
|
|
38
41
|
def loader(name, **opts)
|
|
@@ -39,7 +39,10 @@ module RagRuby
|
|
|
39
39
|
raise "Cohere API error (#{response.code}): #{response.body}"
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
JSON.parse(response.body)
|
|
42
|
+
parsed = JSON.parse(response.body)
|
|
43
|
+
embeddings = parsed["embeddings"]
|
|
44
|
+
raise RagRuby::Error, "No embeddings in Cohere response" if embeddings.nil? || embeddings.empty?
|
|
45
|
+
embeddings
|
|
43
46
|
end
|
|
44
47
|
|
|
45
48
|
def dimension
|
|
@@ -40,24 +40,44 @@ module RagRuby
|
|
|
40
40
|
private
|
|
41
41
|
|
|
42
42
|
def request(input)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
request_with_retry do
|
|
44
|
+
uri = URI.parse(ENDPOINT)
|
|
45
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
46
|
+
http.use_ssl = true
|
|
47
|
+
http.open_timeout = 30
|
|
48
|
+
http.read_timeout = 60
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
req = Net::HTTP::Post.new(uri)
|
|
51
|
+
req["Authorization"] = "Bearer #{@api_key}"
|
|
52
|
+
req["Content-Type"] = "application/json"
|
|
53
|
+
req.body = JSON.generate(model: @model, input: input)
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
response = http.request(req)
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
unless response.is_a?(Net::HTTPSuccess)
|
|
58
|
+
raise "OpenAI API error (#{response.code}): #{response.body}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
JSON.parse(response.body)
|
|
58
62
|
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def request_with_retry(max_retries: 3)
|
|
66
|
+
retries = 0
|
|
67
|
+
begin
|
|
68
|
+
yield
|
|
69
|
+
rescue => e
|
|
70
|
+
retries += 1
|
|
71
|
+
if retries <= max_retries && retryable?(e)
|
|
72
|
+
sleep(2 ** (retries - 1))
|
|
73
|
+
retry
|
|
74
|
+
end
|
|
75
|
+
raise
|
|
76
|
+
end
|
|
77
|
+
end
|
|
59
78
|
|
|
60
|
-
|
|
79
|
+
def retryable?(e)
|
|
80
|
+
e.message.match?(/429|500|502|503/)
|
|
61
81
|
end
|
|
62
82
|
end
|
|
63
83
|
end
|
|
@@ -26,34 +26,57 @@ module RagRuby
|
|
|
26
26
|
temperature: temperature
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
request_with_retry do
|
|
30
|
+
uri = URI.parse(ENDPOINT)
|
|
31
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
32
|
+
http.use_ssl = true
|
|
33
|
+
http.open_timeout = 30
|
|
34
|
+
http.read_timeout = 120
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
req = Net::HTTP::Post.new(uri)
|
|
37
|
+
req["Authorization"] = "Bearer #{@api_key}"
|
|
38
|
+
req["Content-Type"] = "application/json"
|
|
39
|
+
req.body = JSON.generate(body)
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
response = http.request(req)
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
unless response.is_a?(Net::HTTPSuccess)
|
|
44
|
+
raise "OpenAI API error (#{response.code}): #{response.body}"
|
|
45
|
+
end
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
data = JSON.parse(response.body)
|
|
48
|
+
text = data.dig("choices", 0, "message", "content")
|
|
49
|
+
raise RagRuby::Error, "Empty response from OpenAI" if text.nil?
|
|
50
|
+
usage = data["usage"] || {}
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
{
|
|
53
|
+
text: text,
|
|
54
|
+
tokens_used: {
|
|
55
|
+
prompt: usage["prompt_tokens"],
|
|
56
|
+
completion: usage["completion_tokens"]
|
|
57
|
+
}
|
|
55
58
|
}
|
|
56
|
-
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def request_with_retry(max_retries: 3)
|
|
65
|
+
retries = 0
|
|
66
|
+
begin
|
|
67
|
+
yield
|
|
68
|
+
rescue => e
|
|
69
|
+
retries += 1
|
|
70
|
+
if retries <= max_retries && retryable?(e)
|
|
71
|
+
sleep(2 ** (retries - 1))
|
|
72
|
+
retry
|
|
73
|
+
end
|
|
74
|
+
raise
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def retryable?(e)
|
|
79
|
+
e.message.match?(/429|500|502|503/)
|
|
57
80
|
end
|
|
58
81
|
end
|
|
59
82
|
end
|
data/lib/rag_ruby/loaders/url.rb
CHANGED
|
@@ -31,7 +31,7 @@ module RagRuby
|
|
|
31
31
|
private
|
|
32
32
|
|
|
33
33
|
def fetch(uri, redirect_limit: 5)
|
|
34
|
-
raise "Too many redirects" if redirect_limit == 0
|
|
34
|
+
raise RagRuby::Error, "Too many redirects for #{uri}" if redirect_limit == 0
|
|
35
35
|
|
|
36
36
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
37
37
|
http.use_ssl = uri.scheme == "https"
|
|
@@ -43,7 +43,9 @@ module RagRuby
|
|
|
43
43
|
|
|
44
44
|
case response
|
|
45
45
|
when Net::HTTPRedirection
|
|
46
|
-
|
|
46
|
+
location = response["location"]
|
|
47
|
+
raise RagRuby::Error, "Redirect with no location header" if location.nil?
|
|
48
|
+
fetch(URI.parse(location), redirect_limit: redirect_limit - 1)
|
|
47
49
|
when Net::HTTPSuccess
|
|
48
50
|
response
|
|
49
51
|
else
|
data/lib/rag_ruby/pipeline.rb
CHANGED
|
@@ -134,6 +134,9 @@ module RagRuby
|
|
|
134
134
|
def embed_chunks(chunks)
|
|
135
135
|
texts = chunks.map(&:text)
|
|
136
136
|
embeddings = @config.embedder_instance.embed_batch(texts)
|
|
137
|
+
if embeddings.length != chunks.length
|
|
138
|
+
raise RagRuby::Error, "Embedding count (#{embeddings.length}) doesn't match chunk count (#{chunks.length})"
|
|
139
|
+
end
|
|
137
140
|
chunks.each_with_index do |chunk, i|
|
|
138
141
|
chunk.embedding = embeddings[i]
|
|
139
142
|
end
|
|
@@ -150,8 +153,9 @@ module RagRuby
|
|
|
150
153
|
def build_context(sources, max_chars: 12000)
|
|
151
154
|
context = ""
|
|
152
155
|
sources.each do |source|
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
separator = context.empty? ? "" : "\n---\n"
|
|
157
|
+
candidate = context + separator + source.text
|
|
158
|
+
break if candidate.length > max_chars && !context.empty?
|
|
155
159
|
context = candidate
|
|
156
160
|
end
|
|
157
161
|
context.strip
|
|
@@ -47,8 +47,10 @@ module RagRuby
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def rag_remove_record
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
store = self.class.rag_pipeline&.config&.store_instance
|
|
51
|
+
if store && store.respond_to?(:delete)
|
|
52
|
+
store.delete(id.to_s)
|
|
53
|
+
end
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
class InlineLoader < Loaders::Base
|
data/lib/rag_ruby/version.rb
CHANGED
data/lib/rag_ruby.rb
CHANGED