Spaces:
Runtime error
Runtime error
| from __future__ import annotations | |
| from typing import Any | |
| from schemas.wc_kxl_dynamic import FeptEscalacao, FeptTitularesEstruturados | |
| POSITION_LINE = { | |
| "G": "goleiro", | |
| "D": "defesa", | |
| "M": "meio", | |
| "F": "ataque", | |
| } | |
| TOURNAMENT_PRIORITY = ( | |
| "world-championship", | |
| "european-championship", | |
| "copa-america", | |
| "international-friendly", | |
| "world-championship-qual", | |
| "uefa-nations-league", | |
| "conmebol-nations-league", | |
| "laliga", | |
| "premier-league", | |
| "bundesliga", | |
| "serie-a", | |
| "ligue-1", | |
| "brasileirao", | |
| "eredivisie", | |
| "primeira-liga", | |
| ) | |
| def _line_from_position(position: str | None) -> str: | |
| key = (position or "M").strip().upper()[:1] | |
| return POSITION_LINE.get(key, "meio") | |
| def _lineup_rating(entry: dict[str, Any]) -> float | None: | |
| for key in ("rating", "averageRating"): | |
| value = entry.get(key) | |
| if value is not None: | |
| return float(value) | |
| stats = entry.get("statistics") or {} | |
| value = stats.get("rating") | |
| if value is not None: | |
| return float(value) | |
| return None | |
| def _season_priority(season_row: dict[str, Any]) -> tuple[int, int, float]: | |
| tournament = season_row.get("uniqueTournament") or {} | |
| slug = str(tournament.get("slug") or "").lower() | |
| priority = len(TOURNAMENT_PRIORITY) | |
| for idx, token in enumerate(TOURNAMENT_PRIORITY): | |
| if token in slug: | |
| priority = idx | |
| break | |
| stats = season_row.get("statistics") or {} | |
| count_rating = int(stats.get("countRating") or 0) | |
| rating = float(stats.get("rating") or 0.0) | |
| return priority, -count_rating, -rating | |
| def pick_player_rating_from_statistics(seasons: list[dict[str, Any]]) -> float | None: | |
| candidates: list[tuple[tuple[int, int, float], float]] = [] | |
| for row in seasons: | |
| stats = row.get("statistics") or {} | |
| rating = stats.get("rating") | |
| count_rating = stats.get("countRating") or 0 | |
| if rating is None or int(count_rating) < 3: | |
| continue | |
| candidates.append((_season_priority(row), float(rating))) | |
| if not candidates: | |
| return None | |
| candidates.sort(key=lambda item: item[0]) | |
| return candidates[0][1] | |
| def resolve_player_rating( | |
| entry: dict[str, Any], | |
| *, | |
| rating_cache: dict[int, float | None], | |
| fetch_statistics, | |
| ) -> float | None: | |
| rating = _lineup_rating(entry) | |
| if rating is not None: | |
| return rating | |
| player = entry.get("player") or {} | |
| player_id = player.get("id") | |
| if player_id is None: | |
| return None | |
| pid = int(player_id) | |
| if pid in rating_cache: | |
| return rating_cache[pid] | |
| seasons = fetch_statistics(pid) | |
| rating_cache[pid] = pick_player_rating_from_statistics(seasons) | |
| return rating_cache[pid] | |
| def _player_payload(entry: dict[str, Any], rating: float | None) -> dict[str, Any]: | |
| player = entry.get("player") or {} | |
| position = entry.get("position") or player.get("position") | |
| payload = { | |
| "nome": player.get("shortName") or player.get("name") or "Desconhecido", | |
| "posicao": position, | |
| } | |
| if rating is not None: | |
| payload["nota_sofascore"] = round(rating, 2) | |
| return payload | |
| def map_side_to_structured( | |
| side_block: dict[str, Any], | |
| *, | |
| rating_cache: dict[int, float | None], | |
| fetch_statistics, | |
| ) -> FeptTitularesEstruturados: | |
| players = [ | |
| entry | |
| for entry in (side_block.get("players") or []) | |
| if entry.get("substitute") is False | |
| ] | |
| goleiro = None | |
| defensores: list[dict] = [] | |
| meio_campistas: list[dict] = [] | |
| atacantes: list[dict] = [] | |
| for entry in players: | |
| player = entry.get("player") or {} | |
| position = entry.get("position") or player.get("position") | |
| line = _line_from_position(position) | |
| rating = resolve_player_rating( | |
| entry, | |
| rating_cache=rating_cache, | |
| fetch_statistics=fetch_statistics, | |
| ) | |
| payload = _player_payload(entry, rating) | |
| if line == "goleiro" and goleiro is None: | |
| goleiro = payload | |
| elif line == "defesa": | |
| defensores.append(payload) | |
| elif line == "meio": | |
| meio_campistas.append(payload) | |
| else: | |
| atacantes.append(payload) | |
| return FeptTitularesEstruturados( | |
| goleiro=goleiro, | |
| defensores=defensores, | |
| meio_campistas=meio_campistas, | |
| atacantes=atacantes, | |
| ) | |
| def map_side_bench_players( | |
| side_block: dict[str, Any], | |
| *, | |
| rating_cache: dict[int, float | None], | |
| fetch_statistics, | |
| ) -> list[dict[str, Any]]: | |
| """Reservas do jogo (substitute=true) com nota quando disponível.""" | |
| bench: list[dict[str, Any]] = [] | |
| for entry in side_block.get("players") or []: | |
| if entry.get("substitute") is not True: | |
| continue | |
| player = entry.get("player") or {} | |
| position = entry.get("position") or player.get("position") | |
| rating = resolve_player_rating( | |
| entry, | |
| rating_cache=rating_cache, | |
| fetch_statistics=fetch_statistics, | |
| ) | |
| payload = _player_payload(entry, rating) | |
| payload["linha"] = _line_from_position(position) | |
| bench.append(payload) | |
| return bench | |
| def map_lineups_bench( | |
| lineups: dict[str, Any], | |
| *, | |
| home_is_event_home: bool, | |
| fetch_statistics, | |
| rating_cache: dict[int, float | None] | None = None, | |
| ) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: | |
| cache = rating_cache if rating_cache is not None else {} | |
| home_block = lineups.get("home") or {} | |
| away_block = lineups.get("away") or {} | |
| if home_is_event_home: | |
| mandante_block, visitante_block = home_block, away_block | |
| else: | |
| mandante_block, visitante_block = away_block, home_block | |
| return ( | |
| map_side_bench_players( | |
| mandante_block, | |
| rating_cache=cache, | |
| fetch_statistics=fetch_statistics, | |
| ), | |
| map_side_bench_players( | |
| visitante_block, | |
| rating_cache=cache, | |
| fetch_statistics=fetch_statistics, | |
| ), | |
| ) | |
| def map_lineups_to_fept( | |
| lineups: dict[str, Any], | |
| *, | |
| home_is_event_home: bool, | |
| fetch_statistics, | |
| rating_cache: dict[int, float | None] | None = None, | |
| ) -> FeptEscalacao: | |
| cache = rating_cache if rating_cache is not None else {} | |
| home_block = lineups.get("home") or {} | |
| away_block = lineups.get("away") or {} | |
| if home_is_event_home: | |
| mandante_block, visitante_block = home_block, away_block | |
| else: | |
| mandante_block, visitante_block = away_block, home_block | |
| return FeptEscalacao( | |
| esquema_mandante=mandante_block.get("formation"), | |
| esquema_visitante=visitante_block.get("formation"), | |
| mandante_titulares_notas=map_side_to_structured( | |
| mandante_block, | |
| rating_cache=cache, | |
| fetch_statistics=fetch_statistics, | |
| ), | |
| visitante_titulares_notas=map_side_to_structured( | |
| visitante_block, | |
| rating_cache=cache, | |
| fetch_statistics=fetch_statistics, | |
| ), | |
| ) | |