sksameermujahid commited on
Commit
e224767
·
verified ·
1 Parent(s): a1ad6d6

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +0 -0
  2. templates/index.html +2132 -0
app.py ADDED
The diff for this file is too large to render. See raw diff
 
templates/index.html ADDED
@@ -0,0 +1,2132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 Property Verifier</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
8
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <style>
10
+ :root {
11
+ --primary: #4361ee;
12
+ --secondary: #3f37c9;
13
+ --success: #4cc9f0;
14
+ --danger: #f72585;
15
+ --warning: #f8961e;
16
+ --info: #4895ef;
17
+ --light: #f8f9fa;
18
+ --dark: #212529;
19
+ --gray: #6c757d;
20
+ --border-radius: 12px;
21
+ --box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
22
+ }
23
+
24
+ * {
25
+ margin: 0;
26
+ padding: 0;
27
+ box-sizing: border-box;
28
+ }
29
+
30
+ body {
31
+ font-family: 'Poppins', sans-serif;
32
+ background-color: #f5f7fa;
33
+ color: #333;
34
+ line-height: 1.6;
35
+ padding: 20px;
36
+ }
37
+
38
+ .container {
39
+ max-width: 1200px;
40
+ margin: 0 auto;
41
+ }
42
+
43
+ header {
44
+ text-align: center;
45
+ margin-bottom: 30px;
46
+ }
47
+
48
+ h1 {
49
+ font-size: 2.5rem;
50
+ color: var(--primary);
51
+ margin-bottom: 10px;
52
+ }
53
+
54
+ .subtitle {
55
+ font-size: 1.1rem;
56
+ color: var(--gray);
57
+ }
58
+
59
+ .card {
60
+ background: white;
61
+ border-radius: var(--border-radius);
62
+ box-shadow: var(--box-shadow);
63
+ padding: 25px;
64
+ margin-bottom: 25px;
65
+ }
66
+
67
+ .card-header {
68
+ border-bottom: 1px solid #eee;
69
+ padding-bottom: 15px;
70
+ margin-bottom: 20px;
71
+ display: flex;
72
+ justify-content: space-between;
73
+ align-items: center;
74
+ }
75
+
76
+ .card-title {
77
+ font-size: 1.5rem;
78
+ color: var(--dark);
79
+ font-weight: 600;
80
+ }
81
+
82
+ .form-grid {
83
+ display: grid;
84
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
85
+ gap: 20px;
86
+ }
87
+
88
+ .form-group {
89
+ margin-bottom: 20px;
90
+ }
91
+
92
+ .form-label {
93
+ display: block;
94
+ margin-bottom: 8px;
95
+ font-weight: 500;
96
+ color: var(--dark);
97
+ }
98
+
99
+ .form-control {
100
+ width: 100%;
101
+ padding: 12px 15px;
102
+ border: 1px solid #ddd;
103
+ border-radius: var(--border-radius);
104
+ font-size: 1rem;
105
+ transition: border-color 0.3s;
106
+ }
107
+
108
+ .form-control:focus {
109
+ border-color: var(--primary);
110
+ outline: none;
111
+ box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1);
112
+ }
113
+
114
+ textarea.form-control {
115
+ min-height: 100px;
116
+ resize: vertical;
117
+ }
118
+
119
+ .btn {
120
+ display: inline-block;
121
+ padding: 12px 24px;
122
+ background-color: var(--primary);
123
+ color: white;
124
+ border: none;
125
+ border-radius: var(--border-radius);
126
+ font-size: 1rem;
127
+ font-weight: 500;
128
+ cursor: pointer;
129
+ transition: all 0.3s;
130
+ }
131
+
132
+ .btn:hover {
133
+ background-color: var(--secondary);
134
+ transform: translateY(-2px);
135
+ }
136
+
137
+ .btn-block {
138
+ display: block;
139
+ width: 100%;
140
+ }
141
+
142
+ .section-title {
143
+ font-size: 1.2rem;
144
+ color: var(--primary);
145
+ margin-bottom: 15px;
146
+ font-weight: 600;
147
+ }
148
+
149
+ .results-container {
150
+ display: none;
151
+ margin-top: 30px;
152
+ }
153
+
154
+ .results-grid {
155
+ display: grid;
156
+ grid-template-columns: repeat(auto-fill, minmax(450px, 1fr));
157
+ gap: 25px;
158
+ }
159
+
160
+
161
+ .result-card {
162
+ background: white;
163
+ border-radius: var(--border-radius);
164
+ box-shadow: var(--box-shadow);
165
+ padding: 20px;
166
+ height: 100%;
167
+ }
168
+
169
+ .result-header {
170
+ display: flex;
171
+ align-items: center;
172
+ margin-bottom: 15px;
173
+ }
174
+
175
+ .result-icon {
176
+ width: 40px;
177
+ height: 40px;
178
+ background-color: var(--light);
179
+ border-radius: 50%;
180
+ display: flex;
181
+ align-items: center;
182
+ justify-content: center;
183
+ margin-right: 15px;
184
+ }
185
+
186
+ .result-title {
187
+ font-size: 1.2rem;
188
+ font-weight: 600;
189
+ color: var(--dark);
190
+ }
191
+
192
+ .trust-score {
193
+ text-align: center;
194
+ padding: 20px;
195
+ }
196
+
197
+ .score-value {
198
+ font-size: 3rem;
199
+ font-weight: 700;
200
+ color: var(--primary);
201
+ }
202
+
203
+ .score-label {
204
+ font-size: 1rem;
205
+ color: var(--gray);
206
+ }
207
+
208
+ .progress-container {
209
+ margin: 15px 0;
210
+ }
211
+
212
+ .progress-bar {
213
+ height: 10px;
214
+ background-color: #eee;
215
+ border-radius: 5px;
216
+ overflow: hidden;
217
+ }
218
+
219
+ .progress-fill {
220
+ height: 100%;
221
+ background-color: var(--primary);
222
+ border-radius: 5px;
223
+ transition: width 0.5s ease-in-out;
224
+ }
225
+
226
+ .alert {
227
+ padding: 15px;
228
+ border-radius: var(--border-radius);
229
+ margin-bottom: 20px;
230
+ font-weight: 500;
231
+ }
232
+
233
+ .alert-danger {
234
+ background-color: rgba(247, 37, 133, 0.1);
235
+ color: var(--danger);
236
+ border-left: 4px solid var(--danger);
237
+ }
238
+
239
+ .alert-warning {
240
+ background-color: rgba(248, 150, 30, 0.1);
241
+ color: var(--warning);
242
+ border-left: 4px solid var(--warning);
243
+ }
244
+
245
+ .alert-success {
246
+ background-color: rgba(76, 201, 240, 0.1);
247
+ color: var(--success);
248
+ border-left: 4px solid var(--success);
249
+ }
250
+
251
+ .suggestion-list {
252
+ list-style-type: none;
253
+ padding: 0;
254
+ }
255
+
256
+ .suggestion-item {
257
+ padding: 10px 15px;
258
+ background-color: rgba(67, 97, 238, 0.05);
259
+ border-radius: var(--border-radius);
260
+ margin-bottom: 10px;
261
+ border-left: 3px solid var(--primary);
262
+ }
263
+
264
+ .image-preview {
265
+ display: flex;
266
+ flex-wrap: wrap;
267
+ gap: 10px;
268
+ margin-top: 10px;
269
+ }
270
+
271
+ .preview-item {
272
+ width: 100px;
273
+ height: 100px;
274
+ border-radius: 8px;
275
+ overflow: hidden;
276
+ position: relative;
277
+ }
278
+
279
+ .preview-item img {
280
+ width: 100%;
281
+ height: 100%;
282
+ object-fit: cover;
283
+ }
284
+
285
+ .preview-remove {
286
+ position: absolute;
287
+ top: 5px;
288
+ right: 5px;
289
+ background: rgba(0, 0, 0, 0.5);
290
+ color: white;
291
+ border: none;
292
+ border-radius: 50%;
293
+ width: 20px;
294
+ height: 20px;
295
+ display: flex;
296
+ align-items: center;
297
+ justify-content: center;
298
+ cursor: pointer;
299
+ }
300
+
301
+ .loading {
302
+ display: none;
303
+ text-align: center;
304
+ padding: 30px;
305
+ }
306
+
307
+ .spinner {
308
+ width: 50px;
309
+ height: 50px;
310
+ border: 5px solid rgba(67, 97, 238, 0.1);
311
+ border-radius: 50%;
312
+ border-top-color: var(--primary);
313
+ animation: spin 1s ease-in-out infinite;
314
+ margin: 0 auto 20px;
315
+ }
316
+
317
+ @keyframes spin {
318
+ to { transform: rotate(360deg); }
319
+ }
320
+
321
+ .chart-container {
322
+ position: relative;
323
+ height: 200px;
324
+ margin-bottom: 20px;
325
+ }
326
+
327
+ .pdf-preview {
328
+ background-color: #f8f9fa;
329
+ padding: 15px;
330
+ border-radius: var(--border-radius);
331
+ margin-top: 10px;
332
+ max-height: 200px;
333
+ overflow-y: auto;
334
+ }
335
+
336
+ .pdf-filename {
337
+ font-weight: 500;
338
+ margin-bottom: 5px;
339
+ }
340
+
341
+ .image-gallery {
342
+ display: grid;
343
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
344
+ gap: 15px;
345
+ margin-top: 20px;
346
+ }
347
+
348
+ .gallery-item {
349
+ border-radius: var(--border-radius);
350
+ overflow: hidden;
351
+ box-shadow: var(--box-shadow);
352
+ aspect-ratio: 1;
353
+ }
354
+
355
+ .gallery-item img {
356
+ width: 100%;
357
+ height: 100%;
358
+ object-fit: cover;
359
+ }
360
+
361
+ .badge {
362
+ display: inline-block;
363
+ padding: 5px 10px;
364
+ border-radius: 20px;
365
+ font-size: 0.8rem;
366
+ font-weight: 500;
367
+ margin-right: 5px;
368
+ margin-bottom: 5px;
369
+ }
370
+
371
+ .badge-primary { background-color: rgba(67, 97, 238, 0.1); color: var(--primary); }
372
+ .badge-success { background-color: rgba(76, 201, 240, 0.1); color: var(--success); }
373
+ .badge-warning { background-color: rgba(248, 150, 30, 0.1); color: var(--warning); }
374
+ .badge-danger { background-color: rgba(247, 37, 133, 0.1); color: var(--danger); }
375
+
376
+ .explanation-box {
377
+ background-color: #f8f9fa;
378
+ border-radius: var(--border-radius);
379
+ padding: 15px;
380
+ margin-top: 15px;
381
+ border-left: 4px solid var(--info);
382
+ }
383
+
384
+ .explanation-title {
385
+ font-weight: 600;
386
+ color: var(--info);
387
+ margin-bottom: 10px;
388
+ }
389
+
390
+ @media (max-width: 768px) {
391
+ .form-grid, .results-grid {
392
+ grid-template-columns: 1fr;
393
+ }
394
+
395
+ .card {
396
+ padding: 15px;
397
+ }
398
+ }
399
+
400
+ .property-summary {
401
+ padding: 15px;
402
+ }
403
+
404
+ .property-details p {
405
+ margin-bottom: 8px;
406
+ }
407
+
408
+ .final-verdict {
409
+ padding: 15px;
410
+ }
411
+
412
+ .verdict-box {
413
+ display: flex;
414
+ align-items: center;
415
+ padding: 15px;
416
+ border-radius: var(--border-radius);
417
+ margin-bottom: 15px;
418
+ background-color: #f8f9fa;
419
+ }
420
+
421
+ .verdict-icon {
422
+ font-size: 2rem;
423
+ margin-right: 15px;
424
+ }
425
+
426
+ .verdict-text {
427
+ font-size: 1.2rem;
428
+ font-weight: 600;
429
+ }
430
+
431
+ .verdict-legitimate {
432
+ background-color: rgba(76, 201, 240, 0.1);
433
+ border-left: 4px solid var(--success);
434
+ }
435
+
436
+ .verdict-suspicious {
437
+ background-color: rgba(248, 150, 30, 0.1);
438
+ border-left: 4px solid var(--warning);
439
+ }
440
+
441
+ .verdict-fraudulent {
442
+ background-color: rgba(247, 37, 133, 0.1);
443
+ border-left: 4px solid var(--danger);
444
+ }
445
+
446
+ .verification-scores {
447
+ padding: 15px;
448
+ }
449
+
450
+ .score-item {
451
+ margin-bottom: 15px;
452
+ }
453
+
454
+ .score-label {
455
+ font-weight: 500;
456
+ margin-bottom: 5px;
457
+ }
458
+
459
+ .score-bar-container {
460
+ display: flex;
461
+ align-items: center;
462
+ }
463
+
464
+ .score-bar {
465
+ height: 10px;
466
+ background-color: #e9ecef;
467
+ border-radius: 5px;
468
+ flex-grow: 1;
469
+ margin-right: 10px;
470
+ position: relative;
471
+ overflow: hidden;
472
+ }
473
+
474
+ .score-bar::before {
475
+ content: '';
476
+ position: absolute;
477
+ top: 0;
478
+ left: 0;
479
+ height: 100%;
480
+ background-color: var(--primary);
481
+ border-radius: 5px;
482
+ width: 0%;
483
+ transition: width 0.5s ease;
484
+ }
485
+
486
+ .score-value {
487
+ font-weight: 600;
488
+ min-width: 40px;
489
+ text-align: right;
490
+ }
491
+
492
+ .red-flags {
493
+ padding: 15px;
494
+ }
495
+
496
+ .verdict-score {
497
+ text-align: center;
498
+ margin: 15px 0;
499
+ padding: 10px;
500
+ background-color: rgba(67, 97, 238, 0.05);
501
+ border-radius: var(--border-radius);
502
+ }
503
+
504
+ .verdict-details {
505
+ margin-top: 20px;
506
+ }
507
+
508
+ .verdict-section {
509
+ margin-bottom: 15px;
510
+ padding: 10px;
511
+ border-radius: var(--border-radius);
512
+ }
513
+
514
+ .verdict-section h4 {
515
+ font-size: 1rem;
516
+ margin-bottom: 10px;
517
+ color: var(--dark);
518
+ }
519
+
520
+ #criticalIssuesSection {
521
+ background-color: rgba(247, 37, 133, 0.05);
522
+ border-left: 4px solid var(--danger);
523
+ }
524
+
525
+ #warningsSection {
526
+ background-color: rgba(248, 150, 30, 0.05);
527
+ border-left: 4px solid var(--warning);
528
+ }
529
+
530
+ #recommendationsSection {
531
+ background-color: rgba(76, 201, 240, 0.05);
532
+ border-left: 4px solid var(--success);
533
+ }
534
+ </style>
535
+ </head>
536
+ <body>
537
+ <div class="container">
538
+ <header>
539
+ <h1>AI Property Verifier & Fraud Detection</h1>
540
+ <p class="subtitle">Powered by advanced AI models to verify property listings and detect potential fraud</p>
541
+ </header>
542
+
543
+ <div class="card">
544
+ <div class="card-header">
545
+ <h2 class="card-title">Property Details</h2>
546
+ </div>
547
+
548
+ <form id="propertyForm">
549
+ <div class="section-title">Basic Information</div>
550
+ <div class="form-grid">
551
+ <div class="form-group">
552
+ <label class="form-label" for="propertyName">Property Name</label>
553
+ <input type="text" class="form-control" id="propertyName" name="property_name" required>
554
+ </div>
555
+
556
+ <div class="form-group">
557
+ <label class="form-label" for="propertyType">Property Type</label>
558
+ <select class="form-control" id="propertyType" name="property_type" required>
559
+ <option value="">Select Type</option>
560
+ <option value="Apartment">Apartment</option>
561
+ <option value="House">House</option>
562
+ <option value="Condo">Condo</option>
563
+ <option value="Townhouse">Townhouse</option>
564
+ <option value="Villa">Villa</option>
565
+ <option value="Land">Land</option>
566
+ <option value="Commercial">Commercial</option>
567
+ <option value="Other">Other</option>
568
+ </select>
569
+ </div>
570
+
571
+ <div class="form-group">
572
+ <label class="form-label" for="status">Status</label>
573
+ <select class="form-control" id="status" name="status" required>
574
+ <option value="">Select Status</option>
575
+ <option value="For Sale">For Sale</option>
576
+ <option value="For Rent">For Rent</option>
577
+ <option value="Sold">Sold</option>
578
+ <option value="Under Contract">Under Contract</option>
579
+ <option value="Pending">Pending</option>
580
+ </select>
581
+ </div>
582
+ </div>
583
+
584
+ <div class="form-group">
585
+ <label class="form-label" for="description">Property Description</label>
586
+ <textarea class="form-control" id="description" name="description" rows="4" required></textarea>
587
+ </div>
588
+
589
+ <div class="section-title">Location Details</div>
590
+ <div class="form-grid">
591
+ <div class="form-group">
592
+ <label class="form-label" for="address">Address</label>
593
+ <input type="text" class="form-control" id="address" name="address" required>
594
+ </div>
595
+
596
+ <div class="form-group">
597
+ <label class="form-label" for="city">City</label>
598
+ <input type="text" class="form-control" id="city" name="city" required>
599
+ </div>
600
+
601
+ <div class="form-group">
602
+ <label class="form-label" for="state">State/Province</label>
603
+ <input type="text" class="form-control" id="state" name="state" required>
604
+ </div>
605
+
606
+ <div class="form-group">
607
+ <label class="form-label" for="country">Country</label>
608
+ <input type="text" class="form-control" id="country" name="country" required>
609
+ </div>
610
+
611
+ <div class="form-group">
612
+ <label class="form-label" for="zip">Zip/Postal Code</label>
613
+ <input type="text" class="form-control" id="zip" name="zip" required>
614
+ </div>
615
+
616
+ <div class="form-group">
617
+ <label class="form-label" for="latitude">Latitude</label>
618
+ <input type="text" class="form-control" id="latitude" name="latitude" placeholder="e.g. 40.7128">
619
+ </div>
620
+
621
+ <div class="form-group">
622
+ <label class="form-label" for="longitude">Longitude</label>
623
+ <input type="text" class="form-control" id="longitude" name="longitude" placeholder="e.g. -74.0060">
624
+ </div>
625
+ </div>
626
+
627
+ <div class="section-title">Property Specifications</div>
628
+ <div class="form-grid">
629
+ <div class="form-group">
630
+ <label class="form-label" for="bedrooms">Bedrooms</label>
631
+ <input type="number" class="form-control" id="bedrooms" name="bedrooms" min="0">
632
+ </div>
633
+
634
+ <div class="form-group">
635
+ <label class="form-label" for="bathrooms">Bathrooms</label>
636
+ <input type="number" class="form-control" id="bathrooms" name="bathrooms" min="0" step="0.5">
637
+ </div>
638
+
639
+ <div class="form-group">
640
+ <label class="form-label" for="totalRooms">Total Rooms</label>
641
+ <input type="number" class="form-control" id="totalRooms" name="total_rooms" min="0">
642
+ </div>
643
+
644
+ <div class="form-group">
645
+ <label class="form-label" for="yearBuilt">Year Built</label>
646
+ <input type="number" class="form-control" id="yearBuilt" name="year_built" min="1800" max="2100">
647
+ </div>
648
+
649
+ <div class="form-group">
650
+ <label class="form-label" for="parking">Parking Spaces</label>
651
+ <input type="number" class="form-control" id="parking" name="parking" min="0">
652
+ </div>
653
+
654
+ <div class="form-group">
655
+ <label class="form-label" for="sqFt">Square Feet</label>
656
+ <input type="text" class="form-control" id="sqFt" name="sq_ft" min="0">
657
+ </div>
658
+
659
+ <div class="form-group">
660
+ <label class="form-label" for="marketValue">Market Value</label>
661
+ <input type="text" class="form-control" id="marketValue" name="market_value" min="0">
662
+ </div>
663
+ </div>
664
+
665
+ <div class="form-group">
666
+ <label class="form-label" for="amenities">Amenities (comma separated)</label>
667
+ <input type="text" class="form-control" id="amenities" name="amenities" placeholder="e.g. Pool, Gym, Garden, Garage">
668
+ </div>
669
+
670
+ <div class="form-group">
671
+ <label class="form-label" for="nearbyLandmarks">Nearby Landmarks</label>
672
+ <input type="text" class="form-control" id="nearbyLandmarks" name="nearby_landmarks" placeholder="e.g. School, Hospital, Park, Shopping Mall">
673
+ </div>
674
+
675
+ <div class="form-group">
676
+ <label class="form-label" for="legalDetails">Legal & Infrastructure Details</label>
677
+ <textarea class="form-control" id="legalDetails" name="legal_details" rows="3" placeholder="Include zoning, permits, utilities, etc."></textarea>
678
+ </div>
679
+
680
+ <div class="section-title">Documents & Images</div>
681
+ <div class="form-group">
682
+ <label class="form-label" for="images">Upload Images (JPG/PNG)</label>
683
+ <input type="file" class="form-control" id="images" name="images" accept="image/jpeg, image/png" multiple>
684
+ <div class="image-preview" id="imagePreview"></div>
685
+ </div>
686
+
687
+ <div class="form-group">
688
+ <label class="form-label" for="documents">Upload Documents (PDF)</label>
689
+ <input type="file" class="form-control" id="documents" name="documents" accept="application/pdf" multiple>
690
+ <div id="pdfPreview"></div>
691
+ </div>
692
+
693
+ <div class="form-group">
694
+ <button type="submit" class="btn btn-block" id="submitBtn">Verify Property with AI</button>
695
+ </div>
696
+ </form>
697
+ </div>
698
+
699
+ <div class="loading" id="loadingIndicator">
700
+ <div class="spinner"></div>
701
+ <p>AI models are analyzing your property data...</p>
702
+ <p class="subtitle">This may take a moment as we're processing multiple AI models</p>
703
+ </div>
704
+
705
+ <div class="results-container" id="resultsContainer">
706
+ <div class="card">
707
+ <div class="card-header">
708
+ <h2 class="card-title">AI Verification Results</h2>
709
+ </div>
710
+
711
+ <div class="results-grid">
712
+ <div class="result-card">
713
+ <div class="result-header">
714
+ <div class="result-icon">🏠</div>
715
+ <div class="result-title">Property Summary</div>
716
+ </div>
717
+ <div class="property-summary">
718
+ <h3 id="propertyTitle">Property Details</h3>
719
+ <div class="property-details">
720
+ <p><strong>Name:</strong> <span id="summaryName"></span></p>
721
+ <p><strong>Type:</strong> <span id="summaryType"></span></p>
722
+ <p><strong>Status:</strong> <span id="summaryStatus"></span></p>
723
+ <p><strong>Location:</strong> <span id="summaryLocation"></span></p>
724
+ <p><strong>Price:</strong> <span id="summaryPrice"></span></p>
725
+ <p><strong>Size:</strong> <span id="summarySize"></span></p>
726
+ <p><strong>Bedrooms/Bathrooms:</strong> <span id="summaryRooms"></span></p>
727
+ </div>
728
+ </div>
729
+ </div>
730
+
731
+ <div class="result-card">
732
+ <div class="result-header">
733
+ <div class="result-icon">⚠️</div>
734
+ <div class="result-title">Final Verdict</div>
735
+ </div>
736
+ <div class="final-verdict" id="finalVerdict">
737
+ <div class="verdict-box" id="verdictBox">
738
+ <div class="verdict-icon" id="verdictIcon">⏳</div>
739
+ <div class="verdict-text" id="verdictText">Analysis in progress...</div>
740
+ </div>
741
+ <div class="verdict-score">
742
+ <div class="score-label">Overall Score</div>
743
+ <div class="score-value" id="verdictScoreValue">--</div>
744
+ <div class="progress-container">
745
+ <div class="progress-bar">
746
+ <div class="progress-fill" id="verdictScoreBar" style="width: 0%"></div>
747
+ </div>
748
+ </div>
749
+ </div>
750
+ <div class="verdict-details">
751
+ <div class="verdict-section" id="criticalIssuesSection">
752
+ <h4>Critical Issues</h4>
753
+ <ul id="criticalIssuesList" class="suggestion-list">
754
+ <!-- Will be populated by JavaScript -->
755
+ </ul>
756
+ </div>
757
+ <div class="verdict-section" id="warningsSection">
758
+ <h4>Warnings</h4>
759
+ <ul id="warningsList" class="suggestion-list">
760
+ <!-- Will be populated by JavaScript -->
761
+ </ul>
762
+ </div>
763
+ <div class="verdict-section" id="recommendationsSection">
764
+ <h4>Recommendations</h4>
765
+ <ul id="recommendationsList" class="suggestion-list">
766
+ <!-- Will be populated by JavaScript -->
767
+ </ul>
768
+ </div>
769
+ </div>
770
+ </div>
771
+ </div>
772
+
773
+ <div class="result-card">
774
+ <div class="result-header">
775
+ <div class="result-icon">🔍</div>
776
+ <div class="result-title">Detailed Verification</div>
777
+ </div>
778
+ <div class="verification-scores">
779
+ <div class="score-item">
780
+ <div class="score-label">Trust Score</div>
781
+ <div class="score-bar-container">
782
+ <div class="score-bar" id="trustBar"></div>
783
+ <div class="score-value" id="trustValue">--</div>
784
+ </div>
785
+ </div>
786
+ <div class="score-item">
787
+ <div class="score-label">Image Authenticity</div>
788
+ <div class="score-bar-container">
789
+ <div class="score-bar" id="imageBar"></div>
790
+ <div class="score-value" id="imageValue">--</div>
791
+ </div>
792
+ </div>
793
+ <div class="score-item">
794
+ <div class="score-label">Document Verification</div>
795
+ <div class="score-bar-container">
796
+ <div class="score-bar" id="documentBar"></div>
797
+ <div class="score-value" id="documentValue">--</div>
798
+ </div>
799
+ </div>
800
+ <div class="score-item">
801
+ <div class="score-label">Content Quality</div>
802
+ <div class="score-bar-container">
803
+ <div class="score-bar" id="contentBar"></div>
804
+ <div class="score-value" id="contentValue">--</div>
805
+ </div>
806
+ </div>
807
+ <div class="score-item">
808
+ <div class="score-label">Location Accuracy</div>
809
+ <div class="score-bar-container">
810
+ <div class="score-bar" id="locationBar"></div>
811
+ <div class="score-value" id="locationValue">--</div>
812
+ </div>
813
+ </div>
814
+ </div>
815
+ </div>
816
+
817
+ <div class="result-card">
818
+ <div class="result-header">
819
+ <div class="result-icon">🚩</div>
820
+ <div class="result-title">Red Flags</div>
821
+ </div>
822
+ <div class="red-flags">
823
+ <ul id="redFlagsList" class="suggestion-list">
824
+ <!-- Will be populated by JavaScript -->
825
+ </ul>
826
+ </div>
827
+ </div>
828
+
829
+ <div class="result-card">
830
+ <div class="result-header">
831
+ <div class="result-icon">📊</div>
832
+ <div class="result-title">Trust Score</div>
833
+ </div>
834
+ <div class="trust-score">
835
+ <div class="score-value" id="trustScoreValue">--</div>
836
+ <div class="score-label">Trust Score</div>
837
+ <div class="progress-container">
838
+ <div class="progress-bar">
839
+ <div class="progress-fill" id="trustScoreBar" style="width: 0%"></div>
840
+ </div>
841
+ </div>
842
+ </div>
843
+ <div class="chart-container">
844
+ <canvas id="trustScoreChart"></canvas>
845
+ </div>
846
+ <div class="explanation-box">
847
+ <div class="explanation-title">AI Reasoning</div>
848
+ <div id="trustReasoning"></div>
849
+ </div>
850
+ </div>
851
+
852
+ <div class="result-card">
853
+ <div class="result-header">
854
+ <div class="result-icon">🔍</div>
855
+ <div class="result-title">Fraud Analysis</div>
856
+ </div>
857
+ <div id="fraudAlertContainer"></div>
858
+ <div class="chart-container">
859
+ <canvas id="fraudAnalysisChart"></canvas>
860
+ </div>
861
+ <div class="explanation-box">
862
+ <div class="explanation-title">AI Reasoning</div>
863
+ <div id="fraudReasoning"></div>
864
+ </div>
865
+ </div>
866
+
867
+ <div class="result-card">
868
+ <div class="result-header">
869
+ <div class="result-icon">📝</div>
870
+ <div class="result-title">AI Summary</div>
871
+ </div>
872
+ <div id="aiSummary"></div>
873
+ </div>
874
+
875
+ <div class="result-card">
876
+ <div class="result-header">
877
+ <div class="result-icon">💡</div>
878
+ <div class="result-title">Improvement Suggestions</div>
879
+ </div>
880
+ <div id="improvementSuggestions"></div>
881
+ </div>
882
+
883
+ <div class="result-card">
884
+ <div class="result-header">
885
+ <div class="result-icon">🏠</div>
886
+ <div class="result-title">Property Quality Assessment</div>
887
+ </div>
888
+ <div id="qualityAssessment"></div>
889
+ <div class="chart-container">
890
+ <canvas id="qualityChart"></canvas>
891
+ </div>
892
+ </div>
893
+
894
+ <div class="result-card">
895
+ <div class="result-header">
896
+ <div class="result-icon">📍</div>
897
+ <div class="result-title">Location Analysis</div>
898
+ </div>
899
+ <div id="locationAnalysis"></div>
900
+ <div class="chart-container">
901
+ <canvas id="locationChart"></canvas>
902
+ </div>
903
+ </div>
904
+
905
+ <div class="result-card">
906
+ <div class="result-header">
907
+ <div class="result-icon">💰</div>
908
+ <div class="result-title">Price Analysis</div>
909
+ </div>
910
+ <div id="priceAnalysis"></div>
911
+ <div class="chart-container">
912
+ <canvas id="priceChart"></canvas>
913
+ </div>
914
+ </div>
915
+
916
+ <div class="result-card">
917
+ <div class="result-header">
918
+ <div class="result-icon">⚖️</div>
919
+ <div class="result-title">Legal Analysis</div>
920
+ </div>
921
+ <div id="legalAnalysis"></div>
922
+ <div class="chart-container">
923
+ <canvas id="legalChart"></canvas>
924
+ </div>
925
+ </div>
926
+
927
+ <div class="result-card">
928
+ <div class="result-header">
929
+ <div class="result-icon">🔄</div>
930
+ <div class="result-title">Cross-Validation Checks</div>
931
+ </div>
932
+ <div id="crossValidation"></div>
933
+ </div>
934
+
935
+ <div class="result-card">
936
+ <div class="result-header">
937
+ <div class="result-icon">📄</div>
938
+ <div class="result-title">Document Analysis</div>
939
+ </div>
940
+ <div id="documentAnalysis"></div>
941
+ <div class="chart-container">
942
+ <canvas id="documentChart"></canvas>
943
+ </div>
944
+ </div>
945
+
946
+ <div class="result-card">
947
+ <div class="result-header">
948
+ <div class="result-icon">🖼️</div>
949
+ <div class="result-title">Image Analysis</div>
950
+ </div>
951
+ <div id="imageAnalysis"></div>
952
+ <div class="image-gallery" id="imageGallery"></div>
953
+ </div>
954
+ </div>
955
+ </div>
956
+ </div>
957
+ </div>
958
+
959
+ <script>
960
+ // Global variables to store form data
961
+ let uploadedImages = [];
962
+ let uploadedPDFs = [];
963
+
964
+ // Initialize charts
965
+ let trustScoreChart;
966
+ let fraudAnalysisChart;
967
+ let qualityChart;
968
+ let locationChart;
969
+ let priceChart;
970
+ let legalChart;
971
+ let documentChart;
972
+
973
+ document.addEventListener('DOMContentLoaded', function() {
974
+ // Request location access when page loads
975
+ requestLocationAccess();
976
+
977
+ const propertyForm = document.getElementById('propertyForm');
978
+ const loadingIndicator = document.getElementById('loadingIndicator');
979
+ const resultsContainer = document.getElementById('resultsContainer');
980
+ const imageInput = document.getElementById('images');
981
+ const imagePreview = document.getElementById('imagePreview');
982
+ const pdfInput = document.getElementById('documents');
983
+ const pdfPreview = document.getElementById('pdfPreview');
984
+
985
+ // Handle image uploads
986
+ imageInput.addEventListener('change', function(e) {
987
+ handleImageUpload(e.target.files);
988
+ });
989
+
990
+ // Handle PDF uploads
991
+ pdfInput.addEventListener('change', function(e) {
992
+ handlePDFUpload(e.target.files);
993
+ });
994
+
995
+ // Form submission
996
+ propertyForm.addEventListener('submit', function(e) {
997
+ e.preventDefault();
998
+ submitForm();
999
+ });
1000
+
1001
+ // Initialize charts
1002
+ initCharts();
1003
+ });
1004
+
1005
+ function requestLocationAccess() {
1006
+ if (navigator.geolocation) {
1007
+ navigator.geolocation.getCurrentPosition(
1008
+ function(position) {
1009
+ const latitude = position.coords.latitude;
1010
+ const longitude = position.coords.longitude;
1011
+
1012
+ // Update form fields with coordinates
1013
+ document.getElementById('latitude').value = latitude;
1014
+ document.getElementById('longitude').value = longitude;
1015
+
1016
+ // Send to backend to get address details
1017
+ fetch('/get-location', {
1018
+ method: 'POST',
1019
+ headers: {
1020
+ 'Content-Type': 'application/json',
1021
+ },
1022
+ body: JSON.stringify({
1023
+ latitude: latitude,
1024
+ longitude: longitude
1025
+ }),
1026
+ })
1027
+ .then(response => response.json())
1028
+ .then(data => {
1029
+ if (data.status === 'success') {
1030
+ // Fill form fields with location data
1031
+ document.getElementById('address').value = data.address || '';
1032
+ document.getElementById('city').value = data.city || '';
1033
+ document.getElementById('state').value = data.state || '';
1034
+ document.getElementById('country').value = data.country || '';
1035
+ document.getElementById('zip').value = data.postal_code || '';
1036
+
1037
+ console.log('Location data loaded successfully');
1038
+ } else {
1039
+ console.error('Error getting location details:', data.message);
1040
+ }
1041
+ })
1042
+ .catch(error => {
1043
+ console.error('Error getting location details:', error);
1044
+ });
1045
+ },
1046
+ function(error) {
1047
+ console.error('Error getting location:', error.message);
1048
+ // Show a message to the user about location access
1049
+ const locationMessage = document.createElement('div');
1050
+ locationMessage.className = 'alert alert-warning';
1051
+ locationMessage.innerHTML = 'Location access denied or unavailable. Please enter your location manually.';
1052
+ document.querySelector('.container').prepend(locationMessage);
1053
+
1054
+ // Auto-remove the message after 5 seconds
1055
+ setTimeout(() => {
1056
+ locationMessage.remove();
1057
+ }, 5000);
1058
+ },
1059
+ {
1060
+ enableHighAccuracy: true,
1061
+ timeout: 5000,
1062
+ maximumAge: 0
1063
+ }
1064
+ );
1065
+ } else {
1066
+ console.error('Geolocation is not supported by this browser');
1067
+ }
1068
+ }
1069
+
1070
+ function handleImageUpload(files) {
1071
+ const imagePreview = document.getElementById('imagePreview');
1072
+ imagePreview.innerHTML = ''; // Clear existing previews
1073
+ uploadedImages = []; // Reset uploaded images array
1074
+
1075
+ for (let i = 0; i < files.length; i++) {
1076
+ const file = files[i];
1077
+ if (!file.type.match('image.*')) continue;
1078
+
1079
+ const reader = new FileReader();
1080
+ reader.onload = function(e) {
1081
+ const imageData = e.target.result;
1082
+ uploadedImages.push({
1083
+ name: file.name,
1084
+ data: imageData,
1085
+ file: file
1086
+ });
1087
+
1088
+ // Create preview
1089
+ const previewItem = document.createElement('div');
1090
+ previewItem.className = 'preview-item';
1091
+ previewItem.innerHTML = `
1092
+ <img src="${imageData}" alt="${file.name}">
1093
+ <button type="button" class="preview-remove" data-index="${uploadedImages.length - 1}">×</button>
1094
+ `;
1095
+ imagePreview.appendChild(previewItem);
1096
+
1097
+ // Add remove functionality
1098
+ previewItem.querySelector('.preview-remove').addEventListener('click', function() {
1099
+ const index = parseInt(this.getAttribute('data-index'));
1100
+ uploadedImages.splice(index, 1);
1101
+ imagePreview.removeChild(previewItem);
1102
+ updateImagePreviews();
1103
+ });
1104
+ };
1105
+ reader.readAsDataURL(file);
1106
+ }
1107
+ }
1108
+
1109
+ function updateImagePreviews() {
1110
+ const imagePreview = document.getElementById('imagePreview');
1111
+ imagePreview.innerHTML = '';
1112
+
1113
+ uploadedImages.forEach((image, index) => {
1114
+ const previewItem = document.createElement('div');
1115
+ previewItem.className = 'preview-item';
1116
+ previewItem.innerHTML = `
1117
+ <img src="${image.data}" alt="${image.name}">
1118
+ <button type="button" class="preview-remove" data-index="${index}">×</button>
1119
+ `;
1120
+ imagePreview.appendChild(previewItem);
1121
+
1122
+ previewItem.querySelector('.preview-remove').addEventListener('click', function() {
1123
+ uploadedImages.splice(index, 1);
1124
+ updateImagePreviews();
1125
+ });
1126
+ });
1127
+ }
1128
+
1129
+ function handlePDFUpload(files) {
1130
+ const pdfPreview = document.getElementById('pdfPreview');
1131
+ pdfPreview.innerHTML = ''; // Clear existing previews
1132
+ uploadedPDFs = []; // Reset uploaded PDFs array
1133
+
1134
+ for (let i = 0; i < files.length; i++) {
1135
+ const file = files[i];
1136
+ if (file.type !== 'application/pdf') continue;
1137
+
1138
+ uploadedPDFs.push({
1139
+ name: file.name,
1140
+ file: file
1141
+ });
1142
+
1143
+ // Create preview
1144
+ const previewItem = document.createElement('div');
1145
+ previewItem.className = 'pdf-preview';
1146
+ previewItem.innerHTML = `
1147
+ <div class="pdf-filename">${file.name}</div>
1148
+ <button type="button" class="btn" data-index="${uploadedPDFs.length - 1}">Remove</button>
1149
+ `;
1150
+ pdfPreview.appendChild(previewItem);
1151
+
1152
+ // Add remove functionality
1153
+ previewItem.querySelector('.btn').addEventListener('click', function() {
1154
+ const index = parseInt(this.getAttribute('data-index'));
1155
+ uploadedPDFs.splice(index, 1);
1156
+ pdfPreview.removeChild(previewItem);
1157
+ updatePDFPreviews();
1158
+ });
1159
+ }
1160
+ }
1161
+
1162
+ function updatePDFPreviews() {
1163
+ const pdfPreview = document.getElementById('pdfPreview');
1164
+ pdfPreview.innerHTML = '';
1165
+
1166
+ uploadedPDFs.forEach((pdf, index) => {
1167
+ const previewItem = document.createElement('div');
1168
+ previewItem.className = 'pdf-preview';
1169
+ previewItem.innerHTML = `
1170
+ <div class="pdf-filename">${pdf.name}</div>
1171
+ <button type="button" class="btn" data-index="${index}">Remove</button>
1172
+ `;
1173
+ pdfPreview.appendChild(previewItem);
1174
+
1175
+ previewItem.querySelector('.btn').addEventListener('click', function() {
1176
+ uploadedPDFs.splice(index, 1);
1177
+ updatePDFPreviews();
1178
+ });
1179
+ });
1180
+ }
1181
+
1182
+ function initCharts() {
1183
+ try {
1184
+ // Store all charts in an array for easier management
1185
+ window.charts = [];
1186
+
1187
+ // Trust Score Chart initialization
1188
+ const trustCtx = document.getElementById('trustScoreChart').getContext('2d');
1189
+ trustScoreChart = new Chart(trustCtx, {
1190
+ type: 'doughnut',
1191
+ data: {
1192
+ datasets: [{
1193
+ data: [0, 100],
1194
+ backgroundColor: [
1195
+ '#4361ee',
1196
+ '#f1f1f1'
1197
+ ],
1198
+ borderWidth: 0
1199
+ }]
1200
+ },
1201
+ options: {
1202
+ cutout: '70%',
1203
+ circumference: 180,
1204
+ rotation: -90,
1205
+ plugins: {
1206
+ legend: {
1207
+ display: false
1208
+ },
1209
+ tooltip: {
1210
+ enabled: false
1211
+ }
1212
+ },
1213
+ maintainAspectRatio: false
1214
+ }
1215
+ });
1216
+ charts.push(trustScoreChart);
1217
+
1218
+ // Fraud Analysis Chart (Bar)
1219
+ const fraudAnalysisCtx = document.getElementById('fraudAnalysisChart').getContext('2d');
1220
+ fraudAnalysisChart = new Chart(fraudAnalysisCtx, {
1221
+ type: 'bar',
1222
+ data: {
1223
+ labels: ['Legitimate', 'Suspicious', 'Fraudulent'],
1224
+ datasets: [{
1225
+ label: 'Fraud Indicators',
1226
+ data: [0, 0, 0],
1227
+ backgroundColor: [
1228
+ '#4cc9f0',
1229
+ '#f8961e',
1230
+ '#f72585'
1231
+ ],
1232
+ borderWidth: 0
1233
+ }]
1234
+ },
1235
+ options: {
1236
+ indexAxis: 'y',
1237
+ plugins: {
1238
+ legend: {
1239
+ display: false
1240
+ }
1241
+ },
1242
+ scales: {
1243
+ x: {
1244
+ beginAtZero: true,
1245
+ max: 100
1246
+ }
1247
+ },
1248
+ maintainAspectRatio: false
1249
+ }
1250
+ });
1251
+
1252
+ // Quality Assessment Chart
1253
+ const qualityCtx = document.getElementById('qualityChart').getContext('2d');
1254
+ qualityChart = new Chart(qualityCtx, {
1255
+ type: 'radar',
1256
+ data: {
1257
+ labels: ['Completeness', 'Accuracy', 'Clarity', 'Authenticity', 'Detail'],
1258
+ datasets: [{
1259
+ label: 'Quality Score',
1260
+ data: [0, 0, 0, 0, 0],
1261
+ backgroundColor: 'rgba(67, 97, 238, 0.2)',
1262
+ borderColor: '#4361ee',
1263
+ borderWidth: 2,
1264
+ pointBackgroundColor: '#4361ee'
1265
+ }]
1266
+ },
1267
+ options: {
1268
+ scales: {
1269
+ r: {
1270
+ beginAtZero: true,
1271
+ max: 100
1272
+ }
1273
+ },
1274
+ maintainAspectRatio: false
1275
+ }
1276
+ });
1277
+
1278
+ // Location Analysis Chart
1279
+ const locationCtx = document.getElementById('locationChart').getContext('2d');
1280
+ locationChart = new Chart(locationCtx, {
1281
+ type: 'pie',
1282
+ data: {
1283
+ labels: ['Complete', 'Partial', 'Missing'],
1284
+ datasets: [{
1285
+ data: [0, 0, 0],
1286
+ backgroundColor: [
1287
+ '#4cc9f0',
1288
+ '#f8961e',
1289
+ '#f72585'
1290
+ ],
1291
+ borderWidth: 0
1292
+ }]
1293
+ },
1294
+ options: {
1295
+ plugins: {
1296
+ legend: {
1297
+ position: 'bottom'
1298
+ }
1299
+ },
1300
+ maintainAspectRatio: false
1301
+ }
1302
+ });
1303
+
1304
+ // Price Analysis Chart
1305
+ const priceCtx = document.getElementById('priceChart').getContext('2d');
1306
+ priceChart = new Chart(priceCtx, {
1307
+ type: 'bar',
1308
+ data: {
1309
+ labels: ['Market Value', 'Price per Sq.Ft.'],
1310
+ datasets: [{
1311
+ label: 'Price Analysis',
1312
+ data: [0, 0],
1313
+ backgroundColor: [
1314
+ '#4361ee',
1315
+ '#4895ef'
1316
+ ],
1317
+ borderWidth: 0
1318
+ }]
1319
+ },
1320
+ options: {
1321
+ scales: {
1322
+ y: {
1323
+ beginAtZero: true
1324
+ }
1325
+ },
1326
+ maintainAspectRatio: false
1327
+ }
1328
+ });
1329
+
1330
+ // Legal Analysis Chart
1331
+ const legalCtx = document.getElementById('legalChart').getContext('2d');
1332
+ legalChart = new Chart(legalCtx, {
1333
+ type: 'doughnut',
1334
+ data: {
1335
+ labels: ['Complete', 'Partial', 'Missing'],
1336
+ datasets: [{
1337
+ data: [0, 0, 0],
1338
+ backgroundColor: [
1339
+ '#4cc9f0',
1340
+ '#f8961e',
1341
+ '#f72585'
1342
+ ],
1343
+ borderWidth: 0
1344
+ }]
1345
+ },
1346
+ options: {
1347
+ plugins: {
1348
+ legend: {
1349
+ position: 'bottom'
1350
+ }
1351
+ },
1352
+ maintainAspectRatio: false
1353
+ }
1354
+ });
1355
+
1356
+ // Document Analysis Chart
1357
+ const documentCtx = document.getElementById('documentChart').getContext('2d');
1358
+ documentChart = new Chart(documentCtx, {
1359
+ type: 'polarArea',
1360
+ data: {
1361
+ labels: ['Authentic', 'Suspicious', 'Incomplete'],
1362
+ datasets: [{
1363
+ data: [0, 0, 0],
1364
+ backgroundColor: [
1365
+ '#4cc9f0',
1366
+ '#f8961e',
1367
+ '#f72585'
1368
+ ],
1369
+ borderWidth: 0
1370
+ }]
1371
+ },
1372
+ options: {
1373
+ plugins: {
1374
+ legend: {
1375
+ position: 'bottom'
1376
+ }
1377
+ },
1378
+ maintainAspectRatio: false
1379
+ }
1380
+ });
1381
+
1382
+ // Add window resize handler for chart responsiveness
1383
+ window.addEventListener('resize', debounce(() => {
1384
+ charts.forEach(chart => {
1385
+ if (chart && typeof chart.resize === 'function') {
1386
+ chart.resize();
1387
+ }
1388
+ });
1389
+ }, 250));
1390
+
1391
+ } catch (error) {
1392
+ console.error('Error initializing charts:', error);
1393
+ document.getElementById('chartErrors').innerHTML =
1394
+ '<div class="alert alert-danger">Error initializing charts. Please refresh the page.</div>';
1395
+ }
1396
+ }
1397
+
1398
+ // Utility function for debouncing
1399
+ function debounce(func, wait) {
1400
+ let timeout;
1401
+ return function executedFunction(...args) {
1402
+ const later = () => {
1403
+ clearTimeout(timeout);
1404
+ func(...args);
1405
+ };
1406
+ clearTimeout(timeout);
1407
+ timeout = setTimeout(later, wait);
1408
+ };
1409
+ }
1410
+
1411
+ // Data validation function
1412
+ function validateAnalysisData(data) {
1413
+ return {
1414
+ trustScore: {
1415
+ score: data.trust_score?.score ?? 0,
1416
+ reasoning: data.trust_score?.reasoning ?? 'No reasoning provided'
1417
+ },
1418
+ fraudClassification: {
1419
+ alertLevel: data.fraud_classification?.alert_level ?? 'low',
1420
+ classification: data.fraud_classification?.classification ?? 'Unknown',
1421
+ confidence: data.fraud_classification?.confidence ?? 0,
1422
+ indicators: data.fraud_classification?.fraud_indicators ?? [],
1423
+ scores: data.fraud_classification?.indicator_scores ?? []
1424
+ },
1425
+ qualityAssessment: {
1426
+ assessment: data.quality_assessment?.assessment ?? 'Unknown',
1427
+ score: data.quality_assessment?.score ?? 0,
1428
+ isAiGenerated: data.quality_assessment?.is_ai_generated ?? false,
1429
+ reasoning: data.quality_assessment?.reasoning ?? 'No reasoning provided'
1430
+ },
1431
+ // ... other validations
1432
+ };
1433
+ }
1434
+
1435
+ // Safe chart update function
1436
+ function updateChart(chart, newData, options = {}) {
1437
+ try {
1438
+ if (chart && typeof chart.update === 'function') {
1439
+ chart.data = newData;
1440
+ chart.update(options);
1441
+ return true;
1442
+ }
1443
+ return false;
1444
+ } catch (error) {
1445
+ console.error('Error updating chart:', error);
1446
+ return false;
1447
+ }
1448
+ }
1449
+
1450
+ function submitForm() {
1451
+ // Show loading indicator
1452
+ document.getElementById('loadingIndicator').style.display = 'block';
1453
+ document.getElementById('resultsContainer').style.display = 'none';
1454
+
1455
+ // Create form data
1456
+ const formData = new FormData(document.getElementById('propertyForm'));
1457
+
1458
+ // Clear any existing image/document entries
1459
+ formData.delete('images');
1460
+ formData.delete('documents');
1461
+
1462
+ // Add images (only once)
1463
+ uploadedImages.forEach((image) => {
1464
+ formData.append('images', image.file);
1465
+ });
1466
+
1467
+ // Add PDFs (only once)
1468
+ uploadedPDFs.forEach((pdf) => {
1469
+ formData.append('documents', pdf.file);
1470
+ });
1471
+
1472
+ // Send to backend
1473
+ fetch('/verify', {
1474
+ method: 'POST',
1475
+ body: formData
1476
+ })
1477
+ .then(response => {
1478
+ if (!response.ok) {
1479
+ throw new Error('Network response was not ok');
1480
+ }
1481
+ return response.json();
1482
+ })
1483
+ .then(data => {
1484
+ // Hide loading indicator
1485
+ document.getElementById('loadingIndicator').style.display = 'none';
1486
+
1487
+ // Display results
1488
+ displayResults(data);
1489
+
1490
+ // Show results container
1491
+ document.getElementById('resultsContainer').style.display = 'block';
1492
+
1493
+ // Scroll to results
1494
+ document.getElementById('resultsContainer').scrollIntoView({ behavior: 'smooth' });
1495
+ })
1496
+ .catch(error => {
1497
+ console.error('Error:', error);
1498
+ document.getElementById('loadingIndicator').style.display = 'none';
1499
+ alert('An error occurred while processing your request. Please try again.');
1500
+ });
1501
+ }
1502
+ function displayResults(data) {
1503
+ console.log("Received data:", JSON.stringify(data));
1504
+
1505
+ // Validate and sanitize data
1506
+ const validatedData = validateAnalysisData(data);
1507
+
1508
+ try {
1509
+ // Display Trust Score with validated data
1510
+ const trustScore = validatedData.trustScore.score;
1511
+ document.getElementById('trustScoreValue').textContent = trustScore;
1512
+ document.getElementById('trustScoreBar').style.width = `${trustScore}%`;
1513
+ document.getElementById('trustReasoning').textContent = validatedData.trustScore.reasoning;
1514
+
1515
+ // Update Trust Score Chart safely
1516
+ updateChart(trustScoreChart, {
1517
+ datasets: [{
1518
+ data: [trustScore, 100 - trustScore]
1519
+ }]
1520
+ });
1521
+
1522
+ // Display Fraud Analysis
1523
+ const fraudLevel = validatedData.fraudClassification.alertLevel;
1524
+ const fraudContainer = document.getElementById('fraudAlertContainer');
1525
+ fraudContainer.innerHTML = '';
1526
+
1527
+ const alertClass = fraudLevel === 'high' ? 'alert-danger' :
1528
+ fraudLevel === 'medium' ? 'alert-warning' : 'alert-success';
1529
+
1530
+ const alertDiv = document.createElement('div');
1531
+ alertDiv.className = `alert ${alertClass}`;
1532
+
1533
+ // Create detailed fraud analysis display
1534
+ let fraudContent = `<h4>Fraud Classification</h4>`;
1535
+ fraudContent += `<p>Alert Level: ${fraudLevel.toUpperCase()}</p>`;
1536
+
1537
+ if (data.fraud_classification.high_risk && data.fraud_classification.high_risk.length > 0) {
1538
+ fraudContent += `<div class="risk-section">
1539
+ <h5>High Risk Indicators:</h5>
1540
+ <ul>`;
1541
+ data.fraud_classification.high_risk.forEach(([indicator, score]) => {
1542
+ fraudContent += `<li>${indicator} (${Math.round(score * 100)}% confidence)</li>`;
1543
+ });
1544
+ fraudContent += `</ul></div>`;
1545
+ }
1546
+
1547
+ if (data.fraud_classification.medium_risk && data.fraud_classification.medium_risk.length > 0) {
1548
+ fraudContent += `<div class="risk-section">
1549
+ <h5>Medium Risk Indicators:</h5>
1550
+ <ul>`;
1551
+ data.fraud_classification.medium_risk.forEach(([indicator, score]) => {
1552
+ fraudContent += `<li>${indicator} (${Math.round(score * 100)}% confidence)</li>`;
1553
+ });
1554
+ fraudContent += `</ul></div>`;
1555
+ }
1556
+
1557
+ if (data.fraud_classification.low_risk && data.fraud_classification.low_risk.length > 0) {
1558
+ fraudContent += `<div class="risk-section">
1559
+ <h5>Low Risk Indicators:</h5>
1560
+ <ul>`;
1561
+ data.fraud_classification.low_risk.forEach(([indicator, score]) => {
1562
+ fraudContent += `<li>${indicator} (${Math.round(score * 100)}% confidence)</li>`;
1563
+ });
1564
+ fraudContent += `</ul></div>`;
1565
+ }
1566
+
1567
+ alertDiv.innerHTML = fraudContent;
1568
+ fraudContainer.appendChild(alertDiv);
1569
+
1570
+ // Update Fraud Analysis Chart
1571
+ const fraudChartData = {
1572
+ labels: ['High Risk', 'Medium Risk', 'Low Risk'],
1573
+ datasets: [{
1574
+ data: [
1575
+ data.fraud_classification.high_risk ? data.fraud_classification.high_risk.reduce((sum, [_, score]) => sum + score, 0) * 100 : 0,
1576
+ data.fraud_classification.medium_risk ? data.fraud_classification.medium_risk.reduce((sum, [_, score]) => sum + score, 0) * 100 : 0,
1577
+ data.fraud_classification.low_risk ? data.fraud_classification.low_risk.reduce((sum, [_, score]) => sum + score, 0) * 100 : 0
1578
+ ],
1579
+ backgroundColor: ['#dc3545', '#ffc107', '#28a745']
1580
+ }]
1581
+ };
1582
+
1583
+ updateChart(fraudAnalysisChart, fraudChartData);
1584
+
1585
+ document.getElementById('fraudReasoning').textContent = `This property was classified as ${validatedData.fraudClassification.classification} based on AI analysis of the listing details.`;
1586
+
1587
+ // Display AI Summary
1588
+ document.getElementById('aiSummary').textContent = data.summary || "No summary available";
1589
+
1590
+ // Display Improvement Suggestions
1591
+ const improvementContainer = document.getElementById('improvementSuggestions');
1592
+ improvementContainer.innerHTML = '';
1593
+
1594
+ // Create sections for different types of improvements
1595
+ const sections = {
1596
+ 'Critical Issues': [],
1597
+ 'Important Improvements': [],
1598
+ 'Optional Enhancements': []
1599
+ };
1600
+
1601
+ // Safely check if improvement_suggestions exists and is an array
1602
+ if (data && data.improvement_suggestions && Array.isArray(data.improvement_suggestions)) {
1603
+ // Categorize improvements based on severity
1604
+ data.improvement_suggestions.forEach(suggestion => {
1605
+ if (suggestion && typeof suggestion === 'string') {
1606
+ if (suggestion.toLowerCase().includes('critical') ||
1607
+ suggestion.toLowerCase().includes('required') ||
1608
+ suggestion.toLowerCase().includes('must')) {
1609
+ sections['Critical Issues'].push(suggestion);
1610
+ } else if (suggestion.toLowerCase().includes('should') ||
1611
+ suggestion.toLowerCase().includes('recommended')) {
1612
+ sections['Important Improvements'].push(suggestion);
1613
+ } else {
1614
+ sections['Optional Enhancements'].push(suggestion);
1615
+ }
1616
+ }
1617
+ });
1618
+ }
1619
+
1620
+ // Display each section
1621
+ Object.entries(sections).forEach(([title, suggestions]) => {
1622
+ if (suggestions.length > 0) {
1623
+ const sectionDiv = document.createElement('div');
1624
+ sectionDiv.className = 'improvement-section mb-4';
1625
+
1626
+ const sectionTitle = document.createElement('h5');
1627
+ sectionTitle.className = title === 'Critical Issues' ? 'text-danger' :
1628
+ title === 'Important Improvements' ? 'text-warning' : 'text-info';
1629
+ sectionTitle.textContent = title;
1630
+
1631
+ const suggestionList = document.createElement('ul');
1632
+ suggestionList.className = 'list-unstyled';
1633
+
1634
+ suggestions.forEach(suggestion => {
1635
+ const li = document.createElement('li');
1636
+ li.className = 'mb-2';
1637
+ li.innerHTML = `<i class="fas fa-arrow-right me-2"></i>${suggestion}`;
1638
+ suggestionList.appendChild(li);
1639
+ });
1640
+
1641
+ sectionDiv.appendChild(sectionTitle);
1642
+ sectionDiv.appendChild(suggestionList);
1643
+ improvementContainer.appendChild(sectionDiv);
1644
+ }
1645
+ });
1646
+
1647
+ // If no suggestions are available, display a message
1648
+ if (!Object.values(sections).some(suggestions => suggestions.length > 0)) {
1649
+ improvementContainer.innerHTML = '<p class="text-muted">No improvement suggestions available at this time.</p>';
1650
+ }
1651
+
1652
+ // Display Quality Assessment
1653
+ const qualityDiv = document.getElementById('qualityAssessment');
1654
+ qualityDiv.innerHTML = '';
1655
+
1656
+ if (data.quality_assessment) {
1657
+ const qualityScore = data.quality_assessment.score || 0;
1658
+ const assessment = data.quality_assessment.assessment || 'Not assessed';
1659
+ const reasoning = data.quality_assessment.reasoning || 'No reasoning provided';
1660
+ const isAiGenerated = data.quality_assessment.is_ai_generated || false;
1661
+
1662
+ qualityDiv.innerHTML = `
1663
+ <div class="quality-score mb-4">
1664
+ <h5>Content Quality Score</h5>
1665
+ <div class="score-display">
1666
+ <span class="score-value">${qualityScore}%</span>
1667
+ <div class="progress">
1668
+ <div class="progress-bar ${getScoreColorClass(qualityScore)}"
1669
+ role="progressbar"
1670
+ style="width: ${qualityScore}%"
1671
+ aria-valuenow="${qualityScore}"
1672
+ aria-valuemin="0"
1673
+ aria-valuemax="100">
1674
+ </div>
1675
+ </div>
1676
+ </div>
1677
+ </div>
1678
+ <div class="quality-details">
1679
+ <div class="detail-item">
1680
+ <strong>Assessment:</strong> ${assessment}
1681
+ </div>
1682
+ <div class="detail-item">
1683
+ <strong>AI Generated:</strong> ${isAiGenerated ? 'Yes' : 'No'}
1684
+ </div>
1685
+ <div class="detail-item">
1686
+ <strong>Analysis:</strong>
1687
+ <p class="reasoning-text">${reasoning}</p>
1688
+ </div>
1689
+ </div>
1690
+ `;
1691
+
1692
+ // Update Quality Chart
1693
+ const qualityChartData = {
1694
+ labels: ['Completeness', 'Accuracy', 'Clarity', 'Authenticity', 'Detail'],
1695
+ datasets: [{
1696
+ label: 'Quality Metrics',
1697
+ data: [
1698
+ data.quality_assessment.completeness_score || 0,
1699
+ data.quality_assessment.accuracy_score || 0,
1700
+ data.quality_assessment.clarity_score || 0,
1701
+ data.quality_assessment.authenticity_score || 0,
1702
+ data.quality_assessment.detail_score || 0
1703
+ ],
1704
+ backgroundColor: 'rgba(67, 97, 238, 0.2)',
1705
+ borderColor: '#4361ee',
1706
+ borderWidth: 2,
1707
+ pointBackgroundColor: '#4361ee'
1708
+ }]
1709
+ };
1710
+
1711
+ updateChart(qualityChart, qualityChartData);
1712
+ } else {
1713
+ qualityDiv.innerHTML = '<p class="text-muted">No quality assessment available at this time.</p>';
1714
+ }
1715
+
1716
+ // Add helper function for score color classes
1717
+ function getScoreColorClass(score) {
1718
+ if (score >= 80) return 'bg-success';
1719
+ if (score >= 60) return 'bg-info';
1720
+ if (score >= 40) return 'bg-warning';
1721
+ return 'bg-danger';
1722
+ }
1723
+
1724
+ // Display Location Analysis
1725
+ const locationDiv = document.getElementById('locationAnalysis');
1726
+ if (data.location_analysis) {
1727
+ locationDiv.innerHTML = `
1728
+ <p><strong>Assessment:</strong> ${data.location_analysis.assessment || "Unknown"}</p>
1729
+ <p><strong>Completeness:</strong> ${data.location_analysis.completeness_score || 0}%</p>
1730
+ <p><strong>Coordinates:</strong> ${data.location_analysis.coordinates_check || "Unknown"}</p>
1731
+ <p><strong>Landmarks:</strong> ${data.location_analysis.landmarks_provided ? 'Provided' : 'Not provided'}</p>
1732
+ `;
1733
+
1734
+ // Update Location Chart
1735
+ updateChart(locationChart, {
1736
+ datasets: [{
1737
+ data: [
1738
+ data.location_analysis.completeness_score || 0,
1739
+ 100 - (data.location_analysis.completeness_score || 0),
1740
+ data.location_analysis.coordinates_check === 'coordinates_missing' ? 30 : 0
1741
+ ]
1742
+ }]
1743
+ });
1744
+ } else {
1745
+ locationDiv.innerHTML = '<p>No location analysis available</p>';
1746
+ }
1747
+
1748
+ // Display Price Analysis
1749
+ const priceDiv = document.getElementById('priceAnalysis');
1750
+ if (data.price_analysis && data.price_analysis.has_price) {
1751
+ priceDiv.innerHTML = `
1752
+ <p><strong>Assessment:</strong> ${data.price_analysis.assessment || "Unknown"}</p>
1753
+ <p><strong>Price:</strong> ₹${(data.price_analysis.price || 0).toLocaleString()}</p>
1754
+ ${data.price_analysis.has_sqft ? `<p><strong>Price per Sq.Ft.:</strong> ₹${(data.price_analysis.price_per_sqft || 0).toLocaleString(undefined, {maximumFractionDigits: 2})}</p>` : ''}
1755
+ <p><strong>Confidence:</strong> ${Math.round((data.price_analysis.confidence || 0) * 100)}%</p>
1756
+ `;
1757
+
1758
+ // Update Price Chart
1759
+ updateChart(priceChart, {
1760
+ labels: ['Market Value (thousands)', 'Price per Sq.Ft.'],
1761
+ datasets: [{
1762
+ data: [
1763
+ (data.price_analysis.price || 0) / 1000, // Scale down for better visualization
1764
+ data.price_analysis.price_per_sqft || 0
1765
+ ]
1766
+ }]
1767
+ });
1768
+ } else {
1769
+ priceDiv.innerHTML = `<p>No price information provided for analysis.</p>`;
1770
+ }
1771
+
1772
+ // Display Legal Analysis
1773
+ const legalDiv = document.getElementById('legalAnalysis');
1774
+ if (data.legal_analysis) {
1775
+ legalDiv.innerHTML = `
1776
+ <p><strong>Assessment:</strong> ${data.legal_analysis.assessment || "Unknown"}</p>
1777
+ <p><strong>Completeness:</strong> ${data.legal_analysis.completeness_score || 0}%</p>
1778
+ <p><strong>Summary:</strong> ${data.legal_analysis.summary || "No summary available"}</p>
1779
+ ${data.legal_analysis.terms_found && data.legal_analysis.terms_found.length > 0 ? `<p><strong>Legal Terms Found:</strong> ${data.legal_analysis.terms_found.join(', ')}</p>` : ''}
1780
+ ${data.legal_analysis.potential_issues ? '<p class="alert alert-warning">Potential legal issues detected</p>' : ''}
1781
+ `;
1782
+
1783
+ // Update Legal Chart
1784
+ updateChart(legalChart, {
1785
+ datasets: [{
1786
+ data: [
1787
+ data.legal_analysis.completeness_score || 0,
1788
+ 100 - (data.legal_analysis.completeness_score || 0),
1789
+ data.legal_analysis.potential_issues ? 30 : 0
1790
+ ]
1791
+ }]
1792
+ });
1793
+ } else {
1794
+ legalDiv.innerHTML = '<p>No legal analysis available</p>';
1795
+ }
1796
+
1797
+ // Display Cross-Validation Checks
1798
+ const crossValidationDiv = document.getElementById('crossValidation');
1799
+ crossValidationDiv.innerHTML = '<ul class="suggestion-list">';
1800
+
1801
+ try {
1802
+ // Safely check if cross_validation exists and is an array
1803
+ if (data && data.cross_validation && Array.isArray(data.cross_validation)) {
1804
+ // Only proceed if the array has items
1805
+ if (data.cross_validation.length > 0) {
1806
+ data.cross_validation.forEach(check => {
1807
+ if (check && typeof check === 'object') {
1808
+ const status = check.status || 'unknown';
1809
+ const checkName = check.check || 'Check';
1810
+ const message = check.message || 'No details available';
1811
+
1812
+ // Determine status class
1813
+ let statusClass = 'badge-warning'; // Default
1814
+ if (['consistent', 'valid', 'reasonable', 'match', 'likely_valid'].includes(status)) {
1815
+ statusClass = 'badge-success';
1816
+ } else if (['suspicious', 'inconsistent', 'invalid', 'no_match'].includes(status)) {
1817
+ statusClass = 'badge-danger';
1818
+ }
1819
+
1820
+ crossValidationDiv.innerHTML += `
1821
+ <li class="suggestion-item">
1822
+ <span class="badge ${statusClass}">${status}</span>
1823
+ <strong>${checkName}:</strong> ${message}
1824
+ </li>
1825
+ `;
1826
+ }
1827
+ });
1828
+ } else {
1829
+ crossValidationDiv.innerHTML += '<li class="suggestion-item">No cross-validation checks performed</li>';
1830
+ }
1831
+ } else {
1832
+ crossValidationDiv.innerHTML += '<li class="suggestion-item">No cross-validation data available</li>';
1833
+ }
1834
+ } catch (error) {
1835
+ console.error("Error displaying cross-validation:", error);
1836
+ crossValidationDiv.innerHTML += '<li class="suggestion-item">Error displaying cross-validation results</li>';
1837
+ }
1838
+
1839
+ crossValidationDiv.innerHTML += '</ul>';
1840
+
1841
+ // Display Document Analysis
1842
+ const documentDiv = document.getElementById('documentAnalysis');
1843
+ documentDiv.innerHTML = '';
1844
+
1845
+ if (data.document_analysis && data.document_analysis.pdf_count > 0) {
1846
+ documentDiv.innerHTML = `<p><strong>Documents Analyzed:</strong> ${data.document_analysis.pdf_count}</p>`;
1847
+
1848
+ data.document_analysis.pdf_analysis.forEach((pdf, index) => {
1849
+ documentDiv.innerHTML += `
1850
+ <div class="pdf-preview">
1851
+ <p><strong>Document ${index + 1}</strong></p>
1852
+ <p><strong>Type:</strong> ${pdf.document_type.classification} (${Math.round(pdf.document_type.confidence * 100)}% confidence)</p>
1853
+ <p><strong>Authenticity:</strong> ${pdf.authenticity.assessment} (${Math.round(pdf.authenticity.confidence * 100)}% confidence)</p>
1854
+ <p><strong>Summary:</strong> ${pdf.summary}</p>
1855
+ <p><strong>Contains Signatures:</strong> ${pdf.contains_signatures ? 'Yes' : 'No'}</p>
1856
+ <p><strong>Contains Dates:</strong> ${pdf.contains_dates ? 'Yes' : 'No'}</p>
1857
+ </div>
1858
+ `;
1859
+ });
1860
+
1861
+ // Update Document Chart
1862
+ let authenticCount = 0;
1863
+ let suspiciousCount = 0;
1864
+ let incompleteCount = 0;
1865
+
1866
+ data.document_analysis.pdf_analysis.forEach(pdf => {
1867
+ if (pdf.authenticity.assessment.includes('authentic')) {
1868
+ authenticCount++;
1869
+ } else if (pdf.authenticity.assessment.includes('fraudulent')) {
1870
+ suspiciousCount++;
1871
+ } else {
1872
+ incompleteCount++;
1873
+ }
1874
+ });
1875
+
1876
+ updateChart(documentChart, {
1877
+ datasets: [{
1878
+ data: [
1879
+ authenticCount,
1880
+ suspiciousCount,
1881
+ incompleteCount
1882
+ ]
1883
+ }]
1884
+ });
1885
+ } else {
1886
+ documentDiv.innerHTML = '<p>No documents were uploaded for analysis.</p>';
1887
+ }
1888
+
1889
+ // Display Image Analysis
1890
+ const imageAnalysisDiv = document.getElementById('imageAnalysis');
1891
+ const imageGallery = document.getElementById('imageGallery');
1892
+
1893
+ imageAnalysisDiv.innerHTML = '';
1894
+ imageGallery.innerHTML = '';
1895
+
1896
+ if (data.image_analysis && data.images && data.images.length > 0) {
1897
+ imageAnalysisDiv.innerHTML = `<p><strong>Images Analyzed:</strong> ${data.image_analysis.image_count}</p>`;
1898
+
1899
+ let propertyRelatedCount = 0;
1900
+ data.image_analysis.image_analysis.forEach(img => {
1901
+ if (img && img.is_property_related) {
1902
+ propertyRelatedCount++;
1903
+ }
1904
+ });
1905
+
1906
+ imageAnalysisDiv.innerHTML += `<p><strong>Property-Related Images:</strong> ${propertyRelatedCount} of ${data.image_analysis.image_count}</p>`;
1907
+
1908
+ // Display images in gallery
1909
+ data.images.forEach((imgData, index) => {
1910
+ const imgAnalysis = data.image_analysis.image_analysis[index];
1911
+ const galleryItem = document.createElement('div');
1912
+ galleryItem.className = 'gallery-item';
1913
+
1914
+ galleryItem.innerHTML = `
1915
+ <img src="data:image/jpeg;base64,${imgData}" alt="Property Image ${index + 1}">
1916
+ <div class="badge ${imgAnalysis && imgAnalysis.is_property_related ? 'badge-success' : 'badge-warning'}"
1917
+ style="position: absolute; top: 5px; right: 5px;">
1918
+ ${imgAnalysis && imgAnalysis.is_property_related ? 'Property' : 'Not Property'}
1919
+ </div>
1920
+ `;
1921
+
1922
+ imageGallery.appendChild(galleryItem);
1923
+ });
1924
+ } else {
1925
+ imageAnalysisDiv.innerHTML = '<p>No images were uploaded for analysis.</p>';
1926
+ }
1927
+
1928
+ // Update Property Summary
1929
+ document.getElementById('summaryName').textContent = document.getElementById('propertyName').value || 'Not provided';
1930
+ document.getElementById('summaryType').textContent = document.getElementById('propertyType').value || 'Not provided';
1931
+ document.getElementById('summaryStatus').textContent = document.getElementById('status').value || 'Not provided';
1932
+ document.getElementById('summaryLocation').textContent =
1933
+ `${document.getElementById('address').value || ''}, ${document.getElementById('city').value || ''}, ${document.getElementById('state').value || ''}, India`;
1934
+ document.getElementById('summaryPrice').textContent = document.getElementById('marketValue').value ? `₹${document.getElementById('marketValue').value}` : 'Not provided';
1935
+ document.getElementById('summarySize').textContent = document.getElementById('sqFt').value ? `${document.getElementById('sqFt').value} sq. ft.` : 'Not provided';
1936
+ document.getElementById('summaryRooms').textContent =
1937
+ `${document.getElementById('bedrooms').value || '0'} BHK`; // BHK is common in Indian real estate
1938
+
1939
+ // Update Final Verdict
1940
+ const verdictBox = document.getElementById('verdictBox');
1941
+ const verdictIcon = document.getElementById('verdictIcon');
1942
+ const verdictText = document.getElementById('verdictText');
1943
+ const verdictScoreValue = document.getElementById('verdictScoreValue');
1944
+ const verdictScoreBar = document.getElementById('verdictScoreBar');
1945
+
1946
+ // Get final verdict data
1947
+ const finalVerdict = data.final_verdict || {};
1948
+ const verdictStatus = finalVerdict.status || 'unknown';
1949
+ const verdictScore = finalVerdict.score || 0;
1950
+ const verdictConfidence = finalVerdict.confidence || 0;
1951
+
1952
+ // Update verdict display
1953
+ if (verdictStatus === 'fraudulent') {
1954
+ verdictBox.className = 'verdict-box verdict-fraudulent';
1955
+ verdictIcon.textContent = '❌';
1956
+ verdictText.textContent = 'HIGH RISK - LIKELY FRAUDULENT';
1957
+ } else if (verdictStatus === 'suspicious') {
1958
+ verdictBox.className = 'verdict-box verdict-suspicious';
1959
+ verdictIcon.textContent = '⚠️';
1960
+ verdictText.textContent = 'CAUTION - SUSPICIOUS ELEMENTS';
1961
+ } else if (verdictStatus === 'legitimate') {
1962
+ verdictBox.className = 'verdict-box verdict-legitimate';
1963
+ verdictIcon.textContent = '✅';
1964
+ verdictText.textContent = 'VERIFIED REAL ESTATE LISTING';
1965
+ } else {
1966
+ verdictBox.className = 'verdict-box';
1967
+ verdictIcon.textContent = '❓';
1968
+ verdictText.textContent = 'VERDICT UNKNOWN';
1969
+ }
1970
+
1971
+ // Update verdict score
1972
+ verdictScoreValue.textContent = `${Math.round(verdictScore)}%`;
1973
+ verdictScoreBar.style.width = `${verdictScore}%`;
1974
+ verdictScoreBar.className = `progress-fill ${getScoreColorClass(verdictScore)}`;
1975
+
1976
+ // Display critical issues
1977
+ const criticalIssuesList = document.getElementById('criticalIssuesList');
1978
+ criticalIssuesList.innerHTML = '';
1979
+
1980
+ if (finalVerdict.critical_issues && finalVerdict.critical_issues.length > 0) {
1981
+ finalVerdict.critical_issues.forEach(issue => {
1982
+ const li = document.createElement('li');
1983
+ li.className = 'suggestion-item';
1984
+ li.innerHTML = `<i class="fas fa-exclamation-circle"></i> ${issue}`;
1985
+ criticalIssuesList.appendChild(li);
1986
+ });
1987
+ document.getElementById('criticalIssuesSection').style.display = 'block';
1988
+ } else {
1989
+ document.getElementById('criticalIssuesSection').style.display = 'none';
1990
+ }
1991
+
1992
+ // Display warnings
1993
+ const warningsList = document.getElementById('warningsList');
1994
+ warningsList.innerHTML = '';
1995
+
1996
+ if (finalVerdict.warnings && finalVerdict.warnings.length > 0) {
1997
+ finalVerdict.warnings.forEach(warning => {
1998
+ const li = document.createElement('li');
1999
+ li.className = 'suggestion-item';
2000
+ li.innerHTML = `<i class="fas fa-exclamation-triangle"></i> ${warning}`;
2001
+ warningsList.appendChild(li);
2002
+ });
2003
+ document.getElementById('warningsSection').style.display = 'block';
2004
+ } else {
2005
+ document.getElementById('warningsSection').style.display = 'none';
2006
+ }
2007
+
2008
+ // Display recommendations
2009
+ const recommendationsList = document.getElementById('recommendationsList');
2010
+ recommendationsList.innerHTML = '';
2011
+
2012
+ if (finalVerdict.recommendations && finalVerdict.recommendations.length > 0) {
2013
+ finalVerdict.recommendations.forEach(recommendation => {
2014
+ const li = document.createElement('li');
2015
+ li.className = 'suggestion-item';
2016
+ li.innerHTML = `<i class="fas fa-check-circle"></i> ${recommendation}`;
2017
+ recommendationsList.appendChild(li);
2018
+ });
2019
+ document.getElementById('recommendationsSection').style.display = 'block';
2020
+ } else {
2021
+ document.getElementById('recommendationsSection').style.display = 'none';
2022
+ }
2023
+
2024
+ // Update Verification Scores
2025
+ updateScoreBar('trustBar', 'trustValue', trustScore);
2026
+
2027
+ // Image authenticity score
2028
+ let imageScore = 0;
2029
+ if (data.image_analysis && data.image_analysis.image_analysis) {
2030
+ const propertyImages = data.image_analysis.image_analysis.filter(img => img && img.is_property_related);
2031
+ imageScore = data.image_analysis.image_count > 0 ?
2032
+ Math.round((propertyImages.length / data.image_analysis.image_count) * 100) : 0;
2033
+ }
2034
+ updateScoreBar('imageBar', 'imageValue', imageScore);
2035
+
2036
+ // Document verification score
2037
+ let docScore = 0;
2038
+ if (data.document_analysis && data.document_analysis.pdf_analysis) {
2039
+ const verificationScores = data.document_analysis.pdf_analysis.map(
2040
+ pdf => pdf.verification_score || 0
2041
+ );
2042
+ docScore = verificationScores.length > 0 ?
2043
+ Math.round((verificationScores.reduce((a, b) => a + b, 0) / verificationScores.length) * 100) : 0;
2044
+ }
2045
+ updateScoreBar('documentBar', 'documentValue', docScore);
2046
+
2047
+ // Content quality score
2048
+ const contentScore = validatedData.qualityAssessment ? validatedData.qualityAssessment.score : 0;
2049
+ updateScoreBar('contentBar', 'contentValue', contentScore);
2050
+
2051
+ // Location accuracy score
2052
+ const locationScore = data.location_analysis ? data.location_analysis.completeness_score || 0 : 0;
2053
+ updateScoreBar('locationBar', 'locationValue', locationScore);
2054
+
2055
+ // Update Red Flags
2056
+ const redFlagsList = document.getElementById('redFlagsList');
2057
+ redFlagsList.innerHTML = '';
2058
+
2059
+ const redFlags = [];
2060
+
2061
+ // Check for inconsistencies and issues
2062
+ if (data.cross_validation) {
2063
+ data.cross_validation.forEach(check => {
2064
+ if (check.status === 'inconsistent' || check.status === 'invalid' ||
2065
+ check.status === 'suspicious' || check.status === 'no_match') {
2066
+ redFlags.push(`${check.check}: ${check.message}`);
2067
+ }
2068
+ });
2069
+ }
2070
+
2071
+ if (validatedData.qualityAssessment && validatedData.qualityAssessment.isAiGenerated) {
2072
+ redFlags.push('Description appears to be AI-generated, which may indicate a fake listing');
2073
+ }
2074
+
2075
+ if (data.price_analysis &&
2076
+ (data.price_analysis.assessment === 'suspicious pricing' ||
2077
+ data.price_analysis.assessment === 'overpriced' ||
2078
+ data.price_analysis.assessment === 'underpriced')) {
2079
+ redFlags.push(`Price is ${data.price_analysis.assessment} for this type of property`);
2080
+ }
2081
+
2082
+ if (data.legal_analysis && data.legal_analysis.potential_issues) {
2083
+ redFlags.push('Potential legal issues detected in the property documentation');
2084
+ }
2085
+
2086
+ if (data.image_analysis && data.image_analysis.image_count > 0) {
2087
+ const propertyImages = data.image_analysis.image_analysis.filter(img => img && img.is_property_related);
2088
+ if (propertyImages.length === 0) {
2089
+ redFlags.push('None of the uploaded images appear to be related to real estate');
2090
+ }
2091
+ }
2092
+
2093
+ // If no red flags, add a positive message
2094
+ if (redFlags.length === 0) {
2095
+ redFlags.push('No significant red flags detected in this listing');
2096
+ }
2097
+
2098
+ redFlags.forEach(flag => {
2099
+ const li = document.createElement('li');
2100
+ li.className = 'suggestion-item';
2101
+ li.textContent = flag;
2102
+ redFlagsList.appendChild(li);
2103
+ });
2104
+
2105
+ } catch (error) {
2106
+ console.error('Error displaying results:', error);
2107
+ document.getElementById('resultsContainer').innerHTML =
2108
+ '<div class="alert alert-danger">Error displaying results. Please try again.</div>';
2109
+ }
2110
+ }
2111
+
2112
+ function updateScoreBar(barId, valueId, score) {
2113
+ const bar = document.getElementById(barId);
2114
+ const value = document.getElementById(valueId);
2115
+
2116
+ if (bar && value) {
2117
+ bar.style.setProperty('--score-width', `${score}%`);
2118
+ bar.style.background = `linear-gradient(to right,
2119
+ ${getScoreColor(score)} ${score}%,
2120
+ #e9ecef ${score}%)`;
2121
+ value.textContent = `${score}%`;
2122
+ }
2123
+ }
2124
+
2125
+ function getScoreColor(score) {
2126
+ if (score >= 70) return 'var(--success)';
2127
+ if (score >= 40) return 'var(--warning)';
2128
+ return 'var(--danger)';
2129
+ }
2130
+ </script>
2131
+ </body>
2132
+ </html>