Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -11,6 +11,7 @@ import os
|
|
| 11 |
# found in __main__") instead of executing the __main__ block at the bottom.
|
| 12 |
os.environ.setdefault("GRADIO_SSR_MODE", "false")
|
| 13 |
|
|
|
|
| 14 |
import queue
|
| 15 |
import re
|
| 16 |
import threading
|
|
@@ -43,6 +44,7 @@ from model import stream_broadcast
|
|
| 43 |
from stations import (
|
| 44 |
CURSED_FREQUENCY,
|
| 45 |
CURSED_SYSTEM_PROMPT,
|
|
|
|
| 46 |
STATION_TOLERANCE,
|
| 47 |
get_station,
|
| 48 |
localized_system_prompt,
|
|
@@ -122,6 +124,31 @@ def _stream_fixed(text: str, char_delay: float = 0.025, should_continue=None):
|
|
| 122 |
_broadcast_cache: dict[str, str] = {}
|
| 123 |
_CACHE_MAX = 256
|
| 124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
# Rapid retuning: each /tune bumps this epoch. An in-flight generation that is
|
| 126 |
# no longer the latest self-terminates at the next token, releasing the model
|
| 127 |
# lock so the newest tune can run. Without this, a superseded generation runs to
|
|
@@ -246,6 +273,12 @@ def _stream_model_cached(cache_key: str, system_prompt: str, should_continue=Non
|
|
| 246 |
def superseded():
|
| 247 |
return should_continue is not None and not should_continue()
|
| 248 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
cached = _broadcast_cache.get(cache_key)
|
| 250 |
if cached:
|
| 251 |
yield from _stream_fixed(cached, char_delay=0.018, should_continue=should_continue)
|
|
@@ -291,12 +324,16 @@ def _norm_variant(variant) -> int:
|
|
| 291 |
def tune(frequency: float, language: str = "es", variant: float = 0) -> str:
|
| 292 |
"""Tunes a frequency and streams the broadcast (SSE).
|
| 293 |
|
| 294 |
-
`variant` is a per-listener session nonce
|
| 295 |
-
|
|
|
|
|
|
|
|
|
|
| 296 |
"""
|
| 297 |
frequency = float(frequency)
|
| 298 |
lang = normalize_lang(language)
|
| 299 |
var = _norm_variant(variant)
|
|
|
|
| 300 |
my_epoch = _next_tune_epoch()
|
| 301 |
|
| 302 |
def still_current():
|
|
@@ -310,11 +347,11 @@ def tune(frequency: float, language: str = "es", variant: float = 0) -> str:
|
|
| 310 |
# The unsolvable station: the model broadcasts, the frontend never cleans it.
|
| 311 |
if abs(frequency - CURSED_FREQUENCY) <= STATION_TOLERANCE:
|
| 312 |
yield from _stream_model_cached(
|
| 313 |
-
f"cursed:{CURSED_FREQUENCY}:{lang}:{
|
| 314 |
localized_system_prompt(CURSED_SYSTEM_PROMPT, "es", lang),
|
| 315 |
should_continue=still_current,
|
| 316 |
user_prompt=localized_user_prompt(None, lang),
|
| 317 |
-
seed=_mix_seed(station_seed(CURSED_FREQUENCY),
|
| 318 |
max_tokens=160,
|
| 319 |
)
|
| 320 |
return
|
|
@@ -333,11 +370,11 @@ def tune(frequency: float, language: str = "es", variant: float = 0) -> str:
|
|
| 333 |
return
|
| 334 |
|
| 335 |
yield from _stream_model_cached(
|
| 336 |
-
f"station:{canonical}:{lang}:{
|
| 337 |
station_system_prompt(canonical, lang),
|
| 338 |
should_continue=still_current,
|
| 339 |
user_prompt=localized_user_prompt(station, lang),
|
| 340 |
-
seed=_mix_seed(station_seed(canonical),
|
| 341 |
)
|
| 342 |
|
| 343 |
|
|
@@ -393,7 +430,7 @@ def _warm_up():
|
|
| 393 |
so the first visitor (a judge) doesn't pay the cold-start penalty: the GGUF
|
| 394 |
is already in memory and llama.cpp is warm before anyone turns the dial."""
|
| 395 |
try:
|
| 396 |
-
canonical =
|
| 397 |
for _ in stream_broadcast(
|
| 398 |
station_system_prompt(canonical, "es"),
|
| 399 |
user_prompt="hola",
|
|
@@ -407,7 +444,9 @@ def _warm_up():
|
|
| 407 |
|
| 408 |
|
| 409 |
# Kick the warm-up as soon as the module is imported (HF imports app.py on boot).
|
| 410 |
-
|
|
|
|
|
|
|
| 411 |
|
| 412 |
|
| 413 |
if __name__ == "__main__":
|
|
|
|
| 11 |
# found in __main__") instead of executing the __main__ block at the bottom.
|
| 12 |
os.environ.setdefault("GRADIO_SSR_MODE", "false")
|
| 13 |
|
| 14 |
+
import json
|
| 15 |
import queue
|
| 16 |
import re
|
| 17 |
import threading
|
|
|
|
| 44 |
from stations import (
|
| 45 |
CURSED_FREQUENCY,
|
| 46 |
CURSED_SYSTEM_PROMPT,
|
| 47 |
+
STATION_FREQUENCIES,
|
| 48 |
STATION_TOLERANCE,
|
| 49 |
get_station,
|
| 50 |
localized_system_prompt,
|
|
|
|
| 124 |
_broadcast_cache: dict[str, str] = {}
|
| 125 |
_CACHE_MAX = 256
|
| 126 |
|
| 127 |
+
# Pre-baked broadcasts: stations and the cursed signal are generated ahead of
|
| 128 |
+
# time (see prebake.py) into broadcasts_cache.json and served instantly, so a
|
| 129 |
+
# visitor never waits ~50s for a first-touch generation on the Space's CPU.
|
| 130 |
+
# Per-listener variety is preserved by baking a POOL of wordings per station and
|
| 131 |
+
# mapping each listener's session variant onto one of them (variant % POOL_SIZE):
|
| 132 |
+
# different visitors land on different editions, but every edition is instant.
|
| 133 |
+
POOL_SIZE = 6
|
| 134 |
+
_PREBAKED: dict[str, str] = {}
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def _load_prebaked():
|
| 138 |
+
path = ROOT / "broadcasts_cache.json"
|
| 139 |
+
try:
|
| 140 |
+
if path.exists():
|
| 141 |
+
data = json.loads(path.read_text(encoding="utf-8"))
|
| 142 |
+
for key, text in data.items():
|
| 143 |
+
if isinstance(text, str) and text.strip():
|
| 144 |
+
_PREBAKED[key] = text
|
| 145 |
+
print(f"[prebake] loaded {len(_PREBAKED)} pre-baked broadcasts")
|
| 146 |
+
except Exception as exc: # noqa: BLE001 - never let a bad cache crash boot
|
| 147 |
+
print(f"[prebake] could not load cache: {exc}")
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
_load_prebaked()
|
| 151 |
+
|
| 152 |
# Rapid retuning: each /tune bumps this epoch. An in-flight generation that is
|
| 153 |
# no longer the latest self-terminates at the next token, releasing the model
|
| 154 |
# lock so the newest tune can run. Without this, a superseded generation runs to
|
|
|
|
| 273 |
def superseded():
|
| 274 |
return should_continue is not None and not should_continue()
|
| 275 |
|
| 276 |
+
# Pre-baked broadcasts are served instantly, no model call, no cold wait.
|
| 277 |
+
prebaked = _PREBAKED.get(cache_key)
|
| 278 |
+
if prebaked:
|
| 279 |
+
yield from _stream_fixed(prebaked, char_delay=0.018, should_continue=should_continue)
|
| 280 |
+
return
|
| 281 |
+
|
| 282 |
cached = _broadcast_cache.get(cache_key)
|
| 283 |
if cached:
|
| 284 |
yield from _stream_fixed(cached, char_delay=0.018, should_continue=should_continue)
|
|
|
|
| 324 |
def tune(frequency: float, language: str = "es", variant: float = 0) -> str:
|
| 325 |
"""Tunes a frequency and streams the broadcast (SSE).
|
| 326 |
|
| 327 |
+
`variant` is a per-listener session nonce. For the encrypted station it
|
| 328 |
+
drives that listener's unique cipher (kept fully per-session). For the
|
| 329 |
+
spoken stations and the cursed signal it selects one of POOL_SIZE pre-baked
|
| 330 |
+
editions (`pool`), so different visitors still hear different wordings while
|
| 331 |
+
every edition is served instantly from the pre-baked cache.
|
| 332 |
"""
|
| 333 |
frequency = float(frequency)
|
| 334 |
lang = normalize_lang(language)
|
| 335 |
var = _norm_variant(variant)
|
| 336 |
+
pool = var % POOL_SIZE
|
| 337 |
my_epoch = _next_tune_epoch()
|
| 338 |
|
| 339 |
def still_current():
|
|
|
|
| 347 |
# The unsolvable station: the model broadcasts, the frontend never cleans it.
|
| 348 |
if abs(frequency - CURSED_FREQUENCY) <= STATION_TOLERANCE:
|
| 349 |
yield from _stream_model_cached(
|
| 350 |
+
f"cursed:{CURSED_FREQUENCY}:{lang}:{pool}",
|
| 351 |
localized_system_prompt(CURSED_SYSTEM_PROMPT, "es", lang),
|
| 352 |
should_continue=still_current,
|
| 353 |
user_prompt=localized_user_prompt(None, lang),
|
| 354 |
+
seed=_mix_seed(station_seed(CURSED_FREQUENCY), pool),
|
| 355 |
max_tokens=160,
|
| 356 |
)
|
| 357 |
return
|
|
|
|
| 370 |
return
|
| 371 |
|
| 372 |
yield from _stream_model_cached(
|
| 373 |
+
f"station:{canonical}:{lang}:{pool}",
|
| 374 |
station_system_prompt(canonical, lang),
|
| 375 |
should_continue=still_current,
|
| 376 |
user_prompt=localized_user_prompt(station, lang),
|
| 377 |
+
seed=_mix_seed(station_seed(canonical), pool),
|
| 378 |
)
|
| 379 |
|
| 380 |
|
|
|
|
| 430 |
so the first visitor (a judge) doesn't pay the cold-start penalty: the GGUF
|
| 431 |
is already in memory and llama.cpp is warm before anyone turns the dial."""
|
| 432 |
try:
|
| 433 |
+
canonical = STATION_FREQUENCIES[len(STATION_FREQUENCIES) // 2]
|
| 434 |
for _ in stream_broadcast(
|
| 435 |
station_system_prompt(canonical, "es"),
|
| 436 |
user_prompt="hola",
|
|
|
|
| 444 |
|
| 445 |
|
| 446 |
# Kick the warm-up as soon as the module is imported (HF imports app.py on boot).
|
| 447 |
+
# Skipped when prebake.py imports this module just to reuse its helpers.
|
| 448 |
+
if not os.environ.get("PREBAKE"):
|
| 449 |
+
threading.Thread(target=_warm_up, daemon=True).start()
|
| 450 |
|
| 451 |
|
| 452 |
if __name__ == "__main__":
|