Class: ContentEmbedding::ImageEmbedding

Inherits:
ContentEmbedding
  • Object
show all
Defined in:
app/models/content_embedding/image_embedding.rb

Constant Summary collapse

EMBEDDING_MODEL =
'gemini-embedding-2-preview'
EMBEDDING_DIMENSIONS =
1536

Belongs to collapse

Class Method Summary collapse

Class Method Details

.apply_published_filter(scope) ⇒ Object



95
96
97
98
# File 'app/models/content_embedding/image_embedding.rb', line 95

def apply_published_filter(scope)
  scope.joins('INNER JOIN digital_assets ON digital_assets.id = content_embeddings_images.embeddable_id')
       .where(digital_assets: { inactive: false })
end

.generate_gemini_query_embedding(query) ⇒ Array<Float>?

Generate query embedding using Gemini Embedding 2

Parameters:

  • query (String)

    Text to embed

Returns:

  • (Array<Float>, nil)

    Embedding vector or nil on error



80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'app/models/content_embedding/image_embedding.rb', line 80

def generate_gemini_query_embedding(query)
  cache_key = "query_embedding:gemini:#{EMBEDDING_DIMENSIONS}:#{Digest::SHA256.hexdigest(query.downcase.strip)[0..15]}"

  cached = Rails.cache.read(cache_key)
  return cached if cached.present?

  vector = Embedding::Gemini.embed_query(query, dimensions: EMBEDDING_DIMENSIONS)

  Rails.cache.write(cache_key, vector, expires_in: 24.hours) if vector.present?
  vector
rescue Embedding::Gemini::Error => e
  Rails.logger.error "[ImageEmbedding] Failed to generate Gemini query embedding: #{e.message}"
  nil
end

.primary_contentActiveRecord::Relation<ContentEmbedding::ImageEmbedding>

A relation of ContentEmbedding::ImageEmbeddings that are primary content. Active Record Scope

Returns:

See Also:



45
# File 'app/models/content_embedding/image_embedding.rb', line 45

scope :primary_content, -> { where(content_type: 'primary') }

.semantic_search(query, limit: 10, published_only: true) ⇒ ActiveRecord::Relation

Visual semantic search using Gemini Embedding 2 multimodal embeddings.
Enables text-to-image search (describe what you want, find matching images).

Searches both new Gemini and legacy Jina embeddings during migration.

Parameters:

  • query (String)

    Natural language description of desired images

  • limit (Integer) (defaults to: 10)

    Maximum results (default: 10)

  • published_only (Boolean) (defaults to: true)

    Filter to active images (default: true)

Returns:

  • (ActiveRecord::Relation)

    Image embeddings ordered by similarity



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'app/models/content_embedding/image_embedding.rb', line 60

def semantic_search(query, limit: 10, published_only: true, **)
  return none if query.blank?

  query_embedding = generate_gemini_query_embedding(query)
  return none unless query_embedding

  scope = unified_content
          .with_unified_embedding
          .where(embedding_model: [EMBEDDING_MODEL, 'jina-embeddings-v4'])
          .nearest_neighbors(:unified_embedding, query_embedding, distance: :cosine)

  scope = apply_published_filter(scope) if published_only

  scope.limit(limit).includes(:embeddable)
end

.unified_contentActiveRecord::Relation<ContentEmbedding::ImageEmbedding>

A relation of ContentEmbedding::ImageEmbeddings that are unified content. Active Record Scope

Returns:

See Also:



46
# File 'app/models/content_embedding/image_embedding.rb', line 46

scope :unified_content, -> { where(content_type: 'unified') }

.with_embeddingActiveRecord::Relation<ContentEmbedding::ImageEmbedding>

A relation of ContentEmbedding::ImageEmbeddings that are with embedding. Active Record Scope

Returns:

See Also:



47
# File 'app/models/content_embedding/image_embedding.rb', line 47

scope :with_embedding, -> { where.not(embedding: nil) }

.with_unified_embeddingActiveRecord::Relation<ContentEmbedding::ImageEmbedding>

A relation of ContentEmbedding::ImageEmbeddings that are with unified embedding. Active Record Scope

Returns:

See Also:



48
# File 'app/models/content_embedding/image_embedding.rb', line 48

scope :with_unified_embedding, -> { where.not(unified_embedding: nil) }

Instance Method Details

#embeddableImage Also known as: image

Returns:

See Also:



39
# File 'app/models/content_embedding/image_embedding.rb', line 39

belongs_to :embeddable, class_name: 'Image'