From bb34b0292f1be50024b872e2cf51583fadea08d3 Mon Sep 17 00:00:00 2001 From: Mayank Aamseek Date: Fri, 3 Oct 2025 18:51:30 +0000 Subject: [PATCH] Merged in bugfix/methodology-breakout (pull request #723) Bugfix/methodology breakout * moved carveout after methodology breakout * Merge branch 'main' into bugfix/methodology-breakout * fixed unit_of_measure issues * carveout_cd fixes * pipeline error fix * Merged main into bugfix/methodology-breakout Approved-by: Katon Minhas --- fieldExtraction/src/investment/one_to_n_funcs.py | 12 ++++++++---- fieldExtraction/src/investment/prompt_calls.py | 3 ++- fieldExtraction/src/prompts/investment_prompts.json | 4 ++-- fieldExtraction/src/prompts/prompt_templates.py | 7 ++++--- fieldExtraction/tests/test_one_to_n.py | 7 +++---- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/fieldExtraction/src/investment/one_to_n_funcs.py b/fieldExtraction/src/investment/one_to_n_funcs.py index 02a0670..dd4b0e4 100644 --- a/fieldExtraction/src/investment/one_to_n_funcs.py +++ b/fieldExtraction/src/investment/one_to_n_funcs.py @@ -235,13 +235,13 @@ def breakout( - list[dict]: The processed reimbursement primary answers with breakout details. - dict[str, list]: The processed special case primary answers with breakout details. """ + reimbursement_primary_answers = methodology_breakout( + reimbursement_primary_answers, constants, filename + ) # Including base methodology breakout, grouper, and fee schedule # Standard Methodology Breakout reimbursement_primary_answers = carveout_check( reimbursement_primary_answers, constants, filename ) - reimbursement_primary_answers = methodology_breakout( - reimbursement_primary_answers, constants, filename - ) # Including base methodology breakout, grouper, and fee schedule # Special Case Breakout special_case_answers = special_case_breakout( @@ -264,12 +264,16 @@ def carveout_check( Returns: list[dict]: The updated reimbursement primary answers with carveout details. """ + # additional fields besides service and reimb term to pass to LLM for context + additional_fields_for_carveout = ['AARETE_DERIVED_REIMB_METHOD', 'UNIT_OF_MEASURE', 'REIMB_FEE_RATE' + , 'REIMB_PCT_RATE', 'REIMB_CONVERSION_FACTOR', 'FEE_SCHEDULE'] for answer_dict in reimbursement_primary_answers: service_term = answer_dict.get("SERVICE_TERM") reimb_term = answer_dict.get("REIMB_TERM") + base_reimb_answer_dict = {key: answer_dict[key] for key in additional_fields_for_carveout if key in answer_dict} carveout_answer = prompt_calls.prompt_carveout_check( - service_term, reimb_term, constants, filename + service_term, reimb_term, str(base_reimb_answer_dict), constants, filename ) answer_dict["CARVEOUT_CD"] = carveout_answer diff --git a/fieldExtraction/src/investment/prompt_calls.py b/fieldExtraction/src/investment/prompt_calls.py index e130886..8208414 100644 --- a/fieldExtraction/src/investment/prompt_calls.py +++ b/fieldExtraction/src/investment/prompt_calls.py @@ -210,11 +210,12 @@ def prompt_grouper_breakout( def prompt_carveout_check( - service_cd: str, reimb_method: str, constants: Constants, filename: str + service_cd: str, reimb_method: str, base_reimb_answer: str, constants: Constants, filename: str ): carveout_prompt = prompt_templates.CARVEOUT_CHECK( service_cd, reimb_method, + base_reimb_answer, constants.VALID_CARVEOUTS, ) logging.debug( diff --git a/fieldExtraction/src/prompts/investment_prompts.json b/fieldExtraction/src/prompts/investment_prompts.json index 9003d4c..74ebc88 100644 --- a/fieldExtraction/src/prompts/investment_prompts.json +++ b/fieldExtraction/src/prompts/investment_prompts.json @@ -9,7 +9,7 @@ "field_name" : "REIMB_TERM", "relationship" : "one_to_n", "field_type" : "reimbursement_level", - "prompt" : "Write the full sentence or paragraph in the text describing the reimbursement methodology, including any lesser of language, rates, or other important information." + "prompt" : "Write the full sentence or paragraph in the text describing the reimbursement methodology, including any lesser of language, rates, unit_of_measure and other important information." }, { "field_name": "LESSER_OF_IND", @@ -40,7 +40,7 @@ "field_name": "UNIT_OF_MEASURE", "relationship": "one_to_n", "field_type": "methodology_breakout", - "prompt": "Extract the unit of measure for flat rate or fee schedule reimbursements. Look for specific units like 'per day', 'per visit', 'per procedure', 'per ASA unit', etc. If a specific unit of measure is found and matches the valid values list, return that exact match. If a unit is mentioned but not in the valid values list, return 'Per Unit'. For flat rate methodologies where no specific unit is mentioned, default to 'Per Unit' regardless of whether procedure codes are present. For non-flat rate methodologies (percentages, bundled payments, etc.), return 'N/A'. Valid values are: {valid_values}", + "prompt": "Extract the unit of measure for flat rate or fee schedule reimbursements. Look for specific units like 'per day', 'per visit', 'per procedure', 'per ASA unit', etc. If a specific unit of measure is found and matches the valid values list, return that exact match. If a unit is mentioned but not in the valid values list, return 'Per Unit'. For flat rate methodologies where no specific unit is mentioned, default to 'Per Unit' regardless of whether procedure codes are present. For non-flat rate methodologies (percentages, bundled payments, etc.) where no unit is explicitly stated, return 'N/A'. Valid values are: {valid_values}. Don't assume units based on context; only extract explicitly stated units, except for the flat rate default rule.", "valid_values": "VALID_UNIT_OF_MEASURE" }, { diff --git a/fieldExtraction/src/prompts/prompt_templates.py b/fieldExtraction/src/prompts/prompt_templates.py index 8e9431f..eb1f109 100644 --- a/fieldExtraction/src/prompts/prompt_templates.py +++ b/fieldExtraction/src/prompts/prompt_templates.py @@ -1066,20 +1066,21 @@ Answer YES only if the exhibit constraint adds NO additional limitation beyond w Briefly explain your reasoning, then return YES or NO in |pipes|.""" -def CARVEOUT_CHECK(service, methodology, VALID_CARVEOUTS): +def CARVEOUT_CHECK(service, methodology, base_reimb_answer, VALID_CARVEOUTS): carveout_definitions = { carveout: definition for carveout, definition in VALID_CARVEOUTS.items() if definition } # Get only not None - return f"""Examine the combination of Service and Methodology below and identify which of the following cases it falls under. + return f"""Examine the combination of Service, Methodology and specific reimbursement method below and identify which of the following cases it falls under. Here are the Cases, with their definitions: {carveout_definitions} -Here is the Service and Methodology: +Here is the Service, Methodology and specific reimbursement method to analyze: Service: {service.replace('"', "'")} Methodology: {methodology.replace('"', "'")} +reimbursement method: {base_reimb_answer.replace('"', "'")} Determine which case description corresponds to the Service and Methodology combination. The Service and Methodology will always match one of the listed cases. If multiple cases apply, choose the one that describes how the payment changes over time rather than what service is being paid or choose a special case. Always return a value from the list of cases above; do not return 'N/A' or 'UNKNOWN'. diff --git a/fieldExtraction/tests/test_one_to_n.py b/fieldExtraction/tests/test_one_to_n.py index 12facae..1751aae 100644 --- a/fieldExtraction/tests/test_one_to_n.py +++ b/fieldExtraction/tests/test_one_to_n.py @@ -273,17 +273,16 @@ class TestOneToNFuncs(unittest.TestCase): ): """Test the breakout function processing flow.""" # Setup mocks - mock_carveout_check.return_value = [ - {"SERVICE_TERM": "Service", "REIMB_TERM": "Reimb", "CARVEOUT_CD": "N/A"} - ] mock_methodology_breakout.return_value = [ { "SERVICE_TERM": "Service", "REIMB_TERM": "Reimb", - "CARVEOUT_CD": "N/A", "METHODOLOGY": "Value", } ] + mock_carveout_check.return_value = [ + {"SERVICE_TERM": "Service", "REIMB_TERM": "Reimb", "CARVEOUT_CD": "N/A", "METHODOLOGY": "Value"} + ] mock_special_breakout.return_value = { "SPECIAL_CASE_FIELD": [ {