""" Pydantic схемы для API Embedding сервиса. """ from typing import Any, Dict, Optional from pydantic import BaseModel, Field # ============================================================================= # Запросы # ============================================================================= class ScoreRequest(BaseModel): """Запрос на расчет скора.""" text: str = Field(..., min_length=1, description="Текст поста для оценки") model_config = { "json_schema_extra": { "example": { "text": "Это пример текста поста для оценки скоринга" } } } class ExampleRequest(BaseModel): """Запрос на добавление примера.""" text: str = Field(..., min_length=1, description="Текст примера") model_config = { "json_schema_extra": { "example": { "text": "Это пример опубликованного/отклоненного поста" } } } # ============================================================================= # Ответы # ============================================================================= class ScoreMetadata(BaseModel): """Метаданные результата скоринга.""" positive_examples: int = Field(..., description="Количество положительных примеров") negative_examples: int = Field(..., description="Количество отрицательных примеров") model: str = Field(..., description="Название модели") timestamp: int = Field(..., description="Время расчета (unix timestamp)") class ScoreResponse(BaseModel): """Ответ с результатом скоринга.""" rag_score: float = Field(..., ge=0.0, le=1.0, description="Основной скор (neg/pos формула)") rag_confidence: float = Field(..., ge=0.0, le=1.0, description="Уверенность в оценке") rag_score_pos_only: float = Field(..., ge=0.0, le=1.0, description="Скор только по положительным примерам") meta: ScoreMetadata = Field(..., description="Метаданные") model_config = { "json_schema_extra": { "example": { "rag_score": 0.7523, "rag_confidence": 0.85, "rag_score_pos_only": 0.6891, "meta": { "positive_examples": 500, "negative_examples": 350, "model": "sentence-transformers/all-MiniLM-L12-v2", "timestamp": 1706270000 } } } } class ExampleResponse(BaseModel): """Ответ на добавление примера.""" success: bool = Field(..., description="Успешность добавления") message: str = Field(..., description="Сообщение о результате") positive_count: int = Field(..., description="Текущее количество положительных примеров") negative_count: int = Field(..., description="Текущее количество отрицательных примеров") model_config = { "json_schema_extra": { "example": { "success": True, "message": "Положительный пример добавлен", "positive_count": 501, "negative_count": 350 } } } class VectorStoreStats(BaseModel): """Статистика хранилища векторов.""" positive_count: int = Field(..., description="Количество положительных примеров") negative_count: int = Field(..., description="Количество отрицательных примеров") total_count: int = Field(..., description="Общее количество примеров") vector_dim: int = Field(..., description="Размерность векторов") max_examples: int = Field(..., description="Максимальное количество примеров") class StatsResponse(BaseModel): """Ответ со статистикой сервиса.""" model_name: str = Field(..., description="Название модели") model_loaded: bool = Field(..., description="Загружена ли модель") device: Optional[str] = Field(None, description="Устройство (cpu/cuda)") vector_store: VectorStoreStats = Field(..., description="Статистика хранилища векторов") model_config = { "json_schema_extra": { "example": { "model_name": "sentence-transformers/all-MiniLM-L12-v2", "model_loaded": True, "device": "cpu", "vector_store": { "positive_count": 500, "negative_count": 350, "total_count": 850, "vector_dim": 384, "max_examples": 10000 } } } } class WarmupResponse(BaseModel): """Ответ на прогрев модели.""" success: bool = Field(..., description="Успешность загрузки") model_loaded: bool = Field(..., description="Загружена ли модель") message: str = Field(..., description="Сообщение о результате") model_config = { "json_schema_extra": { "example": { "success": True, "model_loaded": True, "message": "Модель успешно загружена" } } } class ErrorResponse(BaseModel): """Ответ с ошибкой.""" detail: str = Field(..., description="Описание ошибки") error_type: str = Field(..., description="Тип ошибки") model_config = { "json_schema_extra": { "example": { "detail": "Недостаточно примеров для расчета скора", "error_type": "InsufficientExamplesError" } } } class HealthResponse(BaseModel): """Ответ проверки здоровья сервиса.""" status: str = Field(..., description="Статус сервиса") model_loaded: bool = Field(..., description="Загружена ли модель") version: str = Field(..., description="Версия сервиса") model_config = { "json_schema_extra": { "example": { "status": "healthy", "model_loaded": True, "version": "0.1.0" } } } class ScoringParamsResponse(BaseModel): """Ответ с текущими параметрами формулы расчета score.""" score_multiplier: float = Field( ..., description=( "Множитель для масштабирования разницы в скорах. " "Используется в формуле: score = (diff * score_multiplier + 1) / 2, " "где diff = avg_pos - avg_neg (разница средних сходств топ-k примеров). " "Чем больше значение, тем сильнее влияние разницы между положительными и отрицательными примерами на итоговый score. " "Рекомендуемое значение: 5.0" ) ) k: int = Field( ..., description=( "Количество ближайших примеров для расчета среднего сходства. " "Алгоритм берет топ-k самых похожих примеров из каждого типа (положительные/отрицательные) " "и вычисляет среднее косинусное сходство. " "Меньшее значение k делает алгоритм более чувствительным к различиям, но может быть менее стабильным. " "Рекомендуемое значение: 3" ) ) model_config = { "json_schema_extra": { "example": { "score_multiplier": 5.0, "k": 3 } } } class UpdateScoringParamsRequest(BaseModel): """Запрос на обновление параметров формулы расчета score.""" score_multiplier: Optional[float] = Field( None, gt=0, description=( "Множитель для масштабирования разницы в скорах. " "Используется в формуле: score = (diff * score_multiplier + 1) / 2, " "где diff = avg_pos - avg_neg (разница средних сходств топ-k примеров). " "Чем больше значение, тем сильнее влияние разницы между положительными и отрицательными примерами на итоговый score. " "Должен быть > 0. Рекомендуемое значение: 5.0" ) ) k: Optional[int] = Field( None, ge=1, description=( "Количество ближайших примеров для расчета среднего сходства. " "Алгоритм берет топ-k самых похожих примеров из каждого типа (положительные/отрицательные) " "и вычисляет среднее косинусное сходство. " "Меньшее значение k делает алгоритм более чувствительным к различиям, но может быть менее стабильным. " "Должно быть >= 1. Рекомендуемое значение: 3" ) ) model_config = { "json_schema_extra": { "example": { "score_multiplier": 5.0, "k": 3 } } }