berlin-picnic-api/app/models/green_space.py

140 lines
5.0 KiB
Python

# app/models/green_space.py
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Tuple, Any
from datetime import datetime
from enum import Enum
class GreenSpaceType(str, Enum):
PARK = "park"
GARDEN = "garden"
FOREST = "forest"
RIVERSIDE = "riverside"
CEMETERY = "cemetery"
PLAYGROUND = "playground"
SPORTS_FIELD = "sports_field"
ALLOTMENT = "allotment"
SQUARE = "square"
OTHER = "other"
class NoiseLevel(int, Enum):
VERY_QUIET = 1
QUIET = 2
MODERATE = 3
NOISY = 4
VERY_NOISY = 5
class AmenityType(str, Enum):
TOILET = "toilet"
RESTAURANT = "restaurant"
CAFE = "cafe"
ICE_CREAM = "ice_cream"
SPATI = "spati"
PLAYGROUND = "playground"
WATER_FEATURE = "water_feature"
FITNESS = "fitness"
BIKE_RENTAL = "bike_rental"
PARKING = "parking"
PUBLIC_TRANSPORT = "public_transport"
class Coordinates(BaseModel):
lat: float = Field(..., ge=-90, le=90)
lng: float = Field(..., ge=-180, le=180)
class Amenity(BaseModel):
id: str
name: str
type: AmenityType
coordinates: Coordinates
distance_meters: int
rating: Optional[float] = Field(None, ge=0, le=5)
opening_hours: Optional[str] = None
description: Optional[str] = None
class EnvironmentalFeatures(BaseModel):
"""Environmental characteristics of the green space."""
tree_coverage_percent: int = Field(..., ge=0, le=100, description="Percentage of area covered by trees")
shade_quality: int = Field(..., ge=0, le=100, description="Quality of shade availability")
noise_level: NoiseLevel = Field(..., description="Average noise level")
wildlife_diversity_score: int = Field(..., ge=0, le=100, description="Biodiversity indicator")
water_features: bool = Field(False, description="Has ponds, fountains, or streams")
natural_surface_percent: int = Field(..., ge=0, le=100, description="Percentage of natural vs paved surface")
class AccessibilityFeatures(BaseModel):
"""Accessibility and infrastructure features."""
wheelchair_accessible: bool = Field(False)
public_transport_score: int = Field(..., ge=1, le=5, description="Public transport accessibility")
cycling_infrastructure: bool = Field(False, description="Has bike paths or bike parking")
parking_availability: int = Field(..., ge=1, le=5, description="Car parking availability")
lighting_quality: int = Field(..., ge=1, le=5, description="Evening lighting quality")
class RecreationFeatures(BaseModel):
"""Recreation and activity features."""
playground_quality: int = Field(0, ge=0, le=100, description="Playground facilities quality")
sports_facilities: bool = Field(False, description="Has sports courts, fitness equipment")
running_paths: bool = Field(False, description="Has designated running/walking paths")
cycling_paths: bool = Field(False, description="Has cycling paths")
dog_friendly: bool = Field(True, description="Dogs allowed")
bbq_allowed: bool = Field(False, description="BBQ/grilling allowed")
class PersonalityScore(BaseModel):
"""Personality-specific score with explanation."""
personality: str
score: int = Field(..., ge=0, le=100)
explanation: str
key_factors: List[str]
recommendations: List[str]
class GreenSpace(BaseModel):
"""Complete green space model with all features and scoring."""
# Basic info
id: str
name: str
description: Optional[str] = None
type: GreenSpaceType
# Location
coordinates: Coordinates
neighborhood: str
address: Optional[str] = None
# Physical characteristics
area_sqm: Optional[int] = Field(None, ge=1, description="Area in square meters")
perimeter_m: Optional[int] = Field(None, ge=1, description="Perimeter in meters")
# Features
environmental: EnvironmentalFeatures
accessibility: AccessibilityFeatures
recreation: RecreationFeatures
# Nearby amenities (within search radius)
nearby_amenities: List[Amenity] = []
# Personality scoring (for current request)
current_personality_score: Optional[PersonalityScore] = None
all_personality_scores: Optional[Dict[str, int]] = None
# Metadata
last_updated: datetime
data_sources: List[str] = []
confidence_score: int = Field(..., ge=0, le=100, description="Data quality confidence")
class ScoringRequest(BaseModel):
"""Request parameters for green space scoring."""
personality: str
location: Optional[Tuple[float, float]] = None # (lat, lng)
radius: int = Field(2000, ge=100, le=10000)
neighborhood: Optional[str] = None
min_score: int = Field(60, ge=0, le=100)
filters: Dict[str, Any] = {}
limit: int = Field(20, ge=1, le=100)
include_amenities: bool = False
class LocationScore(BaseModel):
"""Score for a specific location within a green space."""
coordinates: Coordinates
score: int = Field(..., ge=0, le=100)
explanation: str
nearby_features: List[str]
best_for: List[str] # Best personality types for this location
recommendations: List[str]