lluminary 0.1.1 → 0.1.3

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/lluminary/config.rb +6 -1
  3. data/lib/lluminary/models/base.rb +235 -0
  4. data/lib/lluminary/models/bedrock/amazon_nova_pro_v1.rb +19 -0
  5. data/lib/lluminary/models/bedrock/anthropic_claude_instant_v1.rb +17 -0
  6. data/lib/lluminary/models/bedrock/base.rb +29 -0
  7. data/lib/lluminary/models/openai/gpt35_turbo.rb +20 -0
  8. data/lib/lluminary/provider_error.rb +2 -1
  9. data/lib/lluminary/providers/base.rb +20 -3
  10. data/lib/lluminary/providers/bedrock.rb +52 -32
  11. data/lib/lluminary/providers/openai.rb +41 -24
  12. data/lib/lluminary/providers/test.rb +14 -13
  13. data/lib/lluminary/result.rb +5 -2
  14. data/lib/lluminary/schema.rb +59 -15
  15. data/lib/lluminary/schema_model.rb +67 -10
  16. data/lib/lluminary/task.rb +58 -99
  17. data/lib/lluminary/validation_error.rb +2 -1
  18. data/lib/lluminary/version.rb +3 -2
  19. data/lib/lluminary.rb +25 -7
  20. data/spec/examples/analyze_text_spec.rb +7 -4
  21. data/spec/examples/color_analyzer_spec.rb +22 -22
  22. data/spec/examples/content_analyzer_spec.rb +27 -44
  23. data/spec/examples/historical_event_analyzer_spec.rb +18 -15
  24. data/spec/examples/meal_suggester_spec.rb +64 -0
  25. data/spec/examples/price_analyzer_spec.rb +22 -28
  26. data/spec/examples/quote_task_spec.rb +9 -8
  27. data/spec/examples/sentiment_analysis_spec.rb +13 -10
  28. data/spec/examples/summarize_text_spec.rb +7 -4
  29. data/spec/lluminary/config_spec.rb +28 -26
  30. data/spec/lluminary/models/base_spec.rb +581 -0
  31. data/spec/lluminary/models/bedrock/amazon_nova_pro_v1_spec.rb +30 -0
  32. data/spec/lluminary/models/bedrock/anthropic_claude_instant_v1_spec.rb +21 -0
  33. data/spec/lluminary/models/openai/gpt35_turbo_spec.rb +22 -0
  34. data/spec/lluminary/providers/bedrock_spec.rb +86 -57
  35. data/spec/lluminary/providers/openai_spec.rb +58 -34
  36. data/spec/lluminary/providers/test_spec.rb +46 -16
  37. data/spec/lluminary/result_spec.rb +17 -10
  38. data/spec/lluminary/schema_model_spec.rb +108 -22
  39. data/spec/lluminary/schema_spec.rb +241 -107
  40. data/spec/lluminary/task_spec.rb +118 -584
  41. data/spec/spec_helper.rb +8 -2
  42. metadata +73 -22
  43. data/lib/lluminary/field_description.rb +0 -148
  44. data/spec/lluminary/field_description_spec.rb +0 -36
  45. data/spec/lluminary/providers/base_spec.rb +0 -17
@@ -1,75 +1,58 @@
1
- require 'spec_helper'
2
- require_relative '../../examples/content_analyzer'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/content_analyzer"
3
4
 
4
5
  RSpec.describe ContentAnalyzer do
5
- let(:technical_text) do
6
- <<~TEXT
6
+ let(:technical_text) { <<~TEXT }
7
7
  The revolutionary new quantum processor leverages advanced photonic circuits to achieve unprecedented computational speeds.
8
8
  By utilizing entangled photon pairs, it can perform complex calculations in parallel, significantly reducing processing time.
9
9
  This breakthrough technology represents a major advancement in quantum computing.
10
10
  TEXT
11
- end
12
11
 
13
- let(:emotional_text) do
14
- <<~TEXT
12
+ let(:emotional_text) { <<~TEXT }
15
13
  I can't believe how amazing this experience was! My heart was racing with excitement as I watched the performance.
16
14
  The raw emotion and passion in every movement brought tears to my eyes. It was truly a transformative moment that I'll never forget.
17
15
  TEXT
18
- end
19
16
 
20
- describe '#call' do
21
- it 'correctly identifies technical content' do
22
- result = described_class.call(
23
- text: technical_text,
24
- content_type: "technical"
25
- )
17
+ describe "#call" do
18
+ it "correctly identifies technical content" do
19
+ result =
20
+ described_class.call(text: technical_text, content_type: "technical")
26
21
 
27
22
  expect(result.output.contains_type).to be true
28
23
  end
29
24
 
30
- it 'correctly identifies non-technical content' do
31
- result = described_class.call(
32
- text: emotional_text,
33
- content_type: "technical"
34
- )
25
+ it "correctly identifies non-technical content" do
26
+ result =
27
+ described_class.call(text: emotional_text, content_type: "technical")
35
28
 
36
29
  expect(result.output.contains_type).to be false
37
30
  end
38
31
 
39
- it 'correctly identifies emotional content' do
40
- result = described_class.call(
41
- text: emotional_text,
42
- content_type: "emotional"
43
- )
32
+ it "correctly identifies emotional content" do
33
+ result =
34
+ described_class.call(text: emotional_text, content_type: "emotional")
44
35
 
45
36
  expect(result.output.contains_type).to be true
46
37
  end
47
38
 
48
- it 'correctly identifies non-emotional content' do
49
- result = described_class.call(
50
- text: technical_text,
51
- content_type: "emotional"
52
- )
39
+ it "correctly identifies non-emotional content" do
40
+ result =
41
+ described_class.call(text: technical_text, content_type: "emotional")
53
42
 
54
43
  expect(result.output.contains_type).to be false
55
44
  end
56
45
 
57
- it 'validates presence of text' do
58
- expect {
59
- described_class.call!(
60
- text: "",
61
- content_type: "technical"
62
- )
63
- }.to raise_error(Lluminary::ValidationError)
46
+ it "validates presence of text" do
47
+ expect do
48
+ described_class.call!(text: "", content_type: "technical")
49
+ end.to raise_error(Lluminary::ValidationError)
64
50
  end
65
51
 
66
- it 'validates presence of content_type' do
67
- expect {
68
- described_class.call!(
69
- text: technical_text,
70
- content_type: ""
71
- )
72
- }.to raise_error(Lluminary::ValidationError)
52
+ it "validates presence of content_type" do
53
+ expect do
54
+ described_class.call!(text: technical_text, content_type: "")
55
+ end.to raise_error(Lluminary::ValidationError)
73
56
  end
74
57
  end
75
- end
58
+ end
@@ -1,14 +1,16 @@
1
- require 'spec_helper'
2
- require_relative '../../examples/historical_event_analyzer'
3
- require 'pry-byebug'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/historical_event_analyzer"
4
+ require "pry-byebug"
4
5
 
5
6
  RSpec.describe HistoricalEventAnalyzer do
6
- describe '#call' do
7
- context 'with events that have known exact times' do
8
- it 'returns the exact time of the human step on the moon' do
9
- result = described_class.call(
10
- event_description: "Neil Armstrong's first step onto the Moon"
11
- )
7
+ describe "#call" do
8
+ context "with events that have known exact times" do
9
+ it "returns the exact time of the human step on the moon" do
10
+ result =
11
+ described_class.call(
12
+ event_description: "Neil Armstrong's first step onto the Moon"
13
+ )
12
14
 
13
15
  expect(result.output.valid?).to be true
14
16
  expect(result.output.event_datetime).to be_a(DateTime)
@@ -19,11 +21,12 @@ RSpec.describe HistoricalEventAnalyzer do
19
21
  end
20
22
  end
21
23
 
22
- context 'with events that have approximate times' do
23
- it 'returns midnight for the fall of the Roman Empire' do
24
- result = described_class.call(
25
- event_description: "Assassination of Julius Caesar"
26
- )
24
+ context "with events that have approximate times" do
25
+ it "returns midnight for the fall of the Roman Empire" do
26
+ result =
27
+ described_class.call(
28
+ event_description: "Assassination of Julius Caesar"
29
+ )
27
30
 
28
31
  expect(result.output.valid?).to be true
29
32
  expect(result.output.event_datetime).to be_a(DateTime)
@@ -34,4 +37,4 @@ RSpec.describe HistoricalEventAnalyzer do
34
37
  end
35
38
  end
36
39
  end
37
- end
40
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/meal_suggester"
4
+
5
+ RSpec.describe MealSuggester do
6
+ let(:valid_ingredients) { %w[eggs bread butter] }
7
+ let(:valid_count) { 3 }
8
+ let(:valid_params) do
9
+ { ingredients: valid_ingredients, suggestions_count: valid_count }
10
+ end
11
+
12
+ describe "input validation" do
13
+ it "accepts valid parameters" do
14
+ expect { described_class.call!(**valid_params) }.not_to raise_error
15
+ end
16
+
17
+ it "requires ingredients to be present" do
18
+ expect do
19
+ described_class.call!(ingredients: [], suggestions_count: valid_count)
20
+ end.to raise_error(Lluminary::ValidationError)
21
+ end
22
+
23
+ it "requires suggestions_count to be present" do
24
+ expect do
25
+ described_class.call!(
26
+ ingredients: valid_ingredients,
27
+ suggestions_count: nil
28
+ )
29
+ end.to raise_error(Lluminary::ValidationError)
30
+ end
31
+ end
32
+
33
+ describe "output validation" do
34
+ let(:result) { described_class.call(**valid_params) }
35
+
36
+ it "returns an array of meal suggestions" do
37
+ expect(result.output.meal_suggestions).to be_an(Array)
38
+ end
39
+
40
+ it "returns the requested number of suggestions" do
41
+ expect(result.output.meal_suggestions.length).to eq(valid_count)
42
+ end
43
+
44
+ it "returns string suggestions" do
45
+ expect(result.output.meal_suggestions).to all(be_a(String))
46
+ end
47
+
48
+ it "returns non-empty suggestions" do
49
+ expect(result.output.meal_suggestions).to all(be_present)
50
+ end
51
+ end
52
+
53
+ describe "prompt generation" do
54
+ let(:result) { described_class.call(**valid_params) }
55
+
56
+ it "includes the ingredients in the prompt" do
57
+ expect(result.prompt).to include(valid_ingredients.inspect)
58
+ end
59
+
60
+ it "includes the suggestions count in the prompt" do
61
+ expect(result.prompt).to include(valid_count.to_s)
62
+ end
63
+ end
64
+ end
@@ -1,46 +1,40 @@
1
- require 'spec_helper'
2
- require_relative '../../examples/price_analyzer'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/price_analyzer"
3
4
 
4
5
  RSpec.describe PriceAnalyzer do
5
- describe '#call' do
6
- it 'returns a competitiveness score between 0.0 and 1.0 for a high-priced item' do
7
- result = described_class.call(
8
- product_name: "Entry LevelLuxury Watch",
9
- price: 999.99
10
- )
6
+ describe "#call" do
7
+ it "returns a competitiveness score between 0.0 and 1.0 for a high-priced item" do
8
+ result =
9
+ described_class.call(
10
+ product_name: "Entry LevelLuxury Watch",
11
+ price: 999.99
12
+ )
11
13
 
12
14
  expect(result.output.competitiveness_score).to be_a(Float)
13
15
  expect(result.output.competitiveness_score).to be_between(0.0, 1.0)
14
16
  expect(result.output.competitiveness_score).to be >= 0.5 # Lower priced luxury watch is more competitive
15
17
  end
16
18
 
17
- it 'returns a higher competitiveness score for a reasonably priced item' do
18
- result = described_class.call(
19
- product_name: "Basic Watch",
20
- price: 10049.99
21
- )
19
+ it "returns a higher competitiveness score for a reasonably priced item" do
20
+ result =
21
+ described_class.call(product_name: "Basic Watch", price: 10_049.99)
22
22
 
23
23
  expect(result.output.competitiveness_score).to be_a(Float)
24
24
  expect(result.output.competitiveness_score).to be_between(0.0, 1.0)
25
25
  expect(result.output.competitiveness_score).to be <= 0.5 # Higher priced basic watch is less competitive
26
26
  end
27
27
 
28
- it 'validates presence of product_name' do
29
- expect {
30
- described_class.call!(
31
- product_name: "",
32
- price: 49.99
33
- )
34
- }.to raise_error(Lluminary::ValidationError)
28
+ it "validates presence of product_name" do
29
+ expect do
30
+ described_class.call!(product_name: "", price: 49.99)
31
+ end.to raise_error(Lluminary::ValidationError)
35
32
  end
36
33
 
37
- it 'validates presence of price' do
38
- expect {
39
- described_class.call!(
40
- product_name: "Basic Watch",
41
- price: nil
42
- )
43
- }.to raise_error(Lluminary::ValidationError)
34
+ it "validates presence of price" do
35
+ expect do
36
+ described_class.call!(product_name: "Basic Watch", price: nil)
37
+ end.to raise_error(Lluminary::ValidationError)
44
38
  end
45
39
  end
46
- end
40
+ end
@@ -1,27 +1,28 @@
1
- require 'spec_helper'
2
- require_relative '../../examples/quote_task'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/quote_task"
3
4
 
4
5
  RSpec.describe QuoteTask do
5
- describe '.call' do
6
- it 'returns a quote and its author' do
6
+ describe ".call" do
7
+ it "returns a quote and its author" do
7
8
  result = described_class.call
8
9
 
9
10
  expect(result.output.quote).to be_a(String)
10
11
  expect(result.output.quote).not_to be_empty
11
-
12
+
12
13
  expect(result.output.author).to be_a(String)
13
14
  expect(result.output.author).not_to be_empty
14
15
  end
15
16
 
16
- it 'can be called without any input parameters' do
17
+ it "can be called without any input parameters" do
17
18
  expect { described_class.call }.not_to raise_error
18
19
  end
19
20
 
20
- it 'returns a valid result object' do
21
+ it "returns a valid result object" do
21
22
  result = described_class.call
22
23
  expect(result).to be_a(Lluminary::Task)
23
24
  expect(result.input).to be_a(Lluminary::SchemaModel)
24
25
  expect(result.input.valid?).to be true
25
26
  end
26
27
  end
27
- end
28
+ end
@@ -1,13 +1,14 @@
1
- require 'spec_helper'
2
- require_relative '../../examples/sentiment_analysis'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/sentiment_analysis"
3
4
 
4
5
  RSpec.describe SentimentAnalysis do
5
6
  let(:text) { "I absolutely love this new feature!" }
6
7
 
7
- describe '.call' do
8
- it 'analyzes sentiment of given text' do
8
+ describe ".call" do
9
+ it "analyzes sentiment of given text" do
9
10
  result = described_class.call(text: text)
10
-
11
+
11
12
  expect(result.output.sentiment).to be_a(String)
12
13
  expect(result.output.sentiment).not_to be_empty
13
14
  expect(result.output.explanation).to be_a(String)
@@ -16,7 +17,7 @@ RSpec.describe SentimentAnalysis do
16
17
  expect(result.output.confidence).to be_between(0, 100)
17
18
  end
18
19
 
19
- it 'returns valid JSON response' do
20
+ it "returns valid JSON response" do
20
21
  result = described_class.call(text: text)
21
22
  expect(result.output.raw_response).to be_a(String)
22
23
  expect { JSON.parse(result.output.raw_response) }.not_to raise_error
@@ -29,17 +30,19 @@ RSpec.describe SentimentAnalysis do
29
30
  expect(json["confidence"]).to eq(result.output.confidence)
30
31
  end
31
32
 
32
- it 'requires text input' do
33
+ it "requires text input" do
33
34
  result = described_class.call({})
34
35
  expect(result.valid?).to be false
35
- expect(result.input.errors.full_messages).to include("Text can't be blank")
36
+ expect(result.input.errors.full_messages).to include(
37
+ "Text can't be blank"
38
+ )
36
39
  end
37
40
 
38
- it 'returns a valid result object' do
41
+ it "returns a valid result object" do
39
42
  result = described_class.call(text: text)
40
43
  expect(result).to be_a(Lluminary::Task)
41
44
  expect(result.input).to be_a(Lluminary::SchemaModel)
42
45
  expect(result.input.valid?).to be true
43
46
  end
44
47
  end
45
- end
48
+ end
@@ -1,8 +1,11 @@
1
- require 'spec_helper'
2
- require_relative '../../examples/summarize_text'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/summarize_text"
3
4
 
4
5
  RSpec.describe SummarizeText do
5
- let(:text) { "Ruby is a dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write." }
6
+ let(:text) { <<~TEXT }
7
+ Ruby is a dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.
8
+ TEXT
6
9
 
7
10
  it "summarizes text" do
8
11
  result = described_class.call(text: text)
@@ -18,4 +21,4 @@ RSpec.describe SummarizeText do
18
21
  expect(json).to have_key("summary")
19
22
  expect(json["summary"]).to eq(result.output.summary)
20
23
  end
21
- end
24
+ end
@@ -1,47 +1,49 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
2
3
 
3
4
  RSpec.describe Lluminary::Config do
4
5
  let(:config) { described_class.new }
5
6
 
6
- describe '#configure' do
7
- it 'allows setting provider configurations' do
7
+ describe "#configure" do
8
+ it "allows setting provider configurations" do
8
9
  config.configure do |c|
9
- c.provider(:openai, api_key: 'global-key')
10
- c.provider(:bedrock,
11
- access_key_id: 'global-access-key',
12
- secret_access_key: 'global-secret-key',
13
- region: 'us-east-1'
10
+ c.provider(:openai, api_key: "global-key")
11
+ c.provider(
12
+ :bedrock,
13
+ access_key_id: "global-access-key",
14
+ secret_access_key: "global-secret-key",
15
+ region: "us-east-1"
14
16
  )
15
17
  end
16
18
 
17
- expect(config.provider_config(:openai)).to eq({ api_key: 'global-key' })
18
- expect(config.provider_config(:bedrock)).to eq({
19
- access_key_id: 'global-access-key',
20
- secret_access_key: 'global-secret-key',
21
- region: 'us-east-1'
22
- })
19
+ expect(config.provider_config(:openai)).to eq({ api_key: "global-key" })
20
+ expect(config.provider_config(:bedrock)).to eq(
21
+ {
22
+ access_key_id: "global-access-key",
23
+ secret_access_key: "global-secret-key",
24
+ region: "us-east-1"
25
+ }
26
+ )
23
27
  end
24
28
  end
25
29
 
26
- describe '#provider_config' do
27
- it 'returns empty hash for unconfigured providers' do
30
+ describe "#provider_config" do
31
+ it "returns empty hash for unconfigured providers" do
28
32
  expect(config.provider_config(:unknown)).to eq({})
29
33
  end
30
34
 
31
- it 'returns the configuration for a configured provider' do
32
- config.configure do |c|
33
- c.provider(:openai, api_key: 'test-key')
34
- end
35
+ it "returns the configuration for a configured provider" do
36
+ config.configure { |c| c.provider(:openai, api_key: "test-key") }
35
37
 
36
- expect(config.provider_config(:openai)).to eq({ api_key: 'test-key' })
38
+ expect(config.provider_config(:openai)).to eq({ api_key: "test-key" })
37
39
  end
38
40
  end
39
41
 
40
- describe '#reset!' do
41
- it 'clears all provider configurations' do
42
+ describe "#reset!" do
43
+ it "clears all provider configurations" do
42
44
  config.configure do |c|
43
- c.provider(:openai, api_key: 'test-key')
44
- c.provider(:bedrock, access_key_id: 'test-access-key')
45
+ c.provider(:openai, api_key: "test-key")
46
+ c.provider(:bedrock, access_key_id: "test-access-key")
45
47
  end
46
48
 
47
49
  config.reset!
@@ -50,4 +52,4 @@ RSpec.describe Lluminary::Config do
50
52
  expect(config.provider_config(:bedrock)).to eq({})
51
53
  end
52
54
  end
53
- end
55
+ end