Class: Embedding::Gemini
- Inherits:
-
Object
- Object
- Embedding::Gemini
- Defined in:
- app/services/embedding/gemini.rb
Overview
Gemini Embedding 2 service for multimodal embeddings.
Natively embeds images, text, and interleaved image+text into a unified
vector space via the Gemini API embedContent endpoint.
== Architecture
Image Analysis: pHash → Gemini Embedding 2 (image + metadata)
Vision Desc: Gemini Flash (independent, on-demand)
== Embedding Dimensions
Gemini Embedding 2 supports Matryoshka Representation Learning:
- 3072: Full quality (default from API)
- 1536: Used here for HNSW compatibility (pgvector 2000-dim limit)
- 768: For constrained environments
== Rate Limiting
Redis-based sliding window rate limiter.
Configurable via GEMINI_EMBED_REQUESTS_PER_MINUTE (default: 300).
Defined Under Namespace
Classes: ApiError, ConfigurationError, Error, RateLimitError
Constant Summary collapse
- BASE_URL =
'https://generativelanguage.googleapis.com'- API_VERSION =
'v1beta'- EMBED_MODEL =
'gemini-embedding-2-preview'- MODEL_NAME =
'gemini-embedding-2-preview'- DEFAULT_DIMENSIONS =
1536- DEFAULT_TEXT_DIMENSIONS =
1536- DEFAULT_VISUAL_DIMENSIONS =
1536- TIMEOUT =
120- RATE_LIMIT_KEY =
'gemini_embed:rate_limit'- REQUESTS_PER_MINUTE =
ENV.fetch('GEMINI_EMBED_REQUESTS_PER_MINUTE', 300).to_i
- RATE_LIMIT_WINDOW =
seconds
60- MAX_RETRIES =
5- BASE_RETRY_DELAY =
2- TASK_TYPES =
Gemini task types for embedding optimization
{ query: 'RETRIEVAL_QUERY', document: 'RETRIEVAL_DOCUMENT', similarity: 'SEMANTIC_SIMILARITY', classification: 'CLASSIFICATION', clustering: 'CLUSTERING' }.freeze
- MIME_TYPES =
{ '.jpg' => 'image/jpeg', '.jpeg' => 'image/jpeg', '.png' => 'image/png' }.freeze
- RETRYABLE_EXCEPTIONS =
[ RateLimitError, Faraday::TimeoutError, Faraday::ConnectionFailed ].freeze
Class Method Summary collapse
-
.available? ⇒ Boolean
Check if the API is configured.
-
.embed_image(image_url, text: nil, dimensions: DEFAULT_VISUAL_DIMENSIONS) ⇒ Array<Float>
Embed an image, optionally with accompanying text metadata.
-
.embed_image_file(path, text: nil, dimensions: DEFAULT_VISUAL_DIMENSIONS) ⇒ Array<Float>
Embed a local image file.
-
.embed_image_url(url, dimensions: DEFAULT_VISUAL_DIMENSIONS) ⇒ Object
Alias for embed_image.
-
.embed_query(text, dimensions: DEFAULT_TEXT_DIMENSIONS) ⇒ Array<Float>
Embed text for a search query.
-
.embed_text(text, dimensions: DEFAULT_TEXT_DIMENSIONS) ⇒ Array<Float>
Embed text for storage/indexing.
-
.embed_visual_query(text, dimensions: DEFAULT_VISUAL_DIMENSIONS) ⇒ Array<Float>
Embed a text query for visual search (cross-modal text → image).
-
.model_name ⇒ String
Model name for database storage.
Class Method Details
.available? ⇒ Boolean
Check if the API is configured
145 146 147 148 149 |
# File 'app/services/embedding/gemini.rb', line 145 def available? api_key.present? rescue ConfigurationError false end |
.embed_image(image_url, text: nil, dimensions: DEFAULT_VISUAL_DIMENSIONS) ⇒ Array<Float>
Embed an image, optionally with accompanying text metadata.
Sends the image as inlineData (base64) with optional text parts.
91 92 93 94 95 96 97 |
# File 'app/services/embedding/gemini.rb', line 91 def (image_url, text: nil, dimensions: DEFAULT_VISUAL_DIMENSIONS) parts = [] parts << { text: text } if text.present? parts << build_image_part(image_url) (parts, task_type: :document, dimensions: dimensions) end |
.embed_image_file(path, text: nil, dimensions: DEFAULT_VISUAL_DIMENSIONS) ⇒ Array<Float>
Embed a local image file
105 106 107 108 109 110 111 112 113 |
# File 'app/services/embedding/gemini.rb', line 105 def (path, text: nil, dimensions: DEFAULT_VISUAL_DIMENSIONS) raise Error, "Image file not found: #{path}" unless File.exist?(path) parts = [] parts << { text: text } if text.present? parts << build_file_image_part(path) (parts, task_type: :document, dimensions: dimensions) end |
.embed_image_url(url, dimensions: DEFAULT_VISUAL_DIMENSIONS) ⇒ Object
Alias for embed_image
157 158 159 |
# File 'app/services/embedding/gemini.rb', line 157 def (url, dimensions: DEFAULT_VISUAL_DIMENSIONS) (url, dimensions: dimensions) end |
.embed_query(text, dimensions: DEFAULT_TEXT_DIMENSIONS) ⇒ Array<Float>
Embed text for a search query
120 121 122 |
# File 'app/services/embedding/gemini.rb', line 120 def (text, dimensions: DEFAULT_TEXT_DIMENSIONS) ([{ text: text }], task_type: :query, dimensions: dimensions) end |
.embed_text(text, dimensions: DEFAULT_TEXT_DIMENSIONS) ⇒ Array<Float>
Embed text for storage/indexing
129 130 131 |
# File 'app/services/embedding/gemini.rb', line 129 def (text, dimensions: DEFAULT_TEXT_DIMENSIONS) ([{ text: text }], task_type: :document, dimensions: dimensions) end |
.embed_visual_query(text, dimensions: DEFAULT_VISUAL_DIMENSIONS) ⇒ Array<Float>
Embed a text query for visual search (cross-modal text → image)
138 139 140 |
# File 'app/services/embedding/gemini.rb', line 138 def (text, dimensions: DEFAULT_VISUAL_DIMENSIONS) (text, dimensions: dimensions) end |
.model_name ⇒ String
Returns Model name for database storage.
152 153 154 |
# File 'app/services/embedding/gemini.rb', line 152 def model_name MODEL_NAME end |