Aka18 commited on
Commit
a394086
Β·
verified Β·
1 Parent(s): dd19e4a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1538 -51
app.py CHANGED
@@ -1,61 +1,1548 @@
1
- # debug_app.py - Replace your app.py temporarily with this
2
  import streamlit as st
 
 
 
 
 
 
 
 
3
  import os
4
  import sys
 
 
5
 
6
- st.title("πŸ” AIDA Debug Mode")
7
 
8
- # Show current directory and files
9
- st.write("**Current working directory:**", os.getcwd())
10
- st.write("**Files in current directory:**")
11
- files = os.listdir('.')
12
- for file in files:
13
- st.write(f"- {file}")
14
 
15
- # Show Python path
16
- st.write("**Python sys.path:**")
17
- for path in sys.path:
18
- st.write(f"- {path}")
 
 
19
 
20
- # Test if data_analysis_agent.py exists
21
- agent_exists = os.path.exists('data_analysis_agent.py')
22
- st.write(f"**data_analysis_agent.py exists:** {agent_exists}")
 
 
 
 
 
 
 
 
 
23
 
24
- if agent_exists:
25
- st.write("**File size:**", os.path.getsize('data_analysis_agent.py'), "bytes")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- # Try to import
28
- st.write("**Attempting import...**")
29
- try:
30
- import data_analysis_agent
31
- st.success("βœ… Import successful!")
32
- st.write("**Available classes/functions:**")
33
- st.write(dir(data_analysis_agent))
34
- except ImportError as e:
35
- st.error(f"❌ ImportError: {e}")
36
- except Exception as e:
37
- st.error(f"❌ Other error: {e}")
38
-
39
- # Try alternative import methods
40
- st.write("**Trying alternative import methods...**")
41
-
42
- # Method 1: Add current directory to path
43
- try:
44
- sys.path.insert(0, os.getcwd())
45
- import data_analysis_agent
46
- st.success("βœ… Alternative import method 1 worked!")
47
- except Exception as e:
48
- st.error(f"❌ Method 1 failed: {e}")
49
 
50
- # Method 2: Direct module loading
51
- try:
52
- import importlib.util
53
- spec = importlib.util.spec_from_file_location("data_analysis_agent", "./data_analysis_agent.py")
54
- module = importlib.util.module_from_spec(spec)
55
- spec.loader.exec_module(module)
56
- st.success("βœ… Alternative import method 2 worked!")
57
- except Exception as e:
58
- st.error(f"❌ Method 2 failed: {e}")
59
-
60
- st.write("---")
61
- st.write("**This debug info will help us fix the import issue!**")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import plotly.express as px
4
+ import plotly.graph_objects as go
5
+ from plotly.subplots import make_subplots
6
+ import io
7
+ import base64
8
+ from datetime import datetime
9
+ import json
10
  import os
11
  import sys
12
+ from pathlib import Path
13
+ import time
14
 
 
15
 
16
+ # Add the current directory to path to import our agent
17
+ sys.path.append(str(Path(__file__).parent))
 
 
 
 
18
 
19
+ try:
20
+ from data_analysis_agent import DataAnalysisAgent, DataAnalysisConfig
21
+ except ImportError:
22
+ st.error("❌ Please ensure data_analysis_agent.py is in the same directory")
23
+ st.info("Download both files and place them in the same folder")
24
+ st.stop()
25
 
26
+ # Page configuration
27
+ st.set_page_config(
28
+ page_title="AI Data Analysis Agent",
29
+ page_icon="πŸ€–",
30
+ layout="wide",
31
+ initial_sidebar_state="expanded",
32
+ menu_items={
33
+ 'Get Help': 'https://github.com/yourusername/ai-data-analysis-agent',
34
+ 'Report a bug': "https://github.com/yourusername/ai-data-analysis-agent/issues",
35
+ 'About': "# AI Data Analysis Agent\nPowered by Llama 3 & LangGraph"
36
+ }
37
+ )
38
 
39
+ # Custom CSS for beautiful styling
40
+ st.markdown("""
41
+ <style>
42
+ /* Import Google Fonts */
43
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
44
+
45
+ /* Global Styles */
46
+ .main .block-container {
47
+ padding-top: 2rem;
48
+ max-width: 1200px;
49
+ }
50
+
51
+ /* Main Header */
52
+ .main-header {
53
+ font-family: 'Inter', sans-serif;
54
+ font-size: 3.5rem;
55
+ font-weight: 700;
56
+ text-align: center;
57
+ margin: 2rem 0;
58
+ background: linear-gradient(135deg, #1e40af 0%, #3b82f6 50%, #06b6d4 100%);
59
+ -webkit-background-clip: text;
60
+ -webkit-text-fill-color: transparent;
61
+ background-clip: text;
62
+ text-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
63
+ }
64
+
65
+ /* Subtitle */
66
+ .subtitle {
67
+ font-family: 'Inter', sans-serif;
68
+ font-size: 1.2rem;
69
+ text-align: center;
70
+ color: #64748b;
71
+ margin-bottom: 3rem;
72
+ font-weight: 400;
73
+ }
74
+
75
+ /* Feature Cards */
76
+ .feature-card {
77
+ background: linear-gradient(145deg, #ffffff 0%, #f8fafc 100%);
78
+ border: 1px solid #e2e8f0;
79
+ border-radius: 16px;
80
+ padding: 2rem;
81
+ margin: 1rem 0;
82
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
83
+ transition: all 0.3s ease;
84
+ height: 100%;
85
+ }
86
+
87
+ .feature-card:hover {
88
+ transform: translateY(-4px);
89
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
90
+ }
91
+
92
+ .feature-icon {
93
+ font-size: 3rem;
94
+ margin-bottom: 1rem;
95
+ display: block;
96
+ }
97
+
98
+ .feature-title {
99
+ font-family: 'Inter', sans-serif;
100
+ font-size: 1.5rem;
101
+ font-weight: 600;
102
+ color: #1e293b;
103
+ margin-bottom: 0.5rem;
104
+ }
105
+
106
+ .feature-description {
107
+ color: #64748b;
108
+ font-size: 1rem;
109
+ line-height: 1.6;
110
+ }
111
+
112
+ /* Metric Cards */
113
+ .metric-container {
114
+ display: flex;
115
+ gap: 1rem;
116
+ margin: 2rem 0;
117
+ }
118
+
119
+ .metric-card {
120
+ background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
121
+ color: white;
122
+ padding: 1.5 rem;
123
+ border-radius: 12px;
124
+ text-align: center;
125
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
126
+ flex: 1;
127
+ transition: transform 0.2s ease;
128
+ }
129
+
130
+ .metric-card:hover {
131
+ transform: scale(1.05);
132
+ }
133
+
134
+ .metric-value {
135
+ font-size: 2rem;
136
+ font-weight: 700;
137
+ margin-bottom: 0.5rem;
138
+ }
139
+
140
+ .metric-label {
141
+ font-size: 0.9rem;
142
+ opacity: 0.9;
143
+ font-weight: 500;
144
+ }
145
+
146
+ /* Insight and Recommendation Boxes */
147
+ .insight-box {
148
+ background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
149
+ border-left: 5px solid #3b82f6;
150
+ padding: 1.5rem;
151
+ margin: 1rem 0;
152
+ border-radius: 0 12px 12px 0;
153
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
154
+ transition: all 0.3s ease;
155
+ }
156
+
157
+ .insight-box:hover {
158
+ transform: translateX(4px);
159
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
160
+ }
161
+
162
+ .recommendation-box {
163
+ background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
164
+ border-left: 5px solid #22c55e;
165
+ padding: 1.5rem;
166
+ margin: 1rem 0;
167
+ border-radius: 0 12px 12px 0;
168
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
169
+ transition: all 0.3s ease;
170
+ }
171
+
172
+ .recommendation-box:hover {
173
+ transform: translateX(4px);
174
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
175
+ }
176
+
177
+ /* Upload Area */
178
+ .upload-area {
179
+ border: 2px dashed #cbd5e1;
180
+ border-radius: 12px;
181
+ padding: 3rem 2rem;
182
+ text-align: center;
183
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
184
+ margin: 2rem 0;
185
+ transition: all 0.3s ease;
186
+ }
187
+
188
+ .upload-area:hover {
189
+ border-color: #3b82f6;
190
+ background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
191
+ }
192
+
193
+ /* Progress Bar */
194
+ .stProgress > div > div > div > div {
195
+ background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
196
+ border-radius: 10px;
197
+ }
198
+
199
+ /* Buttons */
200
+ .stButton > button {
201
+ background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
202
+ color: white;
203
+ border: none;
204
+ border-radius: 12px;
205
+ padding: 0.75rem 2rem;
206
+ font-weight: 600;
207
+ font-size: 1rem;
208
+ transition: all 0.3s ease;
209
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
210
+ }
211
+
212
+ .stButton > button:hover {
213
+ transform: translateY(-2px);
214
+ box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
215
+ }
216
+
217
+ /* Sidebar Styling */
218
+ .css-1d391kg {
219
+ background: linear-gradient(180deg, #1e293b 0%, #334155 100%);
220
+ }
221
+
222
+ .css-1d391kg .sidebar-content {
223
+ color: white;
224
+ }
225
+
226
+ /* Tab Styling */
227
+ .stTabs [data-baseweb="tab-list"] {
228
+ gap: 8px;
229
+ }
230
+
231
+ .stTabs [data-baseweb="tab"] {
232
+ height: 50px;
233
+ background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
234
+ border-radius: 12px;
235
+ border: 1px solid #cbd5e1;
236
+ color: #475569;
237
+ font-weight: 500;
238
+ transition: all 0.3s ease;
239
+ }
240
+
241
+ .stTabs [aria-selected="true"] {
242
+ background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
243
+ color: white;
244
+ border: 1px solid #3b82f6;
245
+ }
246
+
247
+ /* Success/Warning/Error Messages */
248
+ .stSuccess {
249
+ background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%);
250
+ border: 1px solid #22c55e;
251
+ border-radius: 12px;
252
+ }
253
+
254
+ .stWarning {
255
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
256
+ border: 1px solid #f59e0b;
257
+ border-radius: 12px;
258
+ }
259
+
260
+ .stError {
261
+ background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
262
+ border: 1px solid #ef4444;
263
+ border-radius: 12px;
264
+ }
265
+
266
+ /* Animation */
267
+ @keyframes fadeInUp {
268
+ from {
269
+ opacity: 0;
270
+ transform: translateY(30px);
271
+ }
272
+ to {
273
+ opacity: 1;
274
+ transform: translateY(0);
275
+ }
276
+ }
277
+
278
+ .animate-fade-in {
279
+ animation: fadeInUp 0.6s ease-out;
280
+ }
281
+
282
+ /* Data Table Styling */
283
+ .stDataFrame {
284
+ border-radius: 12px;
285
+ overflow: hidden;
286
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
287
+ }
288
+
289
+ /* Expander Styling */
290
+ .streamlit-expanderHeader {
291
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
292
+ border-radius: 12px;
293
+ border: 1px solid #e2e8f0;
294
+ }
295
+
296
+ /* Footer */
297
+ .footer {
298
+ text-align: center;
299
+ padding: 3rem 0;
300
+ color: #64748b;
301
+ font-size: 0.9rem;
302
+ border-top: 1px solid #e2e8f0;
303
+ margin-top: 4rem;
304
+ }
305
+
306
+ .footer a {
307
+ color: #3b82f6;
308
+ text-decoration: none;
309
+ font-weight: 500;
310
+ }
311
+
312
+ .footer a:hover {
313
+ text-decoration: underline;
314
+ }
315
+
316
+ /* Loading Animation */
317
+ .loading-container {
318
+ display: flex;
319
+ justify-content: center;
320
+ align-items: center;
321
+ padding: 2rem;
322
+ }
323
+
324
+ .loading-spinner {
325
+ border: 4px solid #f3f4f6;
326
+ border-top: 4px solid #3b82f6;
327
+ border-radius: 50%;
328
+ width: 40px;
329
+ height: 40px;
330
+ animation: spin 1s linear infinite;
331
+ }
332
+
333
+ @keyframes spin {
334
+ 0% { transform: rotate(0deg); }
335
+ 100% { transform: rotate(360deg); }
336
+ }
337
+ </style>
338
+ """, unsafe_allow_html=True)
339
 
340
+ def initialize_session_state():
341
+ """Initialize session state variables"""
342
+ if 'analysis_results' not in st.session_state:
343
+ st.session_state.analysis_results = None
344
+ if 'dataset' not in st.session_state:
345
+ st.session_state.dataset = None
346
+ if 'agent' not in st.session_state:
347
+ st.session_state.agent = None
348
+ if 'groq_api_key' not in st.session_state:
349
+ st.session_state.groq_api_key = ""
350
+ if 'model_name' not in st.session_state:
351
+ st.session_state.model_name = "llama3-70b-8192"
352
+ if 'analysis_complete' not in st.session_state:
353
+ st.session_state.analysis_complete = False
 
 
 
 
 
 
 
 
354
 
355
+ def create_agent():
356
+ """Create and configure the data analysis agent"""
357
+ try:
358
+ # Check environment variable first, then session state
359
+ groq_api_key = os.environ.get('GROQ_API_KEY') or st.session_state.get('groq_api_key', '')
360
+ if not groq_api_key:
361
+ return None
362
+
363
+ agent = DataAnalysisAgent(
364
+ groq_api_key=groq_api_key,
365
+ model_name=st.session_state.get('model_name', 'llama3-70b-8192')
366
+ )
367
+ return agent
368
+ except Exception as e:
369
+ st.error(f"Failed to create agent: {str(e)}")
370
+ return None
371
+
372
+ def sidebar_config():
373
+ """Configure the beautiful sidebar"""
374
+ with st.sidebar:
375
+ st.markdown("""
376
+ <div style='text-align: center; padding: 1rem 0;'>
377
+ <div style='font-size: 4.5rem; margin-bottom: 0 rem;'>πŸ€–</div>
378
+ <h1 style='
379
+ background: linear-gradient(135deg, #1e40af 0%, #3b82f6 50%, #06b6d4 100%);
380
+ -webkit-background-clip: text;
381
+ -webkit-text-fill-color: transparent;
382
+ background-clip: text;
383
+ margin: 0;
384
+ font-size: 1.6rem;
385
+ font-weight: 700;
386
+ '>AI Agents on action</h1>
387
+ <p style='color: #94a3b8; margin: 0.5rem 0 0 0; font-size: 0.9rem;'>Powered by Llama 3</p>
388
+ </div>
389
+ """, unsafe_allow_html=True)
390
+
391
+ st.markdown("---")
392
+
393
+ # Check for environment variable first
394
+ env_api_key = os.environ.get('GROQ_API_KEY')
395
+
396
+ if env_api_key:
397
+ st.success("βœ… API Key Configured")
398
+ st.session_state.groq_api_key = env_api_key
399
+ api_key_configured = True
400
+ else:
401
+ st.subheader("πŸ”‘ API Setup")
402
+ st.info("πŸ’‘ Set GROQ_API_KEY environment variable")
403
+
404
+ groq_api_key = st.text_input(
405
+ "Groq API Key",
406
+ type="password",
407
+ value=st.session_state.groq_api_key,
408
+ help="Get your API key from console.groq.com"
409
+ )
410
+
411
+ if groq_api_key:
412
+ st.session_state.groq_api_key = groq_api_key
413
+ api_key_configured = True
414
+ else:
415
+ api_key_configured = False
416
+
417
+ st.markdown("---")
418
+
419
+ # Model Selection
420
+ st.subheader("🧠 AI Model")
421
+ model_options = {
422
+ "llama3-70b-8192": "Llama 3 70B (Recommended)",
423
+ "llama3-8b-8192": "Llama 3 8B (Faster)",
424
+ "mixtral-8x7b-32768": "Mixtral 8x7B"
425
+ }
426
+
427
+ selected_model = st.selectbox(
428
+ "Choose Model",
429
+ options=list(model_options.keys()),
430
+ format_func=lambda x: model_options[x],
431
+ index=0
432
+ )
433
+ st.session_state.model_name = selected_model
434
+
435
+ st.markdown("---")
436
+
437
+ # Analysis Options
438
+ st.subheader("βš™οΈ Analysis Settings")
439
+
440
+ industry_type = st.selectbox(
441
+ "Industry Focus",
442
+ ["General", "Retail", "Healthcare", "Finance", "Manufacturing", "Technology"],
443
+ help="Customize insights for your industry"
444
+ )
445
+ st.session_state.industry_type = industry_type
446
+
447
+ enable_advanced = st.toggle(
448
+ "Advanced Analysis",
449
+ value=True,
450
+ help="Include correlation analysis and advanced insights"
451
+ )
452
+ st.session_state.enable_advanced = enable_advanced
453
+
454
+ auto_insights = st.toggle(
455
+ "Auto-Generate Insights",
456
+ value=True,
457
+ help="Automatically generate business insights"
458
+ )
459
+ st.session_state.auto_insights = auto_insights
460
+
461
+ st.markdown("---")
462
+
463
+ # Quick Stats with dynamic insights count
464
+ if st.session_state.dataset is not None:
465
+ st.subheader("πŸ“Š Dataset Info")
466
+ df = st.session_state.dataset
467
+
468
+ col1, col2 = st.columns(2)
469
+ with col1:
470
+ st.metric("Rows", f"{df.shape[0]:,}")
471
+ st.metric("Columns", df.shape[1])
472
+ with col2:
473
+ st.metric("Missing", f"{df.isnull().sum().sum():,}")
474
+ st.metric("Size", f"{df.memory_usage(deep=True).sum() / 1024**2:.1f} MB")
475
+
476
+ # Show insights count if analysis is complete (now shows top 5)
477
+ if st.session_state.analysis_results:
478
+ insights = st.session_state.analysis_results.get('insights', [])
479
+ recommendations = st.session_state.analysis_results.get('recommendations', [])
480
+
481
+ # Process to get clean counts (max 5 each)
482
+ processed_insights_count = min(len([i for i in insights if isinstance(i, str) and len(i.strip()) > 20]), 5)
483
+ processed_recommendations_count = min(len([r for r in recommendations if isinstance(r, str) and len(r.strip()) > 20]), 5)
484
+
485
+ st.markdown("---")
486
+ st.subheader("🧠 Analysis Results")
487
+
488
+ col1, col2 = st.columns(2)
489
+ with col1:
490
+ st.metric("πŸ’‘ Top Insights", processed_insights_count)
491
+ with col2:
492
+ st.metric("🎯 Top Recommendations", processed_recommendations_count)
493
+
494
+ st.markdown("---")
495
+
496
+ # Help Section
497
+ with st.expander("πŸ’‘ Quick Help"):
498
+ st.markdown("""
499
+ **Supported Formats:**
500
+ - CSV files (.csv)
501
+ - Excel files (.xlsx, .xls)
502
+ - JSON files (.json)
503
+
504
+ **Best Practices:**
505
+ - Clean column names
506
+ - Handle missing values
507
+ - Include date columns
508
+ - Mix numeric & categorical data
509
+
510
+ **Need Help?**
511
+ - [Documentation](https://github.com/yourusername/ai-data-analysis-agent)
512
+ - [Examples](https://github.com/yourusername/ai-data-analysis-agent/examples)
513
+ """)
514
+
515
+ return api_key_configured
516
+
517
+ def display_hero_section():
518
+ """Display the beautiful hero section"""
519
+ st.markdown('<div class="main-header animate-fade-in">AIDA-AI Data Analyzer </div>', unsafe_allow_html=True)
520
+
521
+ st.markdown("""
522
+ <div class="subtitle animate-fade-in">
523
+ Transform your raw data into actionable business insights with the power of AI.<br>
524
+ Upload, analyze, and discover patterns automatically using intelligent agents.
525
+ </div>
526
+ """, unsafe_allow_html=True)
527
+
528
+ def display_features():
529
+ """Display feature cards"""
530
+ st.markdown("### ✨ What This AI Agent Can Do")
531
+
532
+ col1, col2, col3 = st.columns(3)
533
+
534
+ with col1:
535
+ st.markdown("""
536
+ <div class="feature-card">
537
+ <div class="feature-icon">🧠</div>
538
+ <div class="feature-title">Intelligent Analysis</div>
539
+ <div class="feature-description">
540
+ Our AI automatically understands your data structure, identifies patterns,
541
+ and generates meaningful insights without any manual configuration.
542
+ </div>
543
+ </div>
544
+ """, unsafe_allow_html=True)
545
+
546
+ with col2:
547
+ st.markdown("""
548
+ <div class="feature-card">
549
+ <div class="feature-icon">πŸ“Š</div>
550
+ <div class="feature-title">Smart Visualizations</div>
551
+ <div class="feature-description">
552
+ Automatically creates the most appropriate charts and graphs for your data,
553
+ with interactive visualizations.
554
+ </div>
555
+ </div>
556
+ """, unsafe_allow_html=True)
557
+
558
+ with col3:
559
+ st.markdown("""
560
+ <div class="feature-card">
561
+ <div class="feature-icon">🎯</div>
562
+ <div class="feature-title">Actionable Recommendations</div>
563
+ <div class="feature-description">
564
+ Get specific, measurable recommendations for improving your business
565
+ based on data-driven insights.
566
+ </div>
567
+ </div>
568
+ """, unsafe_allow_html=True)
569
+
570
+ def upload_dataset():
571
+ """Beautiful dataset upload section"""
572
+ st.markdown("### πŸ“Š Upload Your Dataset")
573
+
574
+ uploaded_file = st.file_uploader(
575
+ "",
576
+ type=['csv', 'xlsx', 'xls', 'json'],
577
+ help="Drag and drop your file here or click to browse",
578
+ label_visibility="collapsed"
579
+ )
580
+
581
+ if uploaded_file is not None:
582
+ try:
583
+ # Show loading spinner
584
+ with st.spinner("πŸ” Processing your dataset..."):
585
+ time.sleep(1) # Small delay for UX
586
+
587
+ # Read the file based on extension
588
+ if uploaded_file.name.endswith('.csv'):
589
+ df = pd.read_csv(uploaded_file)
590
+ elif uploaded_file.name.endswith(('.xlsx', '.xls')):
591
+ df = pd.read_excel(uploaded_file)
592
+ elif uploaded_file.name.endswith('.json'):
593
+ df = pd.read_json(uploaded_file)
594
+ else:
595
+ st.error("Unsupported file format")
596
+ return False
597
+
598
+ st.session_state.dataset = df
599
+ st.session_state.uploaded_filename = uploaded_file.name
600
+
601
+ # Success message
602
+ st.success(f"βœ… Successfully loaded **{uploaded_file.name}**")
603
+
604
+ # Beautiful metrics display
605
+ col1, col2, col3, col4 = st.columns(4)
606
+
607
+ with col1:
608
+ st.markdown(f"""
609
+ <div class="metric-card">
610
+ <div class="metric-value">{df.shape[0]:,}</div>
611
+ <div class="metric-label">Rows</div>
612
+ </div>
613
+ """, unsafe_allow_html=True)
614
+
615
+ with col2:
616
+ st.markdown(f"""
617
+ <div class="metric-card">
618
+ <div class="metric-value">{df.shape[1]}</div>
619
+ <div class="metric-label">Columns</div>
620
+ </div>
621
+ """, unsafe_allow_html=True)
622
+
623
+ with col3:
624
+ missing = df.isnull().sum().sum()
625
+ st.markdown(f"""
626
+ <div class="metric-card">
627
+ <div class="metric-value">{missing:,}</div>
628
+ <div class="metric-label">Missing Values</div>
629
+ </div>
630
+ """, unsafe_allow_html=True)
631
+
632
+ with col4:
633
+ size_mb = df.memory_usage(deep=True).sum() / 1024**2
634
+ st.markdown(f"""
635
+ <div class="metric-card">
636
+ <div class="metric-value">{size_mb:.1f} MB</div>
637
+ <div class="metric-label">File Size</div>
638
+ </div>
639
+ """, unsafe_allow_html=True)
640
+
641
+ st.markdown("<br>", unsafe_allow_html=True)
642
+
643
+ # Data preview with beautiful styling
644
+ st.markdown("#### πŸ“‹ Data Preview")
645
+ st.dataframe(
646
+ df.head(10),
647
+ use_container_width=True,
648
+ height=300
649
+ )
650
+
651
+ # Column information in expandable section
652
+ with st.expander("πŸ“Š Detailed Column Information", expanded=False):
653
+ col_info = pd.DataFrame({
654
+ 'Column': df.columns,
655
+ 'Type': df.dtypes.astype(str),
656
+ 'Non-Null': df.count(),
657
+ 'Null Count': df.isnull().sum(),
658
+ 'Unique Values': df.nunique(),
659
+ 'Sample Data': [str(df[col].iloc[0]) if len(df) > 0 else '' for col in df.columns]
660
+ })
661
+ st.dataframe(col_info, use_container_width=True)
662
+
663
+ return True
664
+
665
+ except Exception as e:
666
+ st.error(f"❌ Error reading file: {str(e)}")
667
+ return False
668
+ else:
669
+ # Show upload placeholder
670
+ st.markdown("""
671
+ <div class="upload-area">
672
+ <div style="font-size: 3rem; margin-bottom: 1rem;">πŸ“</div>
673
+ <div style="font-size: 1.2rem; font-weight: 600; margin-bottom: 0.5rem;">
674
+ Drop your dataset here
675
+ </div>
676
+ <div style="color: #64748b;">
677
+ Supports CSV, Excel, and JSON files β€’ Max 200MB
678
+ </div>
679
+ </div>
680
+ """, unsafe_allow_html=True)
681
+
682
+ return False
683
+
684
+ def run_analysis():
685
+ """Run the AI analysis with beautiful progress indicators"""
686
+ if st.session_state.dataset is None:
687
+ st.warning("Please upload a dataset first.")
688
+ return
689
+
690
+ # Check for API key from environment or session state
691
+ api_key = os.environ.get('GROQ_API_KEY') or st.session_state.get('groq_api_key')
692
+ if not api_key:
693
+ st.warning("Please set GROQ_API_KEY environment variable or enter it in the sidebar.")
694
+ return
695
+
696
+ # Create agent
697
+ with st.spinner("πŸ€– Initializing AI agent..."):
698
+ agent = create_agent()
699
+ if agent is None:
700
+ st.error("Failed to initialize AI agent. Check your API key.")
701
+ return
702
+
703
+ st.session_state.agent = agent
704
+
705
+ # Save dataset temporarily
706
+ temp_file = "temp_dataset.csv"
707
+ st.session_state.dataset.to_csv(temp_file, index=False)
708
+
709
+ # Beautiful progress tracking
710
+ progress_container = st.container()
711
+
712
+ with progress_container:
713
+ st.markdown("### πŸš€ AI Analysis in Progress")
714
+
715
+ # Progress bar
716
+ progress_bar = st.progress(0)
717
+ status_text = st.empty()
718
+
719
+ # Step indicators
720
+ steps = [
721
+ ("πŸ”", "Analyzing dataset structure"),
722
+ ("πŸ“Š", "Examining columns and data quality"),
723
+ ("🧠", "Generating AI insights"),
724
+ ("πŸ“ˆ", "Planning visualizations"),
725
+ ("🎨", "Creating charts"),
726
+ ("🎯", "Formulating recommendations")
727
+ ]
728
+
729
+ step_cols = st.columns(len(steps))
730
+ step_indicators = []
731
+
732
+ for i, (icon, desc) in enumerate(steps):
733
+ with step_cols[i]:
734
+ step_indicators.append(st.empty())
735
+ step_indicators[i].markdown(f"""
736
+ <div style="text-align: center; padding: 1rem; opacity: 0.3;">
737
+ <div style="font-size: 2rem;">{icon}</div>
738
+ <div style="font-size: 0.8rem; margin-top: 0.5rem;">{desc}</div>
739
+ </div>
740
+ """, unsafe_allow_html=True)
741
+
742
+ try:
743
+ # Step 1
744
+ step_indicators[0].markdown(f"""
745
+ <div style="text-align: center; padding: 1rem; opacity: 1; background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); border-radius: 12px;">
746
+ <div style="font-size: 2rem;">πŸ”</div>
747
+ <div style="font-size: 0.8rem; margin-top: 0.5rem; font-weight: 600;">Analyzing Structure</div>
748
+ </div>
749
+ """, unsafe_allow_html=True)
750
+ status_text.markdown("**πŸ” AI agent analyzing dataset structure...**")
751
+ progress_bar.progress(15)
752
+ time.sleep(1)
753
+
754
+ # Step 2
755
+ step_indicators[1].markdown(f"""
756
+ <div style="text-align: center; padding: 1rem; opacity: 1; background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); border-radius: 12px;">
757
+ <div style="font-size: 2rem;">πŸ“Š</div>
758
+ <div style="font-size: 0.8rem; margin-top: 0.5rem; font-weight: 600;">Examining Data</div>
759
+ </div>
760
+ """, unsafe_allow_html=True)
761
+ status_text.markdown("**πŸ“Š Analyzing columns and data quality...**")
762
+ progress_bar.progress(30)
763
+ time.sleep(1)
764
+
765
+ # Step 3
766
+ step_indicators[2].markdown(f"""
767
+ <div style="text-align: center; padding: 1rem; opacity: 1; background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); border-radius: 12px;">
768
+ <div style="font-size: 2rem;">🧠</div>
769
+ <div style="font-size: 0.8rem; margin-top: 0.5rem; font-weight: 600;">AI Thinking</div>
770
+ </div>
771
+ """, unsafe_allow_html=True)
772
+ status_text.markdown("**🧠 Generating insights with AI...**")
773
+ progress_bar.progress(50)
774
+ time.sleep(1)
775
+
776
+ # Step 4
777
+ step_indicators[3].markdown(f"""
778
+ <div style="text-align: center; padding: 1rem; opacity: 1; background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); border-radius: 12px;">
779
+ <div style="font-size: 2rem;">πŸ“ˆ</div>
780
+ <div style="font-size: 0.8rem; margin-top: 0.5rem; font-weight: 600;">Planning Charts</div>
781
+ </div>
782
+ """, unsafe_allow_html=True)
783
+ status_text.markdown("**πŸ“ˆ Planning optimal visualizations...**")
784
+ progress_bar.progress(70)
785
+ time.sleep(1)
786
+
787
+ # Step 5
788
+ step_indicators[4].markdown(f"""
789
+ <div style="text-align: center; padding: 1rem; opacity: 1; background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); border-radius: 12px;">
790
+ <div style="font-size: 2rem;">🎨</div>
791
+ <div style="font-size: 0.8rem; margin-top: 0.5rem; font-weight: 600;">Creating Charts</div>
792
+ </div>
793
+ """, unsafe_allow_html=True)
794
+ status_text.markdown("**🎨 Creating beautiful visualizations...**")
795
+ progress_bar.progress(85)
796
+
797
+ # Run the actual analysis
798
+ results = agent.analyze_dataset(temp_file)
799
+
800
+ # Step 6
801
+ step_indicators[5].markdown(f"""
802
+ <div style="text-align: center; padding: 1rem; opacity: 1; background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); border-radius: 12px;">
803
+ <div style="font-size: 2rem;">🎯</div>
804
+ <div style="font-size: 0.8rem; margin-top: 0.5rem; font-weight: 600;">Final Recommendations</div>
805
+ </div>
806
+ """, unsafe_allow_html=True)
807
+ status_text.markdown("**🎯 Formulating actionable recommendations...**")
808
+ progress_bar.progress(100)
809
+
810
+ # Clean up temp file
811
+ if os.path.exists(temp_file):
812
+ os.remove(temp_file)
813
+
814
+ if "error" in results:
815
+ st.error(f"❌ Analysis failed: {results['error']}")
816
+ return
817
+
818
+ st.session_state.analysis_results = results
819
+ st.session_state.analysis_complete = True
820
+
821
+ # Success animation
822
+ status_text.markdown("**βœ… Analysis completed successfully!**")
823
+
824
+ # Show completion message
825
+ st.balloons()
826
+ time.sleep(1)
827
+
828
+ # Clear progress and show results
829
+ progress_container.empty()
830
+ st.rerun()
831
+
832
+ except Exception as e:
833
+ st.error(f"❌ Analysis failed: {str(e)}")
834
+ if os.path.exists(temp_file):
835
+ os.remove(temp_file)
836
+
837
+ def display_results():
838
+ """Display beautiful analysis results"""
839
+ results = st.session_state.analysis_results
840
+ if results is None:
841
+ return
842
+
843
+ # Results header
844
+ st.markdown("""
845
+ <div style="text-align: center; margin: 3rem 0;">
846
+ <h1 style="font-size: 2.5rem; color: #1e293b; margin-bottom: 0.5rem;">πŸ“Š Analysis Complete!</h1>
847
+ <p style="font-size: 1.1rem; color: #64748b;">Here are your AI-generated insights and recommendations</p>
848
+ </div>
849
+ """, unsafe_allow_html=True)
850
+
851
+ # Dataset Overview with beautiful cards
852
+ st.markdown("### πŸ“‹ Dataset Overview")
853
+ info = results.get('dataset_info', {})
854
+
855
+ col1, col2, col3, col4, col5 = st.columns(5)
856
+
857
+ metrics = [
858
+ ("πŸ“Š", "Total Rows", f"{info.get('shape', [0])[0]:,}", "#3b82f6"),
859
+ ("πŸ“‹", "Columns", str(info.get('shape', [0, 0])[1]), "#8b5cf6"),
860
+ ("πŸ”’", "Numeric", str(len(info.get('numeric_columns', []))), "#06b6d4"),
861
+ ("πŸ“", "Categorical", str(len(info.get('categorical_columns', []))), "#10b981"),
862
+ ("✨", "Quality Score", f"{max(0, 100 - (sum(info.get('null_counts', {}).values()) / max(info.get('shape', [1, 1])[0] * info.get('shape', [1, 1])[1], 1) * 100)):.0f}%", "#f59e0b")
863
+ ]
864
+
865
+ for i, (icon, label, value, color) in enumerate(metrics):
866
+ with [col1, col2, col3, col4, col5][i]:
867
+ st.markdown(f"""
868
+ <div style="
869
+ background: linear-gradient(135deg, {color}15 0%, {color}25 100%);
870
+ border: 2px solid {color}30;
871
+ border-radius: 16px;
872
+ padding: 1.5rem;
873
+ text-align: center;
874
+ margin: 0.5rem 0;
875
+ transition: transform 0.2s ease;
876
+ ">
877
+ <div style="font-size: 2rem; margin-bottom: 0.5rem;">{icon}</div>
878
+ <div style="font-size: 1.8rem; font-weight: 700; color: {color}; margin-bottom: 0.25rem;">{value}</div>
879
+ <div style="font-size: 0.9rem; color: #64748b; font-weight: 500;">{label}</div>
880
+ </div>
881
+ """, unsafe_allow_html=True)
882
+
883
+ st.markdown("<br>", unsafe_allow_html=True)
884
+
885
+ # Key Insights Section - Extract complete insights with headers and content combined
886
+ st.markdown("### πŸ’‘ Key Insights")
887
+ insights = results.get('insights', [])
888
+
889
+ if insights:
890
+ # Combine all insight text and parse properly
891
+ full_text = ' '.join(str(item) for item in insights)
892
+
893
+ # Extract complete insights (header + content) using regex
894
+ import re
895
+
896
+ # Pattern to match **Insight X:** followed by content until next insight or end
897
+ insight_pattern = r'\*\*Insight (\d+):(.*?)(?=\*\*Insight \d+:|$)'
898
+ matches = re.findall(insight_pattern, full_text, re.DOTALL)
899
+
900
+ processed_insights = []
901
+ for match in matches:
902
+ insight_num, content = match
903
+ clean_content = content.strip().rstrip('*')
904
+ if len(clean_content) > 20:
905
+ processed_insights.append(clean_content)
906
+
907
+ # Take top 5 insights
908
+ top_insights = processed_insights[:5]
909
+
910
+ if top_insights:
911
+ st.markdown(f"**Top {len(top_insights)} key insights from your data:**")
912
+ st.markdown("<br>", unsafe_allow_html=True)
913
+
914
+ for i, insight in enumerate(top_insights):
915
+ st.markdown(f"""
916
+ <div class="insight-box animate-fade-in">
917
+ <div style="display: flex; align-items: flex-start; gap: 1rem;">
918
+ <div style="
919
+ background: #3b82f6;
920
+ color: white;
921
+ border-radius: 50%;
922
+ width: 32px;
923
+ height: 32px;
924
+ display: flex;
925
+ align-items: center;
926
+ justify-content: center;
927
+ font-weight: bold;
928
+ font-size: 0.9rem;
929
+ flex-shrink: 0;
930
+ ">{i+1}</div>
931
+ <div style="flex: 1;">
932
+ <strong style="color: #1e293b;">πŸ’‘ Key Insight {i+1}:</strong><br>
933
+ <span style="color: #475569; line-height: 1.6;">{insight}</span>
934
+ </div>
935
+ </div>
936
+ </div>
937
+ """, unsafe_allow_html=True)
938
+ else:
939
+ st.info("πŸ” No insights could be extracted from the analysis.")
940
+ else:
941
+ st.info("πŸ” No insights were generated.")
942
+
943
+ # Interactive Visualizations Section
944
+ st.markdown("### πŸ“ˆ Interactive Data Exploration")
945
+
946
+ if st.session_state.dataset is not None:
947
+ df = st.session_state.dataset
948
+
949
+ # Beautiful tabs
950
+ tab1, tab2, tab3, tab4 = st.tabs([
951
+ "πŸ“Š Distributions",
952
+ "πŸ”— Correlations",
953
+ "πŸ“ˆ Trends & Patterns",
954
+ "🎯 Custom Analysis"
955
+ ])
956
+
957
+ with tab1:
958
+ st.markdown("#### πŸ“Š Distribution Analysis")
959
+ numeric_cols = df.select_dtypes(include=['number']).columns.tolist()
960
+
961
+ if len(numeric_cols) > 0:
962
+ # Column selector at the top
963
+ selected_col = st.selectbox(
964
+ "Select column to analyze",
965
+ numeric_cols,
966
+ key="dist_col"
967
+ )
968
+
969
+ st.markdown("<br>", unsafe_allow_html=True)
970
+
971
+ # Show all three plots side by side
972
+ col1, col2, col3 = st.columns(3)
973
+
974
+ with col1:
975
+ st.markdown("**Histogram**")
976
+ fig_hist = px.histogram(
977
+ df,
978
+ x=selected_col,
979
+ title=f"Histogram",
980
+ nbins=30,
981
+ color_discrete_sequence=['#3b82f6']
982
+ )
983
+ fig_hist.update_layout(
984
+ height=380,
985
+ plot_bgcolor='rgba(0,0,0,0)',
986
+ paper_bgcolor='rgba(0,0,0,0)',
987
+ title_font_size=14,
988
+ margin=dict(t=40, b=40, l=40, r=40)
989
+ )
990
+ st.plotly_chart(fig_hist, use_container_width=True)
991
+
992
+ with col2:
993
+ st.markdown("**Box Plot**")
994
+ fig_box = px.box(
995
+ df,
996
+ y=selected_col,
997
+ title=f"Box Plot",
998
+ color_discrete_sequence=['#8b5cf6']
999
+ )
1000
+ fig_box.update_layout(
1001
+ height=380,
1002
+ plot_bgcolor='rgba(0,0,0,0)',
1003
+ paper_bgcolor='rgba(0,0,0,0)',
1004
+ title_font_size=14,
1005
+ margin=dict(t=40, b=40, l=40, r=40)
1006
+ )
1007
+ st.plotly_chart(fig_box, use_container_width=True)
1008
+
1009
+ with col3:
1010
+ st.markdown("**Violin Plot**")
1011
+ fig_violin = px.violin(
1012
+ df,
1013
+ y=selected_col,
1014
+ title=f"Violin Plot",
1015
+ color_discrete_sequence=['#06b6d4']
1016
+ )
1017
+ fig_violin.update_layout(
1018
+ height=380,
1019
+ plot_bgcolor='rgba(0,0,0,0)',
1020
+ paper_bgcolor='rgba(0,0,0,0)',
1021
+ title_font_size=14,
1022
+ margin=dict(t=40, b=40, l=40, r=40)
1023
+ )
1024
+ st.plotly_chart(fig_violin, use_container_width=True)
1025
+
1026
+ # Statistics cards below the plots
1027
+ st.markdown("#### πŸ“Š Statistical Summary")
1028
+ stats_col1, stats_col2, stats_col3, stats_col4, stats_col5 = st.columns(5)
1029
+
1030
+ stats = [
1031
+ ("Mean", f"{df[selected_col].mean():.2f}", "#3b82f6"),
1032
+ ("Median", f"{df[selected_col].median():.2f}", "#8b5cf6"),
1033
+ ("Std Dev", f"{df[selected_col].std():.2f}", "#06b6d4"),
1034
+ ("Min", f"{df[selected_col].min():.2f}", "#10b981"),
1035
+ ("Max", f"{df[selected_col].max():.2f}", "#f59e0b")
1036
+ ]
1037
+
1038
+ for i, (label, value, color) in enumerate(stats):
1039
+ with [stats_col1, stats_col2, stats_col3, stats_col4, stats_col5][i]:
1040
+ st.markdown(f"""
1041
+ <div style="
1042
+ background: {color}15;
1043
+ border: 1px solid {color}30;
1044
+ border-radius: 12px;
1045
+ padding: 1rem;
1046
+ text-align: center;
1047
+ ">
1048
+ <div style="font-size: 1.4rem; font-weight: 700; color: {color};">{value}</div>
1049
+ <div style="font-size: 0.85rem; color: #64748b; margin-top: 0.25rem;">{label}</div>
1050
+ </div>
1051
+ """, unsafe_allow_html=True)
1052
+ else:
1053
+ st.info("πŸ“Š No numeric columns found for distribution analysis.")
1054
+
1055
+ with tab2:
1056
+ st.markdown("#### πŸ”— Correlation Analysis")
1057
+
1058
+ if len(numeric_cols) > 1:
1059
+ # Correlation matrix heatmap
1060
+ corr_matrix = df[numeric_cols].corr()
1061
+
1062
+ fig = px.imshow(
1063
+ corr_matrix,
1064
+ text_auto=True,
1065
+ aspect="auto",
1066
+ title="Correlation Matrix",
1067
+ color_continuous_scale="RdBu_r",
1068
+ zmin=-1,
1069
+ zmax=1
1070
+ )
1071
+ fig.update_layout(
1072
+ height=500,
1073
+ plot_bgcolor='rgba(0,0,0,0)',
1074
+ paper_bgcolor='rgba(0,0,0,0)'
1075
+ )
1076
+ st.plotly_chart(fig, use_container_width=True)
1077
+
1078
+ # Top correlations
1079
+ st.markdown("#### πŸ”— Strongest Correlations")
1080
+ correlations = []
1081
+ for i in range(len(corr_matrix.columns)):
1082
+ for j in range(i+1, len(corr_matrix.columns)):
1083
+ corr_val = corr_matrix.iloc[i, j]
1084
+ if not pd.isna(corr_val):
1085
+ correlations.append({
1086
+ 'Variable 1': corr_matrix.columns[i],
1087
+ 'Variable 2': corr_matrix.columns[j],
1088
+ 'Correlation': corr_val,
1089
+ 'Strength': abs(corr_val)
1090
+ })
1091
+
1092
+ if correlations:
1093
+ corr_df = pd.DataFrame(correlations)
1094
+ corr_df = corr_df.sort_values('Strength', ascending=False).head(10)
1095
+
1096
+ # Display as beautiful cards
1097
+ for _, row in corr_df.head(5).iterrows():
1098
+ strength = "Strong" if row['Strength'] > 0.7 else "Moderate" if row['Strength'] > 0.5 else "Weak"
1099
+ color = "#ef4444" if row['Strength'] > 0.7 else "#f59e0b" if row['Strength'] > 0.5 else "#10b981"
1100
+
1101
+ st.markdown(f"""
1102
+ <div style="
1103
+ background: {color}15;
1104
+ border-left: 4px solid {color};
1105
+ border-radius: 8px;
1106
+ padding: 1rem;
1107
+ margin: 0.5rem 0;
1108
+ ">
1109
+ <div style="font-weight: 600; color: #1e293b; margin-bottom: 0.5rem;">
1110
+ {row['Variable 1']} ↔ {row['Variable 2']}
1111
+ </div>
1112
+ <div style="color: #64748b;">
1113
+ Correlation: <strong style="color: {color};">{row['Correlation']:.3f}</strong>
1114
+ ({strength} relationship)
1115
+ </div>
1116
+ </div>
1117
+ """, unsafe_allow_html=True)
1118
+ else:
1119
+ st.info("πŸ”— Need at least 2 numeric columns for correlation analysis.")
1120
+
1121
+ with tab3:
1122
+ st.markdown("#### πŸ“ˆ Trends & Patterns")
1123
+
1124
+ date_cols = df.select_dtypes(include=['datetime64']).columns.tolist()
1125
+ cat_cols = df.select_dtypes(include=['object', 'category']).columns.tolist()
1126
+
1127
+ if len(date_cols) > 0 and len(numeric_cols) > 0:
1128
+ col1, col2 = st.columns(2)
1129
+ with col1:
1130
+ date_col = st.selectbox("Date column", date_cols, key="trend_date")
1131
+ with col2:
1132
+ value_col = st.selectbox("Value column", numeric_cols, key="trend_value")
1133
+
1134
+ df_sorted = df.sort_values(date_col)
1135
+ fig = px.line(
1136
+ df_sorted,
1137
+ x=date_col,
1138
+ y=value_col,
1139
+ title=f"{value_col} Over Time",
1140
+ color_discrete_sequence=['#3b82f6']
1141
+ )
1142
+ fig.update_layout(height=400)
1143
+ st.plotly_chart(fig, use_container_width=True)
1144
+
1145
+ elif cat_cols and numeric_cols:
1146
+ st.markdown("#### πŸ“Š Category-based Analysis")
1147
+
1148
+ col1, col2, col3 = st.columns(3)
1149
+ with col1:
1150
+ cat_col = st.selectbox("Category", cat_cols, key="cat_trend")
1151
+ with col2:
1152
+ num_col = st.selectbox("Numeric value", numeric_cols, key="num_trend")
1153
+ with col3:
1154
+ agg_func = st.selectbox("Aggregation", ["mean", "sum", "count", "median"])
1155
+
1156
+ if agg_func == "count":
1157
+ grouped = df.groupby(cat_col).size().reset_index(name='count')
1158
+ y_col = 'count'
1159
+ else:
1160
+ grouped = df.groupby(cat_col)[num_col].agg(agg_func).reset_index()
1161
+ y_col = num_col
1162
+
1163
+ fig = px.bar(
1164
+ grouped,
1165
+ x=cat_col,
1166
+ y=y_col,
1167
+ title=f"{agg_func.title()} of {num_col if agg_func != 'count' else 'Count'} by {cat_col}",
1168
+ color_discrete_sequence=['#8b5cf6']
1169
+ )
1170
+ fig.update_layout(height=400)
1171
+ st.plotly_chart(fig, use_container_width=True)
1172
+ else:
1173
+ st.info("πŸ“ˆ Upload data with date columns or categorical data to see trends.")
1174
+
1175
+ with tab4:
1176
+ st.markdown("#### 🎯 Custom Analysis Builder")
1177
+
1178
+ col1, col2 = st.columns([1, 2])
1179
+
1180
+ with col1:
1181
+ viz_type = st.selectbox(
1182
+ "Chart Type",
1183
+ ["Scatter Plot", "Bar Chart", "Pie Chart", "Sunburst", "Treemap"]
1184
+ )
1185
+
1186
+ if viz_type == "Scatter Plot" and len(numeric_cols) >= 2:
1187
+ x_col = st.selectbox("X-axis", numeric_cols, key="custom_x")
1188
+ y_col = st.selectbox("Y-axis", numeric_cols, key="custom_y")
1189
+ color_col = st.selectbox("Color by", ["None"] + list(df.columns), key="custom_color")
1190
+ size_col = st.selectbox("Size by", ["None"] + numeric_cols, key="custom_size")
1191
+
1192
+ elif viz_type in ["Bar Chart", "Pie Chart"] and cat_cols:
1193
+ cat_col = st.selectbox("Category", cat_cols, key="custom_cat")
1194
+ if numeric_cols:
1195
+ val_col = st.selectbox("Value (optional)", ["Count"] + numeric_cols, key="custom_val")
1196
+ else:
1197
+ val_col = "Count"
1198
+
1199
+ with col2:
1200
+ try:
1201
+ if viz_type == "Scatter Plot" and len(numeric_cols) >= 2:
1202
+ fig = px.scatter(
1203
+ df,
1204
+ x=x_col,
1205
+ y=y_col,
1206
+ color=None if color_col == "None" else color_col,
1207
+ size=None if size_col == "None" else size_col,
1208
+ title=f"{y_col} vs {x_col}",
1209
+ color_discrete_sequence=['#3b82f6'],
1210
+ hover_data=df.columns[:5].tolist()
1211
+ )
1212
+ fig.update_layout(height=500)
1213
+ st.plotly_chart(fig, use_container_width=True)
1214
+
1215
+ elif viz_type == "Pie Chart" and cat_cols:
1216
+ if val_col == "Count":
1217
+ value_counts = df[cat_col].value_counts().head(8)
1218
+ fig = px.pie(
1219
+ values=value_counts.values,
1220
+ names=value_counts.index,
1221
+ title=f"Distribution of {cat_col}"
1222
+ )
1223
+ else:
1224
+ grouped = df.groupby(cat_col)[val_col].sum().head(8)
1225
+ fig = px.pie(
1226
+ values=grouped.values,
1227
+ names=grouped.index,
1228
+ title=f"{val_col} by {cat_col}"
1229
+ )
1230
+ fig.update_layout(height=500)
1231
+ st.plotly_chart(fig, use_container_width=True)
1232
+
1233
+ except Exception as e:
1234
+ st.error(f"Error creating visualization: {str(e)}")
1235
+
1236
+ # Recommendations Section - Extract complete recommendations with headers and content combined
1237
+ st.markdown("### 🎯 AI-Generated Recommendations")
1238
+ recommendations = results.get('recommendations', [])
1239
+
1240
+ if recommendations:
1241
+ # Combine all recommendation text and parse properly
1242
+ full_text = ' '.join(str(item) for item in recommendations)
1243
+
1244
+ # Extract complete recommendations using regex
1245
+ import re
1246
+
1247
+ # Pattern to match recommendations (various formats)
1248
+ rec_patterns = [
1249
+ r'\*\*.*?(\d+):(.*?)(?=\*\*.*?\d+:|$)', # **Something 1:** format
1250
+ r'(\d+)\.\s+(.*?)(?=\d+\.|$)', # 1. format
1251
+ ]
1252
+
1253
+ processed_recommendations = []
1254
+ for pattern in rec_patterns:
1255
+ matches = re.findall(pattern, full_text, re.DOTALL)
1256
+ if matches:
1257
+ for match in matches:
1258
+ if len(match) == 2:
1259
+ rec_num, content = match
1260
+ clean_content = content.strip().rstrip('*')
1261
+ if len(clean_content) > 20:
1262
+ processed_recommendations.append(clean_content)
1263
+ break
1264
+
1265
+ # Take top 5 recommendations
1266
+ top_recommendations = processed_recommendations[:5]
1267
+
1268
+ if top_recommendations:
1269
+ st.markdown(f"**Top {len(top_recommendations)} actionable recommendations:**")
1270
+ st.markdown("<br>", unsafe_allow_html=True)
1271
+
1272
+ for i, rec in enumerate(top_recommendations):
1273
+ st.markdown(f"""
1274
+ <div class="recommendation-box animate-fade-in">
1275
+ <div style="display: flex; align-items: flex-start; gap: 1rem;">
1276
+ <div style="
1277
+ background: #22c55e;
1278
+ color: white;
1279
+ border-radius: 50%;
1280
+ width: 32px;
1281
+ height: 32px;
1282
+ display: flex;
1283
+ align-items: center;
1284
+ justify-content: center;
1285
+ font-weight: bold;
1286
+ font-size: 0.9rem;
1287
+ flex-shrink: 0;
1288
+ ">{i+1}</div>
1289
+ <div style="flex: 1;">
1290
+ <strong style="color: #1e293b;">🎯 Recommendation {i+1}:</strong><br>
1291
+ <span style="color: #475569; line-height: 1.6;">{rec}</span>
1292
+ </div>
1293
+ </div>
1294
+ </div>
1295
+ """, unsafe_allow_html=True)
1296
+ else:
1297
+ st.info("🎯 No recommendations could be extracted from the analysis.")
1298
+ else:
1299
+ st.info("🎯 No recommendations were generated.")
1300
+
1301
+ # Download Results Section
1302
+ st.markdown("### πŸ’Ύ Download Your Results")
1303
+
1304
+ col1, col2, col3 = st.columns(3)
1305
+
1306
+ download_items = [
1307
+ ("πŸ“„", "Analysis Report (JSON)", "Download complete analysis", "json"),
1308
+ ("πŸ“Š", "Enhanced Dataset (CSV)", "Download processed data", "csv"),
1309
+ ("πŸ“‹", "Executive Summary (MD)", "Download business report", "md")
1310
+ ]
1311
+
1312
+ for i, (icon, title, desc, file_type) in enumerate(download_items):
1313
+ with [col1, col2, col3][i]:
1314
+ st.markdown(f"""
1315
+ <div style="
1316
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
1317
+ border: 2px solid #e2e8f0;
1318
+ border-radius: 16px;
1319
+ padding: 1.5rem;
1320
+ text-align: center;
1321
+ margin: 0.5rem 0;
1322
+ transition: all 0.3s ease;
1323
+ ">
1324
+ <div style="font-size: 2.5rem; margin-bottom: 1rem;">{icon}</div>
1325
+ <div style="font-size: 1.1rem; font-weight: 600; margin-bottom: 0.5rem; color: #1e293b;">{title}</div>
1326
+ <div style="font-size: 0.9rem; color: #64748b; margin-bottom: 1rem;">{desc}</div>
1327
+ """, unsafe_allow_html=True)
1328
+
1329
+ if file_type == "json":
1330
+ data = json.dumps(results, indent=2, default=str)
1331
+ filename = f"analysis_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
1332
+ mime = "application/json"
1333
+ elif file_type == "csv":
1334
+ data = st.session_state.dataset.to_csv(index=False)
1335
+ filename = f"enhanced_dataset_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
1336
+ mime = "text/csv"
1337
+ else: # md
1338
+ data = generate_report(results)
1339
+ filename = f"executive_summary_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
1340
+ mime = "text/markdown"
1341
+
1342
+ st.download_button(
1343
+ label=f"Download {file_type.upper()}",
1344
+ data=data,
1345
+ file_name=filename,
1346
+ mime=mime,
1347
+ use_container_width=True
1348
+ )
1349
+
1350
+ st.markdown("</div>", unsafe_allow_html=True)
1351
+
1352
+ def generate_report(results):
1353
+ """Generate a beautiful markdown report"""
1354
+ filename = getattr(st.session_state, 'uploaded_filename', 'dataset')
1355
+
1356
+ report = f"""# πŸ€– AI Data Analysis Executive Summary
1357
+
1358
+ **Dataset:** {filename}
1359
+ **Generated:** {datetime.now().strftime('%B %d, %Y at %I:%M %p')}
1360
+ **Powered by:** Llama 3 & LangGraph AI Agents
1361
+
1362
+ ---
1363
+
1364
+ ## πŸ“Š Executive Overview
1365
+
1366
+ This report presents key findings from an AI-powered analysis of your dataset. Our advanced language models have identified patterns, trends, and opportunities that can drive business decisions.
1367
+
1368
+ ### Dataset Metrics
1369
+ - **Total Records:** {results.get('dataset_info', {}).get('shape', [0])[0]:,}
1370
+ - **Data Points:** {len(results.get('dataset_info', {}).get('columns', []))}
1371
+ - **Data Quality Score:** {max(0, 100 - (sum(results.get('dataset_info', {}).get('null_counts', {}).values()) / max(results.get('dataset_info', {}).get('shape', [1, 1])[0] * results.get('dataset_info', {}).get('shape', [1, 1])[1], 1) * 100)):.0f}%
1372
+
1373
+ ---
1374
+
1375
+ ## πŸ’‘ Strategic Insights
1376
+
1377
+ Our AI analysis has uncovered the following key insights:
1378
+
1379
+ """
1380
+
1381
+ insights = results.get('insights', [])
1382
+ if insights:
1383
+ for i, insight in enumerate(insights, 1):
1384
+ report += f"**{i}.** {insight}\n\n"
1385
+ else:
1386
+ report += "*No specific insights were generated for this dataset.*\n\n"
1387
+
1388
+ report += """---
1389
+
1390
+ ## 🎯 Recommended Actions
1391
+
1392
+ Based on the data analysis, we recommend the following strategic actions:
1393
+
1394
+ """
1395
+
1396
+ recommendations = results.get('recommendations', [])
1397
+ if recommendations:
1398
+ for i, rec in enumerate(recommendations, 1):
1399
+ report += f"**{i}.** {rec}\n\n"
1400
+ else:
1401
+ report += "*No specific recommendations were generated for this dataset.*\n\n"
1402
+
1403
+ report += f"""---
1404
+
1405
+ ## πŸ”§ Technical Summary
1406
+
1407
+ - **Analysis Completed:** {results.get('analysis_timestamp', 'N/A')}
1408
+ - **Visualizations Created:** {len(results.get('visualizations', []))}
1409
+ - **Processing Errors:** {len(results.get('errors', []))}
1410
+ - **AI Model Used:** Llama 3 (70B parameters)
1411
+
1412
+ ---
1413
+
1414
+ ## πŸ“ˆ Next Steps
1415
+
1416
+ 1. **Review Insights:** Analyze each insight for immediate actionable opportunities
1417
+ 2. **Implement Recommendations:** Prioritize recommendations based on business impact
1418
+ 3. **Monitor Progress:** Track key metrics identified in this analysis
1419
+ 4. **Iterate:** Regular re-analysis as new data becomes available
1420
+
1421
+ ---
1422
+
1423
+ *This report was generated automatically by our AI Data Analysis Agent. For questions or support, please contact your data team.*
1424
+ """
1425
+
1426
+ return report
1427
+
1428
+ def main():
1429
+ """Main application function with beautiful design"""
1430
+ initialize_session_state()
1431
+
1432
+ # Check if analysis is complete to show results immediately
1433
+ if st.session_state.analysis_complete and st.session_state.analysis_results:
1434
+ display_results()
1435
+
1436
+ # Add a "Start New Analysis" button
1437
+ st.markdown("---")
1438
+ col1, col2, col3 = st.columns([1, 1, 1])
1439
+ with col2:
1440
+ if st.button("πŸ”„ Start New Analysis", use_container_width=True):
1441
+ # Reset session state
1442
+ st.session_state.analysis_results = None
1443
+ st.session_state.analysis_complete = False
1444
+ st.session_state.dataset = None
1445
+ st.rerun()
1446
+ return
1447
+
1448
+ # Hero Section
1449
+ display_hero_section()
1450
+
1451
+ # Feature showcase
1452
+ display_features()
1453
+
1454
+ # Sidebar configuration
1455
+ api_configured = sidebar_config()
1456
+
1457
+ if not api_configured:
1458
+ # Beautiful warning with setup instructions
1459
+ st.markdown("""
1460
+ <div style="
1461
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
1462
+ border: 2px solid #f59e0b;
1463
+ border-radius: 16px;
1464
+ padding: 2rem;
1465
+ margin: 2rem 0;
1466
+ text-align: center;
1467
+ ">
1468
+ <div style="font-size: 3rem; margin-bottom: 1rem;">πŸ”‘</div>
1469
+ <h3 style="color: #92400e; margin-bottom: 1rem;">API Key Required</h3>
1470
+ <p style="color: #78350f; margin-bottom: 1.5rem;">
1471
+ Please configure your Groq API key to unlock the power of AI analysis
1472
+ </p>
1473
+ </div>
1474
+ """, unsafe_allow_html=True)
1475
+
1476
+ # Expandable setup guide
1477
+ with st.expander("πŸš€ Quick Setup Guide", expanded=True):
1478
+ st.markdown("""
1479
+ ### Option 1: Environment Variable (Recommended)
1480
+ ```bash
1481
+ export GROQ_API_KEY="your_api_key_here"
1482
+ streamlit run web_app.py
1483
+ ```
1484
+
1485
+ ### Option 2: Manual Entry
1486
+ 1. Visit [Groq Console](https://console.groq.com/) πŸ”—
1487
+ 2. Create a free account and generate your API key
1488
+ 3. Enter the key in the sidebar ←
1489
+ 4. Upload your dataset and start analyzing!
1490
+
1491
+ ### Supported File Formats
1492
+ - **CSV files** (.csv) - Most common format
1493
+ - **Excel files** (.xlsx, .xls) - Spreadsheet data
1494
+ - **JSON files** (.json) - Structured data
1495
+
1496
+ ### Tips for Best Results
1497
+ - Ensure clean, well-structured data
1498
+ - Include meaningful column names
1499
+ - Mix of numeric and categorical columns works best
1500
+ - Date/time columns enable trend analysis
1501
+ """)
1502
+ return
1503
+
1504
+ # Main content area with beautiful layout
1505
+ st.markdown("---")
1506
+
1507
+ # Dataset upload section
1508
+ dataset_uploaded = upload_dataset()
1509
+
1510
+ # Analysis section
1511
+ if dataset_uploaded:
1512
+ st.markdown("---")
1513
+
1514
+ # Center the analyze button with beautiful styling
1515
+ col1, col2, col3 = st.columns([1, 2, 1])
1516
+ with col2:
1517
+ if st.button(
1518
+ "πŸš€ Analyze My Data with AI",
1519
+ type="primary",
1520
+ use_container_width=True,
1521
+ help="Start the AI-powered analysis of your dataset"
1522
+ ):
1523
+ run_analysis()
1524
+
1525
+ # Footer
1526
+ st.markdown("""
1527
+ <div class="footer">
1528
+ <div style="max-width: 800px; margin: 0 auto;">
1529
+ <div style="font-size: 1.5rem; margin-bottom: 1rem;">πŸ€–βœ¨</div>
1530
+ <p style="margin-bottom: 1rem;">
1531
+ <strong>AI Data Analysis Agent</strong> - Transform your data into actionable insights
1532
+ </p>
1533
+ <p style="font-size: 0.85rem; margin-bottom: 1rem;">
1534
+ Powered by <strong>Llama 3</strong> β€’ Built with <strong>LangGraph</strong> β€’
1535
+ Designed with <strong>Streamlit</strong>
1536
+ </p>
1537
+ <div style="display: flex; justify-content: center; gap: 2rem; font-size: 0.9rem;">
1538
+ <a href="#" style="color: #3b82f6; text-decoration: none;">πŸ“– Documentation</a>
1539
+ <a href="#" style="color: #3b82f6; text-decoration: none;">πŸ› Report Issues</a>
1540
+ <a href="#" style="color: #3b82f6; text-decoration: none;">⭐ Give Feedback</a>
1541
+ <a href="#" style="color: #3b82f6; text-decoration: none;">πŸ’‘ Feature Requests</a>
1542
+ </div>
1543
+ </div>
1544
+ </div>
1545
+ """, unsafe_allow_html=True)
1546
+
1547
+ if __name__ == "__main__":
1548
+ main()