add trees data
This commit is contained in:
parent
74baba4a7e
commit
c14f5ead38
|
@ -99,9 +99,12 @@ class ScoringEngine:
|
|||
if not weights:
|
||||
raise ValueError(f"Unknown personality type: {personality}")
|
||||
|
||||
# Calculate component scores
|
||||
# Pre-fetch tree data once for all calculations
|
||||
tree_data = await self._fetch_tree_data_once(green_space)
|
||||
|
||||
# Calculate component scores with cached tree data
|
||||
component_scores = await self._calculate_component_scores(
|
||||
green_space, personality, user_location
|
||||
green_space, personality, user_location, tree_data
|
||||
)
|
||||
|
||||
# Calculate weighted final score
|
||||
|
@ -134,11 +137,26 @@ class ScoringEngine:
|
|||
recommendations=recommendations
|
||||
)
|
||||
|
||||
async def _fetch_tree_data_once(self, green_space: GreenSpace) -> Optional[Any]:
|
||||
"""Fetch tree data once and reuse for all calculations."""
|
||||
try:
|
||||
# Use the largest radius needed across all methods (400m)
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=400
|
||||
)
|
||||
return tree_response
|
||||
except Exception as e:
|
||||
print(f"Error fetching tree data: {e}")
|
||||
return None
|
||||
|
||||
async def _calculate_component_scores(
|
||||
self,
|
||||
green_space: GreenSpace,
|
||||
personality: str,
|
||||
user_location: Optional[Tuple[float, float]] = None
|
||||
user_location: Optional[Tuple[float, float]] = None,
|
||||
tree_data: Optional[Any] = None
|
||||
) -> Dict[str, int]:
|
||||
"""Calculate individual component scores."""
|
||||
scores = {}
|
||||
|
@ -151,7 +169,7 @@ class ScoringEngine:
|
|||
# Personality-specific components
|
||||
if personality == "little_adventurers":
|
||||
scores["playground_quality"] = green_space.recreation.playground_quality
|
||||
scores["shade_quality"] = await self._score_shade_quality_with_trees(green_space)
|
||||
scores["shade_quality"] = self._score_shade_quality_with_trees(green_space, tree_data)
|
||||
scores["toilet_proximity"] = await self._score_toilet_proximity(green_space)
|
||||
scores["family_amenities"] = await self._score_family_amenities(green_space)
|
||||
|
||||
|
@ -171,11 +189,11 @@ class ScoringEngine:
|
|||
|
||||
elif personality == "zen_masters":
|
||||
scores["quietness"] = self._score_quietness(green_space)
|
||||
scores["nature_immersion"] = await self._score_nature_immersion_with_trees(green_space)
|
||||
scores["nature_immersion"] = self._score_nature_immersion_with_trees(green_space, tree_data)
|
||||
scores["crowd_density"] = await self._score_crowd_density(green_space)
|
||||
scores["water_features"] = 100 if green_space.environmental.water_features else 0
|
||||
scores["meditation_spots"] = await self._score_meditation_spots_with_trees(green_space)
|
||||
scores["air_quality"] = await self._score_air_quality_with_trees(green_space)
|
||||
scores["meditation_spots"] = self._score_meditation_spots_with_trees(green_space, tree_data)
|
||||
scores["air_quality"] = self._score_air_quality_with_trees(green_space, tree_data)
|
||||
|
||||
elif personality == "active_lifestyle":
|
||||
scores["fitness_facilities"] = 100 if green_space.recreation.sports_facilities else 0
|
||||
|
@ -184,11 +202,11 @@ class ScoringEngine:
|
|||
scores["terrain_variety"] = self._score_terrain_variety(green_space)
|
||||
|
||||
elif personality == "wildlife_lover":
|
||||
scores["wildlife_diversity"] = await self._score_wildlife_diversity_with_trees(green_space)
|
||||
scores["natural_habitat"] = await self._score_natural_habitat_with_trees(green_space)
|
||||
scores["wildlife_diversity"] = self._score_wildlife_diversity_with_trees(green_space, tree_data)
|
||||
scores["natural_habitat"] = self._score_natural_habitat_with_trees(green_space, tree_data)
|
||||
scores["water_features"] = 100 if green_space.environmental.water_features else 0
|
||||
scores["tree_coverage"] = await self._score_tree_coverage_with_real_data(green_space)
|
||||
scores["observation_spots"] = await self._score_observation_spots_with_trees(green_space)
|
||||
scores["tree_coverage"] = self._score_tree_coverage_with_real_data(green_space, tree_data)
|
||||
scores["observation_spots"] = self._score_observation_spots_with_trees(green_space, tree_data)
|
||||
|
||||
elif personality == "art_nerd":
|
||||
scores["cultural_proximity"] = await self._score_cultural_proximity(green_space)
|
||||
|
@ -391,7 +409,7 @@ class ScoringEngine:
|
|||
score += 25
|
||||
return min(100, score)
|
||||
|
||||
async def _score_air_quality(self, green_space: GreenSpace) -> int:
|
||||
def _score_air_quality(self, green_space: GreenSpace) -> int:
|
||||
"""Score air quality."""
|
||||
score = green_space.environmental.tree_coverage_percent
|
||||
if green_space.environmental.natural_surface_percent > 80:
|
||||
|
@ -570,7 +588,7 @@ class ScoringEngine:
|
|||
personality: str,
|
||||
radius: int
|
||||
) -> Dict[str, Any]:
|
||||
"""Score a specific location."""
|
||||
"""Score a specific location with optimized performance."""
|
||||
# Check if location is in a green space
|
||||
green_space = await self.berlin_data.get_green_space_at_location(lat, lng)
|
||||
|
||||
|
@ -582,7 +600,7 @@ class ScoringEngine:
|
|||
"personality": personality
|
||||
}
|
||||
|
||||
# Score the green space
|
||||
# Score the green space (this now uses cached tree data internally)
|
||||
personality_score = await self.score_green_space(green_space, personality, (lat, lng))
|
||||
|
||||
return {
|
||||
|
@ -628,26 +646,23 @@ class ScoringEngine:
|
|||
|
||||
# === ENHANCED TREE-BASED SCORING METHODS ===
|
||||
|
||||
async def _score_tree_coverage_with_real_data(self, green_space: GreenSpace) -> int:
|
||||
def _score_tree_coverage_with_real_data(self, green_space: GreenSpace, tree_data: Optional[Any] = None) -> int:
|
||||
"""Enhanced tree coverage scoring using real street tree data."""
|
||||
if not tree_data:
|
||||
return green_space.environmental.tree_coverage_percent
|
||||
|
||||
try:
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=300
|
||||
)
|
||||
|
||||
# Combine base environmental score with real tree data
|
||||
base_score = green_space.environmental.tree_coverage_percent
|
||||
tree_shade_coverage = tree_response.shade_analysis.estimated_shade_coverage
|
||||
tree_shade_coverage = tree_data.shade_analysis.estimated_shade_coverage
|
||||
|
||||
# Use the higher of the two scores, with bonus for high tree density
|
||||
enhanced_score = max(base_score, tree_shade_coverage)
|
||||
|
||||
# Bonus for high tree density
|
||||
if tree_response.metrics.trees_per_hectare > 50:
|
||||
if tree_data.metrics.trees_per_hectare > 50:
|
||||
enhanced_score = min(100, enhanced_score + 15)
|
||||
elif tree_response.metrics.trees_per_hectare > 20:
|
||||
elif tree_data.metrics.trees_per_hectare > 20:
|
||||
enhanced_score = min(100, enhanced_score + 10)
|
||||
|
||||
return int(enhanced_score)
|
||||
|
@ -656,18 +671,15 @@ class ScoringEngine:
|
|||
print(f"Error enhancing tree coverage score: {e}")
|
||||
return green_space.environmental.tree_coverage_percent
|
||||
|
||||
async def _score_wildlife_diversity_with_trees(self, green_space: GreenSpace) -> int:
|
||||
def _score_wildlife_diversity_with_trees(self, green_space: GreenSpace, tree_data: Optional[Any] = None) -> int:
|
||||
"""Enhanced wildlife diversity scoring using real tree species data."""
|
||||
if not tree_data:
|
||||
return green_space.environmental.wildlife_diversity_score
|
||||
|
||||
try:
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=400
|
||||
)
|
||||
|
||||
base_score = green_space.environmental.wildlife_diversity_score
|
||||
tree_diversity = tree_response.metrics.species_diversity_score
|
||||
mature_trees_bonus = min(20, tree_response.metrics.mature_trees_count)
|
||||
tree_diversity = tree_data.metrics.species_diversity_score
|
||||
mature_trees_bonus = min(20, tree_data.metrics.mature_trees_count)
|
||||
|
||||
# Combine scores with weighting
|
||||
enhanced_score = int((base_score * 0.6) + (tree_diversity * 0.4) + mature_trees_bonus)
|
||||
|
@ -678,23 +690,20 @@ class ScoringEngine:
|
|||
print(f"Error enhancing wildlife diversity score: {e}")
|
||||
return green_space.environmental.wildlife_diversity_score
|
||||
|
||||
async def _score_shade_quality_with_trees(self, green_space: GreenSpace) -> int:
|
||||
def _score_shade_quality_with_trees(self, green_space: GreenSpace, tree_data: Optional[Any] = None) -> int:
|
||||
"""Enhanced shade quality scoring using real tree data."""
|
||||
if not tree_data:
|
||||
return green_space.environmental.shade_quality
|
||||
|
||||
try:
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=200
|
||||
)
|
||||
|
||||
base_shade = green_space.environmental.shade_quality
|
||||
tree_shade_quality = tree_response.shade_analysis.shade_quality_score
|
||||
tree_shade_quality = tree_data.shade_analysis.shade_quality_score
|
||||
|
||||
# Use the better of the two scores
|
||||
enhanced_score = max(base_shade, tree_shade_quality)
|
||||
|
||||
# Bonus for large nearby trees
|
||||
large_trees_count = len(tree_response.shade_analysis.nearby_large_trees)
|
||||
large_trees_count = len(tree_data.shade_analysis.nearby_large_trees)
|
||||
if large_trees_count > 5:
|
||||
enhanced_score = min(100, enhanced_score + 15)
|
||||
elif large_trees_count > 2:
|
||||
|
@ -706,15 +715,12 @@ class ScoringEngine:
|
|||
print(f"Error enhancing shade quality score: {e}")
|
||||
return green_space.environmental.shade_quality
|
||||
|
||||
async def _score_nature_immersion_with_trees(self, green_space: GreenSpace) -> int:
|
||||
def _score_nature_immersion_with_trees(self, green_space: GreenSpace, tree_data: Optional[Any] = None) -> int:
|
||||
"""Enhanced nature immersion scoring using real tree data."""
|
||||
if not tree_data:
|
||||
return self._score_nature_immersion(green_space)
|
||||
|
||||
try:
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=350
|
||||
)
|
||||
|
||||
# Base score from existing method
|
||||
base_score = green_space.environmental.tree_coverage_percent
|
||||
base_score += green_space.environmental.natural_surface_percent // 2
|
||||
|
@ -722,9 +728,9 @@ class ScoringEngine:
|
|||
base_score += 15
|
||||
|
||||
# Enhancement from tree data
|
||||
tree_density_score = min(30, tree_response.metrics.trees_per_hectare)
|
||||
canopy_density_bonus = int(tree_response.shade_analysis.canopy_density * 20) if tree_response.shade_analysis.canopy_density else 0
|
||||
species_diversity_bonus = min(15, tree_response.metrics.species_diversity_score // 5)
|
||||
tree_density_score = min(30, tree_data.metrics.trees_per_hectare)
|
||||
canopy_density_bonus = int(tree_data.shade_analysis.canopy_density * 20) if tree_data.shade_analysis.canopy_density else 0
|
||||
species_diversity_bonus = min(15, tree_data.metrics.species_diversity_score // 5)
|
||||
|
||||
enhanced_score = base_score + tree_density_score + canopy_density_bonus + species_diversity_bonus
|
||||
|
||||
|
@ -734,23 +740,20 @@ class ScoringEngine:
|
|||
print(f"Error enhancing nature immersion score: {e}")
|
||||
return self._score_nature_immersion(green_space)
|
||||
|
||||
async def _score_natural_habitat_with_trees(self, green_space: GreenSpace) -> int:
|
||||
def _score_natural_habitat_with_trees(self, green_space: GreenSpace, tree_data: Optional[Any] = None) -> int:
|
||||
"""Enhanced natural habitat scoring using real tree data."""
|
||||
if not tree_data:
|
||||
return self._score_natural_habitat(green_space)
|
||||
|
||||
try:
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=300
|
||||
)
|
||||
|
||||
base_score = green_space.environmental.tree_coverage_percent
|
||||
base_score += green_space.environmental.natural_surface_percent // 2
|
||||
if green_space.environmental.water_features:
|
||||
base_score += 15
|
||||
|
||||
# Tree habitat quality factors
|
||||
mature_trees_score = min(25, tree_response.metrics.mature_trees_count // 2)
|
||||
species_diversity_score = min(20, tree_response.metrics.species_diversity_score // 3)
|
||||
mature_trees_score = min(25, tree_data.metrics.mature_trees_count // 2)
|
||||
species_diversity_score = min(20, tree_data.metrics.species_diversity_score // 3)
|
||||
|
||||
enhanced_score = base_score + mature_trees_score + species_diversity_score
|
||||
|
||||
|
@ -760,15 +763,12 @@ class ScoringEngine:
|
|||
print(f"Error enhancing natural habitat score: {e}")
|
||||
return self._score_natural_habitat(green_space)
|
||||
|
||||
async def _score_observation_spots_with_trees(self, green_space: GreenSpace) -> int:
|
||||
def _score_observation_spots_with_trees(self, green_space: GreenSpace, tree_data: Optional[Any] = None) -> int:
|
||||
"""Enhanced wildlife observation scoring using real tree data."""
|
||||
if not tree_data:
|
||||
return self._score_observation_spots(green_space)
|
||||
|
||||
try:
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=250
|
||||
)
|
||||
|
||||
base_score = green_space.environmental.tree_coverage_percent // 2
|
||||
if green_space.environmental.water_features:
|
||||
base_score += 30
|
||||
|
@ -776,11 +776,11 @@ class ScoringEngine:
|
|||
base_score += 20
|
||||
|
||||
# Large trees provide better observation opportunities
|
||||
large_trees_count = len(tree_response.shade_analysis.nearby_large_trees)
|
||||
large_trees_count = len(tree_data.shade_analysis.nearby_large_trees)
|
||||
observation_bonus = min(25, large_trees_count * 3)
|
||||
|
||||
# Species diversity attracts more wildlife to observe
|
||||
diversity_bonus = min(15, tree_response.metrics.species_diversity_score // 4)
|
||||
diversity_bonus = min(15, tree_data.metrics.species_diversity_score // 4)
|
||||
|
||||
enhanced_score = base_score + observation_bonus + diversity_bonus
|
||||
|
||||
|
@ -790,15 +790,12 @@ class ScoringEngine:
|
|||
print(f"Error enhancing observation spots score: {e}")
|
||||
return self._score_observation_spots(green_space)
|
||||
|
||||
async def _score_meditation_spots_with_trees(self, green_space: GreenSpace) -> int:
|
||||
def _score_meditation_spots_with_trees(self, green_space: GreenSpace, tree_data: Optional[Any] = None) -> int:
|
||||
"""Enhanced meditation spots scoring using real tree data."""
|
||||
if not tree_data:
|
||||
return self._score_meditation_spots(green_space)
|
||||
|
||||
try:
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=200
|
||||
)
|
||||
|
||||
base_score = green_space.environmental.tree_coverage_percent // 2
|
||||
if green_space.environmental.water_features:
|
||||
base_score += 25
|
||||
|
@ -806,8 +803,8 @@ class ScoringEngine:
|
|||
base_score += 25
|
||||
|
||||
# Trees enhance meditation through natural sounds and shade
|
||||
shade_quality_bonus = min(20, tree_response.shade_analysis.shade_quality_score // 4)
|
||||
canopy_bonus = int(tree_response.shade_analysis.canopy_density * 15) if tree_response.shade_analysis.canopy_density else 0
|
||||
shade_quality_bonus = min(20, tree_data.shade_analysis.shade_quality_score // 4)
|
||||
canopy_bonus = int(tree_data.shade_analysis.canopy_density * 15) if tree_data.shade_analysis.canopy_density else 0
|
||||
|
||||
enhanced_score = base_score + shade_quality_bonus + canopy_bonus
|
||||
|
||||
|
@ -817,22 +814,19 @@ class ScoringEngine:
|
|||
print(f"Error enhancing meditation spots score: {e}")
|
||||
return self._score_meditation_spots(green_space)
|
||||
|
||||
async def _score_air_quality_with_trees(self, green_space: GreenSpace) -> int:
|
||||
def _score_air_quality_with_trees(self, green_space: GreenSpace, tree_data: Optional[Any] = None) -> int:
|
||||
"""Enhanced air quality scoring using real tree data."""
|
||||
if not tree_data:
|
||||
return self._score_air_quality(green_space)
|
||||
|
||||
try:
|
||||
tree_response = await self.street_tree_service.get_trees_near_location(
|
||||
green_space.coordinates.lat,
|
||||
green_space.coordinates.lng,
|
||||
radius_m=400
|
||||
)
|
||||
|
||||
base_score = green_space.environmental.tree_coverage_percent
|
||||
if green_space.environmental.natural_surface_percent > 80:
|
||||
base_score += 20
|
||||
|
||||
# More trees = better air quality
|
||||
tree_density_bonus = min(25, tree_response.metrics.trees_per_hectare // 2)
|
||||
mature_trees_bonus = min(15, tree_response.metrics.mature_trees_count // 3)
|
||||
tree_density_bonus = min(25, tree_data.metrics.trees_per_hectare // 2)
|
||||
mature_trees_bonus = min(15, tree_data.metrics.mature_trees_count // 3)
|
||||
|
||||
enhanced_score = base_score + tree_density_bonus + mature_trees_bonus
|
||||
|
||||
|
@ -840,4 +834,4 @@ class ScoringEngine:
|
|||
|
||||
except Exception as e:
|
||||
print(f"Error enhancing air quality score: {e}")
|
||||
return await self._score_air_quality(green_space)
|
||||
return self._score_air_quality(green_space)
|
||||
|
|
Loading…
Reference in New Issue