Class: ImageGeneration::TitleSuggester

Inherits:
Object
  • Object
show all
Defined in:
app/services/image_generation/title_suggester.rb

Overview

Generates a concise, SEO-aware image title from the generation prompt and
optional source image metadata using a cheap fast-text model via RubyLLM.

Returns a +Result+ value object with:

  • +title+ [String] The suggested title (nil on failure)
  • +input_tokens+ [Integer] Tokens consumed (nil if unavailable)
  • +output_tokens+ [Integer]
  • +model_id+ [String] Model that was used
  • +error+ [String] Error message on failure (nil on success)

Examples:

result = ImageGeneration::TitleSuggester.call(
  prompt:       "radiant floor heating under marble tile in a spa bathroom",
  source_title: "Marble spa bathroom — floor heating installation",
  source_tags:  %w[bathroom spa marble ai-generated]
)
result.title        # => "Marble Spa Bathroom Radiant Floor Heating Installation"
result.input_tokens # => 78

Defined Under Namespace

Classes: Result

Constant Summary collapse

PREFERRED_MODELS =

Prefer gemini-flash or gpt-4o-mini — cheap, fast, adequate quality.
Falls back down the list in order of availability.

%w[
  gemini-2.0-flash
  gemini-1.5-flash
  gpt-4o-mini
  claude-3-5-haiku-20241022
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(prompt:, source_title: nil, source_tags: []) ⇒ TitleSuggester

Returns a new instance of TitleSuggester.



47
48
49
50
51
# File 'app/services/image_generation/title_suggester.rb', line 47

def initialize(prompt:, source_title: nil, source_tags: [])
  @prompt       = prompt.to_s.strip
  @source_title = source_title.to_s.presence
  @source_tags  = Array(source_tags).reject(&:blank?) - Image::PROVENANCE_TAGS
end

Class Method Details

.call(prompt:, source_title: nil, source_tags: []) ⇒ Object



43
44
45
# File 'app/services/image_generation/title_suggester.rb', line 43

def self.call(prompt:, source_title: nil, source_tags: [])
  new(prompt: prompt, source_title: source_title, source_tags: source_tags).call
end

Instance Method Details

#callObject



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'app/services/image_generation/title_suggester.rb', line 53

def call
  model = select_model
  return Result.new(error: 'No LLM model available for title suggestion') unless model

  llm_message = generate_title(model)
  title       = clean_title(llm_message.content.to_s)

  Result.new(
    title:         title,
    input_tokens:  llm_message.input_tokens,
    output_tokens: llm_message.output_tokens,
    model_id:      model
  )
rescue RubyLLM::RateLimitError => e
  Rails.logger.warn "[TitleSuggester] Rate limited: #{e.message}"
  Result.new(error: "Rate limited — please retry shortly")
rescue RubyLLM::Error => e
  Rails.logger.warn "[TitleSuggester] RubyLLM error: #{e.message}"
  Result.new(error: e.message)
rescue StandardError => e
  Rails.logger.warn "[TitleSuggester] Failed: #{e.message}"
  Result.new(error: e.message)
end