diff --git a/fieldExtraction/constants/investment_columns.py b/fieldExtraction/constants/investment_columns.py index b04d379..dc4dffe 100644 --- a/fieldExtraction/constants/investment_columns.py +++ b/fieldExtraction/constants/investment_columns.py @@ -132,20 +132,10 @@ COLUMN_ORDER = [ "OUTLIER_EXCLUSION_CD_DESC", "FACILITY_ADJUSTMENT_TERM", "DSH_IND", - "DSH_PCT_RATE", - "DSH_FEE_RATE", "IME_IND", - "IME_PCT_RATE", - "IME_FEE_RATE", "NTAP_IND", - "NTAP_PCT_RATE", - "NTAP_FEE_RATE", "UC_IND", - "UC_PCT_RATE", - "UC_FEE_RATE", "GME_IND", - "GME_PCT_RATE", - "GME_FEE_RATE", "RATE_ESCALATOR_IND", "RATE_ESCALATOR_TERM", "RATE_ESCALATOR_MAX_RATE_INC_PCT", diff --git a/fieldExtraction/src/investment/one_to_n_funcs.py b/fieldExtraction/src/investment/one_to_n_funcs.py index 3eac07a..2bebb36 100644 --- a/fieldExtraction/src/investment/one_to_n_funcs.py +++ b/fieldExtraction/src/investment/one_to_n_funcs.py @@ -47,6 +47,11 @@ def exhibit_level( exhibit_text, exhibit_level_fields, constants, filename ) + exhibit_level_answers = prompt_calls.prompt_exhibit_level_breakout( + exhibit_level_answers, filename + ) + + # Dynamic Primary exhibit_level_answers, dynamic_reimbursement_fields = dynamic_funcs.dynamic_primary( exhibit_text, diff --git a/fieldExtraction/src/investment/prompt_calls.py b/fieldExtraction/src/investment/prompt_calls.py index 7a26fb2..6be03cf 100644 --- a/fieldExtraction/src/investment/prompt_calls.py +++ b/fieldExtraction/src/investment/prompt_calls.py @@ -22,13 +22,54 @@ def prompt_exhibit_level( exhibit_text, exhibit_level_fields.print_prompt_dict(constants) ) llm_answer_raw = llm_utils.invoke_claude( - prompt, "legacy_sonnet", filename, max_tokens=8192 + prompt, "sonnet_latest", filename, max_tokens=8192 ) logging.debug(f"LLM raw output for {filename}: {llm_answer_raw}") + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + + + return llm_answer_final - +def prompt_exhibit_level_breakout(exhibit_level_answers: dict[str, str], filename: str) -> dict[str, str]: + """ + Process exhibit-level answers by breaking out facility adjustment terms using an LLM. + This function checks if a FACILITY_ADJUSTMENT_TERM exists in the exhibit-level answers, + and if present, invokes Claude LLM to break it down into structured components. The + resulting parsed data is then merged back into the exhibit-level answers dictionary. + Args: + exhibit_level_answers (dict[str, str]): A dictionary containing exhibit-level + field names as keys and their corresponding values as strings. Must contain + a "FACILITY_ADJUSTMENT_TERM" key to trigger processing. + filename (str): The name of the file being processed, used for logging and + tracking purposes in the LLM invocation. + Returns: + dict[str, str]: The updated exhibit_level_answers dictionary with additional + fields extracted from the FACILITY_ADJUSTMENT_TERM breakout, or the original + dictionary if no FACILITY_ADJUSTMENT_TERM was present. + Raises: + Any exceptions raised by llm_utils.invoke_claude() or string_utils.universal_json_load() + will propagate to the caller. + """ + + # FACILITY_ADJUSTMENT_BREAKOUT + if not string_utils.is_empty(exhibit_level_answers.get("FACILITY_ADJUSTMENT_TERM", "")): + prompt = prompt_templates.FACILITY_ADJUSTMENT_BREAKOUT( + exhibit_level_answers["FACILITY_ADJUSTMENT_TERM"] + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt=prompt, + model_id="sonnet_latest", + filename=filename + ) + print("Facility Adjustment: ", llm_answer_raw) + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + exhibit_level_answers.update(llm_answer_final) + + return exhibit_level_answers + + def prompt_exhibit_lesser( exhibit_text: str, exhibit_level_answers: dict, diff --git a/fieldExtraction/src/prompts/investment_prompts.json b/fieldExtraction/src/prompts/investment_prompts.json index 880486c..ef1548e 100644 --- a/fieldExtraction/src/prompts/investment_prompts.json +++ b/fieldExtraction/src/prompts/investment_prompts.json @@ -821,7 +821,7 @@ { "field_name": "FACILITY_ADJUSTMENT_TERM", "relationship": "one_to_n", - "field_type": "special_case_check", + "field_type": "exhibit_level", "prompt": "Extract any language in the Exhibit that relates to Disproportionate Share Hospital ('DSH'), Direct Graduate Medical Education ('GME'), Indirect Medical Education('IME'), New Technology Add-on Payment ('NTAP'), or Uncompensated Care ('UC'). Extract the full sentence or sentences.", "breakout_template": "FACILITY_ADJUSTMENT_BREAKOUT" }, @@ -831,90 +831,30 @@ "field_type": "facility_adjustment_breakout", "prompt": "Are adjustments for Disproportionate Share Hospitals (DSH) included in the reimbursement? Return 'Y' or 'N'." }, - { - "field_name": "DSH_PCT_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If DSH adjustments are included, and they are listed as a % Rate, write that % rate here. If DSH is not included, write 'N/A'." - }, - { - "field_name": "DSH_FEE_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If DSH adjustments are included, and they are listed as a $ value, write that $ value here. If DSH is not included, write 'N/A'." - }, { "field_name": "IME_IND", "relationship": "one_to_n", "field_type": "facility_adjustment_breakout", "prompt": "Are adjustments for Indirect Medical Education (IME) included in the reimbursement? Return 'Y' or 'N'." }, - { - "field_name": "IME_PCT_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If IME adjustments are included, and they are listed as a % Rate, write that % rate here. If IME is not included, write 'N/A'." - }, - { - "field_name": "IME_FEE_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If IME adjustments are included, and they are listed as a $ value, write that $ value here. If IME is not included, write 'N/A'." - }, { "field_name": "NTAP_IND", "relationship": "one_to_n", "field_type": "facility_adjustment_breakout", "prompt": "Are adjustments for New Technology Add-On Payments (NTAP) included in the reimbursement? Return 'Y' or 'N'." }, - { - "field_name": "NTAP_PCT_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If NTAP adjustments are included, and they are listed as a % Rate, write that % rate here. If NTAP is not included, write 'N/A'." - }, - { - "field_name": "NTAP_FEE_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If NTAP adjustments are included, and they are listed as a $ value, write that $ value here. If NTAP is not included, write 'N/A'." - }, { "field_name": "UC_IND", "relationship": "one_to_n", "field_type": "facility_adjustment_breakout", "prompt": "Are adjustments for Uncompensated Care ('UC') included in the reimbursement? Return 'Y' or 'N'." }, - { - "field_name": "UC_PCT_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If UC adjustments are included, and they are listed as a % Rate, write that % rate here. If UC is not included, write 'N/A'." - }, - { - "field_name": "UC_FEE_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If UC adjustments are included, and they are listed as a $ value, write that $ value here. If UC is not included, write 'N/A'." - }, { "field_name": "GME_IND", "relationship": "one_to_n", "field_type": "facility_adjustment_breakout", "prompt": "Are adjustments for Graduate Medical Education (GME) included in the reimbursement? Return 'Y' or 'N'." }, - { - "field_name": "GME_PCT_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If GME adjustments are included, and they are listed as a % Rate, write that % rate here. If GME is not included, write 'N/A'." - }, - { - "field_name": "GME_FEE_RATE", - "relationship": "one_to_n", - "field_type": "facility_adjustment_breakout", - "prompt": "If GME adjustments are included, and they are listed as a $ value, write that $ value here. If GME is not included, write 'N/A'." - }, { "field_name": "NUM_AVAILABLE_SIGNATORY_LINE_COUNT", "relationship": "one_to_one",