alexdatamed commited on
Commit
3dd786e
·
verified ·
1 Parent(s): babf82e

Upload app.js

Browse files
Files changed (1) hide show
  1. app.js +513 -0
app.js ADDED
@@ -0,0 +1,513 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }