active_genie 0.0.10 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,120 +0,0 @@
1
- require 'securerandom'
2
-
3
- require_relative './players_collection'
4
- require_relative './free_for_all'
5
- require_relative './elo_ranking'
6
- require_relative '../scoring/recommended_reviews'
7
-
8
- # This class orchestrates player ranking through multiple evaluation stages
9
- # using Elo ranking and free-for-all match simulations.
10
- # 1. Sets initial scores
11
- # 2. Eliminates low performers
12
- # 3. Runs Elo ranking (for large groups)
13
- # 4. Conducts free-for-all matches
14
- #
15
- # @example Basic usage
16
- # League.call(players, criteria)
17
- #
18
- # @param param_players [Array] Collection of player objects to evaluate
19
- # Example: ["Circle", "Triangle", "Square"]
20
- # or
21
- # [
22
- # { content: "Circle", score: 10 },
23
- # { content: "Triangle", score: 7 },
24
- # { content: "Square", score: 5 }
25
- # ]
26
- # @param criteria [String] Evaluation criteria configuration
27
- # Example: "What is more similar to the letter 'O'?"
28
- # @param config [Hash] Additional configuration config
29
- # Example: { model: "gpt-4o", api_key: ENV['OPENAI_API_KEY'] }
30
- # @return [Hash] Final ranked player results
31
- module ActiveGenie::League
32
- class League
33
- def self.call(param_players, criteria, config: {})
34
- new(param_players, criteria, config:).call
35
- end
36
-
37
- def initialize(param_players, criteria, config: {})
38
- @param_players = param_players
39
- @criteria = criteria
40
- @config = config
41
- @league_id = SecureRandom.uuid
42
- @start_time = Time.now
43
- end
44
-
45
- def call
46
- set_initial_score_players
47
- eliminate_obvious_bad_players
48
- run_elo_ranking if players.eligible_size > 10
49
- run_free_for_all
50
-
51
- ActiveGenie::Logger.info({ **log, step: :league_end, top5: players.first(5).map(&:id) })
52
- players.to_h
53
- end
54
-
55
- private
56
-
57
- SCORE_VARIATION_THRESHOLD = 10
58
-
59
- def set_initial_score_players
60
- players_without_score = players.reject { |player| player.score }
61
- players_without_score.each do |player|
62
- player.score = generate_score(player.content) # This can take a while, can be parallelized
63
- ActiveGenie::Logger.trace({ **log, step: :player_score, player_id: player.id, score: player.score })
64
- end
65
-
66
- ActiveGenie::Logger.info({ **log, step: :initial_score, evaluated_players: players_without_score.size })
67
- end
68
-
69
- def generate_score(content)
70
- ActiveGenie::Scoring::Basic.call(content, @criteria, reviewers, config:)['final_score']
71
- end
72
-
73
- def eliminate_obvious_bad_players
74
- eliminated_count = 0
75
- while players.coefficient_of_variation >= SCORE_VARIATION_THRESHOLD
76
- players.eligible.last.eliminated = 'variation_too_high'
77
- eliminated_count += 1
78
- end
79
-
80
- ActiveGenie::Logger.info({ **log, step: :eliminate_obvious_bad_players, eliminated_count: })
81
- end
82
-
83
- def run_elo_ranking
84
- EloRanking.call(players, @criteria, config:)
85
- end
86
-
87
- def run_free_for_all
88
- FreeForAll.call(players, @criteria, config:)
89
- end
90
-
91
- def reviewers
92
- [recommended_reviews['reviewer1'], recommended_reviews['reviewer2'], recommended_reviews['reviewer3']]
93
- end
94
-
95
- def recommended_reviews
96
- @recommended_reviews ||= ActiveGenie::Scoring::RecommendedReviews.call(
97
- [players.sample.content, players.sample.content].join("\n\n"),
98
- @criteria,
99
- config:
100
- )
101
- end
102
-
103
- def players
104
- @players ||= PlayersCollection.new(@param_players)
105
- end
106
-
107
- def config
108
- { log:, **@config }
109
- end
110
-
111
- def log
112
- {
113
- **(@config.dig(:log) || {}),
114
- league_id: @league_id,
115
- league_start_time: @start_time,
116
- duration: Time.now - @start_time
117
- }
118
- end
119
- end
120
- end
@@ -1,59 +0,0 @@
1
- require 'securerandom'
2
-
3
- module ActiveGenie::Leaderboard
4
- class Player
5
- def initialize(params)
6
- params = { content: params } if params.is_a?(String)
7
-
8
- @id = params.dig(:id) || SecureRandom.uuid
9
- @content = params.dig(:content) || params
10
- @score = params.dig(:score) || nil
11
- @elo = params.dig(:elo) || nil
12
- @free_for_all = {
13
- win: params.dig(:free_for_all, :win) || 0,
14
- lose: params.dig(:free_for_all, :lose) || 0,
15
- draw: params.dig(:free_for_all, :draw) || 0
16
- }
17
- @eliminated = params.dig(:eliminated) || nil
18
- end
19
-
20
- attr_reader :id, :content, :score, :elo, :free_for_all, :eliminated
21
-
22
- def generate_elo_by_score
23
- return if !@elo.nil?
24
-
25
- if @score.nil?
26
- @elo = BASE_ELO
27
- else
28
- @elo = BASE_ELO + (@score - 50)
29
- end
30
- end
31
-
32
- def score=(value)
33
- @score = value
34
- end
35
-
36
- def elo=(value)
37
- @elo = value
38
- end
39
-
40
- def eliminated=(value)
41
- @eliminated = value
42
- end
43
-
44
- def free_for_all_score
45
- @free_for_all[:win] * 3 + @free_for_all[:draw]
46
- end
47
-
48
- def to_h
49
- {
50
- id:, content:, score:, elo:,
51
- eliminated:, free_for_all:, free_for_all_score:
52
- }
53
- end
54
-
55
- private
56
-
57
- BASE_ELO = 1000
58
- end
59
- end
@@ -1,12 +0,0 @@
1
- require_relative 'league/league'
2
-
3
- module ActiveGenie
4
- # See the [league README](lib/active_genie/league/README.md) for more information.
5
- module League
6
- module_function
7
-
8
- def call(...)
9
- league.call(...)
10
- end
11
- end
12
- end