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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12c5c526a10f93e649ca39c4789a21065c0f2d329bd57248260b1fd997507296
4
- data.tar.gz: 6fc9074a5282f1b9759c41dd98aaa31a179bc495964839e8bfc42e891b15e7d2
3
+ metadata.gz: a9c9c17c2c02f617c53edd6177ff72e0e2da34a4faf6bbeb9f9698b3858e4b69
4
+ data.tar.gz: 777620b958c17c9a439fcf5b8bdb3195564005e5becd8c41955c1c255c1a6ad3
5
5
  SHA512:
6
- metadata.gz: 76672044e7a1a88779100b9b0f32d75547ac1105031f5ca40d6bbce71a34edecadb63e0dda99c6ca23ee03647bf5dd09a3b3bc98a38faad3a07fdbc245f87dc4
7
- data.tar.gz: 2ac5ed0ae70edbf7a736e7b7bc3408a16c76628c7efecb277291641bb8b04e8ea633a36c16dc0e86851bbf3c40d82c3f4456af0e7e3ea1beea057bb60660ad6a
6
+ metadata.gz: c3bee8941701e3516f48106d96165d78ea279cea1c7e5623515aed3361b5a337e191c85a3e4774a9526e3412a4b11f4c4f5d766e7f5a0e827cc74d869bd1ca54
7
+ data.tar.gz: a489c2f042aee21501697dfac47d0a37bd1a8bf50d990472dda2f7f8567615c3efd4422500653ac798c425a65df7bc065afaa3337f08a16305d4ef8f0b254a05
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Gem Version](https://badge.fury.io/rb/active_genie.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/active_genie)
5
5
  [![Ruby](https://github.com/roriz/active_genie/actions/workflows/benchmark.yml/badge.svg)](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 reliable.
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*: `gemini-2.0-flash-lite`
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.19
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-4o-mini'
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-4o'
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 || 'o1-preview'
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
- :ffa_win_count, :ffa_lose_count, :ffa_draw_count,
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| [-p.ffa_score, -(p.elo || 0), -(p.score || 0)] }
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
- SCORE_VARIATION_THRESHOLD = 15
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
- while @players.coefficient_of_variation >= SCORE_VARIATION_THRESHOLD
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
- players_without_score.each do |player|
21
- # TODO: This can take a while, can be parallelized
22
- player.score = generate_score(player)
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
@@ -49,7 +49,8 @@ module ActiveGenie::Scoring
49
49
  reviewer1: { type: 'string' },
50
50
  reviewer2: { type: 'string' },
51
51
  reviewer3: { type: 'string' },
52
- }
52
+ },
53
+ required: ['reasoning', 'reviewer1', 'reviewer2', 'reviewer3']
53
54
  }
54
55
  }
55
56
 
@@ -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(:internal_company_api, InternalCompanyApi::Configuration)
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.19
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: 2025-04-04 00:00:00.000000000 Z
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\n[![Gem Version](https://badge.fury.io/rb/active_genie.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/active_genie)\n[![Ruby](https://github.com/roriz/active_genie/actions/workflows/benchmark.yml/badge.svg)](https://github.com/roriz/active_genie/actions/workflows/benchmark.yml)\n\nActiveGenie
15
- is a Ruby gem that provides valuable solutions powered by Generative AI (GenAI)
16
- models. Just like Lodash or ActiveStorage, ActiveGenie brings a set of Modules reach
17
- real value fast and reliable.\nActiveGenie is backed by a custom benchmarking system
18
- that ensures consistent quality and performance across different models and providers
19
- in every release.\n\n## Installation\n\n1. Add to your Gemfile:\n```ruby\ngem 'active_genie'\n```\n\n2.
20
- Install the gem:\n```shell\nbundle install\n```\n\n3. Generate the configuration:\n```shell\necho
21
- \"ActiveGenie.load_tasks\" >> Rakefile\nrails g active_genie:install\n```\n\n4.
22
- Configure your credentials in `config/initializers/active_genie.rb`:\n```ruby\nActiveGenie.configure
23
- do |config|\n config.openai.api_key = ENV['OPENAI_API_KEY']\nend\n```\n\n## Quick
24
- Start\n\n### Data Extractor\n\nExtract structured data from text using AI-powered
25
- analysis, handling informal language and complex expressions.\n\n```ruby\ntext =
26
- \"Nike Air Max 90 - Size 42 - $199.99\"\nschema = {\n brand: { \n type: 'string',\n
27
- \ enum: [\"Nike\", \"Adidas\", \"Puma\"]\n },\n price: { \n type: 'number',\n
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.5.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: []