Spaces:
Sleeping
Sleeping
File size: 3,740 Bytes
214f910 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | from __future__ import annotations
from typing import Dict, List, Optional
from pydantic import BaseModel, Field, field_validator
class UserRequest(BaseModel):
"""Validated user request for planning a Qiddiya visit."""
visit_date: str = Field(
...,
description="Date of visit in YYYY-MM-DD format.",
examples=["2026-02-15"],
)
start_time: str = Field(
...,
description="Start time in HH:MM 24h format.",
examples=["10:00"],
)
end_time: str = Field(
...,
description="End time in HH:MM 24h format.",
examples=["20:00"],
)
must_do_attractions: List[str] = Field(
default_factory=list,
description="List of must-do attraction names.",
)
intensity_preference: int = Field(
3,
ge=1,
le=5,
description="1=relaxed, 5=extreme thrills.",
)
walking_tolerance: int = Field(
3,
ge=1,
le=5,
description="1=min walking, 5=okay with longer walks.",
)
@field_validator("visit_date")
@classmethod
def validate_date(cls, v: str) -> str:
parts = v.split("-")
if len(parts) != 3:
raise ValueError("visit_date must be in YYYY-MM-DD format")
year, month, day = parts
if len(year) != 4 or len(month) != 2 or len(day) != 2:
raise ValueError("visit_date must be in YYYY-MM-DD format")
return v
@field_validator("start_time", "end_time")
@classmethod
def validate_time(cls, v: str) -> str:
parts = v.split(":")
if len(parts) != 2:
raise ValueError("time must be in HH:MM format")
hour, minute = parts
if not hour.isdigit() or not minute.isdigit():
raise ValueError("time must be numeric HH:MM")
h = int(hour)
m = int(minute)
if not (0 <= h <= 23 and 0 <= m <= 59):
raise ValueError("time must be a valid 24h time")
return v
class Attraction(BaseModel):
id: str
name: str
node_id: str
thrill_level: int = Field(ge=1, le=5)
family_friendly: bool
average_duration_minutes: int = Field(ge=5, le=240)
base_popularity: int = Field(ge=1, le=10)
class ItineraryStop(BaseModel):
attraction_id: str
attraction_name: str
node_id: str
start_time: str
end_time: str
estimated_wait_minutes: int = Field(ge=0)
walking_distance_m: int = Field(ge=0)
is_suggested: bool = Field(default=False, description="True if added by system to boost enjoyment, not selected by user.")
class ItineraryPlan(BaseModel):
visit_date: str
total_wait_minutes: int
total_walking_m: int
coverage_score: float = Field(ge=0.0)
enjoyment_score: float = Field(ge=0.0)
stops: List[ItineraryStop]
logs: List[str] = Field(default_factory=list)
class EvaluationResult(BaseModel):
visit_date: str
request_summary: str
total_wait_minutes: int
total_walking_m: int
estimated_fatigue_score: float = Field(ge=0.0)
must_do_coverage_ratio: float = Field(ge=0.0, le=1.0)
constraint_violations: List[str] = Field(default_factory=list)
notes: Optional[str] = None
class SystemResponse(BaseModel):
"""Debug view of the multi-agent run (logs, reflection, critique)."""
logs: List[str] = Field(default_factory=list)
reflection_round: int = 0
critique: str = ""
wait_time_forecast: Optional[Dict[str, int]] = None
class PlanResponse(BaseModel):
"""Plan plus system debug info for the UI."""
plan: ItineraryPlan
system: SystemResponse
|