2025-01-06 15:39:29 +00:00
import csv
2025-04-25 20:28:52 +00:00
import json
2024-10-28 23:39:36 +00:00
import os
2025-01-06 15:39:29 +00:00
2024-10-28 23:39:36 +00:00
import pandas as pd
2025-04-25 20:28:52 +00:00
import src . investment . aarete_derived as aarete_derived
import src . investment . dynamic_funcs as dynamic_funcs
2025-01-08 21:59:47 +00:00
import src . investment . one_to_n_funcs as one_to_n_funcs
2025-01-27 19:39:23 +00:00
import src . investment . one_to_one_funcs as one_to_one_funcs
2025-01-08 21:59:47 +00:00
import src . investment . postprocess as postprocess
2025-05-07 23:03:16 +00:00
import src . investment . investment_postprocessing_funcs as investment_postprocessing_funcs
2025-01-08 21:59:47 +00:00
import src . investment . preprocess as preprocess
2025-01-27 19:39:23 +00:00
import src . investment . smart_chunking_funcs as smart_chunking_funcs
import src . utils . io_utils as io_utils
2025-04-25 20:28:52 +00:00
import src . utils . string_utils as string_utils
from src import config
2025-01-27 21:27:15 +00:00
from src . config import FIELD_JSON_PATH
2025-04-25 20:28:52 +00:00
from src . investment . one_to_n_funcs import ( combine_one_to_n_answers ,
reimbursement_level )
from src . investment . tin_npi_funcs import ( merge_provider_info ,
reimbursement_tin_npi )
from src . prompts . investment_prompts import Field , FieldSet
from src . utils . string_utils import datetime_str
2025-04-08 18:29:39 +00:00
################## MERGE ##################
def merge_one_to_one_into_one_to_n ( one_to_n_results , one_to_one_results ) :
"""
Merges one_to_one_results into one_to_n_results.
Args:
one_to_n_results (pd.DataFrame): DataFrame with N rows and M columns, including FILE_NAME.
one_to_one_results (dict): Dictionary with several keys, including FILE_NAME.
Returns:
pd.DataFrame: Updated one_to_n_results with merged values from one_to_one_results.
"""
# Iterate over all key-value pairs in one_to_one_results
for k , v in one_to_one_results . items ( ) :
if k not in one_to_n_results . columns :
# If k is not a column in one_to_n_results, create it and populate all rows with v
one_to_n_results [ k ] = v
else :
# If k is a column in one_to_n_results, replace empty values with v
one_to_n_results [ k ] = one_to_n_results [ k ] . apply (
lambda row_val : v if string_utils . is_empty ( row_val ) else row_val
)
return one_to_n_results
2025-02-21 14:44:36 +00:00
def process_file ( file_object , all_dataset , run_timestamp ) :
2024-10-28 23:39:36 +00:00
filename , contract_text = file_object
2025-02-20 20:19:53 +00:00
print ( f " { datetime_str ( ) } Processing { filename } ... " )
2024-11-13 17:08:19 +00:00
2025-01-27 19:39:23 +00:00
################## PREPROCESS ##################
2025-01-10 17:24:44 +00:00
contract_text = preprocess . clean_text ( contract_text )
2025-01-27 19:39:23 +00:00
text_dict , top_sheet_dict = preprocess . split_text ( contract_text )
2025-04-23 22:00:02 +00:00
text_dict = preprocess . clean_tables ( text_dict , filename )
2025-01-27 19:39:23 +00:00
exhibit_pages , exhibit_chunk_mapping = preprocess . one_to_n_exhibit_chunking ( text_dict , filename )
2025-02-20 20:19:53 +00:00
print ( f " { datetime_str ( ) } Preprocessing Complete - { filename } " )
2025-01-27 19:39:23 +00:00
################## ONE TO N ##################
if string_utils . contains_reimbursement ( contract_text ) :
2025-04-08 18:29:39 +00:00
one_to_n_results , dynamic_one_to_one_fields = run_one_to_n_prompts ( filename , text_dict , exhibit_pages , exhibit_chunk_mapping , all_dataset ) # Return df
2025-03-21 18:11:55 +00:00
one_to_n_results [ ' FILE_NAME ' ] = filename
2025-02-25 17:11:02 +00:00
print ( f " { datetime_str ( ) } One to N Complete - { filename } " )
2025-01-27 19:39:23 +00:00
else :
2025-03-21 18:11:55 +00:00
one_to_n_results = pd . DataFrame ( [ { ' FILE_NAME ' : filename } ] )
2025-04-08 18:29:39 +00:00
dynamic_one_to_one_fields = FieldSet ( )
2025-02-25 17:11:02 +00:00
print ( f " { datetime_str ( ) } No One to N Found, Skipping - { filename } " )
2025-01-28 20:51:19 +00:00
2025-02-25 17:11:02 +00:00
################## ONE TO ONE ##################
2025-04-23 22:00:02 +00:00
one_to_one_results = run_one_to_one_prompts ( filename , contract_text , text_dict , top_sheet_dict , dynamic_one_to_one_fields ) # Return dict
2025-03-21 18:11:55 +00:00
one_to_one_results [ ' FILE_NAME ' ] = filename
2025-02-25 17:11:02 +00:00
print ( f " { datetime_str ( ) } One to One Complete - { filename } " )
################## MERGE ##################
2025-04-08 18:29:39 +00:00
final_results = merge_one_to_one_into_one_to_n ( one_to_n_results , one_to_one_results )
2025-01-27 19:39:23 +00:00
################## POSTPROCESS ##################
final_df = postprocess . postprocess ( final_results )
2025-02-20 20:19:53 +00:00
print ( f " { datetime_str ( ) } Postprocessing Complete - { filename } " )
2025-01-27 19:39:23 +00:00
################## WRITE INDIVIDUAL ##################
if config . WRITE_TO_S3 :
io_utils . write_s3 ( final_df , filename , run_timestamp , " individual " )
else :
io_utils . write_local ( final_df , filename , " " , " individual " )
2025-02-20 20:19:53 +00:00
print ( f " { datetime_str ( ) } Writing Complete - { filename } " )
2025-01-27 19:39:23 +00:00
return final_df
2025-04-08 18:29:39 +00:00
def run_one_to_one_prompts ( filename , contract_text , text_dict , top_sheet_dict , dynamic_one_to_one_fields ) :
2024-10-28 23:39:36 +00:00
2025-01-27 19:39:23 +00:00
################## INITIALIZE FIELDS ##################
2025-04-08 18:29:39 +00:00
one_to_one_fields = FieldSet ( relationship = " one_to_one " , file_path = config . FIELD_JSON_PATH ) . combine ( dynamic_one_to_one_fields )
2024-12-02 19:50:41 +00:00
2025-01-27 19:39:23 +00:00
################## RUN REGEX ##################
2025-04-18 20:50:25 +00:00
regex_answers_dict = one_to_one_funcs . run_provider_info_fields ( contract_text , text_dict , filename )
one_to_one_results = { }
2025-04-25 20:28:52 +00:00
one_to_one_results [ ' PROV_INFO_JSON ' ] = json . dumps ( regex_answers_dict )
2025-04-18 20:50:25 +00:00
one_to_one_results = merge_provider_info ( one_to_one_results , regex_answers_dict )
2025-05-07 22:53:27 +00:00
# What if the TIN/NPI regexes don't find anything? Add PROV_GROUP_NAME_FULL to full context
if one_to_one_results . get ( " PROV_OTHER_NAME_FULL " ) == " NO_IDENTIFIERS_FOUND " : # This is how we know the regex didn't find anything
other_provider_name_field = Field . from_values (
field_name = " PROV_GROUP_NAME_FULL " ,
relationship = " one_to_one " ,
field_type = " full_context " ,
prompt = " What is the name of the group provider associated with this contract? Return the full name as it appears in the document. "
)
one_to_one_fields . add_field ( other_provider_name_field )
one_to_one_results [ " PROV_OTHER_NAME_FULL " ] = " UNKNOWN "
2025-01-10 17:24:44 +00:00
2024-12-06 18:19:58 +00:00
################## RUN SMART CHUNKED PROMPTS ##################
2025-01-27 19:39:23 +00:00
smart_chunked_answers_dict = one_to_one_funcs . run_smart_chunked_fields (
2025-05-07 18:21:09 +00:00
one_to_one_fields , contract_text , filename , text_dict
2024-12-06 18:19:58 +00:00
)
2024-10-28 23:39:36 +00:00
2024-12-06 18:19:58 +00:00
################## RUN FULL CONTEXT PROMPTS ##################
2025-01-27 19:39:23 +00:00
full_context_answers_dict = one_to_one_funcs . run_full_context_fields (
one_to_one_fields , contract_text , filename
2024-12-06 18:19:58 +00:00
)
2024-11-18 21:01:09 +00:00
2025-01-31 22:36:11 +00:00
################## COMBINE ANSWERS ################
2025-04-18 20:50:25 +00:00
one_to_one_results . update ( smart_chunked_answers_dict )
one_to_one_results . update ( full_context_answers_dict )
2025-01-31 22:36:11 +00:00
2025-04-08 18:29:39 +00:00
################## Crosswalk Fields ##################
one_to_one_results = aarete_derived . get_crosswalk_fields ( [ one_to_one_results ] )
2024-11-13 17:08:19 +00:00
2025-04-08 18:29:39 +00:00
################## Fill NA Mapping ##################
one_to_one_results = aarete_derived . fill_na_mapping ( one_to_one_results )
return one_to_one_results [ 0 ]
2024-10-28 23:39:36 +00:00
2025-02-21 14:44:36 +00:00
def run_one_to_n_prompts ( filename , text_dict , exhibit_pages , exhibit_chunk_mapping , all_dataset ) :
2024-10-28 23:39:36 +00:00
2025-01-27 19:39:23 +00:00
################## RUN PROMPTS ##################
2025-01-31 22:36:11 +00:00
one_to_n_results = [ ]
for exhibit_page in exhibit_pages :
exhibit_chunk = string_utils . get_exhibit_chunk ( text_dict , exhibit_chunk_mapping , exhibit_page )
if string_utils . contains_reimbursement ( exhibit_chunk ) :
2025-02-21 20:24:34 +00:00
2025-01-31 22:36:11 +00:00
################## INITIALIZE FIELDS ##################
reimbursement_level_fields = FieldSet ( relationship = " one_to_n " , field_type = " reimbursement_level " , file_path = FIELD_JSON_PATH )
2025-04-23 22:00:02 +00:00
################## GET EXHIBIT HEADER ##################
exhibit_header = one_to_n_funcs . get_exhibit_header ( exhibit_chunk , filename )
2025-01-31 22:36:11 +00:00
2025-02-03 21:50:50 +00:00
################## GET REIMBURSEMENT TIN/NPI ##################
2025-05-02 20:13:02 +00:00
tin_npi_answers , reimbursement_level_fields = reimbursement_tin_npi ( exhibit_chunk , reimbursement_level_fields , filename )
2025-02-03 21:50:50 +00:00
2025-04-23 22:00:02 +00:00
################## GET EXHIBIT-LEVEL ANSWERS ##################
exhibit_level_answers = one_to_n_funcs . get_exhibit_level_answers ( exhibit_chunk , filename )
2025-01-31 22:36:11 +00:00
exhibit_level_answers [ ' EXHIBIT_PAGE ' ] = exhibit_page
2025-04-23 22:00:02 +00:00
exhibit_level_answers [ ' EXHIBIT_TITLE ' ] = exhibit_header
################## GET DYNAMIC-PRIMARY ANSWERS ##################
dynamic_to_exhibit_level_answers , dynamic_to_reimbursement_level_fields = dynamic_funcs . get_dynamic_answers ( exhibit_chunk ,
exhibit_header ,
filename ,
FieldSet ( relationship = " one_to_n " , field_type = " dynamic " , file_path = config . FIELD_JSON_PATH ) )
exhibit_level_answers . update ( dynamic_to_exhibit_level_answers )
reimbursement_level_fields . combine ( dynamic_to_reimbursement_level_fields , inplace = True )
################## GET DYNAMIC-CODE ANSWERS ##################
code_to_exhibit_level_answers , code_to_reimbursement_level_fields = dynamic_funcs . get_dynamic_answers ( exhibit_chunk ,
exhibit_header ,
filename ,
FieldSet ( relationship = " one_to_n " , field_type = " dynamic_code " , file_path = config . FIELD_JSON_PATH ) )
exhibit_level_answers . update ( code_to_exhibit_level_answers )
reimbursement_level_fields . combine ( code_to_reimbursement_level_fields , inplace = True )
2025-01-31 22:36:11 +00:00
################## GET REIMBURSEMENT-LEVEL ANSWERS (INCLUDING DYNAMIC) ##################
2025-03-17 20:38:50 +00:00
reimbursement_level_answers = reimbursement_level ( exhibit_chunk , filename , reimbursement_level_fields , all_dataset , exhibit_page ) # Return list of dictionaries
2025-02-26 14:14:30 +00:00
2025-04-23 22:00:02 +00:00
################# COMBINE ANSWERS ##################
2025-02-03 21:50:50 +00:00
full_answer_dict = combine_one_to_n_answers ( exhibit_level_answers , reimbursement_level_answers , tin_npi_answers )
2025-01-31 22:36:11 +00:00
one_to_n_results + = full_answer_dict
2025-05-07 23:03:16 +00:00
2025-04-08 18:29:39 +00:00
################## Crosswalk Fields ##################
2025-03-31 20:07:19 +00:00
one_to_n_results = aarete_derived . get_crosswalk_fields ( one_to_n_results )
################## Fill NA Mapping ##################
one_to_n_results = aarete_derived . fill_na_mapping ( one_to_n_results )
2025-04-08 18:29:39 +00:00
2025-05-07 23:03:16 +00:00
################## Update LOB for Duals ##################
one_to_n_results = investment_postprocessing_funcs . update_lob_for_duals ( one_to_n_results )
2025-04-08 18:29:39 +00:00
################## Add N/A Dynamic or Exhibit to One-to-One ##################
dynamic_one_to_one_fields = dynamic_funcs . get_dynamic_one_to_one_fields ( one_to_n_results )
2025-01-31 22:36:11 +00:00
################## CONVERT TO DF ##################
2025-01-27 19:39:23 +00:00
one_to_n_df = pd . DataFrame ( one_to_n_results )
2025-04-08 18:29:39 +00:00
return one_to_n_df , dynamic_one_to_one_fields
2025-02-21 14:44:36 +00:00