Spaces:
Sleeping
Sleeping
| """ | |
| Validation Rules for Trip Quality Assurance | |
| This module implements specific validation rules that ensure travel recommendations | |
| meet quality standards and business requirements. | |
| """ | |
| from datetime import datetime, timedelta | |
| from typing import Dict, List, Any | |
| from ..core.trip_validation import ValidationRule, ValidationResult, ValidationSeverity, ValidationLevel | |
| class FlightValidationRule(ValidationRule): | |
| """Validates individual flight recommendations.""" | |
| def __init__(self): | |
| super().__init__("flight_validation", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| if "flight" not in agent_outputs: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.CRITICAL, | |
| rule_name=self.rule_name, | |
| message="No flight selected", | |
| agent_id="flight_agent", | |
| suggestions=["Select a flight option"] | |
| )) | |
| return results | |
| flight = agent_outputs["flight"] | |
| # Validate flight has required attributes | |
| if not hasattr(flight, 'price') or flight.price <= 0: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.CRITICAL, | |
| rule_name=self.rule_name, | |
| message="Invalid flight price", | |
| agent_id="flight_agent", | |
| suggestions=["Select flight with valid price"] | |
| )) | |
| # Validate duration is reasonable | |
| if hasattr(flight, 'duration_hours') and flight.duration_hours > 24: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message=f"Very long flight duration: {flight.duration_hours}h", | |
| agent_id="flight_agent", | |
| suggestions=["Consider shorter flight options or breaks"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates flight options for price, duration, and basic requirements" | |
| class HotelValidationRule(ValidationRule): | |
| """Validates individual hotel recommendations.""" | |
| def __init__(self): | |
| super().__init__("hotel_validation", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| if "hotel" not in agent_outputs: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.CRITICAL, | |
| rule_name=self.rule_name, | |
| message="No hotel selected", | |
| agent_id="hotel_agent", | |
| suggestions=["Select a hotel option"] | |
| )) | |
| return results | |
| hotel = agent_outputs["hotel"] | |
| # Validate hotel rating | |
| if hasattr(hotel, 'rating') and hotel.rating < 2.0: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message=f"Low hotel rating: {hotel.rating}/5", | |
| agent_id="hotel_agent", | |
| suggestions=["Consider higher-rated hotel options"] | |
| )) | |
| # Validate location | |
| if hasattr(hotel, 'distance_city_center_km') and hotel.distance_city_center_km > 50: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message=f"Hotel very far from city center: {hotel.distance_city_center_km}km", | |
| agent_id="hotel_agent", | |
| suggestions=["Consider hotels closer to city center"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates hotel options for rating, location, and quality standards" | |
| class POIValidationRule(ValidationRule): | |
| """Validates individual POI recommendations.""" | |
| def __init__(self): | |
| super().__init__("poi_validation", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| if "pois" not in agent_outputs: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message="No activities selected", | |
| agent_id="poi_agent", | |
| suggestions=["Add activities to enhance trip experience"] | |
| )) | |
| return results | |
| pois = agent_outputs["pois"] | |
| if not pois: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message="Empty activity list", | |
| agent_id="poi_agent", | |
| suggestions=["Select at least one activity"] | |
| )) | |
| return results | |
| # Check for activity diversity | |
| categories = set() | |
| for poi in pois: | |
| if hasattr(poi, 'category'): | |
| categories.add(poi.category.value if hasattr(poi.category, 'value') else str(poi.category)) | |
| if len(categories) < 2 and len(pois) > 1: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.INDIVIDUAL, | |
| severity=ValidationSeverity.INFO, | |
| rule_name=self.rule_name, | |
| message=f"Limited activity diversity: {len(categories)} categories", | |
| agent_id="poi_agent", | |
| suggestions=["Add activities from different categories"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates POI selections for diversity and quality" | |
| class FlightHotelCompatibilityRule(ValidationRule): | |
| """Validates compatibility between flight and hotel selections.""" | |
| def __init__(self): | |
| super().__init__("flight_hotel_compatibility", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| if "flight" not in agent_outputs or "hotel" not in agent_outputs: | |
| return results | |
| flight = agent_outputs["flight"] | |
| hotel = agent_outputs["hotel"] | |
| # Check timing compatibility | |
| if (hasattr(flight, 'arrival_time') and hasattr(hotel, 'check_in_time')): | |
| arrival_time = flight.arrival_time | |
| check_in_time = hotel.check_in_time | |
| time_diff = (check_in_time - arrival_time).total_seconds() / 3600 # hours | |
| if time_diff < 1: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.CROSS_AGENT, | |
| severity=ValidationSeverity.CRITICAL, | |
| rule_name=self.rule_name, | |
| message=f"Insufficient time between flight arrival and hotel check-in: {time_diff:.1f}h", | |
| agent_id="flight_agent,hotel_agent", | |
| suggestions=[ | |
| "Select later hotel check-in time", | |
| "Choose earlier flight arrival", | |
| "Add buffer time for delays" | |
| ] | |
| )) | |
| elif time_diff < 2: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.CROSS_AGENT, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message=f"Tight schedule between flight arrival and hotel check-in: {time_diff:.1f}h", | |
| agent_id="flight_agent,hotel_agent", | |
| suggestions=["Consider adding buffer time for potential delays"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates timing compatibility between flight arrival and hotel check-in" | |
| class HotelPOICompatibilityRule(ValidationRule): | |
| """Validates compatibility between hotel and POI selections.""" | |
| def __init__(self): | |
| super().__init__("hotel_poi_compatibility", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| if "hotel" not in agent_outputs or "pois" not in agent_outputs: | |
| return results | |
| hotel = agent_outputs["hotel"] | |
| pois = agent_outputs["pois"] | |
| if not pois: | |
| return results | |
| # Check distance compatibility | |
| if hasattr(hotel, 'distance_city_center_km'): | |
| hotel_distance = hotel.distance_city_center_km | |
| far_activities = [] | |
| for poi in pois: | |
| if hasattr(poi, 'distance_city_center_km'): | |
| poi_distance = poi.distance_city_center_km | |
| total_distance = abs(hotel_distance - poi_distance) | |
| if total_distance > 15: # More than 15km apart | |
| far_activities.append(poi.name if hasattr(poi, 'name') else 'Unknown') | |
| if far_activities: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.CROSS_AGENT, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message=f"Hotel and activities are far apart: {', '.join(far_activities[:3])}", | |
| agent_id="hotel_agent,poi_agent", | |
| suggestions=[ | |
| "Select hotel closer to activities", | |
| "Choose activities closer to hotel", | |
| "Plan for additional transportation time" | |
| ] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates location compatibility between hotel and activities" | |
| class FlightPOICompatibilityRule(ValidationRule): | |
| """Validates compatibility between flight and POI selections.""" | |
| def __init__(self): | |
| super().__init__("flight_poi_compatibility", ValidationSeverity.INFO) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| if "flight" not in agent_outputs or "pois" not in agent_outputs: | |
| return results | |
| flight = agent_outputs["flight"] | |
| pois = agent_outputs["pois"] | |
| if not pois: | |
| return results | |
| # Check if activities require early arrival but flight arrives late | |
| if hasattr(flight, 'arrival_time'): | |
| arrival_hour = flight.arrival_time.hour | |
| # Check for morning activities | |
| morning_activities = [] | |
| for poi in pois: | |
| if hasattr(poi, 'opening_hours'): | |
| # In real implementation, parse opening hours | |
| # For now, assume some activities are morning-only | |
| if hasattr(poi, 'category') and 'museum' in str(poi.category).lower(): | |
| morning_activities.append(poi.name if hasattr(poi, 'name') else 'Unknown') | |
| if morning_activities and arrival_hour > 14: # Arriving after 2 PM | |
| results.append(ValidationResult( | |
| level=ValidationLevel.CROSS_AGENT, | |
| severity=ValidationSeverity.INFO, | |
| rule_name=self.rule_name, | |
| message=f"Late flight arrival may limit morning activities: {', '.join(morning_activities[:2])}", | |
| agent_id="flight_agent,poi_agent", | |
| suggestions=[ | |
| "Consider earlier flight arrival", | |
| "Reschedule morning activities for later days", | |
| "Choose activities with flexible hours" | |
| ] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates timing compatibility between flight arrival and activity schedules" | |
| class TripCoherenceRule(ValidationRule): | |
| """Validates overall trip coherence and quality.""" | |
| def __init__(self): | |
| super().__init__("trip_coherence", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| trip_context = context.get("trip_context", {}) | |
| # Check if all major components are present | |
| required_components = ["flight", "hotel"] | |
| missing_components = [comp for comp in required_components if comp not in agent_outputs] | |
| if missing_components: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.OVERALL, | |
| severity=ValidationSeverity.CRITICAL, | |
| rule_name=self.rule_name, | |
| message=f"Missing essential trip components: {', '.join(missing_components)}", | |
| suggestions=[f"Add {comp} selection" for comp in missing_components] | |
| )) | |
| # Check trip duration vs activity count | |
| if "pois" in agent_outputs: | |
| pois = agent_outputs["pois"] | |
| if pois: | |
| activity_count = len(pois) | |
| trip_duration = trip_context.get("trip_duration_days", 3) | |
| # Rough estimate: 2-3 activities per day is reasonable | |
| max_recommended = trip_duration * 3 | |
| if activity_count > max_recommended: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.OVERALL, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message=f"Many activities ({activity_count}) for short trip ({trip_duration} days)", | |
| suggestions=[ | |
| "Reduce number of activities", | |
| "Extend trip duration", | |
| "Prioritize most important activities" | |
| ] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates overall trip coherence and completeness" | |
| class BudgetAdherenceRule(ValidationRule): | |
| """Validates budget adherence across all components.""" | |
| def __init__(self): | |
| super().__init__("budget_adherence", ValidationSeverity.CRITICAL) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| trip_context = context.get("trip_context", {}) | |
| total_budget = trip_context.get("total_budget", 0) | |
| if total_budget <= 0: | |
| return results | |
| # Calculate total cost | |
| total_cost = 0 | |
| component_costs = {} | |
| for agent_id, output in agent_outputs.items(): | |
| if "cost" in output: | |
| cost = output["cost"] | |
| total_cost += cost | |
| component_costs[agent_id] = cost | |
| # Check budget adherence | |
| if total_cost > total_budget: | |
| overage = total_cost - total_budget | |
| overage_percentage = (overage / total_budget) * 100 | |
| severity = ValidationSeverity.CRITICAL if overage_percentage > 20 else ValidationSeverity.WARNING | |
| results.append(ValidationResult( | |
| level=ValidationLevel.OVERALL, | |
| severity=severity, | |
| rule_name=self.rule_name, | |
| message=f"Trip exceeds budget by ${overage:.2f} ({overage_percentage:.1f}%)", | |
| details={ | |
| "total_budget": total_budget, | |
| "total_cost": total_cost, | |
| "component_costs": component_costs | |
| }, | |
| suggestions=[ | |
| "Reduce flight costs", | |
| "Choose cheaper hotel", | |
| "Select fewer or cheaper activities", | |
| "Increase budget allocation" | |
| ] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates that trip stays within allocated budget" | |
| class QualityThresholdRule(ValidationRule): | |
| """Validates that trip meets minimum quality thresholds.""" | |
| def __init__(self): | |
| super().__init__("quality_threshold", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| # This rule would integrate with quality scores calculated elsewhere | |
| # For now, provide basic quality checks | |
| agent_outputs = context.get("agent_outputs", {}) | |
| # Check hotel quality | |
| if "hotel" in agent_outputs: | |
| hotel = agent_outputs["hotel"] | |
| if hasattr(hotel, 'rating') and hotel.rating < 3.0: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.OVERALL, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message=f"Hotel quality below recommended threshold: {hotel.rating}/5", | |
| suggestions=["Consider higher-rated hotel options"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates minimum quality thresholds for trip components" | |
| class TravelTimeRule(ValidationRule): | |
| """Validates realistic travel times and schedules.""" | |
| def __init__(self): | |
| super().__init__("travel_time", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| # Check flight duration reasonableness | |
| if "flight" in agent_outputs: | |
| flight = agent_outputs["flight"] | |
| if hasattr(flight, 'duration_hours'): | |
| if flight.duration_hours > 20: # Unrealistically long | |
| results.append(ValidationResult( | |
| level=ValidationLevel.BUSINESS_RULES, | |
| severity=ValidationSeverity.CRITICAL, | |
| rule_name=self.rule_name, | |
| message=f"Unrealistic flight duration: {flight.duration_hours}h", | |
| suggestions=["Verify flight details", "Consider alternative routes"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates realistic travel times and schedules" | |
| class CheckInOutSequenceRule(ValidationRule): | |
| """Validates proper check-in/check-out sequences.""" | |
| def __init__(self): | |
| super().__init__("checkin_checkout_sequence", ValidationSeverity.CRITICAL) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| if "hotel" in agent_outputs: | |
| hotel = agent_outputs["hotel"] | |
| # Check check-in/check-out sequence | |
| if (hasattr(hotel, 'check_in_time') and hasattr(hotel, 'check_out_time')): | |
| check_in = hotel.check_in_time | |
| check_out = hotel.check_out_time | |
| if check_out <= check_in: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.BUSINESS_RULES, | |
| severity=ValidationSeverity.CRITICAL, | |
| rule_name=self.rule_name, | |
| message="Invalid hotel stay: check-out before check-in", | |
| suggestions=["Fix hotel check-in/check-out times"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates proper hotel check-in/check-out sequences" | |
| class RealisticScheduleRule(ValidationRule): | |
| """Validates that the schedule is realistic and achievable.""" | |
| def __init__(self): | |
| super().__init__("realistic_schedule", ValidationSeverity.WARNING) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| # Check if too many activities are scheduled for the available time | |
| if "pois" in agent_outputs: | |
| pois = agent_outputs["pois"] | |
| if pois: | |
| total_duration = sum( | |
| getattr(poi, 'duration_hours', 4) for poi in pois | |
| ) # Assume 4 hours per activity if not specified | |
| trip_duration = context.get("trip_context", {}).get("trip_duration_days", 3) | |
| available_hours = trip_duration * 12 # 12 hours per day for activities | |
| if total_duration > available_hours: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.BUSINESS_RULES, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message=f"Activities require {total_duration}h but only {available_hours}h available", | |
| suggestions=[ | |
| "Reduce number of activities", | |
| "Extend trip duration", | |
| "Choose shorter activities" | |
| ] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates that the trip schedule is realistic and achievable" | |
| class AirportTransferRule(ValidationRule): | |
| """Validates airport transfer logistics.""" | |
| def __init__(self): | |
| super().__init__("airport_transfer", ValidationSeverity.INFO) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| # Check if hotel is reasonably close to airport | |
| if "hotel" in agent_outputs and "flight" in agent_outputs: | |
| hotel = agent_outputs["hotel"] | |
| flight = agent_outputs["flight"] | |
| # In real implementation, calculate actual airport-hotel distance | |
| # For now, use city center distance as proxy | |
| if hasattr(hotel, 'distance_city_center_km'): | |
| if hotel.distance_city_center_km > 30: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.BUSINESS_RULES, | |
| severity=ValidationSeverity.INFO, | |
| rule_name=self.rule_name, | |
| message="Hotel far from likely airport location", | |
| suggestions=[ | |
| "Consider airport transfer logistics", | |
| "Look for hotels closer to airport", | |
| "Plan for additional transfer time" | |
| ] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates airport transfer logistics and distances" | |
| class PreferenceAlignmentRule(ValidationRule): | |
| """Validates alignment with user preferences.""" | |
| def __init__(self): | |
| super().__init__("preference_alignment", ValidationSeverity.INFO) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| trip_context = context.get("trip_context", {}) | |
| preferences = trip_context.get("preferences", {}) | |
| # Check flight preferences | |
| if preferences.get("prefer_direct_flights", False) and "flight" in agent_outputs: | |
| flight = agent_outputs["flight"] | |
| if hasattr(flight, 'stops') and flight.stops > 0: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.USER_SATISFACTION, | |
| severity=ValidationSeverity.INFO, | |
| rule_name=self.rule_name, | |
| message="User prefers direct flights but selected flight has stops", | |
| suggestions=["Look for direct flight alternatives"] | |
| )) | |
| # Check hotel preferences | |
| if preferences.get("prefer_central_hotels", False) and "hotel" in agent_outputs: | |
| hotel = agent_outputs["hotel"] | |
| if hasattr(hotel, 'distance_city_center_km') and hotel.distance_city_center_km > 5: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.USER_SATISFACTION, | |
| severity=ValidationSeverity.INFO, | |
| rule_name=self.rule_name, | |
| message="User prefers central hotels but selected hotel is far from center", | |
| suggestions=["Look for hotels closer to city center"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates alignment with user preferences and travel style" | |
| class TravelStyleRule(ValidationRule): | |
| """Validates alignment with travel style.""" | |
| def __init__(self): | |
| super().__init__("travel_style", ValidationSeverity.INFO) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| trip_context = context.get("trip_context", {}) | |
| agent_outputs = context.get("agent_outputs", {}) | |
| trip_type = trip_context.get("trip_type", "leisure") | |
| # Check business trip requirements | |
| if trip_type == "business": | |
| if "hotel" in agent_outputs: | |
| hotel = agent_outputs["hotel"] | |
| if hasattr(hotel, 'rating') and hotel.rating < 4.0: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.USER_SATISFACTION, | |
| severity=ValidationSeverity.WARNING, | |
| rule_name=self.rule_name, | |
| message="Business trip may require higher-rated hotel", | |
| suggestions=["Consider 4+ star hotel for business travel"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates alignment with travel style and trip type" | |
| class EnergyLevelRule(ValidationRule): | |
| """Validates consideration of energy levels and activity intensity.""" | |
| def __init__(self): | |
| super().__init__("energy_level", ValidationSeverity.INFO) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| agent_outputs = context.get("agent_outputs", {}) | |
| if "pois" in agent_outputs: | |
| pois = agent_outputs["pois"] | |
| if pois: | |
| # Check for too many high-intensity activities | |
| high_intensity_count = 0 | |
| for poi in pois: | |
| if hasattr(poi, 'activity_level'): | |
| activity_level = poi.activity_level.value if hasattr(poi.activity_level, 'value') else str(poi.activity_level) | |
| if activity_level.lower() in ['high', 'strenuous']: | |
| high_intensity_count += 1 | |
| if high_intensity_count > len(pois) * 0.7: # More than 70% high intensity | |
| results.append(ValidationResult( | |
| level=ValidationLevel.USER_SATISFACTION, | |
| severity=ValidationSeverity.INFO, | |
| rule_name=self.rule_name, | |
| message="High proportion of strenuous activities may be exhausting", | |
| suggestions=[ | |
| "Add some low-intensity activities", | |
| "Space out high-intensity activities", | |
| "Consider rest days" | |
| ] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates consideration of energy levels and activity intensity" | |
| class AccessibilityRule(ValidationRule): | |
| """Validates accessibility considerations.""" | |
| def __init__(self): | |
| super().__init__("accessibility", ValidationSeverity.INFO) | |
| async def validate(self, context: Dict[str, Any]) -> List[ValidationResult]: | |
| results = [] | |
| # This rule would check for accessibility requirements if specified | |
| # For now, provide a placeholder implementation | |
| trip_context = context.get("trip_context", {}) | |
| special_requirements = trip_context.get("special_requirements", []) | |
| if "wheelchair_accessible" in special_requirements: | |
| results.append(ValidationResult( | |
| level=ValidationLevel.USER_SATISFACTION, | |
| severity=ValidationSeverity.INFO, | |
| rule_name=self.rule_name, | |
| message="Accessibility requirements specified", | |
| suggestions=["Verify all selected options are wheelchair accessible"] | |
| )) | |
| return results | |
| def get_rule_description(self) -> str: | |
| return "Validates accessibility requirements and considerations" | |