rubycanusellm 0.2.0 → 0.3.0

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: 4d8c900c65c552170f515c984fd822ee4a004dc45dbfd384106ee98e2f52a6b4
4
- data.tar.gz: faad0d33ac6759890ba9aea14cdfd45c686f305f4e660dd1a99e25244fb7888a
3
+ metadata.gz: 76737cbccfa63deb73a8a13e57c7202d42eb0689595ddae1b1cedf122f262e91
4
+ data.tar.gz: 282fda500fb7f36bebcd7e4fc3683a25e264e483b63e264da5aeb21b5cf229ef
5
5
  SHA512:
6
- metadata.gz: 8c56cf78abac614fccc2cb7595d1a356e015bbd4ad6ddc3af3afd6e2364cfa6317d4f45a676c93f869378f00e9a6651729541ae9304a3572aa1c29462040ecc3
7
- data.tar.gz: cb98a023aa10da202850b5e7783030440384d9646b5ed9ffb2923377296bb07f550ddd057eadd04c96c7e60f4caaa0017c9e272bde08c345bca2cd637e257233
6
+ metadata.gz: 9ffb10c5216314c8ae733b3be09391197a8e785308c42555764e7bc0144e958638dfb8a253e5d818ed6ba77eb69ee07e1b9279f4a7aafd1aca6e7f0e26f8c1b1
7
+ data.tar.gz: de69c64ab2ee56df386974bd9f99ffbcbc374cd4661b6394ee3295338f02ecee6cab439fbcd0a6bd3b8d9e54b045ef065fda7a8e290d4f6c6a95cce69cdc7949
data/CHANGELOG.md CHANGED
@@ -20,4 +20,12 @@
20
20
  - CLI with generators:
21
21
  - `generate:config` — scaffolds configuration file
22
22
  - `generate:completion` — scaffolds completion service object
23
- - Rails and plain Ruby project detection for generators
23
+ - Rails and plain Ruby project detection for generators
24
+
25
+ ## [0.3.0] - 2025-04-03
26
+
27
+ ### Added
28
+
29
+ - Embeddings support for OpenAI provider (text-embedding-3-small)
30
+ - EmbeddingResponse object with cosine similarity helper
31
+ - `RubyCanUseLLM.embed` method
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyCanUseLLM
4
+ class EmbeddingResponse
5
+ attr_reader :embedding, :model, :tokens, :raw
6
+
7
+ def initialize(embedding:, model:, tokens:, raw:)
8
+ @embedding = embedding
9
+ @model = model
10
+ @tokens = tokens
11
+ @raw = raw
12
+ end
13
+
14
+ def cosine_similarity(other)
15
+ dot = embedding.zip(other).sum { |a, b| a * b }
16
+ mag_a = Math.sqrt(embedding.sum { |a| a**2 })
17
+ mag_b = Math.sqrt(other.sum { |b| b**2 })
18
+ return 0.0 if mag_a.zero? || mag_b.zero?
19
+
20
+ dot / (mag_a * mag_b)
21
+ end
22
+ end
23
+ end
@@ -10,6 +10,10 @@ module RubyCanUseLLM
10
10
  def chat(messages, **options)
11
11
  raise NotImplementedError, "#{self.class} must implement #chat"
12
12
  end
13
+
14
+ def embed(text, **options)
15
+ raise NotImplementedError, "#{self.class} must implement #embed"
16
+ end
13
17
 
14
18
  private
15
19
 
@@ -20,6 +20,15 @@ module RubyCanUseLLM
20
20
  end
21
21
  end
22
22
 
23
+ def embed(text, **options)
24
+ body = {
25
+ model: options[:model] || "text-embedding-3-small",
26
+ input: text
27
+ }
28
+ response = embedding_request(body)
29
+ parse_embedding(response)
30
+ end
31
+
23
32
  private
24
33
 
25
34
  def build_body(messages, options)
@@ -118,6 +127,34 @@ module RubyCanUseLLM
118
127
  raw: data
119
128
  )
120
129
  end
130
+
131
+ def embedding_request(body)
132
+ uri = URI("https://api.openai.com/v1/embeddings")
133
+ http = Net::HTTP.new(uri.host, uri.port)
134
+ http.use_ssl = true
135
+ http.read_timeout = config.timeout
136
+
137
+ req = Net::HTTP::Post.new(uri)
138
+ req["Authorization"] = "Bearer #{config.api_key}"
139
+ req["Content-Type"] = "application/json"
140
+ req.body = body.to_json
141
+
142
+ handle_response(http.request(req))
143
+ rescue Net::ReadTimeout, Net::OpenTimeout
144
+ raise TimeoutError, "Request to OpenAI timed out after #{config.timeout}s"
145
+ end
146
+
147
+ def parse_embedding(data)
148
+ embedding = data.dig("data", 0, "embedding")
149
+ usage = data["usage"]
150
+
151
+ EmbeddingResponse.new(
152
+ embedding: embedding,
153
+ model: data["model"],
154
+ tokens: usage["total_tokens"],
155
+ raw: data
156
+ )
157
+ end
121
158
  end
122
159
  end
123
- end
160
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubycanusellm
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/rubycanusellm.rb CHANGED
@@ -8,6 +8,7 @@ require_relative "rubycanusellm/chunk"
8
8
  require_relative "rubycanusellm/providers/base"
9
9
  require_relative "rubycanusellm/providers/openai"
10
10
  require_relative "rubycanusellm/providers/anthropic"
11
+ require_relative "rubycanusellm/embedding_response"
11
12
 
12
13
  module RubyCanUseLLM
13
14
  PROVIDERS = {
@@ -39,5 +40,9 @@ module RubyCanUseLLM
39
40
  def chat(messages, **options, &block)
40
41
  client.chat(messages, **options, &block)
41
42
  end
43
+
44
+ def embed(text, **options)
45
+ client.embed(text, **options)
46
+ end
42
47
  end
43
48
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubycanusellm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Manuel Guzman Nava
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-01 00:00:00.000000000 Z
11
+ date: 2026-04-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: One interface, every LLM. Rubycanusellm provides a unified client for
14
14
  OpenAI, Anthropic, and more, plus generators that scaffold the boilerplate so you
@@ -31,6 +31,7 @@ files:
31
31
  - lib/rubycanusellm/chunk.rb
32
32
  - lib/rubycanusellm/cli.rb
33
33
  - lib/rubycanusellm/configuration.rb
34
+ - lib/rubycanusellm/embedding_response.rb
34
35
  - lib/rubycanusellm/errors.rb
35
36
  - lib/rubycanusellm/providers/anthropic.rb
36
37
  - lib/rubycanusellm/providers/base.rb