Timo commited on
Commit
892a8b7
·
1 Parent(s): b743918
Files changed (1) hide show
  1. src/streamlit_app.py +0 -160
src/streamlit_app.py CHANGED
@@ -1,160 +0,0 @@
1
- """
2
- MTG Draft Assistant Streamlit App
3
- ---------------------------------
4
- A booster-draft helper written with Streamlit and deployable on Hugging Face Spaces.
5
-
6
- Changes in this revision
7
- ~~~~~~~~~~~~~~~~~~~~~~~~
8
- * **supported_sets.txt** – one set code per line.
9
- * Sidebar now shows a **single-choice list** (radio buttons) sourced from that
10
- file instead of a free-text box, so users can only draft sets you actually
11
- support.
12
- * Fallback to the old text input if the text-file is missing or empty.
13
-
14
- Replace the three stub functions (`load_model`, `suggest_pick`,
15
- `generate_booster`) with your real model-/API-calls when you are ready.
16
- """
17
-
18
- from __future__ import annotations
19
-
20
- import os
21
- import random
22
- from pathlib import Path
23
- from typing import Dict, List
24
-
25
- import requests
26
- import streamlit as st
27
-
28
- # -----------------------------------------------------------------------------
29
- # 0. Constants & helpers
30
- # -----------------------------------------------------------------------------
31
-
32
- SUPPORTED_SETS_PATH = Path("helper_files/supported_sets.txt")
33
-
34
- @st.cache_data(show_spinner="Reading supported sets …")
35
- def get_supported_sets(path: Path = SUPPORTED_SETS_PATH) -> List[str]:
36
- """Return a list of legal set codes read from *supported_sets.txt*.
37
-
38
- The file should contain **one set tag per line**, e.g.::
39
-
40
- WOE
41
- LCI
42
- MKM
43
-
44
- If the file is missing we fall back to an empty list so the UI
45
- degrades gracefully.
46
- """
47
- if path.is_file():
48
- return [ln.strip() for ln in path.read_text().splitlines() if ln.strip()]
49
- return []
50
-
51
- # -----------------------------------------------------------------------------
52
- # 1. Model loading (stub)
53
- # -----------------------------------------------------------------------------
54
-
55
- @st.cache_resource(show_spinner="Loading draft model …")
56
- def load_model():
57
- """Load and return the trained drafting model.
58
-
59
- Adapt to your own pipeline; see previous revision for an example that pulls
60
- an artefact from *huggingface_hub*. Returning *None* leaves us in demo
61
- mode and will pick random cards.
62
- """
63
- return None
64
-
65
- model = load_model()
66
-
67
- # -----------------------------------------------------------------------------
68
- # 2. Draft-logic helpers (stubs)
69
- # -----------------------------------------------------------------------------
70
-
71
- def suggest_pick(pack: List[Dict], picks: List[Dict]) -> Dict:
72
- """Return the card the model recommends from *pack*."""
73
- if model is None:
74
- return random.choice(pack)
75
- return model.predict(pack=pack, picks=picks) # type: ignore[attr-defined]
76
-
77
-
78
- def fetch_card_image(card_name: str) -> str:
79
- """Fetch card art URL from Scryfall (normal size)."""
80
- r = requests.get(
81
- "https://api.scryfall.com/cards/named", params={"exact": card_name, "format": "json"}
82
- )
83
- r.raise_for_status()
84
- data = r.json()
85
- if "image_uris" in data:
86
- return data["image_uris"]["normal"]
87
- return data["card_faces"][0]["image_uris"]["normal"]
88
-
89
-
90
- def generate_booster(set_code: str) -> List[Dict]:
91
- """Return a pseudo-random 15-card booster using Scryfall search."""
92
- url = f"https://api.scryfall.com/cards/search?q=set%3A{set_code}+is%3Abooster+unique%3Aprints"
93
- cards: List[Dict] = []
94
- while url:
95
- resp = requests.get(url)
96
- resp.raise_for_status()
97
- payload = resp.json()
98
- cards += payload["data"]
99
- url = payload.get("next_page") if payload.get("has_more") else None
100
- return random.sample(cards, 15)
101
-
102
- # -----------------------------------------------------------------------------
103
- # 3. Streamlit UI
104
- # -----------------------------------------------------------------------------
105
-
106
- st.set_page_config(page_title="MTG Draft Assistant", page_icon="🃏")
107
-
108
- st.title("🃏 MTG Draft Assistant")
109
-
110
- # ---------------- Sidebar -----------------------------------------------------
111
-
112
- with st.sidebar:
113
- st.header("Draft setup")
114
-
115
- supported_sets = get_supported_sets()
116
-
117
- if supported_sets:
118
- set_code = st.radio("Choose a set to draft", supported_sets, index=0)
119
- else:
120
- st.warning(
121
- "*supported_sets.txt* not found or empty. Using free-text input instead.",
122
- icon="⚠️",
123
- )
124
- set_code = st.text_input("Set code", value="WOE")
125
-
126
- if st.button("Start new draft", type="primary"):
127
- st.session_state["pack"] = generate_booster(set_code)
128
- st.session_state["picks"] = []
129
-
130
- # ---------------- Session state guards ---------------------------------------
131
-
132
- st.session_state.setdefault("pack", [])
133
- st.session_state.setdefault("picks", [])
134
-
135
- if not st.session_state["pack"]:
136
- st.info("Choose **Start new draft** in the sidebar to open pack 1.")
137
- st.stop()
138
-
139
- pack: List[Dict] = st.session_state["pack"]
140
- picks: List[Dict] = st.session_state["picks"]
141
-
142
- st.subheader(f"Pack {len(picks) // 15 + 1} — Pick {len(picks) % 15 + 1}")
143
- suggested = suggest_pick(pack, picks)
144
-
145
- st.success(f"**Model suggests:** {suggested['name']}")
146
-
147
- # Display current pack as a 5-column grid of card images
148
- cols = st.columns(5)
149
- for idx, card in enumerate(pack):
150
- col = cols[idx % 5]
151
- col.image(fetch_card_image(card["name"]), use_column_width=True)
152
- if col.button(f"Pick {card['name']}", key=f"pick-{idx}"):
153
- picks.append(card)
154
- pack.remove(card)
155
- if not pack: # end of pack ⇒ open a fresh booster
156
- st.session_state["pack"] = generate_booster(set_code)
157
- st.experimental_rerun()
158
-
159
- with st.expander("Current picks", expanded=False):
160
- st.write("\n".join([c["name"] for c in picks]))