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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18916baa3b84e6a947a1fa8411658475e4608ff4a127d681ca9b29332d669e81
4
- data.tar.gz: f18c5e4d77640750e570ae4762122d0b687b73b2d12731e11add7b34d00b9d8c
3
+ metadata.gz: 2b029b1c946d1f57c25b9098864b13297520b56e8970e4882e54684a09f2bbc1
4
+ data.tar.gz: ff6367e701579b6e93bca9d9c4c2f58d686d9af400e974bd1627936cd80f95e5
5
5
  SHA512:
6
- metadata.gz: f397468f410d2475d1d59557749e83092c6b65b6f844b4169fff2774dbaac436a7eca5d9e667a35f7750937722d4bf92f97ec550b1919fd0deadd1857a9b1531
7
- data.tar.gz: 54d733930d3ba8c0a241240318fbe58c4e8dd1750e3e9f9dc5969c86b9280721386fbe24f9379c47f06a598871950e5d97e8e6b42a13c72d6f8d89da40d2f1d9
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)["embeddings"]
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
- uri = URI.parse(ENDPOINT)
44
- http = Net::HTTP.new(uri.host, uri.port)
45
- http.use_ssl = true
46
- http.open_timeout = 30
47
- http.read_timeout = 60
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
- req = Net::HTTP::Post.new(uri)
50
- req["Authorization"] = "Bearer #{@api_key}"
51
- req["Content-Type"] = "application/json"
52
- req.body = JSON.generate(model: @model, input: input)
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
- response = http.request(req)
55
+ response = http.request(req)
55
56
 
56
- unless response.is_a?(Net::HTTPSuccess)
57
- raise "OpenAI API error (#{response.code}): #{response.body}"
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
- JSON.parse(response.body)
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
- uri = URI.parse(ENDPOINT)
30
- http = Net::HTTP.new(uri.host, uri.port)
31
- http.use_ssl = true
32
- http.open_timeout = 30
33
- http.read_timeout = 120
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
- req = Net::HTTP::Post.new(uri)
36
- req["Authorization"] = "Bearer #{@api_key}"
37
- req["Content-Type"] = "application/json"
38
- req.body = JSON.generate(body)
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
- response = http.request(req)
41
+ response = http.request(req)
41
42
 
42
- unless response.is_a?(Net::HTTPSuccess)
43
- raise "OpenAI API error (#{response.code}): #{response.body}"
44
- end
43
+ unless response.is_a?(Net::HTTPSuccess)
44
+ raise "OpenAI API error (#{response.code}): #{response.body}"
45
+ end
45
46
 
46
- data = JSON.parse(response.body)
47
- text = data.dig("choices", 0, "message", "content")
48
- usage = data["usage"] || {}
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
- text: text,
52
- tokens_used: {
53
- prompt: usage["prompt_tokens"],
54
- completion: usage["completion_tokens"]
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
@@ -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
- fetch(URI.parse(response["location"]), redirect_limit: redirect_limit - 1)
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
@@ -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
- candidate = context + "\n---\n" + source.text
154
- break if candidate.length > max_chars
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
- # Remove from store by metadata filter
51
- # Implementation depends on store capabilities
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RagRuby
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/rag_ruby.rb CHANGED
@@ -27,6 +27,9 @@ require_relative "rag_ruby/pipeline"
27
27
 
28
28
  module RagRuby
29
29
  class Error < StandardError; end
30
+ class ConfigurationError < Error; end
31
+ class EmbeddingError < Error; end
32
+ class GenerationError < Error; end
30
33
 
31
34
  class << self
32
35
  def pipeline
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rag-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johannes Dwi Cahyo