Class: SpreeMenuChat::Embedder

Inherits:
Object
  • Object
show all
Defined in:
app/services/spree_menu_chat/embedder.rb

Overview

Embeds one record (a Spree::Product or Spree::Policy) and upserts its SpreeMenuChat::Embedding row — the shared "build content, skip if unchanged, call Voyage, save" logic both ReembedProductJob and ReembedCatalogJob call into, so there's exactly one place that decides when a re-embed is actually necessary.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(embeddable, store:) ⇒ Embedder

Returns a new instance of Embedder.



12
13
14
15
# File 'app/services/spree_menu_chat/embedder.rb', line 12

def initialize(embeddable, store:)
  @embeddable = embeddable
  @store = store
end

Class Method Details

.call(embeddable, store: Spree::Store.default) ⇒ Object



8
9
10
# File 'app/services/spree_menu_chat/embedder.rb', line 8

def self.call(embeddable, store: Spree::Store.default)
  new(embeddable, store: store).call
end

Instance Method Details

#callObject



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'app/services/spree_menu_chat/embedder.rb', line 17

def call
  content = SpreeMenuChat::ContentBuilder.call(@embeddable)
  return nil if content.blank?

  content_hash = SpreeMenuChat::Embedding.content_hash_for(content)
  existing = SpreeMenuChat::Embedding.find_by(embeddable: @embeddable)

  # Nothing embeddable actually changed — skip the Voyage call entirely
  # rather than re-billing for identical content (e.g. a product saved
  # for an unrelated field, or a webhook re-sync that changed nothing).
  return existing if existing&.content_hash == content_hash

  vectors = SpreeMenuChat::EmbeddingClient.for_store(@store).embed(content, input_type: 'document')
  vector = vectors.first
  raise "Voyage returned no embedding for #{@embeddable.class.name}##{@embeddable.id}" unless vector

  record = existing || SpreeMenuChat::Embedding.new(embeddable: @embeddable, store: @store)
  record.assign_attributes(content: content, content_hash: content_hash, embedding: vector)
  record.save!
  record
end