CosmickVisions commited on
Commit
86a359b
·
verified ·
1 Parent(s): cd83fd0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +235 -18
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
- # Sidebar Navigation
14
- with st.sidebar:
15
- st.title("🔮 Neural-Vision Enhanced")
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.write("---")
42
- st.subheader("Dataset Preview")
43
- st.dataframe(df.head(10))
 
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: # Regression
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: # Regression
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: # Regression
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>