Build field suggestions from vision candidate fields
This commit is contained in:
parent
b06e260dad
commit
d542bcfdf8
|
|
@ -696,6 +696,76 @@ def build_vision_candidate_fields(classification: dict[str, Any]) -> list[dict[s
|
|||
|
||||
return fields
|
||||
|
||||
|
||||
def build_vision_field_suggestions(
|
||||
candidate_fields: list[dict[str, Any]],
|
||||
existing_fields: dict[str, Any] | None = None,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""
|
||||
Convert vision candidate fields into simple add/update/ignore suggestions.
|
||||
|
||||
This intentionally stays conservative:
|
||||
- high confidence merchant/time/item_count/money candidates are surfaced
|
||||
- symbol/noise is ignored
|
||||
- existing field comparison can be expanded later
|
||||
"""
|
||||
existing_fields = existing_fields or {}
|
||||
suggestions: list[dict[str, Any]] = []
|
||||
|
||||
type_to_existing_key = {
|
||||
"merchant_or_header": "merchant_raw",
|
||||
"transaction_time": "transaction_time",
|
||||
"item_count": "item_count",
|
||||
"money_amounts": "amount_candidates",
|
||||
}
|
||||
|
||||
for field in candidate_fields or []:
|
||||
candidate_type = field.get("candidate_type")
|
||||
if candidate_type == "symbol_or_noise":
|
||||
continue
|
||||
|
||||
confidence = float(field.get("confidence") or 0)
|
||||
ocr_confidence = field.get("ocr_confidence")
|
||||
value = field.get("value")
|
||||
|
||||
if not value:
|
||||
continue
|
||||
|
||||
min_conf = 0.40
|
||||
if candidate_type in {"merchant_or_header", "transaction_time"}:
|
||||
min_conf = 0.60
|
||||
elif candidate_type == "money_amounts":
|
||||
min_conf = 0.50
|
||||
|
||||
if confidence < min_conf:
|
||||
continue
|
||||
|
||||
existing_key = type_to_existing_key.get(candidate_type, candidate_type)
|
||||
existing_value = existing_fields.get(existing_key)
|
||||
|
||||
action = "add"
|
||||
if existing_value:
|
||||
action = "review_update" if str(existing_value).strip() != str(value).strip() else "already_present"
|
||||
|
||||
suggestions.append(
|
||||
{
|
||||
"suggestion_type": candidate_type,
|
||||
"target_field": existing_key,
|
||||
"action": action,
|
||||
"value": value,
|
||||
"existing_value": existing_value,
|
||||
"confidence": confidence,
|
||||
"ocr_confidence": ocr_confidence,
|
||||
"source": "vision_candidate_fields",
|
||||
"source_region_index": field.get("source_region_index"),
|
||||
"source_bbox": field.get("source_bbox"),
|
||||
"source_crop_path": field.get("source_crop_path"),
|
||||
"raw_text": field.get("raw_text"),
|
||||
}
|
||||
)
|
||||
|
||||
return suggestions
|
||||
|
||||
def build_vision_assisted_layout(source_layout: dict[str, Any] | None, vision_result: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
Convert vision analysis into normal layout_json.
|
||||
|
|
@ -716,6 +786,7 @@ def build_vision_assisted_layout(source_layout: dict[str, Any] | None, vision_re
|
|||
region_score,
|
||||
)
|
||||
candidate_fields = build_vision_candidate_fields(region_classification)
|
||||
field_suggestions = build_vision_field_suggestions(candidate_fields)
|
||||
|
||||
layout["vision_assisted"] = True
|
||||
layout["vision_assisted_status"] = normalized_vision.get("status", "unknown")
|
||||
|
|
@ -725,6 +796,7 @@ def build_vision_assisted_layout(source_layout: dict[str, Any] | None, vision_re
|
|||
layout["vision_region_score"] = region_score
|
||||
layout["vision_region_classification"] = region_classification
|
||||
layout["vision_candidate_fields"] = candidate_fields
|
||||
layout["vision_field_suggestions"] = field_suggestions
|
||||
layout["layout_sync_source"] = "vision_assisted"
|
||||
layout["layout_needs_review"] = True
|
||||
return layout
|
||||
|
|
|
|||
Loading…
Reference in New Issue