Merged in pricing_before_carveouts_priorityhealth (pull request #209)
Pricing before carveouts priorityhealth Approved-by: Katon Minhas
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
dotenv_if_exists .env
|
||||
|
||||
require AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
require LOCAL_PATH
|
||||
require BUCKET BUCKET_PREFIX
|
||||
require READ_MODE MAX_WORKERS
|
||||
require CLIENT
|
||||
@@ -1,5 +1,5 @@
|
||||
import dict_operations
|
||||
import postprocessing_funcs
|
||||
import postprocess_funcs
|
||||
import prompts
|
||||
import config
|
||||
import claude_funcs
|
||||
@@ -27,13 +27,18 @@ def run_bottom_up(filename, text_dict):
|
||||
# Bottom Up Primary - SERVICE, REIMBURSEMENT_FLAT_FEE, REIMBURSEMENT_RATE, METHODOLOGY
|
||||
answer_strings = run_bottom_up_primary(text_dict, 8000)
|
||||
answer_dicts = dict_operations.primary_string_to_dict(answer_strings, filename)
|
||||
answer_dicts_filtered = postprocessing_funcs.filter_service_column(answer_dicts)
|
||||
answer_dicts_filtered = postprocess_funcs.filter_service_column(answer_dicts)
|
||||
|
||||
# Bottom Up Secondary
|
||||
results_dicts = run_bottom_up_secondary(answer_dicts_filtered, text_dict, 8000)
|
||||
|
||||
# Add _PG columns
|
||||
results_dicts = postprocess_funcs.add_PG_columns(results_dicts)
|
||||
|
||||
# Add Filename
|
||||
for d in results_dicts:
|
||||
d["Filename"] = filename
|
||||
|
||||
return results_dicts # List of dictionaries
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import os
|
||||
|
||||
import utils
|
||||
import preprocess
|
||||
import table_funcs
|
||||
|
||||
|
||||
def contains_reimbursement(text_dict, page):
|
||||
return (
|
||||
"%" in text_dict[page]
|
||||
or "$" in text_dict[page]
|
||||
or "percent" in text_dict[page].lower()
|
||||
)
|
||||
|
||||
|
||||
directory_path = (
|
||||
"C:\\Users\\kminhas\\Documents\\Doczy\\doczy.ai\\data\\centene_healthnet"
|
||||
)
|
||||
# input_dict = utils.read_input(path=folder_path)
|
||||
all_files = {}
|
||||
reimbursement_count = 0
|
||||
total_count = 0
|
||||
# Walk through all directories and files in the directory
|
||||
for root, dirs, files in os.walk(directory_path):
|
||||
for file in files:
|
||||
if file.endswith(".txt"):
|
||||
# Construct full file path
|
||||
file_path = os.path.join(root, file)
|
||||
print(file_path)
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
contract_text = file.read()
|
||||
if (
|
||||
"%" in contract_text
|
||||
or "$" in contract_text
|
||||
or "percent" in contract_text.lower()
|
||||
):
|
||||
reimbursement_count += 1
|
||||
total_count += 1
|
||||
except:
|
||||
continue
|
||||
|
||||
print(
|
||||
f"For Centene HealthNet, {reimbursement_count}/{total_count} files contain potential reimbursement terms."
|
||||
)
|
||||
@@ -0,0 +1,104 @@
|
||||
VALID_COLUMNS_TEMPLATE = {
|
||||
"base": [
|
||||
"Filename",
|
||||
"page_num",
|
||||
"SERVICE",
|
||||
"REIMBURSEMENT_FLAT_FEE",
|
||||
"REIMBURSEMENT_RATE",
|
||||
"FULL_METHODOLOGY",
|
||||
"REIMBURSEMENT_METHODOLOGY",
|
||||
"REIMBURSEMENT_FEE_SCHEDULE",
|
||||
"REIMBURSEMENT_FEE_SCHEDULE_VERSION",
|
||||
"LESSER_OF_LANGUAGE_IND",
|
||||
"GREATER_OF_LANGUAGE_IND",
|
||||
"CONTRACT_LOB",
|
||||
"CONTRACT_NETWORK",
|
||||
"PRODUCT",
|
||||
"CONTRACT_PROGRAM",
|
||||
"CONTRACT_MARKETPLACE_METAL_LEVEL",
|
||||
"PROV_TYPE",
|
||||
"REIMBURSEMENT_PROC_CODES",
|
||||
"REIMBURSEMENT_PROC_CODE_MODIFIERS",
|
||||
"REIMBURSEMENT_REVENUE_CODES",
|
||||
"REIMBURSEMENT_STATUS_INDICATOR_CODES",
|
||||
"REIMBURSEMENT_DIAG_CODES",
|
||||
"REIMBURSEMENT_GROUPER_CODES",
|
||||
"REIMBURSEMENT_GROUPER",
|
||||
"REIMBURSEMENT_PLACEOFSERVICE_CODES",
|
||||
"REIMBURSEMENT_ADMITTYPE_CODES",
|
||||
"REIMBURSEMENT_EXCEPTION_IND",
|
||||
"REIMBURSEMENT_DESCRIBE_EXCEPTION",
|
||||
"RATE_ESCALATOR_IND",
|
||||
"RATE_ESCALATOR_BASIS",
|
||||
"RATE_ESCALATOR_YEARLY_PERCENT_INCREASE",
|
||||
"Corrected_LOB",
|
||||
"Corrected_PROGRAM",
|
||||
"Corrected_NETWORK",
|
||||
],
|
||||
"priorityhealth": [
|
||||
"Filename",
|
||||
"SERVICE",
|
||||
"SERVICE_PG",
|
||||
"REIMBURSEMENT_FLAT_FEE",
|
||||
"REIMBURSEMENT_FLAT_FEE_PG",
|
||||
"REIMBURSEMENT_RATE",
|
||||
"REIMBURSEMENT_RATE_PG",
|
||||
"FULL_METHODOLOGY",
|
||||
"FULL_METHODOLOGY_PG",
|
||||
"REIMBURSEMENT_TIN",
|
||||
"REIMBURSEMENT_TIN_PG",
|
||||
"DATE_RANGE",
|
||||
"DATE_RANGE_PG",
|
||||
"REIMBURSEMENT_METHODOLOGY",
|
||||
"REIMBURSEMENT_METHODOLOGY_PG",
|
||||
"REIMBURSEMENT_FEE_SCHEDULE",
|
||||
"REIMBURSEMENT_FEE_SCHEDULE_PG",
|
||||
"REIMBURSEMENT_FEE_SCHEDULE_VERSION",
|
||||
"REIMBURSEMENT_FEE_SCHEDULE_VERSION_PG",
|
||||
"LESSER_OF_LANGUAGE_IND",
|
||||
"LESSER_OF_LANGUAGE_IND_PG",
|
||||
"GREATER_OF_LANGUAGE_IND",
|
||||
"GREATER_OF_LANGUAGE_IND_PG",
|
||||
"CONTRACT_LOB",
|
||||
"CONTRACT_LOB_PG",
|
||||
"CONTRACT_MARKETPLACE_METAL_LEVEL",
|
||||
"CONTRACT_MARKETPLACE_METAL_LEVEL_PG",
|
||||
"CONTRACT_NETWORK",
|
||||
"CONTRACT_NETWORK_PG",
|
||||
"PRODUCT",
|
||||
"PRODUCT_PG",
|
||||
"CONTRACT_PROGRAM",
|
||||
"CONTRACT_PROGRAM_PG",
|
||||
"REIMBURSEMENT_PROC_CODES",
|
||||
"REIMBURSEMENT_PROC_CODES_PG",
|
||||
"REIMBURSEMENT_PROC_CODE_MODIFIERS",
|
||||
"REIMBURSEMENT_PROC_CODE_MODIFIERS_PG",
|
||||
"REIMBURSEMENT_REVENUE_CODES",
|
||||
"REIMBURSEMENT_REVENUE_CODES_PG",
|
||||
"REIMBURSEMENT_STATUS_INDICATOR_CODES",
|
||||
"REIMBURSEMENT_STATUS_INDICATOR_CODES_PG",
|
||||
"REIMBURSEMENT_DIAG_CODES",
|
||||
"REIMBURSEMENT_DIAG_CODES_PG",
|
||||
"REIMBURSEMENT_GROUPER_CODES",
|
||||
"REIMBURSEMENT_GROUPER_CODES_PG",
|
||||
"REIMBURSEMENT_GROUPER",
|
||||
"REIMBURSEMENT_GROUPER_PG",
|
||||
"REIMBURSEMENT_PLACEOFSERVICE_CODES",
|
||||
"REIMBURSEMENT_PLACEOFSERVICE_CODES_PG",
|
||||
"REIMBURSEMENT_ADMITTYPE_CODES",
|
||||
"REIMBURSEMENT_ADMITTYPE_CODES_PG",
|
||||
"REIMBURSEMENT_EXCEPTION_IND",
|
||||
"REIMBURSEMENT_EXCEPTION_IND_PG",
|
||||
"REIMBURSEMENT_DESCRIBE_EXCEPTION",
|
||||
"REIMBURSEMENT_DESCRIBE_EXCEPTION_PG",
|
||||
"RATE_ESCALATOR_IND",
|
||||
"RATE_ESCALATOR_IND_PG",
|
||||
"RATE_ESCALATOR_BASIS",
|
||||
"RATE_ESCALATOR_BASIS_PG",
|
||||
"RATE_ESCALATOR_YEARLY_PERCENT_INCREASE",
|
||||
"RATE_ESCALATOR_YEARLY_PERCENT_INCREASE_PG",
|
||||
"Corrected_LOB",
|
||||
"Corrected_PROGRAM",
|
||||
"Corrected_NETWORK",
|
||||
],
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import os
|
||||
import columns
|
||||
from datetime import datetime
|
||||
import boto3
|
||||
|
||||
@@ -34,7 +36,8 @@ VALID_PROGRAMS = [
|
||||
VALID_NETWORKS = ["HMO", "PPO", "EPO", "POS", "FFS"]
|
||||
|
||||
# Input Settings
|
||||
READ_MODE = "_LOCAL_" # OR '_S3_'
|
||||
READ_MODE = os.getenv("READ_MODE")
|
||||
# '_LOCAL_' OR '_S3_'
|
||||
FILTER_ALREADY_PROCESSED = True
|
||||
|
||||
# Output Settings
|
||||
@@ -50,7 +53,7 @@ UNPROCESSED_RESULTS_NAME = "combined_results_unprocessed.csv"
|
||||
PROCESSED_RESULTS_NAME = "combined_results_post_processed.csv"
|
||||
|
||||
# Multithread Settings
|
||||
MAX_WORKERS = 10
|
||||
MAX_WORKERS = os.getenv("MAX_WORKERS", 10)
|
||||
|
||||
# Prompt Debugging
|
||||
RUN_PRIMARY = True # Always True
|
||||
@@ -63,50 +66,16 @@ RUN_CODES = True
|
||||
|
||||
# Postprocessing Settings
|
||||
FUZZY_MATCH_THRESHOLD = 0.8
|
||||
VALID_COLUMNS = [
|
||||
"Filename",
|
||||
"page_num",
|
||||
"SERVICE",
|
||||
"REIMBURSEMENT_FLAT_FEE",
|
||||
"REIMBURSEMENT_RATE",
|
||||
"FULL_METHODOLOGY",
|
||||
"REIMBURSEMENT_METHODOLOGY",
|
||||
"REIMBURSEMENT_FEE_SCHEDULE",
|
||||
"REIMBURSEMENT_FEE_SCHEDULE_VERSION",
|
||||
"LESSER_OF_LANGUAGE_IND",
|
||||
"GREATER_OF_LANGUAGE_IND",
|
||||
"CONTRACT_LOB",
|
||||
"CONTRACT_NETWORK",
|
||||
"PRODUCT",
|
||||
"CONTRACT_PROGRAM",
|
||||
"CONTRACT_MARKETPLACE_METAL_LEVEL",
|
||||
"PROV_TYPE",
|
||||
"REIMBURSEMENT_PROC_CODES",
|
||||
"REIMBURSEMENT_PROC_CODE_MODIFIERS",
|
||||
"REIMBURSEMENT_REVENUE_CODES",
|
||||
"REIMBURSEMENT_STATUS_INDICATOR_CODES",
|
||||
"REIMBURSEMENT_DIAG_CODES",
|
||||
"REIMBURSEMENT_GROUPER_CODES",
|
||||
"REIMBURSEMENT_GROUPER",
|
||||
"REIMBURSEMENT_PLACEOFSERVICE_CODES",
|
||||
"REIMBURSEMENT_ADMITTYPE_CODES",
|
||||
"REIMBURSEMENT_EXCEPTION_IND",
|
||||
"REIMBURSEMENT_DESCRIBE_EXCEPTION",
|
||||
"RATE_ESCALATOR_IND",
|
||||
"RATE_ESCALATOR_BASIS",
|
||||
"RATE_ESCALATOR_YEARLY_PERCENT_INCREASE",
|
||||
"Corrected_LOB",
|
||||
"Corrected_PROGRAM",
|
||||
"Corrected_NETWORK",
|
||||
]
|
||||
CLIENT = os.getenv("CLIENT", "base")
|
||||
VALID_COLUMNS = columns.VALID_COLUMNS_TEMPLATE[CLIENT]
|
||||
|
||||
# AWS Keys
|
||||
AWS_ACCESS_KEY_ID = "ASIAZTMXAXNXHQSWW2R5"
|
||||
AWS_SECRET_ACCESS_KEY = "W9zH4nDGaae8SuJqcPDXyTHFpQ4xV43eRjbDfPGo"
|
||||
AWS_SESSION_TOKEN = "IQoJb3JpZ2luX2VjEIX//////////wEaCXVzLWVhc3QtMiJIMEYCIQCjQVKSzQSWuO8bDdeGjDUJNUc1NwOA795yLFiBGDSslwIhAOccVQAzlBZyOVtU5mZztHVRbqEbrFigeg2aPzlczG1QKoMDCG8QABoMNjYwMTMxMDY4NzgyIgyP2pSGtJAhII6aZIMq4AI3XnnJgTtwbj6u15RcBlTCYgyn+SqIASHvEaJzyWHP/b7Vf5ZNyWKBsccgIZ590De/biM4Gb7tLsnWYCkFuyj3XswHKgyInBDqDg6b4olgyMGoDxrDmNUI28tQxB5XpwKxsas/azzwNPAgRAyXWMK4b1DcslPGpTRBBi+eBF+hTLiGk1jQnip0qR+GuJnCwXe66gcIGmgscjVxGSg2Q5n0O7VD2UOrr5T7BhvnGLiNtlrXqd3f+BFVk6/SzmuQJgsK33rtsmQUI7R5LXlyZEfH3cEkCXrdch6bFO4Wu53oBmiDtNEkle5n95TXCnXC1EchWzuDA6iP061kLRF3jdihMls8St/RoNACCR41YtOuU5oH1n5qXGvH1HQzOvBuSQBCKIqVGgB7hU63mbJlQCdX+0qd0jgteXFHMyjrwr604zPCxdcfbyehAwpxJR8xLVMimgxJqvyzvAoUjzW1sZPPMKG4rLUGOqUBOobUcGB1mI6GHaV6p6+t+qU/BG9FCt9BZbC/IJsHQkWWemCWpvV6lGVM5JPBmmgGQc3LiwH8g5JSHnoUDjTWlLvlHjXZ2ODLJP+aDFcuS4b1WZmXedL6RTsMvg8qhiELEB7rR+6jEmBmXvh56c+R4mkCG5AiWRBZ/ah910JnvKy5wQTOGJGzNxflyiJmwoO2JOZAKBLT0jg78iG1T3DMJ2qc+Qx7"
|
||||
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
|
||||
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
|
||||
AWS_SESSION_TOKEN = os.getenv("AWS_SESSION_TOKEN")
|
||||
|
||||
# File Paths
|
||||
LOCAL_PATH = "data/texas_childrens" # Replace with local
|
||||
LOCAL_PATH = os.getenv("LOCAL_PATH", "data/")
|
||||
|
||||
# S3 Settings
|
||||
S3_CLIENT = boto3.client(
|
||||
@@ -116,8 +85,8 @@ S3_CLIENT = boto3.client(
|
||||
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
|
||||
aws_session_token=AWS_SESSION_TOKEN,
|
||||
)
|
||||
BUCKET = "doczy-dev-infra-textract"
|
||||
PREFIX = "batches/batch_1/contract-text-file/" # replace with s3 path
|
||||
BUCKET = os.getenv("BUCKET", "doczy-dev-infra-textract")
|
||||
PREFIX = os.getenv("BUCKET_PREFIX")
|
||||
|
||||
# Bedrock Settings
|
||||
BEDROCK_RUNTIME = boto3.client(
|
||||
|
||||
@@ -4,8 +4,9 @@ import pandas as pd
|
||||
import config
|
||||
import preprocess
|
||||
import table_funcs
|
||||
import bottom_up_funcs
|
||||
import top_down_funcs
|
||||
import bottom_up_funcs
|
||||
import postprocess_funcs
|
||||
import postprocess
|
||||
import merge_funcs
|
||||
|
||||
@@ -40,11 +41,6 @@ def process_file(file_object):
|
||||
if config.VERBOSE:
|
||||
print(f"Processing {filename}...")
|
||||
|
||||
################## CREATE OUTPUT DIRECTORIES ##################
|
||||
base_filename = os.path.splitext(filename)[0].strip()
|
||||
output_dir = os.path.join(config.OUTPUT_DIRECTORY, base_filename)
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
################## PREPROCESS ##################
|
||||
contract_text = preprocess.clean_newlines(contract_text)
|
||||
contract_text = preprocess.clean_billed_charges(contract_text)
|
||||
@@ -56,37 +52,20 @@ def process_file(file_object):
|
||||
td_results = top_down_funcs.run_top_down(
|
||||
filename, text_dict
|
||||
) # Returns list of dictionaries for each page
|
||||
pd.DataFrame(td_results).to_csv(
|
||||
os.path.join(output_dir, config.TD_RESULTS_NAME), index=False
|
||||
)
|
||||
print(f"Top Down Complete - {filename}")
|
||||
|
||||
################## RUN BOTTOM UP ##################
|
||||
bu_results = bottom_up_funcs.run_bottom_up(
|
||||
filename, text_dict
|
||||
) # Returns list of dictionaries
|
||||
pd.DataFrame(bu_results).to_csv(
|
||||
os.path.join(output_dir, config.BU_RESULTS_NAME), index=False
|
||||
)
|
||||
print(f"Bottom Up Complete - {filename}")
|
||||
|
||||
################## COMBINE TOP DOWN AND BOTTOM UP ##################
|
||||
combined_results = merge_funcs.merge_results(td_results, bu_results, text_dict)
|
||||
print(f"TD/BU Merge Complete - {filename} ")
|
||||
|
||||
################## WRITE UNPROCESSED OUTPUT ##################
|
||||
combined_df = pd.DataFrame(combined_results)
|
||||
combined_df.to_csv(
|
||||
os.path.join(output_dir, config.UNPROCESSED_RESULTS_NAME), index=False
|
||||
)
|
||||
|
||||
################## RUN POSTPROCESSING ##################
|
||||
# combined_df = combined_df.applymap(postprocessingfuncs.sanitize_value) # Deprecated
|
||||
|
||||
combined_df = pd.DataFrame(combined_results)
|
||||
post_processed_combined_df = postprocess.postprocess_results(combined_df)
|
||||
post_processed_combined_df.to_csv(
|
||||
os.path.join(output_dir, config.PROCESSED_RESULTS_NAME), index=False
|
||||
)
|
||||
print(f"Postprocessing Complete - {filename} ")
|
||||
|
||||
print(f"Output Complete - {filename} ")
|
||||
return post_processed_combined_df
|
||||
|
||||
@@ -11,8 +11,7 @@ Functional Overview:
|
||||
"""
|
||||
|
||||
# Imports
|
||||
import concurrent.futures
|
||||
import traceback
|
||||
import pandas as pd
|
||||
import os
|
||||
|
||||
import utils
|
||||
@@ -61,8 +60,24 @@ def main():
|
||||
print(f"Error: {e}")
|
||||
|
||||
# Write Consolidated Output
|
||||
# if config.WRITE_OUTPUT:
|
||||
# utils.consolidate_csvs(config.CONSOLIDATED_OUTPUT_DIRECTORY, config.OUTPUT_CSV_PATH)
|
||||
if config.WRITE_OUTPUT:
|
||||
all_results_df = pd.concat(all_results).reset_index(drop=True)
|
||||
all_results_df.drop("page_num", axis=1, inplace=True)
|
||||
|
||||
# Reorder columns
|
||||
final_df = all_results_df[
|
||||
[col for col in config.VALID_COLUMNS if col in all_results_df.columns]
|
||||
+ [
|
||||
col
|
||||
for col in all_results_df.columns
|
||||
if col not in config.VALID_COLUMNS
|
||||
]
|
||||
]
|
||||
final_df.to_csv(
|
||||
os.path.join(
|
||||
config.CONSOLIDATED_OUTPUT_DIRECTORY, config.OUTPUT_CSV_PATH
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -23,21 +23,23 @@ def merge_results(td_results, bu_results, text_dict):
|
||||
if int(page_num) > 1:
|
||||
return get_value(
|
||||
find_td_dict(int(page_num) - 1), key, int(page_num) - 1, text_dict
|
||||
)
|
||||
), str(int(page_num) - 1)
|
||||
else:
|
||||
return "N/A" # Base case if no previous pages exist
|
||||
return "N/A", "N/A" # Base case if no previous pages exist
|
||||
else:
|
||||
value = td_dict.get(key, "N/A")
|
||||
if value == "N/A" or value == "":
|
||||
# If value is 'N/A' or empty, use recursion to look one page earlier
|
||||
return get_value(
|
||||
find_td_dict(int(page_num) - 1), key, int(page_num) - 1, text_dict
|
||||
)
|
||||
), str(int(page_num) - 1)
|
||||
elif "," in value and "DATE" not in key:
|
||||
# Randomly select one of the comma-separated values
|
||||
return prompt_select_multiple(key, value, bu_dict, text_dict[page_num])
|
||||
return prompt_select_multiple(
|
||||
key, value, bu_dict, text_dict[page_num]
|
||||
), str(int(page_num))
|
||||
else:
|
||||
return value
|
||||
return value, page_num
|
||||
|
||||
merged_results = []
|
||||
for bu_dict in bu_results:
|
||||
@@ -49,7 +51,9 @@ def merge_results(td_results, bu_results, text_dict):
|
||||
if td_dict:
|
||||
for key, value in td_dict.items():
|
||||
if key not in ["Filename", "page_num"]:
|
||||
new_dict[key] = get_value(td_dict, key, page_num, text_dict)
|
||||
new_dict[key], new_dict[f"{key}_PG"] = get_value(
|
||||
td_dict, key, page_num, text_dict
|
||||
)
|
||||
|
||||
merged_results.append(new_dict)
|
||||
return merged_results
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import pandas as pd
|
||||
import re
|
||||
|
||||
import postprocessing_funcs
|
||||
import postprocess_funcs
|
||||
import config
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ def postprocess_results(combined_df):
|
||||
|
||||
# Sanitize the combined data
|
||||
try:
|
||||
df = postprocessing_funcs.sanitize_combined(combined_df)
|
||||
df = postprocess_funcs.sanitize_combined(combined_df)
|
||||
except Exception as e:
|
||||
print(f"Postprocessing Error - santize_combined : {e}")
|
||||
|
||||
@@ -27,14 +27,14 @@ def postprocess_results(combined_df):
|
||||
["CONTRACT_NETWORK", "Corrected_NETWORK", config.VALID_NETWORKS],
|
||||
]:
|
||||
try:
|
||||
postprocessing_funcs.clean_columns_combined(
|
||||
postprocess_funcs.clean_columns_combined(
|
||||
df, field_list[0], field_list[2], field_list[1]
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Postprocessing Error - clean_columns_combined : {e}")
|
||||
|
||||
try:
|
||||
postprocessing_funcs.clean_columns_combined_fuzzy(
|
||||
postprocess_funcs.clean_columns_combined_fuzzy(
|
||||
df, field_list[0], field_list[2], config.FUZZY_MATCH_THRESHOLD
|
||||
)
|
||||
except Exception as e:
|
||||
@@ -42,7 +42,7 @@ def postprocess_results(combined_df):
|
||||
|
||||
# Correct misplaced values across columns
|
||||
try:
|
||||
df = postprocessing_funcs.correct_misplaced_values(
|
||||
df = postprocess_funcs.correct_misplaced_values(
|
||||
df,
|
||||
["CONTRACT_LOB", "CONTRACT_PROGRAM", "CONTRACT_NETWORK"],
|
||||
valid_values_dict,
|
||||
@@ -52,19 +52,19 @@ def postprocess_results(combined_df):
|
||||
|
||||
# Move percentages and large numbers to correct columns
|
||||
try:
|
||||
df = postprocessing_funcs.move_percentage_to_rate(df)
|
||||
df = postprocess_funcs.move_percentage_to_rate(df)
|
||||
except Exception as e:
|
||||
print(f"Postprocessing Error - move_percentage_to_rate : {e}")
|
||||
|
||||
# Replace N/As in "Not Covered" with 0%
|
||||
try:
|
||||
df = postprocessing_funcs.set_rate_to_zero_if_not_covered(df)
|
||||
df = postprocess_funcs.set_rate_to_zero_if_not_covered(df)
|
||||
except Exception as e:
|
||||
print(f"Postprocessing Error - set_rate_to_zero_if_not_covered : {e}")
|
||||
|
||||
# Adjust for adding or subtracting
|
||||
try:
|
||||
df = postprocessing_funcs.adjust_reimbursement_rate(df)
|
||||
df = postprocess_funcs.adjust_reimbursement_rate(df)
|
||||
except Exception as e:
|
||||
print(f"Postprocessing Error - adjust_reimbursement_rate : {e}")
|
||||
|
||||
|
||||
@@ -513,3 +513,11 @@ def clean_dates(df):
|
||||
df.loc[idx, "LOB_PRICING_TERMS_TERMINATION_DATE"] = "N/A"
|
||||
|
||||
return df
|
||||
|
||||
|
||||
def add_PG_columns(results_dicts):
|
||||
for key in list(results_dicts[0].keys()):
|
||||
if key != "page_num":
|
||||
for d in results_dicts:
|
||||
d[f"{key}_PG"] = d["page_num"]
|
||||
return results_dicts
|
||||
@@ -133,6 +133,7 @@ def clean_billed_charges(contract_text):
|
||||
"Billed Charges",
|
||||
"the rates set forth in this Exhibit",
|
||||
"the rutes set forth in this Exhibit",
|
||||
"Provider's usual and customary charge",
|
||||
]
|
||||
max_substring_length = max([len(s) for s in substrings])
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ Here are the attributes to be included in each dictionary, and instructions on h
|
||||
'REIMBURSEMENT_FLAT_FEE' : If the listed reimbursement is dollar value, return only that dollar value. There can only be one answer for each object. If more than one rate is found, create additional objects for them.
|
||||
'REIMBURSEMENT_RATE' : If the listed reimbursement is a percent of something, return only that percent. There can only be one answer for each object. If more than one rate is found, create additional objects for them. Do NOT include multiple percentages in this value.
|
||||
'FULL_METHODOLOGY' : If the listed reimbursement is a percent of something, what is it the percent of? If the listed reimbursement is a direct dollar value, how is that dollar value paid (per diem, per unit, etc)? Write the full sentence in text describing the payment methodology.
|
||||
'REIMBURSEMENT_DATES' : If the listed reimbursement only applies to a specific date range, write that range here. Write only the exact text. Write only the range. If there is none, write 'N/A'.
|
||||
'DATE_RANGE' : If the listed reimbursement only applies to a specific date range, write that range here. Write only the exact text. Write only the range. If there is none, write 'N/A'.
|
||||
'REIMBURSEMENT_TIN' : If the listed reimbursement only applies to a specific TIN, write only the TIN here. If not, write 'N/A'
|
||||
|
||||
Note that only one of REIMBURSEMENT_FLAT_FEE or REIMBURSEMENT_RATE should be populated in each dictionary. Ensure all 4 keys are in the dictionary.
|
||||
@@ -176,7 +176,7 @@ Read and analyze the page, then populate a JSON dictionary with the following co
|
||||
|
||||
Return a value for each type of code - return N/A for any values not found. Multiple codes for each type may be found. In this case, return them all. They may also present as a range. If so, return the range.
|
||||
|
||||
Note that some PROC_CODES may have 'Modifiers' listed as well. These are 2-character strings. If Modifiers are present, include them as part of this field.
|
||||
Note that some PROC_CODES may have 'Modifiers' listed as well. These are 2-character strings. If Modifiers are present, include them.
|
||||
|
||||
Ensure you ONLY return codes if they are associated directly with the Service listed. Codes referring to other services should not be included.
|
||||
|
||||
@@ -194,7 +194,7 @@ Here are the attributes to be included in each dictionary, and instructions on h
|
||||
'CONTRACT_PROGRAM' : List any Programs mentioned on the page. Some examples of Programs are: CHIP, CHIP-P, CHIP-Perinate, STAR, STAR+PLUS. Do your best to infer the program from this page.
|
||||
'CONTRACT_NETWORK' : List any Networks mentioned on the page. Networks are types of managed care organizations involved in the delivery of healthcare services. Some examples of Networks are: HMO, PPO, EMO, POS, FFS. Do your best to infer the network from this page. If it says anywhere that they are out of network then only return "OUT OF NETWORK" as your answer.
|
||||
'PRODUCT' : List any Products listed on the page. These are typically the brand name of a health plan. You may also use this field as a catch-all for entities that you are unsure of.
|
||||
'PROV_TYPE' : List any Provider Type listed on the page. This may be something like Inpatient, Outpatient, Ambulatory Surgery Center, DME, Home Health, Hospice, Skilled Nursing Facility, or similar.
|
||||
'PROV_TYPE' : List any Provider Types listed on the page. This can be something like Inpatient, Outpatient, Ancillary, ASC, DME, Hospital, Home Health, Hospice, or similar.
|
||||
|
||||
If any of the attributes are not found, return N/A. If there are multiple answers for a given attribute, return the answers in a comma-separated list.
|
||||
|
||||
|
||||
+72
-35
@@ -1,48 +1,85 @@
|
||||
import utils
|
||||
import preprocess
|
||||
import table_funcs
|
||||
import prompts
|
||||
import claude_funcs
|
||||
import config
|
||||
|
||||
import os
|
||||
import pandas as pd
|
||||
import boto3
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
||||
s3 = boto3.Session(
|
||||
aws_access_key_id="ASIA6GBMBVWOJOOHVXUE",
|
||||
aws_secret_access_key="YsXnoYhY599uOifnQ+hZnqQJpWTyjhZ8XppJr43V",
|
||||
aws_session_token="IQoJb3JpZ2luX2VjEHcaCXVzLWVhc3QtMiJHMEUCIBdFMYRAL20l87z9xZJzlvOW8H7+jOIoI2f6zOkNtMdQAiEAomTpoulfRpLcPhzbNFQVR5atGD8xbM49/gKX0rNDZYgqgQMIYRAAGgw5NzUwNDk5NjA4NjAiDGoxXZfA4RDhWkpflCreAmgKA3i7fZYV6z/e5WejrcnSfffciNhUKpen98pi1gJT6xgB9Cy4k19DAkF8ab8dQcyTO80K20hd2QjzwaTXDDiIpXYJq1TRHiJVN+g0QKOx10l4KOo7g8hGPzD/QPmA80aTxC96PqRklnJkUGNKe9zfZ7nCujts/i/rs0oAeuRCCnEKsh3lOtj4YEhoQGsNlKUsx4Pfh2cTn/JTZ4hma0zO8HnVfPh2f4i4hpa8Ula/0arXZJrkJyHdbQV85w+lmjypILQwAy6kQUd57lURDXDF1uPtziKZ2WqkozpEdeblmUUAT24rXKBhv3m86oqN59pb1IiFoDE7IOmJgRqNbh58OhOwifijMRWYouvSFM8pcBDTD725UmTzNu5GKgGJE00Q4PyBu5K2YXX1rHFmOhr29wq11mPMBPVRTF/zMLjG8ZloHYQWtt8VZwso8WE7ezV7RyScz0SBwBvhOX0mMPSwqbUGOqYBhMdcVuF9yw0Norg5U7G8SDl2WmiYCh/Anfea87h/1KzPs6ZNphtuSLcaH9+C7hVx5DVAJUW7gI0xx5jhPgqHbcptDPkNWCL129URUMPFOmuRiPxyTl0Xl5jSeh0Mj+RJz81OCWaEQyTQYOTtNUir77f1KAm8y+ClFrkYFrk6uz6HyiYknmcxAokjdNMIOS/83O7GTUv1Vo6/fIXo2MKX7gxhuNUoNw==",
|
||||
).client("s3")
|
||||
# input_dict = utils.read_input()
|
||||
|
||||
# filename = list(input_dict.keys())[0]
|
||||
# contract_text = input_dict[filename]
|
||||
|
||||
# contract_text = preprocess.clean_newlines(contract_text)
|
||||
# contract_text = preprocess.clean_billed_charges(contract_text)
|
||||
# text_dict = preprocess.split_text(contract_text)
|
||||
# text_dict = table_funcs.align_and_format_tables(text_dict)
|
||||
# text_dict = preprocess.highlight_rates(text_dict)
|
||||
|
||||
# def BOTTOM_UP_PRIMARY(page, payer):
|
||||
# return f"""
|
||||
# ### PAGE START ### {page} ### PAGE END
|
||||
|
||||
# The preceding text is one page of a contract between Payer {payer} and a provider in their network. Your job is to extract attributes related to the reimbursement of different services and specialties.
|
||||
|
||||
# The reimbursement values will be identified with >>> <<< indicators (e.g. >>>105%<<<). Make sure there is at least one dictionary object for EVERY reimbursement value seen (either % or $).
|
||||
|
||||
# Some values are found in sections explicitly identified as examples - these must be omitted from output. Other values might be related to liability - these must also be excluded.
|
||||
|
||||
# If any of the attributes are not found, return N/A. For all attributes, only write what is written on the page. Do not make up new phrases or words.
|
||||
|
||||
# Return at least one json object for each combination of attributes seen. It is possible that a page will not have any attributes. When this is the case, return an empty list.
|
||||
|
||||
# Here are the attributes to be included in each dictionary, and instructions on how to correctly answer:
|
||||
# 'SERVICE' : What is the Service that is being reimbursed? Use your best judgement and knowledge of the healthcare industry to answer. Use only exact text from the document. Do not leave this field N/A.
|
||||
# 'REIMBURSEMENT_FLAT_FEE' : If the listed reimbursement is dollar value, return only that dollar value. There can only be one answer for each object. If more than one rate is found, create additional objects for them.
|
||||
# 'REIMBURSEMENT_RATE' : If the listed reimbursement is a percent of something, return only that percent. There can only be one answer for each object. If more than one rate is found, create additional objects for them. Do NOT include multiple percentages in this value.
|
||||
# 'FULL_METHODOLOGY' : If the listed reimbursement is a percent of something, what is it the percent of? If the listed reimbursement is a direct dollar value, how is that dollar value paid (per diem, per unit, etc)? Write the full sentence in text describing the payment methodology.
|
||||
# 'DATE_RANGE' : If the listed reimbursement only applies to a specific date range, write that range here. Write only the exact text. Write only the range. If there is none, write 'N/A'.
|
||||
# 'REIMBURSEMENT_TIN' : If the listed reimbursement only applies to a specific TIN, write only the TIN here. If not, write 'N/A'
|
||||
|
||||
# Note that only one of REIMBURSEMENT_FLAT_FEE or REIMBURSEMENT_RATE should be populated in each dictionary. Ensure all 4 keys are in the dictionary.
|
||||
|
||||
# Only return the list, with no other commentary or explanation. Ensure you abide by proper JSON formatting.
|
||||
# """
|
||||
# answer_dict = {}
|
||||
# for page_number in text_dict.keys():
|
||||
# if utils.contains_reimbursement(text_dict, page_number):
|
||||
# # Run Primary
|
||||
# prompt = BOTTOM_UP_PRIMARY(text_dict[page_number], config.CLIENT_NAME)
|
||||
# answer = claude_funcs.invoke_claude_3(prompt, max_tokens=4000)
|
||||
# answer_dict[page_number] = answer
|
||||
|
||||
# for page_num in answer_dict.keys():
|
||||
# print(f"Page {page_num}\n")
|
||||
# print(answer_dict[page_num])
|
||||
|
||||
|
||||
def get_s3_files(bucket_name, folder):
|
||||
paginator = s3.get_paginator("list_objects_v2")
|
||||
result = paginator.paginate(Bucket=bucket_name, Prefix=folder)
|
||||
files = set()
|
||||
batch1_files = pd.read_excel(
|
||||
"C:\\Users\\kminhas\\Documents\\Doczy\\Facility TINs_DOCZY AI_DOCUMENT EXTRACTION_ASSIGNMENT_7.1.2024.xlsx",
|
||||
sheet_name="DOCZY AI",
|
||||
)
|
||||
batch1_files = batch1_files["File Name"]
|
||||
# print(list(batch1_files))
|
||||
|
||||
for page in result:
|
||||
if "Contents" in page:
|
||||
for obj in page["Contents"]:
|
||||
file_name = obj["Key"]
|
||||
if file_name: # Ensure it's not a folder
|
||||
files.add(file_name)
|
||||
tdrive_path = "T:\\AArete Client Work\\Centene\\Restricted\\HealthNet\\Doczy Contract Metadata\\1. Contracts\\05232024\\Extracted"
|
||||
batch_path = os.path.join(tdrive_path, "Batch0")
|
||||
try:
|
||||
os.mkdir(batch_path)
|
||||
except:
|
||||
pass
|
||||
|
||||
return files
|
||||
|
||||
|
||||
bucket_name = "texas-children-files"
|
||||
folder = "510_text_files/"
|
||||
files_in_folder = get_s3_files(bucket_name, folder)
|
||||
|
||||
source_bucket = "texas-children-files"
|
||||
for source_key in files_in_folder:
|
||||
filename = source_key.split("510_text_files/")[1]
|
||||
print(filename)
|
||||
|
||||
if filename not in os.listdir("data/texas_childrens"):
|
||||
for file in os.listdir(tdrive_path):
|
||||
if file.endswith(".Pdf") and file.split(".Pdf")[0] in list(batch1_files):
|
||||
try:
|
||||
response = s3.get_object(Bucket=source_bucket, Key=source_key)["Body"]
|
||||
file_content = response.read().decode("utf-8")
|
||||
|
||||
with open(f"data/texas_childrens/{filename}", "w") as file:
|
||||
file.write(file_content)
|
||||
source_path = os.path.join(tdrive_path, file)
|
||||
destination_path = os.path.join(batch_path, file)
|
||||
shutil.move(source_path, destination_path)
|
||||
print(f"Moved file: {file}")
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -139,7 +139,9 @@ def consolidate_csvs(
|
||||
pass
|
||||
|
||||
concatenated_df = pd.concat(df_list, ignore_index=True)
|
||||
concatenated_df.to_csv(os.path.join(output_dir, output_file), index=False)
|
||||
concatenated_df.to_csv(
|
||||
os.path.join(config.CONSOLIDATED_OUTPUT_DIRECTORY, output_file), index=False
|
||||
)
|
||||
print(f"All CSV files have been consolidated into {output_file}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user