Rush147/ROI-PL
0
1import streamlit as st2import pandas as pd3import numpy as np4import shap5import seaborn as sns6import matplotlib.pyplot as plt7from sklearn.model_selection import train_test_split, KFold, RandomizedSearchCV, cross_val_score8from sklearn.linear_model import LinearRegression9from sklearn.ensemble import RandomForestRegressor10from sklearn.preprocessing import StandardScaler, PolynomialFeatures11from sklearn.pipeline import Pipeline12import xgboost as xgb13from xgboost import XGBRegressor14from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error15import plotly.graph_objects as go16import plotly.express as px17from reportlab.pdfgen import canvas18from reportlab.lib.pagesizes import letter, A419from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle20from reportlab.lib.units import inch21from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle22from reportlab.lib import colors23from reportlab.platypus import Image, PageBreak24from reportlab.pdfbase import pdfmetrics25from reportlab.pdfbase.ttfonts import TTFont26import io27import urllib.request28import os29import tempfile30from io import BytesIO31from PIL import Image as PILImage32from datetime import datetime33import warnings34import base6435import matplotlib.pyplot as plt36import matplotlib.font_manager as fm37from matplotlib import rcParams38import os39import google.generativeai as genai40import warnings41import joblib42import pickle43import time44from plotly.subplots import make_subplots45import plotly.express as px46 47gemini_api_key = os.getenv("GEMINI_API_KEY")48 49if not gemini_api_key:50 st.error("Gemini API key not found. Please set GEMINI_API_KEY in HF Space secrets.")51 52# ===========================53# SESSION STATE INITIALIZATION54# ===========================55if 'prediction_made' not in st.session_state:56 st.session_state.prediction_made = False57if 'pred_result' not in st.session_state:58 st.session_state.pred_result = None59if 'feat_shap' not in st.session_state:60 st.session_state.feat_shap = None61if 'chart_fig' not in st.session_state:62 st.session_state.chart_fig = None63if 'model_metrics' not in st.session_state:64 st.session_state.model_metrics = None65if 'data_engineered' not in st.session_state:66 st.session_state.data_engineered = None67if 'kpi_data' not in st.session_state:68 st.session_state.kpi_data = None69if 'pretrained_models' not in st.session_state:70 st.session_state.pretrained_models = None71if 'model_training_complete' not in st.session_state:72 st.session_state.model_training_complete = False73if 'best_models' not in st.session_state:74 st.session_state.best_models = {}75if 'whatif_scenarios' not in st.session_state:76 st.session_state.whatif_scenarios = {}77if 'whatif_baseline' not in st.session_state:78 st.session_state.whatif_baseline = None79if 'whatif_results' not in st.session_state:80 st.session_state.whatif_results = {}81 82# ===========================83# PAGE CONFIGURATION84# ===========================85st.set_page_config(86 page_title="GainSight AI โ Smarter Business Predictions", 87 page_icon="๐", 88 layout="wide"89)90 91st.title("๐ GainSight AI โ Smarter Business Predictions")92st.write("**Advanced ML predictions with feature engineering and comprehensive model evaluation for any business domain.**")93 94class MultilingualPDFHandler:95 def __init__(self, language):96 self.language = language97 self.font_registered = False98 self.base_font = 'Helvetica'99 self.bold_font = 'Helvetica-Bold'100 self.styles = getSampleStyleSheet()101 102 self.register_devanagari_fonts()103 self.create_multilingual_styles()104 105# ===========================106# PRE-TRAINING SECTION107# ===========================108def create_dummy_dataset():109 """Create a comprehensive dummy business dataset for training"""110 np.random.seed(42)111 n_samples = 1000112 113 # Generate dummy business data114 data = {115 'Revenue': np.random.normal(100000, 30000, n_samples),116 'Marketing_Spend': np.random.normal(15000, 5000, n_samples),117 'R_D_Investment': np.random.normal(8000, 3000, n_samples),118 'Employee_Count': np.random.randint(10, 500, n_samples),119 'Units_Sold': np.random.randint(100, 5000, n_samples),120 'Customer_Satisfaction': np.random.uniform(1, 5, n_samples),121 'Market_Share': np.random.uniform(0.01, 0.3, n_samples),122 'Product_Price': np.random.uniform(10, 200, n_samples),123 'Competition_Level': np.random.choice(['Low', 'Medium', 'High'], n_samples),124 'Season': np.random.choice(['Q1', 'Q2', 'Q3', 'Q4'], n_samples),125 'Region': np.random.choice(['North', 'South', 'East', 'West'], n_samples),126 'Year': np.random.choice([2021, 2022, 2023, 2024], n_samples)127 }128 129 df = pd.DataFrame(data)130 131 # Create realistic relationships132 df['Operating_Costs'] = (df['Revenue'] * 0.6 + 133 df['Marketing_Spend'] * 0.8 + 134 df['Employee_Count'] * 100 + 135 np.random.normal(0, 5000, n_samples))136 137 df['Net_Profit'] = (df['Revenue'] - df['Operating_Costs'] + 138 np.random.normal(0, 8000, n_samples))139 140 # Ensure some realistic constraints141 df['Operating_Costs'] = np.clip(df['Operating_Costs'], 0, df['Revenue'] * 0.9)142 df['Revenue'] = np.clip(df['Revenue'], 10000, 500000)143 df['Marketing_Spend'] = np.clip(df['Marketing_Spend'], 1000, 50000)144 145 return df146 147def get_hyperparameter_grids():148 """Define hyperparameter grids for different models"""149 param_grids = {150 'LinearRegression': {151 'model__fit_intercept': [True, False],152 'model__positive': [False, True]153 },154 'RandomForest': {155 'model__n_estimators': [50, 100, 200, 300],156 'model__max_depth': [None, 10, 20, 30],157 'model__min_samples_split': [2, 5, 10],158 'model__min_samples_leaf': [1, 2, 4],159 'model__max_features': ['sqrt', 'log2', None]160 },161 'XGBoost': {162 'model__n_estimators': [50, 100, 200, 300],163 'model__max_depth': [3, 6, 9, 12],164 'model__learning_rate': [0.01, 0.1, 0.2, 0.3],165 'model__subsample': [0.8, 0.9, 1.0],166 'model__colsample_bytree': [0.8, 0.9, 1.0],167 'model__reg_alpha': [0, 0.1, 1],168 'model__reg_lambda': [0, 0.1, 1]169 }170 }171 return param_grids172 173def train_models_with_hyperparameter_tuning(X, y, cv_folds=5, n_iter=20):174 """Train multiple models with hyperparameter tuning"""175 models = {176 'LinearRegression': LinearRegression(),177 'RandomForest': RandomForestRegressor(random_state=42, n_jobs=-1),178 'XGBoost': XGBRegressor(random_state=42, n_jobs=-1, verbosity=0)179 }180 181 param_grids = get_hyperparameter_grids()182 best_models = {}183 model_results = {}184 185 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)186 187 progress_bar = st.progress(0)188 status_text = st.empty()189 190 for idx, (model_name, base_model) in enumerate(models.items()):191 status_text.text(f"Training {model_name} with hyperparameter tuning...")192 193 # Create pipeline194 pipeline = Pipeline([195 ('scaler', StandardScaler()),196 ('model', base_model)197 ])198 199 # Hyperparameter tuning200 if model_name in param_grids:201 search = RandomizedSearchCV(202 pipeline,203 param_grids[model_name],204 n_iter=n_iter,205 cv=cv_folds,206 scoring='r2',207 random_state=42,208 n_jobs=-1,209 verbose=0210 )211 212 search.fit(X_train, y_train)213 best_model = search.best_estimator_214 best_params = search.best_params_215 cv_score = search.best_score_216 else:217 # For models without hyperparameters218 pipeline.fit(X_train, y_train)219 best_model = pipeline220 best_params = {}221 cv_score = cross_val_score(pipeline, X_train, y_train, cv=cv_folds, scoring='r2').mean()222 223 # Evaluate on test set224 y_train_pred = best_model.predict(X_train)225 y_test_pred = best_model.predict(X_test)226 227 metrics = {228 'cv_score': cv_score,229 'train_r2': r2_score(y_train, y_train_pred),230 'test_r2': r2_score(y_test, y_test_pred),231 'train_mae': mean_absolute_error(y_train, y_train_pred),232 'test_mae': mean_absolute_error(y_test, y_test_pred),233 'train_rmse': np.sqrt(mean_squared_error(y_train, y_train_pred)),234 'test_rmse': np.sqrt(mean_squared_error(y_test, y_test_pred)),235 'best_params': best_params236 }237 metrics['overfitting_score'] = metrics['train_r2'] - metrics['test_r2']238 239 best_models[model_name] = best_model240 model_results[model_name] = metrics241 242 progress_bar.progress((idx + 1) / len(models))243 244 status_text.text("Model training completed! โ
")245 return best_models, model_results246 247def display_model_comparison(model_results):248 """Display comparison of trained models"""249 st.subheader("๐ Pre-trained Model Performance Comparison")250 251 # Create comparison dataframe252 comparison_data = []253 for model_name, metrics in model_results.items():254 comparison_data.append({255 'Model': model_name,256 'CV Score': f"{metrics['cv_score']:.4f}",257 'Test Rยฒ': f"{metrics['test_r2']:.4f}",258 'Test MAE': f"{metrics['test_mae']:.2f}",259 'Test RMSE': f"{metrics['test_rmse']:.2f}",260 'Overfitting': f"{metrics['overfitting_score']:.4f}"261 })262 263 comparison_df = pd.DataFrame(comparison_data)264 st.dataframe(comparison_df, use_container_width=True)265 266 # Visualize model performance267 col1, col2 = st.columns(2)268 269 with col1:270 # Rยฒ Score comparison271 r2_scores = [model_results[model]['test_r2'] for model in model_results.keys()]272 model_names = list(model_results.keys())273 274 fig_r2 = go.Figure(data=[275 go.Bar(x=model_names, y=r2_scores, 276 marker_color=['#FF6B6B', '#4ECDC4', '#45B7D1'])277 ])278 fig_r2.update_layout(279 title="๐ Test Rยฒ Score Comparison",280 xaxis_title="Models",281 yaxis_title="Rยฒ Score",282 height=400283 )284 st.plotly_chart(fig_r2, use_container_width=True)285 286 with col2:287 # MAE comparison288 mae_scores = [model_results[model]['test_mae'] for model in model_results.keys()]289 290 fig_mae = go.Figure(data=[291 go.Bar(x=model_names, y=mae_scores,292 marker_color=['#FF6B6B', '#4ECDC4', '#45B7D1'])293 ])294 fig_mae.update_layout(295 title="๐ Mean Absolute Error Comparison",296 xaxis_title="Models",297 yaxis_title="MAE",298 height=400299 )300 st.plotly_chart(fig_mae, use_container_width=True)301 302# ===========================303# PRE-TRAINING EXECUTION304# ===========================305def train_models_with_hyperparameter_tuning(X, y, cv_folds=5, n_iter=20):306 """Train multiple models with hyperparameter tuning (silent version)"""307 models = {308 'LinearRegression': LinearRegression(),309 'RandomForest': RandomForestRegressor(random_state=42, n_jobs=-1),310 'XGBoost': XGBRegressor(random_state=42, n_jobs=-1, verbosity=0)311 }312 313 param_grids = get_hyperparameter_grids()314 best_models = {}315 model_results = {}316 317 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)318 319 # Remove progress indicators - train silently320 for model_name, base_model in models.items():321 # Create pipeline322 pipeline = Pipeline([323 ('scaler', StandardScaler()),324 ('model', base_model)325 ])326 327 # Hyperparameter tuning328 if model_name in param_grids:329 search = RandomizedSearchCV(330 pipeline,331 param_grids[model_name],332 n_iter=n_iter,333 cv=cv_folds,334 scoring='r2',335 random_state=42,336 n_jobs=-1,337 verbose=0 # Silent operation338 )339 340 search.fit(X_train, y_train)341 best_model = search.best_estimator_342 best_params = search.best_params_343 cv_score = search.best_score_344 else:345 # For models without hyperparameters346 pipeline.fit(X_train, y_train)347 best_model = pipeline348 best_params = {}349 cv_score = cross_val_score(pipeline, X_train, y_train, cv=cv_folds, scoring='r2').mean()350 351 # Evaluate on test set352 y_train_pred = best_model.predict(X_train)353 y_test_pred = best_model.predict(X_test)354 355 metrics = {356 'cv_score': cv_score,357 'train_r2': r2_score(y_train, y_train_pred),358 'test_r2': r2_score(y_test, y_test_pred),359 'train_mae': mean_absolute_error(y_train, y_train_pred),360 'test_mae': mean_absolute_error(y_test, y_test_pred),361 'train_rmse': np.sqrt(mean_squared_error(y_train, y_train_pred)),362 'test_rmse': np.sqrt(mean_squared_error(y_test, y_test_pred)),363 'best_params': best_params364 }365 metrics['overfitting_score'] = metrics['train_r2'] - metrics['test_r2']366 367 best_models[model_name] = best_model368 model_results[model_name] = metrics369 370 return best_models, model_results371 372# ===========================373# MULTILINGUAL TRANSLATION SYSTEM374# ===========================375# Global TRANSLATIONS dictionary for multilingual support376TRANSLATIONS = {377 "English": {378 # Report titles and headers379 "business_intelligence_report": "Business Intelligence Analysis Report",380 "executive_summary": "Executive Summary", 381 "detailed_analysis": "Detailed Analysis",382 "technical_report": "Technical Report",383 "visual_analysis_dashboard": "Visual Analysis Dashboard",384 "ai_powered_recommendations": "AI-Powered Strategic Recommendations",385 "expected_financial_impact": "Expected Financial Impact",386 "key_performance_indicators": "Key Performance Indicators",387 "critical_success_factors": "Critical Success Factors",388 "analysis_focus": "Analysis Focus",389 "key_insight": "Key Insight",390 "recommendation": "Recommendation",391 "generated_in_ai": "Generated in {language} by AI, displayed in English",392 393 # Chart titles394 "financial_waterfall_analysis": "Financial Waterfall Analysis",395 "profitability_trend_analysis": "Profitability Trend Analysis", 396 "breakeven_analysis": "Break-Even Analysis",397 "segment_profitability_analysis": "Segment Profitability Analysis",398 "roi_performance_distribution": "ROI Performance Distribution",399 "cumulative_roi_analysis": "Cumulative ROI Analysis",400 "roi_by_project_analysis": "ROI by Project Analysis",401 "roi_vs_risk_analysis": "ROI vs Risk Analysis",402 403 # Table headers404 "metric": "Metric", "value": "Value", "interpretation": "Interpretation",405 "rank": "Rank", "success_factor": "Success Factor", "impact_score": "Impact Score", "priority": "Priority",406 "current": "Current", "projected": "Projected", "improvement": "Improvement",407 408 # FIXED: Metric Names - using exact keys from KPI calculation409 "totalrevenue": "Total Revenue", 410 "totalprofit": "Total Profit", 411 "totalloss": "Total Loss",412 "totalebit": "Total EBIT", 413 "totalgrossprofit": "Total Gross Profit", 414 "averageroi": "Average ROI",415 "profitmargin": "Profit Margin", 416 "revenueimpact": "Revenue Impact", 417 "additionalprofit": "Additional Profit",418 419 # Add to Marathi section:420 "revenue": "เคฎเคนเคธเฅเคฒ",421 "marketing_spend": "เคฎเคพเคฐเฅเคเฅเคเคฟเคเค เคเคฐเฅเค",422 "employee_count": "เคเคฐเฅเคฎเคเคพเคฐเฅ เคธเคเคเฅเคฏเคพ",423 "units_sold": "เคตเคฟเคเคฒเฅ เคเฅเคฒเฅเคฒเฅ เคฏเฅเคจเคฟเคเฅเคธ", 424 "customer_satisfaction": "เคเฅเคฐเคพเคนเค เคธเคฎเคพเคงเคพเคจ",425 "market_share": "เคฌเคพเคเคพเคฐ เคตเคพเคเคพ",426 "product_price": "เคเคคเฅเคชเคพเคฆ เคเคฟเคเคฎเคค",427 "revenue_per_unit": "เคชเฅเคฐเคคเคฟ เคฏเฅเคจเคฟเค เคฎเคนเคธเฅเคฒ",428 "cost_per_unit": "เคชเฅเคฐเคคเคฟ เคฏเฅเคจเคฟเค เคเคฟเคเคฎเคค", 429 "roi": "เคเคฐเคเคเค",430 "operating_costs": "เคเคชเคฐเฅเคเคฟเคเค เคเคฐเฅเค",431 432 # Status and interpretations433 "above_average": "Above Average", "needs_improvement": "Needs Improvement", "strong": "Strong",434 "moderate": "Moderate", "weak": "Weak", "positive": "Positive", "negative": "Negative",435 "high": "High", "medium": "Medium", "normal": "Normal",436 437 # Metadata labels438 "business_context": "Business Context", "analysis_type": "Analysis Type", "target_variable": "Target Variable",439 "report_language": "Report Language", "generated_on": "Generated On",440 441 # Notes and messages442 "multilingual_note": "Note: This report was generated for {language} language. Due to PDF font limitations, content is displayed in English with {language} AI insights included.",443 "no_insight_available": "No specific insight available."444 },445 446 "Hindi": {447 # Report titles and headers 448 "business_intelligence_report": "เคตเฅเคฏเคพเคตเคธเคพเคฏเคฟเค เคฌเฅเคฆเฅเคงเคฟเคฎเคคเฅเคคเคพ เคตเคฟเคถเฅเคฒเฅเคทเคฃ เคฐเคฟเคชเฅเคฐเฅเค",449 "executive_summary": "เคเคพเคฐเฅเคฏเคเคพเคฐเฅ เคธเคพเคฐเคพเคเคถ", "detailed_analysis": "เคตเคฟเคธเฅเคคเฅเคค เคตเคฟเคถเฅเคฒเฅเคทเคฃ", 450 "technical_report": "เคคเคเคจเฅเคเฅ เคฐเคฟเคชเฅเคฐเฅเค", "visual_analysis_dashboard": "เคฆเฅเคถเฅเคฏ เคตเคฟเคถเฅเคฒเฅเคทเคฃ เคกเฅเคถเคฌเฅเคฐเฅเคก",451 "ai_powered_recommendations": "AI-เคธเคเคเคพเคฒเคฟเคค เคฐเคฃเคจเฅเคคเคฟเค เคธเคฟเคซเคพเคฐเคฟเคถเฅเค", "expected_financial_impact": "เค
เคชเฅเคเฅเคทเคฟเคค เคตเคฟเคคเฅเคคเฅเคฏ เคชเฅเคฐเคญเคพเคต",452 "key_performance_indicators": "เคฎเฅเคเฅเคฏ เคชเฅเคฐเคฆเคฐเฅเคถเคจ เคธเคเคเฅเคคเค", "critical_success_factors": "เคฎเคนเคคเฅเคตเคชเฅเคฐเฅเคฃ เคธเคซเคฒเคคเคพ เคเคพเคฐเค",453 "analysis_focus": "เคตเคฟเคถเฅเคฒเฅเคทเคฃ เคซเฅเคเคธ", "key_insight": "เคฎเฅเคเฅเคฏ เค
เคเคคเคฐเฅเคฆเฅเคทเฅเคเคฟ", "recommendation": "เคธเคฟเคซเคพเคฐเคฟเคถ",454 "generated_in_ai": "{language} เคฎเฅเค AI เคฆเฅเคตเคพเคฐเคพ เคเฅเคจเคฐเฅเค เคเคฟเคฏเคพ เคเคฏเคพ, เค
เคเคเฅเคฐเฅเคเฅ เคฎเฅเค เคชเฅเคฐเคฆเคฐเฅเคถเคฟเคค",455 456 # Chart titles457 "financial_waterfall_analysis": "เคตเคฟเคคเฅเคคเฅเคฏ เคตเฅเคเคฐเคซเฅเคฒ เคตเคฟเคถเฅเคฒเฅเคทเคฃ", "profitability_trend_analysis": "เคฒเคพเคญเคชเฅเคฐเคฆเคคเคพ เคฐเฅเคเคพเคจ เคตเคฟเคถเฅเคฒเฅเคทเคฃ",458 "breakeven_analysis": "เคฌเฅเคฐเฅเค-เคเคตเคจ เคตเคฟเคถเฅเคฒเฅเคทเคฃ", "segment_profitability_analysis": "เคเคเคก เคฒเคพเคญเคชเฅเคฐเคฆเคคเคพ เคตเคฟเคถเฅเคฒเฅเคทเคฃ",459 "roi_performance_distribution": "ROI เคชเฅเคฐเคฆเคฐเฅเคถเคจ เคตเคฟเคคเคฐเคฃ", "cumulative_roi_analysis": "เคธเคเคเคฏเฅ ROI เคตเคฟเคถเฅเคฒเฅเคทเคฃ",460 "roi_by_project_analysis": "เคชเคฐเคฟเคฏเฅเคเคจเคพ เคฆเฅเคตเคพเคฐเคพ ROI เคตเคฟเคถเฅเคฒเฅเคทเคฃ", "roi_vs_risk_analysis": "ROI เคฌเคจเคพเคฎ เคเฅเคเคฟเคฎ เคตเคฟเคถเฅเคฒเฅเคทเคฃ",461 462 # Table headers463 "metric": "เคฎเฅเคเฅเคฐเคฟเค", "value": "เคฎเฅเคฒเฅเคฏ", "interpretation": "เคตเฅเคฏเคพเคเฅเคฏเคพ", 464 "rank": "เคฐเฅเคเค", "success_factor": "เคธเคซเคฒเคคเคพ เคเคพเคฐเค", "impact_score": "เคชเฅเคฐเคญเคพเคต เคธเฅเคเฅเคฐ", "priority": "เคชเฅเคฐเคพเคฅเคฎเคฟเคเคคเคพ",465 "current": "เคตเคฐเฅเคคเคฎเคพเคจ", "projected": "เค
เคจเฅเคฎเคพเคจเคฟเคค", "improvement": "เคธเฅเคงเคพเคฐ",466 467 # FIXED: Metric Names - Hindi translations468 "totalrevenue": "เคเฅเคฒ เคฐเคพเคเคธเฅเคต", 469 "totalprofit": "เคเฅเคฒ เคฒเคพเคญ", 470 "totalloss": "เคเฅเคฒ เคนเคพเคจเคฟ",471 "totalebit": "เคเฅเคฒ เคเคฌเคฟเค", 472 "totalgrossprofit": "เคเฅเคฒ เคธเคเคฒ เคฒเคพเคญ", 473 "averageroi": "เคเคธเคค เคเคฐเคเคเค",474 "profitmargin": "เคฒเคพเคญ เคฎเคพเคฐเฅเคเคฟเคจ", 475 "revenueimpact": "เคฐเคพเคเคธเฅเคต เคชเฅเคฐเคญเคพเคต", 476 "additionalprofit": "เค
เคคเคฟเคฐเคฟเคเฅเคค เคฒเคพเคญ",477 478 # Add to Hindi section:479 "revenue": "เคฐเคพเคเคธเฅเคต",480 "marketing_spend": "เคฎเคพเคฐเฅเคเฅเคเคฟเคเค เคเคฐเฅเค",481 "employee_count": "เคเคฐเฅเคฎเคเคพเคฐเฅ เคธเคเคเฅเคฏเคพ", 482 "units_sold": "เคฌเฅเคเฅ เคเค เคเคเคพเคเคฏเคพเค",483 "customer_satisfaction": "เคเฅเคฐเคพเคนเค เคธเคเคคเฅเคทเฅเคเคฟ",484 "market_share": "เคฌเคพเคเคพเคฐ เคนเคฟเคธเฅเคธเคพ",485 "product_price": "เคเคคเฅเคชเคพเคฆ เคฎเฅเคฒเฅเคฏ",486 "revenue_per_unit": "เคชเฅเคฐเคคเคฟ เคฏเฅเคจเคฟเค เคฐเคพเคเคธเฅเคต",487 "cost_per_unit": "เคชเฅเคฐเคคเคฟ เคฏเฅเคจเคฟเค เคฒเคพเคเคค",488 "roi": "เคเคฐเคเคเค",489 "operating_costs": "เคชเคฐเคฟเคเคพเคฒเคจ เคฒเคพเคเคค",490 491 # Status and interpretations492 "above_average": "เคเคธเคค เคธเฅ เคเคชเคฐ", "needs_improvement": "เคธเฅเคงเคพเคฐ เคเฅ เคเคตเคถเฅเคฏเคเคคเคพ", "strong": "เคฎเคเคฌเฅเคค",493 "moderate": "เคฎเคงเฅเคฏเคฎ", "weak": "เคเคฎเคเฅเคฐ", "positive": "เคธเคเคพเคฐเคพเคคเฅเคฎเค", "negative": "เคจเคเคพเคฐเคพเคคเฅเคฎเค",494 "high": "เคเคเฅเค", "medium": "เคฎเคงเฅเคฏเคฎ", "normal": "เคธเคพเคฎเคพเคจเฅเคฏ",495 496 # Metadata labels497 "business_context": "เคตเฅเคฏเคพเคตเคธเคพเคฏเคฟเค เคธเคเคฆเคฐเฅเคญ", "analysis_type": "เคตเคฟเคถเฅเคฒเฅเคทเคฃ เคชเฅเคฐเคเคพเคฐ", "target_variable": "เคฒเคเฅเคทเฅเคฏ เคเคฐ",498 "report_language": "เคฐเคฟเคชเฅเคฐเฅเค เคญเคพเคทเคพ", "generated_on": "เคเฅเคจเคฐเฅเค เคเคฟเคฏเคพ เคเคฏเคพ",499 500 # Notes and messages501 "multilingual_note": "เคจเฅเค: เคฏเคน เคฐเคฟเคชเฅเคฐเฅเค {language} เคญเคพเคทเคพ เคเฅ เคฒเคฟเค เคเฅเคจเคฐเฅเค เคเฅ เคเค เคฅเฅเฅค PDF เคซเฅเคจเฅเค เคธเฅเคฎเคพเคเค เคเฅ เคเคพเคฐเคฃ, เคธเคพเคฎเคเฅเคฐเฅ {language} AI เค
เคเคคเคฐเฅเคฆเฅเคทเฅเคเคฟ เคเฅ เคธเคพเคฅ เค
เคเคเฅเคฐเฅเคเฅ เคฎเฅเค เคชเฅเคฐเคฆเคฐเฅเคถเคฟเคค เคเฅ เคเคพเคคเฅ เคนเฅเฅค",502 "no_insight_available": "เคเฅเค เคตเคฟเคถเคฟเคทเฅเค เค
เคเคคเคฐเฅเคฆเฅเคทเฅเคเคฟ เคเคชเคฒเคฌเฅเคง เคจเคนเฅเคเฅค"503 },504 505 "Marathi": {506 # Report titles and headers507 "business_intelligence_report": "เคตเฅเคฏเคพเคตเคธเคพเคฏเคฟเค เคฌเฅเคฆเฅเคงเคฟเคฎเคคเฅเคคเคพ เคตเคฟเคถเฅเคฒเฅเคทเคฃ เค
เคนเคตเคพเคฒ",508 "executive_summary": "เคเคพเคฐเฅเคฏเคเคพเคฐเฅ เคธเคพเคฐเคพเคเคถ", "detailed_analysis": "เคคเคชเคถเฅเคฒเคตเคพเคฐ เคตเคฟเคถเฅเคฒเฅเคทเคฃ",509 "technical_report": "เคคเคพเคเคคเฅเคฐเคฟเค เค
เคนเคตเคพเคฒ", "visual_analysis_dashboard": "เคฆเฅเคถเฅเคฏ เคตเคฟเคถเฅเคฒเฅเคทเคฃ เคกเฅ
เคถเคฌเฅเคฐเฅเคก",510 "ai_powered_recommendations": "AI-เคเคพเคฒเคฟเคค เคงเฅเคฐเคฃเคพเคคเฅเคฎเค เคถเคฟเคซเคพเคฐเคธเฅ", "expected_financial_impact": "เค
เคชเฅเคเฅเคทเคฟเคค เคเคฐเฅเคฅเคฟเค เคชเฅเคฐเคญเคพเคต",511 "key_performance_indicators": "เคฎเฅเคเฅเคฏ เคเคพเคฎเคเคฟเคฐเฅ เคจเคฟเคฐเฅเคฆเฅเคถเค", "critical_success_factors": "เคเคเคญเฅเคฐ เคฏเคถ เคเคเค", 512 "analysis_focus": "เคตเคฟเคถเฅเคฒเฅเคทเคฃ เคซเฅเคเคธ", "key_insight": "เคฎเฅเคเฅเคฏ เค
เคเคคเคฐเฅเคฆเฅเคทเฅเคเฅ", "recommendation": "เคถเคฟเคซเคพเคฐเคธ",513 "generated_in_ai": "{language} เคฎเคงเฅเคฏเฅ AI เคฆเฅเคตเคพเคฐเฅ เคตเฅเคฏเฅเคคเฅเคชเคจเฅเคจ, เคเคเคเฅเคฐเคเฅเคฎเคงเฅเคฏเฅ เคชเฅเคฐเคฆเคฐเฅเคถเคฟเคค",514 515 # Chart titles516 "financial_waterfall_analysis": "เคเคฐเฅเคฅเคฟเค เคตเฅเคเคฐเคซเฅเคฒ เคตเคฟเคถเฅเคฒเฅเคทเคฃ", "profitability_trend_analysis": "เคจเคซเคพ เคเฅเคฐเฅเคเคก เคตเคฟเคถเฅเคฒเฅเคทเคฃ",517 "breakeven_analysis": "เคฌเฅเคฐเฅเค-เคเคตเฅเคนเคจ เคตเคฟเคถเฅเคฒเฅเคทเคฃ", "segment_profitability_analysis": "เคตเคฟเคญเคพเค เคจเคซเคพ เคตเคฟเคถเฅเคฒเฅเคทเคฃ", 518 "roi_performance_distribution": "ROI เคเคพเคฎเคเคฟเคฐเฅ เคตเคฟเคคเคฐเคฃ", "cumulative_roi_analysis": "เคธเคเคเคฏเฅ ROI เคตเคฟเคถเฅเคฒเฅเคทเคฃ",519 "roi_by_project_analysis": "เคชเฅเคฐเคเคฒเฅเคชเคพเคจเฅเคธเคพเคฐ ROI เคตเคฟเคถเฅเคฒเฅเคทเคฃ", "roi_vs_risk_analysis": "ROI เคตเคฟเคฐเฅเคฆเฅเคง เคเฅเคเฅเคฎ เคตเคฟเคถเฅเคฒเฅเคทเคฃ",520 521 # Table headers522 "metric": "เคฎเฅเคเฅเคฐเคฟเค", "value": "เคฎเฅเคฒเฅเคฏ", "interpretation": "เคตเฅเคฏเคพเคเฅเคฏเคพ",523 "rank": "เคฐเคเค", "success_factor": "เคฏเคถ เคเคเค", "impact_score": "เคชเฅเคฐเคญเคพเคต เคธเฅเคเฅเค
เคฐ", "priority": "เคชเฅเคฐเคพเคฅเคฎเคฟเคเคคเคพ",524 "current": "เคธเคงเฅเคฏเคพเคเฅ", "projected": "เค
เคเคฆเคพเคเคฟเคค", "improvement": "เคธเฅเคงเคพเคฐเคฃเคพ",525 526 # FIXED: Metric Names - Marathi translations527 "totalrevenue": "เคเคเฅเคฃ เคฎเคนเคธเฅเคฒ", 528 "totalprofit": "เคเคเฅเคฃ เคจเคซเคพ", 529 "totalloss": "เคเคเฅเคฃ เคคเฅเคเคพ",530 "totalebit": "เคเคเฅเคฃ เคเคฌเคฟเค", 531 "totalgrossprofit": "เคเคเฅเคฃ เคธเคเคฒ เคจเคซเคพ", 532 "averageroi": "เคธเคฐเคพเคธเคฐเฅ ROI",533 "profitmargin": "เคจเคซเคพ เคฎเคพเคฐเฅเคเคฟเคจ", 534 "revenueimpact": "เคฎเคนเคธเฅเคฒ เคชเฅเคฐเคญเคพเคต", 535 "additionalprofit": "เค
เคคเคฟเคฐเคฟเคเฅเคค เคจเคซเคพ",536 537 # Status and interpretations538 "above_average": "เคธเคฐเคพเคธเคฐเฅเคชเฅเคเฅเคทเคพ เคเคพเคธเฅเคค", "needs_improvement": "เคธเฅเคงเคพเคฐเคฃเฅเคเฅ เคเคฐเค", "strong": "เคฎเคเคฌเฅเคค",539 "moderate": "เคฎเคงเฅเคฏเคฎ", "weak": "เคเคฎเคเฅเคตเคค", "positive": "เคธเคเคพเคฐเคพเคคเฅเคฎเค", "negative": "เคจเคเคพเคฐเคพเคคเฅเคฎเค",540 "high": "เคเคเฅเค", "medium": "เคฎเคงเฅเคฏเคฎ", "normal": "เคธเคพเคฎเคพเคจเฅเคฏ",541 542 # Metadata labels543 "business_context": "เคตเฅเคฏเคพเคตเคธเคพเคฏเคฟเค เคธเคเคฆเคฐเฅเคญ", "analysis_type": "เคตเคฟเคถเฅเคฒเฅเคทเคฃ เคชเฅเคฐเคเคพเคฐ", "target_variable": "เคฒเคเฅเคทเฅเคฏ เคเคฒ",544 "report_language": "เค
เคนเคตเคพเคฒ เคญเคพเคทเคพ", "generated_on": "เคตเฅเคฏเฅเคคเฅเคชเคจเฅเคจ เคเฅเคฒเฅ",545 546 # Notes and messages547 "multilingual_note": "เคเฅเคช: เคนเคพ เค
เคนเคตเคพเคฒ {language} เคญเคพเคทเฅเคธเคพเค เฅ เคตเฅเคฏเฅเคคเฅเคชเคจเฅเคจ เคเคฐเคฃเฅเคฏเคพเคค เคเคฒเคพ เคนเฅเคคเคพเฅค PDF เคซเฅเคจเฅเค เคฎเคฐเฅเคฏเคพเคฆเคพเคเคฎเฅเคณเฅ, เคธเคพเคฎเคเฅเคฐเฅ {language} AI เค
เคเคคเคฐเฅเคฆเฅเคทเฅเคเฅเคธเคน เคเคเคเฅเคฐเคเฅเคฎเคงเฅเคฏเฅ เคชเฅเคฐเคฆเคฐเฅเคถเคฟเคค เคเฅเคฒเฅ เคเคพเคคเฅ.",548 "no_insight_available": "เคเฅเคฃเคคเฅเคนเฅ เคตเคฟเคถเคฟเคทเฅเค เค
เคเคคเคฐเฅเคฆเฅเคทเฅเคเฅ เคเคชเคฒเคฌเฅเคง เคจเคพเคนเฅ."549 }550}551 552def get_metric_name_translation(key, language):553 """Get metric name in specified language"""554 return TRANSLATIONS.get(language, {}).get(key, key.replace('_', ' '))555 556def get_translation(key, language="English", **kwargs):557 """Get translated text for a given key and language"""558 try:559 if language in TRANSLATIONS and key in TRANSLATIONS[language]:560 text = TRANSLATIONS[language][key]561 # Handle string formatting if kwargs provided562 if kwargs:563 return text.format(**kwargs)564 return text565 else:566 # Fallback to English567 text = TRANSLATIONS["English"].get(key, key)568 if kwargs:569 return text.format(**kwargs)570 return text571 except Exception as e:572 # Emergency fallback573 return TRANSLATIONS["English"].get(key, key)574 575def translate_chart_title(english_title, language):576 """Translate chart titles to the specified language"""577 578 title_mappings = {579 "Financial Waterfall Analysis": "financial_waterfall_analysis",580 "Profitability Trend Analysis": "profitability_trend_analysis", 581 "Break-Even Analysis": "breakeven_analysis",582 "Segment Profitability Analysis": "segment_profitability_analysis",583 "ROI Performance Distribution": "roi_performance_distribution",584 "Cumulative ROI Analysis": "cumulative_roi_analysis", 585 "ROI by Project Analysis": "roi_by_project_analysis",586 "ROI vs Risk Analysis": "roi_vs_risk_analysis"587 }588 589 # Find the mapping key590 for title, mapping_key in title_mappings.items():591 if title.lower() in english_title.lower():592 return get_translation(mapping_key, language)593 594 # If no mapping found, return original595 return english_title596 597def translate_analysis_type(analysis_type, language):598 """Translate analysis type labels"""599 if "Profit & Loss" in analysis_type or "P/L" in analysis_type:600 if language == "Hindi":601 return "เคฒเคพเคญ เคเคฐ เคนเคพเคจเคฟ (P/L)"602 elif language == "Marathi": 603 return "เคจเคซเคพ เคเคฃเคฟ เคคเฅเคเคพ (P/L)"604 elif "Return on Investment" in analysis_type or "ROI" in analysis_type:605 if language == "Hindi":606 return "เคจเคฟเคตเฅเคถ เคชเคฐ เคฐเคฟเคเคฐเฅเคจ (ROI)"607 elif language == "Marathi":608 return "เคเฅเคเคคเคตเคฃเฅเคเฅเคตเคฐเฅเคฒ เคชเคฐเคคเคพเคตเคพ (ROI)"609 610 return analysis_type611 612def translate_business_context(business_context, language):613 """Translate business context"""614 business_translations = {615 "English": {616 "General Business Analysis": "General Business Analysis",617 "Sales & Revenue Analysis": "Sales & Revenue Analysis", 618 "Marketing ROI Analysis": "Marketing ROI Analysis",619 "Financial Performance": "Financial Performance",620 "Investment Analysis": "Investment Analysis"621 },622 "Hindi": {623 "General Business Analysis": "เคธเคพเคฎเคพเคจเฅเคฏ เคตเฅเคฏเคพเคตเคธเคพเคฏเคฟเค เคตเคฟเคถเฅเคฒเฅเคทเคฃ",624 "Sales & Revenue Analysis": "เคฌเคฟเคเฅเคฐเฅ เคเคฐ เคฐเคพเคเคธเฅเคต เคตเคฟเคถเฅเคฒเฅเคทเคฃ",625 "Marketing ROI Analysis": "เคฎเคพเคฐเฅเคเฅเคเคฟเคเค ROI เคตเคฟเคถเฅเคฒเฅเคทเคฃ", 626 "Financial Performance": "เคตเคฟเคคเฅเคคเฅเคฏ เคชเฅเคฐเคฆเคฐเฅเคถเคจ",627 "Investment Analysis": "เคจเคฟเคตเฅเคถ เคตเคฟเคถเฅเคฒเฅเคทเคฃ"628 },629 "Marathi": {630 "General Business Analysis": "เคธเคพเคฎเคพเคจเฅเคฏ เคตเฅเคฏเคพเคตเคธเคพเคฏเคฟเค เคตเคฟเคถเฅเคฒเฅเคทเคฃ",631 "Sales & Revenue Analysis": "เคตเคฟเคเฅเคฐเฅ เคเคฃเคฟ เคฎเคนเคธเฅเคฒ เคตเคฟเคถเฅเคฒเฅเคทเคฃ",632 "Marketing ROI Analysis": "เคฎเคพเคฐเฅเคเฅเคเคฟเคเค ROI เคตเคฟเคถเฅเคฒเฅเคทเคฃ",633 "Financial Performance": "เคเคฐเฅเคฅเคฟเค เคเคพเคฎเคเคฟเคฐเฅ", 634 "Investment Analysis": "เคเฅเคเคคเคตเคฃเฅเค เคตเคฟเคถเฅเคฒเฅเคทเคฃ"635 }636 }637 638 return business_translations.get(language, {}).get(business_context, business_context)639 640def get_interpretation_text(key, value, language):641 """Get interpretation text in the specified language - FIXED VERSION"""642 643 # Debug print to check inputs644 print(f"DEBUG: Interpreting key='{key}', value={value}, language='{language}'")645 646 try:647 if "profit" in key.lower() or "revenue" in key.lower():648 if value > 100000: # Adjust threshold for large numbers649 interpretation_key = "above_average"650 elif value > 0:651 interpretation_key = "positive"652 else:653 interpretation_key = "needs_improvement"654 elif "roi" in key.lower() or "margin" in key.lower():655 if value > 15:656 interpretation_key = "strong"657 elif value > 5:658 interpretation_key = "moderate"659 elif value > 0:660 interpretation_key = "weak"661 else:662 interpretation_key = "negative"663 elif "loss" in key.lower():664 if value > 0:665 interpretation_key = "negative" # Loss is bad666 else:667 interpretation_key = "positive" # No loss is good668 else:669 interpretation_key = "positive" if value > 0 else "negative"670 671 result = get_translation(interpretation_key, language)672 print(f"DEBUG: Interpretation result: '{result}'")673 return result674 675 except Exception as e:676 print(f"ERROR in get_interpretation_text: {e}")677 # Fallback678 return get_translation("normal", language)679 680def get_priority_text(rank, language):681 """Get priority text in specified language"""682 if rank < 2:683 return get_translation("high", language)684 elif rank < 4:685 return get_translation("medium", language)686 else:687 return get_translation("normal", language)688 689# Function to use in main PDF generation690def create_translated_metadata_table(business_context, analysis_type, target_variable, language):691 """Create metadata table with complete translations - FINAL FIX"""692 693 print(f"DEBUG METADATA: Inputs - context: {business_context}, analysis: {analysis_type}, target: {target_variable}, lang: {language}")694 695 # Ensure all inputs are valid strings with fallbacks696 safe_business_context = str(business_context) if business_context else "General Business Analysis"697 safe_analysis_type = str(analysis_type) if analysis_type else "Business Analysis"698 safe_target_variable = str(target_variable).replace('_', ' ').title() if target_variable else "Business Metric"699 safe_language = str(language) if language else "English"700 701 # FIXED: Translate business context properly702 if safe_business_context == "General Business Analysis":703 if language == "Hindi":704 translated_business_context = "เคธเคพเคฎเคพเคจเฅเคฏ เคตเฅเคฏเคพเคตเคธเคพเคฏเคฟเค เคตเคฟเคถเฅเคฒเฅเคทเคฃ"705 elif language == "Marathi":706 translated_business_context = "เคธเคพเคฎเคพเคจเฅเคฏ เคตเฅเคฏเคพเคตเคธเคพเคฏเคฟเค เคตเคฟเคถเฅเคฒเฅเคทเคฃ"707 else:708 translated_business_context = safe_business_context709 else:710 translated_business_context = translate_business_context(safe_business_context, language)711 712 # FIXED: Translate analysis type properly713 if "Profit & Loss" in safe_analysis_type or "P/L" in safe_analysis_type:714 if language == "Hindi":715 translated_analysis_type = "เคฒเคพเคญ เคเคฐ เคนเคพเคจเคฟ (P/L) เคตเคฟเคถเฅเคฒเฅเคทเคฃ"716 elif language == "Marathi":717 translated_analysis_type = "เคจเคซเคพ เคเคฃเคฟ เคคเฅเคเคพ (P/L) เคตเคฟเคถเฅเคฒเฅเคทเคฃ"718 else:719 translated_analysis_type = safe_analysis_type720 elif "ROI" in safe_analysis_type or "Return on Investment" in safe_analysis_type:721 if language == "Hindi":722 translated_analysis_type = "เคจเคฟเคตเฅเคถ เคชเคฐ เคฐเคฟเคเคฐเฅเคจ (ROI) เคตเคฟเคถเฅเคฒเฅเคทเคฃ"723 elif language == "Marathi":724 translated_analysis_type = "เคเฅเคเคคเคตเคฃเฅเคเฅเคตเคฐเฅเคฒ เคชเคฐเคคเคพเคตเคพ (ROI) เคตเคฟเคถเฅเคฒเฅเคทเคฃ"725 else:726 translated_analysis_type = safe_analysis_type727 else:728 translated_analysis_type = safe_analysis_type729 730 # FIXED: Translate target variable properly731 target_translations = {732 "Net Profit": {"Hindi": "เคถเฅเคฆเฅเคง เคฒเคพเคญ", "Marathi": "เคจเคฟเคตเฅเคตเคณ เคจเคซเคพ"},733 "Revenue": {"Hindi": "เคฐเคพเคเคธเฅเคต", "Marathi": "เคฎเคนเคธเฅเคฒ"},734 "ROI": {"Hindi": "เคเคฐเคเคเค", "Marathi": "เคเคฐเคเคเค"},735 "Total Profit": {"Hindi": "เคเฅเคฒ เคฒเคพเคญ", "Marathi": "เคเคเฅเคฃ เคจเคซเคพ"},736 "Profit Margin": {"Hindi": "เคฒเคพเคญ เคฎเคพเคฐเฅเคเคฟเคจ", "Marathi": "เคจเคซเคพ เคฎเคพเคฐเฅเคเคฟเคจ"}737 }738 739 if safe_target_variable in target_translations and language in target_translations[safe_target_variable]:740 translated_target_variable = target_translations[safe_target_variable][language]741 else:742 translated_target_variable = safe_target_variable743 744 # FIXED: Translate language name745 language_translations = {746 "English": {"Hindi": "เค
เคเคเฅเคฐเฅเคเฅ", "Marathi": "เคเคเคเฅเคฐเคเฅ"},747 "Hindi": {"Hindi": "เคนเคฟเคเคฆเฅ", "Marathi": "เคนเคฟเคเคฆเฅ"},748 "Marathi": {"Hindi": "เคฎเคฐเคพเค เฅ", "Marathi": "เคฎเคฐเคพเค เฅ"}749 }750 751 if safe_language in language_translations and language in language_translations[safe_language]:752 translated_language = language_translations[safe_language][language]753 else:754 translated_language = safe_language755 756 # Generate current timestamp - FIXED for Hindi/Marathi757 if language == "Hindi":758 current_time = datetime.now().strftime('%d %B, %Y เคเฅ %H:%M')759 elif language == "Marathi":760 current_time = datetime.now().strftime('%d %B, %Y เคฐเฅเคเฅ %H:%M')761 else:762 current_time = datetime.now().strftime('%B %d, %Y at %H:%M')763 764 # Create metadata with guaranteed translated content765 metadata = [766 [get_translation("business_context", language), translated_business_context],767 [get_translation("analysis_type", language), translated_analysis_type], 768 [get_translation("target_variable", language), translated_target_variable],769 [get_translation("report_language", language), translated_language],770 [get_translation("generated_on", language), current_time]771 ]772 773 print(f"DEBUG METADATA: Final metadata with translations: {metadata}")774 return metadata775 776def format_currency_value(value):777 """Format currency with guaranteed $M/$K notation."""778 try:779 # Step 1: Clean the value if it's a string780 if isinstance(value, str):781 # Remove any commas, spaces, or currency symbols782 cleaned_value = value.replace(",", "").replace(" ", "").replace("$", "")783 # Convert to float784 val = float(cleaned_value)785 else:786 val = float(value)787 788 abs_val = abs(val)789 790 if abs_val >= 1_000_000:791 return f"${val/1_000_000:.1f}M"792 elif abs_val >= 1_000:793 return f"${val/1_000:.1f}K" 794 else:795 return f"${val:,.0f}"796 except (ValueError, TypeError):797 # Fallback for invalid inputs798 return "$0"799 800def create_translated_kpi_table(kpis, language):801 """Create KPI table with translations and correct currency formatting - FIXED VERSION"""802 803 kpi_data = [[804 get_translation("metric", language), 805 get_translation("value", language), 806 get_translation("interpretation", language)807 ]]808 809 # Fixed mapping dictionary810 kpi_translation_mapping = {811 'Total_Revenue': 'totalrevenue',812 'Total_Profit': 'totalprofit', 813 'Total_Loss': 'totalloss',814 'Total_EBIT': 'totalebit',815 'Total_Gross_Profit': 'totalgrossprofit',816 'Average_ROI': 'averageroi',817 'Profit_Margin': 'profitmargin',818 'Revenue_Impact': 'revenueimpact',819 'Additional_Profit': 'additionalprofit'820 }821 822 for key, value in kpis.items():823 translation_key = kpi_translation_mapping.get(key, key.lower().replace('_', ''))824 metric_name = get_translation(translation_key, language)825 826 if "roi" in key.lower() or "margin" in key.lower():827 formatted_value = f"{value:.1f}%"828 else:829 formatted_value = format_currency_value(value)830 831 interpretation = get_interpretation_text(key, value, language)832 kpi_data.append([metric_name, formatted_value, interpretation])833 834 return kpi_data835 836def create_working_metadata_table(business_context, analysis_type, target_variable, language):837 """Create metadata table with translations and correct date format."""838 839 translated_business_context = translate_business_context(business_context, language)840 translated_analysis_type = translate_analysis_type(analysis_type, language)841 842 months = {843 1: "January", 2: "February", 3: "March", 4: "April",844 5: "May", 6: "June", 7: "July", 8: "August",845 9: "September", 10: "October", 11: "November", 12: "December"846 }847 now = datetime.now()848 month_name = months.get(now.month, "")849 formatted_date = now.strftime(f"{month_name} %d, %Y at %H:%M")850 851 # FIX: Ensure all values are correctly formatted as strings before passing to paragraph852 metadata = [853 [get_translation("business_context", language), translated_business_context],854 [get_translation("analysis_type", language), translated_analysis_type], 855 [get_translation("target_variable", language), target_variable.replace('_', ' ')],856 [get_translation("report_language", language), language],857 [get_translation("generated_on", language), formatted_date]858 ]859 860 return metadata861 862def create_translated_factor_table(feature_df, language):863 """Create success factors table with complete translations - FINAL FIX"""864 865 print(f"DEBUG FACTORS: Input feature_df: {feature_df}")866 print(f"DEBUG FACTORS: Language: {language}")867 868 # Handle empty or None feature_df869 if feature_df is None or feature_df.empty or len(feature_df) == 0:870 no_data_message = get_translation("no_insight_available", language)871 return [[no_data_message, "", "", ""]]872 873 # Create header row874 factor_data = [[875 get_translation("rank", language),876 get_translation("success_factor", language), 877 get_translation("impact_score", language),878 get_translation("priority", language)879 ]]880 881 # COMPREHENSIVE factor translation dictionary882 factor_translations = {883 "English": {884 "Revenue": "Revenue",885 "Marketing Spend": "Marketing Spend",886 "Marketing Investment": "Marketing Investment",887 "Employee Count": "Employee Count",888 "Team Size": "Team Size",889 "Units Sold": "Sales Volume",890 "Sales Volume": "Sales Volume",891 "Customer Satisfaction": "Customer Satisfaction",892 "Market Share": "Market Position",893 "Product Price": "Pricing Strategy",894 "Revenue Per Unit": "Unit Revenue",895 "Cost Per Unit": "Unit Cost",896 "Profit Margin": "Profit Margins",897 "ROI": "Return on Investment",898 "Operating Costs": "Operating Expenses",899 "Net Profit": "Net Profit",900 "R D Investment": "R&D Investment"901 },902 "Hindi": {903 "Revenue": "เคฐเคพเคเคธเฅเคต",904 "Marketing Spend": "เคฎเคพเคฐเฅเคเฅเคเคฟเคเค เคเคฐเฅเค",905 "Marketing Investment": "เคฎเคพเคฐเฅเคเฅเคเคฟเคเค เคจเคฟเคตเฅเคถ",906 "Employee Count": "เคเคฐเฅเคฎเคเคพเคฐเฅ เคธเคเคเฅเคฏเคพ",907 "Team Size": "เคเฅเคฎ เคเคพ เคเคเคพเคฐ",908 "Units Sold": "เคฌเฅเคเฅ เคเค เคเคเคพเคเคฏเคพเค",909 "Sales Volume": "เคฌเคฟเคเฅเคฐเฅ เคฎเคพเคคเฅเคฐเคพ",910 "Customer Satisfaction": "เคเฅเคฐเคพเคนเค เคธเคเคคเฅเคทเฅเคเคฟ",911 "Market Share": "เคฌเคพเคเคพเคฐ เคนเคฟเคธเฅเคธเคพ",912 "Product Price": "เคเคคเฅเคชเคพเคฆ เคฎเฅเคฒเฅเคฏ",913 "Revenue Per Unit": "เคชเฅเคฐเคคเคฟ เคฏเฅเคจเคฟเค เคฐเคพเคเคธเฅเคต",914 "Cost Per Unit": "เคชเฅเคฐเคคเคฟ เคฏเฅเคจเคฟเค เคฒเคพเคเคค",915 "Profit Margin": "เคฒเคพเคญ เคฎเคพเคฐเฅเคเคฟเคจ",916 "ROI": "เคเคฐเคเคเค",917 "Operating Costs": "เคชเคฐเคฟเคเคพเคฒเคจ เคฒเคพเคเคค",918 "Net Profit": "เคถเฅเคฆเฅเคง เคฒเคพเคญ",919 "R D Investment": "เค
เคจเฅเคธเคเคงเคพเคจ เคตเคฟเคเคพเคธ เคจเคฟเคตเฅเคถ"920 },921 "Marathi": {922 "Revenue": "เคฎเคนเคธเฅเคฒ",923 "Marketing Spend": "เคฎเคพเคฐเฅเคเฅเคเคฟเคเค เคเคฐเฅเค",924 "Marketing Investment": "เคฎเคพเคฐเฅเคเฅเคเคฟเคเค เคเฅเคเคคเคตเคฃเฅเค",925 "Employee Count": "เคเคฐเฅเคฎเคเคพเคฐเฅ เคธเคเคเฅเคฏเคพ",926 "Team Size": "เคเฅเคฎ เคเคเคพเคฐ",927 "Units Sold": "เคตเคฟเคเคฒเฅ เคเฅเคฒเฅเคฒเฅ เคฏเฅเคจเคฟเคเฅเคธ",928 "Sales Volume": "เคตเคฟเคเฅเคฐเฅ เคชเฅเคฐเคฎเคพเคฃ",929 "Customer Satisfaction": "เคเฅเคฐเคพเคนเค เคธเคฎเคพเคงเคพเคจ",930 "Market Share": "เคฌเคพเคเคพเคฐ เคตเคพเคเคพ",931 "Product Price": "เคเคคเฅเคชเคพเคฆ เคเคฟเคเคฎเคค",932 "Revenue Per Unit": "เคชเฅเคฐเคคเคฟ เคฏเฅเคจเคฟเค เคฎเคนเคธเฅเคฒ",933 "Cost Per Unit": "เคชเฅเคฐเคคเคฟ เคฏเฅเคจเคฟเค เคเคฟเคเคฎเคค",934 "Profit Margin": "เคจเคซเคพ เคฎเคพเคฐเฅเคเคฟเคจ",935 "ROI": "เคเคฐเคเคเค",936 "Operating Costs": "เคเคชเคฐเฅเคเคฟเคเค เคเคฐเฅเค",937 "Net Profit": "เคจเคฟเคตเฅเคตเคณ เคจเคซเคพ",938 "R D Investment": "เคธเคเคถเฅเคงเคจ เคตเคฟเคเคพเคธ เคเฅเคเคคเคตเคฃเฅเค"939 }940 }941 942 # Process each factor943 for i in range(min(5, len(feature_df))):944 try:945 row = feature_df.iloc[i]946 947 # --- FIX STARTS HERE ---948 # Get factor name and handle missing/invalid data949 factor_name = row.get('Factor', 'Unknown Factor')950 if pd.isna(factor_name) or not isinstance(factor_name, str) or not factor_name.strip():951 factor_name = "Unknown Factor"952 953 # --- FIX ENDS HERE ---954 955 # Get impact score956 impact_score = float(row.get('Impact_Score', 0.0))957 958 # Translate the factor name959 # Check for the key with proper spacing first960 translated_factor = factor_translations.get(language, {}).get(961 factor_name.replace("_", " "), 962 factor_name.replace("_", " ").title()963 )964 965 # Get priority text966 priority = get_priority_text(i, language)967 968 # Add row to table969 factor_row = [970 f"{i+1}",971 translated_factor, 972 f"{impact_score:.3f}",973 priority974 ]975 976 factor_data.append(factor_row)977 978 except Exception as e:979 print(f"ERROR processing factor {i}: {e}")980 error_factor = get_translation(f"Factor", language) + f" {i+1}"981 factor_data.append([982 f"{i+1}",983 error_factor,984 "0.000",985 get_translation("normal", language)986 ])987 988 return factor_data989 990# ===========================991# ORIGINAL FUNCTIONS (keeping all existing functions)992# ===========================993 994def analyze_dataset_features(df):995 """Analyze dataset features and provide insights"""996 st.subheader("๐ Dataset Analysis")997 998 col1, col2, col3 = st.columns(3)999 1000 with col1:1001 st.metric("๐ Total Rows", f"{df.shape[0]:,}")1002 st.metric("๐ Total Columns", f"{df.shape[1]:,}")1003 1004 with col2:1005 missing_values = df.isnull().sum().sum()1006 st.metric("โ Missing Values", f"{missing_values:,}")1007 duplicates = df.duplicated().sum()1008 st.metric("๐ Duplicate Rows", f"{duplicates:,}")1009 1010 with col3:1011 numeric_cols = df.select_dtypes(include=['number']).columns1012 categorical_cols = df.select_dtypes(include=['object', 'category']).columns1013 st.metric("๐ข Numeric Columns", len(numeric_cols))1014 st.metric("๐ท Categorical Columns", len(categorical_cols))1015 1016 # Display column types and missing values1017 col_info = pd.DataFrame({1018 'Column': df.columns,1019 'Data Type': df.dtypes,1020 'Missing Values': df.isnull().sum(),1021 'Missing %': (df.isnull().sum() / len(df) * 100).round(2)1022 })1023 1024 #st.subheader("๐ Column Information")1025 #st.dataframe(col_info)1026 1027 return numeric_cols.tolist(), categorical_cols.tolist()1028 1029def auto_clean_dataset(df):1030 """Perform automatic cleaning: fill missing values and remove outliers."""1031 #st.subheader("๐งน Auto-Cleaning Dataset")1032 1033 df_clean = df.copy()1034 cleaning_log = []1035 1036 categorical_cols = df_clean.select_dtypes(include=["object", "category"]).columns.tolist()1037 numeric_cols = df_clean.select_dtypes(include=["number"]).columns.tolist()1038 1039 # Fill missing values1040 for col in numeric_cols:1041 missing_count = df_clean[col].isnull().sum()1042 if missing_count > 0:1043 df_clean[col] = df_clean[col].fillna(df_clean[col].median())1044 cleaning_log.append(f"โ
Filled {missing_count} missing values in '{col}' with median")1045 1046 for col in categorical_cols:1047 missing_count = df_clean[col].isnull().sum()1048 if missing_count > 0:1049 mode_value = df_clean[col].mode()[0] if not df_clean[col].mode().empty else "Unknown"1050 df_clean[col] = df_clean[col].fillna(mode_value)1051 cleaning_log.append(f"โ
Filled {missing_count} missing values in '{col}' with mode/Unknown")1052 1053 # Remove outliers using IQR for numeric features1054 original_rows = len(df_clean)1055 for col in numeric_cols:1056 Q1 = df_clean[col].quantile(0.25)1057 Q3 = df_clean[col].quantile(0.75)1058 IQR = Q3 - Q11059 if IQR > 0: # Only remove outliers if there's variation1060 lower_bound = Q1 - 1.5 * IQR1061 upper_bound = Q3 + 1.5 * IQR1062 before_outlier_removal = len(df_clean)1063 df_clean = df_clean[(df_clean[col] >= lower_bound) & (df_clean[col] <= upper_bound)]1064 outliers_removed = before_outlier_removal - len(df_clean)1065 #if outliers_removed > 0:1066 #cleaning_log.append(f"๐๏ธ Removed {outliers_removed} outliers from '{col}'")1067 1068 total_outliers_removed = original_rows - len(df_clean)1069 #if total_outliers_removed > 0:1070 #cleaning_log.append(f"๐ Total rows removed due to outliers: {total_outliers_removed}")1071 1072 # Display cleaning log1073 for log in cleaning_log:1074 st.write(log)1075 1076 return df_clean, categorical_cols, numeric_cols1077 1078def engineer_features_with_metrics(df, num_cols, cat_cols):1079 """Engineer comprehensive financial and business features"""1080 #st.subheader("๐งช Feature Engineering")1081 1082 df_eng = df.copy()1083 new_features = []1084 1085 # --- Revenue-based metrics ---1086 revenue_cols = [col for col in df.columns if any(keyword in col.lower() for keyword in ['revenue', 'sales', 'income'])]1087 cost_cols = [col for col in df.columns if any(keyword in col.lower() for keyword in ['cost', 'expense', 'expenditure'])]1088 1089 if revenue_cols and cost_cols:1090 revenue_col = revenue_cols[0]1091 cost_col = cost_cols[0]1092 1093 # Net Profit/Loss1094 df_eng["Net_Profit"] = df_eng[revenue_col] - df_eng[cost_col]1095 df_eng["Net_Loss"] = df_eng["Net_Profit"].apply(lambda x: abs(x) if x < 0 else 0)1096 df_eng["Total_Profit"] = df_eng["Net_Profit"].apply(lambda x: x if x > 0 else 0)1097 new_features.extend(["Net_Profit", "Net_Loss", "Total_Profit"])1098 1099 # Profit Margin1100 df_eng["Profit_Margin"] = (df_eng["Net_Profit"] / df_eng[revenue_col]).replace([np.inf, -np.inf], 0) * 1001101 new_features.append("Profit_Margin")1102 1103 # --- COGS and Gross Profit ---1104 cogs_cols = [col for col in df.columns if any(keyword in col.lower() for keyword in ['cogs', 'cost_of_goods', 'direct_cost'])]1105 if revenue_cols and cogs_cols:1106 revenue_col = revenue_cols[0]1107 cogs_col = cogs_cols[0]1108 df_eng["Gross_Profit"] = df_eng[revenue_col] - df_eng[cogs_col]1109 df_eng["Gross_Profit_Margin"] = (df_eng["Gross_Profit"] / df_eng[revenue_col]).replace([np.inf, -np.inf], 0) * 1001110 new_features.extend(["Gross_Profit", "Gross_Profit_Margin"])1111 1112 # --- Operating metrics ---1113 operating_cost_cols = [col for col in df.columns if any(keyword in col.lower() for keyword in ['operating_cost', 'opex', 'operational'])]1114 if revenue_cols and operating_cost_cols:1115 revenue_col = revenue_cols[0]1116 op_cost_col = operating_cost_cols[0]1117 df_eng["EBIT"] = df_eng[revenue_col] - df_eng[op_cost_col]1118 df_eng["EBIT_Margin"] = (df_eng["EBIT"] / df_eng[revenue_col]).replace([np.inf, -np.inf], 0) * 1001119 new_features.extend(["EBIT", "EBIT_Margin"])1120 1121 # --- Investment and ROI ---1122 investment_cols = [col for col in df.columns if any(keyword in col.lower() for keyword in ['investment', 'capital', 'asset'])]1123 if "Net_Profit" in df_eng.columns and investment_cols:1124 investment_col = investment_cols[0]1125 df_eng["ROI"] = (df_eng["Net_Profit"] / df_eng[investment_col]).replace([np.inf, -np.inf], 0) * 1001126 new_features.append("ROI")1127 1128 # --- Units and Break-even analysis ---1129 units_cols = [col for col in df.columns if any(keyword in col.lower() for keyword in ['units', 'quantity', 'volume'])]1130 if units_cols and revenue_cols:1131 units_col = units_cols[0]1132 revenue_col = revenue_cols[0]1133 df_eng["Revenue_Per_Unit"] = (df_eng[revenue_col] / df_eng[units_col]).replace([np.inf, -np.inf], 0)1134 new_features.append("Revenue_Per_Unit")1135 1136 if cost_cols:1137 cost_col = cost_cols[0]1138 df_eng["Cost_Per_Unit"] = (df_eng[cost_col] / df_eng[units_col]).replace([np.inf, -np.inf], 0)1139 df_eng["Profit_Per_Unit"] = df_eng["Revenue_Per_Unit"] - df_eng["Cost_Per_Unit"]1140 new_features.extend(["Cost_Per_Unit", "Profit_Per_Unit"])1141 1142 # --- Time-based features (if date columns exist) ---1143 date_cols = df.select_dtypes(include=['datetime64']).columns.tolist()1144 if not date_cols:1145 # Try to identify date columns by name1146 potential_date_cols = [col for col in df.columns if any(keyword in col.lower() for keyword in ['date', 'time', 'year', 'month'])]1147 for col in potential_date_cols:1148 try:1149 df_eng[col] = pd.to_datetime(df_eng[col])1150 date_cols.append(col)1151 except:1152 pass1153 1154 if date_cols:1155 date_col = date_cols[0]1156 df_eng['Year'] = df_eng[date_col].dt.year1157 df_eng['Month'] = df_eng[date_col].dt.month1158 df_eng['Quarter'] = df_eng[date_col].dt.quarter1159 new_features.extend(['Year', 'Month', 'Quarter'])1160 1161 # One-hot encode remaining categoricals1162 remaining_cat_cols = [col for col in cat_cols if col in df_eng.columns]1163 if remaining_cat_cols:1164 df_eng = pd.get_dummies(df_eng, columns=remaining_cat_cols, drop_first=True)1165 #st.info(f"๐ One-hot encoded {len(remaining_cat_cols)} categorical columns")1166 1167 return df_eng, new_features1168 1169def calculate_kpis(df):1170 """Calculate comprehensive KPIs with proper naming - FIXED VERSION"""1171 kpis = {}1172 1173 # Revenue metrics1174 revenue_cols = [col for col in df.columns if any(keyword in col.lower() for keyword in ['revenue', 'sales', 'income'])]1175 if revenue_cols:1176 kpis['Total_Revenue'] = float(df[revenue_cols[0]].sum())1177 elif 'Revenue' in df.columns:1178 kpis['Total_Revenue'] = float(df['Revenue'].sum())1179 else:1180 kpis['Total_Revenue'] = 0.01181 1182 # Profit/Loss metrics1183 if 'Total_Profit' in df.columns:1184 kpis['Total_Profit'] = float(df['Total_Profit'].sum())1185 elif 'Net_Profit' in df.columns:1186 kpis['Total_Profit'] = float(df[df['Net_Profit'] > 0]['Net_Profit'].sum())1187 else:1188 kpis['Total_Profit'] = 0.01189 1190 if 'Net_Loss' in df.columns:1191 kpis['Total_Loss'] = float(df['Net_Loss'].sum())1192 elif 'Net_Profit' in df.columns:1193 kpis['Total_Loss'] = float(abs(df[df['Net_Profit'] < 0]['Net_Profit'].sum()))1194 else:1195 kpis['Total_Loss'] = 0.01196 1197 # EBIT1198 if 'EBIT' in df.columns:1199 kpis['Total_EBIT'] = float(df['EBIT'].sum())1200 else: