Spaces:
Runtime error
Runtime error
| """Persistência simples de apostas abertas do usuário em JSON local.""" | |
| from __future__ import annotations | |
| import json | |
| from datetime import datetime | |
| from pathlib import Path | |
| from typing import Any | |
| from pydantic import BaseModel | |
| from config import settings | |
| _USER_BETS_FILE = Path(settings.lake_root) / "user_open_bets.json" | |
| class PickData(BaseModel): | |
| market: str | |
| outcome: str | |
| target_value: str | None = None | |
| class UserOpenBet(BaseModel): | |
| id: str | |
| event_name: str | |
| home_team: str | |
| away_team: str | |
| picks: list[PickData] | |
| stake: float | |
| odds_placed: float | |
| potential_return: float | |
| cashout_value: float | None = None | |
| ticket_code: str | None = None | |
| status: str = "open" | |
| source: str = "manual" | |
| captured_at: str = "" | |
| superbet_event_id: int | None = None | |
| user_id: str | None = None | |
| def model_post_init(self, __context: Any) -> None: | |
| if not self.captured_at: | |
| self.captured_at = datetime.now().isoformat() | |
| def _load_store() -> dict[str, Any]: | |
| if not _USER_BETS_FILE.exists(): | |
| return {"version": 1, "bets": []} | |
| return json.loads(_USER_BETS_FILE.read_text(encoding="utf-8")) | |
| def _save_store(store: dict[str, Any]) -> None: | |
| _USER_BETS_FILE.parent.mkdir(parents=True, exist_ok=True) | |
| _USER_BETS_FILE.write_text(json.dumps(store, ensure_ascii=False, indent=2), encoding="utf-8") | |
| def add_open_bet(ub_kwargs: dict[str, Any]) -> UserOpenBet: | |
| store = _load_store() | |
| ub = UserOpenBet(**ub_kwargs) | |
| store["bets"].append(ub.model_dump(mode="json")) | |
| _save_store(store) | |
| return ub | |
| def list_open_bets(user_id: str | None = None) -> list[UserOpenBet]: | |
| store = _load_store() | |
| bets = [UserOpenBet(**b) for b in store.get("bets", [])] | |
| if user_id: | |
| bets = [b for b in bets if b.user_id == user_id] | |
| return [b for b in bets if b.status == "open"] | |
| def find_open_bet(bet_id: str) -> UserOpenBet | None: | |
| store = _load_store() | |
| for b in store.get("bets", []): | |
| if b.get("id") == bet_id: | |
| return UserOpenBet(**b) | |
| return None | |
| def update_bet_status(bet_id: str, status: str) -> bool: | |
| store = _load_store() | |
| for b in store.get("bets", []): | |
| if b.get("id") == bet_id: | |
| b["status"] = status | |
| _save_store(store) | |
| return True | |
| return False | |
| def get_bets_for_event( | |
| home_team: str, | |
| away_team: str, | |
| *, | |
| status: str = "open", | |
| ) -> list[dict]: | |
| """Retorna apostas do evento filtradas por time, já deduplicadas. | |
| Deduplicação: mesmo stake + odds + market + outcome = duplicata de captura repetida. | |
| """ | |
| store = _load_store() | |
| all_bets = store.get("bets", []) | |
| home_lower = home_team.lower() | |
| away_lower = away_team.lower() | |
| relevant = [] | |
| for b in all_bets: | |
| if status and b.get("status") != status: | |
| continue | |
| event = (b.get("event_name") or "").lower() | |
| b_home = (b.get("home_team") or "").lower() | |
| b_away = (b.get("away_team") or "").lower() | |
| # Match flexível por substring nos times ou event_name | |
| match = ( | |
| (home_lower in b_home or home_lower in event) | |
| and (away_lower in b_away or away_lower in event) | |
| ) | |
| if match: | |
| relevant.append(b) | |
| # Deduplicar por (stake, odds, market, outcome) | |
| seen: set[tuple] = set() | |
| unique: list[dict] = [] | |
| for b in relevant: | |
| picks = b.get("picks") or [] | |
| key = ( | |
| b.get("stake"), | |
| b.get("odds_placed"), | |
| picks[0].get("market") if picks else "", | |
| picks[0].get("outcome") if picks else "", | |
| ) | |
| if key not in seen: | |
| seen.add(key) | |
| unique.append(b) | |
| return unique | |