walaa2022 commited on
Commit
f95f954
·
verified ·
1 Parent(s): 4682c30

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -264
app.py CHANGED
@@ -4,9 +4,7 @@ import pandas as pd
4
  import torch
5
  import logging
6
  import gc
7
- import re
8
  from transformers import pipeline
9
- from typing import Dict, List, Tuple, Optional
10
 
11
  # Setup logging
12
  logging.basicConfig(
@@ -19,13 +17,19 @@ logger = logging.getLogger(__name__)
19
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
20
  logger.info(f"Using device: {DEVICE}")
21
 
 
 
 
 
 
 
22
  class FinancialDataExtractor:
23
- """Extracts and processes financial data from raw CSV files"""
24
 
25
  def __init__(self):
26
- self.numeric_pattern = re.compile(r'[^\d.-]+')
27
 
28
- def clean_number(self, value: str) -> float:
29
  """Clean numeric values from financial statements"""
30
  try:
31
  if pd.isna(value) or value == '' or value == '-':
@@ -34,7 +38,7 @@ class FinancialDataExtractor:
34
  return float(value)
35
 
36
  # Remove currency symbols, spaces, commas
37
- cleaned = str(value).replace('$', '').replace(',', '').strip()
38
  # Handle parentheses for negative numbers
39
  if '(' in cleaned and ')' in cleaned:
40
  cleaned = '-' + cleaned.replace('(', '').replace(')', '')
@@ -42,74 +46,25 @@ class FinancialDataExtractor:
42
  except:
43
  return 0.0
44
 
45
- def process_income_statement(self, df: pd.DataFrame) -> Dict:
46
- """Process income statement data"""
47
- metrics = {}
48
- years = [col for col in df.columns if str(col).isdigit()]
49
 
50
- for year in years:
51
- metrics[year] = {
52
- 'Revenue': 0,
53
- 'Expenses': 0,
54
- 'Profit': 0,
55
- 'Details': {}
56
- }
57
-
58
- # Extract revenue
59
- total_revenue = df[df.iloc[:, 0].str.contains('Total Net Revenue|Revenue', na=False, regex=True)].iloc[0][year]
60
- metrics[year]['Revenue'] = self.clean_number(total_revenue)
61
-
62
- # Extract expenses
63
- total_expenses = df[df.iloc[:, 0].str.contains('Total Expenses', na=False)].iloc[0][year]
64
- metrics[year]['Expenses'] = self.clean_number(total_expenses)
65
-
66
- # Extract profit
67
- net_income = df[df.iloc[:, 0].str.contains('Net Income|Net Earnings', na=False, regex=True)].iloc[-1][year]
68
- metrics[year]['Profit'] = self.clean_number(net_income)
69
-
70
- # Extract additional details
71
- metrics[year]['Details'] = {
72
- 'COGS': self.clean_number(df[df.iloc[:, 0].str.contains('Cost of Goods Sold', na=False)].iloc[0][year]),
73
- 'Gross_Profit': self.clean_number(df[df.iloc[:, 0].str.contains('Gross Profit', na=False)].iloc[0][year]),
74
- 'Operating_Expenses': self.clean_number(total_expenses),
75
- 'EBIT': self.clean_number(df[df.iloc[:, 0].str.contains('Earnings Before Interest & Taxes', na=False)].iloc[0][year]),
76
- 'Interest_Expense': self.clean_number(df[df.iloc[:, 0].str.contains('Interest Expense', na=False)].iloc[0][year]),
77
- 'Tax_Expense': self.clean_number(df[df.iloc[:, 0].str.contains('Income Taxes', na=False)].iloc[0][year])
78
- }
79
-
80
- return metrics
81
-
82
- def process_balance_sheet(self, df: pd.DataFrame) -> Dict:
83
- """Process balance sheet data"""
84
- metrics = {}
85
- years = [col for col in df.columns if str(col).isdigit()]
86
 
87
- for year in years:
88
- metrics[year] = {
89
- 'Assets': 0,
90
- 'Liabilities': 0,
91
- 'Equity': 0,
92
- 'Details': {}
93
- }
94
 
95
- # Extract main metrics
96
- metrics[year]['Assets'] = self.clean_number(df[df.iloc[:, 0].str.contains('Total Assets', na=False)].iloc[0][year])
97
- metrics[year]['Liabilities'] = self.clean_number(df[df.iloc[:, 0].str.contains('Total Liabilities', na=False)].iloc[0][year])
98
- metrics[year]['Equity'] = self.clean_number(df[df.iloc[:, 0].str.contains("Shareholder's Equity", na=False)].iloc[-1][year])
99
 
100
- # Extract additional details
101
- metrics[year]['Details'] = {
102
- 'Current_Assets': self.clean_number(df[df.iloc[:, 0].str.contains('Total current assets', na=False)].iloc[0][year]),
103
- 'Fixed_Assets': self.clean_number(df[df.iloc[:, 0].str.contains('Property & Equipment', na=False)].iloc[0][year]),
104
- 'Current_Liabilities': self.clean_number(df[df.iloc[:, 0].str.contains('Total current liabilities', na=False)].iloc[0][year]),
105
- 'Long_Term_Debt': self.clean_number(df[df.iloc[:, 0].str.contains('Long-term debt', na=False)].iloc[0][year]),
106
- 'Retained_Earnings': self.clean_number(df[df.iloc[:, 0].str.contains('Retained Earnings', na=False)].iloc[0][year])
107
- }
108
-
109
- return metrics
110
 
111
  class FinancialAnalyzer:
112
- """Enhanced Financial Analyzer using small models"""
113
 
114
  def __init__(self):
115
  self.extractor = FinancialDataExtractor()
@@ -140,185 +95,135 @@ class FinancialAnalyzer:
140
  logger.error(f"Error loading models: {str(e)}")
141
  raise
142
 
143
- def calculate_financial_ratios(self, income_metrics: Dict, balance_metrics: Dict, year: str) -> Dict:
144
- """Calculate key financial ratios"""
145
- try:
146
- income = income_metrics[year]
147
- balance = balance_metrics[year]
 
 
 
 
 
 
 
 
148
 
149
- ratios = {
 
 
 
 
 
 
 
 
 
 
150
  'Profitability': {
151
- 'Gross_Margin': (income['Details']['Gross_Profit'] / income['Revenue']) * 100,
152
- 'Operating_Margin': (income['Details']['EBIT'] / income['Revenue']) * 100,
153
- 'Net_Margin': (income['Profit'] / income['Revenue']) * 100
 
 
154
  },
155
  'Liquidity': {
156
- 'Current_Ratio': balance['Details']['Current_Assets'] / balance['Details']['Current_Liabilities'],
157
- 'Quick_Ratio': (balance['Details']['Current_Assets'] - 0) / balance['Details']['Current_Liabilities'],
158
- 'Cash_Ratio': 0 # Would need cash balance for this
159
  },
160
- 'Solvency': {
161
- 'Debt_to_Equity': balance['Liabilities'] / balance['Equity'],
162
- 'Debt_Ratio': balance['Liabilities'] / balance['Assets'],
163
- 'Interest_Coverage': income['Details']['EBIT'] / income['Details']['Interest_Expense'] if income['Details']['Interest_Expense'] != 0 else float('inf')
164
- },
165
- 'Efficiency': {
166
- 'Asset_Turnover': income['Revenue'] / balance['Assets'],
167
- 'ROE': income['Profit'] / balance['Equity'] * 100,
168
- 'ROA': income['Profit'] / balance['Assets'] * 100
169
  }
170
  }
171
-
172
- return ratios
173
-
174
- except Exception as e:
175
- logger.error(f"Error calculating ratios: {str(e)}")
176
- return {}
177
-
178
- def generate_analysis_prompt(self, income_metrics: Dict, balance_metrics: Dict, ratios: Dict) -> str:
179
- """Generate analysis prompt for LLM"""
180
- latest_year = max(income_metrics.keys())
181
- earliest_year = min(income_metrics.keys())
182
 
183
- # Calculate growth metrics
184
- revenue_growth = ((income_metrics[latest_year]['Revenue'] - income_metrics[earliest_year]['Revenue'])
185
- / income_metrics[earliest_year]['Revenue'] * 100)
186
- profit_growth = ((income_metrics[latest_year]['Profit'] - income_metrics[earliest_year]['Profit'])
187
- / income_metrics[earliest_year]['Profit'] * 100)
188
- asset_growth = ((balance_metrics[latest_year]['Assets'] - balance_metrics[earliest_year]['Assets'])
189
- / balance_metrics[earliest_year]['Assets'] * 100)
190
-
191
- prompt = f"""[INST] As a financial analyst, provide a comprehensive analysis of this company:
192
-
193
- Financial Performance ({earliest_year}-{latest_year}):
194
- 1. Growth Metrics:
195
- - Revenue Growth: {revenue_growth:.1f}%
196
- - Profit Growth: {profit_growth:.1f}%
197
- - Asset Growth: {asset_growth:.1f}%
198
-
199
- 2. Latest Year Performance ({latest_year}):
200
- - Revenue: ${income_metrics[latest_year]['Revenue']:,.0f}
201
- - Net Profit: ${income_metrics[latest_year]['Profit']:,.0f}
202
- - Total Assets: ${balance_metrics[latest_year]['Assets']:,.0f}
203
-
204
- 3. Key Ratios ({latest_year}):
205
- - Profitability:
206
- * Gross Margin: {ratios['Profitability']['Gross_Margin']:.1f}%
207
- * Operating Margin: {ratios['Profitability']['Operating_Margin']:.1f}%
208
- * Net Margin: {ratios['Profitability']['Net_Margin']:.1f}%
209
- - Financial Health:
210
- * Current Ratio: {ratios['Liquidity']['Current_Ratio']:.2f}
211
- * Debt-to-Equity: {ratios['Solvency']['Debt_to_Equity']:.2f}
212
- * ROE: {ratios['Efficiency']['ROE']:.1f}%
213
-
214
- Provide:
215
- 1. Overall financial health assessment
216
- 2. Key performance insights and trends
217
- 3. Risk analysis and concerns
218
- 4. Specific strategic recommendations
219
- [/INST]"""
220
-
221
- return prompt
222
 
223
  def analyze_financials(self, income_df: pd.DataFrame, balance_df: pd.DataFrame) -> str:
224
- """Generate complete financial analysis"""
225
  try:
226
- # Extract metrics
227
- income_metrics = self.extractor.process_income_statement(income_df)
228
- balance_metrics = self.extractor.process_balance_sheet(balance_df)
229
 
230
- # Calculate ratios for latest year
231
- latest_year = max(income_metrics.keys())
232
- ratios = self.calculate_financial_ratios(income_metrics, balance_metrics, latest_year)
233
 
234
- # Generate analysis prompt
235
- analysis_prompt = self.generate_analysis_prompt(income_metrics, balance_metrics, ratios)
 
236
 
237
- # Get sentiment analysis
238
- sentiment = self.sentiment_model(
239
- analysis_prompt[:512],
240
- truncation=True
241
- )[0]
242
 
243
- # Generate analysis
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  analysis = self.analysis_model(
245
- analysis_prompt,
246
  max_length=1500,
 
247
  do_sample=True,
248
- temperature=0.7,
249
- num_return_sequences=1
250
  )[0]['generated_text']
251
 
252
- # Format the output
253
- output = self.format_response(analysis, sentiment, income_metrics, balance_metrics, ratios, latest_year)
254
-
255
- return output
256
-
257
- except Exception as e:
258
- logger.error(f"Analysis error: {str(e)}")
259
- return f"Error in analysis: {str(e)}"
260
 
261
- def format_response(self, analysis: str, sentiment: Dict,
262
- income_metrics: Dict, balance_metrics: Dict,
263
- ratios: Dict, year: str) -> str:
264
- """Format the analysis response"""
265
- try:
266
- # Split analysis into sections
267
- sections = analysis.split('\n\n')
268
-
269
- # Format metrics section
270
- metrics_section = f"""
271
- ### Key Financial Metrics ({year})
272
- - Revenue: ${income_metrics[year]['Revenue']:,.0f}
273
- - Net Profit: ${income_metrics[year]['Profit']:,.0f}
274
- - Total Assets: ${balance_metrics[year]['Assets']:,.0f}
275
 
276
- ### Financial Ratios
277
- - Profitability:
278
- * Gross Margin: {ratios['Profitability']['Gross_Margin']:.1f}%
279
- * Operating Margin: {ratios['Profitability']['Operating_Margin']:.1f}%
280
- * Net Margin: {ratios['Profitability']['Net_Margin']:.1f}%
281
-
282
- - Financial Health:
283
- * Current Ratio: {ratios['Liquidity']['Current_Ratio']:.2f}
284
- * Debt-to-Equity: {ratios['Solvency']['Debt_to_Equity']:.2f}
285
- * Interest Coverage: {ratios['Solvency']['Interest_Coverage']:.2f}
286
-
287
- - Efficiency:
288
- * ROE: {ratios['Efficiency']['ROE']:.1f}%
289
- * ROA: {ratios['Efficiency']['ROA']:.1f}%
290
- * Asset Turnover: {ratios['Efficiency']['Asset_Turnover']:.2f}
291
- """
292
 
293
- # Combine all sections
294
- output = [
295
- "# Financial Analysis Report\n",
296
- f"## Overall Sentiment: {sentiment['label'].upper()} ({sentiment['score']:.1%})\n",
297
- metrics_section,
298
- "\n## Analysis\n",
299
- analysis
300
- ]
301
 
302
- return "\n".join(output)
303
 
304
  except Exception as e:
305
- logger.error(f"Error formatting response: {str(e)}")
306
- return "Error formatting analysis results"
307
 
308
  def analyze_statements(income_statement, balance_sheet):
309
  """Main function to analyze financial statements"""
310
  try:
311
  if not income_statement or not balance_sheet:
312
  return "Please upload both Income Statement and Balance Sheet CSV files."
313
-
314
  # Read files
315
  income_df = pd.read_csv(income_statement.name)
316
  balance_df = pd.read_csv(balance_sheet.name)
317
 
318
- # Create analyzer instance
319
  analyzer = FinancialAnalyzer()
320
-
321
- # Generate analysis
322
  result = analyzer.analyze_financials(income_df, balance_df)
323
 
324
  # Clear memory
@@ -331,71 +236,33 @@ def analyze_statements(income_statement, balance_sheet):
331
  return f"""Analysis Error: {str(e)}
332
 
333
  Please ensure your CSV files:
334
- 1. Contain recognizable financial metrics
335
- 2. Have clear period/year columns
336
- 3. Use consistent number formatting
337
- 4. Are not corrupted"""
338
 
339
- # Create Gradio interface with compatible parameters
340
  iface = gr.Interface(
341
  fn=analyze_statements,
342
  inputs=[
343
- gr.File(
344
- label="Upload Income Statement (CSV)",
345
- file_types=[".csv"],
346
- file_count="single"
347
- ),
348
- gr.File(
349
- label="Upload Balance Sheet (CSV)",
350
- file_types=[".csv"],
351
- file_count="single"
352
- )
353
  ],
354
  outputs=gr.Markdown(),
355
- title="Advanced Financial Statement Analyzer",
356
- description="""## Professional Financial Analysis Tool
357
-
358
- ### Supported Financial Statement Formats:
359
-
360
- #### Income Statement Requirements:
361
- - Revenue/Sales information
362
- - Cost and Expense details
363
- - Profit/Income figures
364
- - Operating metrics
365
- - Period/Year information
366
-
367
- #### Balance Sheet Requirements:
368
- - Asset information (Current & Non-current)
369
- - Liability details (Current & Long-term)
370
- - Equity components
371
- - Period/Year information
372
-
373
- ### Analysis Output Includes:
374
- 1. Overall Financial Health Assessment
375
- 2. Key Performance Metrics & Ratios
376
- 3. Trend Analysis
377
- 4. Risk Assessment
378
- 5. Strategic Recommendations
379
 
380
- ### Usage Instructions:
381
- 1. Upload your Income Statement CSV file
382
- 2. Upload your Balance Sheet CSV file
383
- 3. Wait for the analysis to complete
384
- 4. Review the comprehensive financial analysis report
385
- """,
386
- theme="default"
387
  )
388
 
389
- # Launch configurations
390
  if __name__ == "__main__":
391
  try:
392
- # Configure and launch
393
- iface.queue()
394
- iface.launch(
395
- server_name="0.0.0.0",
396
- server_port=7860,
397
- share=False
398
- )
399
  except Exception as e:
400
  logger.error(f"Launch error: {str(e)}")
401
  sys.exit(1)
 
4
  import torch
5
  import logging
6
  import gc
 
7
  from transformers import pipeline
 
8
 
9
  # Setup logging
10
  logging.basicConfig(
 
17
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
18
  logger.info(f"Using device: {DEVICE}")
19
 
20
+ def clear_gpu_memory():
21
+ """Utility function to clear GPU memory"""
22
+ if DEVICE == "cuda":
23
+ torch.cuda.empty_cache()
24
+ gc.collect()
25
+
26
  class FinancialDataExtractor:
27
+ """Extract and clean financial data"""
28
 
29
  def __init__(self):
30
+ self.logger = logger
31
 
32
+ def clean_number(self, value):
33
  """Clean numeric values from financial statements"""
34
  try:
35
  if pd.isna(value) or value == '' or value == '-':
 
38
  return float(value)
39
 
40
  # Remove currency symbols, spaces, commas
41
+ cleaned = str(value).replace('$', '').replace(',', '').replace('"', '').strip()
42
  # Handle parentheses for negative numbers
43
  if '(' in cleaned and ')' in cleaned:
44
  cleaned = '-' + cleaned.replace('(', '').replace(')', '')
 
46
  except:
47
  return 0.0
48
 
49
+ def extract_data(self, df: pd.DataFrame) -> pd.DataFrame:
50
+ """Extract and clean data from DataFrame"""
51
+ # Clean column names
52
+ df.columns = df.columns.str.strip()
53
 
54
+ # Get year columns
55
+ year_cols = [col for col in df.columns if str(col).isdigit()]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
+ if not year_cols:
58
+ raise ValueError("No year columns found in data")
 
 
 
 
 
59
 
60
+ # Clean numeric data
61
+ for col in year_cols:
62
+ df[col] = df[col].apply(self.clean_number)
 
63
 
64
+ return df, year_cols
 
 
 
 
 
 
 
 
 
65
 
66
  class FinancialAnalyzer:
67
+ """Financial analysis using small models"""
68
 
69
  def __init__(self):
70
  self.extractor = FinancialDataExtractor()
 
95
  logger.error(f"Error loading models: {str(e)}")
96
  raise
97
 
98
+ def calculate_metrics(self, income_df: pd.DataFrame, balance_df: pd.DataFrame, year_cols: list) -> dict:
99
+ """Calculate financial metrics"""
100
+ metrics = {}
101
+
102
+ for year in year_cols:
103
+ # Income Statement metrics
104
+ income = {
105
+ 'Revenue': income_df[income_df['Period'].str.contains('Total Net Revenue|Revenue', na=False, case=False)][year].iloc[0],
106
+ 'COGS': income_df[income_df['Period'].str.contains('Cost of Goods Sold', na=False, case=False)][year].iloc[0],
107
+ 'Operating_Expenses': income_df[income_df['Period'].str.contains('Total Expenses', na=False, case=False)][year].iloc[0],
108
+ 'EBIT': income_df[income_df['Period'].str.contains('Earnings Before Interest & Taxes', na=False, case=False)][year].iloc[0],
109
+ 'Net_Income': income_df[income_df['Period'].str.contains('Net Income|Net Earnings', na=False, case=False)][year].iloc[-1]
110
+ }
111
 
112
+ # Balance Sheet metrics
113
+ balance = {
114
+ 'Total_Assets': balance_df[balance_df['Period'].str.contains('Total Assets', na=False, case=False)][year].iloc[0],
115
+ 'Current_Assets': balance_df[balance_df['Period'].str.contains('Total current assets', na=False, case=False)][year].iloc[0],
116
+ 'Total_Liabilities': balance_df[balance_df['Period'].str.contains('Total Liabilities', na=False, case=False)][year].iloc[0],
117
+ 'Current_Liabilities': balance_df[balance_df['Period'].str.contains('Total current liabilities', na=False, case=False)][year].iloc[0],
118
+ 'Equity': balance_df[balance_df['Period'].str.contains("Shareholder's Equity", na=False, case=False)][year].iloc[-1]
119
+ }
120
+
121
+ # Calculate ratios
122
+ metrics[year] = {
123
  'Profitability': {
124
+ 'Gross_Margin': ((income['Revenue'] - income['COGS']) / income['Revenue']) * 100,
125
+ 'Operating_Margin': (income['EBIT'] / income['Revenue']) * 100,
126
+ 'Net_Margin': (income['Net_Income'] / income['Revenue']) * 100,
127
+ 'ROE': (income['Net_Income'] / balance['Equity']) * 100,
128
+ 'ROA': (income['Net_Income'] / balance['Total_Assets']) * 100
129
  },
130
  'Liquidity': {
131
+ 'Current_Ratio': balance['Current_Assets'] / balance['Current_Liabilities'],
132
+ 'Working_Capital': balance['Current_Assets'] - balance['Current_Liabilities']
 
133
  },
134
+ 'Growth': {
135
+ 'Revenue': income['Revenue'],
136
+ 'Net_Income': income['Net_Income'],
137
+ 'Total_Assets': balance['Total_Assets']
 
 
 
 
 
138
  }
139
  }
 
 
 
 
 
 
 
 
 
 
 
140
 
141
+ return metrics
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
  def analyze_financials(self, income_df: pd.DataFrame, balance_df: pd.DataFrame) -> str:
144
+ """Generate financial analysis"""
145
  try:
146
+ # Extract and clean data
147
+ income_df, year_cols = self.extractor.extract_data(income_df)
148
+ balance_df, _ = self.extractor.extract_data(balance_df)
149
 
150
+ # Calculate metrics
151
+ metrics = self.calculate_metrics(income_df, balance_df, year_cols)
 
152
 
153
+ # Get latest and earliest years
154
+ latest_year = max(year_cols)
155
+ earliest_year = min(year_cols)
156
 
157
+ # Calculate growth
158
+ revenue_growth = ((metrics[latest_year]['Growth']['Revenue'] / metrics[earliest_year]['Growth']['Revenue']) - 1) * 100
159
+ profit_growth = ((metrics[latest_year]['Growth']['Net_Income'] / metrics[earliest_year]['Growth']['Net_Income']) - 1) * 100
 
 
160
 
161
+ # Generate analysis context
162
+ context = f"""Financial Analysis ({earliest_year}-{latest_year}):
163
+
164
+ Performance Metrics:
165
+ - Revenue Growth: {revenue_growth:.1f}%
166
+ - Profit Growth: {profit_growth:.1f}%
167
+ - Current Gross Margin: {metrics[latest_year]['Profitability']['Gross_Margin']:.1f}%
168
+ - Current Net Margin: {metrics[latest_year]['Profitability']['Net_Margin']:.1f}%
169
+ - ROE: {metrics[latest_year]['Profitability']['ROE']:.1f}%
170
+ - Current Ratio: {metrics[latest_year]['Liquidity']['Current_Ratio']:.2f}
171
+
172
+ Trends:
173
+ - Revenue has grown from ${metrics[earliest_year]['Growth']['Revenue']:,.0f} to ${metrics[latest_year]['Growth']['Revenue']:,.0f}
174
+ - Net Income has changed from ${metrics[earliest_year]['Growth']['Net_Income']:,.0f} to ${metrics[latest_year]['Growth']['Net_Income']:,.0f}
175
+ - Profitability margins show {('improving' if metrics[latest_year]['Profitability']['Net_Margin'] > metrics[earliest_year]['Profitability']['Net_Margin'] else 'declining')} trend"""
176
+
177
+ # Get sentiment
178
+ sentiment = self.sentiment_model(context[:512])[0]
179
+
180
+ # Generate detailed analysis
181
  analysis = self.analysis_model(
182
+ f"[INST] As a financial analyst, provide a detailed analysis of this company:\n\n{context}\n\nInclude:\n1. Financial health assessment\n2. Key performance insights\n3. Strategic recommendations [/INST]",
183
  max_length=1500,
184
+ num_return_sequences=1,
185
  do_sample=True,
186
+ temperature=0.7
 
187
  )[0]['generated_text']
188
 
189
+ # Format output
190
+ output = f"""# Financial Analysis Report
 
 
 
 
 
 
191
 
192
+ ## Overall Sentiment: {sentiment['label'].upper()} ({sentiment['score']:.1%})
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
+ ## Key Performance Indicators ({latest_year})
195
+ - Gross Margin: {metrics[latest_year]['Profitability']['Gross_Margin']:.1f}%
196
+ - Operating Margin: {metrics[latest_year]['Profitability']['Operating_Margin']:.1f}%
197
+ - Net Margin: {metrics[latest_year]['Profitability']['Net_Margin']:.1f}%
198
+ - ROE: {metrics[latest_year]['Profitability']['ROE']:.1f}%
199
+ - Current Ratio: {metrics[latest_year]['Liquidity']['Current_Ratio']:.2f}
 
 
 
 
 
 
 
 
 
 
200
 
201
+ ## Performance Trends ({earliest_year}-{latest_year})
202
+ - Revenue Growth: {revenue_growth:.1f}%
203
+ - Profit Growth: {profit_growth:.1f}%
204
+ - Working Capital: ${metrics[latest_year]['Liquidity']['Working_Capital']:,.0f}
205
+
206
+ ## Analysis
207
+ {analysis}"""
 
208
 
209
+ return output
210
 
211
  except Exception as e:
212
+ logger.error(f"Analysis error: {str(e)}")
213
+ raise
214
 
215
  def analyze_statements(income_statement, balance_sheet):
216
  """Main function to analyze financial statements"""
217
  try:
218
  if not income_statement or not balance_sheet:
219
  return "Please upload both Income Statement and Balance Sheet CSV files."
220
+
221
  # Read files
222
  income_df = pd.read_csv(income_statement.name)
223
  balance_df = pd.read_csv(balance_sheet.name)
224
 
225
+ # Create analyzer and process
226
  analyzer = FinancialAnalyzer()
 
 
227
  result = analyzer.analyze_financials(income_df, balance_df)
228
 
229
  # Clear memory
 
236
  return f"""Analysis Error: {str(e)}
237
 
238
  Please ensure your CSV files:
239
+ 1. Have clear year columns
240
+ 2. Contain recognizable financial metrics
241
+ 3. Use consistent number formatting"""
 
242
 
243
+ # Create Gradio interface
244
  iface = gr.Interface(
245
  fn=analyze_statements,
246
  inputs=[
247
+ gr.File(label="Upload Income Statement (CSV)", file_types=[".csv"]),
248
+ gr.File(label="Upload Balance Sheet (CSV)", file_types=[".csv"])
 
 
 
 
 
 
 
 
249
  ],
250
  outputs=gr.Markdown(),
251
+ title="Financial Statement Analyzer",
252
+ description="""## Financial Analysis Tool
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
+ Upload your financial statements to get:
255
+ - Performance Analysis
256
+ - Key Metrics & Ratios
257
+ - Trend Analysis
258
+ - Strategic Recommendations""",
259
+ examples=None
 
260
  )
261
 
262
+ # Launch the interface
263
  if __name__ == "__main__":
264
  try:
265
+ iface.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
266
  except Exception as e:
267
  logger.error(f"Launch error: {str(e)}")
268
  sys.exit(1)