|
|
"""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") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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") |
|
|
|
|
|
|