Merged in bugfix/dynamic-reimbursement-primary-nv-issues (pull request #687)
Bugfix/dynamic reimbursement primary nv issues * Add reimb_level_prompt to Field class for dynamic reimbursement handling * Add reimb_level_prompt for dynamic extraction of LOBs, Networks, Products, and Programs * Merged main into bugfix/dynamic-reimbursement-primary-nv-issues Approved-by: Katon Minhas
This commit is contained in:
@@ -34,7 +34,9 @@ def add_full_context_field(one_to_one_fields, field_to_add, answer_dicts):
|
||||
# Special Handling for Program and Product:
|
||||
# If there are multiple non-empty AARETE_DERIVED_LOB values in the contract, don't ask for Program or Product full context
|
||||
if field_to_add.field_name in ["PROGRAM", "PRODUCT"]:
|
||||
lob_values = [answer_dict.get("AARETE_DERIVED_LOB", "") for answer_dict in answer_dicts]
|
||||
lob_values = [
|
||||
answer_dict.get("AARETE_DERIVED_LOB", "") for answer_dict in answer_dicts
|
||||
]
|
||||
non_empty_lobs = [lob for lob in lob_values if not string_utils.is_empty(lob)]
|
||||
if len(non_empty_lobs) > 1:
|
||||
return one_to_one_fields
|
||||
@@ -117,15 +119,15 @@ def get_dynamic_one_to_one_fields(answer_dicts):
|
||||
file_path=config.FIELD_JSON_PATH,
|
||||
field_name=field.base_field,
|
||||
)
|
||||
one_to_one_fields = add_full_context_field(one_to_one_fields, field_to_add, answer_dicts)
|
||||
one_to_one_fields = add_full_context_field(
|
||||
one_to_one_fields, field_to_add, answer_dicts
|
||||
)
|
||||
return one_to_one_fields
|
||||
|
||||
|
||||
def prompt_dynamic_primary(exhibit_text, constants, field, filename, TEMPLATE):
|
||||
# Prompt Exhibit Header
|
||||
prompt = TEMPLATE(
|
||||
exhibit_text, field.field_name, field.get_prompt(constants)
|
||||
)
|
||||
prompt = TEMPLATE(exhibit_text, field.field_name, field.get_prompt(constants))
|
||||
logging.debug(f"Dynamic primary prompt for {filename}; {field}: {prompt}")
|
||||
claude_answer_raw = llm_utils.invoke_claude(prompt, "sonnet_latest", filename)
|
||||
logging.debug(f"Claude answer for {filename}; {field}: {claude_answer_raw}")
|
||||
@@ -170,7 +172,11 @@ def get_dynamic_primary(
|
||||
exhibit_header_answer = "N/A"
|
||||
else:
|
||||
exhibit_header_answer = prompt_dynamic_primary(
|
||||
exhibit_header, constants, field, filename, prompt_templates.DYNAMIC_PRIMARY_HEADER
|
||||
exhibit_header,
|
||||
constants,
|
||||
field,
|
||||
filename,
|
||||
prompt_templates.DYNAMIC_PRIMARY_HEADER,
|
||||
)
|
||||
|
||||
# If there is exactly ONE Non-N/A answer in the header
|
||||
@@ -185,20 +191,29 @@ def get_dynamic_primary(
|
||||
and "|" in exhibit_header_answer
|
||||
):
|
||||
field.update_valid_values(exhibit_header_answer)
|
||||
field.prompt = (
|
||||
field.prompt
|
||||
+ ". Ensure ALL values that apply to the specific reimbursement term are included."
|
||||
)
|
||||
if field.reimb_level_prompt:
|
||||
field.prompt = field.reimb_level_prompt
|
||||
else:
|
||||
field.prompt = (
|
||||
field.prompt
|
||||
+ ". Ensure ALL values that apply to the specific reimbursement term are included."
|
||||
)
|
||||
reimbursement_level_fields.add_field(field)
|
||||
dynamic_fields.remove_field(field.field_name)
|
||||
# If there are ZERO Non-N/A answers in the header
|
||||
else:
|
||||
exhibit_text_answer = prompt_dynamic_primary(
|
||||
exhibit_chunk, constants, field, filename, prompt_templates.DYNAMIC_PRIMARY_TEXT
|
||||
exhibit_chunk,
|
||||
constants,
|
||||
field,
|
||||
filename,
|
||||
prompt_templates.DYNAMIC_PRIMARY_TEXT,
|
||||
)
|
||||
# If there is at least ONE Non-N/A answers in the Exhibit
|
||||
if not string_utils.is_empty(exhibit_text_answer):
|
||||
field.update_valid_values(exhibit_text_answer + " | N/A")
|
||||
if field.reimb_level_prompt:
|
||||
field.prompt = field.reimb_level_prompt
|
||||
reimbursement_level_fields.add_field(field)
|
||||
dynamic_fields.remove_field(field.field_name)
|
||||
# If the field is not found, add to Exhibit-Level answers (the answer will be N/A or similar)
|
||||
@@ -216,7 +231,7 @@ def get_dynamic_answers(
|
||||
constants: Constants,
|
||||
):
|
||||
"""
|
||||
Processes dynamic fields from exhibit header and chunk text.
|
||||
Processes dynamic (code and provider info) fields from exhibit header and chunk text.
|
||||
|
||||
Args:
|
||||
exhibit_chunk (str): The main text chunk of the exhibit
|
||||
@@ -247,10 +262,13 @@ def get_dynamic_answers(
|
||||
if not string_utils.is_empty(answer):
|
||||
field = dynamic_fields.get_field(field_name)
|
||||
field.update_valid_values(answer)
|
||||
field.prompt = (
|
||||
field.prompt
|
||||
+ ". Ensure ALL values that apply to the specific reimbursement term are included."
|
||||
)
|
||||
if field.reimb_level_prompt:
|
||||
field.prompt = field.reimb_level_prompt
|
||||
else:
|
||||
field.prompt = (
|
||||
field.prompt
|
||||
+ ". Ensure ALL values that apply to the specific reimbursement term are included."
|
||||
)
|
||||
reimbursement_level_fields.add_field(field)
|
||||
dynamic_fields.remove_field(field_name)
|
||||
|
||||
|
||||
@@ -43,6 +43,11 @@ class Field:
|
||||
self.relationship = field_dict["relationship"]
|
||||
self.field_type = field_dict["field_type"]
|
||||
self.prompt = field_dict["prompt"] if "prompt" in field_dict else None
|
||||
self.reimb_level_prompt = (
|
||||
field_dict["reimb_level_prompt"]
|
||||
if "reimb_level_prompt" in field_dict
|
||||
else None
|
||||
)
|
||||
self.valid_values = (
|
||||
field_dict["valid_values"] if "valid_values" in field_dict else None
|
||||
)
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
"relationship" : "one_to_n",
|
||||
"field_type" : "dynamic_primary",
|
||||
"prompt" : "Extract ONLY LOBs that are **explicitly mentioned** in the text. Do NOT extract based on Programs, Products, context, implications, or any other form of inference. Choose LOBs ONLY from the following values: {valid_values}. ",
|
||||
"reimb_level_prompt": "What LOB applies specifically to this service-reimbursement pair? Extract only LOBs that are directly associated with this particular service or methodology. Choose ONLY from: {valid_values}. If no LOB is specifically associated with this service-reimbursement pair, return 'N/A'.",
|
||||
"valid_values" : "VALID_LOBS"
|
||||
},
|
||||
{
|
||||
@@ -127,6 +128,7 @@
|
||||
"relationship" : "one_to_n",
|
||||
"field_type" : "dynamic_primary",
|
||||
"prompt" : "List any Networks explicitly stated in the text. Choose ONLY from the following: {valid_values}.",
|
||||
"reimb_level_prompt": "What Network applies specifically to this service-reimbursement pair? Look for network references that are directly associated with this particular service or methodology. Choose ONLY from: {valid_values}. If no network is specifically associated with this service-reimbursement pair, return 'N/A'.",
|
||||
"valid_values" : "VALID_NETWORKS"
|
||||
},
|
||||
{
|
||||
@@ -142,6 +144,7 @@
|
||||
"relationship" : "one_to_n",
|
||||
"field_type" : "dynamic_primary",
|
||||
"prompt" : "List any Products explicitly stated in the text. Look for the brand name of a health plan or product. Do not include the name of the entire healthplan (such as 'Molina', 'Centene' etc) - rather, look for the Product that these healthplans offer. Valid products include, but are not limited to, the following: {valid_values}. If any of the values in this list are mentioned, return them exactly as written in the list. Use reasonable judgment for obvious synonyms and equivalent terms.",
|
||||
"reimb_level_prompt" : "What Product applies specifically to this service-reimbursement pair? Look for product references that are directly associated with this particular service or methodology. Choose ONLY from: {valid_values}. If no product is specifically associated with this service-reimbursement pair, return 'N/A'.",
|
||||
"valid_values" : "VALID_PRODUCTS"
|
||||
},
|
||||
{
|
||||
@@ -156,6 +159,7 @@
|
||||
"relationship" : "one_to_n",
|
||||
"field_type" : "dynamic_primary",
|
||||
"prompt" : "List any Programs explicitly stated in the text. Choose ONLY from the following: {valid_values}. Note that 'Medicare' does NOT mean 'Medicare Advantage'. If only 'Medicare' is seen, do not write 'Medicare Advantage'. Choose the answer from the list that most closely matches what is found in the text. Use reasonable judgment for obvious synonyms and equivalent terms (e.g., 'Medicare-Medicaid Program' matches 'Medicare-Medicaid Plan').",
|
||||
"reimb_level_prompt" : "What Program applies specifically to this service-reimbursement pair? Look for program references that are directly associated with this particular service or reimbursement methodology. Choose ONLY from: {valid_values}. Note: 'Medicare' alone does NOT mean 'Medicare Advantage'. Use reasonable judgment for synonyms (e.g., 'Medicare-Medicaid Program' matches 'Medicare-Medicaid Plan'). If no program is specifically associated with this service-reimbursement pair, return 'N/A'.",
|
||||
"valid_values" : "VALID_PROGRAMS"
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user