sksameermujahid commited on
Commit
647e8fa
·
verified ·
1 Parent(s): b4d9d6a

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +546 -239
templates/index.html CHANGED
@@ -3,223 +3,491 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Advanced AI Property Image Analyzer</title>
7
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
8
- <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
9
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  body {
 
11
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
12
  min-height: 100vh;
13
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 
 
 
 
 
14
  }
 
15
  .main-container {
16
- background: rgba(255, 255, 255, 0.95);
17
- border-radius: 20px;
18
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
19
- backdrop-filter: blur(10px);
20
- margin: 20px auto;
21
- max-width: 1400px;
 
22
  }
 
23
  .header {
24
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
25
  color: white;
26
- padding: 30px;
27
- border-radius: 20px 20px 0 0;
28
  text-align: center;
 
 
29
  }
30
- .upload-area {
31
- border: 3px dashed #667eea;
32
- border-radius: 15px;
33
- padding: 40px;
34
- text-align: center;
35
- background: rgba(102, 126, 234, 0.05);
36
- transition: all 0.3s ease;
37
- cursor: pointer;
 
 
38
  }
39
- .upload-area:hover {
40
- border-color: #764ba2;
41
- background: rgba(118, 75, 162, 0.05);
 
 
 
 
42
  }
43
- .upload-area.dragover {
44
- border-color: #764ba2;
45
- background: rgba(118, 75, 162, 0.1);
 
 
 
 
46
  }
47
- .result-card {
48
- background: white;
49
- border-radius: 15px;
50
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
51
- margin: 20px 0;
52
- overflow: hidden;
53
- transition: transform 0.3s ease;
 
 
 
 
54
  }
55
- .result-card:hover {
56
- transform: translateY(-5px);
 
57
  }
58
- .result-header {
59
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
60
- color: white;
61
- padding: 20px;
62
- font-weight: bold;
 
 
 
63
  }
64
- .result-body {
65
- padding: 25px;
 
 
66
  }
67
- .metric-card {
68
- background: #f8f9fa;
69
- border-radius: 10px;
70
- padding: 20px;
71
- margin: 10px 0;
72
- border-left: 4px solid #667eea;
73
  }
74
- .score-badge {
75
- font-size: 1.2em;
76
- font-weight: bold;
77
- padding: 8px 16px;
78
- border-radius: 20px;
79
  }
80
- .score-excellent { background: #28a745; color: white; }
81
- .score-good { background: #17a2b8; color: white; }
82
- .score-fair { background: #ffc107; color: black; }
83
- .score-poor { background: #dc3545; color: white; }
84
- .ai-model-badge {
85
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
86
- color: white;
87
- padding: 5px 12px;
88
- border-radius: 15px;
89
- font-size: 0.8em;
90
- margin: 2px;
91
- display: inline-block;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
93
- .loading {
 
 
 
 
 
 
 
 
94
  text-align: center;
95
- padding: 40px;
 
 
 
96
  }
 
97
  .spinner {
98
- border: 4px solid #f3f3f3;
99
- border-top: 4px solid #667eea;
 
 
100
  border-radius: 50%;
101
- width: 50px;
102
- height: 50px;
103
  animation: spin 1s linear infinite;
104
- margin: 0 auto 20px;
105
  }
 
106
  @keyframes spin {
107
  0% { transform: rotate(0deg); }
108
  100% { transform: rotate(360deg); }
109
  }
110
- .progress-bar {
 
 
 
111
  height: 8px;
112
- border-radius: 4px;
113
- background: #e9ecef;
114
  overflow: hidden;
 
115
  }
116
- .progress-fill {
 
117
  height: 100%;
118
- background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
119
  transition: width 0.3s ease;
120
- }
121
- .insight-card {
122
- background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
123
  border-radius: 10px;
124
- padding: 15px;
125
- margin: 10px 0;
126
- border-left: 4px solid #28a745;
127
  }
128
- .warning-card {
129
- background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
130
- border-radius: 10px;
131
- padding: 15px;
132
- margin: 10px 0;
133
- border-left: 4px solid #ffc107;
134
  }
135
- .error-card {
136
- background: linear-gradient(135deg, #f8d7da 0%, #f5c6cb 100%);
137
- border-radius: 10px;
138
- padding: 15px;
139
- margin: 10px 0;
140
- border-left: 4px solid #dc3545;
 
 
 
141
  }
142
- .object-item {
143
- background: white;
144
- border: 1px solid #dee2e6;
145
- border-radius: 8px;
146
- padding: 10px;
147
- margin: 5px 0;
148
- display: flex;
149
- justify-content: space-between;
150
- align-items: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  .confidence-bar {
153
- width: 100px;
154
  height: 6px;
155
- background: #e9ecef;
156
  border-radius: 3px;
157
  overflow: hidden;
 
158
  }
 
159
  .confidence-fill {
160
  height: 100%;
161
- background: linear-gradient(90deg, #28a745 0%, #17a2b8 100%);
162
  transition: width 0.3s ease;
 
163
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  .scene-concept {
165
- background: rgba(102, 126, 234, 0.1);
 
166
  border-radius: 8px;
167
- padding: 8px 12px;
168
- margin: 5px;
169
  display: inline-block;
170
- font-size: 0.9em;
 
171
  }
 
172
  .market-tier-badge {
173
- font-size: 1.1em;
174
- font-weight: bold;
175
- padding: 10px 20px;
176
- border-radius: 25px;
177
  text-transform: uppercase;
178
- letter-spacing: 1px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  }
180
- .tier-luxury { background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%); color: #333; }
181
- .tier-premium { background: linear-gradient(135deg, #c0c0c0 0%, #e5e5e5 100%); color: #333; }
182
- .tier-standard { background: linear-gradient(135deg, #cd7f32 0%, #daa520 100%); color: white; }
183
- .tier-value { background: linear-gradient(135deg, #6c757d 0%, #495057 100%); color: white; }
184
  </style>
185
  </head>
186
  <body>
187
  <div class="container-fluid">
188
  <div class="main-container">
189
  <div class="header">
190
- <h1><i class="fas fa-robot"></i> Advanced AI Property Image Analyzer</h1>
191
- <p class="mb-0">State-of-the-art AI-powered real estate image analysis with comprehensive insights</p>
 
 
 
 
 
192
  </div>
193
 
194
- <div class="container-fluid p-4">
195
  <div class="row">
196
- <div class="col-md-6">
197
- <div class="upload-area" id="uploadArea">
198
- <i class="fas fa-cloud-upload-alt fa-3x text-primary mb-3"></i>
199
- <h4>Upload Property Image</h4>
200
- <p>Drag and drop your image here or click to browse</p>
201
- <input type="file" id="imageInput" accept="image/*" style="display: none;">
202
- <button class="btn btn-primary btn-lg" onclick="document.getElementById('imageInput').click()">
203
- <i class="fas fa-upload"></i> Choose Image
204
- </button>
 
 
 
 
205
  </div>
206
 
207
- <div id="imagePreview" class="mt-3" style="display: none;">
208
- <img id="previewImg" class="img-fluid rounded" style="max-height: 300px;">
209
  </div>
210
  </div>
211
 
212
- <div class="col-md-6">
213
- <div id="loading" class="loading" style="display: none;">
214
  <div class="spinner"></div>
215
- <h4>Advanced AI Analysis in Progress...</h4>
216
  <p>Multiple AI models are analyzing your image</p>
217
- <div class="progress-bar">
218
- <div class="progress-fill" style="width: 0%"></div>
219
  </div>
220
  </div>
221
 
222
- <div id="results" style="display: none;">
223
  <!-- Results will be populated here -->
224
  </div>
225
  </div>
@@ -228,7 +496,7 @@
228
  </div>
229
  </div>
230
 
231
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
232
  <script>
233
  const uploadArea = document.getElementById('uploadArea');
234
  const imageInput = document.getElementById('imageInput');
@@ -268,15 +536,16 @@
268
 
269
  function handleImageUpload(file) {
270
  if (!file.type.startsWith('image/')) {
271
- alert('Please select a valid image file.');
272
  return;
273
  }
274
 
275
- // Show preview
276
  const reader = new FileReader();
277
  reader.onload = (e) => {
278
  previewImg.src = e.target.result;
279
  imagePreview.style.display = 'block';
 
280
  };
281
  reader.readAsDataURL(file);
282
 
@@ -284,6 +553,21 @@
284
  analyzeImage(file);
285
  }
286
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
 
288
 
289
  function displayResults(data) {
@@ -291,7 +575,7 @@
291
 
292
  if (data.error) {
293
  results.innerHTML = `
294
- <div class="error-card">
295
  <h5><i class="fas fa-exclamation-triangle"></i> Analysis Error</h5>
296
  <p>${data.error}</p>
297
  </div>
@@ -313,79 +597,86 @@
313
 
314
  results.innerHTML = `
315
  <!-- Analysis Summary -->
316
- <div class="result-card">
317
  <div class="result-header">
318
  <h4><i class="fas fa-chart-line"></i> Analysis Summary</h4>
319
  </div>
320
  <div class="result-body">
321
- <div class="row">
322
- <div class="col-md-6">
323
- <div class="metric-card">
324
- <h6><i class="fas fa-home"></i> Room Type</h6>
325
- <p class="mb-1"><strong>${roomClass.room_type}</strong></p>
326
- <div class="confidence-bar">
327
- <div class="confidence-fill" style="width: ${roomClass.confidence}%"></div>
328
- </div>
329
- <small>Confidence: ${roomClass.confidence}%</small>
330
  </div>
 
331
  </div>
332
- <div class="col-md-6">
333
- <div class="metric-card">
334
- <h6><i class="fas fa-star"></i> Overall Score</h6>
 
335
  <span class="score-badge ${getScoreClass(assessment.overall_score)}">${assessment.overall_score}/100</span>
336
- <p class="mt-2 mb-0"><small>${assessment.professional_grade ? 'Professional Grade' : 'Standard Grade'}</small></p>
337
  </div>
 
338
  </div>
339
- </div>
340
-
341
- <div class="row mt-3">
342
- <div class="col-md-4">
343
- <div class="metric-card">
344
- <h6><i class="fas fa-camera"></i> Quality Score</h6>
345
  <span class="score-badge ${getScoreClass(quality.quality_score)}">${quality.quality_score}/100</span>
346
- <p class="mt-2 mb-0"><small>${quality.quality_level}</small></p>
347
  </div>
 
348
  </div>
349
- <div class="col-md-4">
350
- <div class="metric-card">
351
- <h6><i class="fas fa-cube"></i> Objects Detected</h6>
352
- <span class="score-badge score-good">${objects.objects.length}</span>
353
- <p class="mt-2 mb-0"><small>${objects.analysis.total_objects || 0} total</small></p>
354
- </div>
 
 
 
 
 
355
  </div>
356
- <div class="col-md-4">
357
- <div class="metric-card">
358
- <h6><i class="fas fa-ruler-combined"></i> Room Size</h6>
359
- <span class="score-badge score-good">${roomSize.estimated_size}</span>
360
- <p class="mt-2 mb-0"><small>Confidence: ${roomSize.confidence}</small></p>
361
  </div>
 
362
  </div>
363
  </div>
364
  </div>
365
  </div>
366
 
367
  <!-- Market Analysis -->
368
- <div class="result-card">
369
  <div class="result-header">
370
  <h4><i class="fas fa-chart-bar"></i> Market Analysis</h4>
371
  </div>
372
  <div class="result-body">
373
  <div class="row">
374
  <div class="col-md-6">
375
- <div class="market-tier-badge tier-${market.market_tier.toLowerCase()}">${market.market_tier}</div>
376
- <p class="mt-2"><strong>Target Market:</strong> ${market.target_market}</p>
377
- <p><strong>Price Positioning:</strong> ${market.price_positioning}</p>
378
  <p><strong>Competitive Position:</strong> ${market.competitive_position}</p>
 
 
 
 
 
379
  </div>
380
  <div class="col-md-6">
381
- <h6>Competitive Advantages:</h6>
382
- <ul>
383
- ${(market.competitive_advantages || []).map(adv => `<li>${adv}</li>`).join('')}
384
  </ul>
385
 
386
- <h6>Differentiation Factors:</h6>
387
- <ul>
388
- ${(market.differentiation_factors || []).map(factor => `<li>${factor}</li>`).join('')}
389
  </ul>
390
  </div>
391
  </div>
@@ -393,32 +684,32 @@
393
  </div>
394
 
395
  <!-- Property Insights -->
396
- <div class="result-card">
397
  <div class="result-header">
398
  <h4><i class="fas fa-lightbulb"></i> Property Insights</h4>
399
  </div>
400
  <div class="result-body">
401
  <div class="row">
402
  <div class="col-md-6">
403
- <h6><i class="fas fa-bullhorn"></i> Marketing Tips</h6>
404
- <ul>
405
- ${(insights.marketing_tips || []).map(tip => `<li>${tip}</li>`).join('')}
406
  </ul>
407
 
408
- <h6><i class="fas fa-users"></i> Target Audience</h6>
409
- <ul>
410
- ${(insights.target_audience || []).map(audience => `<li>${audience}</li>`).join('')}
411
  </ul>
412
  </div>
413
  <div class="col-md-6">
414
- <h6><i class="fas fa-dollar-sign"></i> Pricing Considerations</h6>
415
- <ul>
416
- ${(insights.pricing_considerations || []).map(consideration => `<li>${consideration}</li>`).join('')}
417
  </ul>
418
 
419
- <h6><i class="fas fa-tools"></i> Improvement Suggestions</h6>
420
- <ul>
421
- ${(insights.improvement_suggestions || []).map(suggestion => `<li>${suggestion}</li>`).join('')}
422
  </ul>
423
  </div>
424
  </div>
@@ -426,17 +717,18 @@
426
  </div>
427
 
428
  <!-- Scene Analysis -->
429
- <div class="result-card">
430
  <div class="result-header">
431
  <h4><i class="fas fa-palette"></i> Scene Analysis</h4>
432
  </div>
433
  <div class="result-body">
434
  <div class="row">
435
  <div class="col-md-6">
436
- <h6>Dominant Style: ${scene.style_analysis.dominant_style}</h6>
 
437
  <p><strong>Style Confidence:</strong> ${(scene.style_analysis.style_confidence * 100).toFixed(1)}%</p>
438
 
439
- <h6>Scene Concepts:</h6>
440
  <div>
441
  ${(scene.scene_concepts || []).map(concept =>
442
  `<span class="scene-concept">${concept.concept} (${(concept.confidence * 100).toFixed(1)}%)</span>`
@@ -444,17 +736,17 @@
444
  </div>
445
  </div>
446
  <div class="col-md-6">
447
- <h6>Quality Indicators:</h6>
448
- <ul>
449
  ${(scene.style_analysis.quality_indicators || []).map(indicator =>
450
- `<li>${indicator.concept} (${(indicator.confidence * 100).toFixed(1)}%)</li>`
451
  ).join('')}
452
  </ul>
453
 
454
- <h6>Functionality Indicators:</h6>
455
- <ul>
456
  ${(scene.style_analysis.functionality_indicators || []).map(indicator =>
457
- `<li>${indicator.concept} (${(indicator.confidence * 100).toFixed(1)}%)</li>`
458
  ).join('')}
459
  </ul>
460
  </div>
@@ -463,32 +755,27 @@
463
  </div>
464
 
465
  <!-- Detailed Analysis -->
466
- <div class="result-card">
467
  <div class="result-header">
468
  <h4><i class="fas fa-microscope"></i> Detailed Analysis</h4>
469
  </div>
470
  <div class="result-body">
471
  <div class="row">
472
  <div class="col-md-6">
473
- <h6>Strengths:</h6>
474
- <ul>
475
- ${(assessment.strengths || []).map(strength => `<li class="insight-card">${strength}</li>`).join('')}
476
  </ul>
477
 
478
- <h6>Weaknesses:</h6>
479
- <ul>
480
- ${(assessment.weaknesses || []).map(weakness => `<li class="warning-card">${weakness}</li>`).join('')}
481
  </ul>
482
  </div>
483
  <div class="col-md-6">
484
- <h6>Recommendations:</h6>
485
- <ul>
486
- ${(assessment.recommendations || []).map(rec => `<li class="insight-card">${rec}</li>`).join('')}
487
- </ul>
488
-
489
- <h6>Market Opportunities:</h6>
490
- <ul>
491
- ${(market.market_opportunities || []).map(opp => `<li class="insight-card">${opp}</li>`).join('')}
492
  </ul>
493
  </div>
494
  </div>
@@ -496,14 +783,14 @@
496
  </div>
497
 
498
  <!-- Object Detection Results -->
499
- <div class="result-card">
500
  <div class="result-header">
501
  <h4><i class="fas fa-cube"></i> Object Detection</h4>
502
  </div>
503
  <div class="result-body">
504
  <div class="row">
505
  <div class="col-md-6">
506
- <h6>Detected Objects:</h6>
507
  ${(objects.objects || []).map(obj => `
508
  <div class="object-item">
509
  <span><i class="fas fa-tag"></i> ${obj.label}</span>
@@ -515,13 +802,31 @@
515
  `).join('')}
516
  </div>
517
  <div class="col-md-6">
518
- <h6>Object Categories:</h6>
519
- <p><strong>Furniture:</strong> ${objects.analysis.object_categories?.furniture?.length || 0} items</p>
520
- <p><strong>Appliances:</strong> ${objects.analysis.object_categories?.appliances?.length || 0} items</p>
521
- <p><strong>Fixtures:</strong> ${objects.analysis.object_categories?.fixtures?.length || 0} items</p>
522
- <p><strong>Other:</strong> ${objects.analysis.object_categories?.other?.length || 0} items</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
 
524
- <h6>Composition Analysis:</h6>
525
  <p><strong>Object Density:</strong> ${objects.analysis.object_density?.toFixed(2) || 0}</p>
526
  <p><strong>Composition Balance:</strong> ${(objects.analysis.composition_balance * 100).toFixed(1)}%</p>
527
  </div>
@@ -530,12 +835,12 @@
530
  </div>
531
 
532
  <!-- AI Models Used -->
533
- <div class="result-card">
534
  <div class="result-header">
535
  <h4><i class="fas fa-robot"></i> AI Models Used</h4>
536
  </div>
537
  <div class="result-body">
538
- <div>
539
  <span class="ai-model-badge">Room Classification</span>
540
  <span class="ai-model-badge">BLIP Captioning</span>
541
  <span class="ai-model-badge">DETR Detection</span>
@@ -543,7 +848,9 @@
543
  <span class="ai-model-badge">CLIP Scene Understanding</span>
544
  <span class="ai-model-badge">Market Analysis</span>
545
  </div>
546
- <p class="mt-3 mb-0"><small><i class="fas fa-clock"></i> Analysis completed at ${new Date().toLocaleString()}</small></p>
 
 
547
  </div>
548
  </div>
549
  `;
@@ -562,11 +869,11 @@
562
 
563
  // Simulate progress
564
  let progress = 0;
565
- const progressFill = document.querySelector('.progress-fill');
566
  const progressInterval = setInterval(() => {
567
  progress += Math.random() * 15;
568
  if (progress > 90) progress = 90;
569
- progressFill.style.width = progress + '%';
570
  }, 500);
571
 
572
  fetch('/analyze', {
@@ -581,7 +888,7 @@
581
  })
582
  .then(data => {
583
  clearInterval(progressInterval);
584
- progressFill.style.width = '100%';
585
 
586
  setTimeout(() => {
587
  loading.style.display = 'none';
@@ -593,7 +900,7 @@
593
  loading.style.display = 'none';
594
  console.error('Analysis failed:', error);
595
  results.innerHTML = `
596
- <div class="error-card">
597
  <h5><i class="fas fa-exclamation-triangle"></i> Analysis Failed</h5>
598
  <p>Error: ${error.message}</p>
599
  <p>Please try again or check the server logs.</p>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Property Analyzer</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
9
  <style>
10
+ :root {
11
+ --primary-color: #6366f1;
12
+ --primary-dark: #4f46e5;
13
+ --secondary-color: #8b5cf6;
14
+ --accent-color: #06b6d4;
15
+ --success-color: #10b981;
16
+ --warning-color: #f59e0b;
17
+ --error-color: #ef4444;
18
+ --text-primary: #1f2937;
19
+ --text-secondary: #6b7280;
20
+ --bg-primary: #ffffff;
21
+ --bg-secondary: #f9fafb;
22
+ --border-color: #e5e7eb;
23
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
24
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
25
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
26
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
27
+ }
28
+
29
+ * {
30
+ margin: 0;
31
+ padding: 0;
32
+ box-sizing: border-box;
33
+ }
34
+
35
  body {
36
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
37
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
38
  min-height: 100vh;
39
+ color: var(--text-primary);
40
+ line-height: 1.6;
41
+ }
42
+
43
+ .container-fluid {
44
+ padding: 2rem 1rem;
45
  }
46
+
47
  .main-container {
48
+ background: var(--bg-primary);
49
+ border-radius: 24px;
50
+ box-shadow: var(--shadow-xl);
51
+ backdrop-filter: blur(20px);
52
+ margin: 0 auto;
53
+ max-width: 1200px;
54
+ overflow: hidden;
55
  }
56
+
57
  .header {
58
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
59
  color: white;
60
+ padding: 3rem 2rem;
 
61
  text-align: center;
62
+ position: relative;
63
+ overflow: hidden;
64
  }
65
+
66
+ .header::before {
67
+ content: '';
68
+ position: absolute;
69
+ top: 0;
70
+ left: 0;
71
+ right: 0;
72
+ bottom: 0;
73
+ background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grain" width="100" height="100" patternUnits="userSpaceOnUse"><circle cx="25" cy="25" r="1" fill="white" opacity="0.1"/><circle cx="75" cy="75" r="1" fill="white" opacity="0.1"/><circle cx="50" cy="10" r="0.5" fill="white" opacity="0.1"/></pattern></defs><rect width="100" height="100" fill="url(%23grain)"/></svg>');
74
+ opacity: 0.3;
75
  }
76
+
77
+ .header h1 {
78
+ font-size: 2.5rem;
79
+ font-weight: 800;
80
+ margin-bottom: 0.5rem;
81
+ position: relative;
82
+ z-index: 1;
83
  }
84
+
85
+ .header p {
86
+ font-size: 1.1rem;
87
+ opacity: 0.9;
88
+ margin-bottom: 1.5rem;
89
+ position: relative;
90
+ z-index: 1;
91
  }
92
+
93
+ .badge {
94
+ background: rgba(255, 255, 255, 0.2);
95
+ border: 1px solid rgba(255, 255, 255, 0.3);
96
+ backdrop-filter: blur(10px);
97
+ padding: 0.5rem 1rem;
98
+ border-radius: 50px;
99
+ font-size: 0.875rem;
100
+ font-weight: 500;
101
+ margin: 0.25rem;
102
+ display: inline-block;
103
  }
104
+
105
+ .content-area {
106
+ padding: 3rem 2rem;
107
  }
108
+
109
+ .upload-section {
110
+ background: var(--bg-secondary);
111
+ border-radius: 20px;
112
+ padding: 2rem;
113
+ margin-bottom: 2rem;
114
+ border: 2px dashed var(--border-color);
115
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
116
  }
117
+
118
+ .upload-section:hover {
119
+ border-color: var(--primary-color);
120
+ background: rgba(99, 102, 241, 0.02);
121
  }
122
+
123
+ .upload-section.dragover {
124
+ border-color: var(--primary-color);
125
+ background: rgba(99, 102, 241, 0.05);
126
+ transform: scale(1.02);
 
127
  }
128
+
129
+ .upload-icon {
130
+ font-size: 3rem;
131
+ color: var(--primary-color);
132
+ margin-bottom: 1rem;
133
  }
134
+
135
+ .upload-text h4 {
136
+ font-size: 1.5rem;
137
+ font-weight: 600;
138
+ margin-bottom: 0.5rem;
139
+ color: var(--text-primary);
140
+ }
141
+
142
+ .upload-text p {
143
+ color: var(--text-secondary);
144
+ margin-bottom: 1.5rem;
145
+ }
146
+
147
+ .btn-primary {
148
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
149
+ border: none;
150
+ padding: 0.75rem 2rem;
151
+ border-radius: 12px;
152
+ font-weight: 600;
153
+ transition: all 0.3s ease;
154
+ box-shadow: var(--shadow-md);
155
+ }
156
+
157
+ .btn-primary:hover {
158
+ transform: translateY(-2px);
159
+ box-shadow: var(--shadow-lg);
160
+ }
161
+
162
+ .image-preview {
163
+ margin-top: 1.5rem;
164
+ border-radius: 16px;
165
+ overflow: hidden;
166
+ box-shadow: var(--shadow-lg);
167
  }
168
+
169
+ .image-preview img {
170
+ width: 100%;
171
+ height: auto;
172
+ max-height: 300px;
173
+ object-fit: cover;
174
+ }
175
+
176
+ .loading-section {
177
  text-align: center;
178
+ padding: 3rem 2rem;
179
+ background: var(--bg-secondary);
180
+ border-radius: 20px;
181
+ margin-bottom: 2rem;
182
  }
183
+
184
  .spinner {
185
+ width: 60px;
186
+ height: 60px;
187
+ border: 4px solid var(--border-color);
188
+ border-top: 4px solid var(--primary-color);
189
  border-radius: 50%;
 
 
190
  animation: spin 1s linear infinite;
191
+ margin: 0 auto 1.5rem;
192
  }
193
+
194
  @keyframes spin {
195
  0% { transform: rotate(0deg); }
196
  100% { transform: rotate(360deg); }
197
  }
198
+
199
+ .progress-container {
200
+ background: var(--border-color);
201
+ border-radius: 10px;
202
  height: 8px;
 
 
203
  overflow: hidden;
204
+ margin: 1rem 0;
205
  }
206
+
207
+ .progress-bar {
208
  height: 100%;
209
+ background: linear-gradient(90deg, var(--primary-color) 0%, var(--secondary-color) 100%);
210
  transition: width 0.3s ease;
 
 
 
211
  border-radius: 10px;
 
 
 
212
  }
213
+
214
+ .results-section {
215
+ display: none;
 
 
 
216
  }
217
+
218
+ .result-card {
219
+ background: var(--bg-primary);
220
+ border-radius: 20px;
221
+ box-shadow: var(--shadow-md);
222
+ margin-bottom: 1.5rem;
223
+ overflow: hidden;
224
+ transition: all 0.3s ease;
225
+ border: 1px solid var(--border-color);
226
  }
227
+
228
+ .result-card:hover {
229
+ transform: translateY(-4px);
230
+ box-shadow: var(--shadow-xl);
231
+ }
232
+
233
+ .result-header {
234
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
235
+ color: white;
236
+ padding: 1.5rem 2rem;
237
+ font-weight: 600;
238
+ font-size: 1.25rem;
239
+ }
240
+
241
+ .result-body {
242
+ padding: 2rem;
243
+ }
244
+
245
+ .metric-grid {
246
+ display: grid;
247
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
248
+ gap: 1.5rem;
249
+ margin-bottom: 2rem;
250
+ }
251
+
252
+ .metric-card {
253
+ background: var(--bg-secondary);
254
+ border-radius: 16px;
255
+ padding: 1.5rem;
256
+ border-left: 4px solid var(--primary-color);
257
+ transition: all 0.3s ease;
258
  }
259
+
260
+ .metric-card:hover {
261
+ transform: translateY(-2px);
262
+ box-shadow: var(--shadow-lg);
263
+ }
264
+
265
+ .metric-title {
266
+ font-size: 0.875rem;
267
+ font-weight: 600;
268
+ color: var(--text-secondary);
269
+ text-transform: uppercase;
270
+ letter-spacing: 0.05em;
271
+ margin-bottom: 0.5rem;
272
+ }
273
+
274
+ .metric-value {
275
+ font-size: 1.5rem;
276
+ font-weight: 700;
277
+ color: var(--text-primary);
278
+ margin-bottom: 0.25rem;
279
+ }
280
+
281
+ .metric-subtitle {
282
+ font-size: 0.875rem;
283
+ color: var(--text-secondary);
284
+ }
285
+
286
+ .score-badge {
287
+ display: inline-block;
288
+ padding: 0.5rem 1rem;
289
+ border-radius: 50px;
290
+ font-weight: 600;
291
+ font-size: 0.875rem;
292
+ text-transform: uppercase;
293
+ letter-spacing: 0.05em;
294
+ }
295
+
296
+ .score-excellent { background: var(--success-color); color: white; }
297
+ .score-good { background: var(--accent-color); color: white; }
298
+ .score-fair { background: var(--warning-color); color: white; }
299
+ .score-poor { background: var(--error-color); color: white; }
300
+
301
  .confidence-bar {
302
+ width: 100%;
303
  height: 6px;
304
+ background: var(--border-color);
305
  border-radius: 3px;
306
  overflow: hidden;
307
+ margin: 0.5rem 0;
308
  }
309
+
310
  .confidence-fill {
311
  height: 100%;
312
+ background: linear-gradient(90deg, var(--success-color) 0%, var(--accent-color) 100%);
313
  transition: width 0.3s ease;
314
+ border-radius: 3px;
315
  }
316
+
317
+ .insight-list {
318
+ list-style: none;
319
+ padding: 0;
320
+ }
321
+
322
+ .insight-item {
323
+ background: var(--bg-secondary);
324
+ border-radius: 12px;
325
+ padding: 1rem;
326
+ margin-bottom: 0.75rem;
327
+ border-left: 4px solid var(--success-color);
328
+ transition: all 0.3s ease;
329
+ }
330
+
331
+ .insight-item:hover {
332
+ transform: translateX(4px);
333
+ }
334
+
335
+ .warning-item {
336
+ border-left-color: var(--warning-color);
337
+ }
338
+
339
+ .error-item {
340
+ border-left-color: var(--error-color);
341
+ }
342
+
343
+ .object-item {
344
+ background: var(--bg-secondary);
345
+ border-radius: 12px;
346
+ padding: 1rem;
347
+ margin-bottom: 0.5rem;
348
+ display: flex;
349
+ justify-content: space-between;
350
+ align-items: center;
351
+ transition: all 0.3s ease;
352
+ }
353
+
354
+ .object-item:hover {
355
+ background: var(--bg-primary);
356
+ box-shadow: var(--shadow-sm);
357
+ }
358
+
359
  .scene-concept {
360
+ background: rgba(99, 102, 241, 0.1);
361
+ color: var(--primary-color);
362
  border-radius: 8px;
363
+ padding: 0.5rem 0.75rem;
364
+ margin: 0.25rem;
365
  display: inline-block;
366
+ font-size: 0.875rem;
367
+ font-weight: 500;
368
  }
369
+
370
  .market-tier-badge {
371
+ display: inline-block;
372
+ padding: 0.75rem 1.5rem;
373
+ border-radius: 50px;
374
+ font-weight: 700;
375
  text-transform: uppercase;
376
+ letter-spacing: 0.1em;
377
+ font-size: 0.875rem;
378
+ }
379
+
380
+ .tier-luxury { background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%); color: #92400e; }
381
+ .tier-premium { background: linear-gradient(135deg, #9ca3af 0%, #6b7280 100%); color: white; }
382
+ .tier-standard { background: linear-gradient(135deg, #d97706 0%, #b45309 100%); color: white; }
383
+ .tier-value { background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%); color: white; }
384
+
385
+ .ai-model-badge {
386
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
387
+ color: white;
388
+ padding: 0.5rem 1rem;
389
+ border-radius: 50px;
390
+ font-size: 0.75rem;
391
+ font-weight: 500;
392
+ margin: 0.25rem;
393
+ display: inline-block;
394
+ }
395
+
396
+ .error-card {
397
+ background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
398
+ border: 1px solid #fecaca;
399
+ border-radius: 16px;
400
+ padding: 1.5rem;
401
+ color: var(--error-color);
402
+ }
403
+
404
+ @media (max-width: 768px) {
405
+ .container-fluid {
406
+ padding: 1rem 0.5rem;
407
+ }
408
+
409
+ .header {
410
+ padding: 2rem 1rem;
411
+ }
412
+
413
+ .header h1 {
414
+ font-size: 2rem;
415
+ }
416
+
417
+ .content-area {
418
+ padding: 2rem 1rem;
419
+ }
420
+
421
+ .metric-grid {
422
+ grid-template-columns: 1fr;
423
+ }
424
+ }
425
+
426
+ .fade-in {
427
+ animation: fadeIn 0.6s ease-in-out;
428
+ }
429
+
430
+ @keyframes fadeIn {
431
+ from { opacity: 0; transform: translateY(20px); }
432
+ to { opacity: 1; transform: translateY(0); }
433
+ }
434
+
435
+ .slide-in {
436
+ animation: slideIn 0.8s ease-out;
437
+ }
438
+
439
+ @keyframes slideIn {
440
+ from { transform: translateX(-100%); opacity: 0; }
441
+ to { transform: translateX(0); opacity: 1; }
442
  }
 
 
 
 
443
  </style>
444
  </head>
445
  <body>
446
  <div class="container-fluid">
447
  <div class="main-container">
448
  <div class="header">
449
+ <h1><i class="fas fa-robot"></i> AI Property Analyzer</h1>
450
+ <p>Advanced AI-powered real estate image analysis with comprehensive insights</p>
451
+ <div>
452
+ <span class="badge"><i class="fas fa-brain"></i> AI-Powered</span>
453
+ <span class="badge"><i class="fas fa-chart-line"></i> Market Analysis</span>
454
+ <span class="badge"><i class="fas fa-camera"></i> Quality Assessment</span>
455
+ </div>
456
  </div>
457
 
458
+ <div class="content-area">
459
  <div class="row">
460
+ <div class="col-lg-6">
461
+ <div class="upload-section" id="uploadArea">
462
+ <div class="upload-icon">
463
+ <i class="fas fa-cloud-upload-alt"></i>
464
+ </div>
465
+ <div class="upload-text">
466
+ <h4>Upload Property Image</h4>
467
+ <p>Drag and drop your image here or click to browse</p>
468
+ <input type="file" id="imageInput" accept="image/*" style="display: none;">
469
+ <button class="btn btn-primary" onclick="document.getElementById('imageInput').click()">
470
+ <i class="fas fa-upload"></i> Choose Image
471
+ </button>
472
+ </div>
473
  </div>
474
 
475
+ <div id="imagePreview" class="image-preview" style="display: none;">
476
+ <img id="previewImg" class="img-fluid">
477
  </div>
478
  </div>
479
 
480
+ <div class="col-lg-6">
481
+ <div id="loading" class="loading-section" style="display: none;">
482
  <div class="spinner"></div>
483
+ <h4>AI Analysis in Progress</h4>
484
  <p>Multiple AI models are analyzing your image</p>
485
+ <div class="progress-container">
486
+ <div class="progress-bar" style="width: 0%"></div>
487
  </div>
488
  </div>
489
 
490
+ <div id="results" class="results-section">
491
  <!-- Results will be populated here -->
492
  </div>
493
  </div>
 
496
  </div>
497
  </div>
498
 
499
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
500
  <script>
501
  const uploadArea = document.getElementById('uploadArea');
502
  const imageInput = document.getElementById('imageInput');
 
536
 
537
  function handleImageUpload(file) {
538
  if (!file.type.startsWith('image/')) {
539
+ showNotification('Please select a valid image file.', 'error');
540
  return;
541
  }
542
 
543
+ // Show preview with animation
544
  const reader = new FileReader();
545
  reader.onload = (e) => {
546
  previewImg.src = e.target.result;
547
  imagePreview.style.display = 'block';
548
+ imagePreview.classList.add('fade-in');
549
  };
550
  reader.readAsDataURL(file);
551
 
 
553
  analyzeImage(file);
554
  }
555
 
556
+ function showNotification(message, type = 'info') {
557
+ const notification = document.createElement('div');
558
+ notification.className = `alert alert-${type === 'error' ? 'danger' : 'info'} alert-dismissible fade show position-fixed`;
559
+ notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
560
+ notification.innerHTML = `
561
+ ${message}
562
+ <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
563
+ `;
564
+ document.body.appendChild(notification);
565
+
566
+ setTimeout(() => {
567
+ notification.remove();
568
+ }, 5000);
569
+ }
570
+
571
 
572
 
573
  function displayResults(data) {
 
575
 
576
  if (data.error) {
577
  results.innerHTML = `
578
+ <div class="error-card fade-in">
579
  <h5><i class="fas fa-exclamation-triangle"></i> Analysis Error</h5>
580
  <p>${data.error}</p>
581
  </div>
 
597
 
598
  results.innerHTML = `
599
  <!-- Analysis Summary -->
600
+ <div class="result-card fade-in">
601
  <div class="result-header">
602
  <h4><i class="fas fa-chart-line"></i> Analysis Summary</h4>
603
  </div>
604
  <div class="result-body">
605
+ <div class="metric-grid">
606
+ <div class="metric-card">
607
+ <div class="metric-title"><i class="fas fa-home"></i> Room Type</div>
608
+ <div class="metric-value">${roomClass.room_type}</div>
609
+ <div class="confidence-bar">
610
+ <div class="confidence-fill" style="width: ${roomClass.confidence}%"></div>
 
 
 
611
  </div>
612
+ <div class="metric-subtitle">Confidence: ${roomClass.confidence}%</div>
613
  </div>
614
+
615
+ <div class="metric-card">
616
+ <div class="metric-title"><i class="fas fa-star"></i> Overall Score</div>
617
+ <div class="metric-value">
618
  <span class="score-badge ${getScoreClass(assessment.overall_score)}">${assessment.overall_score}/100</span>
 
619
  </div>
620
+ <div class="metric-subtitle">${assessment.professional_grade ? 'Professional Grade' : 'Standard Grade'}</div>
621
  </div>
622
+
623
+ <div class="metric-card">
624
+ <div class="metric-title"><i class="fas fa-camera"></i> Quality Score</div>
625
+ <div class="metric-value">
 
 
626
  <span class="score-badge ${getScoreClass(quality.quality_score)}">${quality.quality_score}/100</span>
 
627
  </div>
628
+ <div class="metric-subtitle">${quality.quality_level}</div>
629
  </div>
630
+
631
+ <div class="metric-card">
632
+ <div class="metric-title"><i class="fas fa-cube"></i> Objects Detected</div>
633
+ <div class="metric-value">${objects.objects.length}</div>
634
+ <div class="metric-subtitle">${objects.analysis.total_objects || 0} total objects</div>
635
+ </div>
636
+
637
+ <div class="metric-card">
638
+ <div class="metric-title"><i class="fas fa-ruler-combined"></i> Room Size</div>
639
+ <div class="metric-value">${roomSize.estimated_size}</div>
640
+ <div class="metric-subtitle">Confidence: ${roomSize.confidence}</div>
641
  </div>
642
+
643
+ <div class="metric-card">
644
+ <div class="metric-title"><i class="fas fa-chart-bar"></i> Market Tier</div>
645
+ <div class="metric-value">
646
+ <span class="market-tier-badge tier-${market.market_tier.toLowerCase()}">${market.market_tier}</span>
647
  </div>
648
+ <div class="metric-subtitle">${market.price_positioning}</div>
649
  </div>
650
  </div>
651
  </div>
652
  </div>
653
 
654
  <!-- Market Analysis -->
655
+ <div class="result-card slide-in">
656
  <div class="result-header">
657
  <h4><i class="fas fa-chart-bar"></i> Market Analysis</h4>
658
  </div>
659
  <div class="result-body">
660
  <div class="row">
661
  <div class="col-md-6">
662
+ <h6 class="mb-3">Market Position</h6>
663
+ <p><strong>Target Market:</strong> ${market.target_market}</p>
 
664
  <p><strong>Competitive Position:</strong> ${market.competitive_position}</p>
665
+
666
+ <h6 class="mb-3 mt-4">Competitive Advantages</h6>
667
+ <ul class="insight-list">
668
+ ${(market.competitive_advantages || []).map(adv => `<li class="insight-item">${adv}</li>`).join('')}
669
+ </ul>
670
  </div>
671
  <div class="col-md-6">
672
+ <h6 class="mb-3">Differentiation Factors</h6>
673
+ <ul class="insight-list">
674
+ ${(market.differentiation_factors || []).map(factor => `<li class="insight-item">${factor}</li>`).join('')}
675
  </ul>
676
 
677
+ <h6 class="mb-3 mt-4">Market Opportunities</h6>
678
+ <ul class="insight-list">
679
+ ${(market.market_opportunities || []).map(opp => `<li class="insight-item">${opp}</li>`).join('')}
680
  </ul>
681
  </div>
682
  </div>
 
684
  </div>
685
 
686
  <!-- Property Insights -->
687
+ <div class="result-card slide-in">
688
  <div class="result-header">
689
  <h4><i class="fas fa-lightbulb"></i> Property Insights</h4>
690
  </div>
691
  <div class="result-body">
692
  <div class="row">
693
  <div class="col-md-6">
694
+ <h6 class="mb-3"><i class="fas fa-bullhorn"></i> Marketing Tips</h6>
695
+ <ul class="insight-list">
696
+ ${(insights.marketing_tips || []).map(tip => `<li class="insight-item">${tip}</li>`).join('')}
697
  </ul>
698
 
699
+ <h6 class="mb-3 mt-4"><i class="fas fa-users"></i> Target Audience</h6>
700
+ <ul class="insight-list">
701
+ ${(insights.target_audience || []).map(audience => `<li class="insight-item">${audience}</li>`).join('')}
702
  </ul>
703
  </div>
704
  <div class="col-md-6">
705
+ <h6 class="mb-3"><i class="fas fa-dollar-sign"></i> Pricing Considerations</h6>
706
+ <ul class="insight-list">
707
+ ${(insights.pricing_considerations || []).map(consideration => `<li class="insight-item">${consideration}</li>`).join('')}
708
  </ul>
709
 
710
+ <h6 class="mb-3 mt-4"><i class="fas fa-tools"></i> Improvement Suggestions</h6>
711
+ <ul class="insight-list">
712
+ ${(insights.improvement_suggestions || []).map(suggestion => `<li class="insight-item warning-item">${suggestion}</li>`).join('')}
713
  </ul>
714
  </div>
715
  </div>
 
717
  </div>
718
 
719
  <!-- Scene Analysis -->
720
+ <div class="result-card slide-in">
721
  <div class="result-header">
722
  <h4><i class="fas fa-palette"></i> Scene Analysis</h4>
723
  </div>
724
  <div class="result-body">
725
  <div class="row">
726
  <div class="col-md-6">
727
+ <h6 class="mb-3">Style Analysis</h6>
728
+ <p><strong>Dominant Style:</strong> ${scene.style_analysis.dominant_style}</p>
729
  <p><strong>Style Confidence:</strong> ${(scene.style_analysis.style_confidence * 100).toFixed(1)}%</p>
730
 
731
+ <h6 class="mb-3 mt-4">Scene Concepts</h6>
732
  <div>
733
  ${(scene.scene_concepts || []).map(concept =>
734
  `<span class="scene-concept">${concept.concept} (${(concept.confidence * 100).toFixed(1)}%)</span>`
 
736
  </div>
737
  </div>
738
  <div class="col-md-6">
739
+ <h6 class="mb-3">Quality Indicators</h6>
740
+ <ul class="insight-list">
741
  ${(scene.style_analysis.quality_indicators || []).map(indicator =>
742
+ `<li class="insight-item">${indicator.concept} (${(indicator.confidence * 100).toFixed(1)}%)</li>`
743
  ).join('')}
744
  </ul>
745
 
746
+ <h6 class="mb-3 mt-4">Functionality Indicators</h6>
747
+ <ul class="insight-list">
748
  ${(scene.style_analysis.functionality_indicators || []).map(indicator =>
749
+ `<li class="insight-item">${indicator.concept} (${(indicator.confidence * 100).toFixed(1)}%)</li>`
750
  ).join('')}
751
  </ul>
752
  </div>
 
755
  </div>
756
 
757
  <!-- Detailed Analysis -->
758
+ <div class="result-card slide-in">
759
  <div class="result-header">
760
  <h4><i class="fas fa-microscope"></i> Detailed Analysis</h4>
761
  </div>
762
  <div class="result-body">
763
  <div class="row">
764
  <div class="col-md-6">
765
+ <h6 class="mb-3">Strengths</h6>
766
+ <ul class="insight-list">
767
+ ${(assessment.strengths || []).map(strength => `<li class="insight-item">${strength}</li>`).join('')}
768
  </ul>
769
 
770
+ <h6 class="mb-3 mt-4">Weaknesses</h6>
771
+ <ul class="insight-list">
772
+ ${(assessment.weaknesses || []).map(weakness => `<li class="insight-item error-item">${weakness}</li>`).join('')}
773
  </ul>
774
  </div>
775
  <div class="col-md-6">
776
+ <h6 class="mb-3">Recommendations</h6>
777
+ <ul class="insight-list">
778
+ ${(assessment.recommendations || []).map(rec => `<li class="insight-item">${rec}</li>`).join('')}
 
 
 
 
 
779
  </ul>
780
  </div>
781
  </div>
 
783
  </div>
784
 
785
  <!-- Object Detection Results -->
786
+ <div class="result-card slide-in">
787
  <div class="result-header">
788
  <h4><i class="fas fa-cube"></i> Object Detection</h4>
789
  </div>
790
  <div class="result-body">
791
  <div class="row">
792
  <div class="col-md-6">
793
+ <h6 class="mb-3">Detected Objects</h6>
794
  ${(objects.objects || []).map(obj => `
795
  <div class="object-item">
796
  <span><i class="fas fa-tag"></i> ${obj.label}</span>
 
802
  `).join('')}
803
  </div>
804
  <div class="col-md-6">
805
+ <h6 class="mb-3">Object Categories</h6>
806
+ <div class="metric-grid">
807
+ <div class="metric-card">
808
+ <div class="metric-title">Furniture</div>
809
+ <div class="metric-value">${objects.analysis.object_categories?.furniture?.length || 0}</div>
810
+ <div class="metric-subtitle">items</div>
811
+ </div>
812
+ <div class="metric-card">
813
+ <div class="metric-title">Appliances</div>
814
+ <div class="metric-value">${objects.analysis.object_categories?.appliances?.length || 0}</div>
815
+ <div class="metric-subtitle">items</div>
816
+ </div>
817
+ <div class="metric-card">
818
+ <div class="metric-title">Fixtures</div>
819
+ <div class="metric-value">${objects.analysis.object_categories?.fixtures?.length || 0}</div>
820
+ <div class="metric-subtitle">items</div>
821
+ </div>
822
+ <div class="metric-card">
823
+ <div class="metric-title">Other</div>
824
+ <div class="metric-value">${objects.analysis.object_categories?.other?.length || 0}</div>
825
+ <div class="metric-subtitle">items</div>
826
+ </div>
827
+ </div>
828
 
829
+ <h6 class="mb-3 mt-4">Composition Analysis</h6>
830
  <p><strong>Object Density:</strong> ${objects.analysis.object_density?.toFixed(2) || 0}</p>
831
  <p><strong>Composition Balance:</strong> ${(objects.analysis.composition_balance * 100).toFixed(1)}%</p>
832
  </div>
 
835
  </div>
836
 
837
  <!-- AI Models Used -->
838
+ <div class="result-card slide-in">
839
  <div class="result-header">
840
  <h4><i class="fas fa-robot"></i> AI Models Used</h4>
841
  </div>
842
  <div class="result-body">
843
+ <div class="text-center">
844
  <span class="ai-model-badge">Room Classification</span>
845
  <span class="ai-model-badge">BLIP Captioning</span>
846
  <span class="ai-model-badge">DETR Detection</span>
 
848
  <span class="ai-model-badge">CLIP Scene Understanding</span>
849
  <span class="ai-model-badge">Market Analysis</span>
850
  </div>
851
+ <p class="text-center mt-3 mb-0 text-muted">
852
+ <i class="fas fa-clock"></i> Analysis completed at ${new Date().toLocaleString()}
853
+ </p>
854
  </div>
855
  </div>
856
  `;
 
869
 
870
  // Simulate progress
871
  let progress = 0;
872
+ const progressBar = document.querySelector('.progress-bar');
873
  const progressInterval = setInterval(() => {
874
  progress += Math.random() * 15;
875
  if (progress > 90) progress = 90;
876
+ progressBar.style.width = progress + '%';
877
  }, 500);
878
 
879
  fetch('/analyze', {
 
888
  })
889
  .then(data => {
890
  clearInterval(progressInterval);
891
+ progressBar.style.width = '100%';
892
 
893
  setTimeout(() => {
894
  loading.style.display = 'none';
 
900
  loading.style.display = 'none';
901
  console.error('Analysis failed:', error);
902
  results.innerHTML = `
903
+ <div class="error-card fade-in">
904
  <h5><i class="fas fa-exclamation-triangle"></i> Analysis Failed</h5>
905
  <p>Error: ${error.message}</p>
906
  <p>Please try again or check the server logs.</p>