Brightsun10 commited on
Commit
98cebf7
·
verified ·
1 Parent(s): ebf0780

Update static/index.html

Browse files
Files changed (1) hide show
  1. static/index.html +135 -76
static/index.html CHANGED
@@ -1,111 +1,170 @@
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>AI Image Classifier</title>
7
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"/>
8
  <style>
9
- body {
10
- background: #f8f9fa;
 
11
  }
12
- .preview-box {
13
- border: 1px dashed #6c757d;
14
- border-radius: 10px;
15
- padding: 1rem;
16
  text-align: center;
 
 
 
17
  }
18
- #preview {
19
- max-height: 300px;
 
20
  }
21
  </style>
22
  </head>
23
- <body>
24
  <div class="container py-5">
25
- <h1 class="text-center text-primary mb-4">🧠 AI Image Classifier</h1>
26
-
27
- <div class="card shadow-lg">
28
- <div class="card-body">
29
- <form id="uploadForm">
30
- <div class="mb-3">
31
- <label for="imageInput" class="form-label">Choose an Image</label>
32
- <input type="file" class="form-control" id="imageInput" accept="image/*" required />
33
- </div>
34
- <div class="text-center">
35
- <button type="submit" class="btn btn-primary px-4">Predict</button>
36
- </div>
37
- </form>
38
-
39
- <div class="preview-box mt-4 d-none" id="previewContainer">
40
- <p class="text-muted mb-2">Image Preview</p>
41
- <img id="preview" src="#" class="img-fluid rounded" alt="Image Preview"/>
42
- </div>
43
-
44
- <div id="loader" class="text-center mt-4 d-none">
45
- <div class="spinner-border text-primary" role="status"></div>
46
- <p class="text-muted mt-2">Processing...</p>
47
- </div>
48
-
49
- <div id="result" class="alert d-none mt-4"></div>
50
- </div>
51
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  </div>
53
 
 
54
  <script>
55
  const form = document.getElementById('uploadForm');
56
  const imageInput = document.getElementById('imageInput');
57
- const preview = document.getElementById('preview');
58
- const previewContainer = document.getElementById('previewContainer');
59
  const result = document.getElementById('result');
60
- const loader = document.getElementById('loader');
 
 
 
 
 
 
61
 
62
- form.addEventListener('submit', async (e) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  e.preventDefault();
 
 
 
 
 
 
64
 
65
- const file = imageInput.files[0];
66
- if (!file) return;
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- // Show image preview
69
- const reader = new FileReader();
70
- reader.onload = () => {
71
- preview.src = reader.result;
72
- previewContainer.classList.remove('d-none');
73
- };
74
- reader.readAsDataURL(file);
75
 
76
- // UI state: show loader, hide result
77
- loader.classList.remove('d-none');
78
  result.classList.add('d-none');
 
79
 
80
- const formData = new FormData();
81
- formData.append('file', file);
82
 
83
- try {
84
- const response = await fetch('/predict', {
85
- method: 'POST',
86
- body: formData
87
- });
 
 
 
 
88
 
89
- const data = await response.json();
 
90
 
91
- loader.classList.add('d-none');
 
 
92
 
93
- if (data.prediction) {
94
- result.textContent = `🔍 Prediction: ${data.prediction}`;
95
- result.className = 'alert alert-success mt-4';
96
- } else {
97
- result.textContent = '⚠️ No prediction returned.';
98
- result.className = 'alert alert-warning mt-4';
99
  }
100
-
101
- result.classList.remove('d-none');
102
- } catch (err) {
103
- loader.classList.add('d-none');
104
- result.textContent = '❌ Error during prediction.';
105
- result.className = 'alert alert-danger mt-4';
106
- result.classList.remove('d-none');
107
  }
 
 
 
 
 
108
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  </script>
110
  </body>
111
  </html>
 
1
  <!DOCTYPE html>
2
+ <html lang="en" data-bs-theme="light">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>AI Image Classifier</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
8
  <style>
9
+ body.dark-mode {
10
+ background-color: #121212;
11
+ color: white;
12
  }
13
+ .drop-zone {
14
+ border: 2px dashed #6c757d;
15
+ padding: 30px;
 
16
  text-align: center;
17
+ cursor: pointer;
18
+ border-radius: 8px;
19
+ background-color: #f8f9fa;
20
  }
21
+ .drop-zone.dark-mode {
22
+ background-color: #1e1e1e;
23
+ border-color: #aaa;
24
  }
25
  </style>
26
  </head>
27
+ <body class="bg-light">
28
  <div class="container py-5">
29
+ <div class="d-flex justify-content-between align-items-center mb-4">
30
+ <h2 class="text-center flex-grow-1">Upload Images for Classification</h2>
31
+ <button class="btn btn-outline-secondary ms-3" id="toggleMode">Toggle Dark Mode</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  </div>
33
+
34
+ <div class="drop-zone" id="dropZone">
35
+ Drag & Drop Images Here or Click to Upload
36
+ <input type="file" id="imageInput" class="form-control d-none" accept="image/*" multiple>
37
+ </div>
38
+
39
+ <form id="uploadForm" class="mt-3">
40
+ <button type="submit" class="btn btn-primary">Predict</button>
41
+ </form>
42
+
43
+ <div id="result" class="alert d-none mt-3"></div>
44
+
45
+ <div id="previewContainer" class="row mt-4"></div>
46
+
47
+ <canvas id="historyChart" class="mt-5 w-100"></canvas>
48
  </div>
49
 
50
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
51
  <script>
52
  const form = document.getElementById('uploadForm');
53
  const imageInput = document.getElementById('imageInput');
 
 
54
  const result = document.getElementById('result');
55
+ const previewContainer = document.getElementById('previewContainer');
56
+ const dropZone = document.getElementById('dropZone');
57
+ const toggleModeBtn = document.getElementById('toggleMode');
58
+ const chartCanvas = document.getElementById('historyChart');
59
+
60
+ let chart;
61
+ let history = [];
62
 
63
+ toggleModeBtn.addEventListener('click', () => {
64
+ document.body.classList.toggle('dark-mode');
65
+ dropZone.classList.toggle('dark-mode');
66
+ document.documentElement.setAttribute("data-bs-theme",
67
+ document.body.classList.contains('dark-mode') ? "dark" : "light");
68
+ });
69
+
70
+ dropZone.addEventListener('click', () => imageInput.click());
71
+ dropZone.addEventListener('dragover', e => {
72
+ e.preventDefault();
73
+ dropZone.classList.add('border-primary');
74
+ });
75
+ dropZone.addEventListener('dragleave', () => dropZone.classList.remove('border-primary'));
76
+ dropZone.addEventListener('drop', e => {
77
  e.preventDefault();
78
+ dropZone.classList.remove('border-primary');
79
+ imageInput.files = e.dataTransfer.files;
80
+ showPreviews(imageInput.files);
81
+ });
82
+
83
+ imageInput.addEventListener('change', () => showPreviews(imageInput.files));
84
 
85
+ function showPreviews(files) {
86
+ previewContainer.innerHTML = '';
87
+ for (const file of files) {
88
+ const reader = new FileReader();
89
+ reader.onload = e => {
90
+ const img = document.createElement('img');
91
+ img.src = e.target.result;
92
+ img.classList.add('img-thumbnail', 'col-md-3', 'm-2');
93
+ previewContainer.appendChild(img);
94
+ };
95
+ reader.readAsDataURL(file);
96
+ }
97
+ }
98
 
99
+ form.addEventListener('submit', async e => {
100
+ e.preventDefault();
101
+ const files = imageInput.files;
102
+ if (!files.length) return;
 
 
 
103
 
 
 
104
  result.classList.add('d-none');
105
+ result.classList.remove('alert-success', 'alert-danger');
106
 
107
+ previewContainer.innerHTML += `<p class="text-muted">Predicting...</p>`;
 
108
 
109
+ for (const file of files) {
110
+ const formData = new FormData();
111
+ formData.append('file', file);
112
+ try {
113
+ const response = await fetch('http://127.0.0.1:8000/predict', {
114
+ method: 'POST',
115
+ body: formData
116
+ });
117
+ const data = await response.json();
118
 
119
+ const label = data.prediction || 'Error';
120
+ history.push(label);
121
 
122
+ const para = document.createElement('p');
123
+ para.textContent = `${file.name}: ${label}`;
124
+ previewContainer.appendChild(para);
125
 
126
+ } catch (err) {
127
+ const para = document.createElement('p');
128
+ para.textContent = `${file.name}: Error predicting`;
129
+ previewContainer.appendChild(para);
 
 
130
  }
 
 
 
 
 
 
 
131
  }
132
+
133
+ updateChart();
134
+ result.classList.add('alert', 'alert-success');
135
+ result.textContent = 'Predictions completed.';
136
+ result.classList.remove('d-none');
137
  });
138
+
139
+ function updateChart() {
140
+ const counts = {};
141
+ history.forEach(label => counts[label] = (counts[label] || 0) + 1);
142
+ const labels = Object.keys(counts);
143
+ const values = Object.values(counts);
144
+
145
+ if (chart) chart.destroy();
146
+ chart = new Chart(chartCanvas, {
147
+ type: 'bar',
148
+ data: {
149
+ labels,
150
+ datasets: [{
151
+ label: 'Prediction Count',
152
+ data: values,
153
+ backgroundColor: 'rgba(54, 162, 235, 0.6)'
154
+ }]
155
+ },
156
+ options: {
157
+ responsive: true,
158
+ plugins: {
159
+ legend: { display: false },
160
+ title: {
161
+ display: true,
162
+ text: 'Prediction Analytics'
163
+ }
164
+ }
165
+ }
166
+ });
167
+ }
168
  </script>
169
  </body>
170
  </html>