amarorn / pipelines /current_round.py
beAnalytic's picture
feat: sync main with feature/superbet-live-inplay
16c19b8 verified
Raw
History Blame Contribute Delete
5.05 kB
import json
from datetime import datetime, timezone
from hashlib import sha256
from pathlib import Path
import pandas as pd
import structlog
from ingest.fixtures.store import load_fixtures
from models.bolao_predictor import get_predictor
from pipelines.gold import build_gold_for_match, save_gold
from pipelines.silver import load_silver
logger = structlog.get_logger()
ROUNDS_DIR = Path("data/rounds")
def _make_match_id(home: str, away: str, round_number: int) -> str:
key = f"live|{round_number}|{home}|{away}"
return sha256(key.encode()).hexdigest()[:16]
def load_round_schedule(path: Path | None = None) -> dict:
schedule_path = path or ROUNDS_DIR / "current.json"
if not schedule_path.exists():
raise FileNotFoundError(
f"Arquivo de rodada não encontrado: {schedule_path}. "
"Edite data/rounds/current.json com os jogos da rodada."
)
return json.loads(schedule_path.read_text(encoding="utf-8"))
def schedule_to_matches(schedule: dict) -> list[dict]:
season = schedule.get("season", datetime.now().year)
competition = schedule.get("competition", "Brasileirão")
round_number = schedule["round"]
matches = []
for game in schedule["matches"]:
home = game["home_team"]
away = game["away_team"]
match_date = game.get("match_date")
if match_date:
match_date = pd.to_datetime(match_date, utc=True).to_pydatetime()
else:
match_date = datetime.now(timezone.utc)
matches.append({
"match_id": _make_match_id(home, away, round_number),
"home_team": home,
"away_team": away,
"round_number": round_number,
"competition": competition,
"match_date": match_date,
"season": season,
"label": None,
})
return matches
def predict_round(
schedule_path: Path | None = None,
save: bool = True,
) -> list[dict]:
schedule = load_round_schedule(schedule_path)
matches = schedule_to_matches(schedule)
silver_df = load_silver()
fixtures_df = load_fixtures()
results = []
contexts = []
for m in matches:
context = build_gold_for_match(
match_id=m["match_id"],
home_team=m["home_team"],
away_team=m["away_team"],
round_number=m["round_number"],
competition=m["competition"],
match_date=m["match_date"],
silver_df=silver_df,
season=m.get("season"),
fixtures_df=fixtures_df if not fixtures_df.empty else None,
live_mode=True,
)
result = get_predictor().predict(context)
entry = {
"match_id": context.match_id,
"home_team": context.home_team,
"away_team": context.away_team,
"round_number": context.round_number,
"prediction": result.prediction,
"confidence": round(result.confidence, 2),
"reason": result.reason,
"probabilities": {k: round(v, 4) for k, v in result.probabilities.items()},
"model_source": result.model_source,
"news_count": context.features.news_count_home + context.features.news_count_away,
"home_position": context.features.home_position,
"away_position": context.features.away_position,
}
results.append(entry)
contexts.append(context)
if save:
save_gold(contexts, suffix=f"rodada_{schedule['round']}_live")
return results
def print_predictions(results: list[dict], schedule: dict) -> None:
print(f"\n{'='*60}")
print(f" RODADA {schedule['round']}{schedule.get('competition', 'Brasileirão')}")
print(f"{'='*60}\n")
print(f"{'Mandante':<18} {'Visitante':<18} {'Palpite':>7} {'Conf.':>6} {'Mod.':<8} Motivo")
print("-" * 78)
for r in results:
probs = r.get("probabilities") or {}
prob_str = f"1={probs.get('1', 0):.0%} X={probs.get('X', 0):.0%} 2={probs.get('2', 0):.0%}"
print(
f"{r['home_team']:<18} {r['away_team']:<18} "
f"{r['prediction']:>7} {r['confidence']:>5.0%} {r.get('model_source', '?'):<8} "
f"{r['reason']}"
)
print(f"{'':18} {'':18} {'':>7} {'':>6} {'':8} {prob_str}")
print()
def main() -> None:
import argparse
parser = argparse.ArgumentParser(description="Palpites da rodada atual (notícias + estatísticas)")
parser.add_argument("--schedule", type=Path, help="JSON da rodada (default: data/rounds/current.json)")
parser.add_argument("--json", action="store_true", help="Saída em JSON")
args = parser.parse_args()
schedule = load_round_schedule(args.schedule)
results = predict_round(schedule_path=args.schedule)
if args.json:
print(json.dumps({"round": schedule["round"], "predictions": results}, ensure_ascii=False, indent=2))
else:
print_predictions(results, schedule)
if __name__ == "__main__":
main()