Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
@@ -614,10 +614,990 @@ def get_room_type_description(room_type):
|
|
614 |
}
|
615 |
return descriptions.get(room_type, f"A {room_type} area")
|
616 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
617 |
@app.route('/')
|
618 |
def index():
|
619 |
"""Main page for the image analyzer"""
|
620 |
-
return render_template('
|
621 |
|
622 |
@app.route('/analyze', methods=['POST'])
|
623 |
def analyze_image():
|
@@ -785,6 +1765,24 @@ def health_check():
|
|
785 |
}
|
786 |
})
|
787 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
788 |
@app.route('/static/<path:filename>')
|
789 |
def static_files(filename):
|
790 |
"""Serve static files"""
|
|
|
614 |
}
|
615 |
return descriptions.get(room_type, f"A {room_type} area")
|
616 |
|
617 |
+
def assess_property_image_quality(room_classification, quality_analysis, object_detection, image_caption):
|
618 |
+
"""Advanced AI-powered property image assessment using dynamic analysis"""
|
619 |
+
try:
|
620 |
+
# Initialize assessment components
|
621 |
+
assessment = {
|
622 |
+
"overall_score": 0,
|
623 |
+
"strengths": [],
|
624 |
+
"weaknesses": [],
|
625 |
+
"recommendations": [],
|
626 |
+
"market_appeal": {},
|
627 |
+
"technical_analysis": {},
|
628 |
+
"composition_analysis": {},
|
629 |
+
"professional_grade": False
|
630 |
+
}
|
631 |
+
|
632 |
+
# 1. Dynamic Room Classification Analysis (0-25 points)
|
633 |
+
room_score = 0
|
634 |
+
room_confidence = room_classification.get('confidence', 0)
|
635 |
+
room_type = room_classification.get('room_type', 'unknown')
|
636 |
+
|
637 |
+
# AI-based room type validation
|
638 |
+
if room_confidence > 0.8:
|
639 |
+
room_score = 25
|
640 |
+
assessment["strengths"].append(f"Clear {room_type} identification with high confidence")
|
641 |
+
elif room_confidence > 0.6:
|
642 |
+
room_score = 20
|
643 |
+
assessment["strengths"].append(f"Good {room_type} identification")
|
644 |
+
elif room_confidence > 0.4:
|
645 |
+
room_score = 15
|
646 |
+
assessment["weaknesses"].append(f"Uncertain room type identification")
|
647 |
+
else:
|
648 |
+
room_score = 5
|
649 |
+
assessment["weaknesses"].append("Poor room type identification")
|
650 |
+
|
651 |
+
# Cross-validate with object detection
|
652 |
+
object_room_inference = object_detection.get('analysis', {}).get('room_type_inference', {})
|
653 |
+
if room_type in object_room_inference:
|
654 |
+
object_confidence = object_room_inference[room_type]
|
655 |
+
if object_confidence > 0.5:
|
656 |
+
room_score += 5 # Bonus for consistency
|
657 |
+
assessment["strengths"].append("Object detection confirms room type")
|
658 |
+
else:
|
659 |
+
room_score -= 5 # Penalty for inconsistency
|
660 |
+
assessment["weaknesses"].append("Object detection contradicts room type")
|
661 |
+
|
662 |
+
# 2. Advanced Quality Analysis (0-30 points)
|
663 |
+
quality_score = 0
|
664 |
+
quality_metrics = quality_analysis.get('metrics', {})
|
665 |
+
quality_level = quality_analysis.get('quality_level', 'Unknown')
|
666 |
+
quality_issues = quality_analysis.get('issues', [])
|
667 |
+
|
668 |
+
# Dynamic quality scoring based on multiple factors
|
669 |
+
base_quality = quality_analysis.get('quality_score', 0)
|
670 |
+
|
671 |
+
# Technical quality factors
|
672 |
+
brightness_score = 0
|
673 |
+
brightness_mean = quality_metrics.get('brightness_mean', 128)
|
674 |
+
if 60 <= brightness_mean <= 180:
|
675 |
+
brightness_score = 8
|
676 |
+
elif 40 <= brightness_mean <= 200:
|
677 |
+
brightness_score = 5
|
678 |
+
else:
|
679 |
+
brightness_score = 2
|
680 |
+
|
681 |
+
contrast_score = 0
|
682 |
+
contrast = quality_metrics.get('contrast', 0)
|
683 |
+
if contrast > 40:
|
684 |
+
contrast_score = 8
|
685 |
+
elif contrast > 25:
|
686 |
+
contrast_score = 5
|
687 |
+
else:
|
688 |
+
contrast_score = 2
|
689 |
+
|
690 |
+
sharpness_score = 0
|
691 |
+
sharpness = quality_metrics.get('sharpness', 0)
|
692 |
+
if sharpness > 80:
|
693 |
+
sharpness_score = 8
|
694 |
+
elif sharpness > 50:
|
695 |
+
sharpness_score = 5
|
696 |
+
else:
|
697 |
+
sharpness_score = 2
|
698 |
+
|
699 |
+
noise_score = 0
|
700 |
+
noise_level = quality_metrics.get('noise_level', 0)
|
701 |
+
if noise_level < 0.05:
|
702 |
+
noise_score = 6
|
703 |
+
elif noise_level < 0.1:
|
704 |
+
noise_score = 4
|
705 |
+
else:
|
706 |
+
noise_score = 1
|
707 |
+
|
708 |
+
quality_score = brightness_score + contrast_score + sharpness_score + noise_score
|
709 |
+
|
710 |
+
# Add quality issues to weaknesses
|
711 |
+
for issue in quality_issues:
|
712 |
+
assessment["weaknesses"].append(f"Quality: {issue}")
|
713 |
+
|
714 |
+
# 3. Advanced Object Detection Analysis (0-25 points)
|
715 |
+
object_score = 0
|
716 |
+
object_analysis = object_detection.get('analysis', {})
|
717 |
+
detected_objects = object_detection.get('objects', [])
|
718 |
+
|
719 |
+
# Object richness scoring
|
720 |
+
total_objects = object_analysis.get('total_objects', 0)
|
721 |
+
if total_objects >= 8:
|
722 |
+
object_score += 10
|
723 |
+
assessment["strengths"].append("Rich object content enhances property appeal")
|
724 |
+
elif total_objects >= 5:
|
725 |
+
object_score += 7
|
726 |
+
assessment["strengths"].append("Good object variety")
|
727 |
+
elif total_objects >= 3:
|
728 |
+
object_score += 4
|
729 |
+
else:
|
730 |
+
object_score += 1
|
731 |
+
assessment["weaknesses"].append("Limited object content")
|
732 |
+
|
733 |
+
# Object relevance scoring
|
734 |
+
furniture_count = object_analysis.get('furniture_count', 0)
|
735 |
+
appliance_count = object_analysis.get('appliance_count', 0)
|
736 |
+
fixture_count = object_analysis.get('fixture_count', 0)
|
737 |
+
|
738 |
+
if furniture_count > 0:
|
739 |
+
object_score += 5
|
740 |
+
if appliance_count > 0:
|
741 |
+
object_score += 5
|
742 |
+
if fixture_count > 0:
|
743 |
+
object_score += 5
|
744 |
+
|
745 |
+
# Composition balance
|
746 |
+
composition_balance = object_analysis.get('composition_balance', 0)
|
747 |
+
if composition_balance > 0.6:
|
748 |
+
object_score += 5
|
749 |
+
assessment["strengths"].append("Well-balanced object composition")
|
750 |
+
elif composition_balance < 0.3:
|
751 |
+
object_score -= 3
|
752 |
+
assessment["weaknesses"].append("Poor object distribution")
|
753 |
+
|
754 |
+
# 4. Dynamic Caption Quality Analysis (0-20 points)
|
755 |
+
caption_score = 0
|
756 |
+
caption = image_caption.get('caption', '')
|
757 |
+
|
758 |
+
if caption:
|
759 |
+
# Analyze caption length and content
|
760 |
+
caption_length = len(caption.split())
|
761 |
+
|
762 |
+
# Check for real estate keywords
|
763 |
+
real_estate_keywords = ['room', 'kitchen', 'bathroom', 'bedroom', 'living', 'dining',
|
764 |
+
'modern', 'luxury', 'spacious', 'bright', 'clean', 'furnished']
|
765 |
+
|
766 |
+
keyword_count = sum(1 for keyword in real_estate_keywords if keyword.lower() in caption.lower())
|
767 |
+
|
768 |
+
if caption_length >= 10 and keyword_count >= 3:
|
769 |
+
caption_score = 20
|
770 |
+
assessment["strengths"].append("Comprehensive and relevant caption")
|
771 |
+
elif caption_length >= 8 and keyword_count >= 2:
|
772 |
+
caption_score = 15
|
773 |
+
assessment["strengths"].append("Good descriptive caption")
|
774 |
+
elif caption_length >= 5:
|
775 |
+
caption_score = 10
|
776 |
+
else:
|
777 |
+
caption_score = 5
|
778 |
+
assessment["weaknesses"].append("Limited caption description")
|
779 |
+
else:
|
780 |
+
assessment["weaknesses"].append("No caption generated")
|
781 |
+
|
782 |
+
# 5. Calculate Overall Score with Dynamic Weighting
|
783 |
+
overall_score = room_score + quality_score + object_score + caption_score
|
784 |
+
|
785 |
+
# Normalize to 100-point scale
|
786 |
+
overall_score = min(100, overall_score)
|
787 |
+
|
788 |
+
# 6. Advanced Market Appeal Analysis
|
789 |
+
market_appeal = {}
|
790 |
+
|
791 |
+
# Professional grade determination
|
792 |
+
if overall_score >= 85:
|
793 |
+
assessment["professional_grade"] = True
|
794 |
+
market_appeal["level"] = "Premium"
|
795 |
+
market_appeal["description"] = "Professional-grade image suitable for luxury listings"
|
796 |
+
elif overall_score >= 75:
|
797 |
+
assessment["professional_grade"] = True
|
798 |
+
market_appeal["level"] = "Professional"
|
799 |
+
market_appeal["description"] = "High-quality image for professional listings"
|
800 |
+
elif overall_score >= 60:
|
801 |
+
market_appeal["level"] = "Standard"
|
802 |
+
market_appeal["description"] = "Acceptable quality for standard listings"
|
803 |
+
else:
|
804 |
+
market_appeal["level"] = "Needs Improvement"
|
805 |
+
market_appeal["description"] = "Image requires enhancement before listing"
|
806 |
+
|
807 |
+
# Target audience analysis
|
808 |
+
if room_type in ['kitchen', 'bathroom'] and quality_score > 20:
|
809 |
+
market_appeal["target_audience"] = "Home buyers, Investors"
|
810 |
+
elif room_type in ['bedroom', 'living room'] and object_score > 15:
|
811 |
+
market_appeal["target_audience"] = "Families, Young professionals"
|
812 |
+
else:
|
813 |
+
market_appeal["target_audience"] = "General buyers"
|
814 |
+
|
815 |
+
# 7. Dynamic Recommendations Generation
|
816 |
+
recommendations = []
|
817 |
+
|
818 |
+
# Quality-based recommendations
|
819 |
+
if brightness_mean < 50:
|
820 |
+
recommendations.append("Increase lighting or use HDR techniques")
|
821 |
+
elif brightness_mean > 200:
|
822 |
+
recommendations.append("Reduce exposure to avoid overexposure")
|
823 |
+
|
824 |
+
if contrast < 25:
|
825 |
+
recommendations.append("Enhance contrast in post-processing")
|
826 |
+
|
827 |
+
if sharpness < 50:
|
828 |
+
recommendations.append("Use tripod or image stabilization for sharper photos")
|
829 |
+
|
830 |
+
if noise_level > 0.1:
|
831 |
+
recommendations.append("Use noise reduction software")
|
832 |
+
|
833 |
+
# Object-based recommendations
|
834 |
+
if total_objects < 3:
|
835 |
+
recommendations.append("Include more furniture or decorative elements")
|
836 |
+
|
837 |
+
if composition_balance < 0.4:
|
838 |
+
recommendations.append("Reposition camera for better object distribution")
|
839 |
+
|
840 |
+
# Room-specific recommendations
|
841 |
+
if room_type == 'kitchen' and appliance_count < 2:
|
842 |
+
recommendations.append("Highlight kitchen appliances and features")
|
843 |
+
elif room_type == 'bathroom' and fixture_count < 2:
|
844 |
+
recommendations.append("Showcase bathroom fixtures and amenities")
|
845 |
+
|
846 |
+
# Technical recommendations
|
847 |
+
if not assessment["professional_grade"]:
|
848 |
+
recommendations.append("Consider professional photography services")
|
849 |
+
|
850 |
+
assessment["recommendations"] = recommendations
|
851 |
+
assessment["overall_score"] = overall_score
|
852 |
+
assessment["market_appeal"] = market_appeal
|
853 |
+
|
854 |
+
# 8. Technical Analysis Summary
|
855 |
+
assessment["technical_analysis"] = {
|
856 |
+
"room_classification_score": room_score,
|
857 |
+
"quality_analysis_score": quality_score,
|
858 |
+
"object_detection_score": object_score,
|
859 |
+
"caption_quality_score": caption_score,
|
860 |
+
"composition_balance": composition_balance,
|
861 |
+
"object_density": object_analysis.get('object_density', 0),
|
862 |
+
"quality_metrics_summary": {
|
863 |
+
"brightness": round(brightness_mean, 1),
|
864 |
+
"contrast": round(contrast, 1),
|
865 |
+
"sharpness": round(sharpness, 1),
|
866 |
+
"noise_level": round(noise_level, 3)
|
867 |
+
}
|
868 |
+
}
|
869 |
+
|
870 |
+
return assessment
|
871 |
+
|
872 |
+
except Exception as e:
|
873 |
+
logger.error(f"Error in property assessment: {str(e)}")
|
874 |
+
return {
|
875 |
+
"overall_score": 0,
|
876 |
+
"strengths": [],
|
877 |
+
"weaknesses": ["Assessment failed due to technical error"],
|
878 |
+
"recommendations": ["Please try again with a different image"],
|
879 |
+
"market_appeal": {"level": "Unknown", "description": "Unable to assess"},
|
880 |
+
"professional_grade": False,
|
881 |
+
"technical_analysis": {}
|
882 |
+
}
|
883 |
+
|
884 |
+
def estimate_room_size(image, room_type='unknown'):
|
885 |
+
"""Advanced AI-powered room size estimation using multiple analysis methods"""
|
886 |
+
try:
|
887 |
+
# Convert PIL image to numpy array
|
888 |
+
img_array = np.array(image)
|
889 |
+
|
890 |
+
# Get image dimensions
|
891 |
+
height, width = img_array.shape[:2]
|
892 |
+
image_area = height * width
|
893 |
+
|
894 |
+
# 1. Object-based size estimation
|
895 |
+
object_analysis = detect_objects_advanced(image)
|
896 |
+
detected_objects = object_analysis.get('objects', [])
|
897 |
+
object_analysis_data = object_analysis.get('analysis', {})
|
898 |
+
|
899 |
+
# Categorize objects by typical sizes
|
900 |
+
large_furniture = [obj for obj in detected_objects
|
901 |
+
if obj['label'].lower() in ['bed', 'sofa', 'couch', 'dining table', 'kitchen island']]
|
902 |
+
medium_furniture = [obj for obj in detected_objects
|
903 |
+
if obj['label'].lower() in ['chair', 'desk', 'cabinet', 'dresser', 'nightstand']]
|
904 |
+
small_furniture = [obj for obj in detected_objects
|
905 |
+
if obj['label'].lower() in ['lamp', 'plant', 'vase', 'picture frame']]
|
906 |
+
|
907 |
+
# 2. Object density analysis
|
908 |
+
total_objects = len(detected_objects)
|
909 |
+
object_density = object_analysis_data.get('object_density', 0)
|
910 |
+
|
911 |
+
# 3. Perspective and depth analysis
|
912 |
+
# Analyze object positioning for depth perception
|
913 |
+
if detected_objects:
|
914 |
+
# Calculate object distribution across image
|
915 |
+
x_positions = []
|
916 |
+
y_positions = []
|
917 |
+
object_sizes = []
|
918 |
+
|
919 |
+
for obj in detected_objects:
|
920 |
+
bbox = obj['bbox']
|
921 |
+
x_center = (bbox[0] + bbox[2]) / 2
|
922 |
+
y_center = (bbox[1] + bbox[3]) / 2
|
923 |
+
obj_width = bbox[2] - bbox[0]
|
924 |
+
obj_height = bbox[3] - bbox[1]
|
925 |
+
obj_area = obj_width * obj_height
|
926 |
+
|
927 |
+
x_positions.append(x_center)
|
928 |
+
y_positions.append(y_center)
|
929 |
+
object_sizes.append(obj_area)
|
930 |
+
|
931 |
+
# Calculate spatial distribution
|
932 |
+
x_variance = float(np.var(x_positions)) if len(x_positions) > 1 else 0.0
|
933 |
+
y_variance = float(np.var(y_positions)) if len(y_positions) > 1 else 0.0
|
934 |
+
avg_object_size = float(np.mean(object_sizes)) if object_sizes else 0.0
|
935 |
+
|
936 |
+
# Depth perception indicators
|
937 |
+
size_variance = float(np.var(object_sizes)) if len(object_sizes) > 1 else 0.0
|
938 |
+
depth_indicator = float(size_variance / (avg_object_size + 1e-8))
|
939 |
+
else:
|
940 |
+
x_variance = y_variance = avg_object_size = depth_indicator = 0.0
|
941 |
+
|
942 |
+
# 4. Advanced size estimation algorithm
|
943 |
+
size_score = 0
|
944 |
+
size_factors = {}
|
945 |
+
|
946 |
+
# Object count factor (0-30 points)
|
947 |
+
if total_objects >= 10:
|
948 |
+
size_score += 30
|
949 |
+
size_factors["object_count"] = "Very High"
|
950 |
+
elif total_objects >= 7:
|
951 |
+
size_score += 25
|
952 |
+
size_factors["object_count"] = "High"
|
953 |
+
elif total_objects >= 5:
|
954 |
+
size_score += 20
|
955 |
+
size_factors["object_count"] = "Medium-High"
|
956 |
+
elif total_objects >= 3:
|
957 |
+
size_score += 15
|
958 |
+
size_factors["object_count"] = "Medium"
|
959 |
+
elif total_objects >= 1:
|
960 |
+
size_score += 10
|
961 |
+
size_factors["object_count"] = "Low"
|
962 |
+
else:
|
963 |
+
size_factors["object_count"] = "Very Low"
|
964 |
+
|
965 |
+
# Furniture type factor (0-25 points)
|
966 |
+
furniture_score = 0
|
967 |
+
if len(large_furniture) >= 3:
|
968 |
+
furniture_score = 25
|
969 |
+
size_factors["furniture_type"] = "Multiple large pieces"
|
970 |
+
elif len(large_furniture) >= 2:
|
971 |
+
furniture_score = 20
|
972 |
+
size_factors["furniture_type"] = "Several large pieces"
|
973 |
+
elif len(large_furniture) >= 1:
|
974 |
+
furniture_score = 15
|
975 |
+
size_factors["furniture_type"] = "Some large pieces"
|
976 |
+
elif len(medium_furniture) >= 3:
|
977 |
+
furniture_score = 12
|
978 |
+
size_factors["furniture_type"] = "Multiple medium pieces"
|
979 |
+
elif len(medium_furniture) >= 1:
|
980 |
+
furniture_score = 8
|
981 |
+
size_factors["furniture_type"] = "Some medium pieces"
|
982 |
+
else:
|
983 |
+
furniture_score = 5
|
984 |
+
size_factors["furniture_type"] = "Small pieces only"
|
985 |
+
|
986 |
+
size_score += furniture_score
|
987 |
+
|
988 |
+
# Object density factor (0-20 points)
|
989 |
+
if object_density > 15:
|
990 |
+
size_score += 20
|
991 |
+
size_factors["object_density"] = "Very High"
|
992 |
+
elif object_density > 10:
|
993 |
+
size_score += 15
|
994 |
+
size_factors["object_density"] = "High"
|
995 |
+
elif object_density > 5:
|
996 |
+
size_score += 10
|
997 |
+
size_factors["object_density"] = "Medium"
|
998 |
+
elif object_density > 2:
|
999 |
+
size_score += 5
|
1000 |
+
size_factors["object_density"] = "Low"
|
1001 |
+
else:
|
1002 |
+
size_factors["object_density"] = "Very Low"
|
1003 |
+
|
1004 |
+
# Spatial distribution factor (0-15 points)
|
1005 |
+
spatial_score = 0
|
1006 |
+
if x_variance > 10000 and y_variance > 10000:
|
1007 |
+
spatial_score = 15
|
1008 |
+
size_factors["spatial_distribution"] = "Wide spread"
|
1009 |
+
elif x_variance > 5000 or y_variance > 5000:
|
1010 |
+
spatial_score = 10
|
1011 |
+
size_factors["spatial_distribution"] = "Moderate spread"
|
1012 |
+
elif x_variance > 1000 or y_variance > 1000:
|
1013 |
+
spatial_score = 5
|
1014 |
+
size_factors["spatial_distribution"] = "Limited spread"
|
1015 |
+
else:
|
1016 |
+
size_factors["spatial_distribution"] = "Concentrated"
|
1017 |
+
|
1018 |
+
size_score += spatial_score
|
1019 |
+
|
1020 |
+
# Depth perception factor (0-10 points)
|
1021 |
+
if depth_indicator > 0.5:
|
1022 |
+
size_score += 10
|
1023 |
+
size_factors["depth_perception"] = "Strong depth"
|
1024 |
+
elif depth_indicator > 0.2:
|
1025 |
+
size_score += 7
|
1026 |
+
size_factors["depth_perception"] = "Moderate depth"
|
1027 |
+
elif depth_indicator > 0.1:
|
1028 |
+
size_score += 4
|
1029 |
+
size_factors["depth_perception"] = "Limited depth"
|
1030 |
+
else:
|
1031 |
+
size_factors["depth_perception"] = "Flat perspective"
|
1032 |
+
|
1033 |
+
# 5. Dynamic size classification
|
1034 |
+
if size_score >= 80:
|
1035 |
+
estimated_size = "Very Large (300+ sq ft)"
|
1036 |
+
size_category = "XL"
|
1037 |
+
confidence = "High"
|
1038 |
+
elif size_score >= 65:
|
1039 |
+
estimated_size = "Large (200-300 sq ft)"
|
1040 |
+
size_category = "L"
|
1041 |
+
confidence = "High"
|
1042 |
+
elif size_score >= 50:
|
1043 |
+
estimated_size = "Medium-Large (150-200 sq ft)"
|
1044 |
+
size_category = "ML"
|
1045 |
+
confidence = "Medium"
|
1046 |
+
elif size_score >= 35:
|
1047 |
+
estimated_size = "Medium (100-150 sq ft)"
|
1048 |
+
size_category = "M"
|
1049 |
+
confidence = "Medium"
|
1050 |
+
elif size_score >= 20:
|
1051 |
+
estimated_size = "Small-Medium (80-100 sq ft)"
|
1052 |
+
size_category = "SM"
|
1053 |
+
confidence = "Medium"
|
1054 |
+
elif size_score >= 10:
|
1055 |
+
estimated_size = "Small (50-80 sq ft)"
|
1056 |
+
size_category = "S"
|
1057 |
+
confidence = "Low"
|
1058 |
+
else:
|
1059 |
+
estimated_size = "Very Small (<50 sq ft)"
|
1060 |
+
size_category = "XS"
|
1061 |
+
confidence = "Low"
|
1062 |
+
|
1063 |
+
# 6. Room type specific adjustments
|
1064 |
+
# Use the room_type parameter passed to the function
|
1065 |
+
|
1066 |
+
# Adjust size based on room type expectations
|
1067 |
+
if room_type == 'kitchen':
|
1068 |
+
if size_category in ['XS', 'S']:
|
1069 |
+
estimated_size = "Compact Kitchen (50-80 sq ft)"
|
1070 |
+
elif size_category in ['M', 'ML']:
|
1071 |
+
estimated_size = "Standard Kitchen (100-150 sq ft)"
|
1072 |
+
else:
|
1073 |
+
estimated_size = "Large Kitchen (150+ sq ft)"
|
1074 |
+
elif room_type == 'bathroom':
|
1075 |
+
if size_category in ['XS', 'S']:
|
1076 |
+
estimated_size = "Standard Bathroom (40-60 sq ft)"
|
1077 |
+
elif size_category in ['M', 'ML']:
|
1078 |
+
estimated_size = "Large Bathroom (60-100 sq ft)"
|
1079 |
+
else:
|
1080 |
+
estimated_size = "Luxury Bathroom (100+ sq ft)"
|
1081 |
+
elif room_type == 'bedroom':
|
1082 |
+
if size_category in ['XS', 'S']:
|
1083 |
+
estimated_size = "Small Bedroom (80-120 sq ft)"
|
1084 |
+
elif size_category in ['M', 'ML']:
|
1085 |
+
estimated_size = "Standard Bedroom (120-180 sq ft)"
|
1086 |
+
else:
|
1087 |
+
estimated_size = "Large Bedroom (180+ sq ft)"
|
1088 |
+
|
1089 |
+
# 7. Confidence calculation
|
1090 |
+
confidence_factors = []
|
1091 |
+
if total_objects >= 5:
|
1092 |
+
confidence_factors.append("Multiple objects detected")
|
1093 |
+
if len(large_furniture) >= 1:
|
1094 |
+
confidence_factors.append("Large furniture present")
|
1095 |
+
if object_density > 5:
|
1096 |
+
confidence_factors.append("Good object density")
|
1097 |
+
if x_variance > 5000 and y_variance > 5000:
|
1098 |
+
confidence_factors.append("Good spatial distribution")
|
1099 |
+
|
1100 |
+
if len(confidence_factors) >= 3:
|
1101 |
+
confidence = "High"
|
1102 |
+
elif len(confidence_factors) >= 2:
|
1103 |
+
confidence = "Medium"
|
1104 |
+
else:
|
1105 |
+
confidence = "Low"
|
1106 |
+
|
1107 |
+
return {
|
1108 |
+
"estimated_size": estimated_size,
|
1109 |
+
"size_category": size_category,
|
1110 |
+
"confidence": confidence,
|
1111 |
+
"confidence_factors": confidence_factors,
|
1112 |
+
"size_score": int(size_score), # Convert to Python int
|
1113 |
+
"size_factors": size_factors,
|
1114 |
+
"object_analysis": {
|
1115 |
+
"total_objects": int(total_objects), # Convert to Python int
|
1116 |
+
"large_furniture": int(len(large_furniture)), # Convert to Python int
|
1117 |
+
"medium_furniture": int(len(medium_furniture)), # Convert to Python int
|
1118 |
+
"small_furniture": int(len(small_furniture)), # Convert to Python int
|
1119 |
+
"object_density": float(round(object_density, 2)), # Convert to Python float
|
1120 |
+
"spatial_variance": {
|
1121 |
+
"x_variance": float(round(x_variance, 2)), # Convert to Python float
|
1122 |
+
"y_variance": float(round(y_variance, 2)) # Convert to Python float
|
1123 |
+
},
|
1124 |
+
"depth_indicator": float(round(depth_indicator, 3)) # Convert to Python float
|
1125 |
+
}
|
1126 |
+
}
|
1127 |
+
|
1128 |
+
except Exception as e:
|
1129 |
+
logger.error(f"Error in room size estimation: {str(e)}")
|
1130 |
+
return {
|
1131 |
+
"estimated_size": "Unable to estimate",
|
1132 |
+
"size_category": "Unknown",
|
1133 |
+
"confidence": "Low",
|
1134 |
+
"confidence_factors": ["Estimation failed"],
|
1135 |
+
"size_score": 0,
|
1136 |
+
"size_factors": {},
|
1137 |
+
"object_analysis": {
|
1138 |
+
"total_objects": 0,
|
1139 |
+
"large_furniture": 0,
|
1140 |
+
"medium_furniture": 0,
|
1141 |
+
"small_furniture": 0,
|
1142 |
+
"object_density": 0.0,
|
1143 |
+
"spatial_variance": {"x_variance": 0.0, "y_variance": 0.0},
|
1144 |
+
"depth_indicator": 0.0
|
1145 |
+
}
|
1146 |
+
}
|
1147 |
+
|
1148 |
+
def generate_property_insights(room_classification, quality_analysis, object_detection, image_caption):
|
1149 |
+
"""Advanced AI-powered property insights generation using dynamic analysis"""
|
1150 |
+
try:
|
1151 |
+
insights = {
|
1152 |
+
"marketing_tips": [],
|
1153 |
+
"target_audience": [],
|
1154 |
+
"pricing_considerations": [],
|
1155 |
+
"improvement_suggestions": [],
|
1156 |
+
"market_positioning": {},
|
1157 |
+
"competitive_analysis": {},
|
1158 |
+
"investment_potential": {},
|
1159 |
+
"staging_recommendations": []
|
1160 |
+
}
|
1161 |
+
|
1162 |
+
# Extract key data
|
1163 |
+
room_type = room_classification.get('room_type', 'unknown')
|
1164 |
+
room_confidence = room_classification.get('confidence', 0)
|
1165 |
+
quality_score = quality_analysis.get('quality_score', 0)
|
1166 |
+
quality_level = quality_analysis.get('quality_level', 'Unknown')
|
1167 |
+
object_analysis = object_detection.get('analysis', {})
|
1168 |
+
detected_objects = object_detection.get('objects', [])
|
1169 |
+
caption = image_caption.get('caption', '')
|
1170 |
+
|
1171 |
+
# 1. Dynamic Marketing Tips Generation
|
1172 |
+
marketing_tips = []
|
1173 |
+
|
1174 |
+
# Quality-based marketing tips
|
1175 |
+
if quality_score >= 80:
|
1176 |
+
marketing_tips.append("Highlight the professional photography quality in listings")
|
1177 |
+
marketing_tips.append("Use this image as a primary showcase photo")
|
1178 |
+
elif quality_score >= 60:
|
1179 |
+
marketing_tips.append("Consider this image for secondary photo positions")
|
1180 |
+
else:
|
1181 |
+
marketing_tips.append("Use this image sparingly or improve before listing")
|
1182 |
+
|
1183 |
+
# Room-specific marketing tips
|
1184 |
+
if room_type == 'kitchen':
|
1185 |
+
marketing_tips.append("Emphasize modern kitchen features and appliances")
|
1186 |
+
marketing_tips.append("Highlight the kitchen as the heart of the home")
|
1187 |
+
if object_analysis.get('appliance_count', 0) >= 3:
|
1188 |
+
marketing_tips.append("Showcase the fully equipped kitchen")
|
1189 |
+
elif room_type == 'bathroom':
|
1190 |
+
marketing_tips.append("Focus on cleanliness and modern fixtures")
|
1191 |
+
marketing_tips.append("Highlight bathroom luxury and comfort")
|
1192 |
+
elif room_type == 'bedroom':
|
1193 |
+
marketing_tips.append("Emphasize comfort and relaxation potential")
|
1194 |
+
marketing_tips.append("Highlight bedroom size and natural light")
|
1195 |
+
elif room_type == 'living room':
|
1196 |
+
marketing_tips.append("Showcase entertainment and family gathering spaces")
|
1197 |
+
marketing_tips.append("Highlight living room versatility and flow")
|
1198 |
+
|
1199 |
+
# Object-based marketing tips
|
1200 |
+
furniture_count = object_analysis.get('furniture_count', 0)
|
1201 |
+
if furniture_count >= 5:
|
1202 |
+
marketing_tips.append("Emphasize the fully furnished and move-in ready aspect")
|
1203 |
+
elif furniture_count >= 3:
|
1204 |
+
marketing_tips.append("Highlight the well-appointed space")
|
1205 |
+
|
1206 |
+
# 2. Advanced Target Audience Analysis
|
1207 |
+
target_audience = []
|
1208 |
+
|
1209 |
+
# Room type based targeting
|
1210 |
+
if room_type == 'kitchen':
|
1211 |
+
target_audience.extend(["Home chefs", "Families", "Entertainment enthusiasts"])
|
1212 |
+
elif room_type == 'bathroom':
|
1213 |
+
target_audience.extend(["Luxury seekers", "Families", "Young professionals"])
|
1214 |
+
elif room_type == 'bedroom':
|
1215 |
+
target_audience.extend(["Families", "Young professionals", "Students"])
|
1216 |
+
elif room_type == 'living room':
|
1217 |
+
target_audience.extend(["Families", "Entertainment lovers", "Social people"])
|
1218 |
+
|
1219 |
+
# Quality-based targeting
|
1220 |
+
if quality_score >= 85:
|
1221 |
+
target_audience.append("Luxury buyers")
|
1222 |
+
elif quality_score >= 70:
|
1223 |
+
target_audience.append("Professional buyers")
|
1224 |
+
else:
|
1225 |
+
target_audience.append("Budget-conscious buyers")
|
1226 |
+
|
1227 |
+
# Object-based targeting
|
1228 |
+
if object_analysis.get('appliance_count', 0) >= 3:
|
1229 |
+
target_audience.append("Modern lifestyle seekers")
|
1230 |
+
|
1231 |
+
if object_analysis.get('fixture_count', 0) >= 3:
|
1232 |
+
target_audience.append("Quality-conscious buyers")
|
1233 |
+
|
1234 |
+
# 3. Dynamic Pricing Considerations
|
1235 |
+
pricing_considerations = []
|
1236 |
+
|
1237 |
+
# Quality impact on pricing
|
1238 |
+
if quality_score >= 80:
|
1239 |
+
pricing_considerations.append("High-quality images can support premium pricing")
|
1240 |
+
elif quality_score >= 60:
|
1241 |
+
pricing_considerations.append("Standard image quality supports market-rate pricing")
|
1242 |
+
else:
|
1243 |
+
pricing_considerations.append("Image quality may limit pricing potential")
|
1244 |
+
|
1245 |
+
# Room type pricing impact
|
1246 |
+
if room_type == 'kitchen':
|
1247 |
+
pricing_considerations.append("Kitchen quality significantly impacts property value")
|
1248 |
+
if object_analysis.get('appliance_count', 0) >= 3:
|
1249 |
+
pricing_considerations.append("Modern appliances justify higher pricing")
|
1250 |
+
elif room_type == 'bathroom':
|
1251 |
+
pricing_considerations.append("Bathroom luxury can command premium pricing")
|
1252 |
+
elif room_type == 'bedroom':
|
1253 |
+
pricing_considerations.append("Bedroom appeal affects family buyer pricing")
|
1254 |
+
|
1255 |
+
# Object density pricing impact
|
1256 |
+
object_density = object_analysis.get('object_density', 0)
|
1257 |
+
if object_density > 10:
|
1258 |
+
pricing_considerations.append("Rich content suggests well-appointed property")
|
1259 |
+
elif object_density < 3:
|
1260 |
+
pricing_considerations.append("Sparse content may suggest staging needed")
|
1261 |
+
|
1262 |
+
# 4. AI-Powered Improvement Suggestions
|
1263 |
+
improvement_suggestions = []
|
1264 |
+
|
1265 |
+
# Technical improvements
|
1266 |
+
if quality_score < 70:
|
1267 |
+
improvement_suggestions.append("Improve lighting and exposure for better image quality")
|
1268 |
+
improvement_suggestions.append("Use professional photography equipment")
|
1269 |
+
|
1270 |
+
# Composition improvements
|
1271 |
+
composition_balance = object_analysis.get('composition_balance', 0)
|
1272 |
+
if composition_balance < 0.4:
|
1273 |
+
improvement_suggestions.append("Reposition camera for better composition")
|
1274 |
+
improvement_suggestions.append("Follow rule of thirds for better framing")
|
1275 |
+
|
1276 |
+
# Content improvements
|
1277 |
+
total_objects = object_analysis.get('total_objects', 0)
|
1278 |
+
if total_objects < 3:
|
1279 |
+
improvement_suggestions.append("Add more furniture or decorative elements")
|
1280 |
+
improvement_suggestions.append("Consider professional staging")
|
1281 |
+
|
1282 |
+
# Room-specific improvements
|
1283 |
+
if room_type == 'kitchen' and object_analysis.get('appliance_count', 0) < 2:
|
1284 |
+
improvement_suggestions.append("Highlight kitchen appliances and features")
|
1285 |
+
elif room_type == 'bathroom' and object_analysis.get('fixture_count', 0) < 2:
|
1286 |
+
improvement_suggestions.append("Showcase bathroom fixtures and amenities")
|
1287 |
+
|
1288 |
+
# 5. Advanced Market Positioning Analysis
|
1289 |
+
market_positioning = {}
|
1290 |
+
|
1291 |
+
# Quality positioning
|
1292 |
+
if quality_score >= 85:
|
1293 |
+
market_positioning["quality_tier"] = "Premium"
|
1294 |
+
market_positioning["positioning_statement"] = "Luxury property with professional presentation"
|
1295 |
+
elif quality_score >= 70:
|
1296 |
+
market_positioning["quality_tier"] = "Professional"
|
1297 |
+
market_positioning["positioning_statement"] = "Well-presented property suitable for discerning buyers"
|
1298 |
+
elif quality_score >= 50:
|
1299 |
+
market_positioning["quality_tier"] = "Standard"
|
1300 |
+
market_positioning["positioning_statement"] = "Standard property presentation"
|
1301 |
+
else:
|
1302 |
+
market_positioning["quality_tier"] = "Needs Improvement"
|
1303 |
+
market_positioning["positioning_statement"] = "Property requires better presentation"
|
1304 |
+
|
1305 |
+
# Room type positioning
|
1306 |
+
if room_type in ['kitchen', 'bathroom']:
|
1307 |
+
market_positioning["focus_area"] = "High-value rooms"
|
1308 |
+
market_positioning["key_message"] = f"Showcase {room_type} quality and features"
|
1309 |
+
else:
|
1310 |
+
market_positioning["focus_area"] = "Living spaces"
|
1311 |
+
market_positioning["key_message"] = f"Highlight {room_type} comfort and functionality"
|
1312 |
+
|
1313 |
+
# 6. Competitive Analysis
|
1314 |
+
competitive_analysis = {}
|
1315 |
+
|
1316 |
+
# Quality comparison
|
1317 |
+
if quality_score >= 80:
|
1318 |
+
competitive_analysis["quality_advantage"] = "Above average"
|
1319 |
+
competitive_analysis["differentiation"] = "Professional presentation sets property apart"
|
1320 |
+
elif quality_score >= 60:
|
1321 |
+
competitive_analysis["quality_advantage"] = "Competitive"
|
1322 |
+
competitive_analysis["differentiation"] = "Standard presentation meets market expectations"
|
1323 |
+
else:
|
1324 |
+
competitive_analysis["quality_advantage"] = "Below average"
|
1325 |
+
competitive_analysis["differentiation"] = "Needs improvement to compete effectively"
|
1326 |
+
|
1327 |
+
# Content comparison
|
1328 |
+
if object_analysis.get('total_objects', 0) >= 8:
|
1329 |
+
competitive_analysis["content_advantage"] = "Rich content"
|
1330 |
+
competitive_analysis["content_message"] = "Well-appointed space with many features"
|
1331 |
+
elif object_analysis.get('total_objects', 0) >= 5:
|
1332 |
+
competitive_analysis["content_advantage"] = "Good content"
|
1333 |
+
competitive_analysis["content_message"] = "Adequate feature representation"
|
1334 |
+
else:
|
1335 |
+
competitive_analysis["content_advantage"] = "Limited content"
|
1336 |
+
competitive_analysis["content_message"] = "Consider adding more features"
|
1337 |
+
|
1338 |
+
# 7. Investment Potential Analysis
|
1339 |
+
investment_potential = {}
|
1340 |
+
|
1341 |
+
# Quality impact on investment
|
1342 |
+
if quality_score >= 80:
|
1343 |
+
investment_potential["presentation_value"] = "High"
|
1344 |
+
investment_potential["roi_potential"] = "Excellent - professional presentation supports premium pricing"
|
1345 |
+
elif quality_score >= 60:
|
1346 |
+
investment_potential["presentation_value"] = "Medium"
|
1347 |
+
investment_potential["roi_potential"] = "Good - standard presentation supports market pricing"
|
1348 |
+
else:
|
1349 |
+
investment_potential["presentation_value"] = "Low"
|
1350 |
+
investment_potential["roi_potential"] = "Limited - poor presentation may reduce pricing potential"
|
1351 |
+
|
1352 |
+
# Room type investment impact
|
1353 |
+
if room_type in ['kitchen', 'bathroom']:
|
1354 |
+
investment_potential["room_value"] = "High-impact rooms"
|
1355 |
+
investment_potential["investment_priority"] = "Focus on these rooms for maximum ROI"
|
1356 |
+
else:
|
1357 |
+
investment_potential["room_value"] = "Standard rooms"
|
1358 |
+
investment_potential["investment_priority"] = "Ensure adequate presentation quality"
|
1359 |
+
|
1360 |
+
# 8. Dynamic Staging Recommendations
|
1361 |
+
staging_recommendations = []
|
1362 |
+
|
1363 |
+
# Object-based staging
|
1364 |
+
if object_analysis.get('furniture_count', 0) < 2:
|
1365 |
+
staging_recommendations.append("Add key furniture pieces to define the space")
|
1366 |
+
|
1367 |
+
if object_analysis.get('appliance_count', 0) < 2 and room_type == 'kitchen':
|
1368 |
+
staging_recommendations.append("Highlight kitchen appliances and modern features")
|
1369 |
+
|
1370 |
+
if object_analysis.get('fixture_count', 0) < 2 and room_type == 'bathroom':
|
1371 |
+
staging_recommendations.append("Showcase bathroom fixtures and luxury amenities")
|
1372 |
+
|
1373 |
+
# Quality-based staging
|
1374 |
+
if quality_score < 60:
|
1375 |
+
staging_recommendations.append("Improve lighting and staging for better presentation")
|
1376 |
+
|
1377 |
+
# Room-specific staging
|
1378 |
+
if room_type == 'bedroom':
|
1379 |
+
staging_recommendations.append("Create a welcoming and comfortable bedroom atmosphere")
|
1380 |
+
elif room_type == 'living room':
|
1381 |
+
staging_recommendations.append("Stage for entertainment and family gatherings")
|
1382 |
+
|
1383 |
+
# Update insights dictionary
|
1384 |
+
insights.update({
|
1385 |
+
"marketing_tips": marketing_tips,
|
1386 |
+
"target_audience": list(set(target_audience)), # Remove duplicates
|
1387 |
+
"pricing_considerations": pricing_considerations,
|
1388 |
+
"improvement_suggestions": improvement_suggestions,
|
1389 |
+
"market_positioning": market_positioning,
|
1390 |
+
"competitive_analysis": competitive_analysis,
|
1391 |
+
"investment_potential": investment_potential,
|
1392 |
+
"staging_recommendations": staging_recommendations
|
1393 |
+
})
|
1394 |
+
|
1395 |
+
return insights
|
1396 |
+
|
1397 |
+
except Exception as e:
|
1398 |
+
logger.error(f"Error in generating property insights: {str(e)}")
|
1399 |
+
return {
|
1400 |
+
"marketing_tips": ["Unable to generate marketing tips"],
|
1401 |
+
"target_audience": ["General buyers"],
|
1402 |
+
"pricing_considerations": ["Standard market pricing"],
|
1403 |
+
"improvement_suggestions": ["Improve image quality and content"],
|
1404 |
+
"market_positioning": {"quality_tier": "Unknown"},
|
1405 |
+
"competitive_analysis": {"quality_advantage": "Unknown"},
|
1406 |
+
"investment_potential": {"presentation_value": "Unknown"},
|
1407 |
+
"staging_recommendations": ["Consider professional staging"]
|
1408 |
+
}
|
1409 |
+
|
1410 |
+
def analyze_scene_with_clip(image, room_type):
|
1411 |
+
"""Advanced scene understanding using CLIP model"""
|
1412 |
+
try:
|
1413 |
+
if not clip_processor or not clip_model:
|
1414 |
+
return {'scene_concepts': [], 'style_analysis': {}}
|
1415 |
+
|
1416 |
+
# Define comprehensive real estate concepts
|
1417 |
+
real_estate_concepts = [
|
1418 |
+
# Style concepts
|
1419 |
+
"modern design", "traditional style", "contemporary", "luxury", "minimalist", "rustic", "industrial",
|
1420 |
+
"scandinavian", "mediterranean", "asian fusion", "art deco", "mid-century modern",
|
1421 |
+
|
1422 |
+
# Quality indicators
|
1423 |
+
"high-end finishes", "premium materials", "custom details", "architectural features",
|
1424 |
+
"natural light", "open floor plan", "high ceilings", "hardwood floors", "granite countertops",
|
1425 |
+
|
1426 |
+
# Functionality
|
1427 |
+
"functional layout", "efficient design", "storage solutions", "entertainment space",
|
1428 |
+
"home office", "flexible space", "outdoor living", "smart home features",
|
1429 |
+
|
1430 |
+
# Room-specific concepts
|
1431 |
+
"gourmet kitchen", "spa-like bathroom", "master suite", "entertainment room",
|
1432 |
+
"dining area", "living space", "bedroom retreat", "home gym", "wine cellar"
|
1433 |
+
]
|
1434 |
+
|
1435 |
+
# Process image and text
|
1436 |
+
inputs = clip_processor(images=image, text=real_estate_concepts, return_tensors="pt", padding=True)
|
1437 |
+
|
1438 |
+
with torch.no_grad():
|
1439 |
+
outputs = clip_model(**inputs)
|
1440 |
+
logits_per_image = outputs.logits_per_image
|
1441 |
+
probs = logits_per_image.softmax(dim=-1)
|
1442 |
+
|
1443 |
+
# Get top matches
|
1444 |
+
top_concepts = []
|
1445 |
+
for i, prob in enumerate(probs[0]):
|
1446 |
+
if prob > 0.2: # Lower threshold for more concepts
|
1447 |
+
top_concepts.append({
|
1448 |
+
"concept": real_estate_concepts[i],
|
1449 |
+
"confidence": float(prob)
|
1450 |
+
})
|
1451 |
+
|
1452 |
+
# Analyze style patterns
|
1453 |
+
style_keywords = ["modern", "traditional", "contemporary", "luxury", "minimalist", "rustic", "industrial"]
|
1454 |
+
style_scores = {}
|
1455 |
+
|
1456 |
+
for style in style_keywords:
|
1457 |
+
style_score = sum(concept["confidence"] for concept in top_concepts if style in concept["concept"].lower())
|
1458 |
+
if style_score > 0:
|
1459 |
+
style_scores[style] = style_score
|
1460 |
+
|
1461 |
+
# Determine dominant style
|
1462 |
+
dominant_style = max(style_scores.items(), key=lambda x: x[1]) if style_scores else ("unknown", 0)
|
1463 |
+
|
1464 |
+
return {
|
1465 |
+
"scene_concepts": sorted(top_concepts, key=lambda x: x["confidence"], reverse=True)[:10],
|
1466 |
+
"style_analysis": {
|
1467 |
+
"dominant_style": dominant_style[0],
|
1468 |
+
"style_confidence": dominant_style[1],
|
1469 |
+
"all_style_scores": style_scores,
|
1470 |
+
"quality_indicators": [concept for concept in top_concepts if "quality" in concept["concept"].lower() or "premium" in concept["concept"].lower()],
|
1471 |
+
"functionality_indicators": [concept for concept in top_concepts if "functional" in concept["concept"].lower() or "efficient" in concept["concept"].lower()]
|
1472 |
+
}
|
1473 |
+
}
|
1474 |
+
|
1475 |
+
except Exception as e:
|
1476 |
+
logger.error(f"CLIP scene analysis failed: {str(e)}")
|
1477 |
+
return {'scene_concepts': [], 'style_analysis': {}}
|
1478 |
+
|
1479 |
+
def analyze_market_positioning(room_classification, quality_analysis, object_detection, property_assessment):
|
1480 |
+
"""Advanced market positioning analysis"""
|
1481 |
+
try:
|
1482 |
+
market_analysis = {
|
1483 |
+
"market_tier": "Unknown",
|
1484 |
+
"competitive_position": "Unknown",
|
1485 |
+
"price_positioning": "Unknown",
|
1486 |
+
"target_market": "Unknown",
|
1487 |
+
"differentiation_factors": [],
|
1488 |
+
"market_opportunities": [],
|
1489 |
+
"competitive_advantages": [],
|
1490 |
+
"market_risks": []
|
1491 |
+
}
|
1492 |
+
|
1493 |
+
# Extract key metrics
|
1494 |
+
quality_score = quality_analysis.get('quality_score', 0)
|
1495 |
+
overall_score = property_assessment.get('overall_score', 0)
|
1496 |
+
room_type = room_classification.get('room_type', 'unknown')
|
1497 |
+
room_confidence = room_classification.get('confidence', 0)
|
1498 |
+
object_analysis = object_detection.get('analysis', {})
|
1499 |
+
|
1500 |
+
# 1. Market Tier Analysis
|
1501 |
+
if overall_score >= 85:
|
1502 |
+
market_analysis["market_tier"] = "Luxury"
|
1503 |
+
market_analysis["price_positioning"] = "Premium"
|
1504 |
+
market_analysis["target_market"] = "High-end buyers, investors"
|
1505 |
+
elif overall_score >= 75:
|
1506 |
+
market_analysis["market_tier"] = "Premium"
|
1507 |
+
market_analysis["price_positioning"] = "Above market"
|
1508 |
+
market_analysis["target_market"] = "Professional buyers, families"
|
1509 |
+
elif overall_score >= 60:
|
1510 |
+
market_analysis["market_tier"] = "Standard"
|
1511 |
+
market_analysis["price_positioning"] = "Market rate"
|
1512 |
+
market_analysis["target_market"] = "General buyers"
|
1513 |
+
else:
|
1514 |
+
market_analysis["market_tier"] = "Value"
|
1515 |
+
market_analysis["price_positioning"] = "Below market"
|
1516 |
+
market_analysis["target_market"] = "Budget-conscious buyers"
|
1517 |
+
|
1518 |
+
# 2. Competitive Position Analysis
|
1519 |
+
if quality_score >= 80 and room_confidence >= 80:
|
1520 |
+
market_analysis["competitive_position"] = "Strong"
|
1521 |
+
market_analysis["competitive_advantages"].append("High-quality presentation")
|
1522 |
+
market_analysis["competitive_advantages"].append("Clear room identification")
|
1523 |
+
elif quality_score >= 60 and room_confidence >= 60:
|
1524 |
+
market_analysis["competitive_position"] = "Competitive"
|
1525 |
+
market_analysis["competitive_advantages"].append("Good presentation quality")
|
1526 |
+
else:
|
1527 |
+
market_analysis["competitive_position"] = "Needs improvement"
|
1528 |
+
market_analysis["market_risks"].append("Poor presentation may limit appeal")
|
1529 |
+
|
1530 |
+
# 3. Room-specific positioning
|
1531 |
+
if room_type in ['kitchen', 'bathroom']:
|
1532 |
+
appliance_count = object_analysis.get('appliance_count', 0)
|
1533 |
+
fixture_count = object_analysis.get('fixture_count', 0)
|
1534 |
+
|
1535 |
+
if room_type == 'kitchen' and appliance_count >= 3:
|
1536 |
+
market_analysis["differentiation_factors"].append("Fully equipped kitchen")
|
1537 |
+
market_analysis["competitive_advantages"].append("Modern kitchen appliances")
|
1538 |
+
elif room_type == 'bathroom' and fixture_count >= 2:
|
1539 |
+
market_analysis["differentiation_factors"].append("Well-appointed bathroom")
|
1540 |
+
market_analysis["competitive_advantages"].append("Quality bathroom fixtures")
|
1541 |
+
|
1542 |
+
# 4. Object density analysis
|
1543 |
+
object_density = object_analysis.get('object_density', 0)
|
1544 |
+
if object_density > 10:
|
1545 |
+
market_analysis["differentiation_factors"].append("Rich content and features")
|
1546 |
+
market_analysis["competitive_advantages"].append("Well-appointed space")
|
1547 |
+
elif object_density < 3:
|
1548 |
+
market_analysis["market_risks"].append("Limited content may reduce appeal")
|
1549 |
+
|
1550 |
+
# 5. Market opportunities
|
1551 |
+
if quality_score < 70:
|
1552 |
+
market_analysis["market_opportunities"].append("Improve image quality for better positioning")
|
1553 |
+
|
1554 |
+
if room_confidence < 70:
|
1555 |
+
market_analysis["market_opportunities"].append("Enhance room type clarity")
|
1556 |
+
|
1557 |
+
if object_density < 5:
|
1558 |
+
market_analysis["market_opportunities"].append("Add more features and furniture")
|
1559 |
+
|
1560 |
+
# 6. Professional grade analysis
|
1561 |
+
if property_assessment.get('professional_grade', False):
|
1562 |
+
market_analysis["competitive_advantages"].append("Professional-grade presentation")
|
1563 |
+
market_analysis["differentiation_factors"].append("High-quality photography")
|
1564 |
+
else:
|
1565 |
+
market_analysis["market_opportunities"].append("Consider professional photography")
|
1566 |
+
|
1567 |
+
return market_analysis
|
1568 |
+
|
1569 |
+
except Exception as e:
|
1570 |
+
logger.error(f"Market positioning analysis failed: {str(e)}")
|
1571 |
+
return {
|
1572 |
+
"market_tier": "Unknown",
|
1573 |
+
"competitive_position": "Unknown",
|
1574 |
+
"price_positioning": "Unknown",
|
1575 |
+
"target_market": "Unknown",
|
1576 |
+
"differentiation_factors": [],
|
1577 |
+
"market_opportunities": [],
|
1578 |
+
"competitive_advantages": [],
|
1579 |
+
"market_risks": []
|
1580 |
+
}
|
1581 |
+
|
1582 |
+
def classify_room_type(image):
|
1583 |
+
"""Classify room type using the loaded room classifier"""
|
1584 |
+
try:
|
1585 |
+
if room_classifier is None:
|
1586 |
+
return {'room_type': 'unknown', 'confidence': 0}
|
1587 |
+
|
1588 |
+
results = room_classifier(image)
|
1589 |
+
return {
|
1590 |
+
'room_type': results[0]['label'].lower(),
|
1591 |
+
'confidence': round(results[0]['score'] * 100, 2)
|
1592 |
+
}
|
1593 |
+
except Exception as e:
|
1594 |
+
logger.error(f"Room classification failed: {str(e)}")
|
1595 |
+
return {'room_type': 'unknown', 'confidence': 0}
|
1596 |
+
|
1597 |
@app.route('/')
|
1598 |
def index():
|
1599 |
"""Main page for the image analyzer"""
|
1600 |
+
return render_template('analyzeindex.html')
|
1601 |
|
1602 |
@app.route('/analyze', methods=['POST'])
|
1603 |
def analyze_image():
|
|
|
1765 |
}
|
1766 |
})
|
1767 |
|
1768 |
+
@app.route('/debug')
|
1769 |
+
def debug_info():
|
1770 |
+
"""Debug endpoint to check application status"""
|
1771 |
+
return jsonify({
|
1772 |
+
'status': 'running',
|
1773 |
+
'port': os.environ.get('PORT', 7860),
|
1774 |
+
'models_loaded': {
|
1775 |
+
'room_classifier': room_classifier is not None,
|
1776 |
+
'image_captioner': image_captioner is not None,
|
1777 |
+
'yolo_model': yolo_model is not None,
|
1778 |
+
'clip_processor': clip_processor is not None,
|
1779 |
+
'clip_model': clip_model is not None
|
1780 |
+
},
|
1781 |
+
'python_version': sys.version,
|
1782 |
+
'torch_available': torch.cuda.is_available() if torch.cuda.is_available() else 'CPU only',
|
1783 |
+
'timestamp': datetime.now().isoformat()
|
1784 |
+
})
|
1785 |
+
|
1786 |
@app.route('/static/<path:filename>')
|
1787 |
def static_files(filename):
|
1788 |
"""Serve static files"""
|