"""Account snapshots with an explicit local daily simulation allowance.""" from datetime import datetime from zoneinfo import ZoneInfo from .alphas import number LOCAL_DAILY_SIMULATION_LIMIT = 10_000 def daily_activity(raw, today, daily_limit=None): """Read recordset columns by schema; missing dates are not reported as zero usage.""" recordset = raw.get("records", {}) if not isinstance(recordset, dict): raise ValueError("Invalid activity recordset") schema = recordset.get("schema", {}) if not isinstance(schema, dict): raise ValueError("Invalid activity schema") properties, rows = schema.get("properties", []), recordset.get("records", []) if not isinstance(properties, list) or not isinstance(rows, list): raise ValueError("Invalid activity records") names = [p.get("name") if isinstance(p, dict) else p for p in properties] count = None if "date" in names and "value" in names: for row in rows: if isinstance(row, list) and len(row) >= len(names) and row[names.index("date")] == today: count = number(row[names.index("value")]) result = { "today": count, "limit": daily_limit, "remaining": max(0, daily_limit - count) if daily_limit is not None and count is not None else None, } for key in ("yesterday", "total"): period = raw.get(key) result[key] = number(period.get("value")) if isinstance(period, dict) else None if key == "yesterday": result["yesterday_date"] = period.get("end") if isinstance(period, dict) else None # The allowance is a user-chosen local budget, not a platform quota. # Missing activity must not imply that the whole daily budget is available. return result def usage_snapshot(data, errors, at=None): today = (at or datetime.now(ZoneInfo("America/New_York"))).date().isoformat() activities, errors = {}, dict(errors) for key in ("simulations", "submissions"): if key in data: try: activities[key] = daily_activity( data[key], today, daily_limit=LOCAL_DAILY_SIMULATION_LIMIT if key == "simulations" else None, ) except ValueError: errors[key] = "平台用量数据格式无法识别" return { "date": today, "timezone": "America/New_York", **activities, "alphas": { key: number(data.get("alphas", {}).get(key)) for key in ("unsubmitted", "active", "decommissioned") }, "errors": errors, }