goumsss commited on
Commit
61571e8
Β·
1 Parent(s): 8cc324b

Add dev scripts + simplify CLAUDE.md

Browse files
CLAUDE.md CHANGED
@@ -4,39 +4,20 @@
4
  Kids mental math app. Correct answers earn AI-generated cute animal images (FLUX.1-schnell).
5
  Stack: Python Β· Gradio Β· diffusers Β· HuggingFace Spaces (ZeroGPU).
6
 
7
- ## Mandatory dev loop β€” follow for EVERY change
8
-
9
- ```
10
- 1. CODE β†’ edit files
11
- 2. SYNTAX β†’ ~/miniforge3/bin/python3 -c "import ast; [ast.parse(open(f).read()) for f in ['app.py','image_generator.py','math_engine.py']]"
12
- 3. IMPORT β†’ ~/miniforge3/bin/python3 -c "import app" 2>&1 # catches version conflicts & bad imports
13
- must produce NO errors (warnings OK)
14
- SDK CHK β†’ verify README.md sdk_version matches local gradio (HF Spaces pins gradio to sdk_version):
15
- python3 -c "
16
- import re, subprocess
17
- sdk = re.search(r'sdk_version: \"(.+?)\"', open('README.md').read()).group(1)
18
- local = subprocess.check_output(['pip','show','gradio']).decode()
19
- ver = re.search(r'Version: (.+)', local).group(1)
20
- assert sdk == ver, f'MISMATCH: README sdk_version={sdk} but local gradio={ver}'
21
- print(f'βœ… sdk_version {sdk} matches local gradio')
22
- " 2>&1
23
- 4. RUN β†’ kill previous instance, start fresh:
24
- pkill -f "python3 app.py"; ~/miniforge3/bin/python3 app.py > /tmp/numzoo.log 2>&1 &
25
- sleep 10 && cat /tmp/numzoo.log # must show no errors
26
- 5. TEST β†’ run Puppeteer (arm64 Node):
27
- arch -arm64 /bin/zsh -c "source ~/.nvm/nvm.sh && nvm use 20 && cd /Users/uplab/projects/puppeteer && node test_lovemath.mjs"
28
- β†’ take screenshots, read them, verify visually
29
- 6. FIX β†’ if any step fails, fix and restart from step 1
30
- 7. PUSH β†’ only when all steps pass:
31
- git add -A && git commit -m "..." && git push origin main
32
- ```
33
-
34
- **Version pinning rules:**
35
- - **Never put `gradio` in `requirements.txt`** β€” HF Spaces installs it separately using `sdk_version` from README.md frontmatter. Conflicting versions cause build failure.
36
- - **Always keep `sdk_version` in README.md in sync with local gradio** β€” run the SDK check above before every push.
37
- - To upgrade gradio: update `sdk_version` in README.md, reinstall locally (`pip install gradio==x.y.z`), re-run full loop.
38
-
39
- **Never push broken code.** If Puppeteer tests fail, do not proceed to push.
40
 
41
  ## Key files
42
 
@@ -45,8 +26,9 @@ Stack: Python Β· Gradio Β· diffusers Β· HuggingFace Spaces (ZeroGPU).
45
  | `app.py` | Gradio UI, game logic, panel visibility, event wiring |
46
  | `image_generator.py` | FLUX.1-schnell pipeline, emojiβ†’text prompt builder |
47
  | `math_engine.py` | Question generation, level names & thresholds |
48
- | `requirements.txt` | Python dependencies (HF Spaces uses Python 3.13) |
49
- | `README.md` | HF Spaces config (frontmatter) + user docs |
 
50
 
51
  ## Architecture
52
 
@@ -54,36 +36,35 @@ Stack: Python Β· Gradio Β· diffusers Β· HuggingFace Spaces (ZeroGPU).
54
 
55
  **Game state dict keys:**
56
  `name`, `level`, `score`, `streak`, `correct_since_reward`, `level_correct`,
57
- `question`, `answer`, `selected_animals`, `selected_places`,
58
- `future` (ThreadPoolExecutor Future), `awaiting_reward`
59
 
60
  **Reward trigger:** every `REWARD_EVERY = 3` correct answers.
61
- Image generation starts in background (ThreadPoolExecutor) as soon as quiz begins.
62
 
63
  ## Gradio rules
64
- - Use `gr.update(visible=True/False)` β€” never return bare `True/False` for component visibility
65
  - Theme and CSS go in `demo.launch(css=..., theme=...)`, NOT in `gr.Blocks()`
66
- - `gr.Group` has no `.change()` event β€” use explicit output returns from handlers
67
- - HF Spaces runs Python 3.13 β€” watch for removed stdlib modules (`audioop` β†’ add `audioop-lts`)
 
68
 
69
  ## Python runtime
70
  - **Local:** `~/miniforge3/bin/python3` (arm64, Python 3.13, torch 2.12, MPS)
71
- - **HF Spaces:** Python 3.13, ZeroGPU (A100 on demand via `@spaces.GPU`)
72
- - **DO NOT use** `/usr/local/bin/python3` β€” it's x64 Rosetta, torch 2.2, incompatible with latest diffusers
73
 
74
  ## Image generation
75
- - Model: `black-forest-labs/FLUX.1-schnell` (gated β€” must accept license on HF)
76
- - Local speed: ~5 min on MPS Β· HF ZeroGPU: ~5 sec
77
- - Always wrap generation in try/except β†’ return `(None, "")` on failure
78
  - `IS_HF_SPACE = os.environ.get("SPACE_ID") is not None` controls ZeroGPU decorator
79
 
80
  ## HuggingFace deployment
81
  - Space: `https://huggingface.co/spaces/Goumsss/numzoo`
82
- - Remote: `https://huggingface.co/spaces/Goumsss/numzoo` (already set)
83
- - Push = redeploy. Space rebuilds automatically on every push.
84
- - ZeroGPU requires HF Pro or hackathon grant (set in Space Settings β†’ Hardware)
85
 
86
  ## UI/UX principles
87
- - Text: English, minimal β€” **words not sentences** (kids with limited English)
88
- - Feedback: emoji-heavy, short (`βœ… Great! πŸ”₯πŸ”₯` not `Congratulations, your answer was correct!`)
89
- - Never crash visibly β€” all handlers wrapped in try/except with safe fallback returns
 
4
  Kids mental math app. Correct answers earn AI-generated cute animal images (FLUX.1-schnell).
5
  Stack: Python Β· Gradio Β· diffusers Β· HuggingFace Spaces (ZeroGPU).
6
 
7
+ ## Mandatory dev loop
8
+ Run these scripts in order before every push. Fix failures before proceeding.
9
+
10
+ | Step | Command | Must pass |
11
+ |------|---------|-----------|
12
+ | Syntax | `bash scripts/syntax.sh` | No syntax errors |
13
+ | Imports | `bash scripts/check_imports.sh` | No import errors |
14
+ | SDK version | `bash scripts/check_sdk.sh` | README sdk_version == local gradio |
15
+ | Run | `bash scripts/run.sh` | App starts, no errors in logs |
16
+ | Test | `bash scripts/test.sh` | All Puppeteer checks pass, screenshots look correct |
17
+
18
+ Full loop shortcut: `bash scripts/dev.sh` (runs steps 1–4, then run test.sh manually).
19
+
20
+ **Never push if any step fails.**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  ## Key files
23
 
 
26
  | `app.py` | Gradio UI, game logic, panel visibility, event wiring |
27
  | `image_generator.py` | FLUX.1-schnell pipeline, emojiβ†’text prompt builder |
28
  | `math_engine.py` | Question generation, level names & thresholds |
29
+ | `requirements.txt` | Python dependencies β€” never include `gradio` here |
30
+ | `README.md` | HF Spaces config (frontmatter `sdk_version`) + user docs |
31
+ | `scripts/` | Dev loop automation scripts |
32
 
33
  ## Architecture
34
 
 
36
 
37
  **Game state dict keys:**
38
  `name`, `level`, `score`, `streak`, `correct_since_reward`, `level_correct`,
39
+ `question`, `answer`, `selected_animals`, `selected_places`, `generate_now`
 
40
 
41
  **Reward trigger:** every `REWARD_EVERY = 3` correct answers.
42
+ Image generated via `.then()` chaining on the Check button β€” synchronous, within Gradio request context (required for ZeroGPU).
43
 
44
  ## Gradio rules
45
+ - Use `gr.update(visible=True/False)` for visibility β€” never return bare booleans
46
  - Theme and CSS go in `demo.launch(css=..., theme=...)`, NOT in `gr.Blocks()`
47
+ - `gr.Group` has no `.change()` event
48
+ - Never put `gradio` in `requirements.txt` β€” HF Spaces pins it via `sdk_version` in README
49
+ - Keep `sdk_version` in README in sync with local gradio (run `scripts/check_sdk.sh`)
50
 
51
  ## Python runtime
52
  - **Local:** `~/miniforge3/bin/python3` (arm64, Python 3.13, torch 2.12, MPS)
53
+ - **HF Spaces:** Python 3.13, ZeroGPU (A100 via `@spaces.GPU`)
54
+ - Do not use system Python (`/usr/local/bin/python3`) β€” it's x64 Rosetta, incompatible
55
 
56
  ## Image generation
57
+ - Model: `black-forest-labs/FLUX.1-schnell` (gated β€” accept license on HF before first run)
58
+ - Local: ~5 min on MPS Β· HF ZeroGPU: ~5 sec
59
+ - Always wrap in try/except β†’ return `(None, "")` on failure
60
  - `IS_HF_SPACE = os.environ.get("SPACE_ID") is not None` controls ZeroGPU decorator
61
 
62
  ## HuggingFace deployment
63
  - Space: `https://huggingface.co/spaces/Goumsss/numzoo`
64
+ - Push = redeploy. Rebuilds automatically.
65
+ - ZeroGPU: set in Space Settings β†’ Hardware (requires HF Pro or hackathon grant)
 
66
 
67
  ## UI/UX principles
68
+ - English only, minimal text β€” words not sentences (kids with limited English)
69
+ - Emoji-heavy feedback (`βœ… Great! πŸ”₯πŸ”₯` not full sentences)
70
+ - Never crash visibly β€” all handlers wrapped in try/except with safe fallbacks
scripts/check_imports.sh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ cd "$(dirname "$0")/.."
3
+ echo "Checking imports..."
4
+ ~/miniforge3/bin/python3 -c "import app" 2>&1
5
+ if [ $? -eq 0 ]; then echo "βœ… imports OK"; else echo "❌ import failed"; exit 1; fi
scripts/check_sdk.sh ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ cd "$(dirname "$0")/.."
3
+ ~/miniforge3/bin/python3 - <<'EOF'
4
+ import re, subprocess, sys
5
+ sdk = re.search(r'sdk_version: "(.+?)"', open('README.md').read()).group(1)
6
+ out = subprocess.check_output(['/Users/uplab/miniforge3/bin/pip','show','gradio']).decode()
7
+ ver = re.search(r'Version: (.+)', out).group(1)
8
+ if sdk != ver:
9
+ print(f'❌ MISMATCH: README sdk_version={sdk} but local gradio={ver}')
10
+ sys.exit(1)
11
+ print(f'βœ… sdk_version {sdk} matches local gradio')
12
+ EOF
scripts/dev.sh ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ set -e
3
+ DIR="$(dirname "$0")"
4
+ echo "=== 1/4 Syntax ===" && bash "$DIR/syntax.sh"
5
+ echo "=== 2/4 Imports ===" && bash "$DIR/check_imports.sh"
6
+ echo "=== 3/4 SDK ===" && bash "$DIR/check_sdk.sh"
7
+ echo "=== 4/4 Run ===" && bash "$DIR/run.sh"
8
+ echo ""
9
+ echo "App is running. Now run: bash scripts/test.sh"
scripts/run.sh ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ cd "$(dirname "$0")/.."
3
+ pkill -f "python3 app.py" 2>/dev/null; sleep 1
4
+ ~/miniforge3/bin/python3 app.py > /tmp/numzoo.log 2>&1 &
5
+ echo "Starting app..."
6
+ sleep 10
7
+ PORT=$(lsof -i :7860 -i :7861 -i :7862 -i :7863 -i :7864 -i :7865 2>/dev/null | grep LISTEN | tail -1 | grep -oE '786[0-9]')
8
+ if [ -z "$PORT" ]; then
9
+ echo "❌ App failed to start. Logs:"
10
+ cat /tmp/numzoo.log
11
+ exit 1
12
+ fi
13
+ echo "βœ… App running on http://localhost:$PORT"
14
+ echo $PORT > /tmp/numzoo.port
scripts/syntax.sh ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ cd "$(dirname "$0")/.."
3
+ ~/miniforge3/bin/python3 -c "
4
+ import ast, sys
5
+ for f in ['app.py','image_generator.py','math_engine.py']:
6
+ try:
7
+ ast.parse(open(f).read())
8
+ print(f'βœ… {f}')
9
+ except SyntaxError as e:
10
+ print(f'❌ {f}: {e}')
11
+ sys.exit(1)
12
+ "
scripts/test.sh ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ cd "$(dirname "$0")/.."
3
+ PORT=$(cat /tmp/numzoo.port 2>/dev/null || echo "7864")
4
+ # Update port in test file
5
+ sed -i '' "s|http://localhost:[0-9]*/|http://localhost:$PORT/|g" /Users/uplab/projects/puppeteer/test_lovemath.mjs
6
+ arch -arm64 /bin/zsh -c "source ~/.nvm/nvm.sh && nvm use 20 && cd /Users/uplab/projects/puppeteer && node test_lovemath.mjs"