Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,27 +1,23 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
import pandas as pd
|
|
|
|
| 3 |
from pycaret.classification import setup as classification_setup, compare_models as compare_classification_models, evaluate_model as evaluate_classification_model, save_model as save_classification_model, plot_model as plot_classification_model, tune_model as tune_classification_model, get_config
|
| 4 |
from pycaret.regression import setup as regression_setup, compare_models as compare_regression_models, evaluate_model as evaluate_regression_model, save_model as save_regression_model, plot_model as plot_regression_model, tune_model as tune_regression_model, get_config
|
| 5 |
from pycaret.clustering import setup as clustering_setup, evaluate_model as evaluate_clustering_model, save_model as save_clustering_model, plot_model as plot_clustering_model, create_model as create_clustering_model, get_config
|
| 6 |
from ydata_profiling import ProfileReport
|
| 7 |
from streamlit_pandas_profiling import st_profile_report
|
| 8 |
import os
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
# Set page config
|
| 11 |
st.set_page_config(page_title="Neural-Vision Enhanced", layout="wide")
|
| 12 |
|
| 13 |
-
#
|
| 14 |
-
|
| 15 |
-
st.
|
| 16 |
-
st.markdown("Your AI-powered model toolbox.")
|
| 17 |
-
st.markdown("---")
|
| 18 |
-
app_mode = st.selectbox("Navigation", ["Data Upload", "Model Training", "Validation & Exploration"])
|
| 19 |
-
data_type = st.selectbox("Data Type", ["Tabular"])
|
| 20 |
-
st.markdown("---")
|
| 21 |
-
st.markdown("**Dependencies**: `pycaret`, `pandas`, `streamlit`, `ydata-profiling`")
|
| 22 |
-
st.markdown("Created by Calvin Allen-Crawford | v2.0 | © 2025")
|
| 23 |
|
| 24 |
-
# Helper function to get available models
|
| 25 |
def get_available_models(problem_type):
|
| 26 |
if problem_type == "Classification":
|
| 27 |
return list(get_config('available_estimators')['classification'].keys())
|
|
@@ -31,6 +27,194 @@ def get_available_models(problem_type):
|
|
| 31 |
return list(get_config('available_estimators')['clustering'].keys())
|
| 32 |
return []
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
# Main App Sections
|
| 35 |
if app_mode == "Data Upload":
|
| 36 |
st.title("📤 Data Upload")
|
|
@@ -38,22 +222,24 @@ if app_mode == "Data Upload":
|
|
| 38 |
if uploaded_file:
|
| 39 |
df = pd.read_csv(uploaded_file)
|
| 40 |
st.session_state['df'] = df
|
| 41 |
-
st.
|
| 42 |
-
st.
|
| 43 |
-
st.
|
|
|
|
| 44 |
st.write("---")
|
| 45 |
st.subheader("Statistics")
|
| 46 |
col1, col2, col3 = st.columns(3)
|
| 47 |
with col1: st.metric("Rows", df.shape[0])
|
| 48 |
with col2: st.metric("Columns", df.shape[1])
|
| 49 |
with col3: st.metric("Missing Values", df.isna().sum().sum())
|
| 50 |
-
|
| 51 |
st.write("---")
|
| 52 |
st.subheader("Exploratory Data Analysis (EDA)")
|
| 53 |
if st.button("Generate EDA Report"):
|
| 54 |
with st.spinner("Generating EDA Report..."):
|
| 55 |
profile = ProfileReport(df, explorative=True)
|
| 56 |
st_profile_report(profile)
|
|
|
|
|
|
|
| 57 |
|
| 58 |
elif app_mode == "Model Training":
|
| 59 |
st.title("🧠 Model Training")
|
|
@@ -70,10 +256,12 @@ elif app_mode == "Model Training":
|
|
| 70 |
if problem_type == "Classification":
|
| 71 |
classification_setup(data=df, target=target, session_id=123, verbose=False)
|
| 72 |
st.session_state['problem_type'] = "Classification"
|
|
|
|
| 73 |
st.session_state['setup_complete'] = True
|
| 74 |
elif problem_type == "Regression":
|
| 75 |
regression_setup(data=df, target=target, session_id=123, verbose=False)
|
| 76 |
st.session_state['problem_type'] = "Regression"
|
|
|
|
| 77 |
st.session_state['setup_complete'] = True
|
| 78 |
elif problem_type == "Clustering":
|
| 79 |
clustering_setup(data=df, session_id=123, verbose=False)
|
|
@@ -103,18 +291,21 @@ elif app_mode == "Model Training":
|
|
| 103 |
elif selected_model == "hclust":
|
| 104 |
num_clusters = st.number_input("Number of Clusters", min_value=2, max_value=20, value=4, step=1)
|
| 105 |
|
|
|
|
|
|
|
|
|
|
| 106 |
if problem_type in ["Classification", "Regression"]:
|
| 107 |
if st.button("Compare Models"):
|
| 108 |
with st.spinner("Comparing models..."):
|
| 109 |
if selected_models:
|
| 110 |
if problem_type == "Classification":
|
| 111 |
best_model = compare_classification_models(include=selected_models, fold=folds, sort=sort_metric)
|
| 112 |
-
else:
|
| 113 |
best_model = compare_regression_models(include=selected_models, fold=folds, sort=sort_metric)
|
| 114 |
else:
|
| 115 |
if problem_type == "Classification":
|
| 116 |
best_model = compare_classification_models(fold=folds, sort=sort_metric)
|
| 117 |
-
else:
|
| 118 |
best_model = compare_regression_models(fold=folds, sort=sort_metric)
|
| 119 |
st.session_state['best_model'] = best_model
|
| 120 |
st.success(f"Best Model: {best_model}")
|
|
@@ -152,7 +343,7 @@ elif app_mode == "Model Training":
|
|
| 152 |
with st.spinner("Tuning model..."):
|
| 153 |
if problem_type == "Classification":
|
| 154 |
tuned_model = tune_classification_model(st.session_state['best_model'], fold=folds, optimize=sort_metric)
|
| 155 |
-
else:
|
| 156 |
tuned_model = tune_regression_model(st.session_state['best_model'], fold=folds, optimize=sort_metric)
|
| 157 |
st.session_state['best_model'] = tuned_model
|
| 158 |
st.success(f"Tuned Model: {tuned_model}")
|
|
@@ -187,6 +378,32 @@ elif app_mode == "Validation & Exploration":
|
|
| 187 |
st.write("Clustering Results:")
|
| 188 |
plot_clustering_model(st.session_state['best_model'], plot="cluster", display_format="streamlit")
|
| 189 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
# Custom CSS
|
| 191 |
st.markdown("""
|
| 192 |
<style>
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import pandas as pd
|
| 3 |
+
import plotly.express as px
|
| 4 |
from pycaret.classification import setup as classification_setup, compare_models as compare_classification_models, evaluate_model as evaluate_classification_model, save_model as save_classification_model, plot_model as plot_classification_model, tune_model as tune_classification_model, get_config
|
| 5 |
from pycaret.regression import setup as regression_setup, compare_models as compare_regression_models, evaluate_model as evaluate_regression_model, save_model as save_regression_model, plot_model as plot_regression_model, tune_model as tune_regression_model, get_config
|
| 6 |
from pycaret.clustering import setup as clustering_setup, evaluate_model as evaluate_clustering_model, save_model as save_clustering_model, plot_model as plot_clustering_model, create_model as create_clustering_model, get_config
|
| 7 |
from ydata_profiling import ProfileReport
|
| 8 |
from streamlit_pandas_profiling import st_profile_report
|
| 9 |
import os
|
| 10 |
+
import requests
|
| 11 |
+
import json
|
| 12 |
+
import re
|
| 13 |
|
| 14 |
# Set page config
|
| 15 |
st.set_page_config(page_title="Neural-Vision Enhanced", layout="wide")
|
| 16 |
|
| 17 |
+
# Helper Functions
|
| 18 |
+
def enhance_section_title(title):
|
| 19 |
+
st.markdown(f"<h2 style='border-bottom: 2px solid #ccc; padding-bottom: 5px;'>{title}</h2>", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
|
|
|
| 21 |
def get_available_models(problem_type):
|
| 22 |
if problem_type == "Classification":
|
| 23 |
return list(get_config('available_estimators')['classification'].keys())
|
|
|
|
| 27 |
return list(get_config('available_estimators')['clustering'].keys())
|
| 28 |
return []
|
| 29 |
|
| 30 |
+
def get_context():
|
| 31 |
+
context = "You are using Neural-Vision Enhanced, an AI-powered data analysis and modeling tool.\n"
|
| 32 |
+
if 'df' in st.session_state:
|
| 33 |
+
df = st.session_state['df']
|
| 34 |
+
context += f"Current dataset has {df.shape[0]} rows and {df.shape[1]} columns.\n"
|
| 35 |
+
context += f"Missing values: {df.isna().sum().sum()}\n"
|
| 36 |
+
context += "Columns:\n"
|
| 37 |
+
for col in df.columns:
|
| 38 |
+
context += f"- {col} ({df[col].dtype}): Missing={df[col].isna().sum()}\n"
|
| 39 |
+
if 'problem_type' in st.session_state:
|
| 40 |
+
context += f"Selected problem type: {st.session_state['problem_type']}\n"
|
| 41 |
+
if 'target' in st.session_state and st.session_state['problem_type'] != "Clustering":
|
| 42 |
+
context += f"Target column: {st.session_state['target']}\n"
|
| 43 |
+
if 'best_model' in st.session_state:
|
| 44 |
+
context += f"Best model trained: {st.session_state['best_model']}\n"
|
| 45 |
+
return context
|
| 46 |
+
|
| 47 |
+
def deepseek_chat(user_input, app_mode):
|
| 48 |
+
system_prompt = (
|
| 49 |
+
"You are an AI assistant in Neural-Vision Enhanced, a data analysis and modeling app. "
|
| 50 |
+
"The app has three pages:\n"
|
| 51 |
+
"- **Data Upload**: Upload CSV files, view stats, or generate EDA reports.\n"
|
| 52 |
+
"- **Model Training**: Train classification, regression, or clustering models using PyCaret.\n"
|
| 53 |
+
"- **Validation & Exploration**: Evaluate and visualize trained models.\n"
|
| 54 |
+
f"The user is on the '{app_mode}' page.\n"
|
| 55 |
+
f"Current context:\n{get_context()}"
|
| 56 |
+
)
|
| 57 |
+
payload = {
|
| 58 |
+
"model": "deepseek-chat",
|
| 59 |
+
"messages": [
|
| 60 |
+
{"role": "system", "content": system_prompt},
|
| 61 |
+
{"role": "user", "content": user_input}
|
| 62 |
+
],
|
| 63 |
+
"max_tokens": 150,
|
| 64 |
+
"temperature": 0.7
|
| 65 |
+
}
|
| 66 |
+
headers = {"Authorization": f"Bearer {api_key}"}
|
| 67 |
+
try:
|
| 68 |
+
response = requests.post("https://api.deepseek.com/v1/chat/completions", json=payload, headers=headers, timeout=5)
|
| 69 |
+
response.raise_for_status()
|
| 70 |
+
return response.json()["choices"][0]["message"]["content"]
|
| 71 |
+
except requests.exceptions.RequestException as e:
|
| 72 |
+
return f"Error: Could not connect to DeepSeek API. {str(e)}"
|
| 73 |
+
|
| 74 |
+
# LLM Command Functions
|
| 75 |
+
def drop_columns(columns):
|
| 76 |
+
if 'df' in st.session_state:
|
| 77 |
+
df = st.session_state['df'].copy()
|
| 78 |
+
columns_to_drop = [col.strip() for col in columns.split(',')]
|
| 79 |
+
valid_columns = [col for col in columns_to_drop if col in df.columns]
|
| 80 |
+
if valid_columns:
|
| 81 |
+
df.drop(valid_columns, axis=1, inplace=True)
|
| 82 |
+
st.session_state['df'] = df
|
| 83 |
+
st.rerun()
|
| 84 |
+
return f"Dropped columns: {', '.join(valid_columns)}"
|
| 85 |
+
else:
|
| 86 |
+
return "No valid columns found to drop."
|
| 87 |
+
return "No dataset loaded."
|
| 88 |
+
|
| 89 |
+
def generate_scatter_plot(params):
|
| 90 |
+
if 'df' in st.session_state:
|
| 91 |
+
df = st.session_state['df']
|
| 92 |
+
match = re.search(r"([\w\s]+)\s+vs\s+([\w\s]+)", params)
|
| 93 |
+
if match and len(match.groups()) >= 2:
|
| 94 |
+
x_axis, y_axis = match.group(1).strip(), match.group(2).strip()
|
| 95 |
+
if x_axis in df.columns and y_axis in df.columns:
|
| 96 |
+
fig = px.scatter(df, x=x_axis, y=y_axis, title=f'Scatter Plot of {x_axis} vs {y_axis}')
|
| 97 |
+
st.plotly_chart(fig)
|
| 98 |
+
st.session_state.last_plot = {"type": "Scatter Plot", "x": x_axis, "y": y_axis, "data": df[[x_axis, y_axis]].to_json()}
|
| 99 |
+
return f"Generated scatter plot of {x_axis} vs {y_axis}"
|
| 100 |
+
return "Invalid columns or no dataset loaded."
|
| 101 |
+
|
| 102 |
+
def generate_histogram(params):
|
| 103 |
+
if 'df' in st.session_state:
|
| 104 |
+
df = st.session_state['df']
|
| 105 |
+
x_axis = params.strip()
|
| 106 |
+
if x_axis in df.columns:
|
| 107 |
+
fig = px.histogram(df, x=x_axis, title=f'Histogram of {x_axis}')
|
| 108 |
+
st.plotly_chart(fig)
|
| 109 |
+
st.session_state.last_plot = {"type": "Histogram", "x": x_axis, "data": df[[x_axis]].to_json()}
|
| 110 |
+
return f"Generated histogram of {x_axis}"
|
| 111 |
+
return "Invalid column or no dataset loaded."
|
| 112 |
+
|
| 113 |
+
def analyze_plot():
|
| 114 |
+
if "last_plot" not in st.session_state:
|
| 115 |
+
return "No plot available to analyze."
|
| 116 |
+
plot_info = st.session_state.last_plot
|
| 117 |
+
df = pd.read_json(plot_info["data"])
|
| 118 |
+
plot_type = plot_info["type"]
|
| 119 |
+
x_col = plot_info["x"]
|
| 120 |
+
y_col = plot_info["y"] if "y" in plot_info else None
|
| 121 |
+
|
| 122 |
+
if plot_type == "Scatter Plot" and y_col:
|
| 123 |
+
correlation = df[x_col].corr(df[y_col])
|
| 124 |
+
strength = "strong" if abs(correlation) > 0.7 else "moderate" if abs(correlation) > 0.3 else "weak"
|
| 125 |
+
direction = "positive" if correlation > 0 else "negative"
|
| 126 |
+
return f"The scatter plot of {x_col} vs {y_col} shows a {strength} {direction} correlation (Pearson r = {correlation:.2f})."
|
| 127 |
+
elif plot_type == "Histogram":
|
| 128 |
+
skewness = df[x_col].skew()
|
| 129 |
+
skew_desc = "positively skewed" if skewness > 1 else "negatively skewed" if skewness < -1 else "approximately symmetric"
|
| 130 |
+
return f"The histogram of {x_col} is {skew_desc} (skewness = {skewness:.2f})."
|
| 131 |
+
return "Inference not available for this plot type."
|
| 132 |
+
|
| 133 |
+
def suggest_preprocessing():
|
| 134 |
+
if 'df' in st.session_state:
|
| 135 |
+
df = st.session_state['df']
|
| 136 |
+
missing = df.isna().sum().sum()
|
| 137 |
+
if missing > 0:
|
| 138 |
+
return f"Your dataset has {missing} missing values. Consider imputation or dropping rows/columns with missing data before training."
|
| 139 |
+
if df.duplicated().sum() > 0:
|
| 140 |
+
return f"Your dataset has {df.duplicated().sum()} duplicates. Consider removing them for better model performance."
|
| 141 |
+
return "Your dataset looks clean. Proceed to model training."
|
| 142 |
+
return "No dataset loaded yet."
|
| 143 |
+
|
| 144 |
+
def suggest_model():
|
| 145 |
+
if 'df' in st.session_state and 'problem_type' in st.session_state:
|
| 146 |
+
df = st.session_state['df']
|
| 147 |
+
problem_type = st.session_state['problem_type']
|
| 148 |
+
if problem_type == "Classification" and 'target' in st.session_state:
|
| 149 |
+
target = st.session_state['target']
|
| 150 |
+
if df[target].nunique() == 2:
|
| 151 |
+
return "For binary classification, try Logistic Regression or Random Forest."
|
| 152 |
+
return "For multi-class classification, try Gradient Boosting or SVM."
|
| 153 |
+
elif problem_type == "Regression":
|
| 154 |
+
return "For regression, try Linear Regression or Gradient Boosting."
|
| 155 |
+
elif problem_type == "Clustering":
|
| 156 |
+
return "For clustering, try K-Means or DBSCAN based on your data distribution."
|
| 157 |
+
return "Setup PyCaret first to get model suggestions."
|
| 158 |
+
|
| 159 |
+
# Parse Chatbot Commands
|
| 160 |
+
def parse_command(command):
|
| 161 |
+
command = command.lower().strip()
|
| 162 |
+
if "drop columns" in command or "drop column" in command:
|
| 163 |
+
columns = command.replace("drop columns", "").replace("drop column", "").strip()
|
| 164 |
+
return drop_columns, columns
|
| 165 |
+
elif "show a scatter plot" in command or "scatter plot of" in command:
|
| 166 |
+
params = command.replace("show a scatter plot of", "").replace("scatter plot of", "").strip()
|
| 167 |
+
return generate_scatter_plot, params
|
| 168 |
+
elif "show a histogram" in command or "histogram of" in command:
|
| 169 |
+
params = command.replace("show a histogram of", "").replace("histogram of", "").strip()
|
| 170 |
+
return generate_histogram, params
|
| 171 |
+
elif "analyze plot" in command:
|
| 172 |
+
return lambda x: analyze_plot(), None
|
| 173 |
+
elif "suggest preprocessing" in command:
|
| 174 |
+
return lambda x: suggest_preprocessing(), None
|
| 175 |
+
elif "suggest model" in command:
|
| 176 |
+
return lambda x: suggest_model(), None
|
| 177 |
+
return None, "Command not recognized. Try 'drop columns X, Y', 'scatter plot of X vs Y', 'suggest preprocessing', or 'analyze plot'."
|
| 178 |
+
|
| 179 |
+
# Dataset Preview Function
|
| 180 |
+
def display_dataset_preview():
|
| 181 |
+
if 'df' in st.session_state:
|
| 182 |
+
st.subheader("Current Dataset Preview")
|
| 183 |
+
st.dataframe(st.session_state['df'].head(10), use_container_width=True)
|
| 184 |
+
st.write("---")
|
| 185 |
+
|
| 186 |
+
# Sidebar Navigation with API Key Input
|
| 187 |
+
with st.sidebar:
|
| 188 |
+
st.title("🔮 Neural-Vision Enhanced")
|
| 189 |
+
st.markdown("Your AI-powered model toolbox.")
|
| 190 |
+
st.markdown("---")
|
| 191 |
+
app_mode = st.selectbox("Navigation", ["Data Upload", "Model Training", "Validation & Exploration"])
|
| 192 |
+
data_type = st.selectbox("Data Type", ["Tabular"])
|
| 193 |
+
|
| 194 |
+
# API Key Input Field
|
| 195 |
+
api_key_input = st.text_input(
|
| 196 |
+
"Enter DeepSeek API Key (optional)",
|
| 197 |
+
type="password",
|
| 198 |
+
help="Enter your DeepSeek API key to override the default. Leave blank to use the app's default key."
|
| 199 |
+
)
|
| 200 |
+
|
| 201 |
+
st.markdown("---")
|
| 202 |
+
st.markdown("**Dependencies**: `pycaret`, `pandas`, `streamlit`, `ydata-profiling`, `plotly`, `requests`")
|
| 203 |
+
st.markdown("Created by Calvin Allen-Crawford | v2.0 | © 2025")
|
| 204 |
+
|
| 205 |
+
# Determine which API key to use
|
| 206 |
+
if api_key_input:
|
| 207 |
+
api_key = api_key_input # Use the user-provided API key from the sidebar
|
| 208 |
+
else:
|
| 209 |
+
api_key = st.secrets.get("DEEPSEEK_API_KEY", os.getenv("DEEPSEEK_API_KEY")) # Fall back to secret or environment variable
|
| 210 |
+
|
| 211 |
+
if not api_key:
|
| 212 |
+
st.error("DeepSeek API key is required. Please provide it in the sidebar or ensure it’s set in the app’s secrets.")
|
| 213 |
+
st.stop()
|
| 214 |
+
|
| 215 |
+
# Display dataset preview at the top of each page
|
| 216 |
+
display_dataset_preview()
|
| 217 |
+
|
| 218 |
# Main App Sections
|
| 219 |
if app_mode == "Data Upload":
|
| 220 |
st.title("📤 Data Upload")
|
|
|
|
| 222 |
if uploaded_file:
|
| 223 |
df = pd.read_csv(uploaded_file)
|
| 224 |
st.session_state['df'] = df
|
| 225 |
+
st.session_state.pop('problem_type', None)
|
| 226 |
+
st.session_state.pop('setup_complete', None)
|
| 227 |
+
st.session_state.pop('best_model', None)
|
| 228 |
+
st.session_state.pop('target', None)
|
| 229 |
st.write("---")
|
| 230 |
st.subheader("Statistics")
|
| 231 |
col1, col2, col3 = st.columns(3)
|
| 232 |
with col1: st.metric("Rows", df.shape[0])
|
| 233 |
with col2: st.metric("Columns", df.shape[1])
|
| 234 |
with col3: st.metric("Missing Values", df.isna().sum().sum())
|
|
|
|
| 235 |
st.write("---")
|
| 236 |
st.subheader("Exploratory Data Analysis (EDA)")
|
| 237 |
if st.button("Generate EDA Report"):
|
| 238 |
with st.spinner("Generating EDA Report..."):
|
| 239 |
profile = ProfileReport(df, explorative=True)
|
| 240 |
st_profile_report(profile)
|
| 241 |
+
with st.expander("AI Suggestions"):
|
| 242 |
+
st.write(suggest_preprocessing())
|
| 243 |
|
| 244 |
elif app_mode == "Model Training":
|
| 245 |
st.title("🧠 Model Training")
|
|
|
|
| 256 |
if problem_type == "Classification":
|
| 257 |
classification_setup(data=df, target=target, session_id=123, verbose=False)
|
| 258 |
st.session_state['problem_type'] = "Classification"
|
| 259 |
+
st.session_state['target'] = target
|
| 260 |
st.session_state['setup_complete'] = True
|
| 261 |
elif problem_type == "Regression":
|
| 262 |
regression_setup(data=df, target=target, session_id=123, verbose=False)
|
| 263 |
st.session_state['problem_type'] = "Regression"
|
| 264 |
+
st.session_state['target'] = target
|
| 265 |
st.session_state['setup_complete'] = True
|
| 266 |
elif problem_type == "Clustering":
|
| 267 |
clustering_setup(data=df, session_id=123, verbose=False)
|
|
|
|
| 291 |
elif selected_model == "hclust":
|
| 292 |
num_clusters = st.number_input("Number of Clusters", min_value=2, max_value=20, value=4, step=1)
|
| 293 |
|
| 294 |
+
with st.expander("AI Suggestions"):
|
| 295 |
+
st.write(suggest_model())
|
| 296 |
+
|
| 297 |
if problem_type in ["Classification", "Regression"]:
|
| 298 |
if st.button("Compare Models"):
|
| 299 |
with st.spinner("Comparing models..."):
|
| 300 |
if selected_models:
|
| 301 |
if problem_type == "Classification":
|
| 302 |
best_model = compare_classification_models(include=selected_models, fold=folds, sort=sort_metric)
|
| 303 |
+
else:
|
| 304 |
best_model = compare_regression_models(include=selected_models, fold=folds, sort=sort_metric)
|
| 305 |
else:
|
| 306 |
if problem_type == "Classification":
|
| 307 |
best_model = compare_classification_models(fold=folds, sort=sort_metric)
|
| 308 |
+
else:
|
| 309 |
best_model = compare_regression_models(fold=folds, sort=sort_metric)
|
| 310 |
st.session_state['best_model'] = best_model
|
| 311 |
st.success(f"Best Model: {best_model}")
|
|
|
|
| 343 |
with st.spinner("Tuning model..."):
|
| 344 |
if problem_type == "Classification":
|
| 345 |
tuned_model = tune_classification_model(st.session_state['best_model'], fold=folds, optimize=sort_metric)
|
| 346 |
+
else:
|
| 347 |
tuned_model = tune_regression_model(st.session_state['best_model'], fold=folds, optimize=sort_metric)
|
| 348 |
st.session_state['best_model'] = tuned_model
|
| 349 |
st.success(f"Tuned Model: {tuned_model}")
|
|
|
|
| 378 |
st.write("Clustering Results:")
|
| 379 |
plot_clustering_model(st.session_state['best_model'], plot="cluster", display_format="streamlit")
|
| 380 |
|
| 381 |
+
# Chatbot Section
|
| 382 |
+
st.markdown("---")
|
| 383 |
+
st.subheader("💬 AI Chatbot Assistant (DeepSeek Powered)")
|
| 384 |
+
st.info("Ask me to adjust data, explore it, or get suggestions! Try: 'drop columns X, Y', 'scatter plot of X vs Y', 'suggest preprocessing', or 'analyze plot'")
|
| 385 |
+
if "chat_history" not in st.session_state:
|
| 386 |
+
st.session_state.chat_history = []
|
| 387 |
+
|
| 388 |
+
for message in st.session_state.chat_history:
|
| 389 |
+
with st.chat_message(message["role"]):
|
| 390 |
+
st.markdown(message["content"])
|
| 391 |
+
|
| 392 |
+
user_input = st.chat_input("Ask me anything about the app or your data...")
|
| 393 |
+
if user_input:
|
| 394 |
+
st.session_state.chat_history.append({"role": "user", "content": user_input})
|
| 395 |
+
with st.chat_message("user"):
|
| 396 |
+
st.markdown(user_input)
|
| 397 |
+
with st.spinner("Processing..."):
|
| 398 |
+
func, param = parse_command(user_input)
|
| 399 |
+
if func:
|
| 400 |
+
response = func(param) if param else func(None)
|
| 401 |
+
else:
|
| 402 |
+
response = deepseek_chat(user_input, app_mode)
|
| 403 |
+
st.session_state.chat_history.append({"role": "assistant", "content": response})
|
| 404 |
+
with st.chat_message("assistant"):
|
| 405 |
+
st.markdown(response)
|
| 406 |
+
|
| 407 |
# Custom CSS
|
| 408 |
st.markdown("""
|
| 409 |
<style>
|