Spaces:
Sleeping
Sleeping
File size: 6,487 Bytes
f4bf513 df1e49f f4bf513 2bd322b f4bf513 f83d2ce 2bd322b f4bf513 df1e49f 1c44fce f4bf513 df1e49f f4bf513 df1e49f f4bf513 fa1e508 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 7d4c042 f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f f4bf513 df1e49f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
"""
---------------------------------
Booster‑draft helper for Magic: The Gathering, built with Streamlit and ready
for Hugging Face Spaces deployment.
🆕 UI tweaks in this revision
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* **Set selection is now hidden** in an *expander* inside the sidebar—keeps the
layout clean.
* Added a **second tab – “Card rankings”**. When you pick a set, the tab shows a
(stub) ranked list of cards from that set. Replace the `rank_cards()` stub
with real logic later.
"""
from __future__ import annotations
import random, os
from pathlib import Path
from typing import Dict, List
import requests
import streamlit as st
from draft_model import DraftModel
os.environ.setdefault("HF_HOME", os.path.expanduser("~/.cache/huggingface"))
SUPPORTED_SETS_PATH = Path("supported_sets.txt")
st.write("Running Streamlit", st.__version__)
@st.cache_data(show_spinner="Reading supported sets …")
def get_supported_sets(path: Path = SUPPORTED_SETS_PATH) -> List[str]:
"""Return a list of legal set codes read from *supported_sets.txt*."""
if path.is_file():
return [ln.strip() for ln in path.read_text().splitlines() if ln.strip()]
return []
@st.cache_resource(show_spinner="Loading draft model …")
def load_model():
return DraftModel()
@st.cache_data(show_spinner="Calculating card rankings …")
def rank_cards(set_code: str) -> List[Dict]:
"""Return a stubbed ranking list for *set_code*.
Replace with your real evaluation logic. For now we just pull 30 random
commons from the set and assign a dummy score.
"""
url = f"https://api.scryfall.com/cards/search?q=set%3A{set_code}+unique%3Aprints+is%3Acommon"
cards: List[Dict] = []
while url and len(cards) < 60: # cap network use
r = requests.get(url)
r.raise_for_status()
payload = r.json()
cards += payload["data"]
url = payload.get("next_page") if payload.get("has_more") else None
sample = random.sample(cards, k=min(30, len(cards))) if cards else []
ranked = [
{"name": c["name"], "score": round(random.random(), 2)} for c in sample
]
ranked.sort(key=lambda x: x["score"], reverse=True)
return ranked
model = load_model()
# -----------------------------------------------------------------------------
# 2. Draft‑logic helpers (stubs)
# -----------------------------------------------------------------------------
def suggest_pick(pack: List[Dict], picks: List[Dict]) -> Dict:
if model is None:
return random.choice(pack)
return model.predict(pack=pack, picks=picks) # type: ignore[attr-defined]
def fetch_card_image(card_name: str) -> str:
r = requests.get(
"https://api.scryfall.com/cards/named",
params={"exact": card_name, "format": "json"},
)
r.raise_for_status()
data = r.json()
if "image_uris" in data:
return data["image_uris"]["normal"]
return data["card_faces"][0]["image_uris"]["normal"]
def generate_booster(set_code: str) -> List[Dict]:
url = f"https://api.scryfall.com/cards/search?q=set%3A{set_code}+is%3Abooster+unique%3Aprints"
cards: List[Dict] = []
while url:
resp = requests.get(url)
resp.raise_for_status()
payload = resp.json()
cards += payload["data"]
url = payload.get("next_page") if payload.get("has_more") else None
return random.sample(cards, 15)
# -----------------------------------------------------------------------------
# 3. Streamlit UI
# -----------------------------------------------------------------------------
st.set_page_config(page_title="MTG Draft Assistant", page_icon="🃏")
st.title("🃏 MTG Draft Assistant")
# -------- Sidebar ------------------------------------------------------------
with st.sidebar:
st.header("Draft setup")
supported_sets = get_supported_sets()
# Hide control in an expander (collapsed by default)
with st.expander("Set selection", expanded=False):
if supported_sets:
set_code = st.radio("Choose a set to draft", supported_sets, index=0)
else:
st.warning(
"*supported_sets.txt* not found or empty. Using free‑text input instead.",
icon="⚠️",
)
set_code = st.text_input("Set code", value="WOE")
if st.button("Start new draft", type="primary"):
st.session_state["pack"] = generate_booster(set_code)
st.session_state["picks"] = []
# -------- Session state ------------------------------------------------------
st.session_state.setdefault("pack", [])
st.session_state.setdefault("picks", [])
# -------- Main content organised in tabs ------------------------------------
tabs = st.tabs(["Draft", "Card rankings"])
# --- Tab 1: Draft ------------------------------------------------------------
with tabs[0]:
if not st.session_state["pack"]:
st.info("Choose **Start new draft** in the sidebar to open pack 1.")
else:
pack: List[Dict] = st.session_state["pack"]
picks: List[Dict] = st.session_state["picks"]
st.subheader(f"Pack {len(picks) // 15 + 1} — Pick {len(picks) % 15 + 1}")
suggested = suggest_pick(pack, picks)
st.success(f"**Model suggests:** {suggested['name']}")
cols = st.columns(5)
for idx, card in enumerate(pack):
col = cols[idx % 5]
col.image(fetch_card_image(card["name"]), use_column_width=True)
if col.button(f"Pick {card['name']}", key=f"pick-{idx}"):
picks.append(card)
pack.remove(card)
if not pack: # end of pack ⇒ open a fresh booster
st.session_state["pack"] = generate_booster(set_code)
st.experimental_rerun()
with st.expander("Current picks", expanded=False):
st.write("\n".join([c["name"] for c in picks]))
# --- Tab 2: Card rankings ----------------------------------------------------
with tabs[1]:
st.header("Card rankings for set " + set_code)
if set_code:
ranking = rank_cards(set_code)
if ranking:
for idx, card in enumerate(ranking, start=1):
st.write(f"{idx}. {card['name']} — **{card['score']:.2f}**")
else:
st.info("No cards found for this set (or Scryfall unavailable).")
else:
st.info("Select a set in the sidebar to view rankings.")
|