from __future__ import annotations from typing import Literal from pydantic import BaseModel, Field class CreateBirthProfileRequest(BaseModel): name: str birth_date: str birth_time: str | None = None birth_place: str | None = None birth_place_adcode: str | None = None birth_place_level: Literal["county", "city"] | None = None time_confidence: Literal["exact", "approximate", "unknown", "rectified"] class Config: extra = "forbid" class ResolvedLocationResponse(BaseModel): lat: float lng: float timezone: str class Config: extra = "forbid" class CreateBirthProfileResponse(BaseModel): profile_id: str resolved_location: ResolvedLocationResponse class Config: extra = "forbid" class CalculationProfileRequest(BaseModel): ephemeris: Literal["DE440", "DE441"] = "DE440" zodiac: Literal["tropical"] = "tropical" house_system: Literal["whole_sign", "equal", "porphyry", "placidus"] = "placidus" orb_profile: str = "western_default_v1" position_type: Literal["apparent", "astrometric"] = "apparent" ecliptic_epoch: Literal["date", "J2000"] = "date" class Config: extra = "forbid" class CreateNatalChartRequest(BaseModel): profile_id: str calculation_profile: CalculationProfileRequest class Config: extra = "forbid" class CreateChartResponse(BaseModel): chart_id: str chart_json: dict class Config: extra = "forbid" class RenderInputResponse(BaseModel): points: dict houses: list aspects: list labels: dict = Field(default_factory=lambda: {"language": "zh-CN"}) class Config: extra = "forbid" class ValidateChartResponse(BaseModel): status: str max_delta_arcsec: float | None = None warnings: list[str] = Field(default_factory=list) report: dict | None = None class Config: extra = "forbid"