walaa2022's picture
Update app.py
f4bbd39 verified
raw
history blame
9.37 kB
import os
import gradio as gr
import pandas as pd
import torch
import logging
from transformers import pipeline, AutoModelForSequenceClassification, AutoTokenizer
import gc
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Device configuration
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
logger.info(f"Using device: {DEVICE}")
def clear_gpu_memory():
"""Utility function to clear GPU memory"""
if DEVICE == "cuda":
torch.cuda.empty_cache()
gc.collect()
class FinancialAnalyzer:
"""Simplified Financial Analyzer using small models"""
def __init__(self):
# Initialize with two small models
self.sentiment_model = None
self.analysis_model = None
self.load_models()
def load_models(self):
"""Load the required models"""
try:
# Load FinBERT for sentiment analysis
self.sentiment_model = pipeline(
"text-classification",
model="ProsusAI/finbert",
torch_dtype=torch.float16 if DEVICE == "cuda" else torch.float32
)
# Load small model for analysis and recommendations
self.analysis_model = pipeline(
"text-generation",
model="TinyLlama/TinyLlama-1.1B-Chat-v1.0",
torch_dtype=torch.float16 if DEVICE == "cuda" else torch.float32
)
logger.info("Models loaded successfully")
except Exception as e:
logger.error(f"Error loading models: {str(e)}")
raise
def process_csv(self, file_obj):
"""Process CSV file and extract KPIs"""
try:
if file_obj is None:
raise ValueError("No file provided")
df = pd.read_csv(file_obj)
if df.empty:
raise ValueError("Empty CSV file")
# Get numeric columns
numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
if len(numeric_cols) == 0:
raise ValueError("No numeric columns found in CSV")
# Calculate basic KPIs
summary = df[numeric_cols].describe()
# Extract key metrics
metrics = {
'total': df[numeric_cols].sum(),
'average': df[numeric_cols].mean(),
'growth': df[numeric_cols].pct_change().mean() * 100
}
return summary, metrics
except Exception as e:
logger.error(f"Error processing CSV: {str(e)}")
raise
def analyze_financials(self, income_summary, balance_summary):
"""Generate financial analysis and recommendations"""
try:
financial_context = f"""
Income Statement Metrics:
{income_summary[0].to_string()}
Key Income Indicators:
{income_summary[1]}
Balance Sheet Metrics:
{balance_summary[0].to_string()}
Key Balance Sheet Indicators:
{balance_summary[1]}
"""
# Generate sentiment analysis
sentiment = self.sentiment_model(financial_context)[0]
# Generate business analysis
analysis_prompt = f"""[INST] Based on the following financial data, provide:
1. Current Business Status
2. Key Business Insights
3. Strategic Recommendations and Roadmap
Financial Context:
{financial_context}
Sentiment: {sentiment['label']} ({sentiment['score']:.2%})
Provide a concise but detailed analysis for each section.
[/INST]"""
response = self.analysis_model(
analysis_prompt,
max_length=1000,
temperature=0.7,
num_return_sequences=1
)
return self.format_response(response[0]['generated_text'], sentiment)
except Exception as e:
logger.error(f"Error in analysis: {str(e)}")
return "Error generating analysis"
def format_response(self, analysis_text, sentiment):
"""Format the analysis response into structured sections"""
try:
# Split the analysis into sections
sections = analysis_text.split('\n\n')
# Initialize output sections
status = []
insights = []
recommendations = []
# Process each section
current_section = None
for section in sections:
if "Business Status" in section:
current_section = status
elif "Key Business Insights" in section:
current_section = insights
elif "Strategic Recommendations" in section:
current_section = recommendations
elif current_section is not None:
current_section.append(section.strip())
# Format the final output
output = [
"# Financial Analysis Report\n\n",
f"## Overall Sentiment: {sentiment['label'].upper()} ({sentiment['score']:.2%})\n\n",
"## Current Business Status\n",
"".join(f"- {item}\n" for item in status if item),
"\n## Key Business Insights\n",
"".join(f"- {item}\n" for item in insights if item),
"\n## Strategic Recommendations & Roadmap\n",
"".join(f"- {item}\n" for item in recommendations if item)
]
return "".join(output)
except Exception as e:
logger.error(f"Error formatting response: {str(e)}")
return "Error formatting analysis results"
def analyze_statements(income_statement, balance_sheet):
"""Main function to analyze financial statements"""
try:
# Check if files are uploaded
if income_statement is None or balance_sheet is None:
return "Please upload both Income Statement and Balance Sheet CSV files."
# Get file names
income_filename = income_statement.name if hasattr(income_statement, 'name') else 'Income Statement'
balance_filename = balance_sheet.name if hasattr(balance_sheet, 'name') else 'Balance Sheet'
logger.info(f"Processing {income_filename} and {balance_filename}")
# Initialize analyzer
analyzer = FinancialAnalyzer()
# Process statements with better error handling
try:
income_summary = analyzer.process_csv(income_statement)
logger.info("Successfully processed Income Statement")
except Exception as e:
return f"Error processing Income Statement: {str(e)}\nPlease ensure it's a valid CSV file with numeric data."
try:
balance_summary = analyzer.process_csv(balance_sheet)
logger.info("Successfully processed Balance Sheet")
except Exception as e:
return f"Error processing Balance Sheet: {str(e)}\nPlease ensure it's a valid CSV file with numeric data."
# Generate analysis
logger.info("Generating analysis...")
result = analyzer.analyze_financials(income_summary, balance_summary)
clear_gpu_memory()
return result
except Exception as e:
logger.error(f"Analysis error: {str(e)}")
return f"""Analysis Error:
{str(e)}
Please verify:
1. Files are in CSV format
2. Files contain numeric data columns
3. Files follow standard financial statement format"""
# Create Gradio interface with improved file handling
iface = gr.Interface(
fn=analyze_statements,
inputs=[
gr.File(
label="Upload Income Statement (CSV)",
file_types=[".csv"],
file_count="single"
),
gr.File(
label="Upload Balance Sheet (CSV)",
file_types=[".csv"],
file_count="single"
)
],
outputs=gr.Markdown(),
title="Financial Statement Analyzer",
description="""## Financial Analysis Tool
How to use:
1. Click 'Upload Income Statement' to select your income statement CSV file
2. Click 'Upload Balance Sheet' to select your balance sheet CSV file
3. Wait for the analysis to complete
The tool will provide:
- Business Status Assessment
- Key Financial Insights
- Strategic Recommendations
Requirements:
- Files must be in CSV format
- Must contain numeric data columns
- Standard financial statement format preferred""",
flagging_mode="never"
)
# Launch the interface with better error handling
if __name__ == "__main__":
try:
iface.queue() # Enable queuing for better file handling
iface.launch(
share=False,
server_name="0.0.0.0",
server_port=7860,
show_api=False # Disable API tab for security
)
except Exception as e:
logger.error(f"Launch error: {str(e)}")
sys.exit(1)