iremrit commited on
Commit
10fa43e
·
verified ·
1 Parent(s): db9043f

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +442 -0
index.html ADDED
@@ -0,0 +1,442 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>FinRisk-AI</title>
7
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>💳</text></svg>">
8
+ <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap" rel="stylesheet">
9
+ <style>
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ font-family: 'Montserrat', sans-serif;
18
+ background: linear-gradient(135deg, #0f4c75 0%, #3282b8 25%, #bbe1fa 50%, #1b262c 75%, #0f4c75 100%);
19
+ background-size: 400% 400%;
20
+ animation: gradientShift 15s ease infinite;
21
+ min-height: 100vh;
22
+ padding: 20px;
23
+ position: relative;
24
+ overflow: hidden;
25
+ }
26
+
27
+ body::before {
28
+ content: '';
29
+ position: absolute;
30
+ top: 0;
31
+ left: 0;
32
+ right: 0;
33
+ bottom: 0;
34
+ background: radial-gradient(circle at 20% 80%, rgba(0, 128, 0, 0.1) 0%, transparent 50%),
35
+ radial-gradient(circle at 80% 20%, rgba(255, 69, 0, 0.1) 0%, transparent 50%),
36
+ radial-gradient(circle at 40% 40%, rgba(0, 139, 139, 0.1) 0%, transparent 50%);
37
+ animation: float 20s ease-in-out infinite;
38
+ pointer-events: none;
39
+ }
40
+
41
+ @keyframes gradientShift {
42
+ 0% { background-position: 0% 50%; }
43
+ 50% { background-position: 100% 50%; }
44
+ 100% { background-position: 0% 50%; }
45
+ }
46
+
47
+ @keyframes float {
48
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
49
+ 33% { transform: translateY(-10px) rotate(1deg); }
50
+ 66% { transform: translateY(10px) rotate(-1deg); }
51
+ }
52
+
53
+ .container {
54
+ max-width: 1200px;
55
+ margin: 0 auto;
56
+ }
57
+
58
+ .header {
59
+ text-align: center;
60
+ color: white;
61
+ margin-bottom: 30px;
62
+ }
63
+
64
+ .header h1 {
65
+ font-size: 2.8rem;
66
+ margin-bottom: 10px;
67
+ font-weight: 700;
68
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
69
+ }
70
+
71
+ .header p {
72
+ font-size: 1.2rem;
73
+ opacity: 0.9;
74
+ font-weight: 300;
75
+ }
76
+
77
+ .card {
78
+ background: white;
79
+ border-radius: 15px;
80
+ padding: 30px;
81
+ box-shadow: 0 10px 30px rgba(0,0,0,0.2);
82
+ margin-bottom: 20px;
83
+ }
84
+
85
+ .form-grid {
86
+ display: grid;
87
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
88
+ gap: 15px;
89
+ margin-bottom: 20px;
90
+ }
91
+
92
+ .form-group {
93
+ display: flex;
94
+ flex-direction: column;
95
+ }
96
+
97
+ .form-group label {
98
+ font-size: 0.85rem;
99
+ font-weight: 600;
100
+ margin-bottom: 5px;
101
+ color: #34495e;
102
+ }
103
+
104
+ .form-group input {
105
+ padding: 10px;
106
+ border: 2px solid #e0e0e0;
107
+ border-radius: 8px;
108
+ font-size: 0.95rem;
109
+ transition: border-color 0.3s;
110
+ }
111
+
112
+ .form-group input:focus {
113
+ outline: none;
114
+ border-color: #667eea;
115
+ }
116
+
117
+ .button-group {
118
+ display: flex;
119
+ gap: 10px;
120
+ justify-content: center;
121
+ }
122
+
123
+ .btn {
124
+ padding: 12px 30px;
125
+ border: none;
126
+ border-radius: 8px;
127
+ font-size: 1rem;
128
+ font-weight: 600;
129
+ cursor: pointer;
130
+ transition: all 0.3s;
131
+ }
132
+
133
+ .btn-primary {
134
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
135
+ color: white;
136
+ }
137
+
138
+ .btn-primary:hover {
139
+ transform: translateY(-2px);
140
+ box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
141
+ }
142
+
143
+ .btn:disabled {
144
+ opacity: 0.5;
145
+ cursor: not-allowed;
146
+ transform: none;
147
+ }
148
+
149
+ .btn-secondary {
150
+ background: #f0f0f0;
151
+ color: #34495e;
152
+ }
153
+
154
+ .btn-secondary:hover {
155
+ background: #e0e0e0;
156
+ }
157
+
158
+ .result {
159
+ display: none;
160
+ padding: 20px;
161
+ border-radius: 10px;
162
+ margin-top: 20px;
163
+ }
164
+
165
+ .result.show {
166
+ display: block;
167
+ animation: fadeIn 0.5s;
168
+ }
169
+
170
+ @keyframes fadeIn {
171
+ from { opacity: 0; transform: translateY(-10px); }
172
+ to { opacity: 1; transform: translateY(0); }
173
+ }
174
+
175
+ .result-low {
176
+ background: #d4edda;
177
+ border-left: 5px solid #28a745;
178
+ }
179
+
180
+ .result-medium {
181
+ background: #fff3cd;
182
+ border-left: 5px solid #ffc107;
183
+ }
184
+
185
+ .result-high {
186
+ background: #f8d7da;
187
+ border-left: 5px solid #dc3545;
188
+ }
189
+
190
+ .result h3 {
191
+ margin-bottom: 10px;
192
+ font-size: 1.3rem;
193
+ }
194
+
195
+ .result-details {
196
+ display: grid;
197
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
198
+ gap: 15px;
199
+ margin-top: 15px;
200
+ }
201
+
202
+ .result-item {
203
+ padding: 10px;
204
+ background: rgba(255,255,255,0.5);
205
+ border-radius: 5px;
206
+ }
207
+
208
+ .result-item strong {
209
+ display: block;
210
+ margin-bottom: 5px;
211
+ font-size: 0.9rem;
212
+ }
213
+
214
+ .result-item span {
215
+ font-size: 1.2rem;
216
+ font-weight: 600;
217
+ }
218
+
219
+ .loading {
220
+ display: none;
221
+ text-align: center;
222
+ padding: 20px;
223
+ }
224
+
225
+ .loading.show {
226
+ display: block;
227
+ }
228
+
229
+ .spinner {
230
+ border: 4px solid #f3f3f3;
231
+ border-top: 4px solid #667eea;
232
+ border-radius: 50%;
233
+ width: 40px;
234
+ height: 40px;
235
+ animation: spin 1s linear infinite;
236
+ margin: 0 auto;
237
+ }
238
+
239
+ @keyframes spin {
240
+ 0% { transform: rotate(0deg); }
241
+ 100% { transform: rotate(360deg); }
242
+ }
243
+
244
+ .footer {
245
+ text-align: center;
246
+ color: white;
247
+ margin-top: 30px;
248
+ opacity: 0.8;
249
+ font-weight: 300;
250
+ }
251
+ </style>
252
+ </head>
253
+ <body>
254
+ <div class="container">
255
+ <div class="header">
256
+ <h1>💳 FinRisk-AI</h1>
257
+ <p>Intelligent Credit Risk Analysis Powered by AI</p>
258
+ </div>
259
+
260
+ <div class="card">
261
+ <form id="predictionForm">
262
+ <div class="form-grid" id="featureInputs"></div>
263
+
264
+ <div class="button-group">
265
+ <button type="submit" class="btn btn-primary">Predict Risk</button>
266
+ <button type="button" class="btn btn-secondary" onclick="fillSampleData()">Fill Sample Data</button>
267
+ <button type="reset" class="btn btn-secondary">Clear Form</button>
268
+ </div>
269
+
270
+ </form>
271
+
272
+ <div class="loading" id="loading">
273
+ <div class="spinner"></div>
274
+ <p style="margin-top: 10px;">Calculating risk...</p>
275
+ </div>
276
+
277
+ <div class="result" id="result"></div>
278
+ </div>
279
+
280
+ <div class="footer">
281
+ <p>FinRisk-AI v1.0 | 50+ Features | Stacking Classifier</p>
282
+ </div>
283
+ </div>
284
+
285
+ <script>
286
+ const features = {{ features | tojson }};
287
+
288
+ function createFeatureInputs() {
289
+ const container = document.getElementById('featureInputs');
290
+ if (features && features.top_10_features) {
291
+ features.top_10_features.forEach(feature => {
292
+ const div = document.createElement('div');
293
+ div.className = 'form-group';
294
+ div.innerHTML = `
295
+ <label for="${feature}">${feature}</label>
296
+ <input type="number" step="any" id="${feature}" name="${feature}" required>
297
+ `;
298
+ container.appendChild(div);
299
+ });
300
+ }
301
+ }
302
+
303
+ function fillSampleData() {
304
+ const sampleData = {
305
+ 'Credit_Mix_Ordinal': 2,
306
+ 'Outstanding_Debt': 15000,
307
+ 'Delay_from_due_date': 5,
308
+ 'Payment_of_Min_Amount_Yes': 1,
309
+ 'Num_Credit_Card': 3,
310
+ 'Interest_Rate': 12,
311
+ 'Num_of_Delayed_Payment': 2,
312
+ 'Installment_to_Income': 0.25,
313
+ 'Num_Bank_Accounts': 4,
314
+ 'Num_Credit_Inquiries': 1
315
+ };
316
+
317
+ features.top_10_features.forEach(feature => {
318
+ const input = document.getElementById(feature);
319
+ input.value = sampleData[feature] || 0;
320
+ });
321
+ }
322
+
323
+ document.getElementById('predictionForm').addEventListener('submit', async (e) => {
324
+ e.preventDefault();
325
+
326
+ const formData = new FormData(e.target);
327
+ const featuresData = {};
328
+
329
+ // Include all features, using form values for top_10_features and defaults for others
330
+ features.all_features.forEach(feature => {
331
+ if (features.top_10_features.includes(feature)) {
332
+ featuresData[feature] = parseFloat(formData.get(feature));
333
+ } else {
334
+ featuresData[feature] = 0; // Default value for features not in form
335
+ }
336
+ });
337
+
338
+ document.getElementById('loading').classList.add('show');
339
+ document.getElementById('result').classList.remove('show');
340
+
341
+ try {
342
+ const response = await fetch('/predict', {
343
+ method: 'POST',
344
+ headers: {
345
+ 'Content-Type': 'application/json',
346
+ },
347
+ body: JSON.stringify({ features: featuresData })
348
+ });
349
+
350
+ const data = await response.json();
351
+ displayResult(data);
352
+ } catch (error) {
353
+ alert('Error: ' + error.message);
354
+ } finally {
355
+ document.getElementById('loading').classList.remove('show');
356
+ }
357
+ });
358
+
359
+ function displayResult(data) {
360
+ const resultDiv = document.getElementById('result');
361
+
362
+ // Map prediction to risk level for styling
363
+ const riskLevel = data.prediction.toLowerCase() === 'poor' ? 'high' :
364
+ data.prediction.toLowerCase() === 'standard' ? 'medium' : 'low';
365
+
366
+ // Create message based on prediction
367
+ const message = `Your credit score is predicted to be: ${data.prediction}`;
368
+
369
+ resultDiv.className = `result result-${riskLevel} show`;
370
+ resultDiv.innerHTML = `
371
+ <h3>${message}</h3>
372
+ <div class="result-details">
373
+ <div class="result-item">
374
+ <strong>Credit Score</strong>
375
+ <span style="text-transform: uppercase;">${data.prediction}</span>
376
+ </div>
377
+ <div class="result-item">
378
+ <strong>Features Analyzed</strong>
379
+ <span>${data.features_used}</span>
380
+ </div>
381
+ </div>
382
+ `;
383
+ }
384
+
385
+ createFeatureInputs();
386
+
387
+ // Enable Calculator API button when all inputs are filled
388
+ const inputs = document.querySelectorAll('#featureInputs input');
389
+ const calculatorBtn = document.getElementById('calculatorBtn');
390
+
391
+ function checkInputs() {
392
+ let allFilled = true;
393
+ inputs.forEach(input => {
394
+ if (!input.value.trim()) {
395
+ allFilled = false;
396
+ }
397
+ });
398
+ calculatorBtn.disabled = !allFilled;
399
+ }
400
+
401
+ inputs.forEach(input => {
402
+ input.addEventListener('input', checkInputs);
403
+ });
404
+
405
+ calculatorBtn.addEventListener('click', async () => {
406
+ const featuresData = {};
407
+
408
+ // Include all features, using form values for top_10_features and defaults for others
409
+ if (features && features.all_features && features.top_10_features) {
410
+ features.all_features.forEach(feature => {
411
+ if (features.top_10_features.includes(feature)) {
412
+ const input = document.getElementById(feature);
413
+ featuresData[feature] = parseFloat(input.value);
414
+ } else {
415
+ featuresData[feature] = 0; // Default value for features not in form
416
+ }
417
+ });
418
+ }
419
+
420
+ document.getElementById('loading').classList.add('show');
421
+ document.getElementById('result').classList.remove('show');
422
+
423
+ try {
424
+ const response = await fetch('/predict', {
425
+ method: 'POST',
426
+ headers: {
427
+ 'Content-Type': 'application/json',
428
+ },
429
+ body: JSON.stringify({ features: featuresData })
430
+ });
431
+
432
+ const data = await response.json();
433
+ displayResult(data);
434
+ } catch (error) {
435
+ alert('Error: ' + error.message);
436
+ } finally {
437
+ document.getElementById('loading').classList.remove('show');
438
+ }
439
+ });
440
+ </script>
441
+ </body>
442
+ </html>