class LLMClient_v1
Client for interacting with LLM providers (OpenAI, Anthropic, Azure, etc.)
/tf/active/vicechatdev/contract_validity_analyzer/utils/llm_client.py
18 - 613
moderate
Purpose
Client for interacting with LLM providers (OpenAI, Anthropic, Azure, etc.)
Source Code
class LLMClient:
"""Client for interacting with LLM providers (OpenAI, Anthropic, Azure, etc.)"""
# Class-level variable to track instances
_instances = {}
def __new__(cls, config=None):
"""
Implement singleton pattern to prevent multiple initializations
with the same configuration.
"""
config = config or {}
# Create a key from the core config parameters
provider = config.get('provider', 'openai')
model = config.get('model', 'gpt-4o')
key = f"{provider}:{model}"
# If an instance with this configuration exists, return it
if key in cls._instances:
return cls._instances[key]
# Otherwise create a new instance
instance = super(LLMClient, cls).__new__(cls)
cls._instances[key] = instance
return instance
def __init__(self, config=None):
"""
Initialize the LLM client with the provided configuration.
Args:
config: Dictionary with configuration parameters:
- provider: 'openai', 'anthropic', 'azure', or 'local'
- model: Model name to use
- api_key: API key for the selected provider
- temperature: Sampling temperature (0-1)
- max_tokens: Maximum tokens in completion
- (other provider-specific parameters)
"""
config = config or {}
# Check if this instance has already been initialized
if hasattr(self, 'initialized') and self.initialized:
return
self.provider = config.get('provider', 'openai')
self.model = config.get('model', 'gpt-4o')
self.temperature = config.get('temperature', 0.0)
self.max_tokens = config.get('max_tokens', 4000)
self.retry_attempts = config.get('retry_attempts', 3)
self.retry_delay = config.get('retry_delay', 1)
# Track token usage
self.total_prompt_tokens = 0
self.total_completion_tokens = 0
# Initialize client based on provider
if self.provider == 'openai':
try:
import openai
api_key = config.get('api_key') or os.environ.get('OPENAI_API_KEY')
if not api_key:
raise ValueError("OpenAI API key is required")
self.client = openai.OpenAI(api_key=api_key)
except ImportError:
logger.error("OpenAI package not installed. Run 'pip install openai'")
raise
elif self.provider == 'anthropic':
try:
import anthropic
api_key = config.get('api_key') or os.environ.get('ANTHROPIC_API_KEY')
if not api_key:
raise ValueError("Anthropic API key is required")
self.client = anthropic.Anthropic(api_key=api_key)
except ImportError:
logger.error("Anthropic package not installed. Run 'pip install anthropic'")
raise
elif self.provider == 'azure':
try:
from openai import AzureOpenAI
api_key = config.get('azure_api_key') or os.environ.get('AZURE_OPENAI_API_KEY')
endpoint = config.get('azure_endpoint') or os.environ.get('AZURE_OPENAI_ENDPOINT')
api_version = config.get('azure_api_version', '2023-12-01-preview')
if not api_key or not endpoint:
raise ValueError("Azure OpenAI API key and endpoint are required")
self.client = AzureOpenAI(
api_key=api_key,
azure_endpoint=endpoint,
api_version=api_version
)
except ImportError:
logger.error("OpenAI package not installed. Run 'pip install openai'")
raise
else:
raise ValueError(f"Unsupported provider: {self.provider}")
self.initialized = True
logger.info(f"LLM client initialized with provider: {self.provider}, model: {self.model}")
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10),
retry=retry_if_exception_type((RequestException, Exception))
)
def generate_response(self, messages: List[Dict[str, str]], **kwargs) -> Dict[str, Any]:
"""
Generate a response using the configured LLM.
Args:
messages: List of message dictionaries with 'role' and 'content'
**kwargs: Additional parameters to override defaults
Returns:
Dictionary with response and metadata
"""
try:
# Override default parameters with kwargs
temperature = kwargs.get('temperature', self.temperature)
max_tokens = kwargs.get('max_tokens', self.max_tokens)
start_time = time.time()
if self.provider == 'openai' or self.provider == 'azure':
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens
)
# Extract response content and usage
content = response.choices[0].message.content
usage = response.usage
# Track token usage
self.total_prompt_tokens += usage.prompt_tokens
self.total_completion_tokens += usage.completion_tokens
return {
'content': content,
'usage': {
'prompt_tokens': usage.prompt_tokens,
'completion_tokens': usage.completion_tokens,
'total_tokens': usage.total_tokens
},
'model': self.model,
'processing_time': time.time() - start_time
}
elif self.provider == 'anthropic':
# Convert messages to Anthropic format
anthropic_messages = []
system_message = None
for msg in messages:
if msg['role'] == 'system':
system_message = msg['content']
else:
anthropic_messages.append({
'role': msg['role'],
'content': msg['content']
})
response = self.client.messages.create(
model=self.model,
max_tokens=max_tokens,
temperature=temperature,
system=system_message,
messages=anthropic_messages
)
content = response.content[0].text
# Track token usage (Anthropic provides usage info)
usage_info = response.usage
self.total_prompt_tokens += usage_info.input_tokens
self.total_completion_tokens += usage_info.output_tokens
return {
'content': content,
'usage': {
'prompt_tokens': usage_info.input_tokens,
'completion_tokens': usage_info.output_tokens,
'total_tokens': usage_info.input_tokens + usage_info.output_tokens
},
'model': self.model,
'processing_time': time.time() - start_time
}
except Exception as e:
logger.error(f"Error generating LLM response: {e}")
raise
def analyze_contract(self, document_text: str, filename: str) -> Dict[str, Any]:
"""
Analyze a contract document for validity information using a 2-step approach.
Step 1: Focus on finding expiry/validity dates by carefully reading the text
Step 2: Extract complete contract information using Step 1 results and full context
Args:
document_text: Extracted text from the contract
filename: Name of the contract file
Returns:
Dictionary with analysis results
"""
try:
# Step 1: Focus on finding expiry/validity dates
step1_result = self._find_expiry_dates(document_text, filename)
if not step1_result or step1_result.get('error'):
logger.warning(f"Step 1 (expiry date finding) failed for {filename}: {step1_result.get('error', 'Unknown error')}")
# Continue with empty step1 result rather than failing completely
step1_result = {'expiry_analysis': 'Step 1 failed', 'error': True}
# Step 2: Complete contract analysis with expiry date context
step2_result = self._extract_complete_contract_info(step1_result, document_text, filename)
if not step2_result or step2_result.get('error'):
return self._create_fallback_result(filename, step2_result.get('error', 'Step 2 analysis failed'))
# Combine results with metadata
final_result = step2_result
final_result['_metadata'] = {
'processing_time': step1_result.get('_metadata', {}).get('processing_time', 0) +
step2_result.get('_metadata', {}).get('processing_time', 0),
'token_usage': {
'step1_tokens': step1_result.get('_metadata', {}).get('token_usage', {}),
'step2_tokens': step2_result.get('_metadata', {}).get('token_usage', {}),
'total_tokens': (step1_result.get('_metadata', {}).get('token_usage', {}).get('total_tokens', 0) +
step2_result.get('_metadata', {}).get('token_usage', {}).get('total_tokens', 0))
},
'model': self.model,
'analysis_steps': 2
}
return final_result
except Exception as e:
logger.error(f"Error in 2-step contract analysis for {filename}: {e}")
return self._create_fallback_result(filename, f"Analysis failed: {str(e)}")
def _find_expiry_dates(self, document_text: str, filename: str) -> Dict[str, Any]:
"""
Step 1: Focus specifically on finding expiry/validity dates in the contract.
"""
prompt = self._get_expiry_date_prompt(document_text, filename)
messages = [
{"role": "system", "content": prompt["system"]},
{"role": "user", "content": prompt["user"]}
]
try:
response = self.generate_response(messages, temperature=0.0)
content = response['content'].strip()
# The response should be plain text analysis, not JSON
analysis = {
'expiry_analysis': content,
'_metadata': {
'processing_time': response.get('processing_time', 0),
'token_usage': response.get('usage', {}),
'model': response.get('model', self.model)
}
}
return analysis
except Exception as e:
logger.error(f"Error in Step 1 expiry date analysis for {filename}: {e}")
return {'error': f"Step 1 analysis failed: {str(e)}"}
def _extract_complete_contract_info(self, step1_data: Dict[str, Any], document_text: str, filename: str) -> Dict[str, Any]:
"""
Step 2: Extract complete contract information using Step 1 expiry analysis and full document text.
"""
prompt = self._get_complete_contract_analysis_prompt(step1_data, document_text, filename)
messages = [
{"role": "system", "content": prompt["system"]},
{"role": "user", "content": prompt["user"]}
]
try:
response = self.generate_response(messages, temperature=0.0)
content = response['content'].strip()
# Parse JSON response
if content.startswith('```json'):
content = content[7:-3].strip()
elif content.startswith('```'):
content = content[3:-3].strip()
analysis = json.loads(content)
analysis['_metadata'] = {
'processing_time': response.get('processing_time', 0),
'token_usage': response.get('usage', {}),
'model': response.get('model', self.model)
}
return analysis
except json.JSONDecodeError as e:
logger.error(f"Failed to parse Step 2 JSON response for {filename}: {e}")
return {'error': f"Failed to parse Step 2 response: {str(e)}"}
except Exception as e:
logger.error(f"Error in Step 2 analysis for {filename}: {e}")
return {'error': f"Step 2 analysis failed: {str(e)}"}
def _create_fallback_result(self, filename: str, error_message: str) -> Dict[str, Any]:
"""Create a fallback result structure when analysis fails."""
return {
'filename': filename,
'contract_type': 'Unknown',
'third_parties': [],
'third_party_emails': [],
'third_party_tax_ids': [],
'start_date': None,
'end_date': None,
'is_in_effect': False,
'confidence': 0.0,
'analysis_notes': error_message,
'error': True
}
def _get_contract_analysis_prompt(self, document_text: str, filename: str) -> Dict[str, str]:
"""Generate the prompt for contract analysis."""
system_prompt = """You are an expert legal document analyst specializing in contract validity assessment. Your task is to analyze legal documents (contracts, CDAs, MSAs, etc.) and extract key information about their validity status.
IMPORTANT: You must respond with ONLY a valid JSON object, no additional text or markdown formatting.
For each document, you need to:
1. Identify the contract type (MSA, CDA, NDA, PO, MTA, Service Agreement, etc.)
2. Identify all third parties involved in the contract (excluding ViceBio)
3. Extract start and end dates with high precision
4. Determine if the contract is currently in effect
5. Assess your confidence in the analysis
CONTRACT TYPE IDENTIFICATION:
- Look for clear indicators in titles, headers, or explicit statements
- Common types: MSA (Master Service Agreement), CDA (Confidentiality/Non-Disclosure Agreement),
NDA (Non-Disclosure Agreement), MTA (Material Transfer Agreement), PO (Purchase Order),
Service Agreement, License Agreement, Supply Agreement, Employment Agreement, etc.
- If type is unclear, analyze the primary purpose and obligations described
- Use "Unknown" if contract type cannot be determined
THIRD PARTY INFORMATION EXTRACTION:
- Identify all third party company names (excluding ViceBio/Vicebio/ViceBio Ltd)
- For each third party, extract:
* Email addresses: Look for contact emails, official correspondence addresses (email@domain.com format)
* Tax ID/EIN/Registration numbers in various international formats:
- US: Federal Tax ID, EIN (e.g., 12-3456789, 123456789)
- UK: Company Registration Number, VAT Number (e.g., 12345678, GB123456789)
- European: VAT Numbers with country codes (e.g., BE0664510277, FR12345678901, DE123456789)
- Australia: Australian Business Number (ABN), Australian Company Number (ACN) (e.g., 12 345 678 901)
- Canada: Business Number (BN) (e.g., 123456789RC0001)
- Netherlands: KvK number, BTW number
- Germany: Handelsregisternummer, USt-IdNr
- France: SIRET, SIREN numbers
- Look for: "Tax ID:", "EIN:", "VAT:", "Registration Number:", "Company Registration:", "Business Number:", "ABN:", "ACN:", "KvK:", "BTW:", "SIRET:", "SIREN:", "USt-IdNr:", etc.
- Check signature blocks, letterheads, contact sections, company details sections
- Include all email addresses and tax IDs found for each party
DATE EXTRACTION GUIDELINES:
- Look for explicit start/end dates in various formats (DD/MM/YYYY, MM/DD/YYYY, Month DD, YYYY, etc.)
- Search for duration-based terms like "valid for X years", "expires in X years", "during X years", "term of X years"
- Look for renewal clauses and automatic extension terms
- Consider signature dates as potential start dates if no explicit start date is found
- For duration terms, calculate end dates from the start date
- Pay attention to context clues like "effective from", "commencing on", "valid until", "expires on"
- Handle relative dates like "for a period of 3 years from the date of signature"
CRITICAL DATE CALCULATION RULES:
- When you find phrases like "shall remain in effect for a period of X years" or "term of X years", ALWAYS calculate the end date
- If start date is provided and duration is specified, ADD the duration to the start date
- Example: "commence on 2023-01-01" + "period of three (3) years" = end date 2026-01-01
- Look for patterns like "commence on [DATE] and...remain in effect for a period of X years"
- Handle written numbers: "three (3) years", "five (5) years", etc.
- If only signature date + duration is available, use signature date as start date for calculation
- For unclear durations, use context clues but always attempt to calculate when duration is specified
VALIDITY ASSESSMENT:
- Consider today's date as July 2, 2025
- A contract is "in effect" if the current date falls between start and end dates (inclusive)
- LOGIC: if start_date <= July 2, 2025 <= end_date, then is_in_effect = true
- If no end date exists (indefinite/perpetual contracts), and start date has passed, set is_in_effect = true
- Account for auto-renewal clauses
- Consider grace periods for recently expired contracts
- If dates are ambiguous, err on the side of caution
- IMPORTANT: Your analysis_notes must be consistent with your is_in_effect determination
OUTPUT FORMAT:
Respond with a JSON object containing exactly these fields:
{
"filename": "document filename",
"contract_type": "MSA/CDA/NDA/PO/MTA/Service Agreement/License Agreement/Unknown/etc.",
"third_parties": ["list", "of", "third", "party", "names"],
"third_party_emails": ["list", "of", "email", "addresses"],
"third_party_tax_ids": ["list", "of", "tax", "ids"],
"start_date": "YYYY-MM-DD or null",
"end_date": "YYYY-MM-DD or null",
"is_in_effect": true/false,
"confidence": 0.0-1.0,
"analysis_notes": "brief explanation of findings and reasoning"
}"""
user_prompt = f"""Please analyze the following contract document:
FILENAME: {filename}
DOCUMENT TEXT:
{document_text[:8000]} # Limit text to avoid token limits
Analyze this document and provide the required JSON response."""
return {
"system": system_prompt,
"user": user_prompt
}
def _get_expiry_date_prompt(self, document_text: str, filename: str) -> Dict[str, str]:
"""Generate the Step 1 prompt for finding expiry/validity dates."""
system_prompt = """You are an expert legal document analyst. Your task is to carefully read a contract document and find the expiry and/or validity date of the contract.
INSTRUCTIONS:
- Read through the entire document text carefully, including any metadata, signatures, or footer information
- Look for any statements that indicate when the contract expires, terminates, or becomes invalid
- Pay special attention to "Term" sections and various forms of date expressions:
* Explicit end dates: "expires on December 31, 2025", "valid until 2026-01-01", "terminates on [date]"
* Duration-based terms: "valid for 3 years from execution", "term of 24 months", "for a period of X years", "period of one (1) year"
* Renewal clauses: "automatically renews for additional 1-year periods", "renewable annually"
* Termination conditions: "may be terminated with 30 days notice", "perpetual until terminated"
* Indefinite terms: "indefinite", "perpetual", "until terminated", "ongoing"
- Consider signature dates combined with duration terms
- Look for phrases like: "shall remain in effect", "valid for a period of", "expires", "terminates", "end date", "duration", "term", "shall commence", "shall continue for"
- Calculate end dates when you find start dates combined with duration terms
- For CDAs/NDAs, look for typical duration patterns like "3 years", "5 years", or "perpetual"
- Check if the contract mentions standard commercial terms or references to other agreements that might contain duration info
COMMON TERM CLAUSE PATTERNS:
- "Term: This Agreement shall commence and be effective from the Effective Date and shall continue for a period of one (1) year"
- "This Agreement shall commence... and shall continue for a period of [X] year(s)"
- "The term of this Agreement is [X] years from the effective date"
- Look for combinations of effective dates + duration periods
CALCULATION RULES:
- If you find "effective from [DATE]" + "period of one (1) year", calculate end date as exactly 1 year from start date
- If you find "period of X years" without explicit start date, look for signature date or execution date as start date
- Handle written numbers: "one (1) year" = 1 year, "five (5) years" = 5 years
- For documents signed on a specific date with duration terms, use signature date as start date
SPECIAL FOCUS FOR CDAs/NDAs:
- Many CDAs have standard durations (1-5 years)
- Some CDAs are perpetual/indefinite until terminated
- Look for survival clauses that specify how long confidentiality obligations last
- Check for any references to "return of information" deadlines which might indicate duration
RESPONSE FORMAT:
Provide a detailed analysis in plain text (not JSON) explaining:
1. What expiry/validity date information you found (or if you found evidence of indefinite/perpetual terms)
2. How you calculated or determined the date (show your reasoning step by step with dates)
3. Quote the exact relevant text passages that led to your conclusion
4. If you found duration terms, show your calculation: start date + duration = end date
5. If no clear expiry date is found, specify whether this appears to be:
- An indefinite/perpetual contract
- Missing information from the document excerpt
- A contract where duration is defined elsewhere
Be thorough and detailed in your analysis. This information will be used in a second step to extract complete contract details."""
user_prompt = f"""Please analyze the following contract document to find the expiry and/or validity date:
FILENAME: {filename}
DOCUMENT TEXT:
{document_text}
What is the expiry and/or validity date of this contract? Find the answer by carefully reading and looking for statements in the text that allow to calculate an end date. If no explicit end date exists, determine if this is an indefinite/perpetual contract or if duration information might be missing."""
return {
"system": system_prompt,
"user": user_prompt
}
def _get_complete_contract_analysis_prompt(self, step1_data: Dict[str, Any], document_text: str, filename: str) -> Dict[str, str]:
"""Generate the Step 2 prompt for complete contract analysis."""
expiry_analysis = step1_data.get('expiry_analysis', 'No expiry analysis available')
system_prompt = """You are an expert legal document analyst. You are performing the second step of contract analysis where you extract key information needed for an Excel report.
CONTEXT INPUTS:
You have two sources of information:
1. EXPIRY DATE ANALYSIS: A detailed analysis focused on finding expiry/validity dates from Step 1
2. FULL DOCUMENT TEXT: The complete contract text for comprehensive analysis
INSTRUCTIONS:
- Use the expiry date analysis from Step 1 as your primary source for end date information
- Extract all required contract information from the full document text
- For contract type, look for clear indicators in titles, headers, or explicit statements
- Identify all third parties (excluding ViceBio/Vicebio/ViceBio Ltd)
- Use today's date as July 2, 2025 for validity assessment
- VALIDITY LOGIC: A contract is in effect if start_date <= July 2, 2025 <= end_date
- For indefinite/perpetual contracts with no end_date, check if start_date <= July 2, 2025
- CRITICAL: Ensure is_in_effect boolean matches your analysis_notes reasoning
- If your analysis_notes say the contract is "in effect" or "currently valid", set is_in_effect = true
- If your analysis_notes say the contract is "expired" or "not in effect", set is_in_effect = false
- Be as accurate as possible with date extraction and calculations
CONTRACT TYPES TO IDENTIFY:
- MSA (Master Service Agreement)
- CDA (Confidentiality/Non-Disclosure Agreement)
- NDA (Non-Disclosure Agreement)
- MTA (Material Transfer Agreement)
- PO (Purchase Order)
- Service Agreement, License Agreement, Supply Agreement
- Employment Agreement, Consulting Agreement
- If unclear, analyze primary purpose and use "Unknown" if indeterminate
THIRD PARTY INFORMATION EXTRACTION:
- Extract all third party company names (excluding ViceBio/Vicebio/ViceBio Ltd)
- For each third party, look for:
* Email addresses: Look for patterns like email@domain.com, particularly contact emails, official correspondence addresses
* Tax ID/EIN/Registration numbers in various international formats:
- US: Federal Tax ID, EIN (e.g., 12-3456789, 123456789)
- UK: Company Registration Number, VAT Number (e.g., 12345678, GB123456789)
- European: VAT Numbers with country codes (e.g., BE0664510277, FR12345678901, DE123456789)
- Australia: Australian Business Number (ABN), Australian Company Number (ACN) (e.g., 12 345 678 901)
- Canada: Business Number (BN) (e.g., 123456789RC0001)
- Netherlands: KvK number, BTW number
- Germany: Handelsregisternummer, USt-IdNr
- France: SIRET, SIREN numbers
- Look for phrases like: "Tax ID:", "EIN:", "VAT:", "Registration Number:", "Company Registration:", "Business Number:", "ABN:", "ACN:", "KvK:", "BTW:", "SIRET:", "SIREN:", "USt-IdNr:", etc.
- Common locations for this information: signature blocks, letterheads, contact information sections, company details sections, footer information
- If multiple email addresses or tax IDs are found for the same party, include all of them
END DATE HANDLING:
- If Step 1 found a specific end date, use that date
- If Step 1 indicates the contract is indefinite/perpetual, set end_date to null but note this in analysis_notes
- If Step 1 found missing information, indicate uncertainty in analysis_notes
- For contracts without explicit end dates, consider industry standards:
* CDAs/NDAs: often 3-5 years or indefinite
* Service agreements: typically 1-3 years with renewals
* Purchase orders: usually short-term or project-based
IMPORTANT: You must respond with ONLY a valid JSON object, no additional text or markdown formatting.
OUTPUT FORMAT:
{
"filename": "document filename",
"contract_type": "MSA/CDA/NDA/PO/MTA/Service Agreement/License Agreement/Unknown/etc.",
"third_parties": ["list", "of", "third", "party", "names"],
"third_party_emails": ["list", "of", "email", "addresses"],
"third_party_tax_ids": ["list", "of", "tax", "ids"],
"start_date": "YYYY-MM-DD or null",
"end_date": "YYYY-MM-DD or null",
"is_in_effect": true/false,
"confidence": 0.0-1.0,
"analysis_notes": "brief explanation of findings and reasoning, especially for end date determination. If indefinite/perpetual, state this clearly. If duration info is missing, indicate this."
}"""
user_prompt = f"""Please extract complete contract information using the provided context:
FILENAME: {filename}
EXPIRY DATE ANALYSIS (from Step 1):
{expiry_analysis}
FULL DOCUMENT TEXT:
{document_text}
Extract the key contract information and provide the required JSON response."""
return {
"system": system_prompt,
"user": user_prompt
}
def get_usage_stats(self) -> Dict[str, int]:
"""Get token usage statistics."""
return {
'total_prompt_tokens': self.total_prompt_tokens,
'total_completion_tokens': self.total_completion_tokens,
'total_tokens': self.total_prompt_tokens + self.total_completion_tokens
}
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
bases: Parameter of type
Return Value
Returns unspecified type
Class Interface
Methods
__new__(cls, config)
Purpose: Implement singleton pattern to prevent multiple initializations with the same configuration.
Parameters:
cls: Parameterconfig: Parameter
Returns: None
__init__(self, config)
Purpose: Initialize the LLM client with the provided configuration. Args: config: Dictionary with configuration parameters: - provider: 'openai', 'anthropic', 'azure', or 'local' - model: Model name to use - api_key: API key for the selected provider - temperature: Sampling temperature (0-1) - max_tokens: Maximum tokens in completion - (other provider-specific parameters)
Parameters:
config: Parameter
Returns: None
generate_response(self, messages) -> Dict[str, Any]
Purpose: Generate a response using the configured LLM. Args: messages: List of message dictionaries with 'role' and 'content' **kwargs: Additional parameters to override defaults Returns: Dictionary with response and metadata
Parameters:
messages: Type: List[Dict[str, str]]
Returns: Returns Dict[str, Any]
analyze_contract(self, document_text, filename) -> Dict[str, Any]
Purpose: Analyze a contract document for validity information using a 2-step approach. Step 1: Focus on finding expiry/validity dates by carefully reading the text Step 2: Extract complete contract information using Step 1 results and full context Args: document_text: Extracted text from the contract filename: Name of the contract file Returns: Dictionary with analysis results
Parameters:
document_text: Type: strfilename: Type: str
Returns: Returns Dict[str, Any]
_find_expiry_dates(self, document_text, filename) -> Dict[str, Any]
Purpose: Step 1: Focus specifically on finding expiry/validity dates in the contract.
Parameters:
document_text: Type: strfilename: Type: str
Returns: Returns Dict[str, Any]
_extract_complete_contract_info(self, step1_data, document_text, filename) -> Dict[str, Any]
Purpose: Step 2: Extract complete contract information using Step 1 expiry analysis and full document text.
Parameters:
step1_data: Type: Dict[str, Any]document_text: Type: strfilename: Type: str
Returns: Returns Dict[str, Any]
_create_fallback_result(self, filename, error_message) -> Dict[str, Any]
Purpose: Create a fallback result structure when analysis fails.
Parameters:
filename: Type: strerror_message: Type: str
Returns: Returns Dict[str, Any]
_get_contract_analysis_prompt(self, document_text, filename) -> Dict[str, str]
Purpose: Generate the prompt for contract analysis.
Parameters:
document_text: Type: strfilename: Type: str
Returns: Returns Dict[str, str]
_get_expiry_date_prompt(self, document_text, filename) -> Dict[str, str]
Purpose: Generate the Step 1 prompt for finding expiry/validity dates.
Parameters:
document_text: Type: strfilename: Type: str
Returns: Returns Dict[str, str]
_get_complete_contract_analysis_prompt(self, step1_data, document_text, filename) -> Dict[str, str]
Purpose: Generate the Step 2 prompt for complete contract analysis.
Parameters:
step1_data: Type: Dict[str, Any]document_text: Type: strfilename: Type: str
Returns: Returns Dict[str, str]
get_usage_stats(self) -> Dict[str, int]
Purpose: Get token usage statistics.
Returns: Returns Dict[str, int]
Required Imports
import logging
import os
import json
import time
from typing import Dict
Usage Example
# Example usage:
# result = LLMClient(bases)
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class LLMClient 79.5% similar
-
function get_llm_instance 68.1% similar
-
class AzureOpenAIChatLLM 65.6% similar
-
function test_llm_client 64.4% similar
-
class StatisticalAgent 58.5% similar