""" app.py — Multi-AI Analytics Platform v2.1 (Clean Edition) Run: streamlit run app.py Requirements (install before running): pip install streamlit pandas numpy pillow plotly scikit-learn xgboost lightgbm pip install opencv-python-headless transformers torch torchvision pip install openai google-generativeai anthropic # optional, for API providers pip install spacy && python -m spacy download en_core_web_sm # optional NER Place these files in the SAME folder as app.py: generative_ai.py nlp_module.py ml_models.py (your existing file — unchanged) dl_module.py (your existing file — unchanged) data/data_loader.py data/powerbi_export.py config.py utils/helpers.py """ import warnings warnings.filterwarnings("ignore") import os import sys import json from pathlib import Path from typing import Any, Optional import streamlit as st import pandas as pd import numpy as np from PIL import Image # ── Root path setup ─────────────────────────────────────────────────────────── ROOT = Path(__file__).parent sys.path.insert(0, str(ROOT)) # ── Core imports ────────────────────────────────────────────────────────────── try: from config import Config, OUTPUT_DIR except ImportError: OUTPUT_DIR = ROOT / "outputs" OUTPUT_DIR.mkdir(exist_ok=True) from data.data_loader import DataLoader from data.powerbi_export import PowerBIExporter from models.ml_models import MLPipeline, XGBoostPipeline, EnsemblePipeline from models.generative_ai import GenerativeAI, OPENAI_OK, GOOGLE_OK, ANTHROPIC_OK from utils.helpers import ( create_feature_importance_chart, create_metrics_dashboard, create_confusion_matrix, create_correlation_heatmap, create_class_distribution, create_actual_vs_predicted, ) try: from models.ml_models import LightGBMPipeline LGB_OK = True except Exception: LightGBMPipeline = None LGB_OK = False # ── Page config ─────────────────────────────────────────────────────────────── st.set_page_config( page_title="Multi-AI Analytics Platform", page_icon="⚡", layout="wide", initial_sidebar_state="expanded", ) # ══════════════════════════════════════════════════════════════════════════════ # Global CSS — Aurora Dark theme # ══════════════════════════════════════════════════════════════════════════════ st.markdown(""" """, unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════════════════════ # Sidebar # ══════════════════════════════════════════════════════════════════════════════ with st.sidebar: st.markdown("""
AI Platform
v2.1 · CLEAN EDITION
""", unsafe_allow_html=True) st.divider() st.markdown("### 🔑 Generative AI") provider_choice = st.selectbox( "Provider", ["smart", "openai", "google", "anthropic"], format_func=lambda x: { "smart": "⚡ Smart AI (Instant · No API Key)", "openai": "🟢 OpenAI GPT-4o", "google": "🔵 Google Gemini", "anthropic": "🟣 Anthropic Claude", }[x], ) if provider_choice == "smart": st.caption("✅ Instant responses — no API key, no downloads") api_key_input = "" else: api_key_input = st.text_input("API Key", type="password", placeholder="Paste key here…") st.divider() st.markdown("### ⚙️ System Status") for lib, label, emoji in [ ("torch", "PyTorch", "🔥"), ("sklearn", "sklearn", "🤖"), ("xgboost", "XGBoost", "⚡"), ("transformers","Transformers", "🤗"), ("cv2", "OpenCV", "📷"), ("lightgbm", "LightGBM", "🌿"), ]: try: mod = __import__(lib) ver = getattr(mod, "__version__", "✓") st.markdown(f"{emoji} {label} `{ver}`") except ImportError: st.markdown(f"{emoji} {label} ❌") st.divider() if st.button("🔄 Reset Session", use_container_width=True): for k in list(st.session_state.keys()): del st.session_state[k] st.rerun() st.markdown("""
Multi-AI Analytics Platform
KYOTO-Z
""", unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════════════════════ # Session state initialisation # ══════════════════════════════════════════════════════════════════════════════ def _init(): defaults = { "data_loader": DataLoader(), "powerbi_exp": PowerBIExporter(OUTPUT_DIR), "df": None, "data_summary": None, "ml_pipeline": None, "ml_results": None, "ml_metrics": None, "gen_ai": GenerativeAI(provider="smart"), "uploaded_image": None, "target_column": None, } for k, v in defaults.items(): if k not in st.session_state: st.session_state[k] = v _init() # Always rebuild gen_ai when provider/key change st.session_state.gen_ai = GenerativeAI(api_key=api_key_input, provider=provider_choice) # ══════════════════════════════════════════════════════════════════════════════ # Hero Banner # ══════════════════════════════════════════════════════════════════════════════ st.markdown("""
⚡ Multi-AI Analytics Platform
Machine Learning  ·  Deep Learning  ·  NLP  ·  Generative AI  ·  Power BI Export
scikit-learn XGBoost HuggingFace OpenCV PyTorch / TF Plotly Power BI
""", unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════════════════════ # Main tabs # ══════════════════════════════════════════════════════════════════════════════ tab_home, tab_data, tab_ml, tab_dl, tab_nlp, tab_genai, tab_pbi = st.tabs([ "🏠 Home", "📊 Data", "🤖 ML Pipeline", "🧠 Deep Learning", "📝 NLP", "💡 Generative AI", "📤 Power BI", ]) # ────────────────────────────────────────────────────────────────────────────── # TAB 0 · HOME # ────────────────────────────────────────────────────────────────────────────── with tab_home: st.markdown("""
🤖
ML Pipeline
9+ models — Random Forest, XGBoost, LightGBM, Ensemble. Full metrics, ROC, feature importance.
📊
Data Explorer
Upload CSV/Excel/JSON. Auto EDA, correlation heatmaps, distributions, scatter builder.
🧠
Deep Learning
MobileNetV2, ResNet50, VGG16 classification. Grad-CAM, face/edge detection, image filters.
📝
NLP Suite
Sentiment analysis, NER, zero-shot classification, summarization — all via HuggingFace.
💡
Generative AI
GPT-4 · Gemini · Claude. Context-aware chatbot, Q&A, code gen, image generation, reports.
📤
Power BI Export
Export datasets, feature importance tables, and predictions as CSV/Parquet for Power BI.
""", unsafe_allow_html=True) st.markdown("---") c1, c2, c3, c4 = st.columns(4) c1.markdown('
9+
ML Models
', unsafe_allow_html=True) c2.markdown('
4
CNN Backbones
', unsafe_allow_html=True) c3.markdown('
5
NLP Tasks
', unsafe_allow_html=True) c4.markdown('
3
Gen AI Providers
', unsafe_allow_html=True) st.markdown("""
💡 Quick Start: Head to 📊 Data to upload your dataset, then use 🤖 ML Pipeline to train models, or jump to 🧠 Deep Learning for image analysis. Use 💡 Generative AI for automated insights.
""", unsafe_allow_html=True) # ────────────────────────────────────────────────────────────────────────────── # TAB 1 · DATA # ────────────────────────────────────────────────────────────────────────────── with tab_data: st.markdown('
📊 Data Loading & Exploration
', unsafe_allow_html=True) col_up, col_sum = st.columns([2, 1]) with col_up: uploaded_file = st.file_uploader( "Upload CSV, Excel, JSON or Image", type=["csv", "xlsx", "xls", "json", "png", "jpg", "jpeg", "bmp", "webp"], ) if uploaded_file: try: if uploaded_file.type.startswith("image"): img = Image.open(uploaded_file).convert("RGB") st.image(img, caption=uploaded_file.name, width=420) st.session_state.uploaded_image = img else: ext = Path(uploaded_file.name).suffix.lower() if ext == ".csv": df = pd.read_csv(uploaded_file) elif ext in [".xlsx", ".xls"]: df = pd.read_excel(uploaded_file) elif ext == ".json": df = pd.read_json(uploaded_file) else: df = pd.read_csv(uploaded_file) st.session_state.df = df st.session_state.data_summary = st.session_state.data_loader.get_data_summary(df) st.success(f"✅ Loaded **{uploaded_file.name}** — {df.shape[0]:,} rows × {df.shape[1]} cols") except Exception as e: st.error(f"❌ {e}") if st.session_state.df is not None: df = st.session_state.df with col_sum: st.markdown(f'
{df.shape[0]:,}
Rows
', unsafe_allow_html=True) st.markdown(f'
{df.shape[1]}
Columns
', unsafe_allow_html=True) st.markdown(f'
{df.isnull().sum().sum()}
Missing
', unsafe_allow_html=True) dtabs = st.tabs(["🔍 Preview", "📈 Statistics", "📊 Charts", "🌡️ Correlations"]) with dtabs[0]: st.dataframe(df.head(50), use_container_width=True) with dtabs[1]: st.dataframe(df.describe(include="all").T, use_container_width=True) col_a, col_b = st.columns(2) with col_a: st.markdown("**Data Types**") st.dataframe(df.dtypes.rename("Type").reset_index().rename(columns={"index": "Column"}), use_container_width=True) with col_b: st.markdown("**Missing Values**") miss = df.isnull().sum().reset_index() miss.columns = ["Column", "Missing"] miss["Pct"] = (miss["Missing"] / len(df) * 100).round(2) st.dataframe(miss[miss["Missing"] > 0], use_container_width=True) with dtabs[2]: import plotly.express as px num_cols = df.select_dtypes(include=np.number).columns.tolist() cat_cols = df.select_dtypes(include="object").columns.tolist() chart_type = st.selectbox("Chart Type", ["Histogram", "Bar Chart", "Scatter", "Box Plot", "Line"]) if chart_type == "Histogram" and num_cols: col = st.selectbox("Column", num_cols) fig = px.histogram(df, x=col, template="plotly_dark", color_discrete_sequence=["#6366f1"]) fig.update_layout(paper_bgcolor="rgba(0,0,0,0)", plot_bgcolor="rgba(15,18,35,0.6)") st.plotly_chart(fig, use_container_width=True) elif chart_type == "Bar Chart" and cat_cols and num_cols: xc = st.selectbox("X (categorical)", cat_cols) yc = st.selectbox("Y (numeric)", num_cols) fig = px.bar(df.groupby(xc)[yc].mean().reset_index(), x=xc, y=yc, template="plotly_dark", color=yc, color_continuous_scale="Viridis") fig.update_layout(paper_bgcolor="rgba(0,0,0,0)") st.plotly_chart(fig, use_container_width=True) elif chart_type == "Scatter" and len(num_cols) >= 2: xc = st.selectbox("X", num_cols, key="sc_x") yc = st.selectbox("Y", num_cols, index=1, key="sc_y") cc = st.selectbox("Color", ["None"] + cat_cols) fig = px.scatter(df, x=xc, y=yc, color=None if cc == "None" else cc, template="plotly_dark", opacity=0.7) fig.update_layout(paper_bgcolor="rgba(0,0,0,0)") st.plotly_chart(fig, use_container_width=True) elif chart_type == "Box Plot" and num_cols: yc = st.selectbox("Value", num_cols, key="bp_y") gc = st.selectbox("Group", ["None"] + cat_cols) fig = px.box(df, y=yc, x=None if gc == "None" else gc, template="plotly_dark", color_discrete_sequence=["#8b5cf6"]) fig.update_layout(paper_bgcolor="rgba(0,0,0,0)") st.plotly_chart(fig, use_container_width=True) elif chart_type == "Line" and num_cols: yc = st.selectbox("Column", num_cols, key="lc_y") fig = px.line(df.reset_index(), x="index", y=yc, template="plotly_dark", color_discrete_sequence=["#2dd4bf"]) fig.update_layout(paper_bgcolor="rgba(0,0,0,0)") st.plotly_chart(fig, use_container_width=True) with dtabs[3]: num_cols = df.select_dtypes(include=np.number).columns.tolist() cat_cols = df.select_dtypes(include="object").columns.tolist() if len(num_cols) >= 2: fig = create_correlation_heatmap(df) st.plotly_chart(fig, use_container_width=True) if cat_cols: tc = st.selectbox("Class column for distribution", cat_cols) fig2 = create_class_distribution(df[tc], f"{tc} Distribution") st.plotly_chart(fig2, use_container_width=True) else: st.info("Need at least 2 numeric columns for correlation.") # ────────────────────────────────────────────────────────────────────────────── # TAB 2 · ML PIPELINE # ────────────────────────────────────────────────────────────────────────────── with tab_ml: st.markdown('
🤖 Machine Learning Pipeline
', unsafe_allow_html=True) if st.session_state.df is None: st.markdown('
👆 Load a dataset in the 📊 Data tab first.
', unsafe_allow_html=True) else: df = st.session_state.df mc1, mc2, mc3 = st.columns(3) with mc1: target_col = st.selectbox("🎯 Target Column", df.columns.tolist()) st.session_state.target_column = target_col with mc2: from data.data_loader import DataLoader as _DL task_type = _DL().detect_task_type(df[target_col]) st.markdown(f"**Detected Task:** `{task_type}`") model_options = { "classification": ["Random Forest", "Gradient Boosting", "Logistic Regression", "SVM", "XGBoost", "LightGBM", "Ensemble"], "regression": ["Random Forest", "Gradient Boosting", "Ridge Regression", "Lasso Regression", "SVM", "XGBoost", "LightGBM", "Ensemble"], } model_name = st.selectbox("🧠 Algorithm", model_options[task_type]) with mc3: test_size = st.slider("Test Split %", 10, 40, 20) / 100 cv_folds = st.slider("CV Folds", 2, 10, 5) if st.button("🚀 Train Model", type="primary", use_container_width=True): with st.spinner("Training…"): try: if model_name == "XGBoost": pipe = XGBoostPipeline(task_type=task_type) elif model_name == "LightGBM" and LGB_OK and LightGBMPipeline is not None: pipe = LightGBMPipeline(task_type=task_type) elif model_name == "Ensemble": pipe = EnsemblePipeline(task_type=task_type) else: pipe = MLPipeline(task_type=task_type, model_name=model_name) result = pipe.preprocess(df, target_col=target_col) if result is None: st.error("❌ Preprocessing returned None. Check your target column.") st.stop() X, y = result if y is None: st.error("❌ Target column could not be extracted.") st.stop() metrics = pipe.train(X, y, test_size=test_size) st.session_state.ml_pipeline = pipe st.session_state.ml_metrics = metrics st.session_state.ml_results = { "model_name": model_name, "task_type": task_type, "feature_importance": pipe.get_feature_importance().to_dict("records") if hasattr(pipe, "get_feature_importance") else [], } st.success(f"✅ **{model_name}** trained successfully!") except Exception as e: st.error(f"❌ Training failed: {e}") if st.session_state.ml_metrics: metrics = st.session_state.ml_metrics st.markdown("---") st.markdown('
📊 Results
', unsafe_allow_html=True) num_m = {k: v for k, v in metrics.items() if isinstance(v, (int, float)) and not isinstance(v, bool)} cols_m = st.columns(min(len(num_m), 4)) for i, (k, v) in enumerate(list(num_m.items())[:4]): cols_m[i].metric(k.replace("_", " ").title(), f"{v:.4f}" if isinstance(v, float) else str(v)) fig_dash = create_metrics_dashboard(metrics) st.plotly_chart(fig_dash, use_container_width=True) pipe = st.session_state.ml_pipeline if pipe and pipe.is_fitted: result_tabs = st.tabs(["📉 Confusion Matrix / Scatter", "📈 Feature Importance", "📋 Report"]) with result_tabs[0]: task_type = st.session_state.ml_results["task_type"] if task_type == "classification" and pipe.y_pred is not None: labels = [str(c) for c in pipe.classes_] if pipe.classes_ is not None else None fig_cm = create_confusion_matrix( list(pipe.y_test), # type: ignore[arg-type] list(pipe.y_pred), # type: ignore[arg-type] labels, ) st.plotly_chart(fig_cm, use_container_width=True) elif task_type == "regression" and pipe.y_pred is not None: fig_avp = create_actual_vs_predicted( pipe.y_test, pipe.y_pred, f"{st.session_state.ml_results['model_name']} — Actual vs Predicted" ) st.plotly_chart(fig_avp, use_container_width=True) with result_tabs[1]: if hasattr(pipe, "get_feature_importance"): fi_df = pipe.get_feature_importance() if not fi_df.empty: fig_fi = create_feature_importance_chart(fi_df, top_n=20) st.plotly_chart(fig_fi, use_container_width=True) st.dataframe(fi_df.head(20), use_container_width=True) with result_tabs[2]: if "classification_report" in metrics: st.code(metrics["classification_report"], language="text") else: for k, v in num_m.items(): st.markdown(f"**{k.replace('_', ' ').title()}:** `{v:.4f}`") # ────────────────────────────────────────────────────────────────────────────── # TAB 3 · DEEP LEARNING # ────────────────────────────────────────────────────────────────────────────── with tab_dl: st.markdown('
🧠 Deep Learning & Computer Vision
', unsafe_allow_html=True) from models.dl_module import ( _classify_image_tf, _classify_image_torch, detect_edges_opencv, detect_faces_opencv, apply_image_filters, ) dl_uploaded = st.file_uploader("📷 Upload Image (JPG / PNG)", type=["jpg", "jpeg", "png"], key="dl_up") if dl_uploaded is None: st.markdown('
👆 Upload any image — try animals, faces, objects, or landscapes.
', unsafe_allow_html=True) else: pil_img = Image.open(dl_uploaded) c1, c2 = st.columns([2, 1]) with c1: st.image(pil_img, caption="Uploaded Image", use_column_width=True) with c2: w, h = pil_img.size arr_np = np.array(pil_img.convert("RGB")) for lbl, val in [ ("Resolution", f"{w}×{h}"), ("Mode", pil_img.mode), ("Brightness", f"{arr_np.mean():.1f}"), ("File size", f"{dl_uploaded.size / 1024:.1f} KB"), ]: st.markdown( f'
' f'
{val}
' f'
{lbl}
', unsafe_allow_html=True, ) st.markdown("---") dl_tabs = st.tabs(["🏷️ Classification", "🔥 Grad-CAM", "👁️ Detection", "🎨 Filters"]) with dl_tabs[0]: st.subheader("Image Classification — ImageNet 1K") backend = st.radio("Backend", ["TensorFlow/Keras", "PyTorch"], horizontal=True) if backend == "TensorFlow/Keras": model_choice = st.selectbox("Model", ["MobileNetV2", "ResNet50", "VGG16"]) else: model_choice = st.selectbox("Model", ["MobileNetV2", "ResNet50"]) if st.button("🔍 Classify Image", type="primary", key="cls_btn"): with st.spinner(f"Running {model_choice}…"): try: # Verify TF is importable before calling classify if backend == "TensorFlow/Keras": try: import tensorflow as _tf_check # type: ignore[import-untyped] except ImportError: raise ImportError("TensorFlow not installed. Run: pip install tensorflow") results = _classify_image_tf(pil_img, model_choice) else: results = _classify_image_torch(pil_img, model_choice) import plotly.graph_objects as go st.markdown( f'
🏆 {results[0]["Label"]} — {results[0]["Confidence"]}
', unsafe_allow_html=True, ) st.dataframe(pd.DataFrame(results), use_container_width=True) labels_list = [r["Label"][:28] for r in results] scores_list = [r["Score"] for r in results] colors_list = ["#a78bfa" if i == 0 else "#334155" for i in range(len(scores_list))] fig = go.Figure(go.Bar( x=scores_list[::-1], y=labels_list[::-1], orientation="h", marker=dict(color=colors_list[::-1]), text=[f"{s * 100:.1f}%" for s in scores_list[::-1]], textposition="outside", )) fig.update_layout(title="Top-5 Confidence Scores", template="plotly_dark", paper_bgcolor="rgba(0,0,0,0)", height=280) st.plotly_chart(fig, use_container_width=True) except Exception as e: st.error(f"Classification failed: {e}") st.info("Make sure TensorFlow or PyTorch is installed.") with dl_tabs[1]: st.subheader("Grad-CAM — Class Activation Heatmap") st.markdown("Highlights **which image regions** the model focused on for its prediction.") _tf_ok, _pt_ok = False, False try: import tensorflow; _tf_ok = True except ImportError: pass try: import torch; _pt_ok = True except ImportError: pass if not _tf_ok and not _pt_ok: st.markdown("""
⚠️ Grad-CAM requires TensorFlow or PyTorch.
Install: pip install tensorflow or pip install torch torchvision
""", unsafe_allow_html=True) else: backend_opts = (["TensorFlow/Keras"] if _tf_ok else []) + (["PyTorch"] if _pt_ok else []) gc_backend = st.radio("Backend", backend_opts, horizontal=True, key="gc_back") gc_model = st.selectbox( "Model", ["MobileNetV2", "ResNet50"] if gc_backend == "PyTorch" else ["MobileNetV2", "ResNet50", "VGG16"], key="gc_m", ) if st.button("🔥 Generate Grad-CAM", type="primary"): with st.spinner("Computing Grad-CAM…"): try: import cv2 as _cv import numpy as _np orig_224 = _np.array(pil_img.convert("RGB").resize((224, 224))) if gc_backend == "TensorFlow/Keras": # Robust TensorFlow import — handles tf2, tf-cpu, standalone keras try: import tensorflow as tf # type: ignore[import-untyped] except ImportError: st.error("❌ TensorFlow not installed. Run: pip install tensorflow") st.stop() try: from tensorflow.keras.preprocessing.image import img_to_array # type: ignore[import-untyped] except ImportError: try: from tensorflow.keras.utils import img_to_array # type: ignore[import-untyped] except ImportError: from keras.utils import img_to_array # type: ignore[import-untyped] try: from models.dl_module import _load_tf_model except ImportError: from dl_module import _load_tf_model # type: ignore[import] model, preprocess, decode, (ih, iw) = _load_tf_model(gc_model) arr = preprocess(_np.expand_dims(img_to_array( pil_img.convert("RGB").resize((iw, ih))), 0)) layer_name = None try: _conv2d_cls = tf.keras.layers.Conv2D # type: ignore[attr-defined] except AttributeError: import keras _conv2d_cls = keras.layers.Conv2D # type: ignore[attr-defined] for layer in reversed(model.layers): if isinstance(layer, _conv2d_cls): layer_name = layer.name break if not layer_name: st.warning("No Conv2D layer found in model.") st.stop() grad_model = tf.keras.models.Model( inputs=model.inputs, outputs=[model.get_layer(layer_name).output, model.output], ) with tf.GradientTape() as tape: conv_out, preds = grad_model(arr) top_cls = int(tf.argmax(preds[0]).numpy()) # type: ignore[union-attr] loss = preds[:, top_cls] # type: ignore[index] grads = tape.gradient(loss, conv_out) pooled = tf.reduce_mean(grads, axis=(0, 1, 2)) heatmap = conv_out[0] @ pooled[..., tf.newaxis] heatmap = tf.squeeze(heatmap).numpy() top_label = decode(model.predict(arr, verbose=0), top=1)[0][0][1].replace("_", " ").title() else: # PyTorch import torch import torchvision.models as M import torchvision.transforms as T import json, urllib.request pt_map = {"MobileNetV2": M.mobilenet_v2, "ResNet50": M.resnet50} pt_model = pt_map.get(gc_model, M.mobilenet_v2)(weights="DEFAULT") pt_model.eval() last_conv = None for name, m in pt_model.named_modules(): if isinstance(m, torch.nn.Conv2d): last_conv = (name, m) if last_conv is None: st.warning("No Conv2d layer found.") st.stop() activations, gradients = [], [] def _fwd_hook(mod, inp, out): activations.clear(); activations.append(out.detach()) def _bwd_hook(mod, grad_in, grad_out): gradients.clear(); gradients.append(grad_out[0].detach()) h1 = last_conv[1].register_forward_hook(_fwd_hook) h2 = last_conv[1].register_full_backward_hook(_bwd_hook) _transform = T.Compose([ T.Resize(256), T.CenterCrop(224), T.ToTensor(), T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) _tf_raw = _transform(pil_img.convert("RGB")) tf_img = _tf_raw.unsqueeze(0) # torch Tensor — ignore PIL Image complaint # type: ignore[union-attr] tf_img.requires_grad_(True) output = pt_model(tf_img) top_cls_pt = output.argmax(dim=1).item() pt_model.zero_grad() output[0, top_cls_pt].backward() h1.remove(); h2.remove() act = activations[0].squeeze() grad = gradients[0].squeeze() weights = grad.mean(dim=(1, 2)) heatmap = (weights[:, None, None] * act).sum(dim=0).numpy() heatmap = _np.maximum(heatmap, 0) try: url = "https://raw.githubusercontent.com/anishathalye/imagenet-simple-labels/master/imagenet-simple-labels.json" with urllib.request.urlopen(url, timeout=5) as r: class_labels = json.load(r) top_label = class_labels[top_cls_pt].replace("_", " ").title() except Exception: top_label = f"Class {top_cls_pt}" # ── Render heatmap ── heatmap = heatmap / (heatmap.max() + 1e-8) h_res = _cv.resize(heatmap, (224, 224)) _h_uint8 = _np.array(255 * h_res, dtype=_np.uint8) h_col = _cv.cvtColor( _cv.applyColorMap(_h_uint8, _cv.COLORMAP_JET), # type: ignore[call-overload] _cv.COLOR_BGR2RGB, ) overlay = _np.array(orig_224 * 0.6 + h_col * 0.4, dtype=_np.uint8) gc1, gc2, gc3 = st.columns(3) gc1.image(orig_224, caption="Original", use_column_width=True) gc2.image(h_col, caption="Heatmap", use_column_width=True) gc3.image(overlay, caption="Overlay", use_column_width=True) st.markdown( f'
🏆 Top prediction: {top_label} ' f'— red/yellow regions = highest model attention
', unsafe_allow_html=True, ) except Exception as e: st.error(f"Grad-CAM failed: {e}") with dl_tabs[2]: st.subheader("OpenCV Detection") cv_task = st.selectbox("Task", ["Face Detection", "Edge Detection"]) t1 = t2 = None if cv_task == "Edge Detection": t1 = st.slider("Threshold 1", 10, 200, 50) t2 = st.slider("Threshold 2", 50, 400, 150) if st.button("▶ Run Detection", type="primary", key="det_btn"): with st.spinner("Running OpenCV…"): if cv_task == "Edge Detection": import cv2 as _cv _t1: float = float(t1) if t1 is not None else 50.0 _t2: float = float(t2) if t2 is not None else 150.0 gray = _cv.cvtColor(np.array(pil_img.convert("RGB")), _cv.COLOR_RGB2GRAY) edges = _cv.Canny(_cv.GaussianBlur(gray, (5, 5), 0), _t1, _t2) dc1, dc2 = st.columns(2) dc1.image(pil_img, caption="Original", use_column_width=True) dc2.image(edges, caption="Edges", use_column_width=True, clamp=True) st.info(f"Edge pixels: **{np.sum(edges > 0):,}**") else: result_img, face_count = detect_faces_opencv(pil_img) dc1, dc2 = st.columns(2) dc1.image(pil_img, caption="Original", use_column_width=True) dc2.image(result_img, caption="Detections", use_column_width=True) if face_count > 0: st.markdown(f'
✅ Detected {face_count} face(s).
', unsafe_allow_html=True) else: st.warning("No faces detected. Try a clear frontal portrait.") with dl_tabs[3]: st.subheader("Image Filters Gallery") if st.button("🎨 Apply All Filters", type="primary", key="flt_btn"): with st.spinner("Applying filters…"): filters = apply_image_filters(pil_img) cols_f = st.columns(3) for i, (name, img) in enumerate(filters.items()): with cols_f[i % 3]: st.image(img, caption=name, use_column_width=True, clamp=True) # ────────────────────────────────────────────────────────────────────────────── # TAB 4 · NLP # ────────────────────────────────────────────────────────────────────────────── with tab_nlp: st.markdown('
📝 NLP Suite
', unsafe_allow_html=True) try: from models.nlp_module import ( # type: ignore[import] run_sentiment, run_ner, run_text_classification, run_summarization, chat_with_model, ) except ImportError: from nlp_module import ( # type: ignore[import] run_sentiment, run_ner, run_text_classification, run_summarization, chat_with_model, ) nlp_tabs = st.tabs(["😊 Sentiment", "🏷️ NER", "📂 Classification", "📰 Summarization", "💬 Chatbot"]) # ── Sentiment ── with nlp_tabs[0]: st.subheader("Sentiment Analysis — DistilBERT") mode = st.radio("Mode", ["Single", "Batch"], horizontal=True) if mode == "Single": txt = st.text_area("Text to analyze:", height=110, placeholder="The product quality is amazing and delivery was super fast!") if st.button("🔍 Analyze", type="primary", key="sa_btn"): if not txt.strip(): st.warning("Enter some text.") else: with st.spinner("Loading DistilBERT and analyzing…"): r = run_sentiment([txt]) if r: color = "#22c55e" if r[0]["Sentiment"] == "POSITIVE" else "#ef4444" icon = "😊" if r[0]["Sentiment"] == "POSITIVE" else "😞" st.markdown(f"""
{icon}
{r[0]["Sentiment"]}
Confidence: {r[0]["Confidence"]}
""", unsafe_allow_html=True) else: batch = st.text_area("One sentence per line:", height=180, placeholder="Great product!\nTerrible experience.\nIt was okay.") if st.button("🔍 Analyze All", type="primary", key="sa_batch"): lines = [ln.strip() for ln in batch.split("\n") if ln.strip()] if lines: with st.spinner("Analyzing…"): results = run_sentiment(lines) df_s = pd.DataFrame(results) st.dataframe(df_s, use_container_width=True) import plotly.express as px pos = sum(1 for r in results if r["Sentiment"] == "POSITIVE") fig = px.pie( values=[pos, len(results) - pos], names=["Positive", "Negative"], color_discrete_sequence=["#22c55e", "#ef4444"], hole=0.4, template="plotly_dark", ) fig.update_layout(paper_bgcolor="rgba(0,0,0,0)") st.plotly_chart(fig, use_container_width=True) # ── NER ── with nlp_tabs[1]: st.subheader("Named Entity Recognition") ner_txt = st.text_area("Text for NER:", height=130, value="Apple Inc. was founded by Steve Jobs in Cupertino, California in 1976.") if st.button("🏷️ Extract Entities", type="primary", key="ner_btn"): with st.spinner("Running NER…"): ents = run_ner(ner_txt) if ents: df_ner = pd.DataFrame(ents) st.dataframe(df_ner, use_container_width=True) import plotly.express as px vc = df_ner["Type"].value_counts().reset_index() vc.columns = ["Type", "count"] fig = px.bar(vc, x="Type", y="count", template="plotly_dark", color="Type", color_discrete_sequence=["#a78bfa", "#60a5fa", "#34d399", "#f472b6"]) fig.update_layout(paper_bgcolor="rgba(0,0,0,0)", showlegend=False) st.plotly_chart(fig, use_container_width=True) type_icons = {"PER": "🧑", "ORG": "🏢", "LOC": "📍", "MISC": "🔖", "GPE": "🌍"} for _, row in df_ner.iterrows(): st.markdown(f"- **{row['Entity']}** → {type_icons.get(row['Type'], '')} `{row['Type']}` ({row['Score']})") else: st.info("No entities found.") # ── Zero-Shot Classification ── with nlp_tabs[2]: st.subheader("Zero-Shot Text Classification") cl_txt = st.text_area("Text to classify:", height=110, value="The new iPhone features an upgraded camera and faster processor.") cl_labels = st.text_input("Candidate labels (comma-separated):", value="technology, sports, politics, business, health, entertainment") if st.button("📂 Classify", type="primary", key="zs_btn"): lbls = [lb.strip() for lb in cl_labels.split(",") if lb.strip()] if cl_txt.strip() and lbls: with st.spinner("Running zero-shot classification…"): results = run_text_classification(cl_txt, lbls) st.markdown( f'
🏆 Best: {results[0]["Label"]} ({results[0]["Confidence"]})
', unsafe_allow_html=True, ) import plotly.express as px df_zs = pd.DataFrame(results) fig = px.bar(df_zs, x="Label", y="Score", template="plotly_dark", color="Score", color_continuous_scale="Purples") fig.update_layout(paper_bgcolor="rgba(0,0,0,0)") st.plotly_chart(fig, use_container_width=True) # ── Summarization ── with nlp_tabs[3]: st.subheader("Text Summarization — DistilBART") long_txt = st.text_area("Long text to summarize:", height=220, value=( "Artificial intelligence (AI) is intelligence demonstrated by machines, as opposed to " "the natural intelligence displayed by animals including humans. AI research has been defined " "as the field of study of intelligent agents, which refers to any system that perceives its " "environment and takes actions that maximize its chance of achieving its goals. AI applications " "include advanced web search engines, recommendation systems, understanding human speech, " "self-driving cars, generative or creative tools, automated decision-making, and competing " "at the highest level in strategic game systems." )) if st.button("📰 Summarize", type="primary", key="sum_btn"): if len(long_txt.split()) < 30: st.warning("Need at least 30 words.") else: with st.spinner("Loading DistilBART and summarizing…"): summary = run_summarization(long_txt) st.markdown(f'
{summary}
', unsafe_allow_html=True) sc1, sc2 = st.columns(2) sc1.metric("Original Words", len(long_txt.split())) sc2.metric("Summary Words", len(summary.split())) # ── Chatbot ── with nlp_tabs[4]: st.subheader("💬 AI Chatbot") if "chat_pairs" not in st.session_state: st.session_state.chat_pairs = [] with st.expander("⚙️ Settings"): sys_hint = st.text_input("System hint:", value="You are a helpful AI assistant. Be concise.") if st.button("🗑️ Clear Chat"): st.session_state.chat_pairs = [] st.rerun() for um, bm in st.session_state.chat_pairs: with st.chat_message("user"): st.markdown(um) with st.chat_message("assistant"): st.markdown(bm) user_input = st.chat_input("Ask anything…") if user_input: with st.chat_message("user"): st.markdown(user_input) with st.chat_message("assistant"): with st.spinner("Thinking…"): try: prompt = f"{sys_hint}\n\n{user_input}" if sys_hint else user_input resp = chat_with_model(prompt, st.session_state.chat_pairs) except Exception as e: resp = f"⚠️ {e}" st.markdown(resp) st.session_state.chat_pairs.append((user_input, resp)) if not st.session_state.chat_pairs: examples = [ "What is machine learning?", "Explain neural networks simply.", "Top 3 AI programming languages?", "Benefits of deep learning?", ] ecols = st.columns(2) for i, ex in enumerate(examples): with ecols[i % 2]: if st.button(ex, key=f"ex_{i}", use_container_width=True): with st.spinner("Thinking…"): try: resp = chat_with_model(ex, []) except Exception as e: resp = f"⚠️ {e}" st.session_state.chat_pairs.append((ex, resp)) st.rerun() # ────────────────────────────────────────────────────────────────────────────── # TAB 5 · GENERATIVE AI # ────────────────────────────────────────────────────────────────────────────── with tab_genai: st.markdown('
💡 Generative AI Suite
', unsafe_allow_html=True) gen_ai = st.session_state.gen_ai # ── Status banner ── if gen_ai._provider == "smart": st.markdown("""
Smart AI active — instant built-in responses, zero downloads, no API key needed.
Knows: ML algorithms, deep learning, NLP, Python, data science, and more. For open-ended GPT-4 quality responses, add an API key in the sidebar.
""", unsafe_allow_html=True) elif gen_ai.is_available(): st.markdown(f'
{gen_ai._provider_config["name"]} connected and ready.
', unsafe_allow_html=True) elif not gen_ai.pkg_installed(): st.markdown(f"""
⚠️ {gen_ai._provider_config["name"]} package not installed.
Run: {gen_ai.install_cmd()} — then restart Streamlit.
""", unsafe_allow_html=True) else: pkg_status = { "🟢 OpenAI": "✅ installed" if OPENAI_OK else "❌ pip install openai", "🔵 Google": "✅ installed" if GOOGLE_OK else "❌ pip install google-generativeai", "🟣 Anthropic": "✅ installed" if ANTHROPIC_OK else "❌ pip install anthropic", } rows = "
".join(f"  {k}: {v}" for k, v in pkg_status.items()) st.markdown(f"""
⚠️ No API key entered — using Smart AI mode.
To enable full LLM responses, install a package and add your key:

{rows}
""", unsafe_allow_html=True) gen_tabs = st.tabs(["💬 Chatbot", "❓ Data Q&A", "💻 Code Gen", "🎨 Image Gen", "📄 Report"]) # ── Chatbot ── with gen_tabs[0]: st.subheader("Context-Aware Chatbot") if "gen_chat" not in st.session_state: st.session_state.gen_chat = [] st.session_state.gen_history = [] for role, msg in st.session_state.gen_chat: with st.chat_message(role): st.markdown(msg) user_q = st.chat_input("Chat with AI…", key="gen_chat_input") if user_q: st.session_state.gen_chat.append(("user", user_q)) st.session_state.gen_history.append({"role": "user", "content": user_q}) with st.chat_message("user"): st.markdown(user_q) with st.chat_message("assistant"): with st.spinner("Generating…"): try: resp = gen_ai.chat(st.session_state.gen_history) except Exception as e: resp = f"⚠️ {e}" st.markdown(resp) st.session_state.gen_chat.append(("assistant", resp)) st.session_state.gen_history.append({"role": "assistant", "content": resp}) if st.button("🗑️ Clear Conversation", key="clr_gen"): st.session_state.gen_chat = [] st.session_state.gen_history = [] st.rerun() # ── Data Q&A ── with gen_tabs[1]: st.subheader("Prompt-Based Data Q&A") st.markdown("Ask questions about your loaded dataset and get AI-generated insights.") gen_option = st.selectbox("Analysis Type", [ "General Insights", "Trends Analysis", "Anomaly Detection", "Recommendations", "Custom Question", ]) analysis_map = { "General Insights": "general", "Trends Analysis": "trends_analysis", "Anomaly Detection": "anomaly_detection", "Recommendations": "recommendations", } if gen_option != "Custom Question": if st.button("✨ Generate Insights", type="primary", key="gen_ins"): if st.session_state.data_summary: with st.spinner("Generating…"): insights = gen_ai.generate_insights( st.session_state.data_summary, analysis_map[gen_option] ) st.markdown(f'
{insights}
', unsafe_allow_html=True) else: st.warning("Load data in the 📊 Data tab first.") else: question = st.text_input("Your question:", placeholder="What features are most correlated with the target?") if st.button("🔍 Ask", type="primary", key="gen_qa") and question: ctx = json.dumps(st.session_state.data_summary, default=str) if st.session_state.data_summary else None with st.spinner("Thinking…"): answer = gen_ai.answer_question(question, ctx) st.markdown(f'
{answer}
', unsafe_allow_html=True) # ── Code Generation ── with gen_tabs[2]: st.subheader("💻 Code Generation") code_lang = st.selectbox("Language", ["Python", "JavaScript", "SQL", "Bash", "R", "TypeScript"]) code_prompt = st.text_area( "Describe what you want to code:", height=110, placeholder="Write a Python function to clean a pandas dataframe by removing duplicates and filling nulls with median values.", ) if st.button("⚡ Generate Code", type="primary", key="code_gen"): if code_prompt.strip(): with st.spinner("Generating code…"): code_result = gen_ai.generate_code(code_prompt, language=code_lang) st.code(code_result, language=code_lang.lower()) st.download_button( "⬇️ Download", code_result.encode(), file_name=f"generated.{code_lang.lower()[:2]}", mime="text/plain", ) else: st.warning("Enter a code description.") # ── Image Generation ── with gen_tabs[3]: st.subheader("🎨 Image Generation from Text") img_prompt = st.text_area( "Image description:", height=100, placeholder="A futuristic city at night with neon lights and flying cars, digital art style", ) img_style = st.selectbox("Style", ["Photorealistic", "Digital Art", "Oil Painting", "Anime", "Sketch", "Cyberpunk"]) img_size = st.selectbox("Size", ["1024x1024", "512x512", "1792x1024"]) if st.button("🎨 Generate Image", type="primary", key="img_gen"): if img_prompt.strip(): full_prompt = f"{img_prompt}, {img_style} style" with st.spinner("Generating image…"): result = gen_ai.generate_image(full_prompt, size=img_size) if result.get("url"): st.image(result["url"], caption=f"Generated: {img_prompt[:60]}…", use_column_width=True) st.markdown(f"[🔗 Open full size]({result['url']})") elif result.get("error"): st.markdown(f'
⚠️ {result["error"]}
', unsafe_allow_html=True) else: st.warning("Enter an image description.") # ── Report ── with gen_tabs[4]: st.subheader("📄 Auto-Generated Analysis Report") if st.button("📝 Generate Report", type="primary", key="gen_rep"): payload = { "ml_metrics": st.session_state.ml_metrics or {}, "data_summary": st.session_state.data_summary or {}, "model": st.session_state.ml_results.get("model_name", "N/A") if st.session_state.ml_results else "N/A", } with st.spinner("Writing report…"): report = gen_ai.generate_report(payload) st.text_area("Report", report, height=420) st.download_button("⬇️ Download Report", report.encode(), file_name="ai_report.txt", mime="text/plain") # ────────────────────────────────────────────────────────────────────────────── # TAB 6 · POWER BI # ────────────────────────────────────────────────────────────────────────────── with tab_pbi: st.markdown('
📤 Power BI Export
', unsafe_allow_html=True) exporter = st.session_state.powerbi_exp if st.session_state.df is None: st.markdown('
👆 Load data in the 📊 Data tab first.
', unsafe_allow_html=True) else: df = st.session_state.df ec1, ec2 = st.columns(2) with ec1: include_parquet = st.checkbox("Include Parquet files", value=True) export_name = st.text_input("Dataset name", value="main_data") with ec2: st.markdown("**Available datasets:**") available = {"Main Data": df} if st.session_state.ml_results and st.session_state.ml_results.get("feature_importance"): available["Feature Importance"] = pd.DataFrame(st.session_state.ml_results["feature_importance"]) for name in available: st.markdown(f"• {name}") if st.button("📊 Export All for Power BI", type="primary", use_container_width=True): with st.spinner("Exporting…"): try: named = {export_name: df} if "Feature Importance" in available: named["feature_importance"] = available["Feature Importance"] paths = exporter.export_all(named, include_parquet=include_parquet) st.success(f"✅ Exported **{len(paths)}** files to `{OUTPUT_DIR}`") for p in paths: st.markdown(f" • `{p.name}`") except Exception as e: st.error(f"❌ {e}") st.divider() st.info(exporter.generate_powerbi_instructions()) dl1, dl2 = st.columns(2) with dl1: st.download_button("⬇️ Download CSV", df.to_csv(index=False).encode(), file_name=f"{export_name}.csv", mime="text/csv", use_container_width=True) with dl2: if st.session_state.ml_results and st.session_state.ml_results.get("feature_importance"): fi_df = pd.DataFrame(st.session_state.ml_results["feature_importance"]) st.download_button("⬇️ Feature Importance CSV", fi_df.to_csv(index=False).encode(), file_name="feature_importance.csv", mime="text/csv", use_container_width=True) # ── Footer ──────────────────────────────────────────────────────────────────── st.markdown(""" """, unsafe_allow_html=True)