Files
doczyai-pipelines/fieldExtraction/src/config.py
T
Katon Minhas 23af15306b Merged in feature/new-model-testing (pull request #741)
Feature/new model testing

* rename and set up

* Setup

* Get dynamic primary crosswalked answers

* Generate stats for one file

* Update dynamic primary evaluation

* Multithreading

* Set up reimbursement primary evaluation

* UPdate output report generation

* Update TN calculation

* update poetry lock

* reorder reimb primary

* evaluate 3 models

* Configure 4.5

* switch to debug logging

* update type checking

* Fix mypy

* Resolve mypy

* Merged main into feature/new-model-testing


Approved-by: Karan Desai
2025-10-22 16:46:28 +00:00

329 lines
10 KiB
Python

import csv
import os
import sys
from collections import defaultdict
from datetime import datetime
import boto3
from botocore.config import Config
from dotenv import load_dotenv
# Please see the following confluence page for instructions on loading keys into your
# `.env`:
# https://aarete.atlassian.net/wiki/spaces/DoczyAI/pages/1283751954/Using+.env+for+AWS+keys
load_dotenv()
######################################## UTILS ###################################################
# def check_s3_bucket_exists(s3_client, bucket_name: str):
# try:
# s3_client.head_bucket(Bucket=bucket_name)
# print(f"{bucket_name} exists")
# except s3_client.exceptions.ClientError as e:
# error_code = e.response["Error"]["Code"]
# if error_code == "404":
# print(f"{bucket_name} does not exist")
# raise
# else:
# print(f"Error {error_code}")
# raise
# except Exception as e:
# raise
# return
from botocore.exceptions import NoCredentialsError
def check_s3_bucket_exists(s3_client, bucket_name: str):
try:
s3_client.head_bucket(Bucket=bucket_name)
print(f"{bucket_name} exists")
except NoCredentialsError:
print("AWS credentials not found")
return False
except s3_client.exceptions.ClientError as e:
error_code = e.response["Error"]["Code"]
if error_code == "404":
print(f"{bucket_name} does not exist")
raise
else:
print(f"Error {error_code}")
raise
except Exception as e:
raise
return True
######################################## GENERAL SETTINGS ########################################
TEST = False # True to run test prompt - just for testing model connection
TODAY = datetime.now().strftime("%Y%m%d")
MAX_CONTEXT_LENGTH = 100000
######################################## TRACKING ########################################
UPLOAD_FREQUENCY = 10
######################################## SYSTEM ARGUMENTS ########################################
# read_mode, run_mode, input_dir, output_dir, consolidated_output_dir
def get_value_from_env(key: str, default_value: str = None) -> str:
value = os.getenv(key, default_value)
if value is not None:
return value
raise KeyError(f"{key} not found in .env file")
def get_arg_value(arg_name, default):
args = [item for item in sys.argv if arg_name == item.split("=")[0]]
if len(args) == 0:
return default
elif len(args) == 1:
return args[0].split("=")[1]
else:
raise Exception(f"Too many argument values: {args}")
# Run config args
RUN_MODE = get_arg_value("run_mode", "ec2") # Valid: local or ec2
READ_MODE = get_arg_value("read_mode", "s3") # Valid: local or s3
BATCH_ID = get_arg_value("batch_id", "test_batch")
# Per-file logging settings (for debugging)
ENABLE_PER_FILE_LOGGING = get_arg_value("enable_per_file_logging", "False") == "True"
PER_FILE_LOG_LEVEL = get_arg_value(
"per_file_log_level", "DEBUG"
).upper() # DEBUG, INFO, WARNING, ERROR
PER_FILE_LOG_DIR = get_arg_value("per_file_log_dir", "logs")
ENABLE_RUNTIME_ROTATION = False # Set to True to enable multi-runtime failover
# Field args
FIELDS = get_arg_value("fields", "all") # Valid: one_to_one, one_to_n, all
FIELD_JSON_PATH = "src/prompts/investment_prompts.json"
# Client-specific args
STATE = [s.strip() for s in get_arg_value("state", "None").upper().split("-") if s]
CLIENT = [s.strip() for s in get_arg_value("client", "None").split("-") if s]
# File IO args
LOCAL_PATH = get_arg_value(
"input_dir", "data/test"
) # Valid: any valid path that contains txt files
S3_PREFIX = get_arg_value("s3_prefix", "")
S3_BUCKET = get_arg_value("s3_bucket", "")
OUTPUT_DIRECTORY = get_arg_value(
"output_dir", "output_individual"
) # Valid: any valid directory
TRACKING_FILE = get_arg_value("tracking_file", f"{BATCH_ID}_tracking.csv")
WRITE_TO_S3 = get_arg_value("write_to_s3", "True") == "True"
S3_OUTPUT_BUCKET = get_arg_value("s3_output_bucket", default="doczy-output")
# Filtering args
FILTER_ALREADY_PROCESSED = (
get_arg_value("filter", False) == "True"
) # Valid: True or False
# Multithreading args
MAX_WORKERS = int(get_arg_value("max_workers", 2)) # Valid: any integer
# default false for the regex based IRS chunking
IRS_REGEX_CHECK = get_arg_value("irs_regex_check", False) == "True"
# QCQA args - only need to be set when running qa_qc.py INDEPENDENTLY, not needed for at-scale runs
AC_DF = get_arg_value("ac_df", None)
B_DF = get_arg_value("b_df", None)
DF_READ_MODE = get_arg_value("df_read_mode", "s3")
######################################## FILE LOG ########################################
FILE_LOG_FIELDS = [
"filename",
"process_type",
"start_time",
"end_time",
"processing_time_seconds",
"delta_time_hours",
"status",
"error",
"memory_usage_mb",
"cpu_percent",
]
FILE_LOG_NAME = f"{BATCH_ID}_filelog.csv"
if not os.path.exists(FILE_LOG_NAME):
with open(FILE_LOG_NAME, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FILE_LOG_FIELDS)
writer.writeheader()
######################################## CLIENT SETTINGS ########################################
CLIENT_NAME = get_arg_value("client_name", "Test-Client")
PROV_TYPE = None
######################################## I/O SETTINGS ########################################
CONSOLIDATED_OUTPUT_DIRECTORY = "output_consolidated"
REPORTING_OUTPUT_DIRECTORY = "output_reports"
UNPROCESSED_RESULTS_NAME = f"{BATCH_ID}-B-Unprocessed.csv"
AC_RESULTS_NAME = f"{BATCH_ID}-AC.csv"
B_RESULTS_NAME = f"{BATCH_ID}-B.csv"
TABLE_ANALYSIS_NAME = f"{BATCH_ID}-Table-Analysis.csv"
######################################## AWS SETTINGS #########################################
# RUN_MODE = "local" # for testing purposes only
# Bedrock
if RUN_MODE == "local":
AWS_ACCESS_KEY_ID = get_value_from_env("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = get_value_from_env("AWS_SECRET_ACCESS_KEY")
AWS_SESSION_TOKEN = get_value_from_env("AWS_SESSION_TOKEN")
# Bedrock
config = Config(read_timeout=2000)
BEDROCK_RUNTIME = boto3.client(
service_name="bedrock-runtime",
region_name="us-east-1",
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
aws_session_token=AWS_SESSION_TOKEN,
config=config,
)
# S3
S3_CLIENT = boto3.client(
"s3",
region_name="us-east-2",
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
aws_session_token=AWS_SESSION_TOKEN,
)
elif RUN_MODE == "ec2":
# Bedrock
config = Config(
read_timeout=4000, max_pool_connections=60
) # Doubled read_timeout to 4000
BEDROCK_RUNTIME = boto3.client(
service_name="bedrock-runtime", region_name="us-east-1", config=config
)
# S3
S3_CLIENT = boto3.client("s3", region_name="us-east-2")
# Check that S3_OUTPUT_BUCKET exists and raise an error if not
if WRITE_TO_S3:
check_s3_bucket_exists(S3_CLIENT, S3_OUTPUT_BUCKET)
# Claude model IDs
MODEL_ID_CLAUDE3_HAIKU = "anthropic.claude-3-haiku-20240307-v1:0"
MODEL_ID_CLAUDE35_SONNET = "anthropic.claude-3-5-sonnet-20240620-v1:0"
MODEL_ID_CLAUDE2 = "anthropic.claude-instant-v1"
MODEL_ID_CLAUDE35_SONNET_V2 = "anthropic.claude-3-5-sonnet-20241022-v2:0"
MODEL_ID_CLAUDE37_SONNET = "us.anthropic.claude-3-7-sonnet-20250219-v1:0"
MODEL_ID_CLAUDE4_SONNET = "us.anthropic.claude-sonnet-4-20250514-v1:0"
MODEL_ID_CLAUDE45_SONNET = "us.anthropic.claude-sonnet-4-5-20250929-v1:0"
# Model aliases for easy upgrades
MODEL_ALIASES = {
"sonnet_37" : MODEL_ID_CLAUDE37_SONNET,
"sonnet_4" : MODEL_ID_CLAUDE4_SONNET,
"sonnet_45": MODEL_ID_CLAUDE45_SONNET,
"sonnet_latest": MODEL_ID_CLAUDE4_SONNET,
"haiku_latest": MODEL_ID_CLAUDE3_HAIKU,
"legacy_sonnet": MODEL_ID_CLAUDE35_SONNET,
}
def resolve_model_id(model_identifier: str) -> str:
"""
Resolve a model identifier to its actual model ID.
Supports both direct model IDs and aliases.
"""
return MODEL_ALIASES.get(model_identifier, model_identifier)
######################################## CLAUDE AND PROMPT TRACKING ########################################
ENABLE_ANSWER_TRACKING = False
ANSWER_TRACKING_DICT = {}
######################################## POSTPROCESSING SETTINGS ########################################
FUZZY_MATCH_THRESHOLD = 0.8
FILE_NAME_COLUMN = "Contract Name"
BLANKS_THRESHOLD = 0.5
######################################## COMPLEX FLAG SETTINGS ########################################
COMPLEX_MAX_WORKERS = 50
RATE_THRESHOLD = 10
TABLE_THRESHOLD = 2
COMPLEX_OUTPUT_PATH = "complex_flag_output"
COMPLEX_OUTPUT_FILENAME = f"{TODAY}_complex_flag_test.csv"
TABLE_ROW_LIMIT = 10
######################################## EC2 ########################################
MODEL_STATS = defaultdict(
lambda: {
"requests": 0,
"tokens_sent": 0,
"tokens_received": 0,
"total_time": 0,
"claude2_requests": 0,
"claude3_requests": 0,
"claude35_requests": 0,
}
)
GLOBAL_STATS = {
"total_requests": 0,
"total_tokens_sent": 0,
"total_tokens_received": 0,
"total_time": 0,
"total_claude2_requests": 0,
"total_claude3_requests": 0,
"total_claude35_requests": 0,
}
def assume_role_and_get_runtime(account_id, role_name):
sts_client = boto3.client("sts")
role_arn = f"arn:aws:iam::{account_id}:role/{role_name}"
assumed_role = sts_client.assume_role(
RoleArn=role_arn, RoleSessionName=f"UATLambdaSession"
)
credentials = assumed_role["Credentials"]
runtime = boto3.client(
service_name="bedrock-runtime",
region_name="us-east-1",
aws_access_key_id=credentials["AccessKeyId"],
aws_secret_access_key=credentials["SecretAccessKey"],
aws_session_token=credentials["SessionToken"],
config=config,
)
return runtime
dev_account_id = "660131068782"
dev_role_name = "doczy-dev-bedrock-lambda-role"
prod_account_id = "211125720533"
prod_role_name = "doczy-prod-bedrock-lambda-role"
############## S3 BUCKETS FOR PDF FILES ##############
DOCZY_PDF_FILES_BUCKET_NAME = "doczy-pdf-files" # sample bucket name added. we can either use this or create a new one
DOCZY_PDF_FILES_BUCKET_S3_URL = f"https://{DOCZY_PDF_FILES_BUCKET_NAME}.s3.us-east-2.amazonaws.com/" # sample s3 url added. we can either use this or create a new one
############## VISION API SETTINGS ##############
ENABLE_VISION = get_arg_value("enable_vision", "False") == "True" # False by default