MarianaCodebase commited on
Commit
334eeaa
·
verified ·
1 Parent(s): 2e1c2fe

Upload prebake.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. prebake.py +109 -0
prebake.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Pre-bake station + cursed broadcasts into broadcasts_cache.json.
2
+
3
+ Generates POOL_SIZE wording variants for every spoken station, in every
4
+ language, plus the cursed signal. The Space loads this file at startup and
5
+ serves those broadcasts instantly (no model call), while each listener still
6
+ lands on one of several editions (variant % POOL_SIZE), so the per-listener
7
+ feel is kept. The encrypted number station and the hidden-band fragments are
8
+ fixed text already and are not baked; the operator console stays fully live.
9
+
10
+ Run once, locally (it is slow on CPU, a while). Re-run only when you change a
11
+ station persona, a prompt, POOL_SIZE, or the model:
12
+
13
+ python prebake.py
14
+
15
+ The keys written here must match exactly what app.tune() looks up:
16
+ station:{canonical}:{lang}:{pool}
17
+ cursed:{CURSED_FREQUENCY}:{lang}:{pool}
18
+ """
19
+
20
+ import json
21
+ import os
22
+ import time
23
+ from pathlib import Path
24
+
25
+ # Tell app.py not to spawn its background warm-up thread when we import it.
26
+ os.environ["PREBAKE"] = "1"
27
+
28
+ from app import POOL_SIZE, _mix_seed, _strip_leaks # noqa: E402
29
+ from model import stream_broadcast # noqa: E402
30
+ from stations import ( # noqa: E402
31
+ CURSED_FREQUENCY,
32
+ CURSED_SYSTEM_PROMPT,
33
+ STATION_FREQUENCIES,
34
+ get_station,
35
+ localized_system_prompt,
36
+ localized_user_prompt,
37
+ station_seed,
38
+ station_system_prompt,
39
+ )
40
+
41
+ OUT = Path(__file__).parent / "broadcasts_cache.json"
42
+ LANGS = ("es", "en", "fr")
43
+
44
+
45
+ def _generate(system_prompt: str, user_prompt: str, seed: int, max_tokens: int = 160) -> str:
46
+ """One full broadcast, cleaned exactly like the live server caches it."""
47
+ accumulated = ""
48
+ for token in stream_broadcast(
49
+ system_prompt, user_prompt=user_prompt, seed=seed, max_tokens=max_tokens
50
+ ):
51
+ accumulated += token
52
+ return _strip_leaks(accumulated).strip()
53
+
54
+
55
+ def main():
56
+ # Resume support: keep anything already baked so re-runs/interrupts are cheap.
57
+ cache: dict[str, str] = {}
58
+ if OUT.exists():
59
+ try:
60
+ cache = json.loads(OUT.read_text(encoding="utf-8"))
61
+ print(f"resuming: {len(cache)} broadcasts already baked")
62
+ except Exception:
63
+ cache = {}
64
+
65
+ jobs = [] # (key_prefix, system_prompt_fn_args)
66
+ for freq in STATION_FREQUENCIES:
67
+ station = get_station(freq)
68
+ for lang in LANGS:
69
+ jobs.append(
70
+ (
71
+ f"station:{freq}:{lang}",
72
+ station_system_prompt(freq, lang),
73
+ localized_user_prompt(station, lang),
74
+ freq,
75
+ )
76
+ )
77
+ for lang in LANGS:
78
+ jobs.append(
79
+ (
80
+ f"cursed:{CURSED_FREQUENCY}:{lang}",
81
+ localized_system_prompt(CURSED_SYSTEM_PROMPT, "es", lang),
82
+ localized_user_prompt(None, lang),
83
+ CURSED_FREQUENCY,
84
+ )
85
+ )
86
+
87
+ total = len(jobs) * POOL_SIZE
88
+ done = 0
89
+ t0 = time.time()
90
+ for prefix, sysp, usrp, freq in jobs:
91
+ for pool in range(POOL_SIZE):
92
+ done += 1
93
+ key = f"{prefix}:{pool}"
94
+ if cache.get(key):
95
+ print(f"[{done}/{total}] {key} (cached, skip)")
96
+ continue
97
+ text = _generate(sysp, usrp, _mix_seed(station_seed(freq), pool))
98
+ if text:
99
+ cache[key] = text
100
+ # Write incrementally so an interrupt never loses progress.
101
+ OUT.write_text(json.dumps(cache, ensure_ascii=False), encoding="utf-8")
102
+ elapsed = time.time() - t0
103
+ print(f"[{done}/{total}] {key} ({len(text)} chars, {elapsed:.0f}s)")
104
+
105
+ print(f"\nDone: {len(cache)} broadcasts -> {OUT} in {time.time() - t0:.0f}s")
106
+
107
+
108
+ if __name__ == "__main__":
109
+ main()