File size: 6,069 Bytes
ca7a2c2 51ba917 |
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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
"""Trip Planner Models - Pydantic schemas for Plan and PlanItem."""
from datetime import datetime
from pydantic import BaseModel, Field
from typing import Optional
class PlaceInput(BaseModel):
"""Place data for adding to plan."""
place_id: str = Field(..., description="Unique place identifier")
name: str = Field(..., description="Place name")
category: str = Field(default="", description="Place category")
lat: float = Field(..., description="Latitude")
lng: float = Field(..., description="Longitude")
rating: Optional[float] = Field(None, description="Rating 0-5")
description: Optional[str] = Field(None, description="Place description")
class PlanItem(BaseModel):
"""A place in the plan with order and metadata."""
item_id: str = Field(..., description="Unique item identifier")
place_id: str = Field(..., description="Reference to place")
name: str = Field(..., description="Place name")
category: str = Field(default="", description="Category")
lat: float = Field(..., description="Latitude")
lng: float = Field(..., description="Longitude")
order: int = Field(..., description="Order in plan (1-indexed)")
added_at: datetime = Field(default_factory=datetime.now)
notes: Optional[str] = Field(None, description="User notes")
rating: Optional[float] = None
distance_from_prev_km: Optional[float] = Field(None, description="Distance from previous item")
class Plan(BaseModel):
"""A trip plan containing multiple places."""
plan_id: str = Field(..., description="Unique plan identifier")
user_id: str = Field(..., description="Owner user ID")
name: str = Field(default="My Trip", description="Plan name")
items: list[PlanItem] = Field(default_factory=list)
created_at: datetime = Field(default_factory=datetime.now)
updated_at: datetime = Field(default_factory=datetime.now)
total_distance_km: Optional[float] = Field(None, description="Total route distance")
estimated_duration_min: Optional[int] = Field(None, description="Estimated duration")
is_optimized: bool = Field(default=False, description="Route has been optimized")
# Request/Response Models
class CreatePlanRequest(BaseModel):
"""Request to create a new plan."""
name: str = Field(default="My Trip", description="Plan name")
class CreatePlanResponse(BaseModel):
"""Response after creating a plan."""
plan_id: str
name: str
message: str
class AddPlaceRequest(BaseModel):
"""Request to add a place to plan."""
place: PlaceInput
notes: Optional[str] = None
class ReorderRequest(BaseModel):
"""Request to reorder places in plan."""
new_order: list[str] = Field(..., description="List of item_ids in new order")
class ReplaceRequest(BaseModel):
"""Request to replace a place."""
new_place: PlaceInput
class OptimizeResponse(BaseModel):
"""Response from route optimization."""
plan_id: str
items: list[PlanItem]
total_distance_km: float
estimated_duration_min: int
distance_saved_km: Optional[float] = None
message: str
class PlanResponse(BaseModel):
"""Full plan response."""
plan: Plan
message: str
# =============================================================================
# SMART PLAN MODELS
# =============================================================================
class PlaceDetailResponse(BaseModel):
"""Rich detail for a place in smart plan."""
place_id: str = Field(..., description="Place ID")
name: str = Field(..., description="Place name")
category: str = Field(default="", description="Category")
lat: float = Field(default=0.0, description="Latitude")
lng: float = Field(default=0.0, description="Longitude")
recommended_time: str = Field(default="", description="Recommended visit time (HH:MM)")
suggested_duration_min: int = Field(default=60, description="Suggested duration in minutes")
tips: list[str] = Field(default_factory=list, description="Tips for this place")
highlights: str = Field(default="", description="Highlights from research")
social_mentions: list[str] = Field(default_factory=list, description="Social media mentions")
order: int = Field(default=0, description="Order in day")
class DayPlanResponse(BaseModel):
"""Single day plan."""
day_index: int = Field(..., description="Day number (1-indexed)")
date: Optional[str] = Field(None, description="Date (YYYY-MM-DD)")
places: list[PlaceDetailResponse] = Field(default_factory=list)
day_summary: str = Field(default="", description="Day summary")
day_distance_km: float = Field(default=0.0, description="Total distance for the day")
class SmartPlanResponse(BaseModel):
"""Complete optimized plan with enriched details."""
itinerary_id: str = Field(..., description="Reference ID")
title: str = Field(..., description="Plan title")
total_days: int = Field(..., description="Number of days")
days: list[DayPlanResponse] = Field(default_factory=list)
summary: str = Field(default="", description="Plan summary")
total_distance_km: float = Field(default=0.0, description="Total route distance")
estimated_total_duration_min: int = Field(default=0, description="Total estimated duration")
generated_at: datetime = Field(default_factory=datetime.now)
class GetPlanRequest(BaseModel):
"""Request for smart plan generation."""
include_social_research: bool = Field(default=True, description="Include social media research")
freshness: str = Field(default="pw", description="Social search freshness: pw=past week, pm=past month")
class GetPlanResponse(BaseModel):
"""Response with smart plan."""
plan: SmartPlanResponse
research_count: int = Field(default=0, description="Number of social results found")
generation_time_ms: float = Field(default=0, description="Plan generation time in ms")
message: str = Field(default="Smart plan generated successfully")
|