Skip to content

Commit 1eca103

Browse files
committed
fix the ruler offset
1 parent b5495e2 commit 1eca103

File tree

9 files changed

+226
-203
lines changed

9 files changed

+226
-203
lines changed

lib/idp_common_pkg/idp_common/assessment/models.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,15 @@ class BoundingBoxCoordinates(BaseModel):
106106

107107
@classmethod
108108
def from_corners(
109-
cls, x1: float, y1: float, x2: float, y2: float, scale: float = 1000.0
109+
cls,
110+
x1: float,
111+
y1: float,
112+
x2: float,
113+
y2: float,
114+
scale: float = 1000.0,
110115
) -> "BoundingBoxCoordinates":
111116
"""
112-
Create from corner coordinates.
117+
Create from corner coordinates in document space.
113118
114119
Args:
115120
x1, y1: Top-left corner in 0-scale range
@@ -129,6 +134,12 @@ def from_corners(
129134
width = (x2 - x1) / scale
130135
height = (y2 - y1) / scale
131136

137+
# Clamp to valid range
138+
left = min(max(left, 0.0), 1.0)
139+
top = min(max(top, 0.0), 1.0)
140+
width = min(width, 1.0 - left)
141+
height = min(height, 1.0 - top)
142+
132143
return cls(top=top, left=left, width=width, height=height)
133144

134145

@@ -201,7 +212,6 @@ class FieldAssessmentData(BaseModel):
201212
"""
202213

203214
confidence: float = Field(..., ge=0.0, le=1.0)
204-
value: Any = Field(None, description="The extracted value")
205215
reasoning: str = Field(..., description="Confidence reasoning")
206216
confidence_threshold: float = Field(..., ge=0.0, le=1.0)
207217
geometry: list[Geometry] | None = Field(
@@ -213,7 +223,6 @@ class FieldAssessmentData(BaseModel):
213223
def from_llm_response(
214224
cls,
215225
confidence: float,
216-
value: Any,
217226
reasoning: str,
218227
confidence_threshold: float,
219228
bbox_coords: list[float] | None = None,
@@ -227,18 +236,16 @@ def from_llm_response(
227236

228237
return cls(
229238
confidence=confidence,
230-
value=value,
231239
reasoning=reasoning,
232240
confidence_threshold=confidence_threshold,
233241
geometry=geometry,
234242
)
235243

236244
def to_explainability_format(self) -> dict[str, Any]:
237245
"""Convert to explainability_info format for frontend."""
238-
result = {
246+
result: dict[str, Any] = {
239247
"confidence": self.confidence,
240-
"value": self.value,
241-
"reasoning": self.reasoning,
248+
"confidence_reason": self.reasoning,
242249
"confidence_threshold": self.confidence_threshold,
243250
}
244251

lib/idp_common_pkg/idp_common/assessment/strands_models.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ def to_geometry(self) -> dict[str, Any]:
4040
class ConfidenceAssessment(BaseModel):
4141
"""Confidence assessment for an attribute value."""
4242

43-
value: Any = Field(..., description="The extracted value")
4443
confidence: float = Field(..., ge=0.0, le=1.0, description="Confidence score 0-1")
4544
reasoning: str = Field(..., description="Explanation for the confidence score")
4645
bounding_box: BoundingBox | None = Field(

lib/idp_common_pkg/idp_common/assessment/strands_service.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,6 @@ def _convert_to_assessment_result(
416416
# Create standardized field assessment data
417417
field_data = FieldAssessmentData.from_llm_response(
418418
confidence=assessment.confidence,
419-
value=assessment.value,
420419
reasoning=assessment.reasoning,
421420
confidence_threshold=task.confidence_threshold,
422421
bbox_coords=(

lib/idp_common_pkg/idp_common/assessment/strands_tools.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,12 @@ def view_image(input_data: ViewImageInput, agent: Agent) -> dict:
115115
"color": "red",
116116
}
117117

118-
# Draw the bounding box on the image (which already has ruler)
118+
# Draw the bounding box on the image (which has 30px margin for ruler)
119119
# Let drawing errors propagate - if we can't draw, something is wrong
120120
img_bytes = draw_bounding_boxes(
121121
img_bytes,
122122
[bbox_dict],
123-
has_ruler=True,
124-
ruler_width=30,
123+
margin_offset=30,
125124
)
126125

127126
logger.debug(

lib/idp_common_pkg/idp_common/config/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ def set_default_review_agent_model(self) -> Self:
140140

141141
return self
142142

143-
144143
@model_validator(mode="after")
145144
def set_default_review_agent_model(self) -> Self:
146145
"""Set review_agent_model to extraction model if not specified."""
@@ -206,7 +205,8 @@ class AssessmentConfig(BaseModel):
206205

207206
enabled: bool = Field(default=True, description="Enable assessment")
208207
model: Optional[str] = Field(
209-
default=None, description="Bedrock model ID for assessment"
208+
default="us.anthropic.claude-haiku-4-5-20251001-v1:0",
209+
description="Bedrock model ID for assessment",
210210
)
211211
system_prompt: str = Field(
212212
default="You are a document analysis assessment expert. Your role is to evaluate the confidence and accuracy of data extraction results by analyzing them against source documents.\n\nProvide accurate confidence scores for each assessment.",

lib/idp_common_pkg/idp_common/utils/grid_overlay.py

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,7 @@ def add_ruler_edges(
147147
def draw_bounding_boxes(
148148
image_data: bytes,
149149
bboxes: list[dict],
150-
has_ruler: bool = False,
151-
ruler_width: int = 30,
150+
margin_offset: int = 0,
152151
box_color: str = "red",
153152
box_width: int = 3,
154153
label_font_size: int = 12,
@@ -160,12 +159,11 @@ def draw_bounding_boxes(
160159
Args:
161160
image_data: Raw image bytes
162161
bboxes: List of bounding box dictionaries, each containing:
163-
- 'bbox': [x1, y1, x2, y2] in 0-1000 normalized scale
162+
- 'bbox': [x1, y1, x2, y2] in 0-1000 normalized scale (document space)
164163
- 'label': Optional label text for the box
165164
- 'color': Optional color override for this box
166165
- 'page': Optional page number (for multi-page docs)
167-
has_ruler: If True, account for ruler margins in coordinate calculation
168-
ruler_width: Width of ruler margin (only used if has_ruler=True)
166+
margin_offset: Pixel offset for top-left margin (e.g., if image has decorative margins)
169167
box_color: Default color for bounding boxes
170168
box_width: Line width for bounding boxes
171169
label_font_size: Font size for box labels
@@ -191,17 +189,11 @@ def draw_bounding_boxes(
191189
image = Image.open(io.BytesIO(image_data)).convert("RGBA")
192190
width, height = image.size
193191

194-
# If image has ruler edges, calculate the actual document area
195-
if has_ruler:
196-
doc_width = width - ruler_width
197-
doc_height = height - ruler_width
198-
offset_x = ruler_width
199-
offset_y = ruler_width
200-
else:
201-
doc_width = width
202-
doc_height = height
203-
offset_x = 0
204-
offset_y = 0
192+
# Calculate document area (excluding any margin offset)
193+
doc_width = width - margin_offset
194+
doc_height = height - margin_offset
195+
offset_x = margin_offset
196+
offset_y = margin_offset
205197

206198
# Create overlay for semi-transparent boxes
207199
overlay = Image.new("RGBA", (width, height), (0, 0, 0, 0))
@@ -331,12 +323,11 @@ def add_ruler_and_draw_boxes(
331323
label_interval=label_interval,
332324
)
333325

334-
# Then draw bounding boxes (accounting for ruler offset)
326+
# Then draw bounding boxes (accounting for margin offset from ruler)
335327
result = draw_bounding_boxes(
336328
image_with_ruler,
337329
bboxes,
338-
has_ruler=True,
339-
ruler_width=ruler_width,
330+
margin_offset=ruler_width,
340331
box_color=box_color,
341332
box_width=box_width,
342333
)

src/ui/src/components/common/confidence-alerts-utils.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ export const getFieldConfidenceInfo = (fieldName, explainabilityInfo, path = [],
297297
// nosemgrep: javascript.lang.security.audit.prototype-pollution.prototype-pollution-loop - Controlled data source, input validation performed upstream
298298
currentExplainabilityData = currentExplainabilityData[index];
299299
} else {
300+
console.log('getFieldConfidenceInfo: Array index out of bounds or invalid', { pathSegment, index, arrayLength: currentExplainabilityData.length });
300301
return { hasConfidenceInfo: false };
301302
}
302303
} else {
@@ -305,16 +306,19 @@ export const getFieldConfidenceInfo = (fieldName, explainabilityInfo, path = [],
305306
currentExplainabilityData = currentExplainabilityData[pathSegment];
306307
}
307308
} else {
309+
console.log('getFieldConfidenceInfo: Path traversal failed', { pathSegment, currentExplainabilityData });
308310
return { hasConfidenceInfo: false };
309311
}
310312
}
311313

312314
// Now look for the field in the current explainability data location
313315
if (!currentExplainabilityData || typeof currentExplainabilityData !== 'object') {
316+
console.log('getFieldConfidenceInfo: currentExplainabilityData not valid after path traversal', { fieldName, path, currentExplainabilityData });
314317
return { hasConfidenceInfo: false };
315318
}
316319

317320
const fieldData = currentExplainabilityData[fieldName];
321+
console.log('getFieldConfidenceInfo: Looking up field', { fieldName, path, fieldData, currentKeys: Object.keys(currentExplainabilityData) });
318322
if (!fieldData || typeof fieldData !== 'object') {
319323
return { hasConfidenceInfo: false };
320324
}

src/ui/src/components/document-viewer/JSONViewer.jsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,18 @@ const FormEditorView = ({ jsonData, onChange, isReadOnly, sectionData }) => {
133133
? { hasConfidenceInfo: false } // Array indices don't have confidence, their contents do
134134
: getFieldConfidenceInfo(cleanKey, explainabilityInfo, filteredParentPath);
135135

136+
// Debug logging for nested field confidence (groups and list items)
137+
if (!isArrayIndex && filteredParentPath.length > 0) {
138+
console.log('Nested field confidence lookup:', {
139+
fieldName: cleanKey,
140+
parentPath,
141+
filteredParentPath,
142+
hasExplainabilityInfo: !!explainabilityInfo,
143+
explainabilityInfoKeys: explainabilityInfo ? Object.keys(Array.isArray(explainabilityInfo) ? explainabilityInfo[0] || {} : explainabilityInfo) : [],
144+
confidenceInfo,
145+
});
146+
}
147+
136148
// Check if this field should be highlighted due to low confidence (legacy alert-based highlighting)
137149
const confidenceThresholdAlerts = sectionData?.ConfidenceThresholdAlerts || [];
138150
const highlightInfo = getFieldHighlightInfo(key, value, confidenceThresholdAlerts);

0 commit comments

Comments
 (0)