emb 0.4.0.pre3 → 0.4.0.pre5
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/Gemfile +5 -0
- data/README.md +11 -2
- data/lib/emb/proxy.rb +43 -0
- data/lib/emb/railtie.rb +5 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a9b606e95ab03ea635c8ec7acf1aaa0024a4646cb1a8f41d2e3509c8acefedfa
|
|
4
|
+
data.tar.gz: 78c102fe8b5f547104e5b0e124223f34b4694b19de7c5bccdf2881423fedbbd7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8cd7137ff7332f70537789a6bd9ddac1cf3d591156c3bf51676e5242236e8aabd247312e1a166a2aa584ad3041d45a3016979b383b640ffc8dbc6ecc2cf8b64
|
|
7
|
+
data.tar.gz: ef7a6c243c471b0026c4b35b73120e10b38a2384e12de142e5ebef1b3a9c3200a8180bf1b109eb8282114f7546060b43eed1a3a76adc6e8ad14b09d4da3a4b4e
|
data/Gemfile
CHANGED
|
@@ -9,6 +9,11 @@ gem 'redis-client'
|
|
|
9
9
|
gem 'rake', require: false
|
|
10
10
|
gem 'rspec', require: false
|
|
11
11
|
|
|
12
|
+
# Development-only: the Railtie integration suite boots a real Rails app so the
|
|
13
|
+
# real middleware-stack objects and boot order are exercised. Rails is never a
|
|
14
|
+
# runtime dependency of the gem. Select a line with RAILS_VERSION.
|
|
15
|
+
gem 'rails', ENV.fetch('RAILS_VERSION', '~> 8.0'), require: false
|
|
16
|
+
|
|
12
17
|
gem 'rubocop', require: false
|
|
13
18
|
gem 'rubocop-rake', require: false
|
|
14
19
|
gem 'rubocop-rspec', require: false
|
data/README.md
CHANGED
|
@@ -533,13 +533,22 @@ If your Gemfile loads `emb` before Rails is required (non-standard boot order),
|
|
|
533
533
|
guarded railtie require in `emb.rb` is skipped — add `require "emb/railtie"` in
|
|
534
534
|
`config/application.rb` right after `require "rails/all"` (or in an initializer).
|
|
535
535
|
|
|
536
|
-
The middleware is also safe to mount manually in any Rack app
|
|
537
|
-
|
|
536
|
+
The middleware is also safe to mount manually in any Rack app. In a Rails app,
|
|
537
|
+
set the opt-out as well so the Railtie does not add a second copy:
|
|
538
538
|
|
|
539
539
|
```ruby
|
|
540
|
+
# config/application.rb
|
|
541
|
+
config.emb.middleware = false
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
```ruby
|
|
545
|
+
# wherever you build the stack
|
|
540
546
|
use Emb::Middleware
|
|
541
547
|
```
|
|
542
548
|
|
|
549
|
+
A duplicate mount is harmless — clearing the per-thread scope is idempotent — but
|
|
550
|
+
the opt-out keeps the stack clean and makes the intended wiring explicit.
|
|
551
|
+
|
|
543
552
|
The scope is cleared even when the app raises, and a fresh scope starts
|
|
544
553
|
automatically with the next request. Loaders created but never used within a
|
|
545
554
|
request are dropped — the create-then-consume contract applies per request.
|
data/lib/emb/proxy.rb
CHANGED
|
@@ -38,8 +38,51 @@ module Emb
|
|
|
38
38
|
"#<Emb::Proxy #{@name}>"
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
# Embeds one or more raw images (EMB.IMG). Each argument is the encoded
|
|
42
|
+
# bytes of an image (JPEG/PNG/GIF/WebP) and is sent unchanged as an
|
|
43
|
+
# ASCII-8BIT RESP bulk, so no base64/URL encoding is needed:
|
|
44
|
+
#
|
|
45
|
+
# Emb[:clip].image(File.binread('cat.jpg'))
|
|
46
|
+
# Emb[:clip].image(io1, io2) # IO objects are read
|
|
47
|
+
#
|
|
48
|
+
# format: :binary (default) returns the float32-unpacked vectors from the
|
|
49
|
+
# compact BLOB wire (nil for a failed/truncated slot); format: :values
|
|
50
|
+
# returns the decoded dtype/shape/values envelope. The float32 reply decode
|
|
51
|
+
# is the same `unpack('e*')` path text embeddings use.
|
|
52
|
+
def image(image_bytes, *more, format: :binary)
|
|
53
|
+
format = normalize_format(format)
|
|
54
|
+
images = [image_bytes, *more].map { |bytes| self.class.coerce_image_bytes(bytes) }
|
|
55
|
+
|
|
56
|
+
if format == :values
|
|
57
|
+
reply = @client.send_command('EMB.IMG', @name.to_s, 'VALUES', *images)
|
|
58
|
+
envelope = Emb::ValuesReply.parse(reply)
|
|
59
|
+
return envelope if images.size == 1
|
|
60
|
+
|
|
61
|
+
return envelope.merge(values: Emb::ValuesReply.rows(envelope[:shape], envelope[:values]))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
reply = @client.send_command('EMB.IMG', @name.to_s, *images)
|
|
65
|
+
return unpack_embedding(reply) if images.size == 1
|
|
66
|
+
|
|
67
|
+
Array(reply).map { |entry| entry.nil? ? nil : unpack_embedding(entry) }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# coerce_image_bytes normalizes an image argument to a binary byte string
|
|
71
|
+
# without transcoding: a String's bytes are preserved exactly (only the
|
|
72
|
+
# encoding label is set to ASCII-8BIT), and an IO is read fully.
|
|
73
|
+
def self.coerce_image_bytes(bytes)
|
|
74
|
+
data = bytes.respond_to?(:read) ? bytes.read : bytes
|
|
75
|
+
data = data.to_s
|
|
76
|
+
data = data.dup if data.frozen?
|
|
77
|
+
data.force_encoding(Encoding::BINARY)
|
|
78
|
+
end
|
|
79
|
+
|
|
41
80
|
private
|
|
42
81
|
|
|
82
|
+
def unpack_embedding(entry)
|
|
83
|
+
entry.nil? ? nil : entry.unpack('e*')
|
|
84
|
+
end
|
|
85
|
+
|
|
43
86
|
def normalize_format(format)
|
|
44
87
|
unless %i[binary values].include?(format)
|
|
45
88
|
raise ArgumentError, "unknown format #{format.inspect} (expected :binary or :values)"
|
data/lib/emb/railtie.rb
CHANGED
|
@@ -13,9 +13,13 @@ if defined?(Rails::Railtie)
|
|
|
13
13
|
config.emb.middleware = true
|
|
14
14
|
config.emb.job_middleware = true
|
|
15
15
|
|
|
16
|
+
# Insertion is unconditional (opt-out excepted): during initialization the
|
|
17
|
+
# stack is a Rails::Configuration::MiddlewareStackProxy, which records
|
|
18
|
+
# operations but cannot be inspected. Duplicate insertion is safe because
|
|
19
|
+
# Emb::BatchScope clearing is idempotent, so manual mounts use the opt-out
|
|
20
|
+
# instead of relying on detection.
|
|
16
21
|
initializer 'emb.middleware' do |app|
|
|
17
22
|
next if config.emb.middleware == false
|
|
18
|
-
next if app.middleware.include?(Emb::Middleware)
|
|
19
23
|
|
|
20
24
|
app.middleware.use Emb::Middleware
|
|
21
25
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: emb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.0.
|
|
4
|
+
version: 0.4.0.pre5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- elcuervo
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: batch-loader
|