Class: Collavre::GeminiParentRecommender
- Inherits:
-
Object
- Object
- Collavre::GeminiParentRecommender
- Defined in:
- app/services/collavre/gemini_parent_recommender.rb
Instance Method Summary collapse
-
#initialize(client: default_client) ⇒ GeminiParentRecommender
constructor
A new instance of GeminiParentRecommender.
- #recommend(creative) ⇒ Object
Constructor Details
#initialize(client: default_client) ⇒ GeminiParentRecommender
Returns a new instance of GeminiParentRecommender.
3 4 5 |
# File 'app/services/collavre/gemini_parent_recommender.rb', line 3 def initialize(client: default_client) @client = client end |
Instance Method Details
#recommend(creative) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'app/services/collavre/gemini_parent_recommender.rb', line 7 def recommend(creative) user = creative.user # 1. Gather all potential category candidates # Candidates: All creatives user can write to + creative's current parent (even if not writable?) # Original logic: Distinct creatives having children + parent. # Note: Using `joins(:children)` filters only those that have children. categories = Creative .joins(:children) .distinct .where(origin_id: nil) .select { |c| c.(user, :write) } parent = creative.parent if parent&.(user, :write) categories << parent end categories = categories.uniq # Rebuild tree in memory to avoid N+1 in TreeFormatter children_map = categories.group_by(&:parent_id) categories.each do |c| # Manually set the children association target c.association(:children).target = (children_map[c.id] || []).select { |child| child.(user, :write) } end category_ids = categories.index_by(&:id) top_level_categories = categories.reject { |c| category_ids.key?(c.parent_id) } tree_text = Creatives::TreeFormatter.new(use_permissions: false).format(top_level_categories) prompt = build_prompt(tree_text, Creatives::TreeFormatter.plain_description(creative)) Rails.logger.info("### prompt=#{prompt}") response = @client.chat([ { role: :user, parts: [ { text: prompt } ] } ]) ids = parse_response(response) # Reconstruct paths for result ids.map do |id| c = Creative.find_by(id: id) next unless c path = c.ancestors.reverse.map { |a| Creatives::TreeFormatter.plain_description(a) } + [ Creatives::TreeFormatter.plain_description(c) ] { id: id, path: path.join(" > ") } end.compact end |