active_genie 0.0.24 → 0.0.25
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 +35 -50
- data/VERSION +1 -1
- data/lib/active_genie/battle/README.md +5 -5
- data/lib/active_genie/battle/generalist.rb +132 -0
- data/lib/active_genie/battle.rb +6 -5
- data/lib/active_genie/clients/providers/anthropic_client.rb +77 -0
- data/lib/active_genie/clients/{base_client.rb → providers/base_client.rb} +74 -100
- data/lib/active_genie/clients/providers/deepseek_client.rb +91 -0
- data/lib/active_genie/clients/providers/google_client.rb +132 -0
- data/lib/active_genie/clients/providers/openai_client.rb +96 -0
- data/lib/active_genie/clients/unified_client.rb +42 -12
- data/lib/active_genie/concerns/loggable.rb +11 -23
- data/lib/active_genie/config/battle_config.rb +8 -0
- data/lib/active_genie/config/data_extractor_config.rb +23 -0
- data/lib/active_genie/config/llm_config.rb +36 -0
- data/lib/active_genie/config/log_config.rb +44 -0
- data/lib/active_genie/config/providers/anthropic_config.rb +57 -0
- data/lib/active_genie/config/providers/deepseek_config.rb +50 -0
- data/lib/active_genie/config/providers/google_config.rb +52 -0
- data/lib/active_genie/config/providers/openai_config.rb +50 -0
- data/lib/active_genie/config/providers/provider_base.rb +89 -0
- data/lib/active_genie/config/providers_config.rb +62 -0
- data/lib/active_genie/config/ranking_config.rb +21 -0
- data/lib/active_genie/config/scoring_config.rb +8 -0
- data/lib/active_genie/configuration.rb +51 -28
- data/lib/active_genie/data_extractor/README.md +13 -13
- data/lib/active_genie/data_extractor/from_informal.rb +54 -48
- data/lib/active_genie/data_extractor/generalist.md +12 -0
- data/lib/active_genie/data_extractor/generalist.rb +125 -0
- data/lib/active_genie/data_extractor.rb +7 -5
- data/lib/active_genie/errors/invalid_provider_error.rb +41 -0
- data/lib/active_genie/logger.rb +17 -66
- data/lib/active_genie/ranking/README.md +31 -1
- data/lib/active_genie/ranking/elo_round.rb +107 -104
- data/lib/active_genie/ranking/free_for_all.rb +78 -74
- data/lib/active_genie/ranking/player.rb +79 -71
- data/lib/active_genie/ranking/players_collection.rb +83 -71
- data/lib/active_genie/ranking/ranking.rb +71 -94
- data/lib/active_genie/ranking/ranking_scoring.rb +71 -50
- data/lib/active_genie/ranking.rb +2 -0
- data/lib/active_genie/scoring/README.md +4 -4
- data/lib/active_genie/scoring/generalist.rb +171 -0
- data/lib/active_genie/scoring/recommended_reviewers.rb +70 -71
- data/lib/active_genie/scoring.rb +8 -5
- data/lib/active_genie.rb +23 -1
- data/lib/tasks/benchmark.rake +10 -9
- data/lib/tasks/install.rake +3 -1
- data/lib/tasks/templates/active_genie.rb +11 -6
- metadata +31 -22
- data/lib/active_genie/battle/basic.rb +0 -129
- data/lib/active_genie/clients/anthropic_client.rb +0 -84
- data/lib/active_genie/clients/google_client.rb +0 -135
- data/lib/active_genie/clients/helpers/retry.rb +0 -29
- data/lib/active_genie/clients/openai_client.rb +0 -98
- data/lib/active_genie/configuration/log_config.rb +0 -14
- data/lib/active_genie/configuration/providers/anthropic_config.rb +0 -54
- data/lib/active_genie/configuration/providers/base_config.rb +0 -85
- data/lib/active_genie/configuration/providers/deepseek_config.rb +0 -54
- data/lib/active_genie/configuration/providers/google_config.rb +0 -56
- data/lib/active_genie/configuration/providers/internal_company_api_config.rb +0 -54
- data/lib/active_genie/configuration/providers/openai_config.rb +0 -54
- data/lib/active_genie/configuration/providers_config.rb +0 -40
- data/lib/active_genie/configuration/runtime_config.rb +0 -35
- data/lib/active_genie/data_extractor/basic.rb +0 -101
- data/lib/active_genie/scoring/basic.rb +0 -170
@@ -1,75 +1,87 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module ActiveGenie::Ranking
|
4
|
-
class PlayersCollection
|
5
|
-
def initialize(param_players)
|
6
|
-
@players = build(param_players)
|
7
|
-
end
|
8
|
-
attr_reader :players
|
9
|
-
|
10
|
-
def coefficient_of_variation
|
11
|
-
score_list = eligible.map(&:score).compact
|
12
|
-
return nil if score_list.empty?
|
13
|
-
|
14
|
-
mean = score_list.sum.to_f / score_list.size
|
15
|
-
return nil if mean == 0
|
16
|
-
|
17
|
-
variance = score_list.map { |num| (num - mean) ** 2 }.sum / score_list.size
|
18
|
-
standard_deviation = Math.sqrt(variance)
|
19
|
-
|
20
|
-
(standard_deviation / mean) * 100
|
21
|
-
end
|
22
|
-
|
23
|
-
def calc_relegation_tier
|
24
|
-
eligible[(tier_size*-1)..-1]
|
25
|
-
end
|
26
|
-
|
27
|
-
def calc_defender_tier
|
28
|
-
eligible[(tier_size*-2)...(tier_size*-1)]
|
29
|
-
end
|
30
|
-
|
31
|
-
def eligible
|
32
|
-
sorted.reject(&:eliminated)
|
33
|
-
end
|
1
|
+
# frozen_string_literal: true
|
34
2
|
|
35
|
-
|
36
|
-
@players.reject(&:eliminated).size
|
37
|
-
end
|
38
|
-
|
39
|
-
def elo_eligible?
|
40
|
-
eligible.size > 15
|
41
|
-
end
|
42
|
-
|
43
|
-
def sorted
|
44
|
-
sorted_players = @players.sort_by { |p| [-p.ffa_score, -(p.elo || 0), -(p.score || 0)] }
|
45
|
-
sorted_players.each_with_index { |p, i| p.rank = i + 1 }
|
46
|
-
sorted_players
|
47
|
-
end
|
48
|
-
|
49
|
-
def to_h
|
50
|
-
sorted.map { |p| p.to_h }
|
51
|
-
end
|
52
|
-
|
53
|
-
def method_missing(...)
|
54
|
-
@players.send(...)
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def build(param_players)
|
60
|
-
param_players.map { |p| Player.new(p) }
|
61
|
-
end
|
3
|
+
require_relative './player'
|
62
4
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
5
|
+
module ActiveGenie
|
6
|
+
module Ranking
|
7
|
+
class PlayersCollection
|
8
|
+
def initialize(param_players)
|
9
|
+
@players = build(param_players)
|
10
|
+
end
|
11
|
+
attr_reader :players
|
12
|
+
|
13
|
+
def coefficient_of_variation
|
14
|
+
score_list = eligible.map(&:score).compact
|
15
|
+
return nil if score_list.empty?
|
16
|
+
|
17
|
+
mean = score_list.sum.to_f / score_list.size
|
18
|
+
return nil if mean.zero?
|
19
|
+
|
20
|
+
variance = score_list.map { |num| (num - mean)**2 }.sum / score_list.size
|
21
|
+
standard_deviation = Math.sqrt(variance)
|
22
|
+
|
23
|
+
(standard_deviation / mean) * 100
|
24
|
+
end
|
25
|
+
|
26
|
+
def calc_relegation_tier
|
27
|
+
eligible[(tier_size * -1)..]
|
28
|
+
end
|
29
|
+
|
30
|
+
def calc_defender_tier
|
31
|
+
eligible[(tier_size * -2)...(tier_size * -1)]
|
32
|
+
end
|
33
|
+
|
34
|
+
def eligible
|
35
|
+
sorted.reject(&:eliminated)
|
36
|
+
end
|
37
|
+
|
38
|
+
def eligible_size
|
39
|
+
@players.reject(&:eliminated).size
|
40
|
+
end
|
41
|
+
|
42
|
+
def elo_eligible?
|
43
|
+
eligible.size > 15
|
44
|
+
end
|
45
|
+
|
46
|
+
def sorted
|
47
|
+
sorted_players = @players.sort_by { |p| -p.sort_value }
|
48
|
+
sorted_players.each_with_index { |p, i| p.rank = i + 1 }
|
49
|
+
sorted_players
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_json(*_args)
|
53
|
+
to_h.to_json
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_h
|
57
|
+
sorted.map(&:to_h)
|
58
|
+
end
|
59
|
+
|
60
|
+
def method_missing(...)
|
61
|
+
@players.send(...)
|
62
|
+
end
|
63
|
+
|
64
|
+
def respond_to_missing?(method_name, include_private = false)
|
65
|
+
@players.respond_to?(method_name, include_private)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def build(param_players)
|
71
|
+
param_players.map { |p| Player.new(p) }
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the number of players to battle in each round
|
75
|
+
# based on the eligible size, start fast and go slow until top 10
|
76
|
+
# Example:
|
77
|
+
# - 50 eligible, tier_size: 15
|
78
|
+
# - 35 eligible, tier_size: 11
|
79
|
+
# - 24 eligible, tier_size: 10
|
80
|
+
# - 14 eligible, tier_size: 4
|
81
|
+
# 4 rounds to reach top 10 with 50 players
|
82
|
+
def tier_size
|
83
|
+
[[(eligible_size / 3).ceil, 10].max, eligible_size - 10].min
|
84
|
+
end
|
73
85
|
end
|
74
86
|
end
|
75
|
-
end
|
87
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../concerns/loggable'
|
2
4
|
require_relative './players_collection'
|
3
5
|
require_relative './free_for_all'
|
@@ -27,127 +29,102 @@ require_relative './ranking_scoring'
|
|
27
29
|
# @param config [Hash] Additional configuration config
|
28
30
|
# Example: { model: "gpt-4o", api_key: ENV['OPENAI_API_KEY'] }
|
29
31
|
# @return [Hash] Final ranked player results
|
30
|
-
module ActiveGenie
|
31
|
-
|
32
|
-
|
32
|
+
module ActiveGenie
|
33
|
+
module Ranking
|
34
|
+
class Ranking
|
35
|
+
include ActiveGenie::Concerns::Loggable
|
33
36
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
+
def self.call(...)
|
38
|
+
new(...).call
|
39
|
+
end
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@elo_round_battle_count = 0
|
45
|
-
@free_for_all_battle_count = 0
|
46
|
-
@total_tokens = 0
|
47
|
-
@start_time = Time.now
|
48
|
-
end
|
41
|
+
def initialize(_param_players, criteria, reviewers: [], config: {})
|
42
|
+
@criteria = criteria
|
43
|
+
@reviewers = Array(reviewers).compact.uniq
|
44
|
+
@config = ActiveGenie.configuration.merge(config)
|
45
|
+
@players = nil
|
46
|
+
end
|
49
47
|
|
50
|
-
|
51
|
-
|
48
|
+
def call
|
49
|
+
@players = create_players
|
52
50
|
|
53
|
-
|
54
|
-
|
51
|
+
set_initial_player_scores!
|
52
|
+
eliminate_obvious_bad_players!
|
55
53
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
while @players.elo_eligible?
|
55
|
+
elo_report = run_elo_round!
|
56
|
+
eliminate_relegation_players!
|
57
|
+
rebalance_players!(elo_report)
|
58
|
+
end
|
61
59
|
|
62
|
-
|
63
|
-
final_logs
|
60
|
+
run_free_for_all!
|
64
61
|
|
65
|
-
|
66
|
-
|
62
|
+
sorted_players
|
63
|
+
end
|
67
64
|
|
68
|
-
|
65
|
+
private
|
69
66
|
|
70
|
-
|
71
|
-
|
72
|
-
ELIMINATION_RELEGATION = 'relegation_tier'
|
73
|
-
|
74
|
-
with_logging_context :log_context, ->(log) {
|
75
|
-
@total_tokens += log[:total_tokens] || 0 if log[:code] == :llm_usage
|
76
|
-
}
|
67
|
+
ELIMINATION_VARIATION = 'variation_too_high'
|
68
|
+
ELIMINATION_RELEGATION = 'relegation_tier'
|
77
69
|
|
78
|
-
|
79
|
-
@players.each { |p| ActiveGenie::Logger.debug({ code: :new_player, player: p.to_h }) }
|
80
|
-
end
|
70
|
+
call_with_log_context :log_context
|
81
71
|
|
82
|
-
|
83
|
-
|
84
|
-
|
72
|
+
def create_players
|
73
|
+
players = PlayersCollection.new(param_players)
|
74
|
+
players.each { |p| logger({ code: :new_player, player: p.to_h }) }
|
85
75
|
|
86
|
-
|
87
|
-
while @players.coefficient_of_variation >= SCORE_VARIATION_THRESHOLD
|
88
|
-
@players.eligible.last.eliminated = ELIMINATION_VARIATION
|
76
|
+
players
|
89
77
|
end
|
90
|
-
end
|
91
78
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
elo_report = EloRound.call(@players, @criteria, config: @config)
|
79
|
+
def set_initial_player_scores!
|
80
|
+
RankingScoring.call(@players, @criteria, reviewers: @reviewers, config: @config)
|
81
|
+
end
|
96
82
|
|
97
|
-
|
83
|
+
def eliminate_obvious_bad_players!
|
84
|
+
while @players.coefficient_of_variation >= @config.ranking.score_variation_threshold
|
85
|
+
@players.eligible.last.eliminated = ELIMINATION_VARIATION
|
86
|
+
end
|
87
|
+
end
|
98
88
|
|
99
|
-
|
100
|
-
|
89
|
+
def run_elo_round!
|
90
|
+
EloRound.call(@players, @criteria, config: @config)
|
91
|
+
end
|
101
92
|
|
102
|
-
|
103
|
-
|
104
|
-
|
93
|
+
def eliminate_relegation_players!
|
94
|
+
@players.calc_relegation_tier.each { |player| player.eliminated = ELIMINATION_RELEGATION }
|
95
|
+
end
|
105
96
|
|
106
|
-
|
107
|
-
|
97
|
+
def rebalance_players!(elo_report)
|
98
|
+
return if elo_report[:highest_elo_diff].negative?
|
108
99
|
|
109
|
-
|
110
|
-
|
100
|
+
@players.eligible.each do |player|
|
101
|
+
next if elo_report[:players_in_round].include?(player.id)
|
111
102
|
|
112
|
-
|
103
|
+
player.elo += elo_report[:highest_elo_diff]
|
104
|
+
end
|
113
105
|
end
|
114
|
-
end
|
115
106
|
|
116
|
-
|
117
|
-
|
107
|
+
def run_free_for_all!
|
108
|
+
FreeForAll.call(@players, @criteria, config: @config)
|
109
|
+
end
|
118
110
|
|
119
|
-
|
120
|
-
|
111
|
+
def sorted_players
|
112
|
+
players = @players.sorted
|
113
|
+
logger({ code: :ranking_final, players: players.map(&:to_h) })
|
121
114
|
|
122
|
-
|
123
|
-
|
124
|
-
ranking_id: ranking_id,
|
125
|
-
players_count: @players.size,
|
126
|
-
variation_too_high: @players.select { |player| player.eliminated == ELIMINATION_VARIATION }.size,
|
127
|
-
elo_rounds_played: @elo_rounds_played,
|
128
|
-
elo_round_battle_count: @elo_round_battle_count,
|
129
|
-
relegation_tier: @players.select { |player| player.eliminated == ELIMINATION_RELEGATION }.size,
|
130
|
-
ffa_round_battle_count: @free_for_all_battle_count,
|
131
|
-
top3: @players.eligible[0..2].map(&:id),
|
132
|
-
total_tokens: @total_tokens,
|
133
|
-
duration_seconds: Time.now - @start_time,
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
|
-
def final_logs
|
138
|
-
ActiveGenie::Logger.debug({ code: :ranking_final, players: @players.sorted.map(&:to_h) })
|
139
|
-
ActiveGenie::Logger.info({ code: :ranking, **report })
|
140
|
-
end
|
115
|
+
players.map(&:to_h)
|
116
|
+
end
|
141
117
|
|
142
|
-
|
143
|
-
|
144
|
-
|
118
|
+
def log_context
|
119
|
+
{ ranking_id: }
|
120
|
+
end
|
145
121
|
|
146
|
-
|
147
|
-
|
148
|
-
|
122
|
+
def ranking_id
|
123
|
+
player_ids = @players.map(&:id).join(',')
|
124
|
+
ranking_unique_key = [player_ids, @criteria, @config.to_json].join('-')
|
149
125
|
|
150
|
-
|
126
|
+
Digest::MD5.hexdigest(ranking_unique_key)
|
127
|
+
end
|
151
128
|
end
|
152
129
|
end
|
153
130
|
end
|
@@ -1,71 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../scoring/recommended_reviewers'
|
2
4
|
|
3
|
-
module ActiveGenie
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
module ActiveGenie
|
6
|
+
module Ranking
|
7
|
+
class RankingScoring
|
8
|
+
def self.call(...)
|
9
|
+
new(...).call
|
10
|
+
end
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def initialize(players, criteria, reviewers: [], config: {})
|
13
|
+
@players = players
|
14
|
+
@criteria = criteria
|
15
|
+
@config = ActiveGenie.configuration.merge(config)
|
16
|
+
@reviewers = Array(reviewers).compact.uniq
|
17
|
+
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
def call
|
20
|
+
ActiveGenie::Logger.with_context(log_context) do
|
21
|
+
@reviewers = generate_reviewers
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
players_to_score = players_without_score
|
24
|
+
until players_to_score.empty?
|
25
|
+
threads = []
|
26
|
+
mutex = Mutex.new
|
27
|
+
|
28
|
+
# Take up to 3 players for parallel processing
|
29
|
+
current_batch = players_to_score.shift(3)
|
30
|
+
|
31
|
+
current_batch.each do |player|
|
32
|
+
threads << Thread.new(player) do |p|
|
33
|
+
score = generate_score(p)
|
34
|
+
|
35
|
+
mutex.synchronize do
|
36
|
+
p.score = score
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Wait for all threads in this batch to complete
|
42
|
+
threads.each(&:join)
|
43
|
+
end
|
23
44
|
end
|
24
45
|
end
|
25
|
-
end
|
26
46
|
|
27
|
-
|
47
|
+
private
|
28
48
|
|
29
|
-
|
30
|
-
|
31
|
-
|
49
|
+
def players_without_score
|
50
|
+
@players_without_score ||= @players.select { |player| player.score.nil? }
|
51
|
+
end
|
32
52
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
53
|
+
def generate_score(player)
|
54
|
+
score, reasoning = ActiveGenie::Scoring.call(
|
55
|
+
player.content,
|
56
|
+
@criteria,
|
57
|
+
@reviewers,
|
58
|
+
config: @config
|
59
|
+
).values_at('final_score', 'final_reasoning')
|
40
60
|
|
41
|
-
|
61
|
+
ActiveGenie::Logger.call({ code: :new_score, player_id: player.id, score:, reasoning: })
|
42
62
|
|
43
|
-
|
44
|
-
|
63
|
+
score
|
64
|
+
end
|
45
65
|
|
46
|
-
|
47
|
-
|
66
|
+
def generate_reviewers
|
67
|
+
return @reviewers if @reviewers.size.positive?
|
48
68
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
ActiveGenie::Logger.debug({ code: :new_reviewers, reviewers: [reviewer1, reviewer2, reviewer3] })
|
69
|
+
reviewer1, reviewer2, reviewer3 = ActiveGenie::Scoring::RecommendedReviewers.call(
|
70
|
+
[@players.sample.content, @players.sample.content].join("\n\n"),
|
71
|
+
@criteria,
|
72
|
+
config: @config
|
73
|
+
).values_at('reviewer1', 'reviewer2', 'reviewer3')
|
56
74
|
|
57
|
-
|
58
|
-
end
|
75
|
+
ActiveGenie::Logger.call({ code: :new_reviewers, reviewers: [reviewer1, reviewer2, reviewer3] })
|
59
76
|
|
60
|
-
|
61
|
-
|
62
|
-
end
|
77
|
+
[reviewer1, reviewer2, reviewer3]
|
78
|
+
end
|
63
79
|
|
64
|
-
|
65
|
-
|
66
|
-
|
80
|
+
def log_context
|
81
|
+
{ ranking_scoring_id: }
|
82
|
+
end
|
67
83
|
|
68
|
-
|
84
|
+
def ranking_scoring_id
|
85
|
+
player_ids = players_without_score.map(&:id).join(',')
|
86
|
+
ranking_unique_key = [player_ids, @criteria, @config.to_json].join('-')
|
87
|
+
|
88
|
+
"#{Digest::MD5.hexdigest(ranking_unique_key)}-scoring"
|
89
|
+
end
|
69
90
|
end
|
70
91
|
end
|
71
92
|
end
|
data/lib/active_genie/ranking.rb
CHANGED
@@ -17,7 +17,7 @@ text = "The code implements a binary search algorithm with O(log n) complexity"
|
|
17
17
|
criteria = "Evaluate technical accuracy and clarity"
|
18
18
|
reviewers = ["Algorithm Expert", "Technical Writer"]
|
19
19
|
|
20
|
-
result = ActiveGenie::Scoring
|
20
|
+
result = ActiveGenie::Scoring.call(text, criteria, reviewers)
|
21
21
|
# => {
|
22
22
|
# algorithm_expert_score: 95,
|
23
23
|
# algorithm_expert_reasoning: "Accurately describes binary search and its complexity",
|
@@ -35,7 +35,7 @@ When no reviewers are specified, the system automatically recommends appropriate
|
|
35
35
|
text = "The patient shows signs of improved cardiac function"
|
36
36
|
criteria = "Evaluate medical accuracy and clarity"
|
37
37
|
|
38
|
-
result = ActiveGenie::Scoring
|
38
|
+
result = ActiveGenie::Scoring.call(text, criteria)
|
39
39
|
# => {
|
40
40
|
# cardiologist_score: 88,
|
41
41
|
# cardiologist_reasoning: "Accurate assessment of cardiac improvement",
|
@@ -49,7 +49,7 @@ result = ActiveGenie::Scoring::Basic.call(text, criteria)
|
|
49
49
|
|
50
50
|
## Interface
|
51
51
|
|
52
|
-
###
|
52
|
+
### `.call(text, criteria, reviewers = [], config: {})`
|
53
53
|
Main interface for scoring text content.
|
54
54
|
|
55
55
|
#### Parameters
|
@@ -73,4 +73,4 @@ Recommends appropriate reviewers based on content and criteria.
|
|
73
73
|
- Supports custom weighting of reviewer scores
|
74
74
|
- Returns detailed reasoning for each score
|
75
75
|
|
76
|
-
Performance Impact: Using multiple reviewers or requesting detailed feedback may increase processing time.
|
76
|
+
Performance Impact: Using multiple reviewers or requesting detailed feedback may increase processing time.
|