akshay4 commited on
Commit
0a02dca
·
verified ·
1 Parent(s): 384cda6

Upload folder using huggingface_hub

Browse files
.env.example ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ HF_TOKEN=hf_...
2
+ WITGYM_DATA_REPO=akshay4/witgym-data
3
+ WITGYM_SKIP_HUB=1
4
+ LLM_BACKEND=hf_api
.gitignore DELETED
@@ -1,68 +0,0 @@
1
- # Local index is generated; ship transcripts only (Space builds index on startup)
2
- data/*
3
- !data/transcripts/
4
- !data/transcripts/**
5
-
6
- # Virtual environments
7
- .venv/
8
- venv/
9
- env/
10
-
11
- # Environment and secrets
12
- .env
13
- .env.*
14
- !.env.example
15
-
16
- # Python bytecode and packaging
17
- __pycache__/
18
- *.py[cod]
19
- *$py.class
20
- *.so
21
- .Python
22
- *.egg
23
- *.egg-info/
24
- .eggs/
25
- dist/
26
- build/
27
- pip-wheel-metadata/
28
-
29
- # Test and type-check caches
30
- .pytest_cache/
31
- .mypy_cache/
32
- .ruff_cache/
33
- htmlcov/
34
- .coverage
35
- .coverage.*
36
- coverage.xml
37
- *.cover
38
- .hypothesis/
39
-
40
- # Jupyter
41
- .ipynb_checkpoints/
42
-
43
- # IDE and editors
44
- .idea/
45
- .vscode/
46
- *.swp
47
- *.swo
48
- *~
49
-
50
- # OS
51
- .DS_Store
52
- Thumbs.db
53
-
54
- # ML / Hugging Face caches and artifacts
55
- .cache/
56
- huggingface/
57
- checkpoints/
58
- runs/
59
- wandb/
60
- mlruns/
61
- *.pt
62
- *.pth
63
- *.ckpt
64
- *.safetensors
65
-
66
- # Logs
67
- *.log
68
- logs/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -49,9 +49,34 @@ python app.py
49
  |--------|--------|
50
  | `HF_TOKEN` | Your Hugging Face access token |
51
  | `LLM_BACKEND` | `hf_api` (recommended on Spaces) |
 
52
 
53
  Optional: `HF_INFERENCE_PROVIDER` (defaults to `together` for Qwen3.5-9B — required for `enable_thinking: false`), `WITGYM_INDEX_PATH`.
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  ## Architecture
56
 
57
  - **Small talk** (hi, who are you) → polite identity reply, no pipeline
 
49
  |--------|--------|
50
  | `HF_TOKEN` | Your Hugging Face access token |
51
  | `LLM_BACKEND` | `hf_api` (recommended on Spaces) |
52
+ | `WITGYM_DATA_REPO` | Private dataset repo, e.g. `akshay4/witgym-data` |
53
 
54
  Optional: `HF_INFERENCE_PROVIDER` (defaults to `together` for Qwen3.5-9B — required for `enable_thinking: false`), `WITGYM_INDEX_PATH`.
55
 
56
+ ## Large data on Hugging Face Hub
57
+
58
+ Files over 1 MB (`office_generated.txt`, `index.npz`) live in a **private dataset repo**, not in git. The app fetches them at startup via `hf_hub_download`.
59
+
60
+ **One-time setup** (create private dataset `witgym-data`, then upload):
61
+
62
+ ```bash
63
+ hf upload akshay4/witgym-data \
64
+ data/transcripts/office_generated.txt office_generated.txt \
65
+ --repo-type dataset --private
66
+
67
+ hf upload akshay4/witgym-data \
68
+ data/index.npz index.npz \
69
+ --repo-type dataset
70
+ ```
71
+
72
+ **When transcripts change:** re-run `witgym-index`, then re-upload `index.npz`.
73
+
74
+ **Offline local dev:** set `WITGYM_SKIP_HUB=1` and keep local copies in `data/`.
75
+
76
+ ## Deploy (GitHub → Space)
77
+
78
+ Pushes to `main` sync to [build-small-hackathon/WitGym](https://huggingface.co/spaces/build-small-hackathon/WitGym) via `.github/workflows/sync-to-hub.yml`. Add `HF_TOKEN` as a GitHub repository secret.
79
+
80
  ## Architecture
81
 
82
  - **Small talk** (hi, who are you) → polite identity reply, no pipeline
data/transcripts/office_generated.txt DELETED
The diff for this file is too large to render. See raw diff
 
witgym/config.py CHANGED
@@ -57,6 +57,7 @@ CLICHE_PENALTY_TOKENS = 6 # Penalise first N tokens of the obvious response
57
 
58
  # HuggingFace auth + inference backend
59
  HF_TOKEN = os.getenv("HF_TOKEN", "")
 
60
  # "local" = Transformers on device; "hf_api" = Inference Providers (Spaces default)
61
  LLM_BACKEND = os.getenv("LLM_BACKEND", "local")
62
  # Qwen3.5-9B thinking-mode toggle requires Together; "auto" often 400s on extra_body
 
57
 
58
  # HuggingFace auth + inference backend
59
  HF_TOKEN = os.getenv("HF_TOKEN", "")
60
+ WITGYM_DATA_REPO = os.getenv("WITGYM_DATA_REPO", "")
61
  # "local" = Transformers on device; "hf_api" = Inference Providers (Spaces default)
62
  LLM_BACKEND = os.getenv("LLM_BACKEND", "local")
63
  # Qwen3.5-9B thinking-mode toggle requires Together; "auto" often 400s on extra_body
witgym/hub_data.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Fetch >1MB artifacts from a private HF dataset repo."""
2
+ import os
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ from loguru import logger
7
+
8
+ from witgym import config
9
+
10
+ HUB_ARTIFACTS = ("index.npz", "office_generated.txt")
11
+ HUB_CACHE_DIR = "data/hub_cache"
12
+
13
+
14
+ def _local_default_path(filename: str) -> Optional[Path]:
15
+ if filename == "index.npz":
16
+ return Path(config.INDEX_PATH)
17
+ if filename == "office_generated.txt":
18
+ return Path(config.TRANSCRIPT_DIR) / filename
19
+ return None
20
+
21
+
22
+ def ensure_artifact(filename: str, local_dir: str = HUB_CACHE_DIR) -> Path:
23
+ """Return local path; use existing file, cache, or download from Hub."""
24
+ default = _local_default_path(filename)
25
+ if default is not None and default.exists():
26
+ return default
27
+
28
+ cache_dest = Path(local_dir) / filename
29
+ if cache_dest.exists():
30
+ return cache_dest
31
+
32
+ if os.getenv("WITGYM_SKIP_HUB") or not config.WITGYM_DATA_REPO or not config.HF_TOKEN:
33
+ raise FileNotFoundError(f"{filename} not found locally and Hub fetch disabled")
34
+
35
+ from huggingface_hub import hf_hub_download
36
+
37
+ logger.info(f"Downloading {filename} from {config.WITGYM_DATA_REPO}")
38
+ downloaded = hf_hub_download(
39
+ repo_id=config.WITGYM_DATA_REPO,
40
+ filename=filename,
41
+ repo_type="dataset",
42
+ token=config.HF_TOKEN,
43
+ local_dir=local_dir,
44
+ )
45
+ return Path(downloaded)
46
+
47
+
48
+ def materialize_hub_transcripts() -> None:
49
+ """Copy hub transcript into data/transcripts/ so indexer glob stays unchanged."""
50
+ if os.getenv("WITGYM_SKIP_HUB") or not config.WITGYM_DATA_REPO:
51
+ return
52
+
53
+ dest = Path(config.TRANSCRIPT_DIR) / "office_generated.txt"
54
+ if dest.exists():
55
+ return
56
+
57
+ try:
58
+ hub_txt = ensure_artifact("office_generated.txt")
59
+ except FileNotFoundError:
60
+ return
61
+
62
+ dest.parent.mkdir(parents=True, exist_ok=True)
63
+ dest.write_bytes(hub_txt.read_bytes())
64
+ logger.info(f"Materialized {dest} from Hub")
witgym/retriever.py CHANGED
@@ -28,6 +28,18 @@ def load_index(index_path: str = config.INDEX_PATH) -> dict:
28
  if os.path.exists(npz_fallback):
29
  path = npz_fallback
30
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  if not os.path.exists(path):
32
  transcript_dir = Path(config.TRANSCRIPT_DIR)
33
  if transcript_dir.is_dir() and any(transcript_dir.glob("*.txt")):
 
28
  if os.path.exists(npz_fallback):
29
  path = npz_fallback
30
 
31
+ from witgym.hub_data import materialize_hub_transcripts
32
+
33
+ materialize_hub_transcripts()
34
+
35
+ if not os.path.exists(path) and config.WITGYM_DATA_REPO:
36
+ from witgym.hub_data import ensure_artifact
37
+
38
+ try:
39
+ path = str(ensure_artifact("index.npz"))
40
+ except FileNotFoundError:
41
+ pass
42
+
43
  if not os.path.exists(path):
44
  transcript_dir = Path(config.TRANSCRIPT_DIR)
45
  if transcript_dir.is_dir() and any(transcript_dir.glob("*.txt")):