Initial commit

This commit is contained in:
2026-02-01 09:31:38 +01:00
commit e02db93960
4396 changed files with 1511612 additions and 0 deletions

View 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",
]

View 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

View 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"
}
}
}

View 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]

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

View 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"
}
}
}

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

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

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

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

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

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

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

View 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

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