Skip to content

Commit ffca3c3

Browse files
committed
✨ rework confidence scores to be easily comparable
1 parent 8ea8f52 commit ffca3c3

File tree

4 files changed

+108
-64
lines changed

4 files changed

+108
-64
lines changed

lib/mindee/parsing/v2/field/base_field.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ class BaseField
2020
# @param indent_level [Integer] Level of indentation for rst display.
2121
def initialize(raw_prediction, indent_level = 0)
2222
@indent_level = indent_level
23-
@confidence = raw_prediction.key?('confidence') ? raw_prediction['confidence'] : nil
24-
@locations = if raw_prediction.key?('locations')
25-
raw_prediction['locations'].map do |location|
23+
confidence = raw_prediction['confidence']
24+
@confidence = FieldConfidence.new(confidence) unless confidence.nil? || confidence.empty?
25+
26+
locations = raw_prediction['locations']
27+
@locations = if locations.nil? || locations.empty?
28+
[]
29+
else
30+
locations.map do |location|
2631
FieldLocation.new(location)
2732
end
28-
else
29-
[]
3033
end
3134
end
3235

lib/mindee/parsing/v2/field/field_confidence.rb

Lines changed: 76 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,70 +19,107 @@ class FieldConfidence
1919
LOW = 'Low'
2020

2121
# List of valid values, as frozen strings.
22-
VALID_VALUES = [CERTAIN, HIGH, MEDIUM, LOW].freeze
22+
VALID_VALUES = ['Certain', 'High', 'Medium', 'Low'].freeze
2323

2424
# @param value [String] The confidence level value.
2525
# @raise [ArgumentError] If the value is not a valid confidence level.
2626
def initialize(value)
27-
unless VALID_VALUES.include?(value)
27+
case value
28+
when 'Certain' then @value = CERTAIN
29+
when 'High' then @value = HIGH
30+
when 'Medium' then @value = MEDIUM
31+
when 'Low' then @value = LOW
32+
else
2833
raise ArgumentError,
29-
"Invalid confidence level: #{value}. Must be one of: #{VALID_VALUES.join(', ')}"
34+
"Invalid confidence level: '#{value}'. Must be one of: #{VALID_VALUES.join(', ')}"
3035
end
3136

3237
@value = value
3338
end
3439

35-
# Create a FieldConfidence from a string value.
36-
# @param value [String] The confidence level string.
37-
# @return [FieldConfidence] The confidence instance.
38-
def self.from_string(value)
39-
new(value)
40+
# String representation of the confidence level.
41+
# @return [String] The confidence level value.
42+
def to_s
43+
@value
4044
end
4145

42-
# Check if this is a certain confidence level.
43-
# @return [Boolean] `true` if confidence is certain.
44-
def certain?
45-
@value == CERTAIN
46+
# String representation of the confidence level.
47+
# @return [Integer] The confidence level value as an integer: 1 is LOW, 4 is HIGH.
48+
def to_i
49+
val_to_i(@value)
4650
end
4751

48-
# Check if this is a high confidence level.
49-
# @return [Boolean] `true` if confidence is high.
50-
def high?
51-
@value == HIGH
52+
# Inspect method for debugging.
53+
# @return [String] Debug representation.
54+
def inspect
55+
"#<#{self.class.name}:#{@value}>"
5256
end
5357

54-
# Check if this is a medium confidence level.
55-
# @return [Boolean] `true` if confidence is medium.
56-
def medium?
57-
@value == MEDIUM
58-
end
58+
# Using 'case' breaks steep ...
59+
# rubocop:disable Style/CaseLikeIf
5960

60-
# Check if this is a low confidence level.
61-
# @return [Boolean] `true` if confidence is low.
62-
def low?
63-
@value == LOW
61+
# Equality of two FieldConfidence instances.
62+
# @param other [String, Integer, FieldConfidence] The other confidence to compare.
63+
# @return [Boolean] `true` if they have the same value.
64+
def ==(other)
65+
if other.is_a?(FieldConfidence)
66+
@value == other.value
67+
elsif other.is_a?(String)
68+
@value == other
69+
elsif other.is_a?(Integer)
70+
to_i == other
71+
else
72+
raise ArgumentError, "Invalid type: #{other.class}"
73+
end
6474
end
6575

66-
# String representation of the confidence level.
67-
# @return [String] The confidence level value.
68-
def to_s
69-
@value
76+
# Greater than or equality of two FieldConfidence instances.
77+
# @param other [String, Integer, FieldConfidence] The other confidence to compare.
78+
def >=(other)
79+
if other.is_a?(FieldConfidence)
80+
to_i >= val_to_i(other.value)
81+
elsif other.is_a?(String)
82+
to_i >= val_to_i(other)
83+
elsif other.is_a?(Integer)
84+
to_i >= other
85+
else
86+
raise ArgumentError, "Invalid type: #{other.class}"
87+
end
7088
end
7189

72-
# Compare two FieldConfidence instances.
73-
# @param other [FieldConfidence] The other confidence to compare.
74-
# @return [Boolean] `true` if they have the same value.
75-
def ==(other)
76-
other.is_a?(FieldConfidence) && @value == other.value
90+
# less than or equality of two FieldConfidence instances.
91+
# # @param other [String, Integer, FieldConfidence] The other confidence to compare.
92+
def <=(other)
93+
if other.is_a?(FieldConfidence)
94+
to_i <= val_to_i(other.value)
95+
elsif other.is_a?(String)
96+
to_i <= val_to_i(other)
97+
elsif other.is_a?(Integer)
98+
to_i <= other
99+
else
100+
raise ArgumentError, "Invalid type: #{other.class}"
101+
end
77102
end
78103

79-
# Make instances comparable and hashable
104+
# rubocop:enable Style/CaseLikeIf
105+
106+
# Aliases for the comparison operators.
80107
alias eql? ==
108+
alias gteql? >=
109+
alias lteql? <=
81110

82-
# Inspect method for debugging.
83-
# @return [String] Debug representation.
84-
def inspect
85-
"#<#{self.class.name}:#{@value}>"
111+
protected
112+
113+
def val_to_i(value)
114+
case value
115+
when CERTAIN then 4
116+
when HIGH then 3
117+
when MEDIUM then 2
118+
when LOW then 1
119+
else
120+
raise ArgumentError,
121+
"Invalid confidence level: '#{value}'. Must be one of: #{VALID_VALUES.join(', ')}"
122+
end
86123
end
87124
end
88125
end

sig/mindee/parsing/v2/field/field_confidence.rbs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ module Mindee
1212
VALID_VALUES: Array[String]
1313
def initialize: (String) -> void
1414
def self.from_string: (String) -> FieldConfidence
15-
def certain?: -> bool
16-
def high?: -> bool
17-
def medium?: -> bool
18-
def low?: -> bool
15+
def to_i: -> Integer
1916
def to_s: -> String
20-
def ==: (FieldConfidence) -> bool
21-
def eql?: (FieldConfidence) -> bool
17+
def ==: (String | Integer | FieldConfidence) -> bool
18+
def eql?: (String | Integer | FieldConfidence) -> bool
19+
def <=: (String | Integer | FieldConfidence) -> bool
20+
def lteql? : (String | Integer | FieldConfidence) -> bool
21+
def >=: (String | Integer | FieldConfidence) -> bool
22+
def gteql?: (String | Integer | FieldConfidence) -> bool
2223
def inspect: -> String
24+
25+
def val_to_i: (String) -> Integer
2326
end
2427
end
2528
end

spec/parsing/v2/inference_spec.rb

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def load_v2_inference(resource_path)
2222
simple_field = Mindee::Parsing::V2::Field::SimpleField
2323
object_field = Mindee::Parsing::V2::Field::ObjectField
2424
list_field = Mindee::Parsing::V2::Field::ListField
25-
field_conf = Mindee::Parsing::V2::Field::FieldConfidence
25+
field_confidence = Mindee::Parsing::V2::Field::FieldConfidence
2626

2727
describe 'simple' do
2828
it 'loads a blank inference with valid properties' do
@@ -264,19 +264,20 @@ def load_v2_inference(resource_path)
264264
expect(polygon[3][0]).to be_within(1e-12).of(0.948849)
265265
expect(polygon[3][1]).to be_within(1e-12).of(0.244565)
266266

267-
# Confidence can be a FieldConfidence instance or a String depending on implementation.
268-
conf_value =
269-
if date_field.confidence.respond_to?(:to_s)
270-
date_field.confidence.to_s
271-
else
272-
date_field.confidence
273-
end
274-
expect(conf_value).to eq('Medium')
275-
276-
# Optional strict check if equality supports comparing with FieldConfidence constants:
277-
if defined?(field_conf) && field_conf.respond_to?(:from_string)
278-
expect(conf_value).to eq(field_conf.from_string('Medium').to_s)
279-
end
267+
confidence = date_field.confidence
268+
expect(confidence).to be_a(field_confidence)
269+
# equality
270+
expect(confidence).to eq(field_confidence::MEDIUM)
271+
expect(confidence).to eq('Medium')
272+
expect(confidence).to eq(2)
273+
# less than or equal
274+
expect(confidence).to be_lteql(field_confidence::HIGH)
275+
expect(confidence).to be_lteql('High')
276+
expect(confidence).to be_lteql(3)
277+
# greater than or equal
278+
expect(confidence).to be_gteql(field_confidence::LOW)
279+
expect(confidence).to be_gteql('Low')
280+
expect(confidence).to be_gteql(1)
280281
end
281282
end
282283
end

0 commit comments

Comments
 (0)