|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +module Jobs |
| 4 | + class GenerateConceptsFromPopularItems < ::Jobs::Scheduled |
| 5 | + every 1.day |
| 6 | + |
| 7 | + # This job runs daily and generates new concepts from popular topics and posts |
| 8 | + # It selects items based on engagement metrics and generates concepts from their content |
| 9 | + def execute(_args) |
| 10 | + return unless SiteSetting.inferred_concepts_enabled |
| 11 | + |
| 12 | + process_popular_topics |
| 13 | + process_popular_posts |
| 14 | + end |
| 15 | + |
| 16 | + private |
| 17 | + |
| 18 | + def process_popular_topics |
| 19 | + # Find candidate topics that are popular and don't have concepts yet |
| 20 | + manager = DiscourseAi::InferredConcepts::Manager.new |
| 21 | + candidates = |
| 22 | + manager.find_candidate_topics( |
| 23 | + limit: SiteSetting.inferred_concepts_daily_topics_limit || 20, |
| 24 | + min_posts: SiteSetting.inferred_concepts_min_posts || 5, |
| 25 | + min_likes: SiteSetting.inferred_concepts_min_likes || 10, |
| 26 | + min_views: SiteSetting.inferred_concepts_min_views || 100, |
| 27 | + created_after: SiteSetting.inferred_concepts_lookback_days.days.ago, |
| 28 | + ) |
| 29 | + |
| 30 | + return if candidates.blank? |
| 31 | + |
| 32 | + # Process candidate topics - first generate concepts, then match |
| 33 | + Jobs.enqueue( |
| 34 | + :generate_inferred_concepts, |
| 35 | + item_type: "topics", |
| 36 | + item_ids: candidates.map(&:id), |
| 37 | + batch_size: 10, |
| 38 | + ) |
| 39 | + |
| 40 | + if SiteSetting.inferred_concepts_background_match |
| 41 | + # Schedule a follow-up job to match existing concepts |
| 42 | + Jobs.enqueue_in( |
| 43 | + 1.hour, |
| 44 | + :generate_inferred_concepts, |
| 45 | + item_type: "topics", |
| 46 | + item_ids: candidates.map(&:id), |
| 47 | + batch_size: 10, |
| 48 | + match_only: true, |
| 49 | + ) |
| 50 | + end |
| 51 | + end |
| 52 | + |
| 53 | + def process_popular_posts |
| 54 | + # Find candidate posts that are popular and don't have concepts yet |
| 55 | + manager = DiscourseAi::InferredConcepts::Manager.new |
| 56 | + candidates = |
| 57 | + manager.find_candidate_posts( |
| 58 | + limit: SiteSetting.inferred_concepts_daily_posts_limit || 30, |
| 59 | + min_likes: SiteSetting.inferred_concepts_post_min_likes || 5, |
| 60 | + exclude_first_posts: true, |
| 61 | + created_after: SiteSetting.inferred_concepts_lookback_days.days.ago, |
| 62 | + ) |
| 63 | + |
| 64 | + return if candidates.blank? |
| 65 | + |
| 66 | + # Process candidate posts - first generate concepts, then match |
| 67 | + Jobs.enqueue( |
| 68 | + :generate_inferred_concepts, |
| 69 | + item_type: "posts", |
| 70 | + item_ids: candidates.map(&:id), |
| 71 | + batch_size: 10, |
| 72 | + ) |
| 73 | + |
| 74 | + if SiteSetting.inferred_concepts_background_match |
| 75 | + # Schedule a follow-up job to match against existing concepts |
| 76 | + Jobs.enqueue_in( |
| 77 | + 1.hour, |
| 78 | + :generate_inferred_concepts, |
| 79 | + item_type: "posts", |
| 80 | + item_ids: candidates.map(&:id), |
| 81 | + batch_size: 10, |
| 82 | + match_only: true, |
| 83 | + ) |
| 84 | + end |
| 85 | + end |
| 86 | + end |
| 87 | +end |
0 commit comments