byte-vortex commited on
Commit
a6856e0
·
verified ·
1 Parent(s): 19ddb7b

Deploy Myco from CI

Browse files
Files changed (7) hide show
  1. README.md +22 -33
  2. app.py +10 -2
  3. requirements.txt +1 -1
  4. scripts/deploy_space.py +19 -47
  5. ui/gradio_app.py +4 -14
  6. ui/renderers.py +9 -7
  7. ui/styles.py +29 -0
README.md CHANGED
@@ -2,18 +2,16 @@
2
  title: Myco
3
  emoji: 🍄
4
  colorFrom: green
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 5.29.0
8
  app_file: app.py
9
  pinned: false
10
- license: mit
11
- short_description: Cozy mushroom exploration game
12
  ---
13
 
14
  # 🍄 Myco
15
 
16
- Myco is a cozy forest exploration game built with Gradio for Hugging Face Spaces. Explore a magical forest with Myco, an AI mushroom companion. Discover strange fungi, ask about them, study them, and collect them in your MycoDex.
17
 
18
  **Live Space:** https://huggingface.co/spaces/byte-vortex/Myco
19
 
@@ -25,42 +23,33 @@ Myco is a cozy forest exploration game built with Gradio for Hugging Face Spaces
25
  4. Choose **Study**, **Collect**, or **Eat**.
26
  5. Build your **MycoDex** and unlock forest progress.
27
 
28
- ## Features
29
 
30
- - Polished forest-themed hero panel with Myco mascot
31
- - Mushroom discovery with 30 starter species
32
- - Myco AI chat companion
33
- - Eat, Collect, and Study choices
34
- - MycoDex collection tracker
35
- - Forest progression goals: Crystal Grove, Moonlit Cavern, and Mushroom Elder
36
- - Common, Rare, and Legendary rarity tiers
37
 
38
- ## Project Structure
39
-
40
- ```text
41
- ├── app.py
42
- ├── requirements.txt
43
- ├── data/
44
- ├── game/
45
- ├── models/
46
- └── ui/
47
- ```
48
-
49
- ## Local Development
50
 
51
  ```bash
52
- python -m venv .venv
53
- source .venv/bin/activate
54
  pip install -r requirements.txt
55
  python app.py
56
  ```
57
 
58
- ## Codex Track Notes
 
 
 
 
59
 
60
- This project was built with Codex assistance. See `CODEx_USAGE.md` for a record of how Codex shaped the architecture, gameplay loop, and tests.
61
 
62
- ### Submission Checklist
 
 
 
63
 
64
- - [ ] Publish repository on GitHub
65
- - [ ] Confirm live Space works: https://huggingface.co/spaces/byte-vortex/Myco
66
- - [ ] Verify first play loop: Start Exploring → Ask Myco → Study or Collect → MycoDex progress
 
2
  title: Myco
3
  emoji: 🍄
4
  colorFrom: green
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 6.16.0
8
  app_file: app.py
9
  pinned: false
 
 
10
  ---
11
 
12
  # 🍄 Myco
13
 
14
+ Myco is a small Gradio game for Hugging Face Spaces. Explore a cozy forest with Myco, discover strange mushrooms, ask about them, study them, and collect them in your MycoDex.
15
 
16
  **Live Space:** https://huggingface.co/spaces/byte-vortex/Myco
17
 
 
23
  4. Choose **Study**, **Collect**, or **Eat**.
24
  5. Build your **MycoDex** and unlock forest progress.
25
 
26
+ ## What is included
27
 
28
+ - Gradio app entrypoint: `app.py`
29
+ - UI code: `ui/`
30
+ - Game logic: `game/`
31
+ - Mushroom model: `models/`
32
+ - Mushroom catalog: `data/mushrooms.json`
33
+ - Runtime dependency: `requirements.txt`
 
34
 
35
+ ## Local development
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  ```bash
 
 
38
  pip install -r requirements.txt
39
  python app.py
40
  ```
41
 
42
+ Then open the local Gradio URL printed in the terminal.
43
+
44
+ ## Hugging Face Space
45
+
46
+ This repo is intended to run directly as a Gradio Space. Hugging Face Spaces reads the metadata at the top of this README, installs `requirements.txt`, and runs `app.py`.
47
 
48
+ No GitHub Actions deployment workflow is required. To deploy manually:
49
 
50
+ 1. Create or open the Space at https://huggingface.co/spaces/byte-vortex/Myco.
51
+ 2. Make sure the Space SDK is **Gradio**.
52
+ 3. Upload or push this repository's files to the Space repository.
53
+ 4. The Space should install `gradio==6.16.0` from `requirements.txt` and start from `app.py`.
54
 
55
+ The required runtime files are `README.md`, `app.py`, `requirements.txt`, `data/`, `game/`, `models/`, and `ui/`.
 
 
app.py CHANGED
@@ -1,8 +1,16 @@
1
  """Hugging Face Spaces entrypoint for Myco."""
 
 
 
2
  from ui.gradio_app import build_app
 
 
3
 
4
  demo = build_app()
5
 
6
  if __name__ == "__main__":
7
- demo.launch()
8
-
 
 
 
 
1
  """Hugging Face Spaces entrypoint for Myco."""
2
+
3
+ import gradio as gr
4
+
5
  from ui.gradio_app import build_app
6
+ from ui.styles import APP_CSS
7
+
8
 
9
  demo = build_app()
10
 
11
  if __name__ == "__main__":
12
+ demo.launch(
13
+ theme=gr.themes.Soft(primary_hue="green", secondary_hue="emerald"),
14
+ css=APP_CSS,
15
+ ssr_mode=False,
16
+ )
requirements.txt CHANGED
@@ -1 +1 @@
1
-
 
1
+ gradio==6.16.0
scripts/deploy_space.py CHANGED
@@ -4,13 +4,10 @@ This script is intentionally minimal because CI may call it directly. If the
4
  optional HF_BUILD_SMALL_HACKATHON_TOKEN secret is missing, it exits cleanly.
5
  """
6
 
7
- from __future__ import annotations
8
-
9
  import os
10
 
11
  TOKEN_ENV_VAR = "HF_BUILD_SMALL_HACKATHON_TOKEN"
12
  DEFAULT_SPACE_ID = "byte-vortex/Myco"
13
-
14
  IGNORE_PATTERNS_TEXT = """
15
  .git/*
16
  .github/*
@@ -26,65 +23,40 @@ models/**/*.safetensors
26
  """
27
 
28
 
29
- def get_ignore_patterns() -> list[str]:
30
  """Return upload ignore patterns as a list for huggingface_hub."""
31
- return [pattern for pattern in IGNORE_PATTERNS_TEXT.splitlines() if pattern]
32
 
33
 
34
- def get_hf_token() -> str:
35
- """Return the optional Hugging Face deploy token without raising KeyError."""
36
  return os.environ.get(TOKEN_ENV_VAR, "").strip()
37
 
38
 
39
- def get_space_id() -> str:
40
- """Return the target Space repo id."""
41
  return os.environ.get("HF_SPACE_ID", DEFAULT_SPACE_ID).strip() or DEFAULT_SPACE_ID
42
 
43
 
44
- def main() -> None:
45
- """Upload the repository contents to the Hugging Face Space when a token is present."""
46
  token = get_hf_token()
47
  if not token:
48
- print(
49
- f"::warning::{TOKEN_ENV_VAR} is not configured. "
50
- "Skipping Hugging Face Space deployment."
51
- )
52
  return
53
 
54
- try:
55
- from huggingface_hub import HfApi
56
- except ImportError:
57
- print("::warning::huggingface_hub not installed. Skipping deployment.")
58
- return
59
 
60
  repo_id = get_space_id()
61
- print(f"Deploying to Space: {repo_id}")
62
-
63
- try:
64
- # Initialize API with token
65
- api = HfApi(token=token)
66
-
67
- # Validate token and access by attempting to get repo info first
68
- try:
69
- print(f"Verifying access to Space {repo_id}...")
70
- api.repo_info(repo_id=repo_id, repo_type="space")
71
- print(f"✅ Access to Space {repo_id} verified")
72
- except Exception as auth_error:
73
- print(f"::error::Cannot access Space {repo_id}. Check token permissions: {auth_error}")
74
- raise
75
-
76
- # Upload folder to Space
77
- api.upload_folder(
78
- folder_path=".",
79
- repo_id=repo_id,
80
- repo_type="space",
81
- ignore_patterns=get_ignore_patterns(),
82
- commit_message="Deploy Myco from GitHub Actions",
83
- )
84
- print(f"✅ Successfully deployed Myco to https://huggingface.co/spaces/{repo_id}")
85
- except Exception as e:
86
- print(f"::error::Failed to deploy to HF Space: {type(e).__name__}: {e}")
87
- raise
88
 
89
 
90
  if __name__ == "__main__":
 
4
  optional HF_BUILD_SMALL_HACKATHON_TOKEN secret is missing, it exits cleanly.
5
  """
6
 
 
 
7
  import os
8
 
9
  TOKEN_ENV_VAR = "HF_BUILD_SMALL_HACKATHON_TOKEN"
10
  DEFAULT_SPACE_ID = "byte-vortex/Myco"
 
11
  IGNORE_PATTERNS_TEXT = """
12
  .git/*
13
  .github/*
 
23
  """
24
 
25
 
26
+ def get_ignore_patterns():
27
  """Return upload ignore patterns as a list for huggingface_hub."""
28
+ return IGNORE_PATTERNS_TEXT.split()
29
 
30
 
31
+ def get_hf_token():
32
+ """Return the optional Hugging Face deploy token."""
33
  return os.environ.get(TOKEN_ENV_VAR, "").strip()
34
 
35
 
36
+ def get_space_id():
37
+ """Return the target Hugging Face Space id."""
38
  return os.environ.get("HF_SPACE_ID", DEFAULT_SPACE_ID).strip() or DEFAULT_SPACE_ID
39
 
40
 
41
+ def main():
42
+ """Deploy when a token is configured; otherwise skip without failing."""
43
  token = get_hf_token()
44
  if not token:
45
+ print(f"{TOKEN_ENV_VAR} is not configured; skipping Hugging Face Space deployment.")
 
 
 
46
  return
47
 
48
+ from huggingface_hub import HfApi
 
 
 
 
49
 
50
  repo_id = get_space_id()
51
+ HfApi().upload_folder(
52
+ folder_path=".",
53
+ repo_id=repo_id,
54
+ repo_type="space",
55
+ token=token,
56
+ ignore_patterns=get_ignore_patterns(),
57
+ commit_message="Deploy Myco from CI",
58
+ )
59
+ print(f"Deployed Myco to https://huggingface.co/spaces/{repo_id}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
 
62
  if __name__ == "__main__":
ui/gradio_app.py CHANGED
@@ -61,17 +61,11 @@ def mushroom_card_from_state(current: MushroomState | None) -> str:
61
 
62
  def build_app() -> gr.Blocks:
63
  """Build the Gradio interface for Hugging Face Spaces."""
64
- with gr.Blocks(title="Myco", theme=gr.themes.Soft(primary_hue="green", secondary_hue="emerald")) as demo:
65
  current_mushroom = gr.State(None)
66
  collection = gr.State([])
67
 
68
  gr.HTML(hero_markdown())
69
- gr.Markdown(
70
- """
71
- # 🍄 Myco
72
- **Explore a magical forest with Myco, an AI mushroom companion. Discover edible, magical, dangerous, and legendary fungi while completing your MycoDex.**
73
- """
74
- )
75
 
76
  with gr.Row():
77
  with gr.Column(scale=2):
@@ -83,13 +77,10 @@ def build_app() -> gr.Blocks:
83
  collect_button = gr.Button("Collect")
84
  study_button = gr.Button("Study")
85
  with gr.Column(scale=3):
86
- chat = gr.Chatbot(value=welcome_history(), label="Myco Chat", height=360, type="messages")
87
  with gr.Row():
88
- prompt = gr.Textbox(
89
- label="Ask Myco",
90
- placeholder="Myco, should I eat this?",
91
- scale=4,
92
- )
93
  ask_button = gr.Button("Ask Myco", scale=1)
94
 
95
  with gr.Row():
@@ -112,4 +103,3 @@ def build_app() -> gr.Blocks:
112
  eat_button.click(eat_mushroom, inputs=[current_mushroom, chat], outputs=[chat])
113
 
114
  return demo
115
-
 
61
 
62
  def build_app() -> gr.Blocks:
63
  """Build the Gradio interface for Hugging Face Spaces."""
64
+ with gr.Blocks(title="Myco") as demo:
65
  current_mushroom = gr.State(None)
66
  collection = gr.State([])
67
 
68
  gr.HTML(hero_markdown())
 
 
 
 
 
 
69
 
70
  with gr.Row():
71
  with gr.Column(scale=2):
 
77
  collect_button = gr.Button("Collect")
78
  study_button = gr.Button("Study")
79
  with gr.Column(scale=3):
80
+ chat = gr.Chatbot(value=welcome_history(), label="Myco Chat", height=360)
81
  with gr.Row():
82
+ textbox_component = gr.Textbox
83
+ prompt = textbox_component(label="Ask Myco", placeholder="Ask Myco about this mushroom", scale=4)
 
 
 
84
  ask_button = gr.Button("Ask Myco", scale=1)
85
 
86
  with gr.Row():
 
103
  eat_button.click(eat_mushroom, inputs=[current_mushroom, chat], outputs=[chat])
104
 
105
  return demo
 
ui/renderers.py CHANGED
@@ -26,13 +26,15 @@ def mushroom_card(mushroom: Mushroom | None) -> str:
26
  if mushroom is None:
27
  return "### 🌲 Forest Clearing\nClick **Start Exploring** to search for a strange fungus."
28
 
29
- return (
30
- f"### 🍄 {mushroom.name}\n"
31
- f"* **Rarity:** {mushroom.rarity}\n"
32
- f"* **Habitat:** {mushroom.habitat}\n"
33
- f"* **Edible:** {mushroom.edible}\n"
34
- f"* **Magic:** {mushroom.magic}\n"
35
- f"* **Danger:** {mushroom.danger}\n"
 
 
36
  )
37
 
38
 
 
26
  if mushroom is None:
27
  return "### 🌲 Forest Clearing\nClick **Start Exploring** to search for a strange fungus."
28
 
29
+ return "\n".join(
30
+ (
31
+ f"### 🍄 {mushroom.name}",
32
+ f"* **Rarity:** {mushroom.rarity}",
33
+ f"* **Habitat:** {mushroom.habitat}",
34
+ f"* **Edible:** {mushroom.edible}",
35
+ f"* **Magic:** {mushroom.magic}",
36
+ f"* **Danger:** {mushroom.danger}",
37
+ )
38
  )
39
 
40
 
ui/styles.py CHANGED
@@ -4,6 +4,7 @@ APP_CSS = """
4
  .gradio-container {
5
  background:
6
  radial-gradient(circle at top left, rgba(255, 244, 190, 0.55), transparent 32rem),
 
7
  linear-gradient(135deg, #10281f 0%, #214732 48%, #f6e7c8 100%);
8
  }
9
  .myco-hero {
@@ -38,10 +39,38 @@ APP_CSS = """
38
  font-size: 3rem;
39
  color: #173d2a;
40
  }
 
 
 
 
 
 
 
41
  #discovery-card, #mycodex, #progress-panel {
42
  padding: 1rem;
43
  border-radius: 20px;
44
  background: rgba(255, 250, 235, 0.9);
45
  border: 1px solid rgba(72, 108, 75, 0.18);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
  """
 
4
  .gradio-container {
5
  background:
6
  radial-gradient(circle at top left, rgba(255, 244, 190, 0.55), transparent 32rem),
7
+ radial-gradient(circle at bottom right, rgba(133, 214, 159, 0.22), transparent 28rem),
8
  linear-gradient(135deg, #10281f 0%, #214732 48%, #f6e7c8 100%);
9
  }
10
  .myco-hero {
 
39
  font-size: 3rem;
40
  color: #173d2a;
41
  }
42
+ .myco-hero p:last-child {
43
+ margin-bottom: 0;
44
+ color: #31533f;
45
+ }
46
+ #discovery-card,
47
+ #mycodex,
48
+ #progress-panel {
49
  #discovery-card, #mycodex, #progress-panel {
50
  padding: 1rem;
51
  border-radius: 20px;
52
  background: rgba(255, 250, 235, 0.9);
53
  border: 1px solid rgba(72, 108, 75, 0.18);
54
+ box-shadow: 0 12px 28px rgba(16, 40, 31, 0.12);
55
+ }
56
+ button.primary,
57
+ button[variant="primary"] {
58
+ font-weight: 800;
59
+ }
60
+ @media (max-width: 720px) {
61
+ .myco-hero {
62
+ align-items: flex-start;
63
+ flex-direction: column;
64
+ }
65
+
66
+ .myco-mascot {
67
+ width: 4.5rem;
68
+ height: 4.5rem;
69
+ font-size: 3rem;
70
+ }
71
+
72
+ .myco-hero h1 {
73
+ font-size: 2.25rem;
74
+ }
75
  }
76
  """