lluminary 0.1.0 → 0.1.2

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/lluminary/config.rb +11 -1
  3. data/lib/lluminary/field_description.rb +34 -29
  4. data/lib/lluminary/provider_error.rb +2 -1
  5. data/lib/lluminary/providers/base.rb +5 -1
  6. data/lib/lluminary/providers/bedrock.rb +32 -30
  7. data/lib/lluminary/providers/openai.rb +28 -21
  8. data/lib/lluminary/providers/test.rb +9 -14
  9. data/lib/lluminary/result.rb +5 -2
  10. data/lib/lluminary/schema.rb +9 -16
  11. data/lib/lluminary/schema_model.rb +13 -10
  12. data/lib/lluminary/task.rb +84 -59
  13. data/lib/lluminary/validation_error.rb +2 -1
  14. data/lib/lluminary/version.rb +3 -2
  15. data/lib/lluminary.rb +23 -7
  16. data/spec/examples/analyze_text_spec.rb +7 -4
  17. data/spec/examples/color_analyzer_spec.rb +22 -22
  18. data/spec/examples/content_analyzer_spec.rb +27 -44
  19. data/spec/examples/historical_event_analyzer_spec.rb +18 -15
  20. data/spec/examples/price_analyzer_spec.rb +22 -28
  21. data/spec/examples/quote_task_spec.rb +9 -8
  22. data/spec/examples/sentiment_analysis_spec.rb +13 -10
  23. data/spec/examples/summarize_text_spec.rb +7 -4
  24. data/spec/lluminary/config_spec.rb +28 -26
  25. data/spec/lluminary/field_description_spec.rb +19 -21
  26. data/spec/lluminary/providers/base_spec.rb +11 -8
  27. data/spec/lluminary/providers/bedrock_spec.rb +47 -57
  28. data/spec/lluminary/providers/openai_spec.rb +27 -35
  29. data/spec/lluminary/providers/test_spec.rb +21 -16
  30. data/spec/lluminary/result_spec.rb +17 -10
  31. data/spec/lluminary/schema_model_spec.rb +31 -22
  32. data/spec/lluminary/schema_spec.rb +95 -107
  33. data/spec/lluminary/task_spec.rb +366 -300
  34. data/spec/spec_helper.rb +7 -2
  35. metadata +40 -22
@@ -1,10 +1,20 @@
1
- require 'ostruct'
2
- require_relative 'schema'
3
- require_relative 'validation_error'
4
- require_relative 'field_description'
5
- require 'json'
1
+ # frozen_string_literal: true
2
+ require "ostruct"
3
+ require_relative "schema"
4
+ require_relative "validation_error"
5
+ require_relative "field_description"
6
+ require "json"
6
7
 
7
8
  module Lluminary
9
+ # Base class for all Lluminary tasks.
10
+ # Provides the core functionality for defining and running LLM-powered tasks.
11
+ #
12
+ # @example Creating a custom task
13
+ # class MyTask < Lluminary::Task
14
+ # def run
15
+ # # Task implementation
16
+ # end
17
+ # end
8
18
  class Task
9
19
  class << self
10
20
  def input_schema(&block)
@@ -18,19 +28,20 @@ module Lluminary
18
28
  end
19
29
 
20
30
  def use_provider(provider_name, **config)
21
- provider_class = case provider_name
22
- when :openai
23
- require_relative 'providers/openai'
24
- Providers::OpenAI
25
- when :test
26
- require_relative 'providers/test'
27
- Providers::Test
28
- when :bedrock
29
- require_relative 'providers/bedrock'
30
- Providers::Bedrock
31
- else
32
- raise ArgumentError, "Unknown provider: #{provider_name}"
33
- end
31
+ provider_class =
32
+ case provider_name
33
+ when :openai
34
+ require_relative "providers/openai"
35
+ Providers::OpenAI
36
+ when :test
37
+ require_relative "providers/test"
38
+ Providers::Test
39
+ when :bedrock
40
+ require_relative "providers/bedrock"
41
+ Providers::Bedrock
42
+ else
43
+ raise ArgumentError, "Unknown provider: #{provider_name}"
44
+ end
34
45
 
35
46
  # Merge global config with task-specific config
36
47
  global_config = Lluminary.config.provider_config(provider_name)
@@ -48,15 +59,14 @@ module Lluminary
48
59
  end
49
60
 
50
61
  def provider
51
- @provider ||= begin
52
- require_relative 'providers/test'
53
- Providers::Test.new
54
- end
62
+ @provider ||=
63
+ begin
64
+ require_relative "providers/test"
65
+ Providers::Test.new
66
+ end
55
67
  end
56
68
 
57
- def provider=(provider)
58
- @provider = provider
59
- end
69
+ attr_writer :provider
60
70
 
61
71
  def input_fields
62
72
  @input_schema&.fields || {}
@@ -98,7 +108,7 @@ module Lluminary
98
108
  validate_input!
99
109
  response = self.class.provider.call(prompt, self)
100
110
  process_response(response)
101
-
111
+
102
112
  self
103
113
  end
104
114
 
@@ -107,13 +117,12 @@ module Lluminary
107
117
  end
108
118
 
109
119
  def validate_input!
110
- unless @input.valid?
111
- raise ValidationError, @input.errors.full_messages.join(", ")
112
- end
120
+ return if @input.valid?
121
+ raise ValidationError, @input.errors.full_messages.join(", ")
113
122
  end
114
123
 
115
124
  def prompt
116
- base_prompt = <<~PROMPT
125
+ <<~PROMPT
117
126
  #{task_prompt}
118
127
 
119
128
  #{json_schema_example}
@@ -134,23 +143,32 @@ module Lluminary
134
143
  # Merge the parsed response first, then validate
135
144
  if @parsed_response.is_a?(Hash)
136
145
  # Get datetime fields from schema
137
- datetime_fields = self.class.output_fields.select { |_, field| field[:type] == :datetime }.keys
146
+ datetime_fields =
147
+ self
148
+ .class
149
+ .output_fields
150
+ .select { |_, field| field[:type] == :datetime }
151
+ .keys
138
152
 
139
153
  # Convert datetime fields
140
154
  converted_response = @parsed_response.dup
141
155
  datetime_fields.each do |field_name|
142
- if converted_response.key?(field_name.to_s) && converted_response[field_name.to_s].is_a?(String)
143
- begin
144
- converted_response[field_name.to_s] = DateTime.parse(converted_response[field_name.to_s])
145
- rescue ArgumentError
146
- # Leave as string, validation will fail
147
- end
156
+ unless converted_response.key?(field_name.to_s) &&
157
+ converted_response[field_name.to_s].is_a?(String)
158
+ next
159
+ end
160
+ begin
161
+ converted_response[field_name.to_s] = DateTime.parse(
162
+ converted_response[field_name.to_s]
163
+ )
164
+ rescue ArgumentError
165
+ # Leave as string, validation will fail
148
166
  end
149
167
  end
150
168
 
151
169
  @output.attributes.merge!(converted_response)
152
170
  end
153
-
171
+
154
172
  # Validate after merging
155
173
  @output.valid?
156
174
 
@@ -186,29 +204,36 @@ module Lluminary
186
204
  end
187
205
 
188
206
  def generate_field_descriptions
189
- fields.map do |name, field|
190
- # Get validations for this field
191
- validations = self.class.instance_variable_get(:@output_schema)&.validations_for(name) || []
192
- field_with_validations = field.merge(validations: validations)
193
- FieldDescription.new(name, field_with_validations).to_schema_s
194
- end.join("\n\n")
207
+ fields
208
+ .map do |name, field|
209
+ # Get validations for this field
210
+ validations =
211
+ self
212
+ .class
213
+ .instance_variable_get(:@output_schema)
214
+ &.validations_for(name) || []
215
+ field_with_validations = field.merge(validations: validations)
216
+ FieldDescription.new(name, field_with_validations).to_schema_s
217
+ end
218
+ .join("\n\n")
195
219
  end
196
220
 
197
221
  def example_json
198
- json = fields.each_with_object({}) do |(name, field), hash|
199
- hash[name] = case field[:type]
200
- when :string
201
- "your #{name} here"
202
- when :integer
203
- 0
204
- when :datetime
205
- "2024-01-01T12:00:00+00:00"
206
- when :boolean
207
- true
208
- when :float
209
- 0.0
210
- end
211
- end
222
+ json =
223
+ fields.each_with_object({}) do |(name, field), hash|
224
+ hash[name] = case field[:type]
225
+ when :string
226
+ "your #{name} here"
227
+ when :integer
228
+ 0
229
+ when :datetime
230
+ "2024-01-01T12:00:00+00:00"
231
+ when :boolean
232
+ true
233
+ when :float
234
+ 0.0
235
+ end
236
+ end
212
237
 
213
238
  JSON.pretty_generate(json)
214
239
  end
@@ -221,4 +246,4 @@ module Lluminary
221
246
  )
222
247
  end
223
248
  end
224
- end
249
+ end
@@ -1,4 +1,5 @@
1
+ # frozen_string_literal: true
1
2
  module Lluminary
2
3
  class ValidationError < StandardError
3
4
  end
4
- end
5
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Lluminary
2
- VERSION = '0.1.0'
3
- end
3
+ VERSION = "0.1.0"
4
+ end
data/lib/lluminary.rb CHANGED
@@ -1,10 +1,22 @@
1
- require_relative 'lluminary/version'
2
- require_relative 'lluminary/result'
3
- require_relative 'lluminary/task'
4
- require_relative 'lluminary/providers/base'
5
- require_relative 'lluminary/providers/openai'
6
- require_relative 'lluminary/config'
1
+ # frozen_string_literal: true
7
2
 
3
+ require_relative "lluminary/version"
4
+ require_relative "lluminary/result"
5
+ require_relative "lluminary/task"
6
+ require_relative "lluminary/providers/base"
7
+ require_relative "lluminary/providers/openai"
8
+ require_relative "lluminary/config"
9
+
10
+ # Lluminary is a framework for building and running LLM-powered tasks.
11
+ # It provides a structured way to define tasks, their inputs and outputs,
12
+ # and handles the interaction with various LLM providers.
13
+ #
14
+ # @example Creating a simple task
15
+ # class MyTask < Lluminary::Task
16
+ # def run
17
+ # # Task implementation
18
+ # end
19
+ # end
8
20
  module Lluminary
9
21
  class << self
10
22
  def config
@@ -14,5 +26,9 @@ module Lluminary
14
26
  def configure
15
27
  yield config
16
28
  end
29
+
30
+ def reset_configuration
31
+ @config = Config.new
32
+ end
17
33
  end
18
- end
34
+ end
@@ -1,8 +1,11 @@
1
- require 'spec_helper'
2
- require_relative '../../examples/analyze_text'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/analyze_text"
3
4
 
4
5
  RSpec.describe AnalyzeText 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 "analyzes text" do
8
11
  result = described_class.call(text: text)
@@ -18,4 +21,4 @@ RSpec.describe AnalyzeText do
18
21
  expect(json).to have_key("analysis")
19
22
  expect(json["analysis"]).to eq(result.output.analysis)
20
23
  end
21
- end
24
+ end
@@ -1,42 +1,42 @@
1
- require 'spec_helper'
2
- require_relative '../../examples/color_analyzer'
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+ require_relative "../../examples/color_analyzer"
3
4
 
4
5
  RSpec.describe ColorAnalyzer do
5
- describe '#call' do
6
+ describe "#call" do
6
7
  it 'returns "red" for a description strongly suggesting the color red' do
7
- result = described_class.call(
8
- image_description: "A bright red sports car parked in front of a red brick building at sunset. The car's glossy red paint reflects the warm light, making it appear even more vibrant. A red stop sign stands nearby, and red roses bloom in a garden beside the building."
9
- )
8
+ result = described_class.call(image_description: <<~DESCRIPTION)
9
+ A bright red sports car parked in front of a red brick building at sunset. The car's glossy red paint reflects the warm light, making it appear even more vibrant. A red stop sign stands nearby, and red roses bloom in a garden beside the building.
10
+ DESCRIPTION
10
11
 
11
12
  expect(result.output.color_name).to eq("red")
12
13
  expect(result.output.valid?).to be true
13
14
  end
14
15
 
15
- it 'returns invalid output when description strongly suggests orange' do
16
+ it "returns invalid output when description strongly suggests orange" do
16
17
  # This should fail validation because "orange" is not a CSS Level 1 color
17
- result = described_class.call(
18
- image_description: "A field of ripe oranges under a bright orange sunset. The fruit glows with a warm orange hue, and the sky is painted in shades of orange and gold. Orange butterflies flutter among the trees, and orange flowers bloom throughout the scene."
19
- )
18
+ result = described_class.call(image_description: <<~DESCRIPTION)
19
+ A field of ripe oranges under a bright orange sunset. The fruit glows with a warm orange hue, and the sky is painted in shades of orange and gold. Orange butterflies flutter among the trees, and orange flowers bloom throughout the scene.
20
+ DESCRIPTION
20
21
 
21
22
  expect(result.output.valid?).to be false
22
- expect(result.output.errors.full_messages).to include("Color name must be a valid CSS level 1 color name")
23
+ expect(result.output.errors.full_messages).to include(
24
+ "Color name must be a valid CSS level 1 color name"
25
+ )
23
26
  end
24
27
 
25
- it 'validates presence of image_description' do
26
- expect {
27
- described_class.call!(
28
- image_description: ""
29
- )
30
- }.to raise_error(Lluminary::ValidationError)
28
+ it "validates presence of image_description" do
29
+ expect { described_class.call!(image_description: "") }.to raise_error(
30
+ Lluminary::ValidationError
31
+ )
31
32
  end
32
33
 
33
- it 'validates that color_name is lowercase' do
34
- result = described_class.call(
35
- image_description: "A bright red sports car"
36
- )
34
+ it "validates that color_name is lowercase" do
35
+ result =
36
+ described_class.call(image_description: "A bright red sports car")
37
37
 
38
38
  expect(result.output.valid?).to be true
39
39
  expect(result.output.color_name).to eq(result.output.color_name.downcase)
40
40
  end
41
41
  end
42
- end
42
+ end
@@ -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
@@ -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