alexdatamed commited on
Commit
4ad38c8
·
verified ·
1 Parent(s): 73d1b4d

Upload app.js

Browse files
Files changed (1) hide show
  1. app.js +410 -452
app.js CHANGED
@@ -1,513 +1,471 @@
1
- // Дані про робочий процес науки про дані
2
- const workflowData = {
3
- "title": "Робочий процес науки про дані",
4
- "introduction": "Кожен проект з науки про дані включає кілька важливих етапів. Ця інтерактивна панель допоможе вам зрозуміти кожен етап робочого процесу та його важливість.",
5
- "steps": [
6
  {
7
  "id": 1,
8
- "title": "Формулювання проблеми",
9
- "shortTitle": "Проблема",
10
- "description": "Кожен проект з науки про дані починається з визначення проблеми. Незалежно від того, чи це прогнозування результатів пацієнтів або оптимізація бізнес-операцій, переклад реальної проблеми у питання, що базується на даних, є вирішальним.",
11
- "keyPoints": [
12
- "Визначення конкретної проблеми, яку потрібно вирішити",
13
- "Формулювання питань, на які потрібно відповісти за допомогою даних",
14
- "Вибір підходу до вирішення (машинне навчання, статистичний аналіз тощо)"
15
- ],
16
- "example": "У галузі охорони здоров'я, прогнозування часу відновлення пацієнта на основі медичної історії. Формулювання проблеми: лікарям потрібен інструмент для прогнозування тривалості відновлення пацієнта після лікування.",
17
- "tips": [
18
- "Завжди консультуйтеся з експертами в предметній області",
19
- "Переконайтеся, що проблема може бути вирішена за допомогою даних",
20
- "Визначте чіткі критерії успіху"
21
- ],
22
- "quiz": [
23
- {
24
- "question": "Що є першим кроком у проекті науки про дані?",
25
- "options": [
26
- "Збір даних",
27
- "Визначення проблеми",
28
- "Побудова моделі",
29
- "Оцінка результатів"
30
- ],
31
- "answer": 1
32
- }
33
- ]
34
  },
35
  {
36
- "id": 2,
37
- "title": "Збір даних",
38
- "shortTitle": "Дані",
39
- "description": "Наступним кроком є збір відповідних даних з надійних джерел. Це може включати бази даних, публічні набори даних або дані, зібрані через сенсори та додатки.",
40
- "keyPoints": [
41
- "Визначення потрібних даних для вирішення проблеми",
42
- "Ідентифікація джерел даних",
43
- "Розуміння регуляторних вимог та етичних міркувань"
44
- ],
45
- "example": "Збір клінічних записів з баз даних охорони здоров'я для аналізу часу відновлення пацієнтів.",
46
- "tips": [
47
- "Переконайтеся, що ви маєте дозвіл на використання даних",
48
- "Перевірте якість та надійність джерел даних",
49
- "Зберігайте дані безпечно та відповідно до норм"
50
- ],
51
- "quiz": [
52
- {
53
- "question": "Що Ендрю Нг назвав 'їжею для ШІ'?",
54
- "options": [
55
- "Алгоритми",
56
- "Дані",
57
- "Обчислювальні потужності",
58
- "Програмний код"
59
- ],
60
- "answer": 1
61
- }
62
- ]
63
  },
64
  {
65
  "id": 3,
66
- "title": "Підготовка даних",
67
- "shortTitle": "Підготовка",
68
- "description": "Сирі дані часто містять невідповідності, відсутні значення або викиди. Підготовка даних забезпечує, що дані чисті та стандартизовані.",
69
- "keyPoints": [
70
- "Очищення даних від невідповідностей",
71
- "Обробка відсутніх значень",
72
- "Нормалізація та стандартизація даних"
73
- ],
74
- "example": "Очищення клінічних даних для забезпечення послідовності в аналізі.",
75
- "tips": [
76
- "Документуйте всі зміни, внесені до вихідних даних",
77
- "Використовуйте автоматизовані інструменти для очищення великих наборів даних",
78
- "Перевірте дані після очищення, щоб переконатися, що вони все ще відображають реальність"
79
- ],
80
- "quiz": [
81
- {
82
- "question": "Які проблеми вирішує етап підготовки даних?",
83
- "options": [
84
- "Невідповідності, відсутні значення, викиди",
85
- "Формулювання проблеми та вибір алгоритму",
86
- "Вибір метрик оцінки",
87
- "Розгортання моделі в виробництво"
88
- ],
89
- "answer": 0
90
- }
91
- ]
92
  },
93
  {
94
  "id": 4,
95
- "title": "Моделювання",
96
- "shortTitle": "Модель",
97
- "description": "Вибір правильного алгоритму є критичним. В залежності від проблеми, ми можемо використовувати регресію, класифікацію або кластеризацію, тощо.",
98
- "keyPoints": [
99
- "Вибір алгоритму на основі типу проблеми",
100
- "Оцінка доступних даних (кількість та якість)",
101
- "Врахування обчислювальних ресурсів та часу навчання"
102
- ],
103
- "example": "Вибір алгоритму машинного навчання для прогнозування часу відновлення пацієнта на основі історичних даних.",
104
- "tips": [
105
- "Почніть з простих моделей перед переходом до складніших",
106
- "Розділіть дані на тренувальні та тестові набори",
107
- "Експериментуйте з різними алгоритмами для порівняння результатів"
108
- ],
109
- "quiz": [
110
- {
111
- "question": "Які фактори слід враховувати при виборі алгоритму?",
112
- "options": [
113
- "Тільки тип проблеми",
114
- "Тільки обчислювальні ресурси",
115
- "Тип проблеми, доступні дані та обчислювальні ресурси",
116
- "Тільки розмір набору даних"
117
- ],
118
- "answer": 2
119
- }
120
- ]
121
  },
122
  {
123
  "id": 5,
124
- "title": "Оцінювання",
125
- "shortTitle": "Оцінка",
126
- "description": "Після навчання, оцінка моделі є важливою для забезпечення точності та надійності.",
127
- "keyPoints": [
128
- "Вибір відповідних метрик для оцінки моделі",
129
- "Порівняння результатів з бізнес-цілями",
130
- "Виявлення областей для покращення"
131
- ],
132
- "example": "Оцінка моделі для виявлення ранніх симптомів захворювання за допомогою метрик точності, чутливості та специфічності.",
133
- "tips": [
134
- "Використовуйте метрики, що відповідають бізнес-цілям",
135
- "Проведіть крос-валідацію для надійності оцінки",
136
- "Порівняйте результати з базовими моделями"
137
- ],
138
- "quiz": [
139
- {
140
- "question": "Які метрики можуть використовуватися для оцінки моделі?",
141
- "options": [
142
- "Тільки точність (accuracy)",
143
- "Точність, повнота, F1-оцінка та інші",
144
- "Тільки час навчання",
145
- "Тільки розмір моделі"
146
- ],
147
- "answer": 1
148
- }
149
- ]
150
  },
151
  {
152
  "id": 6,
153
- "title": "Розгортання",
154
- "shortTitle": "Розгортання",
155
- "description": "Розгортання це процес інтеграції навченої моделі в виробниче середовище, роблячи її доступною для реального використання. Цей крок є вирішальним для забезпечення того, щоб прогнози моделі були постійно доступні та надійні для кінцевих користувачів або автоматизованих систем.",
156
- "keyPoints": [
157
- "Контейнеризація моделі для портативності",
158
- "Створення API для доступу до моделі",
159
- "Налаштування безперервної інтеграції та доставки (CI/CD)",
160
- "Забезпечення масштабованості та доступності"
161
- ],
162
- "example": "Розгортання моделі прогнозування часу відновлення пацієнта в хмарній платформі (AWS, Azure) та інтеграція з системою електронних медичних карт через API.",
163
- "tips": [
164
- "Тестуйте модель в середовищі, подібному до виробничого",
165
- "Впровадіть моніторинг для відстеження продуктивності",
166
- "Плануйте для масштабування від початку"
167
- ],
168
- "quiz": [
169
- {
170
- "question": "Що таке контейнеризація в контексті розгортання моделі?",
171
- "options": [
172
- "Упаковка моделі в фізичний контейнер для транспортування",
173
- "Упаковка моделі, залежностей і середовища в програмний контейнер (як Docker)",
174
- "Обмеження доступу до моделі",
175
- "Зменшення розміру моделі"
176
- ],
177
- "answer": 1
178
- }
179
- ]
180
  },
181
  {
182
  "id": 7,
183
- "title": "Моніторинг та підтримка",
184
- "shortTitle": "Моніторинг",
185
- "description": "Моделі потребують постійного моніторингу, щоб залишатися точними та ефективними. Зміни в розподілі даних можуть погіршити продуктивність з часом.",
186
- "keyPoints": [
187
- "Відстеження продуктивності моделі в реальному часі",
188
- "Виявлення зміщення даних (data drift)",
189
- "Регулярне перенавчання моделі з новими даними",
190
- "Автоматизація розгортання оновлених моделей"
191
- ],
192
- "example": "Використання інструментів моніторингу, таких як Prometheus і Grafana, для відстеження точності моделі прогнозування часу відновлення пацієнта та виявлення будь-яких змін у розподілі даних.",
193
- "tips": [
194
- "Встановіть сповіщення для виявлення зниження продуктивності",
195
- "Плануйте регулярні огляди моделі",
196
- "Документуйте всі зміни та оновлення"
197
- ],
198
- "quiz": [
199
- {
200
- "question": "Чому важливий моніторинг моделі після р��згортання?",
201
- "options": [
202
- "Він не важливий, якщо модель добре навчена",
203
- "Тільки для задоволення регуляторних вимог",
204
- "Для виявлення зміщення даних та підтримки продуктивності моделі",
205
- "Тільки для економії обчислювальних ресурсів"
206
- ],
207
- "answer": 2
208
- }
209
- ]
210
  }
211
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  };
213
 
214
- // Глобальні змінні стану
215
- let currentStepId = null;
216
- let visitedSteps = new Set();
217
- let selectedQuizOption = null;
218
- let quizAnswered = false;
219
-
220
- // Іконки для етапів
221
- const stepIcons = {
222
- 1: '❓',
223
- 2: '📊',
224
- 3: '🔧',
225
- 4: '🤖',
226
- 5: '📈',
227
- 6: '🚀',
228
- 7: '👁️'
229
  };
 
230
 
231
- // Ініціалізація додатка
232
  document.addEventListener('DOMContentLoaded', function() {
233
- initializeApp();
234
- setupEventListeners();
 
235
  });
236
 
237
- function initializeApp() {
238
- // Встановлення заголовку та вступу
239
- document.getElementById('introText').textContent = workflowData.introduction;
240
-
241
- // Рендер бічної панелі
242
- renderSidebar();
243
-
244
- // Рендер візуалізації робочого процесу
245
- renderWorkflowDiagram();
246
-
247
- // Оновлення прогресу
248
- updateProgress();
249
 
250
- // Приховати деталі етапу спочатку
251
- document.getElementById('stepDetailsSection').classList.remove('active');
252
- }
253
-
254
- function setupEventListeners() {
255
- // Кнопки навігації
256
- document.getElementById('nextStepBtn').addEventListener('click', () => navigateStep(1));
257
- document.getElementById('prevStepBtn').addEventListener('click', () => navigateStep(-1));
258
-
259
- // Кнопка скидання прогресу
260
- document.getElementById('resetProgressBtn').addEventListener('click', resetProgress);
261
-
262
- // Кнопка перевірки відповіді
263
- document.getElementById('checkAnswerBtn').addEventListener('click', checkQuizAnswer);
264
- }
265
-
266
- function renderSidebar() {
267
- const sidebarList = document.getElementById('sidebarStepsList');
268
- sidebarList.innerHTML = '';
269
-
270
- workflowData.steps.forEach(step => {
271
- const listItem = document.createElement('li');
272
-
273
- const link = document.createElement('a');
274
- link.href = '#';
275
- link.className = 'step-link';
276
- link.dataset.stepId = step.id;
277
-
278
- const stepNumber = document.createElement('span');
279
- stepNumber.className = 'step-number';
280
- stepNumber.textContent = step.id;
281
-
282
- const stepTitle = document.createElement('span');
283
- stepTitle.textContent = step.shortTitle;
284
-
285
- link.appendChild(stepNumber);
286
- link.appendChild(stepTitle);
287
-
288
- link.addEventListener('click', (e) => {
289
- e.preventDefault();
290
- showStepDetails(step.id);
291
- });
292
-
293
- listItem.appendChild(link);
294
- sidebarList.appendChild(listItem);
295
  });
296
  }
297
 
298
- function renderWorkflowDiagram() {
299
- const diagram = document.getElementById('workflowDiagram');
300
- diagram.innerHTML = '';
301
-
302
- workflowData.steps.forEach(step => {
303
- const stepElement = document.createElement('div');
304
- stepElement.className = 'workflow-step';
305
- stepElement.dataset.stepId = step.id;
306
-
307
- const icon = document.createElement('div');
308
- icon.className = 'step-icon';
309
- icon.textContent = stepIcons[step.id] || '⚡';
310
-
311
- const title = document.createElement('h3');
312
- title.textContent = step.shortTitle;
313
-
314
- stepElement.appendChild(icon);
315
- stepElement.appendChild(title);
316
-
317
- stepElement.addEventListener('click', () => {
318
- showStepDetails(step.id);
319
- });
320
-
321
- diagram.appendChild(stepElement);
322
- });
323
  }
324
 
325
- function showStepDetails(stepId) {
326
- const step = workflowData.steps.find(s => s.id === stepId);
327
- if (!step) return;
328
-
329
- currentStepId = stepId;
330
- visitedSteps.add(stepId);
331
-
332
- // Оновити активний стан
333
- updateActiveStates();
334
-
335
- // Заповнити деталі етапу
336
- document.getElementById('stepTitle').textContent = step.title;
337
- document.getElementById('stepDescription').textContent = step.description;
338
-
339
- // Ключові моменти
340
- const keyPointsList = document.getElementById('stepKeyPoints');
341
- keyPointsList.innerHTML = '';
342
- step.keyPoints.forEach(point => {
343
- const li = document.createElement('li');
344
- li.textContent = point;
345
- keyPointsList.appendChild(li);
346
  });
347
 
348
- // Приклад
349
- document.getElementById('stepExample').textContent = step.example;
350
-
351
- // Поради
352
- const tipsList = document.getElementById('stepTips');
353
- tipsList.innerHTML = '';
354
- step.tips.forEach(tip => {
355
- const li = document.createElement('li');
356
- li.textContent = tip;
357
- tipsList.appendChild(li);
358
  });
359
 
360
- // Вікторина
361
- setupQuiz(step.quiz[0]);
362
-
363
- // Показати панель деталей
364
- document.getElementById('introSection').style.display = 'none';
365
- document.getElementById('stepDetailsSection').classList.add('active');
366
-
367
- // Оновити кнопки навігації
368
- updateNavigationButtons();
369
-
370
- // Оновити прогрес
371
- updateProgress();
372
-
373
- // Прокрутити до верху
374
- document.getElementById('stepDetailsSection').scrollIntoView({ behavior: 'smooth' });
375
  }
376
 
377
- function updateActiveStates() {
378
- // Оновити бічну панель
379
- document.querySelectorAll('.step-link').forEach(link => {
380
- const stepId = parseInt(link.dataset.stepId);
381
- link.classList.remove('active');
382
- if (visitedSteps.has(stepId)) {
383
- link.classList.add('visited');
384
- }
385
- if (stepId === currentStepId) {
386
- link.classList.add('active');
387
- }
388
- });
389
-
390
- // Оновити діаграму
391
- document.querySelectorAll('.workflow-step').forEach(step => {
392
- const stepId = parseInt(step.dataset.stepId);
393
- step.classList.remove('active');
394
- if (visitedSteps.has(stepId)) {
395
- step.classList.add('visited');
396
- }
397
- if (stepId === currentStepId) {
398
- step.classList.add('active');
399
- }
400
- });
401
  }
402
 
403
- function setupQuiz(quiz) {
404
- document.getElementById('quizQuestion').textContent = quiz.question;
405
-
406
- const optionsContainer = document.getElementById('quizOptions');
407
- optionsContainer.innerHTML = '';
408
-
409
- quiz.options.forEach((option, index) => {
410
- const optionElement = document.createElement('div');
411
- optionElement.className = 'quiz-option';
412
- optionElement.textContent = option;
413
- optionElement.dataset.index = index;
414
-
415
- optionElement.addEventListener('click', () => {
416
- if (quizAnswered) return;
417
-
418
- document.querySelectorAll('.quiz-option').forEach(opt => {
419
- opt.classList.remove('selected');
420
- });
421
- optionElement.classList.add('selected');
422
- selectedQuizOption = index;
423
- });
424
-
425
- optionsContainer.appendChild(optionElement);
426
  });
427
 
428
- // Скинути стан вікторини
429
- selectedQuizOption = null;
430
- quizAnswered = false;
431
- document.getElementById('quizResult').classList.remove('show', 'correct', 'incorrect');
432
- document.getElementById('checkAnswerBtn').style.display = 'block';
 
 
 
 
 
 
 
433
  }
434
 
435
- function checkQuizAnswer() {
436
- if (selectedQuizOption === null) {
437
- alert('Будь ласка, оберіть відповідь');
438
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  }
440
 
441
- const step = workflowData.steps.find(s => s.id === currentStepId);
442
- const quiz = step.quiz[0];
443
- const isCorrect = selectedQuizOption === quiz.answer;
 
444
 
445
- // Показати результат
446
- const resultElement = document.getElementById('quizResult');
447
- resultElement.classList.add('show');
448
 
449
- if (isCorrect) {
450
- resultElement.classList.add('correct');
451
- resultElement.textContent = '✅ Правильно! Відмінна робота!';
452
- } else {
453
- resultElement.classList.add('incorrect');
454
- resultElement.textContent = `❌ Неправильно. Правильна відповідь: ${quiz.options[quiz.answer]}`;
455
  }
456
-
457
- // Підсвітити правильну та неправильну відповіді
458
- document.querySelectorAll('.quiz-option').forEach((option, index) => {
459
- if (index === quiz.answer) {
460
- option.classList.add('correct');
461
- } else if (index === selectedQuizOption && !isCorrect) {
462
- option.classList.add('incorrect');
463
- }
464
- });
465
-
466
- quizAnswered = true;
467
- document.getElementById('checkAnswerBtn').style.display = 'none';
468
  }
469
 
470
- function navigateStep(direction) {
471
- if (!currentStepId) return;
472
-
473
- const currentIndex = workflowData.steps.findIndex(s => s.id === currentStepId);
474
- const newIndex = currentIndex + direction;
475
-
476
- if (newIndex >= 0 && newIndex < workflowData.steps.length) {
477
- showStepDetails(workflowData.steps[newIndex].id);
478
- }
 
 
 
 
 
 
 
 
479
  }
480
 
481
- function updateNavigationButtons() {
482
- const currentIndex = workflowData.steps.findIndex(s => s.id === currentStepId);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
 
484
- document.getElementById('prevStepBtn').disabled = currentIndex === 0;
485
- document.getElementById('nextStepBtn').disabled = currentIndex === workflowData.steps.length - 1;
486
  }
487
 
488
- function updateProgress() {
489
- const totalSteps = workflowData.steps.length;
490
- const completedSteps = visitedSteps.size;
491
- const percentage = (completedSteps / totalSteps) * 100;
 
 
 
 
 
492
 
493
- document.getElementById('progressFill').style.width = `${percentage}%`;
494
- document.getElementById('progressText').textContent = `${completedSteps}/${totalSteps} етапів вивчено`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  }
496
 
497
- function resetProgress() {
498
- if (confirm('Ви впевнені, що хочете скинути свій прогрес?')) {
499
- visitedSteps.clear();
500
- currentStepId = null;
501
-
502
- // Приховати деталі етапу та показати вступ
503
- document.getElementById('stepDetailsSection').classList.remove('active');
504
- document.getElementById('introSection').style.display = 'block';
505
-
506
- // Оновити стани
507
- updateActiveStates();
508
- updateProgress();
509
-
510
- // Прокрутити до верху
511
- window.scrollTo({ top: 0, behavior: 'smooth' });
512
- }
513
  }
 
1
+ // Application data
2
+ const appData = {
3
+ "lifecycleStages": [
 
 
4
  {
5
  "id": 1,
6
+ "name": "Problem Formulation",
7
+ "icon": "💡",
8
+ "description": "Transform real-world problems into data-driven questions",
9
+ "example": "Healthcare: Predicting patient recovery time based on medical history",
10
+ "keyPoints": ["Define business objectives", "Identify success metrics", "Translate to ML problem", "Set constraints and requirements"],
11
+ "status": "completed"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  },
13
  {
14
+ "id": 2,
15
+ "name": "Data Collection",
16
+ "icon": "📊",
17
+ "description": "Gather relevant data from reliable sources",
18
+ "sources": ["Clinical databases", "IoT sensors", "Public datasets", "APIs"],
19
+ "compliance": {"HIPAA": true, "GDPR": true, "SOX": false},
20
+ "status": "completed"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  },
22
  {
23
  "id": 3,
24
+ "name": "Data Preprocessing",
25
+ "icon": "🔧",
26
+ "description": "Clean and standardize data for analysis",
27
+ "metrics": {"missingValues": 12, "normalization": "StandardScaler", "categoricalEncoding": "OneHot", "outliers": 8},
28
+ "status": "in-progress"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  },
30
  {
31
  "id": 4,
32
+ "name": "Modeling",
33
+ "icon": "🤖",
34
+ "description": "Select and apply appropriate algorithms",
35
+ "modelTypes": ["Classification", "Regression", "Clustering"],
36
+ "algorithms": ["Random Forest", "Logistic Regression", "SVM", "Neural Networks"],
37
+ "status": "pending"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  },
39
  {
40
  "id": 5,
41
+ "name": "Evaluation",
42
+ "icon": "📈",
43
+ "description": "Assess model performance and reliability",
44
+ "metrics": {"accuracy": 0.94, "precision": 0.91, "recall": 0.89, "f1Score": 0.90},
45
+ "status": "pending"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  },
47
  {
48
  "id": 6,
49
+ "name": "Deployment",
50
+ "icon": "🚀",
51
+ "description": "Deploy model to production environment",
52
+ "pipeline": {"docker": true, "kubernetes": true, "cicd": "Jenkins", "api": "REST"},
53
+ "status": "pending"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  },
55
  {
56
  "id": 7,
57
+ "name": "Monitoring & Maintenance",
58
+ "icon": "🔍",
59
+ "description": "Monitor performance and maintain model accuracy",
60
+ "alerts": {"dataDrift": false, "accuracyDecay": 2.1, "retrainingDue": "2025-07-15"},
61
+ "status": "pending"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  }
63
+ ],
64
+ "industries": [
65
+ {"name": "Healthcare", "examples": ["Patient recovery prediction", "Disease diagnosis", "Drug discovery"]},
66
+ {"name": "Retail", "examples": ["Customer segmentation", "Demand forecasting", "Price optimization"]},
67
+ {"name": "Finance", "examples": ["Fraud detection", "Credit scoring", "Algorithmic trading"]},
68
+ {"name": "Manufacturing", "examples": ["Predictive maintenance", "Quality control", "Supply chain optimization"]},
69
+ {"name": "Education", "examples": ["Student performance prediction", "Personalized learning", "Dropout prevention"]}
70
+ ],
71
+ "modelTypes": [
72
+ {"name": "Logistic Regression", "type": "Classification", "accuracy": 0.85},
73
+ {"name": "Random Forest", "type": "Classification", "accuracy": 0.92},
74
+ {"name": "SVM", "type": "Classification", "accuracy": 0.88},
75
+ {"name": "Neural Networks", "type": "Classification", "accuracy": 0.94},
76
+ {"name": "Linear Regression", "type": "Regression", "rmse": 0.23},
77
+ {"name": "K-Means", "type": "Clustering", "silhouette": 0.67}
78
+ ],
79
+ "complianceRequirements": {
80
+ "Healthcare": ["HIPAA", "FDA", "HITECH"],
81
+ "Finance": ["SOX", "GDPR", "PCI-DSS"],
82
+ "Retail": ["GDPR", "CCPA"],
83
+ "Manufacturing": ["ISO 27001", "GDPR"],
84
+ "Education": ["FERPA", "COPPA"]
85
+ }
86
  };
87
 
88
+ // Global state
89
+ let currentStage = null;
90
+ let currentFilters = {
91
+ industry: '',
92
+ model: '',
93
+ version: ''
 
 
 
 
 
 
 
 
 
94
  };
95
+ let evaluationChart = null;
96
 
97
+ // Initialize the application
98
  document.addEventListener('DOMContentLoaded', function() {
99
+ initializeTimeline();
100
+ initializeFilters();
101
+ updateProgressSummary();
102
  });
103
 
104
+ // Initialize timeline with stages
105
+ function initializeTimeline() {
106
+ const timelineStages = document.getElementById('timelineStages');
 
 
 
 
 
 
 
 
 
107
 
108
+ appData.lifecycleStages.forEach((stage, index) => {
109
+ const stageElement = createTimelineStage(stage, index);
110
+ timelineStages.appendChild(stageElement);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  });
112
  }
113
 
114
+ // Create timeline stage element
115
+ function createTimelineStage(stage, index) {
116
+ const stageDiv = document.createElement('div');
117
+ stageDiv.className = `timeline-stage timeline-stage--${index % 2 === 0 ? 'left' : 'right'} timeline-stage--${stage.status}`;
118
+ stageDiv.setAttribute('data-stage-id', stage.id);
119
+
120
+ stageDiv.innerHTML = `
121
+ <div class="timeline-stage__card">
122
+ <h3 class="timeline-stage__title">${stage.name}</h3>
123
+ <p class="timeline-stage__description">${stage.description}</p>
124
+ <span class="timeline-stage__status status--${stage.status}">${stage.status.replace('-', ' ')}</span>
125
+ </div>
126
+ <div class="timeline-stage__node">${stage.icon}</div>
127
+ `;
128
+
129
+ stageDiv.addEventListener('click', () => selectStage(stage.id));
130
+
131
+ return stageDiv;
 
 
 
 
 
 
 
132
  }
133
 
134
+ // Initialize filters
135
+ function initializeFilters() {
136
+ const industryFilter = document.getElementById('industryFilter');
137
+ const modelFilter = document.getElementById('modelFilter');
138
+ const versionFilter = document.getElementById('versionFilter');
139
+
140
+ industryFilter.addEventListener('change', (e) => {
141
+ currentFilters.industry = e.target.value;
142
+ applyFilters();
 
 
 
 
 
 
 
 
 
 
 
 
143
  });
144
 
145
+ modelFilter.addEventListener('change', (e) => {
146
+ currentFilters.model = e.target.value;
147
+ applyFilters();
 
 
 
 
 
 
 
148
  });
149
 
150
+ versionFilter.addEventListener('change', (e) => {
151
+ currentFilters.version = e.target.value;
152
+ applyFilters();
153
+ });
 
 
 
 
 
 
 
 
 
 
 
154
  }
155
 
156
+ // Apply filters (placeholder for future filtering logic)
157
+ function applyFilters() {
158
+ // This could filter content based on selected industry, model, etc.
159
+ console.log('Filters applied:', currentFilters);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  }
161
 
162
+ // Select a stage and show its details
163
+ function selectStage(stageId) {
164
+ // Remove active class from all stages
165
+ document.querySelectorAll('.timeline-stage').forEach(stage => {
166
+ stage.classList.remove('timeline-stage--active');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  });
168
 
169
+ // Add active class to selected stage
170
+ const selectedStage = document.querySelector(`[data-stage-id="${stageId}"]`);
171
+ if (selectedStage) {
172
+ selectedStage.classList.add('timeline-stage--active');
173
+ }
174
+
175
+ // Find stage data
176
+ const stage = appData.lifecycleStages.find(s => s.id === stageId);
177
+ if (stage) {
178
+ currentStage = stage;
179
+ showStageDetails(stage);
180
+ }
181
  }
182
 
183
+ // Show detailed information for a stage
184
+ function showStageDetails(stage) {
185
+ const stageDetail = document.getElementById('stageDetail');
186
+
187
+ let content = `
188
+ <div class="stage-content">
189
+ <div class="stage-header">
190
+ <div class="stage-icon">${stage.icon}</div>
191
+ <div>
192
+ <h2 class="stage-title">${stage.name}</h2>
193
+ <p class="stage-description">${stage.description}</p>
194
+ </div>
195
+ </div>
196
+ <div class="stage-sections">
197
+ `;
198
+
199
+ // Generate content based on stage type
200
+ switch(stage.id) {
201
+ case 1: // Problem Formulation
202
+ content += `
203
+ <div class="stage-section">
204
+ <h4>Real-world Example</h4>
205
+ <p>${stage.example}</p>
206
+ </div>
207
+ <div class="stage-section">
208
+ <h4>Key Activities</h4>
209
+ <ul class="key-points">
210
+ ${stage.keyPoints.map(point => `<li>${point}</li>`).join('')}
211
+ </ul>
212
+ </div>
213
+ `;
214
+ break;
215
+
216
+ case 2: // Data Collection
217
+ content += `
218
+ <div class="stage-section">
219
+ <h4>Data Sources</h4>
220
+ <ul class="key-points">
221
+ ${stage.sources.map(source => `<li>${source}</li>`).join('')}
222
+ </ul>
223
+ </div>
224
+ <div class="stage-section">
225
+ <h4>Compliance Status</h4>
226
+ <div class="compliance-badges">
227
+ ${Object.entries(stage.compliance).map(([key, value]) =>
228
+ `<span class="compliance-badge compliance-badge--${value ? 'active' : 'inactive'}">${key}</span>`
229
+ ).join('')}
230
+ </div>
231
+ </div>
232
+ `;
233
+ break;
234
+
235
+ case 3: // Data Preprocessing
236
+ content += `
237
+ <div class="stage-section">
238
+ <h4>Data Quality Metrics</h4>
239
+ <div class="metrics-grid">
240
+ <div class="metric-item">
241
+ <span class="metric-label">Missing Values</span>
242
+ <span class="metric-value">${stage.metrics.missingValues}%</span>
243
+ </div>
244
+ <div class="metric-item">
245
+ <span class="metric-label">Normalization</span>
246
+ <span class="metric-value">${stage.metrics.normalization}</span>
247
+ </div>
248
+ <div class="metric-item">
249
+ <span class="metric-label">Categorical Encoding</span>
250
+ <span class="metric-value">${stage.metrics.categoricalEncoding}</span>
251
+ </div>
252
+ <div class="metric-item">
253
+ <span class="metric-label">Outliers Detected</span>
254
+ <span class="metric-value">${stage.metrics.outliers}</span>
255
+ </div>
256
+ </div>
257
+ </div>
258
+ `;
259
+ break;
260
+
261
+ case 4: // Modeling
262
+ content += `
263
+ <div class="stage-section">
264
+ <h4>Select Model Type</h4>
265
+ <div class="model-selector">
266
+ ${stage.modelTypes.map(type =>
267
+ `<div class="model-option" data-model-type="${type}">${type}</div>`
268
+ ).join('')}
269
+ </div>
270
+ <div id="modelOutput" class="mt-8"></div>
271
+ </div>
272
+ `;
273
+ break;
274
+
275
+ case 5: // Evaluation
276
+ content += `
277
+ <div class="stage-section">
278
+ <h4>Performance Metrics</h4>
279
+ <div class="metrics-grid">
280
+ <div class="metric-item">
281
+ <span class="metric-label">Accuracy</span>
282
+ <span class="metric-value">${(stage.metrics.accuracy * 100).toFixed(1)}%</span>
283
+ </div>
284
+ <div class="metric-item">
285
+ <span class="metric-label">Precision</span>
286
+ <span class="metric-value">${(stage.metrics.precision * 100).toFixed(1)}%</span>
287
+ </div>
288
+ <div class="metric-item">
289
+ <span class="metric-label">Recall</span>
290
+ <span class="metric-value">${(stage.metrics.recall * 100).toFixed(1)}%</span>
291
+ </div>
292
+ <div class="metric-item">
293
+ <span class="metric-label">F1-Score</span>
294
+ <span class="metric-value">${(stage.metrics.f1Score * 100).toFixed(1)}%</span>
295
+ </div>
296
+ </div>
297
+ <div class="chart-container">
298
+ <canvas id="evaluationChart"></canvas>
299
+ </div>
300
+ </div>
301
+ `;
302
+ break;
303
+
304
+ case 6: // Deployment
305
+ content += `
306
+ <div class="stage-section">
307
+ <h4>Infrastructure Status</h4>
308
+ <div class="metrics-grid">
309
+ <div class="metric-item">
310
+ <span class="metric-label">Docker</span>
311
+ <span class="metric-value">${stage.pipeline.docker ? '✓ Ready' : '✗ Not Ready'}</span>
312
+ </div>
313
+ <div class="metric-item">
314
+ <span class="metric-label">Kubernetes</span>
315
+ <span class="metric-value">${stage.pipeline.kubernetes ? '✓ Ready' : '✗ Not Ready'}</span>
316
+ </div>
317
+ <div class="metric-item">
318
+ <span class="metric-label">CI/CD</span>
319
+ <span class="metric-value">${stage.pipeline.cicd}</span>
320
+ </div>
321
+ <div class="metric-item">
322
+ <span class="metric-label">API Type</span>
323
+ <span class="metric-value">${stage.pipeline.api}</span>
324
+ </div>
325
+ </div>
326
+ </div>
327
+ `;
328
+ break;
329
+
330
+ case 7: // Monitoring & Maintenance
331
+ content += `
332
+ <div class="stage-section">
333
+ <h4>System Health</h4>
334
+ <div class="alert alert--${stage.alerts.dataDrift ? 'warning' : 'success'}">
335
+ <strong>Data Drift:</strong> ${stage.alerts.dataDrift ? 'Detected - Review required' : 'No drift detected'}
336
+ </div>
337
+ <div class="alert alert--warning">
338
+ <strong>Accuracy Decay:</strong> ${stage.alerts.accuracyDecay}% decline detected
339
+ </div>
340
+ <div class="alert alert--info">
341
+ <strong>Next Retraining:</strong> Scheduled for ${stage.alerts.retrainingDue}
342
+ </div>
343
+ </div>
344
+ `;
345
+ break;
346
  }
347
 
348
+ content += `
349
+ </div>
350
+ </div>
351
+ `;
352
 
353
+ stageDetail.innerHTML = content;
 
 
354
 
355
+ // Add event listeners for interactive elements
356
+ if (stage.id === 4) {
357
+ setupModelSelector();
358
+ } else if (stage.id === 5) {
359
+ setTimeout(() => createEvaluationChart(stage.metrics), 100);
 
360
  }
 
 
 
 
 
 
 
 
 
 
 
 
361
  }
362
 
363
+ // Setup model selector for modeling stage
364
+ function setupModelSelector() {
365
+ document.querySelectorAll('.model-option').forEach(option => {
366
+ option.addEventListener('click', function() {
367
+ // Remove selected class from all options
368
+ document.querySelectorAll('.model-option').forEach(opt => {
369
+ opt.classList.remove('model-option--selected');
370
+ });
371
+
372
+ // Add selected class to clicked option
373
+ this.classList.add('model-option--selected');
374
+
375
+ // Show sample output
376
+ const modelType = this.getAttribute('data-model-type');
377
+ showModelOutput(modelType);
378
+ });
379
+ });
380
  }
381
 
382
+ // Show model output based on selected type
383
+ function showModelOutput(modelType) {
384
+ const outputDiv = document.getElementById('modelOutput');
385
+ const relevantModels = appData.modelTypes.filter(model => model.type === modelType);
386
+
387
+ let output = `
388
+ <h5>Available ${modelType} Models:</h5>
389
+ <div class="model-selector">
390
+ `;
391
+
392
+ relevantModels.forEach(model => {
393
+ const metric = model.accuracy ? `Accuracy: ${(model.accuracy * 100).toFixed(1)}%` :
394
+ model.rmse ? `RMSE: ${model.rmse}` :
395
+ `Silhouette Score: ${model.silhouette}`;
396
+
397
+ output += `
398
+ <div class="model-option">
399
+ <strong>${model.name}</strong><br>
400
+ <small>${metric}</small>
401
+ </div>
402
+ `;
403
+ });
404
 
405
+ output += '</div>';
406
+ outputDiv.innerHTML = output;
407
  }
408
 
409
+ // Create evaluation chart
410
+ function createEvaluationChart(metrics) {
411
+ const ctx = document.getElementById('evaluationChart');
412
+ if (!ctx) return;
413
+
414
+ // Destroy existing chart if it exists
415
+ if (evaluationChart) {
416
+ evaluationChart.destroy();
417
+ }
418
 
419
+ evaluationChart = new Chart(ctx, {
420
+ type: 'bar',
421
+ data: {
422
+ labels: ['Accuracy', 'Precision', 'Recall', 'F1-Score'],
423
+ datasets: [{
424
+ label: 'Performance Metrics',
425
+ data: [metrics.accuracy, metrics.precision, metrics.recall, metrics.f1Score],
426
+ backgroundColor: ['#1FB8CD', '#FFC185', '#B4413C', '#5D878F'],
427
+ borderColor: ['#1FB8CD', '#FFC185', '#B4413C', '#5D878F'],
428
+ borderWidth: 2,
429
+ borderRadius: 8
430
+ }]
431
+ },
432
+ options: {
433
+ responsive: true,
434
+ maintainAspectRatio: false,
435
+ plugins: {
436
+ legend: {
437
+ display: false
438
+ },
439
+ tooltip: {
440
+ callbacks: {
441
+ label: function(context) {
442
+ return `${context.label}: ${(context.parsed.y * 100).toFixed(1)}%`;
443
+ }
444
+ }
445
+ }
446
+ },
447
+ scales: {
448
+ y: {
449
+ beginAtZero: true,
450
+ max: 1,
451
+ ticks: {
452
+ callback: function(value) {
453
+ return (value * 100).toFixed(0) + '%';
454
+ }
455
+ }
456
+ }
457
+ }
458
+ }
459
+ });
460
  }
461
 
462
+ // Update progress summary
463
+ function updateProgressSummary() {
464
+ const completed = appData.lifecycleStages.filter(stage => stage.status === 'completed').length;
465
+ const inProgress = appData.lifecycleStages.filter(stage => stage.status === 'in-progress').length;
466
+ const pending = appData.lifecycleStages.filter(stage => stage.status === 'pending').length;
467
+
468
+ document.getElementById('completedCount').textContent = completed;
469
+ document.getElementById('inProgressCount').textContent = inProgress;
470
+ document.getElementById('pendingCount').textContent = pending;
 
 
 
 
 
 
 
471
  }