Download controllers/shuffler_controller.py from seba3y/SpeakLab: direct link, hf CLI and curl.
- Browser
- Download file 2.4 kB
-
https://huggingface.co/spaces/seba3y/SpeakLab/resolve/main/controllers/shuffler_controller.py
- Command line
-
hf download hf://spaces/seba3y/SpeakLab/controllers/shuffler_controller.py
-
curl -L -o shuffler_controller.py https://huggingface.co/spaces/seba3y/SpeakLab/resolve/main/controllers/shuffler_controller.py
2.4 kB
| """ | |
| ShufflerController — mirrors the JS makeShuffler() no-repeat logic. | |
| The seen-list for each named pool is kept inside a dict that lives in | |
| gr.BrowserState (localStorage). The state dict shape: | |
| { | |
| "jam": {"seen": ["...", ...]}, | |
| "tt_easy": {"seen": [...]}, | |
| "tt_medium": {"seen": [...]}, | |
| "tt_hard": {"seen": [...]}, | |
| "imp_all": {"seen": [...]}, | |
| "imp_0": {"seen": [...]}, # per-category index | |
| ... | |
| "iv_all": {"seen": [...]}, | |
| "iv_0": {"seen": [...]}, | |
| ... | |
| } | |
| """ | |
| import json | |
| import random | |
| from pydantic import BaseModel | |
| from models.session_models import ShufflerState | |
| def _serialise(item) -> str: | |
| if isinstance(item, str): | |
| return item | |
| if isinstance(item, BaseModel): | |
| return json.dumps(item.model_dump(), ensure_ascii=False, sort_keys=True) | |
| return json.dumps(item, ensure_ascii=False) | |
| def next_item(pool: list, key: str, raw_state: dict) -> tuple: | |
| """ | |
| Pick the next unseen item from pool. | |
| Returns (item, updated_raw_state). | |
| """ | |
| if not pool: | |
| return None, raw_state | |
| state_dict = raw_state.get(key, {}) if isinstance(raw_state, dict) else {} | |
| shuffler = ShufflerState.model_validate(state_dict) | |
| seen_set = set(shuffler.seen) | |
| unseen = [i for i, item in enumerate(pool) if _serialise(item) not in seen_set] | |
| if not unseen: | |
| # Full cycle complete — reset | |
| shuffler.seen = [] | |
| seen_set = set() | |
| unseen = list(range(len(pool))) | |
| idx = random.choice(unseen) | |
| picked = pool[idx] | |
| shuffler.seen.append(_serialise(picked)) | |
| updated = dict(raw_state) if isinstance(raw_state, dict) else {} | |
| updated[key] = shuffler.model_dump() | |
| return picked, updated | |
| def reset_key(key: str, raw_state: dict) -> dict: | |
| """Reset the seen list for a single key.""" | |
| updated = dict(raw_state) if isinstance(raw_state, dict) else {} | |
| updated[key] = ShufflerState().model_dump() | |
| return updated | |
| def imp_pool_key(cat: str, categories: list) -> str: | |
| if cat == "All": | |
| return "imp_all" | |
| idx = next((i for i, c in enumerate(categories) if c.category == cat), 0) | |
| return f"imp_{idx}" | |
| def iv_pool_key(cat: str, categories: list) -> str: | |
| if cat == "All": | |
| return "iv_all" | |
| idx = next((i for i, c in enumerate(categories) if c.category == cat), 0) | |
| return f"iv_{idx}" | |