active_genie 0.0.19 → 0.0.21
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 +60 -2
- data/VERSION +1 -1
- data/lib/active_genie/battle/basic.rb +1 -8
- data/lib/active_genie/configuration/providers/internal_company_api_config.rb +54 -0
- data/lib/active_genie/configuration/providers/openai_config.rb +3 -3
- data/lib/active_genie/ranking/README.md +31 -1
- data/lib/active_genie/ranking/elo_round.rb +3 -0
- data/lib/active_genie/ranking/free_for_all.rb +3 -0
- data/lib/active_genie/ranking/player.rb +17 -5
- data/lib/active_genie/ranking/players_collection.rb +5 -1
- data/lib/active_genie/ranking/ranking.rb +18 -2
- data/lib/active_genie/ranking/ranking_scoring.rb +26 -4
- data/lib/active_genie/scoring/recommended_reviewers.rb +2 -1
- data/lib/tasks/templates/active_genie.rb +1 -1
- metadata +18 -93
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9c9c17c2c02f617c53edd6177ff72e0e2da34a4faf6bbeb9f9698b3858e4b69
|
4
|
+
data.tar.gz: 777620b958c17c9a439fcf5b8bdb3195564005e5becd8c41955c1c255c1a6ad3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3bee8941701e3516f48106d96165d78ea279cea1c7e5623515aed3361b5a337e191c85a3e4774a9526e3412a4b11f4c4f5d766e7f5a0e827cc74d869bd1ca54
|
7
|
+
data.tar.gz: a489c2f042aee21501697dfac47d0a37bd1a8bf50d990472dda2f7f8567615c3efd4422500653ac798c425a65df7bc065afaa3337f08a16305d4ef8f0b254a05
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
[](https://badge.fury.io/rb/active_genie)
|
5
5
|
[](https://github.com/roriz/active_genie/actions/workflows/benchmark.yml)
|
6
6
|
|
7
|
-
ActiveGenie is a Ruby gem that provides valuable solutions powered by Generative AI (GenAI) models. Just like Lodash or ActiveStorage, ActiveGenie brings a set of Modules reach real value fast and
|
7
|
+
ActiveGenie is a Ruby gem that provides valuable solutions powered by Generative AI (GenAI) models. Just like Lodash or ActiveStorage, ActiveGenie brings a set of Modules to reach real value fast and reliably.
|
8
8
|
ActiveGenie is backed by a custom benchmarking system that ensures consistent quality and performance across different models and providers in every release.
|
9
9
|
|
10
10
|
## Installation
|
@@ -137,7 +137,7 @@ result = ActiveGenie::Battle.call(
|
|
137
137
|
# }
|
138
138
|
```
|
139
139
|
|
140
|
-
*Recommended model*: `
|
140
|
+
*Recommended model*: `claude-3-5-haiku`
|
141
141
|
|
142
142
|
Features:
|
143
143
|
- Multi-reviewer evaluation with automatic expert selection
|
@@ -216,6 +216,64 @@ See the [Benchmark README](benchmark/README.md) for detailed results, methodolog
|
|
216
216
|
|
217
217
|
> **Note:** Each module can append its own set of configuration, see the individual module documentation for details.
|
218
218
|
|
219
|
+
## How to create a new provider
|
220
|
+
|
221
|
+
ActiveGenie supports adding custom providers to integrate with different LLM services. To create a new provider:
|
222
|
+
|
223
|
+
1. Create a configuration class for your provider in `lib/active_genie/configuration/providers/`:
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
# Example: lib/active_genie/configuration/providers/internal_company_api_config.rb
|
227
|
+
module ActiveGenie
|
228
|
+
module Configuration::Providers
|
229
|
+
class InternalCompanyApiConfig < BaseConfig
|
230
|
+
NAME = :internal_company_api
|
231
|
+
|
232
|
+
# API key accessor with environment variable fallback
|
233
|
+
def api_key
|
234
|
+
@api_key || ENV['INTERNAL_COMPANY_API_KEY']
|
235
|
+
end
|
236
|
+
|
237
|
+
# Base API URL
|
238
|
+
def api_url
|
239
|
+
@api_url || 'https://api.internal-company.com/v1'
|
240
|
+
end
|
241
|
+
|
242
|
+
# Client instantiation
|
243
|
+
def client
|
244
|
+
@client ||= ::ActiveGenie::Clients::InternalCompanyApiClient.new(self)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Model tier definitions
|
248
|
+
def lower_tier_model
|
249
|
+
@lower_tier_model || 'internal-basic'
|
250
|
+
end
|
251
|
+
|
252
|
+
def middle_tier_model
|
253
|
+
@middle_tier_model || 'internal-standard'
|
254
|
+
end
|
255
|
+
|
256
|
+
def upper_tier_model
|
257
|
+
@upper_tier_model || 'internal-premium'
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
```
|
263
|
+
|
264
|
+
2. Register your provider in your configuration:
|
265
|
+
|
266
|
+
```ruby
|
267
|
+
# In config/initializers/active_genie.rb
|
268
|
+
ActiveGenie.configure do |config|
|
269
|
+
# Register your custom provider
|
270
|
+
config.providers.register(InternalCompanyApi::Configuration)
|
271
|
+
|
272
|
+
# Configure your provider
|
273
|
+
config.internal_company_api.api_key = ENV['INTERNAL_COMPANY_API_KEY']
|
274
|
+
end
|
275
|
+
```
|
276
|
+
|
219
277
|
## Contributing
|
220
278
|
|
221
279
|
1. Fork the repository
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.21
|
@@ -123,14 +123,7 @@ module ActiveGenie::Battle
|
|
123
123
|
enum: ['player_1', 'player_2']
|
124
124
|
},
|
125
125
|
},
|
126
|
-
required: [
|
127
|
-
'player_1_sell_himself',
|
128
|
-
'player_2_sell_himself',
|
129
|
-
'player_1_arguments',
|
130
|
-
'player_2_counter',
|
131
|
-
'impartial_judge_winner_reasoning',
|
132
|
-
'impartial_judge_winner'
|
133
|
-
]
|
126
|
+
required: %w[player_1_sell_himself player_2_sell_himself player_1_arguments player_2_counter impartial_judge_winner_reasoning impartial_judge_winner]
|
134
127
|
}
|
135
128
|
}
|
136
129
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative '../../clients/internal_company_api_client'
|
2
|
+
require_relative './base_config'
|
3
|
+
|
4
|
+
module ActiveGenie
|
5
|
+
module Configuration::Providers
|
6
|
+
# Configuration class for the Internal Company API client.
|
7
|
+
# Manages API keys, URLs, model selections, and client instantiation.
|
8
|
+
class InternalCompanyApiConfig < BaseConfig
|
9
|
+
NAME = :internal_company_api
|
10
|
+
|
11
|
+
# Retrieves the API key.
|
12
|
+
# Falls back to the INTERNAL_COMPANY_API_KEY environment variable if not set.
|
13
|
+
# @return [String, nil] The API key.
|
14
|
+
def api_key
|
15
|
+
@api_key || ENV['INTERNAL_COMPANY_API_KEY']
|
16
|
+
end
|
17
|
+
|
18
|
+
# Retrieves the base API URL for Internal Company API.
|
19
|
+
# Defaults to 'https://api.internal-company.com/v1'.
|
20
|
+
# @return [String] The API base URL.
|
21
|
+
def api_url
|
22
|
+
@api_url || 'https://api.internal-company.com/v1'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Lazily initializes and returns an instance of the InternalCompanyApiClient.
|
26
|
+
# Passes itself (the config object) to the client's constructor.
|
27
|
+
# @return [ActiveGenie::Clients::InternalCompanyApiClient] The client instance.
|
28
|
+
def client
|
29
|
+
@client ||= ::ActiveGenie::Clients::InternalCompanyApiClient.new(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Retrieves the model name designated for the lower tier (e.g., cost-effective, faster).
|
33
|
+
# Defaults to 'internal-basic'.
|
34
|
+
# @return [String] The lower tier model name.
|
35
|
+
def lower_tier_model
|
36
|
+
@lower_tier_model || 'internal-basic'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Retrieves the model name designated for the middle tier (e.g., balanced performance).
|
40
|
+
# Defaults to 'internal-standard'.
|
41
|
+
# @return [String] The middle tier model name.
|
42
|
+
def middle_tier_model
|
43
|
+
@middle_tier_model || 'internal-standard'
|
44
|
+
end
|
45
|
+
|
46
|
+
# Retrieves the model name designated for the upper tier (e.g., most capable).
|
47
|
+
# Defaults to 'internal-premium'.
|
48
|
+
# @return [String] The upper tier model name.
|
49
|
+
def upper_tier_model
|
50
|
+
@upper_tier_model || 'internal-premium'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -33,21 +33,21 @@ module ActiveGenie
|
|
33
33
|
# Defaults to 'gpt-4o-mini'.
|
34
34
|
# @return [String] The lower tier model name.
|
35
35
|
def lower_tier_model
|
36
|
-
@lower_tier_model || 'gpt-
|
36
|
+
@lower_tier_model || 'gpt-4.1-mini'
|
37
37
|
end
|
38
38
|
|
39
39
|
# Retrieves the model name designated for the middle tier (e.g., balanced performance).
|
40
40
|
# Defaults to 'gpt-4o'.
|
41
41
|
# @return [String] The middle tier model name.
|
42
42
|
def middle_tier_model
|
43
|
-
@middle_tier_model || 'gpt-
|
43
|
+
@middle_tier_model || 'gpt-4.1'
|
44
44
|
end
|
45
45
|
|
46
46
|
# Retrieves the model name designated for the upper tier (e.g., most capable).
|
47
47
|
# Defaults to 'o1-preview'.
|
48
48
|
# @return [String] The upper tier model name.
|
49
49
|
def upper_tier_model
|
50
|
-
@upper_tier_model || '
|
50
|
+
@upper_tier_model || 'o3-mini'
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -40,4 +40,34 @@ The method processes the players through scoring, elimination, and ranking phase
|
|
40
40
|
- Adjust initial criteria to ensure consistency
|
41
41
|
- Adjust each player's content to ensure consistency
|
42
42
|
- Support players with images or audio
|
43
|
-
- Parallelize processing battles and scoring
|
43
|
+
- Parallelize processing battles and scoring
|
44
|
+
|
45
|
+
## Ranking Configuration
|
46
|
+
|
47
|
+
| Config | Description | Default |
|
48
|
+
|--------|-------------|---------|
|
49
|
+
| `score_variation_threshold` | Threshold for eliminating players with inconsistent scores | `30` |
|
50
|
+
|
51
|
+
## Ranking Callbacks
|
52
|
+
Callbacks are optional and can be used to watch any changes in players, battles, or scoring.
|
53
|
+
|
54
|
+
| Callback | Description |
|
55
|
+
|--------|-------------|
|
56
|
+
| `watch_players` | Callback to watch any changes in players |
|
57
|
+
| `watch_battles` | Callback to watch any changes in battles |
|
58
|
+
| `watch_scoring` | Callback to watch any changes in scoring |
|
59
|
+
|
60
|
+
Example of callback usage:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
result = ActiveGenie::Ranking.call(
|
64
|
+
players,
|
65
|
+
criteria,
|
66
|
+
config: {
|
67
|
+
watch_players: ->(player) { puts player },
|
68
|
+
watch_battles: ->(battle) { puts battle },
|
69
|
+
watch_scoring: ->(scoring) { puts scoring }
|
70
|
+
}
|
71
|
+
)
|
72
|
+
```
|
73
|
+
|
@@ -76,6 +76,9 @@ module ActiveGenie::Ranking
|
|
76
76
|
when 'draw' then [nil, nil]
|
77
77
|
end
|
78
78
|
|
79
|
+
@config[:runtime][:watch_battle].call({ id: "#{player_1.id}_#{player_2.id}_#{elo_round_id}", player_1:, player_2:, winner:, loser:, reasoning: result['reasoning'] }) if @config[:runtime][:watch_battle]
|
80
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
81
|
+
|
79
82
|
[winner, loser]
|
80
83
|
end
|
81
84
|
end
|
@@ -26,6 +26,8 @@ module ActiveGenie::Ranking
|
|
26
26
|
winner.win!
|
27
27
|
loser.lose!
|
28
28
|
end
|
29
|
+
|
30
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
@@ -56,6 +58,7 @@ module ActiveGenie::Ranking
|
|
56
58
|
when 'draw' then [nil, nil, result['reasoning']]
|
57
59
|
end
|
58
60
|
|
61
|
+
@config[:runtime][:watch_battle].call({ id: "#{player_1.id}_#{player_2.id}_#{free_for_all_id}", player_1:, player_2:, winner:, loser:, reasoning: result['reasoning'] }) if @config[:runtime][:watch_battle]
|
59
62
|
ActiveGenie::Logger.debug({
|
60
63
|
code: :free_for_all_battle,
|
61
64
|
player_ids: [player_1.id, player_2.id],
|
@@ -6,6 +6,7 @@ module ActiveGenie::Ranking
|
|
6
6
|
params = { content: params } if params.is_a?(String)
|
7
7
|
|
8
8
|
@content = params.dig(:content) || params
|
9
|
+
@name = params.dig(:name) || params.dig(:content)[0..10]
|
9
10
|
@id = params.dig(:id) || Digest::MD5.hexdigest(@content)
|
10
11
|
@score = params.dig(:score) || nil
|
11
12
|
@elo = params.dig(:elo) || nil
|
@@ -15,9 +16,8 @@ module ActiveGenie::Ranking
|
|
15
16
|
@eliminated = params.dig(:eliminated) || nil
|
16
17
|
end
|
17
18
|
|
18
|
-
attr_reader :id, :content, :score, :elo,
|
19
|
-
:
|
20
|
-
:eliminated
|
19
|
+
attr_reader :id, :content, :score, :elo, :ffa_win_count,
|
20
|
+
:ffa_lose_count, :ffa_draw_count, :eliminated
|
21
21
|
attr_accessor :rank
|
22
22
|
|
23
23
|
def score=(value)
|
@@ -51,15 +51,27 @@ module ActiveGenie::Ranking
|
|
51
51
|
ActiveGenie::Logger.debug({ code: :new_ffa_score, player_id: id, result: 'lose', ffa_score: })
|
52
52
|
end
|
53
53
|
|
54
|
+
def name
|
55
|
+
@name
|
56
|
+
end
|
57
|
+
|
54
58
|
def ffa_score
|
55
59
|
@ffa_win_count * 3 + @ffa_draw_count
|
56
60
|
end
|
57
61
|
|
62
|
+
def sort_value
|
63
|
+
(ffa_score * 1000000) + ((elo || 0) * 100) + (score || 0)
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_json
|
67
|
+
to_h.to_json
|
68
|
+
end
|
69
|
+
|
58
70
|
def to_h
|
59
71
|
{
|
60
|
-
id:, content:, score:, elo:,
|
72
|
+
id:, name:, content:, score:, elo:,
|
61
73
|
ffa_win_count:, ffa_lose_count:, ffa_draw_count:,
|
62
|
-
eliminated:, ffa_score:
|
74
|
+
eliminated:, ffa_score:, sort_value:
|
63
75
|
}
|
64
76
|
end
|
65
77
|
|
@@ -41,10 +41,14 @@ module ActiveGenie::Ranking
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def sorted
|
44
|
-
sorted_players = @players.sort_by { |p|
|
44
|
+
sorted_players = @players.sort_by { |p| -p.sort_value }
|
45
45
|
sorted_players.each_with_index { |p, i| p.rank = i + 1 }
|
46
46
|
sorted_players
|
47
47
|
end
|
48
|
+
|
49
|
+
def to_json
|
50
|
+
to_h.to_json
|
51
|
+
end
|
48
52
|
|
49
53
|
def to_h
|
50
54
|
sorted.map { |p| p.to_h }
|
@@ -67,7 +67,7 @@ module ActiveGenie::Ranking
|
|
67
67
|
|
68
68
|
private
|
69
69
|
|
70
|
-
|
70
|
+
DEFAULT_SCORE_VARIATION_THRESHOLD = 30
|
71
71
|
ELIMINATION_VARIATION = 'variation_too_high'
|
72
72
|
ELIMINATION_RELEGATION = 'relegation_tier'
|
73
73
|
|
@@ -80,27 +80,36 @@ module ActiveGenie::Ranking
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def set_initial_player_scores!
|
83
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
83
84
|
RankingScoring.call(@players, @criteria, reviewers: @reviewers, config: @config)
|
85
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
84
86
|
end
|
85
87
|
|
86
88
|
def eliminate_obvious_bad_players!
|
87
|
-
|
89
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
90
|
+
while @players.coefficient_of_variation >= score_variation_threshold
|
88
91
|
@players.eligible.last.eliminated = ELIMINATION_VARIATION
|
89
92
|
end
|
93
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
90
94
|
end
|
91
95
|
|
92
96
|
def run_elo_round!
|
97
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
93
98
|
@elo_rounds_played += 1
|
94
99
|
|
95
100
|
elo_report = EloRound.call(@players, @criteria, config: @config)
|
96
101
|
|
97
102
|
@elo_round_battle_count += elo_report[:battles_count]
|
98
103
|
|
104
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
99
105
|
elo_report
|
100
106
|
end
|
101
107
|
|
102
108
|
def eliminate_relegation_players!
|
109
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
103
110
|
@players.calc_relegation_tier.each { |player| player.eliminated = ELIMINATION_RELEGATION }
|
111
|
+
|
112
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
104
113
|
end
|
105
114
|
|
106
115
|
def rebalance_players!(elo_report)
|
@@ -111,12 +120,19 @@ module ActiveGenie::Ranking
|
|
111
120
|
|
112
121
|
player.elo += elo_report[:highest_elo_diff]
|
113
122
|
end
|
123
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
114
124
|
end
|
115
125
|
|
116
126
|
def run_free_for_all!
|
127
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
117
128
|
ffa_report = FreeForAll.call(@players, @criteria, config: @config)
|
118
129
|
|
119
130
|
@free_for_all_battle_count += ffa_report[:battles_count]
|
131
|
+
@config[:runtime][:watch_players].call(@players) if @config[:runtime][:watch_players]
|
132
|
+
end
|
133
|
+
|
134
|
+
def score_variation_threshold
|
135
|
+
@config[:runtime][:score_variation_threshold] || DEFAULT_SCORE_VARIATION_THRESHOLD
|
120
136
|
end
|
121
137
|
|
122
138
|
def report
|
@@ -16,10 +16,27 @@ module ActiveGenie::Ranking
|
|
16
16
|
def call
|
17
17
|
ActiveGenie::Logger.with_context(log_context) do
|
18
18
|
@reviewers = generate_reviewers
|
19
|
+
|
20
|
+
players_to_score = players_without_score
|
21
|
+
until players_to_score.empty?
|
22
|
+
threads = []
|
23
|
+
mutex = Mutex.new
|
24
|
+
|
25
|
+
# Take up to 3 players for parallel processing
|
26
|
+
current_batch = players_to_score.shift(3)
|
19
27
|
|
20
|
-
|
21
|
-
|
22
|
-
|
28
|
+
current_batch.each do |player|
|
29
|
+
threads << Thread.new(player) do |p|
|
30
|
+
score = generate_score(p)
|
31
|
+
|
32
|
+
mutex.synchronize do
|
33
|
+
p.score = score
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Wait for all threads in this batch to complete
|
39
|
+
threads.each(&:join)
|
23
40
|
end
|
24
41
|
end
|
25
42
|
end
|
@@ -39,6 +56,11 @@ module ActiveGenie::Ranking
|
|
39
56
|
).values_at('final_score', 'final_reasoning')
|
40
57
|
|
41
58
|
ActiveGenie::Logger.debug({ code: :new_score, player_id: player.id, score:, reasoning: })
|
59
|
+
@config[:runtime][:watch_scoring].call({
|
60
|
+
player_id: player.id,
|
61
|
+
player_name: player.content[0..10],
|
62
|
+
score: player.score
|
63
|
+
}) if @config[:runtime][:watch_scoring]
|
42
64
|
|
43
65
|
score
|
44
66
|
end
|
@@ -65,7 +87,7 @@ module ActiveGenie::Ranking
|
|
65
87
|
player_ids = players_without_score.map(&:id).join(',')
|
66
88
|
ranking_unique_key = [player_ids, @criteria, @config.to_json].join('-')
|
67
89
|
|
68
|
-
Digest::MD5.hexdigest(ranking_unique_key)
|
90
|
+
Digest::MD5.hexdigest(ranking_unique_key) + '-scoring'
|
69
91
|
end
|
70
92
|
end
|
71
93
|
end
|
@@ -10,7 +10,7 @@ ActiveGenie.configure do |config|
|
|
10
10
|
# config.providers.openai.client = ActiveGenie::Providers::Openai::Client.new(config)
|
11
11
|
|
12
12
|
# example how add a new provider
|
13
|
-
# config.providers.register(
|
13
|
+
# config.providers.register(InternalCompanyApi::Configuration)
|
14
14
|
|
15
15
|
# Logs configuration
|
16
16
|
# config.log_level = :debug # default is :info
|
metadata
CHANGED
@@ -1,103 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_genie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Radamés Roriz
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies: []
|
13
12
|
description: "# ActiveGenie \U0001F9DE♂️\n> The lodash for GenAI, stop reinventing
|
14
|
-
the wheel\n\
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
\ minimum: 0\n },\n size: {\n type: 'number',\n minimum: 35,\n maximum:
|
29
|
-
46\n }\n}\n\nresult = ActiveGenie::DataExtractor.call(\n text,\n schema,\n config:
|
30
|
-
{ provider: :openai, model: 'gpt-4o-mini' } # optional\n)\n# => { \n# brand:
|
31
|
-
\"Nike\", \n# brand_explanation: \"Brand name found at start of text\",\n#
|
32
|
-
\ price: 199.99,\n# price_explanation: \"Price found in USD format at end\",\n#
|
33
|
-
\ size: 42,\n# size_explanation: \"Size explicitly stated in the middle\"\n#
|
34
|
-
\ }\n```\n\n*Recommended model*: `gpt-4o-mini`\n\nFeatures:\n- Structured data
|
35
|
-
extraction with type validation\n- Schema-based extraction with custom constraints\n-
|
36
|
-
Informal text analysis (litotes, hedging)\n- Detailed explanations for extracted
|
37
|
-
values\n\nSee the [Data Extractor README](lib/active_genie/data_extractor/README.md)
|
38
|
-
for informal text processing, advanced schemas, and detailed interface documentation.\n\n###
|
39
|
-
Scoring\nText evaluation system that provides detailed scoring and feedback using
|
40
|
-
multiple expert reviewers. Get balanced scoring through AI-powered expert reviewers
|
41
|
-
that automatically adapt to your content.\n\n```ruby\ntext = \"The code implements
|
42
|
-
a binary search algorithm with O(log n) complexity\"\ncriteria = \"Evaluate technical
|
43
|
-
accuracy and clarity\"\n\nresult = ActiveGenie::Scoring.basic(\n text,\n criteria,\n
|
44
|
-
\ config: { provider: :anthropic, model: 'claude-3-5-haiku-20241022' } # optional\n)\n#
|
45
|
-
=> {\n# algorithm_expert_score: 95,\n# algorithm_expert_reasoning: \"Accurately
|
46
|
-
describes binary search and its complexity\",\n# technical_writer_score: 90,\n#
|
47
|
-
\ technical_writer_reasoning: \"Clear and concise explanation of the algorithm\",\n#
|
48
|
-
\ final_score: 92.5\n# }\n```\n\n*Recommended model*: `claude-3-5-haiku-20241022`\n\nFeatures:\n-
|
49
|
-
Multi-reviewer evaluation with automatic expert selection\n- Detailed feedback with
|
50
|
-
scoring reasoning\n- Customizable reviewer weights\n- Flexible evaluation criteria\n\nSee
|
51
|
-
the [Scoring README](lib/active_genie/scoring/README.md) for advanced usage, custom
|
52
|
-
reviewers, and detailed interface documentation.\n\n### Battle\nAI-powered battle
|
53
|
-
evaluation system that determines winners between two players based on specified
|
54
|
-
criteria.\n\n```ruby\nrequire 'active_genie'\n\nplayer_1 = \"Implementation uses
|
55
|
-
dependency injection for better testability\"\nplayer_2 = \"Code has high test coverage
|
56
|
-
but tightly coupled components\"\ncriteria = \"Evaluate code quality and maintainability\"\n\nresult
|
57
|
-
= ActiveGenie::Battle.call(\n player_1,\n player_2,\n criteria,\n config: {
|
58
|
-
provider: :google, model: 'gemini-2.0-flash-lite' } # optional\n)\n# => {\n# winner_player:
|
59
|
-
\"Implementation uses dependency injection for better testability\",\n# reasoning:
|
60
|
-
\"Player 1 implementation demonstrates better maintainability through dependency
|
61
|
-
injection, \n# which allows for easier testing and component replacement.
|
62
|
-
While Player 2 has good test coverage, \n# the tight coupling makes
|
63
|
-
the code harder to maintain and modify.\",\n# what_could_be_changed_to_avoid_draw:
|
64
|
-
\"Focus on specific architectural patterns and design principles\"\n# }\n```\n\n*Recommended
|
65
|
-
model*: `gemini-2.0-flash-lite`\n\nFeatures:\n- Multi-reviewer evaluation with automatic
|
66
|
-
expert selection\n- Detailed feedback with scoring reasoning\n- Customizable reviewer
|
67
|
-
weights\n- Flexible evaluation criteria\n\nSee the [Battle README](lib/active_genie/battle/README.md)
|
68
|
-
for advanced usage, custom reviewers, and detailed interface documentation.\n\n###
|
69
|
-
Ranking\nThe Ranking module provides competitive ranking through multi-stage evaluation:\n\n```ruby\nrequire
|
70
|
-
'active_genie'\n\nplayers = ['REST API', 'GraphQL API', 'SOAP API', 'gRPC API',
|
71
|
-
'Websocket API']\ncriteria = \"Best one to be used into a high changing environment\"\n\nresult
|
72
|
-
= ActiveGenie::Ranking.call(\n players,\n criteria,\n config: { provider: :google,
|
73
|
-
model: 'gemini-2.0-flash-lite' } # optional\n)\n# => {\n# winner_player: \"gRPC
|
74
|
-
API\",\n# reasoning: \"gRPC API is the best one to be used into a high changing
|
75
|
-
environment\",\n# }\n```\n\n*Recommended model*: `gemini-2.0-flash-lite`\n\n-
|
76
|
-
**Multi-phase ranking system** combining expert scoring and ELO algorithms\n- **Automatic
|
77
|
-
elimination** of inconsistent performers using statistical analysis\n- **Dynamic
|
78
|
-
ranking adjustments** based on simulated pairwise battles, from bottom to top\n\nSee
|
79
|
-
the [Ranking README](lib/active_genie/ranking/README.md) for implementation details,
|
80
|
-
configuration, and advanced ranking strategies.\n\n### Text Summarizer (Future)\n###
|
81
|
-
Categorizer (Future)\n### Language detector (Future)\n### Translator (Future)\n###
|
82
|
-
Sentiment analyzer (Future)\n\n## Benchmarking \U0001F9EA\n\nActiveGenie includes
|
83
|
-
a comprehensive benchmarking system to ensure consistent, high-quality outputs across
|
84
|
-
different LLM models and providers.\n\n```ruby\n# Run all benchmarks\nbundle exec
|
85
|
-
rake active_genie:benchmark\n\n# Run benchmarks for a specific module\nbundle exec
|
86
|
-
rake active_genie:benchmark[data_extractor]\n```\n\n### Latest Results\n\n| Model
|
87
|
-
| Overall Precision |\n|-------|-------------------|\n| claude-3-5-haiku-20241022
|
88
|
-
| 92.25% |\n| gemini-2.0-flash-lite | 84.25% |\n| gpt-4o-mini | 62.75% |\n| deepseek-chat
|
89
|
-
| 57.25% |\n\nSee the [Benchmark README](benchmark/README.md) for detailed results,
|
90
|
-
methodology, and how to contribute to our test suite.\n\n## Configuration\n\n| Config
|
91
|
-
| Description | Default |\n|--------|-------------|---------|\n| `provider` | LLM
|
92
|
-
provider (openai, anthropic, etc) | `nil` |\n| `model` | Model to use | `nil` |\n|
|
93
|
-
`api_key` | Provider API key | `nil` |\n| `timeout` | Request timeout in seconds
|
94
|
-
| `5` |\n| `max_retries` | Maximum retry attempts | `3` |\n\n> **Note:** Each module
|
95
|
-
can append its own set of configuration, see the individual module documentation
|
96
|
-
for details.\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature
|
97
|
-
branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git
|
98
|
-
commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5.
|
99
|
-
Open a Pull Request\n\n## License\n\nThis project is licensed under the Apache License
|
100
|
-
2.0 License - see the [LICENSE](LICENSE) file for details.\n"
|
13
|
+
the wheel\n\nActiveGenie is a Ruby gem that provides valuable solutions powered
|
14
|
+
by Generative AI (GenAI) models. Just like Lodash or ActiveStorage, ActiveGenie
|
15
|
+
brings a set of Modules to reach real value fast and reliably.\nActiveGenie is backed
|
16
|
+
by a custom benchmarking system that ensures consistent quality and performance
|
17
|
+
across different models and providers in every release.\n\n## Features\n\n* **Data
|
18
|
+
Extractor:** Extract structured data from text using AI-powered analysis\n* **Scoring:**
|
19
|
+
Text evaluation system with detailed scoring and feedback\n* **Battle:** AI-powered
|
20
|
+
battle evaluation system between two players\n* **Ranking:** Multi-phase ranking
|
21
|
+
system for multiple options\n\n### Performance Breakdown\n\n| ActiveGenie Module
|
22
|
+
| Best Precision | Worst Precision | Recommended Model |\n|--------------------|-------------------|-------------------|-------------------|\n|
|
23
|
+
data_extractor | 100% | 86% | `gpt-4o-mini` |\n| battle | 100% | 10% | `gemini-2.0-flash-lite`
|
24
|
+
|\n| scoring | 69% | 61% | `claude-3-5-haiku-20241022` |\n| ranking | 100% | 0%
|
25
|
+
| `gemini-2.0-flash-lite` |\n\nSee the [GitHub repository](https://github.com/Roriz/active_genie)
|
26
|
+
for complete documentation and examples.\n"
|
101
27
|
email:
|
102
28
|
- radames@roriz.dev
|
103
29
|
executables: []
|
@@ -124,6 +50,7 @@ files:
|
|
124
50
|
- lib/active_genie/configuration/providers/base_config.rb
|
125
51
|
- lib/active_genie/configuration/providers/deepseek_config.rb
|
126
52
|
- lib/active_genie/configuration/providers/google_config.rb
|
53
|
+
- lib/active_genie/configuration/providers/internal_company_api_config.rb
|
127
54
|
- lib/active_genie/configuration/providers/openai_config.rb
|
128
55
|
- lib/active_genie/configuration/providers_config.rb
|
129
56
|
- lib/active_genie/configuration/runtime_config.rb
|
@@ -156,7 +83,6 @@ metadata:
|
|
156
83
|
changelog_uri: https://github.com/Roriz/active_genie/blob/master/CHANGELOG.md
|
157
84
|
bug_tracker_uri: https://github.com/Roriz/active_genie/issues
|
158
85
|
rubygems_mfa_required: 'true'
|
159
|
-
post_install_message:
|
160
86
|
rdoc_options: []
|
161
87
|
require_paths:
|
162
88
|
- lib
|
@@ -171,8 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
97
|
- !ruby/object:Gem::Version
|
172
98
|
version: '0'
|
173
99
|
requirements: []
|
174
|
-
rubygems_version: 3.
|
175
|
-
signing_key:
|
100
|
+
rubygems_version: 3.6.7
|
176
101
|
specification_version: 4
|
177
102
|
summary: Transform your Ruby application with powerful, production-ready GenAI features
|
178
103
|
test_files: []
|