Initial commit
This commit is contained in:
119
backend/app/schemas/__init__.py
Normal file
119
backend/app/schemas/__init__.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""Schémas Pydantic de l'application."""
|
||||
|
||||
from .user import UserBase, UserCreate, UserResponse
|
||||
from .tweet import (
|
||||
TweetBase,
|
||||
TweetCreate,
|
||||
TweetResponse,
|
||||
TweetListResponse,
|
||||
TweetStatsResponse
|
||||
)
|
||||
from .reddit_post import (
|
||||
RedditPostBase,
|
||||
RedditPostCreate,
|
||||
RedditPostResponse,
|
||||
RedditPostListResponse,
|
||||
RedditCommentBase,
|
||||
RedditCommentCreate,
|
||||
RedditCommentResponse,
|
||||
RedditCommentListResponse,
|
||||
RedditStatsResponse
|
||||
)
|
||||
from .rss_article import (
|
||||
RSSArticleBase,
|
||||
RSSArticleCreate,
|
||||
RSSArticleResponse,
|
||||
RSSArticleListResponse,
|
||||
RSSArticleStatsResponse
|
||||
)
|
||||
from .sentiment_score import (
|
||||
SentimentScoreBase,
|
||||
SentimentScoreCreate,
|
||||
SentimentScoreResponse,
|
||||
SentimentAnalysisRequest,
|
||||
SentimentAnalysisResponse,
|
||||
BatchSentimentAnalysisRequest,
|
||||
BatchSentimentAnalysisResponse,
|
||||
AggregatedSentimentMetrics,
|
||||
SentimentScoreListResponse
|
||||
)
|
||||
from .energy_score import (
|
||||
EnergyScoreBase,
|
||||
EnergyScoreCreate,
|
||||
EnergyScoreUpdate,
|
||||
EnergyScoreResponse,
|
||||
EnergyScoreCalculationRequest,
|
||||
EnergyScoreCalculationResponse,
|
||||
EnergyScoreListResponse,
|
||||
EnergyScoreQueryParams
|
||||
)
|
||||
from .match import (
|
||||
MatchBase,
|
||||
MatchCreate,
|
||||
MatchUpdate,
|
||||
MatchResponse,
|
||||
MatchListResponse,
|
||||
MatchStatsResponse
|
||||
)
|
||||
from .prediction import (
|
||||
PredictionBase,
|
||||
PredictionCreate,
|
||||
PredictionUpdate,
|
||||
PredictionResponse,
|
||||
PredictionListResponse,
|
||||
PredictionStatsResponse
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"UserBase",
|
||||
"UserCreate",
|
||||
"UserResponse",
|
||||
"TweetBase",
|
||||
"TweetCreate",
|
||||
"TweetResponse",
|
||||
"TweetListResponse",
|
||||
"TweetStatsResponse",
|
||||
"RedditPostBase",
|
||||
"RedditPostCreate",
|
||||
"RedditPostResponse",
|
||||
"RedditPostListResponse",
|
||||
"RedditCommentBase",
|
||||
"RedditCommentCreate",
|
||||
"RedditCommentResponse",
|
||||
"RedditCommentListResponse",
|
||||
"RedditStatsResponse",
|
||||
"RSSArticleBase",
|
||||
"RSSArticleCreate",
|
||||
"RSSArticleResponse",
|
||||
"RSSArticleListResponse",
|
||||
"RSSArticleStatsResponse",
|
||||
"SentimentScoreBase",
|
||||
"SentimentScoreCreate",
|
||||
"SentimentScoreResponse",
|
||||
"SentimentAnalysisRequest",
|
||||
"SentimentAnalysisResponse",
|
||||
"BatchSentimentAnalysisRequest",
|
||||
"BatchSentimentAnalysisResponse",
|
||||
"AggregatedSentimentMetrics",
|
||||
"SentimentScoreListResponse",
|
||||
"EnergyScoreBase",
|
||||
"EnergyScoreCreate",
|
||||
"EnergyScoreUpdate",
|
||||
"EnergyScoreResponse",
|
||||
"EnergyScoreCalculationRequest",
|
||||
"EnergyScoreCalculationResponse",
|
||||
"EnergyScoreListResponse",
|
||||
"EnergyScoreQueryParams",
|
||||
"MatchBase",
|
||||
"MatchCreate",
|
||||
"MatchUpdate",
|
||||
"MatchResponse",
|
||||
"MatchListResponse",
|
||||
"MatchStatsResponse",
|
||||
"PredictionBase",
|
||||
"PredictionCreate",
|
||||
"PredictionUpdate",
|
||||
"PredictionResponse",
|
||||
"PredictionListResponse",
|
||||
"PredictionStatsResponse",
|
||||
]
|
||||
37
backend/app/schemas/auth.py
Normal file
37
backend/app/schemas/auth.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
Pydantic schemas for authentication.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
"""Schema pour la requête de connexion"""
|
||||
email: EmailStr = Field(..., description="Email de l'utilisateur")
|
||||
password: str = Field(..., min_length=1, description="Mot de passe de l'utilisateur")
|
||||
|
||||
|
||||
class RegisterRequest(BaseModel):
|
||||
"""Schema pour la requête d'inscription"""
|
||||
email: EmailStr = Field(..., description="Email de l'utilisateur")
|
||||
password: str = Field(..., min_length=8, description="Mot de passe (min 8 caractères)")
|
||||
name: Optional[str] = Field(None, description="Nom de l'utilisateur (optionnel)")
|
||||
referral_code: Optional[str] = Field(None, description="Code de parrainage (optionnel)")
|
||||
|
||||
|
||||
class AuthResponse(BaseModel):
|
||||
"""Schema pour la réponse d'authentification"""
|
||||
data: dict
|
||||
meta: dict
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ErrorResponse(BaseModel):
|
||||
"""Schema pour les réponses d'erreur"""
|
||||
error: dict
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
191
backend/app/schemas/backtesting.py
Normal file
191
backend/app/schemas/backtesting.py
Normal file
@@ -0,0 +1,191 @@
|
||||
"""
|
||||
Backtesting Schemas.
|
||||
|
||||
Pydantic schemas for validating and serializing backtesting API requests and responses.
|
||||
"""
|
||||
|
||||
from typing import List, Optional, Dict, Any
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class BacktestingRequest(BaseModel):
|
||||
"""Request schema for running backtesting."""
|
||||
|
||||
leagues: Optional[List[str]] = Field(
|
||||
None,
|
||||
description="List of leagues to filter by (e.g., ['Ligue 1', 'Premier League'])",
|
||||
example=["Ligue 1", "Premier League"]
|
||||
)
|
||||
|
||||
start_date: Optional[str] = Field(
|
||||
None,
|
||||
description="Start date for filtering matches (ISO 8601 format)",
|
||||
example="2025-01-01T00:00:00Z"
|
||||
)
|
||||
|
||||
end_date: Optional[str] = Field(
|
||||
None,
|
||||
description="End date for filtering matches (ISO 8601 format)",
|
||||
example="2025-12-31T23:59:59Z"
|
||||
)
|
||||
|
||||
export_format: Optional[str] = Field(
|
||||
None,
|
||||
description="Export format for results: 'json', 'csv', or 'html'",
|
||||
example="html"
|
||||
)
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"leagues": ["Ligue 1", "Premier League"],
|
||||
"start_date": "2025-01-01T00:00:00Z",
|
||||
"end_date": "2025-12-31T23:59:59Z",
|
||||
"export_format": "html"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MatchResultSchema(BaseModel):
|
||||
"""Schema for single match backtesting result."""
|
||||
|
||||
match_id: int
|
||||
league: Optional[str] = None
|
||||
date: Optional[str] = None
|
||||
home_team: str
|
||||
away_team: str
|
||||
home_energy: float
|
||||
away_energy: float
|
||||
prediction: Dict[str, Any]
|
||||
actual_winner: str
|
||||
correct: bool
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class LeagueMetricsSchema(BaseModel):
|
||||
"""Schema for league-specific metrics."""
|
||||
|
||||
total: int
|
||||
correct: int
|
||||
accuracy: float
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ValidationThresholdsSchema(BaseModel):
|
||||
"""Schema for validation thresholds."""
|
||||
|
||||
validated: float
|
||||
alert: float
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class BacktestingData(BaseModel):
|
||||
"""Schema for backtesting result data."""
|
||||
|
||||
total_matches: int
|
||||
correct_predictions: int
|
||||
incorrect_predictions: int
|
||||
accuracy: float
|
||||
status: str
|
||||
results: List[MatchResultSchema]
|
||||
metrics_by_league: Dict[str, LeagueMetricsSchema]
|
||||
timestamp: str
|
||||
validation_thresholds: ValidationThresholdsSchema
|
||||
export: Optional[Dict[str, Any]] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class BacktestingResponse(BaseModel):
|
||||
"""Response schema for backtesting API."""
|
||||
|
||||
data: BacktestingData
|
||||
meta: Dict[str, Any]
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"data": {
|
||||
"total_matches": 100,
|
||||
"correct_predictions": 65,
|
||||
"incorrect_predictions": 35,
|
||||
"accuracy": 65.0,
|
||||
"status": "VALIDATED",
|
||||
"results": [
|
||||
{
|
||||
"match_id": 1,
|
||||
"league": "Ligue 1",
|
||||
"date": "2025-01-15T20:00:00Z",
|
||||
"home_team": "PSG",
|
||||
"away_team": "OM",
|
||||
"home_energy": 65.0,
|
||||
"away_energy": 45.0,
|
||||
"prediction": {
|
||||
"confidence": 40.0,
|
||||
"predicted_winner": "home",
|
||||
"home_energy": 65.0,
|
||||
"away_energy": 45.0
|
||||
},
|
||||
"actual_winner": "home",
|
||||
"correct": True
|
||||
}
|
||||
],
|
||||
"metrics_by_league": {
|
||||
"Ligue 1": {"total": 50, "correct": 33, "accuracy": 66.0},
|
||||
"Premier League": {"total": 50, "correct": 32, "accuracy": 64.0}
|
||||
},
|
||||
"timestamp": "2026-01-17T10:30:00Z",
|
||||
"validation_thresholds": {
|
||||
"validated": 60.0,
|
||||
"alert": 55.0
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"timestamp": "2026-01-17T10:30:00Z",
|
||||
"version": "v1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ErrorDetail(BaseModel):
|
||||
"""Schema for error details."""
|
||||
|
||||
code: str
|
||||
message: str
|
||||
details: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class BacktestingErrorResponse(BaseModel):
|
||||
"""Response schema for backtesting API errors."""
|
||||
|
||||
error: ErrorDetail
|
||||
meta: Dict[str, Any]
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"error": {
|
||||
"code": "NO_MATCHES_FOUND",
|
||||
"message": "No historical matches found matching the specified filters",
|
||||
"details": {
|
||||
"filters": {
|
||||
"leagues": ["Ligue 1"],
|
||||
"start_date": "2025-01-01T00:00:00Z",
|
||||
"end_date": "2025-12-31T23:59:59Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"timestamp": "2026-01-17T10:30:00Z",
|
||||
"request_id": "req-abc123"
|
||||
}
|
||||
}
|
||||
}
|
||||
60
backend/app/schemas/badge.py
Normal file
60
backend/app/schemas/badge.py
Normal file
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Schémas Pydantic pour les badges
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List, Optional, Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class BadgeBase(BaseModel):
|
||||
"""Schéma de base pour un badge"""
|
||||
name: str = Field(..., description="Nom du badge")
|
||||
description: str = Field(..., description="Description du badge")
|
||||
icon: str = Field(..., description="Icône ou emoji du badge")
|
||||
category: str = Field(..., description="Catégorie du badge (predictions, accuracy, engagement, social)")
|
||||
criteriaType: str = Field(..., description="Type de critère")
|
||||
criteriaValue: int = Field(..., description="Valeur du critère")
|
||||
criteriaDescription: str = Field(..., description="Description du critère")
|
||||
rarity: str = Field(..., description="Rareté du badge (common, rare, epic, legendary)")
|
||||
points: int = Field(..., description="Points attribués pour le badge")
|
||||
|
||||
|
||||
class BadgeResponse(BadgeBase):
|
||||
"""Réponse avec un badge"""
|
||||
id: int
|
||||
badgeId: str
|
||||
createdAt: str
|
||||
unlocked: Optional[bool] = None # Indique si le badge est débloqué par l'utilisateur
|
||||
|
||||
|
||||
class BadgeListResponse(BaseModel):
|
||||
"""Réponse avec une liste de badges"""
|
||||
data: List[BadgeResponse]
|
||||
meta: Dict[str, Any]
|
||||
|
||||
|
||||
class UserBadgeResponse(BaseModel):
|
||||
"""Réponse avec un badge d'utilisateur"""
|
||||
id: int
|
||||
userId: int
|
||||
badgeId: int
|
||||
unlockedAt: str
|
||||
badge: Dict[str, Any]
|
||||
|
||||
|
||||
class UserBadgeListResponse(BaseModel):
|
||||
"""Réponse avec une liste de badges d'utilisateur"""
|
||||
data: Dict[str, Any]
|
||||
meta: Dict[str, Any]
|
||||
|
||||
|
||||
class BadgeUnlockRequest(BaseModel):
|
||||
"""Requête pour débloquer un badge"""
|
||||
userId: int = Field(..., description="ID de l'utilisateur")
|
||||
badgeId: str = Field(..., description="ID du badge à débloquer")
|
||||
|
||||
|
||||
class BadgeCheckResponse(BaseModel):
|
||||
"""Réponse après vérification des badges"""
|
||||
data: Dict[str, Any]
|
||||
meta: Dict[str, Any]
|
||||
91
backend/app/schemas/energy_score.py
Normal file
91
backend/app/schemas/energy_score.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
Pydantic schemas for energy scores.
|
||||
|
||||
This module defines request and response schemas for energy score operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class EnergyScoreBase(BaseModel):
|
||||
"""Base schema for energy score data."""
|
||||
match_id: int = Field(..., description="ID of the match")
|
||||
team_id: int = Field(..., description="ID of the team")
|
||||
score: float = Field(..., ge=0.0, le=100.0, description="Final energy score (0-100)")
|
||||
confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="Confidence level (0-1)")
|
||||
sources_used: List[str] = Field(default_factory=list, description="List of sources used")
|
||||
|
||||
|
||||
class EnergyScoreCreate(EnergyScoreBase):
|
||||
"""Schema for creating a new energy score."""
|
||||
twitter_score: Optional[float] = Field(None, description="Energy score from Twitter component")
|
||||
reddit_score: Optional[float] = Field(None, description="Energy score from Reddit component")
|
||||
rss_score: Optional[float] = Field(None, description="Energy score from RSS component")
|
||||
temporal_factor: Optional[float] = Field(None, description="Temporal weighting factor applied")
|
||||
twitter_weight: Optional[float] = Field(None, description="Adjusted weight for Twitter")
|
||||
reddit_weight: Optional[float] = Field(None, description="Adjusted weight for Reddit")
|
||||
rss_weight: Optional[float] = Field(None, description="Adjusted weight for RSS")
|
||||
|
||||
|
||||
class EnergyScoreUpdate(BaseModel):
|
||||
"""Schema for updating an energy score."""
|
||||
score: Optional[float] = Field(None, ge=0.0, le=100.0, description="Final energy score (0-100)")
|
||||
confidence: Optional[float] = Field(None, ge=0.0, le=1.0, description="Confidence level (0-1)")
|
||||
sources_used: Optional[List[str]] = Field(None, description="List of sources used")
|
||||
twitter_score: Optional[float] = Field(None, description="Energy score from Twitter component")
|
||||
reddit_score: Optional[float] = Field(None, description="Energy score from Reddit component")
|
||||
rss_score: Optional[float] = Field(None, description="Energy score from RSS component")
|
||||
temporal_factor: Optional[float] = Field(None, description="Temporal weighting factor applied")
|
||||
twitter_weight: Optional[float] = Field(None, description="Adjusted weight for Twitter")
|
||||
reddit_weight: Optional[float] = Field(None, description="Adjusted weight for Reddit")
|
||||
rss_weight: Optional[float] = Field(None, description="Adjusted weight for RSS")
|
||||
|
||||
|
||||
class EnergyScoreResponse(EnergyScoreCreate):
|
||||
"""Schema for energy score response."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
created_at: datetime = Field(..., description="Timestamp when energy score was calculated")
|
||||
updated_at: datetime = Field(..., description="Timestamp when energy score was last updated")
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class EnergyScoreCalculationRequest(BaseModel):
|
||||
"""Schema for requesting energy score calculation."""
|
||||
match_id: int = Field(..., description="ID of the match")
|
||||
team_id: int = Field(..., description="ID of the team")
|
||||
twitter_sentiments: Optional[List[dict]] = Field(None, description="List of Twitter sentiment scores")
|
||||
reddit_sentiments: Optional[List[dict]] = Field(None, description="List of Reddit sentiment scores")
|
||||
rss_sentiments: Optional[List[dict]] = Field(None, description="List of RSS sentiment scores")
|
||||
tweets_with_timestamps: Optional[List[dict]] = Field(None, description="List of tweets with timestamps")
|
||||
|
||||
|
||||
class EnergyScoreCalculationResponse(BaseModel):
|
||||
"""Schema for energy score calculation response."""
|
||||
score: float = Field(..., ge=0.0, le=100.0, description="Final energy score (0-100)")
|
||||
confidence: float = Field(..., ge=0.0, le=1.0, description="Confidence level (0-1)")
|
||||
sources_used: List[str] = Field(..., description="List of sources used")
|
||||
twitter_score: Optional[float] = Field(None, description="Energy score from Twitter component")
|
||||
reddit_score: Optional[float] = Field(None, description="Energy score from Reddit component")
|
||||
rss_score: Optional[float] = Field(None, description="Energy score from RSS component")
|
||||
temporal_factor: Optional[float] = Field(None, description="Temporal weighting factor applied")
|
||||
|
||||
|
||||
class EnergyScoreListResponse(BaseModel):
|
||||
"""Schema for a list of energy scores."""
|
||||
data: List[EnergyScoreResponse] = Field(..., description="List of energy scores")
|
||||
count: int = Field(..., description="Total number of energy scores")
|
||||
meta: dict = Field(default_factory=dict, description="Additional metadata")
|
||||
|
||||
|
||||
class EnergyScoreQueryParams(BaseModel):
|
||||
"""Schema for energy score query parameters."""
|
||||
match_id: Optional[int] = Field(None, description="Filter by match ID")
|
||||
team_id: Optional[int] = Field(None, description="Filter by team ID")
|
||||
min_score: Optional[float] = Field(None, ge=0.0, le=100.0, description="Filter by minimum score")
|
||||
max_score: Optional[float] = Field(None, ge=0.0, le=100.0, description="Filter by maximum score")
|
||||
min_confidence: Optional[float] = Field(None, ge=0.0, le=1.0, description="Filter by minimum confidence")
|
||||
source: Optional[str] = Field(None, description="Filter by source used")
|
||||
limit: int = Field(default=10, ge=1, le=100, description="Maximum number of results")
|
||||
offset: int = Field(default=0, ge=0, description="Offset for pagination")
|
||||
81
backend/app/schemas/leaderboard.py
Normal file
81
backend/app/schemas/leaderboard.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
Schema definitions for leaderboard API.
|
||||
|
||||
This module provides Pydantic models for leaderboard-related responses
|
||||
and requests.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class LeaderboardEntry(BaseModel):
|
||||
"""Represents a single entry in the leaderboard."""
|
||||
user_id: int
|
||||
username: str | None = None
|
||||
accuracy: float = Field(..., ge=0, le=100, description="Accuracy percentage (0-100)")
|
||||
predictions_count: int = Field(..., ge=0, description="Total number of predictions viewed")
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"user_id": 1,
|
||||
"username": "JohnDoe",
|
||||
"accuracy": 85.5,
|
||||
"predictions_count": 42
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PersonalRankData(BaseModel):
|
||||
"""Represents personal rank data for the current user."""
|
||||
rank: int = Field(..., ge=1, description="User's rank in the leaderboard")
|
||||
accuracy: float = Field(..., ge=0, le=100, description="User's accuracy percentage")
|
||||
predictions_count: int = Field(..., ge=0, description="User's total predictions viewed")
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"rank": 42,
|
||||
"accuracy": 75.5,
|
||||
"predictions_count": 25
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LeaderboardResponse(BaseModel):
|
||||
"""Response model for leaderboard endpoint."""
|
||||
data: list[LeaderboardEntry]
|
||||
personal_data: PersonalRankData | None = None
|
||||
meta: dict
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"data": [
|
||||
{
|
||||
"user_id": 1,
|
||||
"username": "JohnDoe",
|
||||
"accuracy": 95.5,
|
||||
"predictions_count": 100
|
||||
},
|
||||
{
|
||||
"user_id": 2,
|
||||
"username": "JaneSmith",
|
||||
"accuracy": 90.0,
|
||||
"predictions_count": 85
|
||||
}
|
||||
],
|
||||
"personal_data": {
|
||||
"rank": 42,
|
||||
"accuracy": 75.5,
|
||||
"predictions_count": 25
|
||||
},
|
||||
"meta": {
|
||||
"total": 2,
|
||||
"limit": 100,
|
||||
"timestamp": "2026-01-18T10:30:00Z",
|
||||
"version": "v1"
|
||||
}
|
||||
}
|
||||
}
|
||||
55
backend/app/schemas/match.py
Normal file
55
backend/app/schemas/match.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Pydantic schemas for matches.
|
||||
|
||||
This module defines request and response schemas for match-related operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class MatchBase(BaseModel):
|
||||
"""Base schema for match data."""
|
||||
home_team: str = Field(..., min_length=1, max_length=255, description="Name of the home team")
|
||||
away_team: str = Field(..., min_length=1, max_length=255, description="Name of the away team")
|
||||
date: datetime = Field(..., description="Match date and time")
|
||||
league: str = Field(..., min_length=1, max_length=255, description="League name")
|
||||
status: str = Field(..., min_length=1, max_length=50, description="Match status")
|
||||
|
||||
|
||||
class MatchCreate(MatchBase):
|
||||
"""Schema for creating a new match."""
|
||||
pass
|
||||
|
||||
|
||||
class MatchUpdate(BaseModel):
|
||||
"""Schema for updating a match."""
|
||||
home_team: Optional[str] = Field(None, min_length=1, max_length=255)
|
||||
away_team: Optional[str] = Field(None, min_length=1, max_length=255)
|
||||
date: Optional[datetime] = None
|
||||
league: Optional[str] = Field(None, min_length=1, max_length=255)
|
||||
status: Optional[str] = Field(None, min_length=1, max_length=50)
|
||||
|
||||
|
||||
class MatchResponse(MatchBase):
|
||||
"""Schema for match response."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class MatchListResponse(BaseModel):
|
||||
"""Schema for a list of matches."""
|
||||
data: list[MatchResponse]
|
||||
count: int = Field(..., description="Total number of matches")
|
||||
meta: dict = Field(default_factory=dict, description="Additional metadata")
|
||||
|
||||
|
||||
class MatchStatsResponse(BaseModel):
|
||||
"""Schema for match statistics."""
|
||||
total_matches: int = Field(..., description="Total number of matches")
|
||||
matches_by_league: dict = Field(..., description="Breakdown by league")
|
||||
matches_by_status: dict = Field(..., description="Breakdown by status")
|
||||
upcoming_matches: int = Field(..., description="Number of upcoming matches")
|
||||
completed_matches: int = Field(..., description="Number of completed matches")
|
||||
77
backend/app/schemas/prediction.py
Normal file
77
backend/app/schemas/prediction.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
Pydantic schemas for predictions.
|
||||
|
||||
This module defines request and response schemas for prediction-related operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional, Any
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class PredictionBase(BaseModel):
|
||||
"""Base schema for prediction data."""
|
||||
match_id: int = Field(..., description="Foreign key to matches table")
|
||||
energy_score: str = Field(..., min_length=1, max_length=50, description="Energy score for the prediction")
|
||||
confidence: str = Field(..., min_length=1, max_length=50, description="Confidence level of the prediction")
|
||||
predicted_winner: str = Field(..., min_length=1, max_length=255, description="Predicted winner team name")
|
||||
created_at: datetime = Field(..., description="Timestamp when prediction was created")
|
||||
|
||||
|
||||
class PredictionCreate(PredictionBase):
|
||||
"""Schema for creating a new prediction."""
|
||||
pass
|
||||
|
||||
|
||||
class PredictionUpdate(BaseModel):
|
||||
"""Schema for updating a prediction."""
|
||||
energy_score: Optional[str] = Field(None, min_length=1, max_length=50)
|
||||
confidence: Optional[str] = Field(None, min_length=1, max_length=50)
|
||||
predicted_winner: Optional[str] = Field(None, min_length=1, max_length=255)
|
||||
|
||||
|
||||
class MatchInfo(BaseModel):
|
||||
"""Schema for match information included in prediction response."""
|
||||
id: int = Field(..., description="Match ID")
|
||||
home_team: str = Field(..., description="Home team name")
|
||||
away_team: str = Field(..., description="Away team name")
|
||||
date: datetime = Field(..., description="Match date and time")
|
||||
league: str = Field(..., description="League name")
|
||||
status: str = Field(..., description="Match status")
|
||||
|
||||
|
||||
class PredictionResponse(BaseModel):
|
||||
"""Schema for prediction response with match details."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
match_id: int = Field(..., description="Foreign key to matches table")
|
||||
match: MatchInfo = Field(..., description="Match details")
|
||||
energy_score: str = Field(..., description="Energy score for the prediction")
|
||||
confidence: str = Field(..., description="Confidence level of the prediction")
|
||||
predicted_winner: str = Field(..., description="Predicted winner team name")
|
||||
created_at: datetime = Field(..., description="Timestamp when prediction was created")
|
||||
model_config = ConfigDict(from_attributes=False)
|
||||
|
||||
|
||||
class PredictionListMeta(BaseModel):
|
||||
"""Schema for pagination metadata."""
|
||||
total: int = Field(..., description="Total number of predictions matching filters")
|
||||
limit: int = Field(..., description="Number of predictions returned")
|
||||
offset: int = Field(..., description="Number of predictions skipped")
|
||||
timestamp: str = Field(..., description="ISO 8601 timestamp of response")
|
||||
version: str = Field(default="v1", description="API version")
|
||||
|
||||
|
||||
class PredictionListResponse(BaseModel):
|
||||
"""Schema for a list of predictions with standardized metadata."""
|
||||
data: list[PredictionResponse] = Field(..., description="List of predictions")
|
||||
meta: PredictionListMeta = Field(..., description="Pagination and metadata")
|
||||
|
||||
|
||||
class PredictionStatsResponse(BaseModel):
|
||||
"""Schema for prediction statistics."""
|
||||
total_predictions: int = Field(..., description="Total number of predictions")
|
||||
predictions_by_confidence: dict = Field(..., description="Breakdown by confidence level")
|
||||
predictions_by_energy_score: dict = Field(..., description="Breakdown by energy score")
|
||||
avg_confidence: float = Field(..., description="Average confidence level")
|
||||
unique_matches_predicted: int = Field(..., description="Number of unique matches with predictions")
|
||||
89
backend/app/schemas/public.py
Normal file
89
backend/app/schemas/public.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
Pydantic schemas for public API.
|
||||
|
||||
This module defines request and response schemas for public API endpoints.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional, Any
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class PublicMatchInfo(BaseModel):
|
||||
"""Schema for match information in public API."""
|
||||
id: int = Field(..., description="Match ID")
|
||||
home_team: str = Field(..., description="Home team name")
|
||||
away_team: str = Field(..., description="Away team name")
|
||||
date: str = Field(..., description="Match date and time (ISO 8601)")
|
||||
league: str = Field(..., description="League name")
|
||||
status: str = Field(..., description="Match status")
|
||||
|
||||
|
||||
class PublicPredictionResponse(BaseModel):
|
||||
"""Schema for prediction response in public API."""
|
||||
id: int = Field(..., description="Prediction ID")
|
||||
match_id: int = Field(..., description="Match ID")
|
||||
match: PublicMatchInfo = Field(..., description="Match details")
|
||||
energy_score: str = Field(..., description="Energy score for the prediction")
|
||||
confidence: str = Field(..., description="Confidence level of the prediction")
|
||||
predicted_winner: str = Field(..., description="Predicted winner team name")
|
||||
created_at: str = Field(..., description="Timestamp when prediction was created")
|
||||
|
||||
|
||||
class PublicMatchResponse(BaseModel):
|
||||
"""Schema for match response in public API."""
|
||||
id: int = Field(..., description="Match ID")
|
||||
home_team: str = Field(..., description="Home team name")
|
||||
away_team: str = Field(..., description="Away team name")
|
||||
date: str = Field(..., description="Match date and time (ISO 8601)")
|
||||
league: str = Field(..., description="League name")
|
||||
status: str = Field(..., description="Match status")
|
||||
|
||||
|
||||
class SuccessMeta(BaseModel):
|
||||
"""Schema for success response metadata."""
|
||||
total: Optional[int] = Field(None, description="Total number of items")
|
||||
limit: Optional[int] = Field(None, description="Number of items returned")
|
||||
offset: Optional[int] = Field(None, description="Number of items skipped")
|
||||
timestamp: str = Field(..., description="ISO 8601 timestamp of response")
|
||||
version: str = Field(default="v1", description="API version")
|
||||
|
||||
|
||||
class SuccessResponse(BaseModel):
|
||||
"""Schema for standardized success response."""
|
||||
data: Any = Field(..., description="Response data")
|
||||
meta: SuccessMeta = Field(..., description="Response metadata")
|
||||
|
||||
|
||||
class ErrorResponse(BaseModel):
|
||||
"""Schema for error response."""
|
||||
error: dict = Field(..., description="Error details")
|
||||
meta: dict = Field(..., description="Response metadata")
|
||||
|
||||
|
||||
class ErrorDetail(BaseModel):
|
||||
"""Schema for error detail."""
|
||||
code: str = Field(..., description="Error code")
|
||||
message: str = Field(..., description="Human-readable error message")
|
||||
details: Optional[dict] = Field(None, description="Additional error details")
|
||||
|
||||
|
||||
class ApiKeyResponse(BaseModel):
|
||||
"""Schema for API key response (includes plain key only on creation)."""
|
||||
id: int = Field(..., description="API key ID")
|
||||
user_id: int = Field(..., description="User ID")
|
||||
key_prefix: str = Field(..., description="First 8 characters of API key")
|
||||
is_active: bool = Field(..., description="Whether the key is active")
|
||||
rate_limit: int = Field(..., description="Rate limit per minute")
|
||||
last_used_at: Optional[str] = Field(None, description="Last usage timestamp")
|
||||
created_at: str = Field(..., description="Creation timestamp")
|
||||
api_key: Optional[str] = Field(None, description="Plain API key (only on creation)")
|
||||
|
||||
|
||||
class ApiStatsResponse(BaseModel):
|
||||
"""Schema for API usage statistics."""
|
||||
total_requests: int = Field(..., description="Total API requests made")
|
||||
requests_this_month: int = Field(..., description="Requests in current month")
|
||||
rate_limit: int = Field(..., description="Rate limit per minute")
|
||||
requests_remaining: int = Field(..., description="Requests remaining in rate limit window")
|
||||
79
backend/app/schemas/reddit_post.py
Normal file
79
backend/app/schemas/reddit_post.py
Normal file
@@ -0,0 +1,79 @@
|
||||
"""
|
||||
Pydantic schemas for Reddit posts and comments.
|
||||
|
||||
This module defines request and response schemas for Reddit-related operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from typing import List
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class RedditPostBase(BaseModel):
|
||||
"""Base schema for Reddit post data."""
|
||||
post_id: str = Field(..., description="Unique identifier from Reddit")
|
||||
title: str = Field(..., min_length=1, max_length=500, description="Post title")
|
||||
text: Optional[str] = Field(None, description="Post content")
|
||||
upvotes: int = Field(default=0, ge=0, description="Number of upvotes")
|
||||
created_at: datetime = Field(..., description="Timestamp when post was created")
|
||||
match_id: Optional[int] = Field(None, description="Foreign key to matches table")
|
||||
subreddit: str = Field(..., description="Subreddit name")
|
||||
source: str = Field(default="reddit", description="Source platform")
|
||||
|
||||
|
||||
class RedditPostCreate(RedditPostBase):
|
||||
"""Schema for creating a new Reddit post."""
|
||||
pass
|
||||
|
||||
|
||||
class RedditPostResponse(RedditPostBase):
|
||||
"""Schema for Reddit post response."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class RedditCommentBase(BaseModel):
|
||||
"""Base schema for Reddit comment data."""
|
||||
comment_id: str = Field(..., description="Unique identifier from Reddit")
|
||||
post_id: str = Field(..., description="Foreign key to posts_reddit table")
|
||||
text: str = Field(..., min_length=1, description="Comment content")
|
||||
upvotes: int = Field(default=0, ge=0, description="Number of upvotes")
|
||||
created_at: datetime = Field(..., description="Timestamp when comment was created")
|
||||
source: str = Field(default="reddit", description="Source platform")
|
||||
|
||||
|
||||
class RedditCommentCreate(RedditCommentBase):
|
||||
"""Schema for creating a new Reddit comment."""
|
||||
pass
|
||||
|
||||
|
||||
class RedditCommentResponse(RedditCommentBase):
|
||||
"""Schema for Reddit comment response."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class RedditPostListResponse(BaseModel):
|
||||
"""Schema for a list of Reddit posts."""
|
||||
data: list[RedditPostResponse]
|
||||
count: int = Field(..., description="Total number of posts")
|
||||
meta: dict = Field(default_factory=dict, description="Additional metadata")
|
||||
|
||||
|
||||
class RedditCommentListResponse(BaseModel):
|
||||
"""Schema for a list of Reddit comments."""
|
||||
data: list[RedditCommentResponse]
|
||||
count: int = Field(..., description="Total number of comments")
|
||||
meta: dict = Field(default_factory=dict, description="Additional metadata")
|
||||
|
||||
|
||||
class RedditStatsResponse(BaseModel):
|
||||
"""Schema for Reddit statistics."""
|
||||
total_posts: int = Field(..., description="Total number of Reddit posts")
|
||||
total_comments: int = Field(..., description="Total number of Reddit comments")
|
||||
posts_by_subreddit: dict = Field(..., description="Breakdown by subreddit")
|
||||
posts_by_match: dict = Field(..., description="Breakdown by match")
|
||||
avg_post_upvotes: float = Field(..., description="Average post upvotes")
|
||||
avg_comment_upvotes: float = Field(..., description="Average comment upvotes")
|
||||
46
backend/app/schemas/rss_article.py
Normal file
46
backend/app/schemas/rss_article.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Pydantic schemas for RSS articles.
|
||||
|
||||
This module defines request and response schemas for RSS article-related operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class RSSArticleBase(BaseModel):
|
||||
"""Base schema for RSS article data."""
|
||||
article_id: str = Field(..., description="Unique identifier from RSS feed")
|
||||
title: str = Field(..., min_length=1, max_length=500, description="Article title")
|
||||
content: Optional[str] = Field(None, description="Article content/description")
|
||||
published_at: datetime = Field(..., description="Timestamp when article was published")
|
||||
source_url: str = Field(..., min_length=1, max_length=1000, description="URL of RSS feed source")
|
||||
match_id: Optional[int] = Field(None, description="Foreign key to matches table")
|
||||
source: str = Field(default="rss", description="Source feed name")
|
||||
|
||||
|
||||
class RSSArticleCreate(RSSArticleBase):
|
||||
"""Schema for creating a new RSS article."""
|
||||
pass
|
||||
|
||||
|
||||
class RSSArticleResponse(RSSArticleBase):
|
||||
"""Schema for RSS article response."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class RSSArticleListResponse(BaseModel):
|
||||
"""Schema for a list of RSS articles."""
|
||||
data: list[RSSArticleResponse]
|
||||
count: int = Field(..., description="Total number of articles")
|
||||
meta: dict = Field(default_factory=dict, description="Additional metadata")
|
||||
|
||||
|
||||
class RSSArticleStatsResponse(BaseModel):
|
||||
"""Schema for RSS article statistics."""
|
||||
total_articles: int = Field(..., description="Total number of articles")
|
||||
articles_by_source: dict = Field(..., description="Breakdown by source feed")
|
||||
articles_by_match: dict = Field(..., description="Breakdown by match")
|
||||
77
backend/app/schemas/sentiment_score.py
Normal file
77
backend/app/schemas/sentiment_score.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
Pydantic schemas for sentiment scores.
|
||||
|
||||
This module defines request and response schemas for sentiment analysis operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class SentimentScoreBase(BaseModel):
|
||||
"""Base schema for sentiment score data."""
|
||||
entity_id: str = Field(..., description="Foreign key to the entity being analyzed")
|
||||
entity_type: str = Field(..., description="Type of entity ('tweet' or 'reddit_post')")
|
||||
score: float = Field(..., ge=-1.0, le=1.0, description="Overall compound sentiment score")
|
||||
sentiment_type: str = Field(..., description="Classification ('positive', 'negative', or 'neutral')")
|
||||
positive: float = Field(default=0.0, ge=0.0, le=1.0, description="Positive proportion score")
|
||||
negative: float = Field(default=0.0, ge=0.0, le=1.0, description="Negative proportion score")
|
||||
neutral: float = Field(default=0.0, ge=0.0, le=1.0, description="Neutral proportion score")
|
||||
|
||||
|
||||
class SentimentScoreCreate(SentimentScoreBase):
|
||||
"""Schema for creating a new sentiment score."""
|
||||
pass
|
||||
|
||||
|
||||
class SentimentScoreResponse(SentimentScoreBase):
|
||||
"""Schema for sentiment score response."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
created_at: datetime = Field(..., description="Timestamp when the sentiment was analyzed")
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class SentimentAnalysisRequest(BaseModel):
|
||||
"""Schema for requesting sentiment analysis."""
|
||||
text: str = Field(..., min_length=1, max_length=1000, description="Text to analyze")
|
||||
|
||||
|
||||
class SentimentAnalysisResponse(BaseModel):
|
||||
"""Schema for sentiment analysis response."""
|
||||
compound: float = Field(..., ge=-1.0, le=1.0, description="Overall compound score")
|
||||
positive: float = Field(..., ge=0.0, le=1.0, description="Positive proportion")
|
||||
negative: float = Field(..., ge=0.0, le=1.0, description="Negative proportion")
|
||||
neutral: float = Field(..., ge=0.0, le=1.0, description="Neutral proportion")
|
||||
sentiment: str = Field(..., description="Classification ('positive', 'negative', or 'neutral')")
|
||||
|
||||
|
||||
class BatchSentimentAnalysisRequest(BaseModel):
|
||||
"""Schema for requesting batch sentiment analysis."""
|
||||
texts: list[str] = Field(..., min_length=1, max_length=1000, description="List of texts to analyze")
|
||||
|
||||
|
||||
class BatchSentimentAnalysisResponse(BaseModel):
|
||||
"""Schema for batch sentiment analysis response."""
|
||||
results: list[SentimentAnalysisResponse] = Field(..., description="List of sentiment analysis results")
|
||||
total_count: int = Field(..., description="Total number of texts analyzed")
|
||||
|
||||
|
||||
class AggregatedSentimentMetrics(BaseModel):
|
||||
"""Schema for aggregated sentiment metrics."""
|
||||
total_count: int = Field(..., ge=0, description="Total number of sentiments")
|
||||
positive_count: int = Field(..., ge=0, description="Count of positive sentiments")
|
||||
negative_count: int = Field(..., ge=0, description="Count of negative sentiments")
|
||||
neutral_count: int = Field(..., ge=0, description="Count of neutral sentiments")
|
||||
positive_ratio: float = Field(..., ge=0.0, le=1.0, description="Ratio of positive sentiments")
|
||||
negative_ratio: float = Field(..., ge=0.0, le=1.0, description="Ratio of negative sentiments")
|
||||
neutral_ratio: float = Field(..., ge=0.0, le=1.0, description="Ratio of neutral sentiments")
|
||||
average_compound: float = Field(..., ge=-1.0, le=1.0, description="Average compound score")
|
||||
|
||||
|
||||
class SentimentScoreListResponse(BaseModel):
|
||||
"""Schema for a list of sentiment scores."""
|
||||
data: list[SentimentScoreResponse]
|
||||
count: int = Field(..., description="Total number of sentiment scores")
|
||||
meta: dict = Field(default_factory=dict, description="Additional metadata")
|
||||
48
backend/app/schemas/tweet.py
Normal file
48
backend/app/schemas/tweet.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
Pydantic schemas for tweets.
|
||||
|
||||
This module defines request and response schemas for tweet-related operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class TweetBase(BaseModel):
|
||||
"""Base schema for tweet data."""
|
||||
tweet_id: str = Field(..., description="Unique identifier from the source platform")
|
||||
text: str = Field(..., min_length=1, max_length=1000, description="Tweet content")
|
||||
created_at: datetime = Field(..., description="Timestamp when the tweet was created")
|
||||
retweet_count: int = Field(default=0, ge=0, description="Number of retweets")
|
||||
like_count: int = Field(default=0, ge=0, description="Number of likes")
|
||||
match_id: Optional[int] = Field(None, description="Foreign key to matches table")
|
||||
source: str = Field(default="twitter", description="Source platform (twitter, reddit, rss)")
|
||||
|
||||
|
||||
class TweetCreate(TweetBase):
|
||||
"""Schema for creating a new tweet."""
|
||||
pass
|
||||
|
||||
|
||||
class TweetResponse(TweetBase):
|
||||
"""Schema for tweet response."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class TweetListResponse(BaseModel):
|
||||
"""Schema for a list of tweets."""
|
||||
data: list[TweetResponse]
|
||||
count: int = Field(..., description="Total number of tweets")
|
||||
meta: dict = Field(default_factory=dict, description="Additional metadata")
|
||||
|
||||
|
||||
class TweetStatsResponse(BaseModel):
|
||||
"""Schema for tweet statistics."""
|
||||
total_tweets: int = Field(..., description="Total number of tweets")
|
||||
tweets_by_source: dict = Field(..., description="Breakdown by source platform")
|
||||
tweets_by_match: dict = Field(..., description="Breakdown by match")
|
||||
avg_retweet_count: float = Field(..., description="Average retweet count")
|
||||
avg_like_count: float = Field(..., description="Average like count")
|
||||
42
backend/app/schemas/user.py
Normal file
42
backend/app/schemas/user.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""Schémas Pydantic pour les utilisateurs."""
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class UserBase(BaseModel):
|
||||
"""Schéma de base pour un utilisateur."""
|
||||
email: EmailStr
|
||||
name: str = Field(..., min_length=1, max_length=100)
|
||||
|
||||
|
||||
class UserCreate(UserBase):
|
||||
"""Schéma pour la création d'un utilisateur."""
|
||||
password: str = Field(..., min_length=8, max_length=100)
|
||||
referral_code: Optional[str] = Field(None, description="Code de parrainage (optionnel)")
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
"""Schéma pour la mise à jour d'un utilisateur."""
|
||||
name: Optional[str] = Field(None, min_length=1, max_length=100)
|
||||
is_premium: Optional[bool] = Field(None, description="Statut Premium")
|
||||
|
||||
|
||||
class UserResponse(BaseModel):
|
||||
"""Schéma pour la réponse d'un utilisateur."""
|
||||
id: int
|
||||
email: EmailStr
|
||||
name: str
|
||||
is_premium: bool = False
|
||||
referral_code: Optional[str] = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class UserLoginRequest(BaseModel):
|
||||
"""Schéma pour la connexion d'un utilisateur."""
|
||||
email: EmailStr
|
||||
password: str
|
||||
75
backend/app/schemas/user_prediction.py
Normal file
75
backend/app/schemas/user_prediction.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Pydantic schemas for user_predictions.
|
||||
|
||||
This module defines request and response schemas for user prediction tracking operations.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional, Any
|
||||
|
||||
from pydantic import BaseModel, Field, ConfigDict
|
||||
|
||||
|
||||
class UserPredictionBase(BaseModel):
|
||||
"""Base schema for user prediction data."""
|
||||
user_id: int = Field(..., description="Foreign key to users table")
|
||||
prediction_id: int = Field(..., description="Foreign key to predictions table")
|
||||
viewed_at: datetime = Field(..., description="Timestamp when user viewed prediction")
|
||||
was_correct: Optional[bool] = Field(None, description="True if prediction was correct, False if incorrect, NULL if match not completed")
|
||||
|
||||
|
||||
class UserPredictionCreate(UserPredictionBase):
|
||||
"""Schema for creating a new user prediction record."""
|
||||
pass
|
||||
|
||||
|
||||
class UserPredictionUpdate(BaseModel):
|
||||
"""Schema for updating a user prediction record."""
|
||||
was_correct: Optional[bool] = Field(None, description="Update whether prediction was correct")
|
||||
|
||||
|
||||
class PredictionMatchInfo(BaseModel):
|
||||
"""Schema for match information included in user prediction response."""
|
||||
id: int = Field(..., description="Match ID")
|
||||
home_team: str = Field(..., description="Home team name")
|
||||
away_team: str = Field(..., description="Away team name")
|
||||
date: datetime = Field(..., description="Match date and time")
|
||||
league: str = Field(..., description="League name")
|
||||
status: str = Field(..., description="Match status")
|
||||
actual_winner: Optional[str] = Field(None, description="Actual winner when match is completed")
|
||||
|
||||
|
||||
class PredictionInfo(BaseModel):
|
||||
"""Schema for prediction information included in user prediction response."""
|
||||
id: int = Field(..., description="Prediction ID")
|
||||
match_id: int = Field(..., description="Match ID")
|
||||
energy_score: str = Field(..., description="Energy score")
|
||||
confidence: str = Field(..., description="Confidence level")
|
||||
predicted_winner: str = Field(..., description="Predicted winner")
|
||||
created_at: datetime = Field(..., description="Prediction creation time")
|
||||
|
||||
|
||||
class UserPredictionResponse(BaseModel):
|
||||
"""Schema for user prediction response with full details."""
|
||||
id: int = Field(..., description="Primary key")
|
||||
user_id: int = Field(..., description="User ID")
|
||||
prediction_id: int = Field(..., description="Prediction ID")
|
||||
viewed_at: datetime = Field(..., description="When user viewed prediction")
|
||||
was_correct: Optional[bool] = Field(None, description="True if prediction was correct")
|
||||
prediction: PredictionInfo = Field(..., description="Full prediction details")
|
||||
model_config = ConfigDict(from_attributes=False)
|
||||
|
||||
|
||||
class UserPredictionListResponse(BaseModel):
|
||||
"""Schema for a list of user predictions with metadata."""
|
||||
data: list[UserPredictionResponse] = Field(..., description="List of user predictions")
|
||||
meta: dict = Field(..., description="Metadata including totals")
|
||||
|
||||
|
||||
class UserStatsResponse(BaseModel):
|
||||
"""Schema for user statistics."""
|
||||
total_predictions_viewed: int = Field(..., description="Total number of predictions viewed by user")
|
||||
correct_predictions: int = Field(..., description="Number of correct predictions")
|
||||
incorrect_predictions: int = Field(..., description="Number of incorrect predictions")
|
||||
accuracy_rate: float = Field(..., description="Accuracy rate as percentage (0-100)")
|
||||
roi: float = Field(..., description="Return on Investment in EUR")
|
||||
Reference in New Issue
Block a user