active_genie 0.29.0 → 0.30.0
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 +2 -2
- data/VERSION +1 -1
- data/lib/active_genie/{battle/generalist.json → comparator/debate.json} +2 -2
- data/lib/active_genie/{battle/generalist.prompt.md → comparator/debate.prompt.md} +1 -1
- data/lib/active_genie/{battle/generalist.rb → comparator/debate.rb} +20 -21
- data/lib/active_genie/{battle → comparator}/fight.rb +7 -7
- data/lib/active_genie/comparator.rb +24 -0
- data/lib/active_genie/{config/scoring_config.rb → configs/comparator_config.rb} +1 -1
- data/lib/active_genie/{config/data_extractor_config.rb → configs/extractor_config.rb} +1 -1
- data/lib/active_genie/{config/factory_config.rb → configs/lister_config.rb} +1 -1
- data/lib/active_genie/{config → configs}/llm_config.rb +6 -6
- data/lib/active_genie/{config/ranking_config.rb → configs/ranker_config.rb} +1 -1
- data/lib/active_genie/{config/battle_config.rb → configs/scorer_config.rb} +1 -1
- data/lib/active_genie/configuration.rb +19 -19
- data/lib/active_genie/errors/invalid_provider_error.rb +1 -1
- data/lib/active_genie/{data_extractor/generalist.rb → extractor/explanation.rb} +11 -11
- data/lib/active_genie/{data_extractor/from_informal.rb → extractor/litote.rb} +7 -7
- data/lib/active_genie/extractor.rb +22 -0
- data/lib/active_genie/{factory → lister}/feud.rb +6 -6
- data/lib/active_genie/lister/juries.prompt.md +20 -0
- data/lib/active_genie/lister/juries.rb +82 -0
- data/lib/active_genie/{factory.rb → lister.rb} +7 -6
- data/lib/active_genie/{clients/providers/anthropic_client.rb → providers/anthropic_provider.rb} +4 -4
- data/lib/active_genie/{clients/providers/base_client.rb → providers/base_provider.rb} +6 -6
- data/lib/active_genie/{clients/providers/deepseek_client.rb → providers/deepseek_provider.rb} +3 -3
- data/lib/active_genie/{clients/providers/google_client.rb → providers/google_provider.rb} +6 -6
- data/lib/active_genie/{clients/providers/openai_client.rb → providers/openai_provider.rb} +3 -3
- data/lib/active_genie/providers/unified_provider.rb +44 -0
- data/lib/active_genie/{ranking/elo_round.rb → ranker/elo.rb} +35 -35
- data/lib/active_genie/ranker/entities/player.rb +124 -0
- data/lib/active_genie/ranker/entities/players.rb +102 -0
- data/lib/active_genie/{ranking → ranker}/free_for_all.rb +8 -8
- data/lib/active_genie/ranker/scoring.rb +66 -0
- data/lib/active_genie/{ranking/ranking.rb → ranker/tournament.rb} +17 -25
- data/lib/active_genie/ranker.rb +32 -0
- data/lib/active_genie/scorer/jury_bench.rb +121 -0
- data/lib/active_genie/scorer.rb +17 -0
- data/lib/active_genie.rb +9 -9
- data/lib/tasks/test.rake +15 -0
- metadata +51 -50
- data/lib/active_genie/battle.rb +0 -31
- data/lib/active_genie/clients/unified_client.rb +0 -50
- data/lib/active_genie/data_extractor.rb +0 -23
- data/lib/active_genie/ranking/player.rb +0 -122
- data/lib/active_genie/ranking/players_collection.rb +0 -95
- data/lib/active_genie/ranking/ranking_scoring.rb +0 -69
- data/lib/active_genie/ranking.rb +0 -14
- data/lib/active_genie/scoring/generalist.json +0 -9
- data/lib/active_genie/scoring/generalist.rb +0 -119
- data/lib/active_genie/scoring/recommended_reviewers.rb +0 -87
- data/lib/active_genie/scoring.rb +0 -23
- /data/lib/active_genie/{battle → comparator}/fight.json +0 -0
- /data/lib/active_genie/{battle → comparator}/fight.prompt.md +0 -0
- /data/lib/active_genie/{config → configs}/log_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/anthropic_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/deepseek_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/google_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/openai_config.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers/provider_base.rb +0 -0
- /data/lib/active_genie/{config → configs}/providers_config.rb +0 -0
- /data/lib/active_genie/{data_extractor/generalist.json → extractor/explanation.json} +0 -0
- /data/lib/active_genie/{data_extractor/generalist.prompt.md → extractor/explanation.prompt.md} +0 -0
- /data/lib/active_genie/{data_extractor/from_informal.json → extractor/litote.json} +0 -0
- /data/lib/active_genie/{factory → lister}/feud.json +0 -0
- /data/lib/active_genie/{factory → lister}/feud.prompt.md +0 -0
- /data/lib/active_genie/{scoring/generalist.prompt.md → scorer/jury_bench.md} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3798199139490fc67b7bd1e154c74ff7c53411bd035cd9e2fd1d9b46e676a90
|
4
|
+
data.tar.gz: 5d9be13a369c0a6116257822f75365241ea7f628e0bdc11af085ecb267cef806
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1929da5851c827ef6b693aa4f66b6118a2cda72c1b7996e602e0b0abd0537d3ac8de4fcd58d55c34fcb30ac798b237e0dea2f42e1f2431f6b61594e74807a2fd
|
7
|
+
data.tar.gz: 4d8a653613a1782f8542a531abf23d0171e5e30d36d42bee1d756963d645113b9ee151206ae81ba34a053b408df945d4f98e1ef35e23fc2fc47023776961dee8
|
data/README.md
CHANGED
@@ -25,7 +25,7 @@ bundle install
|
|
25
25
|
3. Generate the configuration:
|
26
26
|
```shell
|
27
27
|
echo "ActiveGenie.load_tasks" >> Rakefile
|
28
|
-
rails
|
28
|
+
rails active_genie:install
|
29
29
|
```
|
30
30
|
|
31
31
|
4. Configure your credentials in `config/initializers/active_genie.rb`:
|
@@ -60,7 +60,7 @@ schema = {
|
|
60
60
|
result = ActiveGenie::DataExtractor.call(
|
61
61
|
text,
|
62
62
|
schema,
|
63
|
-
config: {
|
63
|
+
config: { provider_name: :openai, model: 'gpt-4.1-mini' } # optional
|
64
64
|
)
|
65
65
|
# => {
|
66
66
|
# brand: "Nike",
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.30.0
|
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
|
-
"name": "
|
3
|
-
"description": "Evaluate a
|
2
|
+
"name": "comparation_through_debate",
|
3
|
+
"description": "Evaluate a debate between player_a and player_b using predefined criteria and identify the winner.",
|
4
4
|
"parameters": {
|
5
5
|
"type": "object",
|
6
6
|
"properties": {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
Based on two players, player_a and player_b, they will
|
1
|
+
Based on two players, player_a and player_b, they will debate against each other based on criteria. Criteria are vital as they provide a clear metric to compare the players. Follow these criteria strictly.
|
2
2
|
|
3
3
|
# Steps
|
4
4
|
1. player_a presents their strengths and how they meet the criteria. Max of 100 words.
|
@@ -1,22 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../
|
3
|
+
require_relative '../providers/unified_provider'
|
4
4
|
|
5
5
|
module ActiveGenie
|
6
|
-
module
|
7
|
-
# The
|
6
|
+
module Comparator
|
7
|
+
# The Debate class provides a foundation for evaluating comparators between two players
|
8
8
|
# using AI-powered evaluation. It determines a winner based on specified criteria,
|
9
9
|
# analyzing how well each player meets the requirements.
|
10
10
|
#
|
11
|
-
# The
|
11
|
+
# The comparator evaluation process compares two players' content against given criteria
|
12
12
|
# and returns detailed feedback including the winner and reasoning for the decision.
|
13
13
|
#
|
14
|
-
# @example
|
15
|
-
#
|
14
|
+
# @example Debate usage with two players and criteria
|
15
|
+
# Debate.call("Player A content", "Player B content", "Evaluate keyword usage and pattern matching")
|
16
16
|
#
|
17
|
-
class
|
18
|
-
BattleResponse = Struct.new(:winner, :loser, :reasoning, :raw, keyword_init: true)
|
19
|
-
|
17
|
+
class Debate
|
20
18
|
def self.call(...)
|
21
19
|
new(...).call
|
22
20
|
end
|
@@ -24,8 +22,8 @@ module ActiveGenie
|
|
24
22
|
# @param player_a [String] The content or submission from the first player
|
25
23
|
# @param player_b [String] The content or submission from the second player
|
26
24
|
# @param criteria [String] The evaluation criteria or rules to assess against
|
27
|
-
# @param config [Hash] Additional configuration options that modify the
|
28
|
-
# @return [
|
25
|
+
# @param config [Hash] Additional configuration options that modify the comparator evaluation behavior
|
26
|
+
# @return [ComparatorResponse] The evaluation result containing the winner and reasoning
|
29
27
|
# @return [String] :winner The winner, either player_a or player_b
|
30
28
|
# @return [String] :reasoning Detailed explanation of why the winner was chosen
|
31
29
|
# @return [String] :what_could_be_changed_to_avoid_draw A suggestion on how to avoid a draw
|
@@ -36,7 +34,7 @@ module ActiveGenie
|
|
36
34
|
@config = ActiveGenie.configuration.merge(config)
|
37
35
|
end
|
38
36
|
|
39
|
-
# @return [
|
37
|
+
# @return [ComparatorResponse] The evaluation result containing the winner and reasoning
|
40
38
|
def call
|
41
39
|
messages = [
|
42
40
|
{ role: 'system', content: PROMPT },
|
@@ -45,7 +43,7 @@ module ActiveGenie
|
|
45
43
|
{ role: 'user', content: "criteria: #{@criteria}" }
|
46
44
|
]
|
47
45
|
|
48
|
-
response = ::ActiveGenie::
|
46
|
+
response = ::ActiveGenie::Providers::UnifiedProvider.function_calling(
|
49
47
|
messages,
|
50
48
|
FUNCTION,
|
51
49
|
config: @config
|
@@ -54,8 +52,8 @@ module ActiveGenie
|
|
54
52
|
response_formatted(response)
|
55
53
|
end
|
56
54
|
|
57
|
-
PROMPT = File.read(File.join(__dir__, '
|
58
|
-
FUNCTION = JSON.parse(File.read(File.join(__dir__, '
|
55
|
+
PROMPT = File.read(File.join(__dir__, 'debate.prompt.md'))
|
56
|
+
FUNCTION = JSON.parse(File.read(File.join(__dir__, 'debate.json')), symbolize_names: true)
|
59
57
|
|
60
58
|
private
|
61
59
|
|
@@ -66,19 +64,20 @@ module ActiveGenie
|
|
66
64
|
end
|
67
65
|
reasoning = response['impartial_judge_winner_reasoning']
|
68
66
|
|
69
|
-
|
70
|
-
|
67
|
+
comparator_response = ActiveGenie::Comparator::ComparatorResponse.new(winner:, loser:, reasoning:,
|
68
|
+
raw: response)
|
69
|
+
log_comparator(comparator_response)
|
71
70
|
|
72
|
-
|
71
|
+
comparator_response
|
73
72
|
end
|
74
73
|
|
75
|
-
def
|
74
|
+
def log_comparator(comparator_response)
|
76
75
|
@config.logger.call(
|
77
|
-
code: :
|
76
|
+
code: :comparator,
|
78
77
|
player_a: @player_a[0..30],
|
79
78
|
player_b: @player_b[0..30],
|
80
79
|
criteria: @criteria[0..30],
|
81
|
-
**
|
80
|
+
**comparator_response.to_h
|
82
81
|
)
|
83
82
|
end
|
84
83
|
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../
|
4
|
-
require_relative '
|
3
|
+
require_relative '../providers/unified_provider'
|
4
|
+
require_relative 'debate'
|
5
5
|
|
6
6
|
module ActiveGenie
|
7
|
-
module
|
8
|
-
# The Fight class are
|
7
|
+
module Comparator
|
8
|
+
# The Fight class are comparation specialized in a fight between two fighters, like martial arts, heroes, characters.
|
9
9
|
# The fight evaluation process simulate a fight using words, techniques, strategies, and reasoning.
|
10
10
|
#
|
11
11
|
# @example Fight usage with two fighters and criteria
|
12
12
|
# Fight.call("Naruto", "Sasuke", "How can win without using jutsu?")
|
13
13
|
#
|
14
|
-
class Fight <
|
15
|
-
# @return [
|
14
|
+
class Fight < Debate
|
15
|
+
# @return [ComparatorResponse] The evaluation result containing the winner and reasoning
|
16
16
|
def call
|
17
17
|
messages = [
|
18
18
|
{ role: 'system', content: PROMPT },
|
@@ -21,7 +21,7 @@ module ActiveGenie
|
|
21
21
|
{ role: 'user', content: "criteria: #{@criteria}" }
|
22
22
|
]
|
23
23
|
|
24
|
-
response = ::ActiveGenie::
|
24
|
+
response = ::ActiveGenie::Providers::UnifiedProvider.function_calling(
|
25
25
|
messages,
|
26
26
|
FUNCTION,
|
27
27
|
config: @config
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'comparator/debate'
|
4
|
+
require_relative 'comparator/fight'
|
5
|
+
|
6
|
+
module ActiveGenie
|
7
|
+
module Comparator
|
8
|
+
module_function
|
9
|
+
|
10
|
+
ComparatorResponse = Struct.new(:winner, :loser, :reasoning, :raw, keyword_init: true)
|
11
|
+
|
12
|
+
def call(...)
|
13
|
+
Debate.call(...)
|
14
|
+
end
|
15
|
+
|
16
|
+
def by_debate(...)
|
17
|
+
Debate.call(...)
|
18
|
+
end
|
19
|
+
|
20
|
+
def by_fight(...)
|
21
|
+
Fight.call(...)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -4,13 +4,13 @@ module ActiveGenie
|
|
4
4
|
module Config
|
5
5
|
class LlmConfig
|
6
6
|
attr_accessor :model, :temperature, :max_tokens, :max_retries, :retry_delay,
|
7
|
-
:model_tier, :read_timeout, :open_timeout, :
|
8
|
-
attr_reader :
|
7
|
+
:model_tier, :read_timeout, :open_timeout, :provider
|
8
|
+
attr_reader :provider_name
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
@model = nil
|
12
|
+
@provider_name = nil
|
12
13
|
@provider = nil
|
13
|
-
@client = nil
|
14
14
|
@temperature = 0
|
15
15
|
@max_tokens = 4096
|
16
16
|
@max_retries = nil
|
@@ -20,10 +20,10 @@ module ActiveGenie
|
|
20
20
|
@open_timeout = nil
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
return if
|
23
|
+
def provider_name=(provider_name)
|
24
|
+
return if provider_name.nil? || provider_name.empty?
|
25
25
|
|
26
|
-
@
|
26
|
+
@provider_name = provider_name.to_s.downcase.strip.to_sym
|
27
27
|
end
|
28
28
|
|
29
29
|
def merge(config_params = {})
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
-
require_relative '
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
10
|
-
require_relative '
|
3
|
+
require_relative 'configs/comparator_config'
|
4
|
+
require_relative 'configs/extractor_config'
|
5
|
+
require_relative 'configs/lister_config'
|
6
|
+
require_relative 'configs/llm_config'
|
7
|
+
require_relative 'configs/log_config'
|
8
|
+
require_relative 'configs/providers_config'
|
9
|
+
require_relative 'configs/ranker_config'
|
10
|
+
require_relative 'configs/scorer_config'
|
11
11
|
|
12
12
|
module ActiveGenie
|
13
13
|
class Configuration
|
@@ -19,24 +19,24 @@ module ActiveGenie
|
|
19
19
|
@providers ||= Config::ProvidersConfig.new
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
@
|
22
|
+
def ranker
|
23
|
+
@ranker ||= Config::RankerConfig.new
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
@
|
26
|
+
def scorer
|
27
|
+
@scorer ||= Config::ScorerConfig.new
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
@
|
30
|
+
def extractor
|
31
|
+
@extractor ||= Config::ExtractorConfig.new
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
35
|
-
@
|
34
|
+
def comparator
|
35
|
+
@comparator ||= Config::ComparatorConfig.new
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
39
|
-
@
|
38
|
+
def lister
|
39
|
+
@lister ||= Config::ListerConfig.new
|
40
40
|
end
|
41
41
|
|
42
42
|
def llm
|
@@ -47,7 +47,7 @@ module ActiveGenie
|
|
47
47
|
@logger ||= ActiveGenie::Logger.new(log_config: log)
|
48
48
|
end
|
49
49
|
|
50
|
-
SUB_CONFIGS = %w[log providers llm
|
50
|
+
SUB_CONFIGS = %w[log providers llm ranker scorer extractor comparator lister].freeze
|
51
51
|
|
52
52
|
def merge(config_params = {})
|
53
53
|
return config_params if config_params.is_a?(Configuration)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../
|
3
|
+
require_relative '../providers/unified_provider'
|
4
4
|
|
5
5
|
module ActiveGenie
|
6
|
-
module
|
7
|
-
class
|
6
|
+
module Extractor
|
7
|
+
class Explanation
|
8
8
|
def self.call(...)
|
9
9
|
new(...).call
|
10
10
|
end
|
@@ -25,7 +25,7 @@ module ActiveGenie
|
|
25
25
|
# age: { type: 'integer', description: 'Age in years' }
|
26
26
|
# }
|
27
27
|
# text = "John Doe is 25 years old"
|
28
|
-
#
|
28
|
+
# Extractor.with_explanation(text, schema)
|
29
29
|
# # => { name: "John Doe", name_explanation: "Found directly in text",
|
30
30
|
# # age: 25, age_explanation: "Explicitly stated as 25 years old" }
|
31
31
|
def initialize(text, data_to_extract, config: {})
|
@@ -42,7 +42,7 @@ module ActiveGenie
|
|
42
42
|
|
43
43
|
properties = data_to_extract_with_explanation
|
44
44
|
|
45
|
-
function = JSON.parse(File.read(File.join(__dir__, '
|
45
|
+
function = JSON.parse(File.read(File.join(__dir__, 'explanation.json')), symbolize_names: true)
|
46
46
|
function[:parameters][:properties] = properties
|
47
47
|
function[:parameters][:required] = properties.keys
|
48
48
|
|
@@ -54,7 +54,7 @@ module ActiveGenie
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def data_to_extract_with_explanation
|
57
|
-
return @data_to_extract unless @config.
|
57
|
+
return @data_to_extract unless @config.extractor.with_explanation
|
58
58
|
|
59
59
|
with_explanation = {}
|
60
60
|
|
@@ -81,7 +81,7 @@ module ActiveGenie
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def function_calling(messages, function)
|
84
|
-
response = ::ActiveGenie::
|
84
|
+
response = ::ActiveGenie::Providers::UnifiedProvider.function_calling(
|
85
85
|
messages,
|
86
86
|
function,
|
87
87
|
config: @config
|
@@ -89,7 +89,7 @@ module ActiveGenie
|
|
89
89
|
|
90
90
|
@config.logger.call(
|
91
91
|
{
|
92
|
-
code: :
|
92
|
+
code: :extractor,
|
93
93
|
text: @text[0..30],
|
94
94
|
data_to_extract: function[:parameters][:properties],
|
95
95
|
extracted_data: response
|
@@ -100,7 +100,7 @@ module ActiveGenie
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def simplify_response(response)
|
103
|
-
return response if @config.
|
103
|
+
return response if @config.extractor.verbose
|
104
104
|
|
105
105
|
simplified_response = {}
|
106
106
|
|
@@ -115,11 +115,11 @@ module ActiveGenie
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def min_accuracy
|
118
|
-
@config.
|
118
|
+
@config.extractor.min_accuracy # default 70
|
119
119
|
end
|
120
120
|
|
121
121
|
def prompt
|
122
|
-
File.read(File.join(__dir__, '
|
122
|
+
File.read(File.join(__dir__, 'explanation.prompt.md'))
|
123
123
|
end
|
124
124
|
end
|
125
125
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'explanation'
|
4
4
|
|
5
5
|
module ActiveGenie
|
6
|
-
module
|
7
|
-
class
|
6
|
+
module Extractor
|
7
|
+
class Litote
|
8
8
|
def self.call(...)
|
9
9
|
new(...).call
|
10
10
|
end
|
@@ -24,7 +24,7 @@ module ActiveGenie
|
|
24
24
|
# @example Analyze text with litote
|
25
25
|
# text = "The weather isn't bad today"
|
26
26
|
# schema = { mood: { type: 'string', description: 'The mood of the message' } }
|
27
|
-
#
|
27
|
+
# Extractor.with_litote(text, schema)
|
28
28
|
# # => { mood: "positive", mood_explanation: "Speaker views weather favorably",
|
29
29
|
# # message_litote: true,
|
30
30
|
# # litote_rephrased: "The weather is good today" }
|
@@ -35,7 +35,7 @@ module ActiveGenie
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def call
|
38
|
-
response = Generalist.call(@text,
|
38
|
+
response = Generalist.call(@text, extract_with_litote, config: @config)
|
39
39
|
|
40
40
|
if response[:message_litote]
|
41
41
|
response = Generalist.call(response[:litote_rephrased], @data_to_extract, config: @config)
|
@@ -46,8 +46,8 @@ module ActiveGenie
|
|
46
46
|
|
47
47
|
private
|
48
48
|
|
49
|
-
def
|
50
|
-
parameters = JSON.parse(File.read(File.join(__dir__, '
|
49
|
+
def extract_with_litote
|
50
|
+
parameters = JSON.parse(File.read(File.join(__dir__, 'with_litote.json')), symbolize_names: true)
|
51
51
|
|
52
52
|
@data_to_extract.merge(parameters)
|
53
53
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'extractor/explanation'
|
4
|
+
require_relative 'extractor/litote'
|
5
|
+
|
6
|
+
module ActiveGenie
|
7
|
+
module Extractor
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def call(...)
|
11
|
+
Explanation.call(...)
|
12
|
+
end
|
13
|
+
|
14
|
+
def with_explanation(...)
|
15
|
+
Explanation.call(...)
|
16
|
+
end
|
17
|
+
|
18
|
+
def with_litote(...)
|
19
|
+
Litote.call(...)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require_relative '../clients/unified_client'
|
4
4
|
|
5
5
|
module ActiveGenie
|
6
|
-
module
|
7
|
-
# The
|
6
|
+
module Lister
|
7
|
+
# The Lister::Feud class provides a foundation for generating a list of items for a given theme
|
8
8
|
#
|
9
9
|
# @example Feud usage with two players and criteria
|
10
10
|
# Feud.call("Industries that are most likely to be affected by climate change")
|
@@ -15,14 +15,14 @@ module ActiveGenie
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# @param theme [String] The theme for the feud
|
18
|
-
# @param config [Hash] Additional configuration options
|
18
|
+
# @param config [Hash] Additional configuration options
|
19
19
|
# @return [Array of strings] List of items
|
20
20
|
def initialize(theme, config: {})
|
21
21
|
@theme = theme
|
22
22
|
@config = ActiveGenie.configuration.merge(config)
|
23
23
|
end
|
24
24
|
|
25
|
-
# @return [Array] The list of items
|
25
|
+
# @return [Array of strings] The list of items
|
26
26
|
def call
|
27
27
|
messages = [
|
28
28
|
{ role: 'system', content: PROMPT },
|
@@ -37,7 +37,7 @@ module ActiveGenie
|
|
37
37
|
)
|
38
38
|
|
39
39
|
log_feud(response)
|
40
|
-
response['items']
|
40
|
+
response['items'] || []
|
41
41
|
end
|
42
42
|
|
43
43
|
PROMPT = File.read(File.join(__dir__, 'feud.prompt.md'))
|
@@ -46,7 +46,7 @@ module ActiveGenie
|
|
46
46
|
private
|
47
47
|
|
48
48
|
def number_of_items
|
49
|
-
@config.
|
49
|
+
@config.lister.number_of_items
|
50
50
|
end
|
51
51
|
|
52
52
|
def log_feud(response)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Emulate the game "Family Feud": For a given theme, reason about the general public's most common answers impersonating a survey of average people's opinions and generate an ordered, survey-style answer list.
|
2
|
+
|
3
|
+
- Before producing the answer list, internally consider: If a group of average people were surveyed on this theme, which answers would be mentioned most frequently?.
|
4
|
+
|
5
|
+
# Output Format
|
6
|
+
|
7
|
+
A numbered list in plain text
|
8
|
+
|
9
|
+
# Example
|
10
|
+
|
11
|
+
Example for the theme "Favorite Fast Foods":
|
12
|
+
1. Pizza
|
13
|
+
2. Hamburgers
|
14
|
+
3. Hot Dogs
|
15
|
+
4. French Fries
|
16
|
+
|
17
|
+
# Notes
|
18
|
+
|
19
|
+
- Always impersonate a "Family Feud" survey: order is critical most likely answers should come first.
|
20
|
+
- Judge each item by their general public reputation and cultural impact.
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../clients/unified_client'
|
4
|
+
|
5
|
+
module ActiveGenie
|
6
|
+
module Lister
|
7
|
+
# The Juries class intelligently suggests appropriate jury roles
|
8
|
+
# for evaluating text content based on specific criteria. It uses AI to analyze
|
9
|
+
# the content and criteria to identify the most suitable subject matter experts.
|
10
|
+
#
|
11
|
+
# The class ensures a balanced and comprehensive review process by recommending
|
12
|
+
# three distinct jury roles with complementary expertise and perspectives.
|
13
|
+
#
|
14
|
+
# @example Getting jury for technical content
|
15
|
+
# Juries.call("Technical documentation about API design",
|
16
|
+
# "Evaluate technical accuracy and clarity")
|
17
|
+
# # => { jury1: "API Architect", jury2: "Technical Writer",
|
18
|
+
# # jury3: "Developer Advocate", reasoning: "..." }
|
19
|
+
#
|
20
|
+
class Juries
|
21
|
+
def self.call(...)
|
22
|
+
new(...).call
|
23
|
+
end
|
24
|
+
|
25
|
+
# Initializes a new jury recommendation instance
|
26
|
+
#
|
27
|
+
# @param text [String] The text content to analyze for jury recommendations
|
28
|
+
# @param criteria [String] The evaluation criteria that will guide jury selection
|
29
|
+
# @param config [Hash] Additional configuration config that modify the recommendation process
|
30
|
+
def initialize(text, criteria, config: {})
|
31
|
+
@text = text
|
32
|
+
@criteria = criteria
|
33
|
+
@config = ActiveGenie.configuration.merge(config)
|
34
|
+
end
|
35
|
+
|
36
|
+
def call
|
37
|
+
messages = [
|
38
|
+
{ role: 'system', content: prompt },
|
39
|
+
{ role: 'user', content: "<criteria> #{@criteria}</criteria>" },
|
40
|
+
{ role: 'user', content: "<text-to-score>#{@text}</text-to-score>" }
|
41
|
+
]
|
42
|
+
|
43
|
+
function = {
|
44
|
+
name: 'identify_jury',
|
45
|
+
description: 'Discover a list of juries based on the text and given criteria.',
|
46
|
+
parameters: {
|
47
|
+
type: 'object',
|
48
|
+
properties: {
|
49
|
+
reasoning: { type: 'string' },
|
50
|
+
juries: {
|
51
|
+
type: 'array',
|
52
|
+
description: 'The list of best juries',
|
53
|
+
items: {
|
54
|
+
type: 'string'
|
55
|
+
}
|
56
|
+
}
|
57
|
+
},
|
58
|
+
required: %w[reasoning juries]
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
result = client.function_calling(
|
63
|
+
messages,
|
64
|
+
function,
|
65
|
+
config: @config
|
66
|
+
)
|
67
|
+
|
68
|
+
result['juries'] || []
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def client
|
74
|
+
::ActiveGenie::Clients::UnifiedClient
|
75
|
+
end
|
76
|
+
|
77
|
+
def prompt
|
78
|
+
@prompt ||= File.read(File.join(__dir__, 'juries.prompt.md'))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|