"""Pydantic-модели для входных параметров и выходных результатов инструментов."""
from datetime import date
from typing import Literal
from pydantic import BaseModel, Field
class PaginationParams(BaseModel):
"""Базовая пагинация."""
limit: int = Field(default=20, ge=1, le=100, description="Количество результатов на странице")
offset: int = Field(default=0, ge=0, description="Смещение для пагинации")
class MetadataFilters(BaseModel):
"""Фильтры по метаданным, общие для всех инструментов поиска."""
deal_type: Literal["sale", "rent_long", "rent_short"] | None = Field(
default=None, description="Тип сделки"
)
city: str | None = Field(default=None, description="Город (украинский)")
district: str | None = Field(default=None, description="Район (украинский)")
rooms_count: int | None = Field(default=None, ge=0, description="Количество комнат")
min_price: float | None = Field(default=None, ge=0, description="Минимальная цена")
max_price: float | None = Field(default=None, ge=0, description="Максимальная цена")
currency: Literal["USD", "EUR", "UAH"] | None = Field(default=None, description="Валюта")
min_total_area: float | None = Field(
default=None, ge=0, description="Минимальная общая площадь (м²)"
)
max_total_area: float | None = Field(
default=None, ge=0, description="Максимальная общая площадь (м²)"
)
building_type: Literal["brick", "panel", "monolith", "gas_block", "wood"] | None = Field(
default=None, description="Тип постройки"
)
floor: int | None = Field(default=None, ge=0, description="Этаж")
listing_status: Literal["active", "sold", "rented", "removed", "archived"] | None = Field(
default=None, description="Статус объявления"
)
metro_station: str | None = Field(default=None, description="Станция метро (украинский)")
class SearchSimilarInput(BaseModel):
"""Входные параметры для векторного поиска."""
query: str = Field(..., description="Текстовый запрос на украинском языке для поиска по смыслу")
filters: MetadataFilters = Field(default_factory=MetadataFilters)
pagination: PaginationParams = Field(default_factory=PaginationParams)
min_similarity: float = Field(
default=0.7, ge=0.0, le=1.0, description="Минимальный порог косинусной близости"
)
class SearchMetadataInput(BaseModel):
"""Входные параметры для поиска по метаданным/FTS."""
query: str = Field(
..., description="Текстовый запрос на украинском языке для полнотекстового поиска"
)
filters: MetadataFilters = Field(default_factory=MetadataFilters)
pagination: PaginationParams = Field(default_factory=PaginationParams)
class GetListingInput(BaseModel):
"""Входные параметры для получения объявления по ID."""
listing_id: int = Field(..., ge=1, description="ID объявления")
class ListingResult(BaseModel):
"""Результат поиска — одно объявление."""
id: int
title: str
description: str | None = None
generated_description: str | None = None
price: float | None = None
currency: str | None = None
deal_type: str | None = None
city: str | None = None
district: str | None = None
rooms_count: int | None = None
total_area: float | None = None
living_area: float | None = None
kitchen_area: float | None = None
floor: int | None = None
floors_count: int | None = None
building_type: str | None = None
building_year: int | None = None
renovation_status: str | None = None
balcony_count: int | None = None
bathroom_type: str | None = None
parking_type: str | None = None
heating_type: str | None = None
layout_type: str | None = None
window_view: str | None = None
metro_station: str | None = None
metro_distance_type: str | None = None
metro_distance_meters: int | None = None
url_source: str | None = None
publish_date: date | None = None
images_count: int | None = None
contact_phone: str | None = None
listing_status: str | None = None
archived_at: date | None = None
created_at: date | None = None
updated_at: date | None = None
similarity_score: float | None = None # для векторного поиска
rank_score: float | None = None # для FTS
class SearchResult(BaseModel):
"""Результат поиска — список объявлений + мета."""
total: int = Field(description="Общее количество найденных записей")
limit: int
offset: int
listings: list[ListingResult]