pranit144 commited on
Commit
7741de0
·
verified ·
1 Parent(s): 4bbb5ff

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +477 -0
  2. templates/index.html +969 -0
  3. templates/result.html +438 -0
app.py ADDED
@@ -0,0 +1,477 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request
2
+ import matplotlib
3
+
4
+ matplotlib.use('Agg')
5
+ import matplotlib.pyplot as plt
6
+ import io
7
+ import base64
8
+ import pandas as pd
9
+ import google.generativeai as genai
10
+ import os
11
+ from docx import Document
12
+ import plotly.express as px
13
+ import plotly.io as pio
14
+
15
+ app = Flask(__name__)
16
+ app.config['UPLOAD_FOLDER'] = 'uploads'
17
+ app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
18
+
19
+ # Configure Gemini API
20
+ GOOGLE_API_KEY = 'AIzaSyBLcWuSj6N1bkhQsTF4kt3_hFh4ibH11pQ' # Replace with your actual API key
21
+ genai.configure(api_key=GOOGLE_API_KEY)
22
+ model = genai.GenerativeModel('gemini-2.0-flash')
23
+
24
+
25
+ def ensure_upload_folder():
26
+ if not os.path.exists(app.config['UPLOAD_FOLDER']):
27
+ os.makedirs(app.config['UPLOAD_FOLDER'])
28
+
29
+
30
+ def extract_text_from_docx(file_path):
31
+ doc = Document(file_path)
32
+ full_text = []
33
+ for paragraph in doc.paragraphs:
34
+ full_text.append(paragraph.text)
35
+ return '\n'.join(full_text)
36
+
37
+
38
+ def extract_data_using_gemini(text):
39
+ prompt = """
40
+ Extract the event counts from the following table format in the text:
41
+
42
+ 2022-2023
43
+ Cultural competitions/events: NUMBER
44
+ Sports competitions/events: NUMBER
45
+ Technical fest/Academic fest: NUMBER
46
+ Social activities/events: NUMBER
47
+ Any other events through Active clubs and forums: NUMBER
48
+
49
+ 2021-2022
50
+ Cultural competitions/events: NUMBER
51
+ Sports competitions/events: NUMBER
52
+ Technical fest/Academic fest: NUMBER
53
+ Social activities/events: NUMBER
54
+ Any other events through Active clubs and forums: NUMBER
55
+
56
+ 2020-2021
57
+ Cultural competitions/events: NUMBER
58
+ Sports competitions/events: NUMBER
59
+ Technical fest/Academic fest: NUMBER
60
+ Social activities/events: NUMBER
61
+ Any other events through Active clubs and forums: NUMBER
62
+
63
+ 2019-2020
64
+ Cultural competitions/events: NUMBER
65
+ Sports competitions/events: NUMBER
66
+ Technical fest/Academic fest: NUMBER
67
+ Social activities/events: NUMBER
68
+ Any other events through Active clubs and forums: NUMBER
69
+
70
+ 2018-2019
71
+ Cultural competitions/events: NUMBER
72
+ Sports competitions/events: NUMBER
73
+ Technical fest/Academic fest: NUMBER
74
+ Social activities/events: NUMBER
75
+ Any other events through Active clubs and forums: NUMBER
76
+
77
+ Look for these exact numbers in the text. The data appears in a table with years and categories.
78
+ For each year, find:
79
+ - Number of Cultural competitions/events
80
+ - Number of Sports competitions/events
81
+ - Number of Technical fest/Academic fest events
82
+ - Number of Social activities/events
83
+ - Number of "Any other events through Active clubs and forums"
84
+
85
+ Return the data in this exact Python dictionary format:
86
+ {
87
+ '2022-2023': {'Cultural': 11, 'Sports': 10, 'Technical': 29, 'Social': 15, 'Other': 20},
88
+ '2021-2022': {'Cultural': 7, 'Sports': 8, 'Technical': 13, 'Social': 12, 'Other': 15},
89
+ '2020-2021': {'Cultural': 7, 'Sports': 9, 'Technical': 15, 'Social': 10, 'Other': 17},
90
+ '2019-2020': {'Cultural': 12, 'Sports': 17, 'Technical': 21, 'Social': 14, 'Other': 11},
91
+ '2018-2019': {'Cultural': 8, 'Sports': 17, 'Technical': 15, 'Social': 11, 'Other': 9}
92
+ }
93
+
94
+ Important:
95
+ - Use the EXACT numbers from the document
96
+ - Include ALL years from 2018-2019 to 2022-2023
97
+ - Make sure to find the correct table in the document that has these numbers
98
+ - Return only the Python dictionary, no other text
99
+ """
100
+
101
+ try:
102
+ # Print the first part of the text for debugging
103
+ print("\nSearching in text:")
104
+ print("=" * 50)
105
+ # Look for specific patterns in text
106
+ import re
107
+ years = re.findall(r'(20\d{2}-20\d{2})', text)
108
+ print(f"Found years: {years}")
109
+
110
+ # Look for numbers near key terms
111
+ cultural = re.findall(r'Cultural competitions/events\s*(\d+)', text)
112
+ sports = re.findall(r'Sports competitions/events\s*(\d+)', text)
113
+ technical = re.findall(r'Technical fest/Academic fest\s*(\d+)', text)
114
+ other = re.findall(r'Any other events.*?(\d+)', text)
115
+ social = re.findall(r'Social activities/events\s*(\d+)', text)
116
+
117
+ print(f"Found cultural numbers: {cultural}")
118
+ print(f"Found sports numbers: {sports}")
119
+ print(f"Found technical numbers: {technical}")
120
+ print(f"Found other numbers: {other}")
121
+ print(f"Found social numbers: {social}")
122
+ print("=" * 50)
123
+
124
+ response = model.generate_content(text + "\n" + prompt)
125
+ response_text = response.text.strip()
126
+
127
+ # Debug print
128
+ print("Raw response:", response_text)
129
+
130
+ # Remove any markdown formatting
131
+ if '' in response_text:
132
+ response_text = response_text.split('')[1]
133
+ if 'python' in response_text.split('\n')[0]:
134
+ response_text = '\n'.join(response_text.split('\n')[1:])
135
+
136
+ # Clean the response text
137
+ response_text = response_text.strip()
138
+ print("Cleaned response:", response_text)
139
+
140
+ # Parse the response
141
+ try:
142
+ import ast
143
+ data = ast.literal_eval(response_text)
144
+ except:
145
+ # Fallback to JSON parsing if ast fails
146
+ response_text = response_text.replace("'", '"')
147
+ import json
148
+ data = json.loads(response_text)
149
+
150
+ # Validate data structure
151
+ if not isinstance(data, dict):
152
+ raise ValueError("Response is not a dictionary")
153
+
154
+ # Ensure all years are present
155
+ expected_years = ['2022-2023', '2021-2022', '2020-2021', '2019-2020', '2018-2019']
156
+ if not all(year in data for year in expected_years):
157
+ raise ValueError("Missing some years in the data")
158
+
159
+ # Ensure all categories are present for each year
160
+ required_categories = {'Cultural', 'Sports', 'Technical', 'Social', 'Other'}
161
+ for year in data:
162
+ if not all(cat in data[year] for cat in required_categories):
163
+ raise ValueError(f"Missing categories in year {year}")
164
+
165
+ return data
166
+
167
+ except Exception as e:
168
+ print(f"Error processing with Gemini: {str(e)}")
169
+ print(f"Response text was: {response_text if 'response_text' in locals() else 'No response text'}")
170
+ return None
171
+
172
+
173
+ def get_graph_insights(data, plot_type):
174
+ """Generate detailed insights including SWOT analysis for different types of plots."""
175
+ df = pd.DataFrame(data).T
176
+
177
+ if plot_type == 'bar':
178
+ total_by_category = df.sum()
179
+ max_category = total_by_category.idxmax()
180
+ min_category = total_by_category.idxmin()
181
+ avg_events = total_by_category.mean()
182
+
183
+ insights = {
184
+ 'main_insight': f"The most frequent event category overall is {max_category} with {int(total_by_category[max_category])} events, while {min_category} has the least with {int(total_by_category[min_category])} events.",
185
+ 'swot': {
186
+ 'strengths': [
187
+ f"Strong performance in {max_category} events",
188
+ f"Diverse range of events across categories",
189
+ f"Average of {avg_events:.1f} events per category"
190
+ ],
191
+ 'weaknesses': [
192
+ f"Low participation in {min_category} events",
193
+ f"Uneven distribution across categories",
194
+ "Potential resource allocation issues"
195
+ ],
196
+ 'opportunities': [
197
+ f"Room for growth in {min_category} category",
198
+ "Potential for cross-category events",
199
+ "Scope for balanced development"
200
+ ],
201
+ 'threats': [
202
+ "Risk of over-dependence on dominant category",
203
+ "Resource strain in peak periods",
204
+ "Sustainability challenges"
205
+ ]
206
+ },
207
+ 'recommendations': [
208
+ f"Consider boosting {min_category} events",
209
+ "Implement balanced resource allocation",
210
+ "Develop cross-category initiatives"
211
+ ]
212
+ }
213
+ return insights
214
+
215
+ elif plot_type == 'pie':
216
+ latest_year = '2022-2023'
217
+ year_data = data[latest_year]
218
+ total = sum(year_data.values())
219
+ max_cat = max(year_data.items(), key=lambda x: x[1])
220
+ min_cat = min(year_data.items(), key=lambda x: x[1])
221
+ percentage = (max_cat[1] / total) * 100
222
+
223
+ insights = {
224
+ 'main_insight': f"In {latest_year}, {max_cat[0]} events dominated with {max_cat[1]} events ({percentage:.1f}% of total events).",
225
+ 'swot': {
226
+ 'strengths': [
227
+ f"Strong presence in {max_cat[0]} category",
228
+ "Clear category leadership",
229
+ "Established event structure"
230
+ ],
231
+ 'weaknesses': [
232
+ f"Under-representation in {min_cat[0]} category",
233
+ "Imbalanced distribution",
234
+ "Resource concentration risks"
235
+ ],
236
+ 'opportunities': [
237
+ "Potential for category diversification",
238
+ "Growth in underserved categories",
239
+ "New event type development"
240
+ ],
241
+ 'threats': [
242
+ "Category saturation risk",
243
+ "Resource allocation challenges",
244
+ "Sustainability concerns"
245
+ ]
246
+ },
247
+ 'recommendations': [
248
+ "Diversify event portfolio",
249
+ f"Strengthen {min_cat[0]} category",
250
+ "Implement balanced growth strategy"
251
+ ]
252
+ }
253
+ return insights
254
+
255
+ elif plot_type == 'line':
256
+ trend = "increasing" if df.iloc[-1].mean() > df.iloc[0].mean() else "decreasing"
257
+ growth_rate = ((df.iloc[-1].mean() - df.iloc[0].mean()) / df.iloc[0].mean() * 100)
258
+
259
+ insights = {
260
+ 'main_insight': f"The overall trend shows a {trend} pattern with a {growth_rate:.1f}% change in event frequency over the years.",
261
+ 'swot': {
262
+ 'strengths': [
263
+ f"Consistent {trend} trend",
264
+ "Clear growth trajectory",
265
+ "Established pattern"
266
+ ],
267
+ 'weaknesses': [
268
+ "Fluctuations in growth rate",
269
+ "Periodic inconsistencies",
270
+ "Resource scaling challenges"
271
+ ],
272
+ 'opportunities': [
273
+ "Growth optimization potential",
274
+ "Pattern regularization",
275
+ "Strategic planning possibilities"
276
+ ],
277
+ 'threats': [
278
+ "Sustainability of growth rate",
279
+ "Resource management challenges",
280
+ "Market saturation risks"
281
+ ]
282
+ },
283
+ 'recommendations': [
284
+ "Develop sustainable growth plan",
285
+ "Implement resource scaling strategy",
286
+ "Monitor growth patterns"
287
+ ]
288
+ }
289
+ return insights
290
+
291
+ elif plot_type == 'growth':
292
+ growth_rates = df.pct_change() * 100
293
+ avg_growth = growth_rates.mean().mean()
294
+ max_growth = growth_rates.max().max()
295
+ min_growth = growth_rates.min().min()
296
+
297
+ insights = {
298
+ 'main_insight': f"The average year-over-year growth rate is {avg_growth:.1f}%, with peaks of {max_growth:.1f}% and lows of {min_growth:.1f}%.",
299
+ 'swot': {
300
+ 'strengths': [
301
+ "Positive average growth rate",
302
+ "Strong peak performance periods",
303
+ "Growth momentum"
304
+ ],
305
+ 'weaknesses': [
306
+ "Growth rate volatility",
307
+ "Negative growth periods",
308
+ "Inconsistent patterns"
309
+ ],
310
+ 'opportunities': [
311
+ "Growth stabilization potential",
312
+ "Performance optimization",
313
+ "Strategic growth planning"
314
+ ],
315
+ 'threats': [
316
+ "Growth sustainability",
317
+ "Resource scaling challenges",
318
+ "Market fluctuations"
319
+ ]
320
+ },
321
+ 'recommendations': [
322
+ "Stabilize growth patterns",
323
+ "Develop contingency plans",
324
+ "Implement growth monitoring"
325
+ ]
326
+ }
327
+ return insights
328
+
329
+ elif plot_type == 'area':
330
+ total_growth = ((df.iloc[-1].sum() - df.iloc[0].sum()) / df.iloc[0].sum() * 100)
331
+ avg_yearly_growth = total_growth / (len(df) - 1)
332
+
333
+ insights = {
334
+ 'main_insight': f"The cumulative events show a {total_growth:.1f}% total change, averaging {avg_yearly_growth:.1f}% yearly growth.",
335
+ 'swot': {
336
+ 'strengths': [
337
+ "Consistent cumulative growth",
338
+ "Strong overall trajectory",
339
+ "Clear progress pattern"
340
+ ],
341
+ 'weaknesses': [
342
+ "Growth rate variations",
343
+ "Resource scaling challenges",
344
+ "Potential sustainability issues"
345
+ ],
346
+ 'opportunities': [
347
+ "Long-term growth potential",
348
+ "Pattern optimization",
349
+ "Strategic expansion"
350
+ ],
351
+ 'threats': [
352
+ "Scaling challenges",
353
+ "Resource constraints",
354
+ "Market saturation"
355
+ ]
356
+ },
357
+ 'recommendations': [
358
+ "Develop long-term growth strategy",
359
+ "Implement resource planning",
360
+ "Monitor cumulative trends"
361
+ ]
362
+ }
363
+ return insights
364
+
365
+ return {
366
+ 'main_insight': "No specific insights available for this visualization.",
367
+ 'swot': {
368
+ 'strengths': [],
369
+ 'weaknesses': [],
370
+ 'opportunities': [],
371
+ 'threats': []
372
+ },
373
+ 'recommendations': []
374
+ }
375
+
376
+
377
+ def create_plots(data):
378
+ plots = {}
379
+ df = pd.DataFrame(data).T
380
+
381
+ # Bar Chart
382
+ fig1 = px.bar(df, barmode='group', title='Events Distribution Across Years')
383
+ plots['bar'] = {
384
+ 'plot': pio.to_html(fig1, full_html=False),
385
+ 'insight': get_graph_insights(data, 'bar')
386
+ }
387
+
388
+ # Pie Chart
389
+ latest_year = '2022-2023'
390
+ fig2 = px.pie(names=data[latest_year].keys(), values=data[latest_year].values(),
391
+ title=f'Event Distribution for {latest_year}')
392
+ plots['pie'] = {
393
+ 'plot': pio.to_html(fig2, full_html=False),
394
+ 'insight': get_graph_insights(data, 'pie')
395
+ }
396
+
397
+ # Line Chart
398
+ fig3 = px.line(df, markers=True, title='Event Trends Over Years')
399
+ plots['line'] = {
400
+ 'plot': pio.to_html(fig3, full_html=False),
401
+ 'insight': get_graph_insights(data, 'line')
402
+ }
403
+
404
+ # Growth Rate Chart
405
+ growth_rates = df.pct_change() * 100
406
+ fig4 = px.bar(growth_rates, title='Year-over-Year Growth Rate by Category')
407
+ plots['growth'] = {
408
+ 'plot': pio.to_html(fig4, full_html=False),
409
+ 'insight': get_graph_insights(data, 'growth')
410
+ }
411
+
412
+ # Area Chart
413
+ fig5 = px.area(df, title='Cumulative Events Distribution')
414
+ plots['area'] = {
415
+ 'plot': pio.to_html(fig5, full_html=False),
416
+ 'insight': get_graph_insights(data, 'area')
417
+ }
418
+
419
+ # Statistical Analysis
420
+ stats = {
421
+ 'total_events': df.sum().sum(),
422
+ 'avg_events_per_year': df.sum(axis=1).mean().round(2),
423
+ 'most_active_year': df.sum(axis=1).idxmax(),
424
+ 'most_common_category': df.sum().idxmax(),
425
+ 'growth_analysis': {
426
+ 'total_growth': ((df.iloc[-1].sum() - df.iloc[0].sum()) / df.iloc[0].sum() * 100).round(2),
427
+ 'category_growth': ((df.iloc[-1] - df.iloc[0]) / df.iloc[0] * 100).round(2).to_dict()
428
+ }
429
+ }
430
+ plots['stats'] = stats
431
+
432
+ return plots
433
+
434
+
435
+ @app.route('/', methods=['GET', 'POST'])
436
+ def index():
437
+ plots = None
438
+ error_message = None
439
+
440
+ if request.method == 'POST':
441
+ if 'document' not in request.files:
442
+ error_message = 'No file uploaded'
443
+ return render_template('index.html', error=error_message)
444
+
445
+ file = request.files['document']
446
+ if file.filename == '':
447
+ error_message = 'No file selected'
448
+ return render_template('index.html', error=error_message)
449
+
450
+ if file and file.filename.endswith('.docx'):
451
+ ensure_upload_folder()
452
+ file_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
453
+ file.save(file_path)
454
+
455
+ try:
456
+ text = extract_text_from_docx(file_path)
457
+ data = extract_data_using_gemini(text)
458
+ print("Extracted data:", data)
459
+
460
+ if data:
461
+ plots = create_plots(data)
462
+ else:
463
+ error_message = 'Could not extract data from document. Please check the document format.'
464
+
465
+ os.remove(file_path)
466
+
467
+ except Exception as e:
468
+ error_message = f'Error processing document: {str(e)}'
469
+ print(f"Full error: {str(e)}")
470
+ else:
471
+ error_message = 'Please upload a .docx file'
472
+
473
+ return render_template('index.html', plots=plots, error=error_message)
474
+
475
+
476
+ if __name__ == '__main__':
477
+ app.run(debug=True, port=5001)
templates/index.html ADDED
@@ -0,0 +1,969 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Event Analysis Dashboard</title>
7
+ <!-- Bootstrap CSS -->
8
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
9
+ <!-- Custom CSS -->
10
+ <style>
11
+ /* Dynamic Animations */
12
+ @keyframes float {
13
+ 0%, 100% { transform: translateY(0px); }
14
+ 50% { transform: translateY(-10px); }
15
+ }
16
+
17
+ @keyframes glow {
18
+ 0%, 100% { box-shadow: 0 0 20px rgba(147, 51, 234, 0.4); }
19
+ 50% { box-shadow: 0 0 40px rgba(147, 51, 234, 0.8), 0 0 60px rgba(147, 51, 234, 0.4); }
20
+ }
21
+
22
+ @keyframes slideIn {
23
+ 0% { transform: translateX(-100%); opacity: 0; }
24
+ 100% { transform: translateX(0); opacity: 1; }
25
+ }
26
+
27
+ @keyframes pulse {
28
+ 0% { transform: scale(1); }
29
+ 50% { transform: scale(1.05); }
30
+ 100% { transform: scale(1); }
31
+ }
32
+
33
+ @keyframes shimmer {
34
+ 0% { background-position: -200% 0; }
35
+ 100% { background-position: 200% 0; }
36
+ }
37
+
38
+ @keyframes rotate {
39
+ 0% { transform: rotate(0deg); }
40
+ 100% { transform: rotate(360deg); }
41
+ }
42
+
43
+ /* Base Styles */
44
+ * {
45
+ margin: 0;
46
+ padding: 0;
47
+ box-sizing: border-box;
48
+ }
49
+
50
+ body {
51
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 25%, #f093fb 50%, #f5576c 75%, #4facfe 100%);
52
+ background-size: 400% 400%;
53
+ animation: gradientShift 15s ease infinite;
54
+ font-family: 'Arial', sans-serif;
55
+ padding-top: 2rem;
56
+ min-height: 100vh;
57
+ position: relative;
58
+ overflow-x: hidden;
59
+ }
60
+
61
+ @keyframes gradientShift {
62
+ 0% { background-position: 0% 50%; }
63
+ 50% { background-position: 100% 50%; }
64
+ 100% { background-position: 0% 50%; }
65
+ }
66
+
67
+ /* Floating particles background */
68
+ body::before {
69
+ content: '';
70
+ position: fixed;
71
+ top: 0;
72
+ left: 0;
73
+ width: 100%;
74
+ height: 100%;
75
+ background:
76
+ radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
77
+ radial-gradient(circle at 80% 80%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
78
+ radial-gradient(circle at 40% 60%, rgba(255, 255, 255, 0.05) 0%, transparent 50%);
79
+ animation: float 8s ease-in-out infinite;
80
+ pointer-events: none;
81
+ z-index: -1;
82
+ }
83
+
84
+ /* Chart Container */
85
+ .chart-container {
86
+ background: rgba(255, 255, 255, 0.95);
87
+ backdrop-filter: blur(20px);
88
+ border-radius: 20px;
89
+ border: 2px solid rgba(255, 255, 255, 0.3);
90
+ box-shadow:
91
+ 0 20px 40px rgba(0, 0, 0, 0.1),
92
+ 0 10px 20px rgba(0, 0, 0, 0.05),
93
+ inset 0 1px 0 rgba(255, 255, 255, 0.8);
94
+ padding: 30px;
95
+ margin-bottom: 30px;
96
+ position: relative;
97
+ overflow: hidden;
98
+ animation: slideIn 0.8s ease-out;
99
+ transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
100
+ }
101
+
102
+ .chart-container::before {
103
+ content: '';
104
+ position: absolute;
105
+ top: 0;
106
+ left: -100%;
107
+ width: 100%;
108
+ height: 100%;
109
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
110
+ animation: shimmer 3s infinite;
111
+ }
112
+
113
+ .chart-container:hover {
114
+ transform: translateY(-10px) scale(1.02);
115
+ box-shadow:
116
+ 0 30px 60px rgba(0, 0, 0, 0.15),
117
+ 0 15px 30px rgba(0, 0, 0, 0.1),
118
+ inset 0 1px 0 rgba(255, 255, 255, 0.9);
119
+ }
120
+
121
+ /* Stats Card */
122
+ .stats-card {
123
+ height: 100%;
124
+ background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
125
+ color: white;
126
+ border-radius: 15px;
127
+ padding: 20px;
128
+ position: relative;
129
+ overflow: hidden;
130
+ transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
131
+ animation: pulse 3s ease-in-out infinite;
132
+ }
133
+
134
+ .stats-card::before {
135
+ content: '';
136
+ position: absolute;
137
+ top: -50%;
138
+ left: -50%;
139
+ width: 200%;
140
+ height: 200%;
141
+ background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
142
+ animation: rotate 10s linear infinite;
143
+ }
144
+
145
+ .stats-card:hover {
146
+ transform: translateY(-15px) rotate(2deg);
147
+ box-shadow:
148
+ 0 25px 50px rgba(238, 90, 36, 0.4),
149
+ 0 12px 24px rgba(238, 90, 36, 0.2);
150
+ animation: glow 2s ease-in-out infinite;
151
+ }
152
+
153
+ .stats-card:nth-child(even) {
154
+ background: linear-gradient(135deg, #4ecdc4 0%, #44a08d 100%);
155
+ }
156
+
157
+ .stats-card:nth-child(3n) {
158
+ background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
159
+ color: #333;
160
+ }
161
+
162
+ /* Upload Section */
163
+ .upload-section {
164
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
165
+ background-size: 300% 300%;
166
+ animation: gradientShift 8s ease infinite;
167
+ color: white;
168
+ padding: 4rem 0;
169
+ margin-bottom: 2rem;
170
+ position: relative;
171
+ overflow: hidden;
172
+ }
173
+
174
+ .upload-section::before {
175
+ content: '';
176
+ position: absolute;
177
+ top: 0;
178
+ left: 0;
179
+ right: 0;
180
+ bottom: 0;
181
+ background:
182
+ radial-gradient(circle at 25% 25%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
183
+ radial-gradient(circle at 75% 75%, rgba(255, 255, 255, 0.1) 0%, transparent 50%);
184
+ animation: float 6s ease-in-out infinite reverse;
185
+ }
186
+
187
+ /* Drop Zone */
188
+ .drop-zone {
189
+ border: 3px dashed rgba(255, 255, 255, 0.6);
190
+ border-radius: 20px;
191
+ padding: 3rem;
192
+ text-align: center;
193
+ transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
194
+ background: rgba(255, 255, 255, 0.1);
195
+ backdrop-filter: blur(10px);
196
+ cursor: pointer;
197
+ position: relative;
198
+ overflow: hidden;
199
+ animation: pulse 4s ease-in-out infinite;
200
+ }
201
+
202
+ .drop-zone::before {
203
+ content: '';
204
+ position: absolute;
205
+ top: 0;
206
+ left: 0;
207
+ right: 0;
208
+ bottom: 0;
209
+ background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.1) 50%, transparent 70%);
210
+ transform: translateX(-100%);
211
+ transition: transform 0.6s ease;
212
+ }
213
+
214
+ .drop-zone:hover::before {
215
+ transform: translateX(100%);
216
+ }
217
+
218
+ .drop-zone:hover {
219
+ transform: scale(1.05);
220
+ background: rgba(255, 255, 255, 0.2);
221
+ border-color: rgba(255, 255, 255, 0.9);
222
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
223
+ }
224
+
225
+ .drop-zone.dragover {
226
+ background: rgba(255, 255, 255, 0.3);
227
+ border-color: #fff;
228
+ transform: scale(1.1);
229
+ animation: glow 1s ease-in-out infinite;
230
+ }
231
+
232
+ .drop-zone-content {
233
+ color: white;
234
+ position: relative;
235
+ z-index: 2;
236
+ font-weight: 600;
237
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
238
+ }
239
+
240
+ .upload-icon {
241
+ width: 60px;
242
+ height: 60px;
243
+ filter: invert(1) drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
244
+ animation: float 3s ease-in-out infinite;
245
+ margin-bottom: 1rem;
246
+ }
247
+
248
+ .selected-file {
249
+ margin-top: 1rem;
250
+ color: #fff;
251
+ font-weight: bold;
252
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
253
+ animation: slideIn 0.5s ease-out;
254
+ }
255
+
256
+ /* Print Button */
257
+ .print-btn {
258
+ position: fixed;
259
+ bottom: 30px;
260
+ right: 30px;
261
+ z-index: 1000;
262
+ background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 50%, #ff9ff3 100%);
263
+ background-size: 200% 200%;
264
+ animation: gradientShift 3s ease infinite;
265
+ color: white;
266
+ border: none;
267
+ padding: 15px 30px;
268
+ border-radius: 50px;
269
+ box-shadow:
270
+ 0 10px 30px rgba(238, 90, 36, 0.4),
271
+ 0 5px 15px rgba(238, 90, 36, 0.2);
272
+ transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
273
+ font-weight: 600;
274
+ font-size: 16px;
275
+ text-transform: uppercase;
276
+ letter-spacing: 1px;
277
+ cursor: pointer;
278
+ position: relative;
279
+ overflow: hidden;
280
+ }
281
+
282
+ .print-btn::before {
283
+ content: '';
284
+ position: absolute;
285
+ top: 0;
286
+ left: -100%;
287
+ width: 100%;
288
+ height: 100%;
289
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
290
+ transition: left 0.5s ease;
291
+ }
292
+
293
+ .print-btn:hover::before {
294
+ left: 100%;
295
+ }
296
+
297
+ .print-btn:hover {
298
+ transform: translateY(-5px) scale(1.05);
299
+ box-shadow:
300
+ 0 20px 50px rgba(238, 90, 36, 0.5),
301
+ 0 10px 25px rgba(238, 90, 36, 0.3);
302
+ animation: glow 2s ease-in-out infinite;
303
+ }
304
+
305
+ .print-btn:active {
306
+ transform: translateY(-2px) scale(0.98);
307
+ }
308
+
309
+ /* Additional Enhancements */
310
+ .neon-text {
311
+ color: #fff;
312
+ text-shadow:
313
+ 0 0 5px currentColor,
314
+ 0 0 10px currentColor,
315
+ 0 0 15px currentColor,
316
+ 0 0 20px #ff6b6b,
317
+ 0 0 35px #ff6b6b,
318
+ 0 0 40px #ff6b6b;
319
+ animation: pulse 2s ease-in-out infinite alternate;
320
+ }
321
+
322
+ .glass-effect {
323
+ background: rgba(255, 255, 255, 0.25);
324
+ backdrop-filter: blur(20px);
325
+ border: 1px solid rgba(255, 255, 255, 0.18);
326
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
327
+ }
328
+
329
+ /* Mobile Responsiveness */
330
+ @media (max-width: 768px) {
331
+ .chart-container {
332
+ padding: 20px;
333
+ margin-bottom: 20px;
334
+ }
335
+
336
+ .upload-section {
337
+ padding: 2rem 0;
338
+ }
339
+
340
+ .drop-zone {
341
+ padding: 2rem;
342
+ }
343
+
344
+ .print-btn {
345
+ bottom: 20px;
346
+ right: 20px;
347
+ padding: 12px 24px;
348
+ }
349
+ }
350
+
351
+ /* Demo Content */
352
+ .demo-content {
353
+ max-width: 1200px;
354
+ margin: 0 auto;
355
+ padding: 20px;
356
+ }
357
+
358
+ .demo-grid {
359
+ display: grid;
360
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
361
+ gap: 20px;
362
+ margin-top: 20px;
363
+ }
364
+
365
+ .demo-title {
366
+ text-align: center;
367
+ font-size: 2.5rem;
368
+ font-weight: bold;
369
+ margin-bottom: 2rem;
370
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
371
+ -webkit-background-clip: text;
372
+ -webkit-text-fill-color: transparent;
373
+ background-clip: text;
374
+ }
375
+ </style>
376
+ </head>
377
+ <body>
378
+ <!-- Header Section -->
379
+ <div class="upload-section">
380
+ <div class="container">
381
+ <h1 class="text-center mb-4">Event Analysis Dashboard</h1>
382
+ <div class="row justify-content-center">
383
+ <div class="col-md-6">
384
+ <form method="POST" enctype="multipart/form-data" class="text-center">
385
+ <div class="mb-3">
386
+ <div class="drop-zone" id="dropZone">
387
+ <div class="drop-zone-content">
388
+ <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MCIgaGVpZ2h0PSI1MCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMSAxNXY0YTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0ydi00Ij48L3BhdGg+PHBvbHlsaW5lIHBvaW50cz0iMTcgOCAxMiAzIDcgOCI+PC9wb2x5bGluZT48bGluZSB4MT0iMTIiIHkxPSIzIiB4Mj0iMTIiIHkyPSIxNSI+PC9saW5lPjwvc3ZnPg==" alt="Upload icon" class="upload-icon mb-2">
389
+ <p class="mb-0">Drag & drop your DOCX file here</p>
390
+ <p class="text-muted">or</p>
391
+ <label for="document" class="btn btn-light">Browse Files</label>
392
+ </div>
393
+ <input type="file" class="form-control d-none" id="document" name="document" accept=".docx">
394
+ </div>
395
+ </div>
396
+ <button type="submit" class="btn btn-light" id="submitBtn" disabled>Analyze Document</button>
397
+ </form>
398
+ {% if error %}
399
+ <div class="alert alert-danger mt-3" role="alert">
400
+ {{ error }}
401
+ </div>
402
+ {% endif %}
403
+ </div>
404
+ </div>
405
+ </div>
406
+ </div>
407
+
408
+ {% if plots %}
409
+ <div class="container">
410
+ <!-- Statistics Cards -->
411
+ <div class="row mb-4">
412
+ <div class="col-md-3">
413
+ <div class="card stats-card">
414
+ <div class="card-body">
415
+ <h5 class="card-title">Total Events</h5>
416
+ <p class="card-text display-6">{{ plots.stats.total_events }}</p>
417
+ </div>
418
+ </div>
419
+ </div>
420
+ <div class="col-md-3">
421
+ <div class="card stats-card">
422
+ <div class="card-body">
423
+ <h5 class="card-title">Avg Events/Year</h5>
424
+ <p class="card-text display-6">{{ plots.stats.avg_events_per_year }}</p>
425
+ </div>
426
+ </div>
427
+ </div>
428
+ <div class="col-md-3">
429
+ <div class="card stats-card">
430
+ <div class="card-body">
431
+ <h5 class="card-title">Most Active Year</h5>
432
+ <p class="card-text display-6">{{ plots.stats.most_active_year }}</p>
433
+ </div>
434
+ </div>
435
+ </div>
436
+ <div class="col-md-3">
437
+ <div class="card stats-card">
438
+ <div class="card-body">
439
+ <h5 class="card-title">Top Category</h5>
440
+ <p class="card-text display-6">{{ plots.stats.most_common_category }}</p>
441
+ </div>
442
+ </div>
443
+ </div>
444
+ </div>
445
+
446
+ <!-- Charts Section -->
447
+ <div class="row">
448
+ <!-- Bar Chart -->
449
+ <div class="col-md-6 mb-4">
450
+ <div class="chart-container">
451
+ <h3 class="text-center mb-3">Events Distribution</h3>
452
+ {{ plots.bar.plot|safe }}
453
+ <div class="mt-4">
454
+ <h5>Key Insight:</h5>
455
+ <p>{{ plots.bar.insight.main_insight }}</p>
456
+
457
+ <h5>SWOT Analysis:</h5>
458
+ <div class="row">
459
+ <div class="col-md-6">
460
+ <div class="card mb-3">
461
+ <div class="card-header bg-success text-white">
462
+ <h6 class="mb-0">Strengths</h6>
463
+ </div>
464
+ <div class="card-body">
465
+ <ul class="list-unstyled mb-0">
466
+ {% for strength in plots.bar.insight.swot.strengths %}
467
+ <li>• {{ strength }}</li>
468
+ {% endfor %}
469
+ </ul>
470
+ </div>
471
+ </div>
472
+ </div>
473
+ <div class="col-md-6">
474
+ <div class="card mb-3">
475
+ <div class="card-header bg-danger text-white">
476
+ <h6 class="mb-0">Weaknesses</h6>
477
+ </div>
478
+ <div class="card-body">
479
+ <ul class="list-unstyled mb-0">
480
+ {% for weakness in plots.bar.insight.swot.weaknesses %}
481
+ <li>• {{ weakness }}</li>
482
+ {% endfor %}
483
+ </ul>
484
+ </div>
485
+ </div>
486
+ </div>
487
+ <div class="col-md-6">
488
+ <div class="card mb-3">
489
+ <div class="card-header bg-primary text-white">
490
+ <h6 class="mb-0">Opportunities</h6>
491
+ </div>
492
+ <div class="card-body">
493
+ <ul class="list-unstyled mb-0">
494
+ {% for opportunity in plots.bar.insight.swot.opportunities %}
495
+ <li>• {{ opportunity }}</li>
496
+ {% endfor %}
497
+ </ul>
498
+ </div>
499
+ </div>
500
+ </div>
501
+ <div class="col-md-6">
502
+ <div class="card mb-3">
503
+ <div class="card-header bg-warning">
504
+ <h6 class="mb-0">Threats</h6>
505
+ </div>
506
+ <div class="card-body">
507
+ <ul class="list-unstyled mb-0">
508
+ {% for threat in plots.bar.insight.swot.threats %}
509
+ <li>• {{ threat }}</li>
510
+ {% endfor %}
511
+ </ul>
512
+ </div>
513
+ </div>
514
+ </div>
515
+ </div>
516
+
517
+ <h5>Recommendations:</h5>
518
+ <ul>
519
+ {% for recommendation in plots.bar.insight.recommendations %}
520
+ <li>{{ recommendation }}</li>
521
+ {% endfor %}
522
+ </ul>
523
+ </div>
524
+ </div>
525
+ </div>
526
+ <!-- Pie Chart -->
527
+ <div class="col-md-6 mb-4">
528
+ <div class="chart-container">
529
+ <h3 class="text-center mb-3">Current Year Distribution</h3>
530
+ {{ plots.pie.plot|safe }}
531
+ <div class="mt-4">
532
+ <h5>Key Insight:</h5>
533
+ <p>{{ plots.pie.insight.main_insight }}</p>
534
+
535
+ <h5>SWOT Analysis:</h5>
536
+ <div class="row">
537
+ <div class="col-md-6">
538
+ <div class="card mb-3">
539
+ <div class="card-header bg-success text-white">
540
+ <h6 class="mb-0">Strengths</h6>
541
+ </div>
542
+ <div class="card-body">
543
+ <ul class="list-unstyled mb-0">
544
+ {% for strength in plots.pie.insight.swot.strengths %}
545
+ <li>• {{ strength }}</li>
546
+ {% endfor %}
547
+ </ul>
548
+ </div>
549
+ </div>
550
+ </div>
551
+ <div class="col-md-6">
552
+ <div class="card mb-3">
553
+ <div class="card-header bg-danger text-white">
554
+ <h6 class="mb-0">Weaknesses</h6>
555
+ </div>
556
+ <div class="card-body">
557
+ <ul class="list-unstyled mb-0">
558
+ {% for weakness in plots.pie.insight.swot.weaknesses %}
559
+ <li>• {{ weakness }}</li>
560
+ {% endfor %}
561
+ </ul>
562
+ </div>
563
+ </div>
564
+ </div>
565
+ <div class="col-md-6">
566
+ <div class="card mb-3">
567
+ <div class="card-header bg-primary text-white">
568
+ <h6 class="mb-0">Opportunities</h6>
569
+ </div>
570
+ <div class="card-body">
571
+ <ul class="list-unstyled mb-0">
572
+ {% for opportunity in plots.pie.insight.swot.opportunities %}
573
+ <li>• {{ opportunity }}</li>
574
+ {% endfor %}
575
+ </ul>
576
+ </div>
577
+ </div>
578
+ </div>
579
+ <div class="col-md-6">
580
+ <div class="card mb-3">
581
+ <div class="card-header bg-warning">
582
+ <h6 class="mb-0">Threats</h6>
583
+ </div>
584
+ <div class="card-body">
585
+ <ul class="list-unstyled mb-0">
586
+ {% for threat in plots.pie.insight.swot.threats %}
587
+ <li>• {{ threat }}</li>
588
+ {% endfor %}
589
+ </ul>
590
+ </div>
591
+ </div>
592
+ </div>
593
+ </div>
594
+
595
+ <h5>Recommendations:</h5>
596
+ <ul>
597
+ {% for recommendation in plots.pie.insight.recommendations %}
598
+ <li>{{ recommendation }}</li>
599
+ {% endfor %}
600
+ </ul>
601
+ </div>
602
+ </div>
603
+ </div>
604
+ <!-- Line Chart -->
605
+ <div class="col-md-6 mb-4">
606
+ <div class="chart-container">
607
+ <h3 class="text-center mb-3">Event Trends</h3>
608
+ {{ plots.line.plot|safe }}
609
+ <div class="mt-4">
610
+ <h5>Key Insight:</h5>
611
+ <p>{{ plots.line.insight.main_insight }}</p>
612
+
613
+ <h5>SWOT Analysis:</h5>
614
+ <div class="row">
615
+ <div class="col-md-6">
616
+ <div class="card mb-3">
617
+ <div class="card-header bg-success text-white">
618
+ <h6 class="mb-0">Strengths</h6>
619
+ </div>
620
+ <div class="card-body">
621
+ <ul class="list-unstyled mb-0">
622
+ {% for strength in plots.line.insight.swot.strengths %}
623
+ <li>• {{ strength }}</li>
624
+ {% endfor %}
625
+ </ul>
626
+ </div>
627
+ </div>
628
+ </div>
629
+ <div class="col-md-6">
630
+ <div class="card mb-3">
631
+ <div class="card-header bg-danger text-white">
632
+ <h6 class="mb-0">Weaknesses</h6>
633
+ </div>
634
+ <div class="card-body">
635
+ <ul class="list-unstyled mb-0">
636
+ {% for weakness in plots.line.insight.swot.weaknesses %}
637
+ <li>• {{ weakness }}</li>
638
+ {% endfor %}
639
+ </ul>
640
+ </div>
641
+ </div>
642
+ </div>
643
+ <div class="col-md-6">
644
+ <div class="card mb-3">
645
+ <div class="card-header bg-primary text-white">
646
+ <h6 class="mb-0">Opportunities</h6>
647
+ </div>
648
+ <div class="card-body">
649
+ <ul class="list-unstyled mb-0">
650
+ {% for opportunity in plots.line.insight.swot.opportunities %}
651
+ <li>• {{ opportunity }}</li>
652
+ {% endfor %}
653
+ </ul>
654
+ </div>
655
+ </div>
656
+ </div>
657
+ <div class="col-md-6">
658
+ <div class="card mb-3">
659
+ <div class="card-header bg-warning">
660
+ <h6 class="mb-0">Threats</h6>
661
+ </div>
662
+ <div class="card-body">
663
+ <ul class="list-unstyled mb-0">
664
+ {% for threat in plots.line.insight.swot.threats %}
665
+ <li>• {{ threat }}</li>
666
+ {% endfor %}
667
+ </ul>
668
+ </div>
669
+ </div>
670
+ </div>
671
+ </div>
672
+
673
+ <h5>Recommendations:</h5>
674
+ <ul>
675
+ {% for recommendation in plots.line.insight.recommendations %}
676
+ <li>{{ recommendation }}</li>
677
+ {% endfor %}
678
+ </ul>
679
+ </div>
680
+ </div>
681
+ </div>
682
+ <!-- Growth Rate Chart -->
683
+ <div class="col-md-6 mb-4">
684
+ <div class="chart-container">
685
+ <h3 class="text-center mb-3">Year-over-Year Growth</h3>
686
+ {{ plots.growth.plot|safe }}
687
+ <div class="mt-4">
688
+ <h5>Key Insight:</h5>
689
+ <p>{{ plots.growth.insight.main_insight }}</p>
690
+
691
+ <h5>SWOT Analysis:</h5>
692
+ <div class="row">
693
+ <div class="col-md-6">
694
+ <div class="card mb-3">
695
+ <div class="card-header bg-success text-white">
696
+ <h6 class="mb-0">Strengths</h6>
697
+ </div>
698
+ <div class="card-body">
699
+ <ul class="list-unstyled mb-0">
700
+ {% for strength in plots.growth.insight.swot.strengths %}
701
+ <li>• {{ strength }}</li>
702
+ {% endfor %}
703
+ </ul>
704
+ </div>
705
+ </div>
706
+ </div>
707
+ <div class="col-md-6">
708
+ <div class="card mb-3">
709
+ <div class="card-header bg-danger text-white">
710
+ <h6 class="mb-0">Weaknesses</h6>
711
+ </div>
712
+ <div class="card-body">
713
+ <ul class="list-unstyled mb-0">
714
+ {% for weakness in plots.growth.insight.swot.weaknesses %}
715
+ <li>• {{ weakness }}</li>
716
+ {% endfor %}
717
+ </ul>
718
+ </div>
719
+ </div>
720
+ </div>
721
+ <div class="col-md-6">
722
+ <div class="card mb-3">
723
+ <div class="card-header bg-primary text-white">
724
+ <h6 class="mb-0">Opportunities</h6>
725
+ </div>
726
+ <div class="card-body">
727
+ <ul class="list-unstyled mb-0">
728
+ {% for opportunity in plots.growth.insight.swot.opportunities %}
729
+ <li>• {{ opportunity }}</li>
730
+ {% endfor %}
731
+ </ul>
732
+ </div>
733
+ </div>
734
+ </div>
735
+ <div class="col-md-6">
736
+ <div class="card mb-3">
737
+ <div class="card-header bg-warning">
738
+ <h6 class="mb-0">Threats</h6>
739
+ </div>
740
+ <div class="card-body">
741
+ <ul class="list-unstyled mb-0">
742
+ {% for threat in plots.growth.insight.swot.threats %}
743
+ <li>• {{ threat }}</li>
744
+ {% endfor %}
745
+ </ul>
746
+ </div>
747
+ </div>
748
+ </div>
749
+ </div>
750
+
751
+ <h5>Recommendations:</h5>
752
+ <ul>
753
+ {% for recommendation in plots.growth.insight.recommendations %}
754
+ <li>{{ recommendation }}</li>
755
+ {% endfor %}
756
+ </ul>
757
+ </div>
758
+ </div>
759
+ </div>
760
+ <!-- Area Chart -->
761
+ <div class="col-md-12 mb-4">
762
+ <div class="chart-container">
763
+ <h3 class="text-center mb-3">Cumulative Events</h3>
764
+ {{ plots.area.plot|safe }}
765
+ <div class="mt-4">
766
+ <h5>Key Insight:</h5>
767
+ <p>{{ plots.area.insight.main_insight }}</p>
768
+
769
+ <h5>SWOT Analysis:</h5>
770
+ <div class="row">
771
+ <div class="col-md-6">
772
+ <div class="card mb-3">
773
+ <div class="card-header bg-success text-white">
774
+ <h6 class="mb-0">Strengths</h6>
775
+ </div>
776
+ <div class="card-body">
777
+ <ul class="list-unstyled mb-0">
778
+ {% for strength in plots.area.insight.swot.strengths %}
779
+ <li>• {{ strength }}</li>
780
+ {% endfor %}
781
+ </ul>
782
+ </div>
783
+ </div>
784
+ </div>
785
+ <div class="col-md-6">
786
+ <div class="card mb-3">
787
+ <div class="card-header bg-danger text-white">
788
+ <h6 class="mb-0">Weaknesses</h6>
789
+ </div>
790
+ <div class="card-body">
791
+ <ul class="list-unstyled mb-0">
792
+ {% for weakness in plots.area.insight.swot.weaknesses %}
793
+ <li>• {{ weakness }}</li>
794
+ {% endfor %}
795
+ </ul>
796
+ </div>
797
+ </div>
798
+ </div>
799
+ <div class="col-md-6">
800
+ <div class="card mb-3">
801
+ <div class="card-header bg-primary text-white">
802
+ <h6 class="mb-0">Opportunities</h6>
803
+ </div>
804
+ <div class="card-body">
805
+ <ul class="list-unstyled mb-0">
806
+ {% for opportunity in plots.area.insight.swot.opportunities %}
807
+ <li>• {{ opportunity }}</li>
808
+ {% endfor %}
809
+ </ul>
810
+ </div>
811
+ </div>
812
+ </div>
813
+ <div class="col-md-6">
814
+ <div class="card mb-3">
815
+ <div class="card-header bg-warning">
816
+ <h6 class="mb-0">Threats</h6>
817
+ </div>
818
+ <div class="card-body">
819
+ <ul class="list-unstyled mb-0">
820
+ {% for threat in plots.area.insight.swot.threats %}
821
+ <li>• {{ threat }}</li>
822
+ {% endfor %}
823
+ </ul>
824
+ </div>
825
+ </div>
826
+ </div>
827
+ </div>
828
+
829
+ <h5>Recommendations:</h5>
830
+ <ul>
831
+ {% for recommendation in plots.area.insight.recommendations %}
832
+ <li>{{ recommendation }}</li>
833
+ {% endfor %}
834
+ </ul>
835
+ </div>
836
+ </div>
837
+ </div>
838
+ </div>
839
+
840
+ <!-- Growth Analysis Section -->
841
+ <div class="row mb-4">
842
+ <div class="col-12">
843
+ <div class="card">
844
+ <div class="card-body">
845
+ <h3 class="card-title">Growth Analysis</h3>
846
+ <p class="card-text">Total Growth: {{ plots.stats.growth_analysis.total_growth }}%</p>
847
+ <h5>Category-wise Growth:</h5>
848
+ <ul class="list-group">
849
+ {% for category, growth in plots.stats.growth_analysis.category_growth.items() %}
850
+ <li class="list-group-item d-flex justify-content-between align-items-center">
851
+ {{ category }}
852
+ <span class="badge bg-{{ 'success' if growth > 0 else 'danger' }} rounded-pill">
853
+ {{ growth }}%
854
+ </span>
855
+ </li>
856
+ {% endfor %}
857
+ </ul>
858
+ </div>
859
+ </div>
860
+ </div>
861
+ </div>
862
+ </div>
863
+ {% endif %}
864
+
865
+ <button class="btn btn-primary print-btn" id="printPageBtn">Print Page</button>
866
+ <!-- Bootstrap JS and Popper.js -->
867
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
868
+ <script>
869
+ document.addEventListener('DOMContentLoaded', function() {
870
+ document.getElementById('printPageBtn').addEventListener('click', function() {
871
+ window.print();
872
+ });
873
+ });
874
+ document.addEventListener('DOMContentLoaded', function() {
875
+ const dropZone = document.getElementById('dropZone');
876
+ const fileInput = document.getElementById('document');
877
+ const submitBtn = document.getElementById('submitBtn');
878
+
879
+ // Prevent default drag behaviors
880
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
881
+ dropZone.addEventListener(eventName, preventDefaults, false);
882
+ document.body.addEventListener(eventName, preventDefaults, false);
883
+ });
884
+
885
+ // Highlight drop zone when dragging over it
886
+ ['dragenter', 'dragover'].forEach(eventName => {
887
+ dropZone.addEventListener(eventName, highlight, false);
888
+ });
889
+
890
+ ['dragleave', 'drop'].forEach(eventName => {
891
+ dropZone.addEventListener(eventName, unhighlight, false);
892
+ });
893
+
894
+ // Handle dropped files
895
+ dropZone.addEventListener('drop', handleDrop, false);
896
+
897
+ // Handle clicked files
898
+ fileInput.addEventListener('change', handleFiles, false);
899
+
900
+ // Click handling for the drop zone
901
+ dropZone.addEventListener('click', (e) => {
902
+ // Prevent click if clicking on the Browse Files button
903
+ if (e.target.tagName === 'LABEL') {
904
+ return;
905
+ }
906
+ fileInput.click();
907
+ });
908
+
909
+ function preventDefaults(e) {
910
+ e.preventDefault();
911
+ e.stopPropagation();
912
+ }
913
+
914
+ function highlight(e) {
915
+ dropZone.classList.add('dragover');
916
+ }
917
+
918
+ function unhighlight(e) {
919
+ dropZone.classList.remove('dragover');
920
+ }
921
+
922
+ function handleDrop(e) {
923
+ const dt = e.dataTransfer;
924
+ const files = dt.files;
925
+
926
+ if (files.length) {
927
+ fileInput.files = files; // Set the files to the input
928
+ handleFiles(files[0]);
929
+ }
930
+ }
931
+
932
+ function handleFiles(e) {
933
+ const file = e.target ? e.target.files[0] : e; // Handle both event and direct file
934
+
935
+ if (file) {
936
+ if (file.name.endsWith('.docx')) {
937
+ updateDropZoneContent(file.name);
938
+ submitBtn.disabled = false;
939
+ } else {
940
+ alert('Please upload a .docx file');
941
+ fileInput.value = '';
942
+ submitBtn.disabled = true;
943
+ resetDropZoneContent();
944
+ }
945
+ }
946
+ }
947
+
948
+ function updateDropZoneContent(fileName) {
949
+ const content = dropZone.querySelector('.drop-zone-content');
950
+ content.innerHTML = `
951
+ <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MCIgaGVpZ2h0PSI1MCIgdmlld0JveG0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMSAxNXY0YTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0ydi00Ij48L3BhdGg+PHBvbHlsaW5lIHBvaW50cz0iMTcgOCAxMiAzIDcgOCI+PC9wb2x5bGluZT48bGluZSB4MT0iMTIiIHkxPSIzIiB4Mj0iMTIiIHkyPSIxNSI+PC9saW5lPjwvc3ZnPg==" alt="Upload icon" class="upload-icon mb-2">
952
+ <p class="selected-file">${fileName}</p>
953
+ <p class="text-muted">Click or drag to change file</p>
954
+ `;
955
+ }
956
+
957
+ function resetDropZoneContent() {
958
+ const content = dropZone.querySelector('.drop-zone-content');
959
+ content.innerHTML = `
960
+ <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MCIgaGVpZ2h0PSI1MCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMSAxNXY0YTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0ydi00Ij48L3BhdGg+PHBvbHlsaW5lIHBvaW50cz0iMTcgOCAxMiAzIDcgOCI+PC9wb2x5bGluZT48bGluZSB4MT0iMTIiIHkxPSIzIiB4Mj0iMTIiIHkyPSIxNSI+PC9saW5lPjwvc3ZnPg==" alt="Upload icon" class="upload-icon mb-2">
961
+ <p class="mb-0">Drag & drop your DOCX file here</p>
962
+ <p class="text-muted">or</p>
963
+ <label for="document" class="btn btn-light">Browse Files</label>
964
+ `;
965
+ }
966
+ });
967
+ </script>
968
+ </body>
969
+ </html>
templates/result.html ADDED
@@ -0,0 +1,438 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <!-- Results Template -->
3
+ <!DOCTYPE html>
4
+ <html lang="en">
5
+ <head>
6
+ <meta charset="UTF-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <title>Analysis Results - Advanced Data Analysis Tool</title>
9
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
10
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
11
+ <style>
12
+ body {
13
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
14
+ min-height: 100vh;
15
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16
+ }
17
+ .main-container {
18
+ background: rgba(255, 255, 255, 0.95);
19
+ border-radius: 20px;
20
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
21
+ backdrop-filter: blur(10px);
22
+ margin: 30px auto;
23
+ max-width: 1400px;
24
+ padding: 30px;
25
+ }
26
+ .stats-grid {
27
+ display: grid;
28
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
29
+ gap: 20px;
30
+ margin: 30px 0;
31
+ }
32
+ .stat-card {
33
+ background: linear-gradient(45deg, #667eea, #764ba2);
34
+ color: white;
35
+ padding: 25px;
36
+ border-radius: 15px;
37
+ text-align: center;
38
+ transition: all 0.3s ease;
39
+ }
40
+ .stat-card:hover {
41
+ transform: scale(1.05);
42
+ }
43
+ .analysis-section {
44
+ background: white;
45
+ border-radius: 15px;
46
+ padding: 30px;
47
+ margin: 20px 0;
48
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
49
+ }
50
+ .plot-container {
51
+ text-align: center;
52
+ margin: 20px 0;
53
+ }
54
+ .plot-container img {
55
+ max-width: 100%;
56
+ border-radius: 10px;
57
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
58
+ }
59
+ .swot-grid {
60
+ display: grid;
61
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
62
+ gap: 20px;
63
+ margin: 20px 0;
64
+ }
65
+ .swot-card {
66
+ padding: 25px;
67
+ border-radius: 15px;
68
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
69
+ }
70
+ .swot-strengths { background: linear-gradient(45deg, #4CAF50, #45a049); color: white; }
71
+ .swot-weaknesses { background: linear-gradient(45deg, #f44336, #d32f2f); color: white; }
72
+ .swot-opportunities { background: linear-gradient(45deg, #2196F3, #1976D2); color: white; }
73
+ .swot-threats { background: linear-gradient(45deg, #FF9800, #F57C00); color: white; }
74
+ .insights-text {
75
+ background: #f8f9fa;
76
+ border-left: 4px solid #667eea;
77
+ padding: 20px;
78
+ border-radius: 5px;
79
+ margin: 20px 0;
80
+ white-space: pre-wrap;
81
+ }
82
+ .btn-primary {
83
+ background: linear-gradient(45deg, #667eea, #764ba2);
84
+ border: none;
85
+ padding: 12px 30px;
86
+ border-radius: 25px;
87
+ font-weight: 600;
88
+ transition: all 0.3s ease;
89
+ }
90
+ .btn-primary:hover {
91
+ transform: translateY(-2px);
92
+ box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
93
+ }
94
+ .nav-tabs .nav-link {
95
+ border: none;
96
+ border-radius: 25px;
97
+ margin: 0 5px;
98
+ padding: 10px 20px;
99
+ transition: all 0.3s ease;
100
+ }
101
+ .nav-tabs .nav-link.active {
102
+ background: linear-gradient(45deg, #667eea, #764ba2);
103
+ color: white;
104
+ }
105
+ .table-responsive {
106
+ border-radius: 10px;
107
+ overflow: hidden;
108
+ }
109
+ .table {
110
+ margin: 0;
111
+ }
112
+ .table th {
113
+ background: linear-gradient(45deg, #667eea, #764ba2);
114
+ color: white;
115
+ border: none;
116
+ }
117
+ .insights-card {
118
+ background: linear-gradient(45deg, #f8f9fa, #e9ecef);
119
+ border-radius: 15px;
120
+ padding: 25px;
121
+ margin: 20px 0;
122
+ border-left: 5px solid #667eea;
123
+ }
124
+ .correlation-matrix {
125
+ overflow-x: auto;
126
+ }
127
+ .section-header {
128
+ background: linear-gradient(45deg, #667eea, #764ba2);
129
+ color: white;
130
+ padding: 15px 25px;
131
+ border-radius: 10px;
132
+ margin: 20px 0 10px 0;
133
+ }
134
+ </style>
135
+ </head>
136
+ <body>
137
+ <div class="container-fluid">
138
+ <div class="main-container">
139
+ <!-- Header -->
140
+ <div class="text-center mb-4">
141
+ <h1 class="display-5 text-primary">
142
+ <i class="fas fa-chart-line me-3"></i>
143
+ Data Analysis Results
144
+ </h1>
145
+ <p class="lead">Comprehensive analysis of: <strong>{{ results.dataset_info.filename }}</strong></p>
146
+ <small class="text-muted">Analysis completed on: {{ results.dataset_info.upload_time }}</small>
147
+ </div>
148
+
149
+ <!-- Quick Stats -->
150
+ <div class="stats-grid">
151
+ <div class="stat-card">
152
+ <i class="fas fa-table fa-2x mb-2"></i>
153
+ <h3>{{ results.dataset_info.rows }}</h3>
154
+ <p>Total Rows</p>
155
+ </div>
156
+ <div class="stat-card">
157
+ <i class="fas fa-columns fa-2x mb-2"></i>
158
+ <h3>{{ results.dataset_info.columns }}</h3>
159
+ <p>Total Columns</p>
160
+ </div>
161
+ <div class="stat-card">
162
+ <i class="fas fa-memory fa-2x mb-2"></i>
163
+ <h3>{{ results.dataset_info.memory_usage }}</h3>
164
+ <p>Memory Usage</p>
165
+ </div>
166
+ <div class="stat-card">
167
+ <i class="fas fa-exclamation-triangle fa-2x mb-2"></i>
168
+ <h3>{{ results.dataset_info.missing_values_total }}</h3>
169
+ <p>Missing Values</p>
170
+ </div>
171
+ </div>
172
+
173
+ <!-- Navigation Tabs -->
174
+ <ul class="nav nav-tabs" id="analysisTab" role="tablist">
175
+ <li class="nav-item" role="presentation">
176
+ <button class="nav-link active" id="overview-tab" data-bs-toggle="tab" data-bs-target="#overview" type="button" role="tab">
177
+ <i class="fas fa-info-circle me-2"></i>Overview
178
+ </button>
179
+ </li>
180
+ <li class="nav-item" role="presentation">
181
+ <button class="nav-link" id="visualizations-tab" data-bs-toggle="tab" data-bs-target="#visualizations" type="button" role="tab">
182
+ <i class="fas fa-chart-bar me-2"></i>Visualizations
183
+ </button>
184
+ </li>
185
+ <li class="nav-item" role="presentation">
186
+ <button class="nav-link" id="insights-tab" data-bs-toggle="tab" data-bs-target="#insights" type="button" role="tab">
187
+ <i class="fas fa-brain me-2"></i>AI Insights
188
+ </button>
189
+ </li>
190
+ <li class="nav-item" role="presentation">
191
+ <button class="nav-link" id="swot-tab" data-bs-toggle="tab" data-bs-target="#swot" type="button" role="tab">
192
+ <i class="fas fa-crosshairs me-2"></i>SWOT Analysis
193
+ </button>
194
+ </li>
195
+ </ul>
196
+
197
+ <!-- Tab Content -->
198
+ <div class="tab-content" id="analysisTabContent">
199
+ <!-- Overview Tab -->
200
+ <div class="tab-pane fade show active" id="overview" role="tabpanel">
201
+ <div class="analysis-section">
202
+ <h3 class="section-header">
203
+ <i class="fas fa-info-circle me-2"></i>Dataset Overview
204
+ </h3>
205
+
206
+ <!-- Column Information -->
207
+ <div class="row">
208
+ <div class="col-md-6">
209
+ <h5>Column Information</h5>
210
+ <div class="table-responsive">
211
+ <table class="table table-striped">
212
+ <thead>
213
+ <tr>
214
+ <th>Column</th>
215
+ <th>Data Type</th>
216
+ <th>Missing Values</th>
217
+ </tr>
218
+ </thead>
219
+ <tbody>
220
+ {% for column in results.basic_stats.columns %}
221
+ <tr>
222
+ <td>{{ column }}</td>
223
+ <td>{{ results.basic_stats.dtypes[column] }}</td>
224
+ <td>{{ results.basic_stats.missing_values[column] }}</td>
225
+ </tr>
226
+ {% endfor %}
227
+ </tbody>
228
+ </table>
229
+ </div>
230
+ </div>
231
+ <div class="col-md-6">
232
+ <h5>Data Quality Summary</h5>
233
+ <div class="insights-card">
234
+ <p><strong>Total Records:</strong> {{ results.dataset_info.rows }}</p>
235
+ <p><strong>Features:</strong> {{ results.dataset_info.columns }}</p>
236
+ <p><strong>Duplicate Rows:</strong> {{ results.dataset_info.duplicate_rows }}</p>
237
+ <p><strong>Memory Usage:</strong> {{ results.dataset_info.memory_usage }}</p>
238
+ <p><strong>Missing Values:</strong> {{ results.dataset_info.missing_values_total }}</p>
239
+ </div>
240
+ </div>
241
+ </div>
242
+
243
+ <!-- Numerical Insights -->
244
+ {% if results.numerical_insights %}
245
+ <h5 class="mt-4">Numerical Columns Analysis</h5>
246
+ <div class="table-responsive">
247
+ <table class="table table-striped">
248
+ <thead>
249
+ <tr>
250
+ <th>Column</th>
251
+ <th>Mean</th>
252
+ <th>Median</th>
253
+ <th>Std Dev</th>
254
+ <th>Min</th>
255
+ <th>Max</th>
256
+ <th>Outliers</th>
257
+ </tr>
258
+ </thead>
259
+ <tbody>
260
+ {% for column, stats in results.numerical_insights.items() %}
261
+ <tr>
262
+ <td>{{ column }}</td>
263
+ <td>{{ "%.2f"|format(stats.mean) }}</td>
264
+ <td>{{ "%.2f"|format(stats.median) }}</td>
265
+ <td>{{ "%.2f"|format(stats.std) }}</td>
266
+ <td>{{ "%.2f"|format(stats.min) }}</td>
267
+ <td>{{ "%.2f"|format(stats.max) }}</td>
268
+ <td>{{ stats.outliers }}</td>
269
+ </tr>
270
+ {% endfor %}
271
+ </tbody>
272
+ </table>
273
+ </div>
274
+ {% endif %}
275
+
276
+ <!-- Categorical Insights -->
277
+ {% if results.categorical_insights %}
278
+ <h5 class="mt-4">Categorical Columns Analysis</h5>
279
+ <div class="row">
280
+ {% for column, stats in results.categorical_insights.items() %}
281
+ <div class="col-md-6 mb-3">
282
+ <div class="insights-card">
283
+ <h6>{{ column }}</h6>
284
+ <p><strong>Unique Values:</strong> {{ stats.unique_count }}</p>
285
+ <p><strong>Most Common:</strong> {{ stats.mode }}</p>
286
+ <p><strong>Top Categories:</strong></p>
287
+ <ul>
288
+ {% for category, count in stats.top_categories.items() %}
289
+ <li>{{ category }}: {{ count }}</li>
290
+ {% endfor %}
291
+ </ul>
292
+ </div>
293
+ </div>
294
+ {% endfor %}
295
+ </div>
296
+ {% endif %}
297
+ </div>
298
+ </div>
299
+
300
+ <!-- Visualizations Tab -->
301
+ <div class="tab-pane fade" id="visualizations" role="tabpanel">
302
+ <div class="analysis-section">
303
+ <h3 class="section-header">
304
+ <i class="fas fa-chart-bar me-2"></i>Data Visualizations
305
+ </h3>
306
+
307
+ {% if results.plot_images %}
308
+ <div class="row">
309
+ {% for plot in results.plot_images %}
310
+ <div class="col-lg-6 col-md-12 mb-4">
311
+ <div class="plot-container">
312
+ <img src="data:image/png;base64,{{ plot }}" alt="Data Visualization" class="img-fluid">
313
+ </div>
314
+ </div>
315
+ {% endfor %}
316
+ </div>
317
+ {% else %}
318
+ <p>No visualizations available for this dataset.</p>
319
+ {% endif %}
320
+ </div>
321
+ </div>
322
+
323
+ <!-- AI Insights Tab -->
324
+ <div class="tab-pane fade" id="insights" role="tabpanel">
325
+ <div class="analysis-section">
326
+ <h3 class="section-header">
327
+ <i class="fas fa-brain me-2"></i>AI-Powered Insights
328
+ </h3>
329
+
330
+ <div class="insights-text">
331
+ {{ results.ai_insights }}
332
+ </div>
333
+
334
+ <!-- Correlation Matrix -->
335
+ {% if results.correlation_matrix %}
336
+ <h5 class="mt-4">Correlation Analysis</h5>
337
+ <div class="correlation-matrix">
338
+ <div class="table-responsive">
339
+ <table class="table table-striped">
340
+ <thead>
341
+ <tr>
342
+ <th>Feature</th>
343
+ {% for col in results.correlation_matrix.keys() %}
344
+ <th>{{ col }}</th>
345
+ {% endfor %}
346
+ </tr>
347
+ </thead>
348
+ <tbody>
349
+ {% for row_col, row_data in results.correlation_matrix.items() %}
350
+ <tr>
351
+ <td><strong>{{ row_col }}</strong></td>
352
+ {% for col, value in row_data.items() %}
353
+ <td>{{ "%.3f"|format(value) }}</td>
354
+ {% endfor %}
355
+ </tr>
356
+ {% endfor %}
357
+ </tbody>
358
+ </table>
359
+ </div>
360
+ </div>
361
+ {% endif %}
362
+ </div>
363
+ </div>
364
+
365
+ <!-- SWOT Analysis Tab -->
366
+ <div class="tab-pane fade" id="swot" role="tabpanel">
367
+ <div class="analysis-section">
368
+ <h3 class="section-header">
369
+ <i class="fas fa-crosshairs me-2"></i>SWOT Analysis
370
+ </h3>
371
+
372
+ <div class="swot-grid">
373
+ <!-- Strengths -->
374
+ <div class="swot-card swot-strengths">
375
+ <h5><i class="fas fa-thumbs-up me-2"></i>Strengths</h5>
376
+ <ul>
377
+ {% for strength in results.swot_analysis.strengths %}
378
+ <li>{{ strength }}</li>
379
+ {% endfor %}
380
+ </ul>
381
+ </div>
382
+
383
+ <!-- Weaknesses -->
384
+ <div class="swot-card swot-weaknesses">
385
+ <h5><i class="fas fa-thumbs-down me-2"></i>Weaknesses</h5>
386
+ <ul>
387
+ {% for weakness in results.swot_analysis.weaknesses %}
388
+ <li>{{ weakness }}</li>
389
+ {% endfor %}
390
+ </ul>
391
+ </div>
392
+
393
+ <!-- Opportunities -->
394
+ <div class="swot-card swot-opportunities">
395
+ <h5><i class="fas fa-lightbulb me-2"></i>Opportunities</h5>
396
+ <ul>
397
+ {% for opportunity in results.swot_analysis.opportunities %}
398
+ <li>{{ opportunity }}</li>
399
+ {% endfor %}
400
+ </ul>
401
+ </div>
402
+
403
+ <!-- Threats -->
404
+ <div class="swot-card swot-threats">
405
+ <h5><i class="fas fa-exclamation-triangle me-2"></i>Threats</h5>
406
+ <ul>
407
+ {% for threat in results.swot_analysis.threats %}
408
+ <li>{{ threat }}</li>
409
+ {% endfor %}
410
+ </ul>
411
+ </div>
412
+ </div>
413
+ </div>
414
+ </div>
415
+ </div>
416
+
417
+ <!-- Action Buttons -->
418
+ <div class="text-center mt-4">
419
+ <a href="/" class="btn btn-primary">
420
+ <i class="fas fa-upload me-2"></i>Analyze Another File
421
+ </a>
422
+ <button class="btn btn-secondary" onclick="window.print()">
423
+ <i class="fas fa-print me-2"></i>Print Report
424
+ </button>
425
+ </div>
426
+ </div>
427
+ </div>
428
+
429
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
430
+ <script>
431
+ // Initialize tooltips
432
+ var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
433
+ var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
434
+ return new bootstrap.Tooltip(tooltipTriggerEl);
435
+ });
436
+ </script>
437
+ </body>
438
+ </html>