Merged in bugfix/dynamic-primary-issues (pull request #669)
Bugfix/dynamic primary issues * add LOB_RELATIONSHIP prompt * Add test script * Integrate prompt * Update one-to-one passing rules * Merged main into bugfix/dynamic-primary-issues * Remove promt * replace quotes Approved-by: Alex Galarce
This commit is contained in:
@@ -40,6 +40,7 @@ def fill_na_mapping(answer_dicts):
|
||||
"AARETE_DERIVED_PROGRAM",
|
||||
"constants/mappings/crosswalk_program_lob.json",
|
||||
)
|
||||
answer_dict["LOB_RELATIONSHIP"] = "Exclusive"
|
||||
|
||||
# Fill AARETE_DERIVED_LOB from PRODUCT
|
||||
if string_utils.is_empty(answer_dict.get("AARETE_DERIVED_LOB")):
|
||||
@@ -49,6 +50,7 @@ def fill_na_mapping(answer_dicts):
|
||||
"PRODUCT",
|
||||
"constants/mappings/crosswalk_product_lob.json",
|
||||
)
|
||||
answer_dict["LOB_RELATIONSHIP"] = "Exclusive"
|
||||
return answer_dicts
|
||||
|
||||
|
||||
|
||||
@@ -26,20 +26,23 @@ def prompt_dynamic(text, field_prompts, filename):
|
||||
return llm_answer_final
|
||||
|
||||
|
||||
def add_full_context_field(one_to_one_fields, field_to_add):
|
||||
def add_full_context_field(one_to_one_fields, field_to_add, answer_dicts):
|
||||
field_to_add.field_type = "full_context"
|
||||
field_to_add.relationship = "one_to_one"
|
||||
|
||||
if field_to_add.allow_na:
|
||||
field_to_add.prompt = (
|
||||
field_to_add.prompt
|
||||
+ " Only answer if the answer applies to the ENTIRE contract. Otherwise, answer N/A."
|
||||
)
|
||||
else:
|
||||
field_to_add.prompt = (
|
||||
field_to_add.prompt
|
||||
+ " Do NOT leave this field N/A. Choose the most appropriate answer based on the context."
|
||||
)
|
||||
# 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]
|
||||
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
|
||||
|
||||
field_to_add.prompt = (
|
||||
field_to_add.prompt
|
||||
+ prompt_templates.FULL_CONTEXT_ADDITIONAL_INSTRUCTIONS(field_to_add.allow_na)
|
||||
)
|
||||
|
||||
one_to_one_fields.add_field(field_to_add)
|
||||
return one_to_one_fields
|
||||
|
||||
@@ -94,7 +97,7 @@ def get_dynamic_one_to_one_fields(answer_dicts):
|
||||
field_name=field.base_field,
|
||||
)
|
||||
one_to_one_fields = add_full_context_field(
|
||||
one_to_one_fields, field_to_add
|
||||
one_to_one_fields, field_to_add, answer_dicts
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -113,7 +116,7 @@ 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)
|
||||
one_to_one_fields = add_full_context_field(one_to_one_fields, field_to_add, answer_dicts)
|
||||
return one_to_one_fields
|
||||
|
||||
|
||||
|
||||
@@ -177,6 +177,9 @@ def run_one_to_n_prompts(filename, exhibit_dict, all_exhibit_headers, constants)
|
||||
################## Crosswalk Fields ##################
|
||||
one_to_n_results = aarete_derived.get_crosswalk_fields(one_to_n_results)
|
||||
|
||||
################## Determine LOB Relationship ##################
|
||||
one_to_n_results = one_to_n_funcs.get_lob_relationship(one_to_n_results, exhibit_dict, filename)
|
||||
|
||||
################## Fill NA Mapping ##################
|
||||
one_to_n_results = aarete_derived.fill_na_mapping(one_to_n_results)
|
||||
|
||||
|
||||
@@ -1367,3 +1367,28 @@ def outlier_terms_breakout(outlier_term, filename: str) -> dict:
|
||||
llm_response = llm_utils.invoke_claude(prompt, "sonnet_latest", filename)
|
||||
outlier_answers = string_utils.universal_json_load(llm_response) or {}
|
||||
return outlier_answers
|
||||
|
||||
|
||||
def get_lob_relationship(answer_dicts, exhibit_dict, filename):
|
||||
|
||||
for answer_dict in answer_dicts:
|
||||
# Process relationship if LOB is present and either Program or Product is present
|
||||
if not string_utils.is_empty(answer_dict.get("AARETE_DERIVED_LOB")) and (not string_utils.is_empty(answer_dict.get("AARETE_DERIVED_PROGRAM")) or not string_utils.is_empty(answer_dict.get("AARETE_DERIVED_PRODUCT"))):
|
||||
# Get values
|
||||
exhibit_text = exhibit_dict.get(answer_dict.get("EXHIBIT_PAGE"))
|
||||
programs_and_products = answer_dict.get("AARETE_DERIVED_PRODUCT", "") + "|" + answer_dict.get("AARETE_DERIVED_PROGRAM", "")
|
||||
dynamic_primary_values = f"LOB: {answer_dict.get("AARETE_DERIVED_LOB")}\nPROGRAM: {programs_and_products}"
|
||||
|
||||
# Prompt LLM
|
||||
prompt = prompt_templates.LOB_RELATIONSHIP(exhibit_text, dynamic_primary_values)
|
||||
llm_answer_raw = llm_utils.invoke_claude(prompt, model_id="sonnet_latest", filename=filename)
|
||||
llm_answer_final = string_utils.extract_text_from_delimiters(llm_answer_raw, Delimiter.PIPE)
|
||||
|
||||
# Assign answer
|
||||
answer_dict["LOB_RELATIONSHIP"] = llm_answer_final
|
||||
|
||||
return answer_dicts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1091,3 +1091,47 @@ Return your answers in valid JSON format using the exact field names from the qu
|
||||
|
||||
**Important:** Base your answers ONLY on the outlier terms provided. Do not make assumptions or add information not present in the contract language.
|
||||
"""
|
||||
|
||||
|
||||
def LOB_RELATIONSHIP(exhibit_text, dynamic_primary_values):
|
||||
return f"""You will be presented with an exhibit from a Payer-Provider contract.
|
||||
|
||||
[BACKGROUND]
|
||||
- In healthcare, there are generally multiple Programs for any given LOB.
|
||||
- For example, under the Medicaid LOB, there can be the Programs CHIP, STAR, Medi-Cal, etc.
|
||||
- The Exhibit shown contains a number of reimbursement terms, which apply to different LOB and Programs.
|
||||
|
||||
It was previously identified that the Exhibit contains the following LOB and Programs:
|
||||
{dynamic_primary_values}
|
||||
|
||||
[INSTRUCTIONS]
|
||||
- Determine if the Exhibit presents an "Inclusive" relationship or "Exclusive" relationship between LOB and Program.
|
||||
- Inclusive Relationship: When the contract refers to an LOB, including (but not limited to) the programs in the list.
|
||||
- Some examples of language indicating an inclusive relationship are: "Medicaid and CHIP", "Medicare, including Medicare Advantage", and "Duals, including all special needs programs"
|
||||
- Exclusive Relationship: When the contract refers to an LOB and Programs, but the information applies to JUST those specific programs.
|
||||
- Some examples of language indicating an exlusive relationship are "Medicaid: CHIP", "Medicare advantage only", and "Duals - only the following SNP programs"
|
||||
- If the programs are represented with different sections of the Exhibit under the same higher-level LOB section, this is indicative of an Exclusive relationship.
|
||||
- Closely read the text, then write either |Inclusive| or |Exclusive| to indicate the nature of the relationship.
|
||||
|
||||
[CONTEXT]
|
||||
Here is the Exhibit to be analyzed:
|
||||
{exhibit_text.replace('"', "'")}
|
||||
|
||||
[OUTPUT]
|
||||
Briefly explain your reasoning, then put your final answer in |pipes|.
|
||||
"""
|
||||
|
||||
|
||||
def FULL_CONTEXT_ADDITIONAL_INSTRUCTIONS(allow_na):
|
||||
if allow_na:
|
||||
return " Only provide an answer if that answer clearly applies to the ENTIRE contract. Otherwise, answer N/A."
|
||||
else:
|
||||
return " Do NOT leave this field N/A. Choose the most appropriate answer based on the context."
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user