CoolFace
Apppublic

Rush147/ROI-PL

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
Generalize.py5013 linesDownload Raw Back to root
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:

Showing the first 1,200 of 5013 lines. Download the file for the rest.