Merged in feature/carveout_ind (pull request #372)
Initialized CONTRACT_CARVEOUT_IND and CONTRACT_CARVEOUT_CD * add carveout list * Write carveout ind prompt and integrated * Remove None carveouts * Add TODO for carveout check * Fill out remaining carveouts * Merged main into feature/carveout_ind Approved-by: Alex Galarce
This commit is contained in:
@@ -65,3 +65,20 @@ VALID_REIMBURSEMENT_METHOD = [
|
||||
"DOFR"
|
||||
]
|
||||
|
||||
VALID_CARVEOUTS = {
|
||||
"UNLISTED_CODE" : "Describes payments for codes that are not listed on a fee schedule",
|
||||
"NEVER_EVENT" : "Indicates that Never Events (e.g. sepsis acquired while inpatient) will not be covered.",
|
||||
"EXPERIMENTAL_INVESTIGATIONAL" : "Describes payments for experimental and investigational procedures.",
|
||||
"NOT_MEDICALLY_NECESSARY" : "Describes payments for procedures deemed not medically necessary (or medically unnecessary)",
|
||||
"GLOBAL_SERVICES" : None,
|
||||
"BUNDLED_CODES" : "Indicates that payment for bundles of codes shall be at a reduced rate.",
|
||||
"MULTIPLE_PROCEDURE_REDUCTIONS" : 'Describes payments for multiple procedures or surgeries performed on the same day as each other.',
|
||||
"MIDLEVELS" : None,
|
||||
"TECHNICAL_COMPONENT" : "If Modifier TC (technical component) is present.",
|
||||
"PROFESSIONAL_COMPONENT" : "If Modifier 26 (professional component) is present.",
|
||||
"DIAGNOSTIC_PROCEDURES" : "Describes payments for diagnostic procedures.",
|
||||
"PREADMISSION" : None,
|
||||
"POST_DISCHARGE" : None,
|
||||
"READMISSIONS" : "Describes payment for subsequent admission with the same diagnostic category of codes as the initial admission.",
|
||||
}
|
||||
|
||||
|
||||
@@ -143,27 +143,56 @@ def get_reimbursement_primary(reimbursement_level_fields, exhibit_text, filename
|
||||
llm_answer_final = string_utils.universal_json_load(llm_answer_raw)
|
||||
return llm_answer_final
|
||||
|
||||
def get_carveout_ind(reimbursement_primary_answers, filename):
|
||||
already_seen = {}
|
||||
carveout_answers = []
|
||||
|
||||
for answer_dict in reimbursement_primary_answers:
|
||||
contract_service_cd, contract_reimbursement_method = answer_dict.get("CONTRACT_SERVICE_CD_OR_DESC"), answer_dict.get("CONTRACT_REIMBURSEMENT_METHOD")
|
||||
if contract_service_cd and contract_reimbursement_method:
|
||||
llm_answer_final = already_seen.setdefault(
|
||||
contract_reimbursement_method,
|
||||
string_utils.extract_text_from_delimiters(
|
||||
llm_utils.invoke_claude(
|
||||
investment_prompts.CARVEOUT_CHECK(contract_service_cd, contract_reimbursement_method),
|
||||
config.MODEL_ID_CLAUDE35_SONNET,
|
||||
filename
|
||||
),
|
||||
Delimiter.PIPE)
|
||||
)
|
||||
answer_dict['CONTRACT_CARVEOUT_CD'] = llm_answer_final
|
||||
answer_dict['CONTRACT_CARVEOUT_IND'] = 'N' if 'N/A' in llm_answer_final else 'Y'
|
||||
carveout_answers.append(answer_dict)
|
||||
|
||||
return carveout_answers
|
||||
|
||||
def get_methodology_breakout(reimbursement_primary_answers, filename):
|
||||
already_seen = {}
|
||||
|
||||
|
||||
methodology_breakout_questions = FieldSet(file_path=config.FIELD_JSON_PATH, field_type="methodology_breakout").get_prompt_dict()
|
||||
methodology_breakout_answers = []
|
||||
|
||||
# TODO DAIP2-86: Add check if there is a CARVEOUT that would require a different methodology breakout
|
||||
|
||||
for answer_dict in reimbursement_primary_answers:
|
||||
if "CONTRACT_REIMBURSEMENT_METHOD" in answer_dict.keys():
|
||||
contract_reimbursement_method = answer_dict["CONTRACT_REIMBURSEMENT_METHOD"]
|
||||
if contract_reimbursement_method not in already_seen.keys():
|
||||
prompt = investment_prompts.REIMBURSEMENT_METHODOLOGY_BREAKOUT(answer_dict["CONTRACT_REIMBURSEMENT_METHOD"], methodology_breakout_questions)
|
||||
llm_answer_raw = llm_utils.invoke_claude(prompt, config.MODEL_ID_CLAUDE35_SONNET, filename)
|
||||
llm_answer_final = string_utils.universal_json_load(llm_answer_raw)
|
||||
already_seen[contract_reimbursement_method] = llm_answer_final
|
||||
else:
|
||||
llm_answer_final = already_seen[contract_reimbursement_method]
|
||||
for breakout_dict in llm_answer_final:
|
||||
breakout_answer = {**answer_dict, **breakout_dict}
|
||||
methodology_breakout_answers.append(breakout_answer)
|
||||
contract_reimbursement_method = answer_dict.get("CONTRACT_REIMBURSEMENT_METHOD")
|
||||
if contract_reimbursement_method:
|
||||
llm_answer_final = already_seen.setdefault(
|
||||
contract_reimbursement_method,
|
||||
string_utils.universal_json_load(
|
||||
llm_utils.invoke_claude(
|
||||
investment_prompts.REIMBURSEMENT_METHODOLOGY_BREAKOUT(contract_reimbursement_method, methodology_breakout_questions),
|
||||
config.MODEL_ID_CLAUDE35_SONNET,
|
||||
filename
|
||||
)
|
||||
)
|
||||
)
|
||||
for breakout_dict in llm_answer_final:
|
||||
methodology_breakout_answers.append({**answer_dict, **breakout_dict})
|
||||
return methodology_breakout_answers
|
||||
|
||||
|
||||
|
||||
def reimbursement_level(exhibit_text, filename, reimbursement_level_fields):
|
||||
"""
|
||||
Processes reimbursement-level fields.
|
||||
@@ -179,6 +208,8 @@ def reimbursement_level(exhibit_text, filename, reimbursement_level_fields):
|
||||
"""
|
||||
|
||||
reimbursement_primary_answers = get_reimbursement_primary(reimbursement_level_fields, exhibit_text, filename) # Returns list of dicts
|
||||
carveout_answers = get_carveout_ind(reimbursement_primary_answers, filename)
|
||||
|
||||
methodology_breakout_answers = get_methodology_breakout(reimbursement_primary_answers, filename)
|
||||
|
||||
return methodology_breakout_answers
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from src.constants.investment_values import VALID_LOBS, VALID_NETWORKS, VALID_PROGRAMS, VALID_CONTRACT_CLAIM_TYPE, VALID_REIMBURSEMENT_METHOD
|
||||
from src.constants.investment_values import VALID_LOBS, VALID_NETWORKS, VALID_PROGRAMS, VALID_CONTRACT_CLAIM_TYPE, VALID_REIMBURSEMENT_METHOD, VALID_CARVEOUTS
|
||||
import src.constants.valid as valid
|
||||
|
||||
#####################################################################################
|
||||
@@ -318,13 +318,29 @@ The term length appears in two places but I'm selecting...
|
||||
"""
|
||||
|
||||
|
||||
def CARVEOUT_CHECK(service, methodology):
|
||||
carveout_definitions = {carveout : definition for carveout, definition in VALID_CARVEOUTS.items() if definition} # Get only not None
|
||||
return f"""Examine the Service and Methodology combination below and determine if the terms fall under one of the following Carveout definitions:
|
||||
|
||||
Here are the Carveouts, with their definitions:
|
||||
{carveout_definitions}
|
||||
|
||||
Here is the Service and Methodology:
|
||||
Service: {service}
|
||||
Methodology: {methodology}
|
||||
|
||||
Determine if the Service and Methodology match any of the Carveout descriptions.
|
||||
If so, write the name of the Carveout. If they do not, simply write N/A. The answer will be somewhat explicitly written - do not attempt to force an answer if it is not the obvious answer.
|
||||
|
||||
Write your reasoning below, but enclose your final answer in |pipes|.
|
||||
"""
|
||||
|
||||
|
||||
#####################################################################################
|
||||
####################################### LEGACY ######################################
|
||||
#####################################################################################
|
||||
|
||||
|
||||
|
||||
|
||||
def BOTTOM_UP_METHODOLOGY_BREAKOUT(d):
|
||||
return f"""Analyze the full methodology text listed below:
|
||||
{d['FULL_METHODOLOGY']}
|
||||
|
||||
Reference in New Issue
Block a user