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.
- checksums.yaml +4 -4
- data/README.md +17 -54
- data/VERSION +1 -1
- data/lib/active_genie/battle/basic.rb +49 -58
- data/lib/active_genie/clients/openai_client.rb +60 -18
- data/lib/active_genie/clients/unified_client.rb +2 -2
- data/lib/active_genie/configuration/openai_config.rb +9 -9
- data/lib/active_genie/data_extractor/README.md +0 -1
- data/lib/active_genie/data_extractor/basic.rb +8 -18
- data/lib/active_genie/data_extractor/from_informal.rb +4 -15
- data/lib/active_genie/logger.rb +34 -7
- data/lib/active_genie/{league → ranking}/README.md +7 -7
- data/lib/active_genie/ranking/elo_round.rb +113 -0
- data/lib/active_genie/ranking/free_for_all.rb +76 -0
- data/lib/active_genie/ranking/player.rb +97 -0
- data/lib/active_genie/{league → ranking}/players_collection.rb +18 -11
- data/lib/active_genie/ranking/ranking.rb +98 -0
- data/lib/active_genie/ranking/ranking_scoring.rb +71 -0
- data/lib/active_genie/ranking.rb +12 -0
- data/lib/active_genie/scoring/README.md +1 -1
- data/lib/active_genie/scoring/basic.rb +55 -30
- data/lib/active_genie/scoring/{recommended_reviews.rb → recommended_reviewers.rb} +18 -7
- data/lib/active_genie/scoring.rb +3 -3
- data/lib/active_genie.rb +1 -1
- metadata +66 -87
- data/lib/active_genie/league/elo_ranking.rb +0 -121
- data/lib/active_genie/league/free_for_all.rb +0 -62
- data/lib/active_genie/league/league.rb +0 -120
- data/lib/active_genie/league/player.rb +0 -59
- data/lib/active_genie/league.rb +0 -12
@@ -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
|
data/lib/active_genie/league.rb
DELETED