AndrewRqy commited on
Commit ·
f9490c0
1
Parent(s): fd741cf
Clean-Space pass: drop self-test, legacy unused handler, BISECT_MINIMAL branch, duplicate banner PNG, stale comments
Browse files- .env.example +14 -5
- app.py +2 -241
- assets/sprites/banner_near.png +0 -3
- run.sh +0 -1
.env.example
CHANGED
|
@@ -1,16 +1,25 @@
|
|
| 1 |
# Copy to .env.local and fill in. Without these, the app runs in mock mode.
|
| 2 |
|
| 3 |
-
# Modal-hosted OpenAI-compatible endpoint (vLLM serving Qwen2.5-
|
| 4 |
# Leave empty to force mock mode for the LLM calls.
|
| 5 |
MODAL_URL=
|
| 6 |
|
| 7 |
-
# Modal proxy auth (
|
| 8 |
MODAL_KEY=
|
| 9 |
MODAL_SECRET=
|
| 10 |
|
| 11 |
# Force mock mode for the LLM even if MODAL_URL is set.
|
| 12 |
ORACLES_FORCE_MOCK=0
|
| 13 |
|
| 14 |
-
#
|
| 15 |
-
#
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# Copy to .env.local and fill in. Without these, the app runs in mock mode.
|
| 2 |
|
| 3 |
+
# Modal-hosted OpenAI-compatible endpoint (vLLM serving Qwen2.5-14B + LoRA).
|
| 4 |
# Leave empty to force mock mode for the LLM calls.
|
| 5 |
MODAL_URL=
|
| 6 |
|
| 7 |
+
# Modal proxy auth (Modal-Key and Modal-Secret headers).
|
| 8 |
MODAL_KEY=
|
| 9 |
MODAL_SECRET=
|
| 10 |
|
| 11 |
# Force mock mode for the LLM even if MODAL_URL is set.
|
| 12 |
ORACLES_FORCE_MOCK=0
|
| 13 |
|
| 14 |
+
# Override the served-model alias. Defaults to "oracle-wizard-lora" which
|
| 15 |
+
# the deployed vLLM serves as Qwen2.5-14B + the custom humor LoRA. Set
|
| 16 |
+
# to "llm" to request the bare base model.
|
| 17 |
+
# ORACLES_LLM_MODEL=oracle-wizard-lora
|
| 18 |
+
|
| 19 |
+
# Disable LLM-call trace recording. Tracing is default-on; remove or set
|
| 20 |
+
# to 0 to keep it on. Set to 1 to opt out.
|
| 21 |
+
# ORACLES_TRACE_DISABLE=0
|
| 22 |
+
|
| 23 |
+
# Visual mode: "lean" (default; minimal PNGs for fast load) or "full"
|
| 24 |
+
# (parallax banner, scene landscapes, all decorative assets).
|
| 25 |
+
# ORACLES_VISUAL_MODE=lean
|
app.py
CHANGED
|
@@ -8,8 +8,7 @@ State machine:
|
|
| 8 |
inscribe → send_off → trial (1..5) → epilogue → done
|
| 9 |
|
| 10 |
Run:
|
| 11 |
-
python app.py # launches Gradio
|
| 12 |
-
python app.py --self-test # scripted walkthrough; exits 0 on pass
|
| 13 |
"""
|
| 14 |
|
| 15 |
from __future__ import annotations
|
|
@@ -4098,52 +4097,6 @@ def handle_grimoire_lang(state: GameState, language_label: str,
|
|
| 4098 |
return _ui_bundle(state)
|
| 4099 |
|
| 4100 |
|
| 4101 |
-
def _legacy_handle_grimoire_lang_unused(state, language_label, theme_label="", narration_label=""):
|
| 4102 |
-
"""Kept only to satisfy any stale call sites; identical to the refactor.
|
| 4103 |
-
DO NOT USE — call _apply_spread0_choices via handle_grimoire_lang instead."""
|
| 4104 |
-
if state.mode != "inscribe" or state.inscribe_step != 0:
|
| 4105 |
-
return _ui_bundle(state)
|
| 4106 |
-
state.lang = _label_to_lang_code(language_label)
|
| 4107 |
-
|
| 4108 |
-
# Resolve theme label back to its key; default to fantasy on miss.
|
| 4109 |
-
from oracles.themes import THEMES, DEFAULT_THEME
|
| 4110 |
-
chosen_key = DEFAULT_THEME
|
| 4111 |
-
for key, theme in THEMES.items():
|
| 4112 |
-
if theme.display_name == theme_label:
|
| 4113 |
-
chosen_key = key
|
| 4114 |
-
break
|
| 4115 |
-
state.theme = chosen_key
|
| 4116 |
-
|
| 4117 |
-
# Resolve narration-length label back to its key; default to medium.
|
| 4118 |
-
# Label is now a `{"en": ..., "zh": ...}` dict — match against either
|
| 4119 |
-
# language so the lookup is robust to whichever tongue the dropdown
|
| 4120 |
-
# was rendered in when the click happened.
|
| 4121 |
-
from oracles.state import NARRATION_LENGTHS as _NL
|
| 4122 |
-
chosen_nl = "medium"
|
| 4123 |
-
for key, (label, *_rest) in _NL.items():
|
| 4124 |
-
if isinstance(label, dict):
|
| 4125 |
-
if narration_label in label.values():
|
| 4126 |
-
chosen_nl = key
|
| 4127 |
-
break
|
| 4128 |
-
elif label == narration_label:
|
| 4129 |
-
chosen_nl = key
|
| 4130 |
-
break
|
| 4131 |
-
state.narration_length = chosen_nl
|
| 4132 |
-
|
| 4133 |
-
# Refresh hero/village defaults to the theme's archetypes, if the user
|
| 4134 |
-
# hasn't customized them yet (so the next spread's prompt shows themed
|
| 4135 |
-
# defaults like "Wren" / "Bunker 7" instead of "Tobin" / "the Hollow").
|
| 4136 |
-
theme_obj = THEMES[chosen_key]
|
| 4137 |
-
if state.hero_name in ("", "Tobin"):
|
| 4138 |
-
state.hero_name = theme_obj.hero_default
|
| 4139 |
-
if state.village_name in ("", "the Hollow"):
|
| 4140 |
-
state.village_name = theme_obj.village_default
|
| 4141 |
-
|
| 4142 |
-
state.grimoire_error = ""
|
| 4143 |
-
state.inscribe_step = 1
|
| 4144 |
-
return _ui_bundle(state)
|
| 4145 |
-
|
| 4146 |
-
|
| 4147 |
def handle_grimoire_name(state: GameState, hero_name: str):
|
| 4148 |
"""Step 1 → 2: inscribe the hero's name."""
|
| 4149 |
if state.mode != "inscribe" or state.inscribe_step != 1:
|
|
@@ -4234,43 +4187,6 @@ def handle_grimoire_begin(state: GameState):
|
|
| 4234 |
yield _ui_bundle(state, trial_substate=TRIAL_STATE_AWAIT)
|
| 4235 |
|
| 4236 |
|
| 4237 |
-
# Back-compat shim for the e2e test and self-test that still call the
|
| 4238 |
-
# original "seal everything in one shot" function.
|
| 4239 |
-
def handle_seal_oracles(
|
| 4240 |
-
state: GameState,
|
| 4241 |
-
hero_name: str,
|
| 4242 |
-
village_name: str,
|
| 4243 |
-
language_label: str,
|
| 4244 |
-
o1: str,
|
| 4245 |
-
o2: str,
|
| 4246 |
-
o3: str,
|
| 4247 |
-
o4: str,
|
| 4248 |
-
o5: str,
|
| 4249 |
-
):
|
| 4250 |
-
if state.mode != "inscribe":
|
| 4251 |
-
return _ui_bundle(state)
|
| 4252 |
-
texts = [o1 or "", o2 or "", o3 or "", o4 or "", o5 or ""]
|
| 4253 |
-
missing = [i + 1 for i, t in enumerate(texts) if not t.strip()]
|
| 4254 |
-
if missing:
|
| 4255 |
-
roman = ", ".join(_ROMAN.get(i, str(i)) for i in missing)
|
| 4256 |
-
err = (
|
| 4257 |
-
f"The parchment is blank — Oracle{'s' if len(missing) > 1 else ''} "
|
| 4258 |
-
f"{roman} must hold at least one word."
|
| 4259 |
-
)
|
| 4260 |
-
# Surface error in the legacy slot AND on the grimoire so tests can find it.
|
| 4261 |
-
state.grimoire_error = err
|
| 4262 |
-
return _ui_bundle(state, inscribe_error=err)
|
| 4263 |
-
state.hero_name = (hero_name or "Tobin").strip() or "Tobin"
|
| 4264 |
-
state.village_name = (village_name or "the Hollow").strip() or "the Hollow"
|
| 4265 |
-
state.lang = _label_to_lang_code(language_label)
|
| 4266 |
-
for o, text in zip(state.oracles, texts):
|
| 4267 |
-
o.text = text
|
| 4268 |
-
state.inscribe_step = 8 # consider all spreads "passed"
|
| 4269 |
-
state.mode = "send_off"
|
| 4270 |
-
state.grimoire_error = ""
|
| 4271 |
-
return _ui_bundle(state, inscribe_error="")
|
| 4272 |
-
|
| 4273 |
-
|
| 4274 |
def handle_send_off(state: GameState):
|
| 4275 |
"""send_off → trial 1. Generates the 5 obstacles AND kicks off the
|
| 4276 |
background precompute so trial reveals are instant in live mode."""
|
|
@@ -5032,140 +4948,6 @@ def build_app() -> gr.Blocks:
|
|
| 5032 |
return demo
|
| 5033 |
|
| 5034 |
|
| 5035 |
-
# ---------------------------------------------------------------------------
|
| 5036 |
-
# Self-test
|
| 5037 |
-
# ---------------------------------------------------------------------------
|
| 5038 |
-
|
| 5039 |
-
|
| 5040 |
-
def _drain(gen_or_value):
|
| 5041 |
-
"""Drain a generator handler to its final yielded bundle.
|
| 5042 |
-
|
| 5043 |
-
Several click handlers (handle_open_oracle, handle_continue,
|
| 5044 |
-
handle_grimoire_begin, handle_send_off) are generators that yield
|
| 5045 |
-
intermediate "walking-hero" UI states then a terminal bundle. The
|
| 5046 |
-
self-test only cares about the terminal bundle. Pass-through any
|
| 5047 |
-
non-generator return value untouched so the helper works for
|
| 5048 |
-
regular handlers too.
|
| 5049 |
-
"""
|
| 5050 |
-
import inspect as _inspect
|
| 5051 |
-
if _inspect.isgenerator(gen_or_value):
|
| 5052 |
-
last = None
|
| 5053 |
-
for b in gen_or_value:
|
| 5054 |
-
last = b
|
| 5055 |
-
return last
|
| 5056 |
-
return gen_or_value
|
| 5057 |
-
|
| 5058 |
-
|
| 5059 |
-
def run_self_test() -> int:
|
| 5060 |
-
"""Scripted walkthrough that doesn't launch the server.
|
| 5061 |
-
|
| 5062 |
-
Returns 0 on success, non-zero on failure.
|
| 5063 |
-
"""
|
| 5064 |
-
# Force mock mode then rebuild the module-level CLIENT.
|
| 5065 |
-
os.environ["ORACLES_FORCE_MOCK"] = "1"
|
| 5066 |
-
global CLIENT
|
| 5067 |
-
CLIENT = LLMClient()
|
| 5068 |
-
assert CLIENT.using_mock, "self-test requires mock mode"
|
| 5069 |
-
|
| 5070 |
-
# Fresh state — and seed the inputs as scripted.
|
| 5071 |
-
state = fresh_state()
|
| 5072 |
-
|
| 5073 |
-
oracle_texts = [
|
| 5074 |
-
"be patient",
|
| 5075 |
-
"pizza is square",
|
| 5076 |
-
"🍕",
|
| 5077 |
-
"wooden spoon",
|
| 5078 |
-
"42",
|
| 5079 |
-
]
|
| 5080 |
-
|
| 5081 |
-
# --- inscribe → send_off ---
|
| 5082 |
-
bundle = handle_seal_oracles(
|
| 5083 |
-
state,
|
| 5084 |
-
"Tobin",
|
| 5085 |
-
"the Hollow",
|
| 5086 |
-
LANG_LABELS["en"],
|
| 5087 |
-
*oracle_texts,
|
| 5088 |
-
)
|
| 5089 |
-
state = bundle[0]
|
| 5090 |
-
assert state.mode == "send_off", f"expected send_off, got {state.mode!r}"
|
| 5091 |
-
assert all(state.oracles[i].text == oracle_texts[i] for i in range(NUM_ORACLES)), \
|
| 5092 |
-
"oracle texts not persisted"
|
| 5093 |
-
|
| 5094 |
-
# --- send_off → trial 1 (also generates obstacles) ---
|
| 5095 |
-
bundle = _drain(handle_send_off(state))
|
| 5096 |
-
state = bundle[0]
|
| 5097 |
-
assert state.mode == "trial", f"expected trial, got {state.mode!r}"
|
| 5098 |
-
assert state.current_trial == 1, f"expected current_trial=1, got {state.current_trial}"
|
| 5099 |
-
assert len(state.obstacles) == NUM_TRIALS, (
|
| 5100 |
-
f"expected {NUM_TRIALS} obstacles, got {len(state.obstacles)}"
|
| 5101 |
-
)
|
| 5102 |
-
assert state.obstacles[-1].is_dragon, "trial 5 should be dragon"
|
| 5103 |
-
|
| 5104 |
-
# --- trials 1..5 ---
|
| 5105 |
-
for trial_n in range(1, NUM_TRIALS + 1):
|
| 5106 |
-
assert state.mode == "trial", f"trial {trial_n}: bad mode {state.mode!r}"
|
| 5107 |
-
assert state.current_trial == trial_n, (
|
| 5108 |
-
f"trial {trial_n}: bad current_trial {state.current_trial}"
|
| 5109 |
-
)
|
| 5110 |
-
|
| 5111 |
-
# Open oracle (await -> reveal).
|
| 5112 |
-
bundle = _drain(handle_open_oracle(state, TRIAL_STATE_AWAIT))
|
| 5113 |
-
state = bundle[0]
|
| 5114 |
-
substate = bundle[1]
|
| 5115 |
-
assert substate == TRIAL_STATE_REVEAL, (
|
| 5116 |
-
f"trial {trial_n}: expected reveal substate, got {substate!r}"
|
| 5117 |
-
)
|
| 5118 |
-
|
| 5119 |
-
res = state.resolutions[-1]
|
| 5120 |
-
assert res.trial_index == trial_n, (
|
| 5121 |
-
f"trial {trial_n}: resolution.trial_index mismatch"
|
| 5122 |
-
)
|
| 5123 |
-
assert res.narration and len(res.narration.strip()) > 0, (
|
| 5124 |
-
f"trial {trial_n}: empty narration"
|
| 5125 |
-
)
|
| 5126 |
-
assert res.tactic and len(res.tactic.strip()) > 0, (
|
| 5127 |
-
f"trial {trial_n}: empty tactic"
|
| 5128 |
-
)
|
| 5129 |
-
# Image file should exist on disk and have non-zero size (mock SVG/PNG).
|
| 5130 |
-
assert res.image_path, f"trial {trial_n}: empty image_path"
|
| 5131 |
-
assert os.path.exists(res.image_path), (
|
| 5132 |
-
f"trial {trial_n}: image_path {res.image_path!r} not on disk"
|
| 5133 |
-
)
|
| 5134 |
-
assert os.path.getsize(res.image_path) > 0, (
|
| 5135 |
-
f"trial {trial_n}: image_path {res.image_path!r} is empty"
|
| 5136 |
-
)
|
| 5137 |
-
|
| 5138 |
-
# Continue.
|
| 5139 |
-
bundle = _drain(handle_continue(state, TRIAL_STATE_REVEAL))
|
| 5140 |
-
state = bundle[0]
|
| 5141 |
-
|
| 5142 |
-
# After trial 5 continue: epilogue.
|
| 5143 |
-
assert state.mode == "epilogue", (
|
| 5144 |
-
f"expected epilogue after trial {NUM_TRIALS}, got {state.mode!r}"
|
| 5145 |
-
)
|
| 5146 |
-
assert state.epilogue and state.epilogue.strip(), "epilogue empty"
|
| 5147 |
-
|
| 5148 |
-
# Restart should land us back in inscribe with a fresh state, names preserved.
|
| 5149 |
-
bundle = handle_restart(state)
|
| 5150 |
-
new_state = bundle[0]
|
| 5151 |
-
assert new_state.mode == "inscribe", (
|
| 5152 |
-
f"after restart expected inscribe, got {new_state.mode!r}"
|
| 5153 |
-
)
|
| 5154 |
-
assert new_state.hero_name == "Tobin", "hero name should be preserved"
|
| 5155 |
-
assert new_state.village_name == "the Hollow", "village name should be preserved"
|
| 5156 |
-
assert all(o.text == "" for o in new_state.oracles), (
|
| 5157 |
-
"oracles should be blank after restart"
|
| 5158 |
-
)
|
| 5159 |
-
assert new_state.resolutions == [], "resolutions should be cleared"
|
| 5160 |
-
|
| 5161 |
-
# Also exercise build_app() once.
|
| 5162 |
-
demo = build_app()
|
| 5163 |
-
assert demo is not None, "build_app returned None"
|
| 5164 |
-
|
| 5165 |
-
print("SELF TEST PASSED")
|
| 5166 |
-
return 0
|
| 5167 |
-
|
| 5168 |
-
|
| 5169 |
# ---------------------------------------------------------------------------
|
| 5170 |
# Entry point
|
| 5171 |
# ---------------------------------------------------------------------------
|
|
@@ -5175,10 +4957,6 @@ def run_self_test() -> int:
|
|
| 5175 |
# to its own ``.launch()`` with DEFAULT settings — which means everything we
|
| 5176 |
# pass to ``demo.launch(...)`` below would be ignored (no theme, no css, no
|
| 5177 |
# ssr_mode=False, no allowed_paths). So we build the demo at module scope.
|
| 5178 |
-
#
|
| 5179 |
-
# To keep --self-test fast (it doesn't need a Blocks instance, and building
|
| 5180 |
-
# one base64-encodes ~30 sprites), we skip the eager build when the flag is
|
| 5181 |
-
# present.
|
| 5182 |
|
| 5183 |
# Register the assets directory with Gradio's static file router so
|
| 5184 |
# /gradio_api/file=<absolute-path> URLs served at runtime resolve to actual
|
|
@@ -5192,27 +4970,10 @@ except Exception:
|
|
| 5192 |
pass
|
| 5193 |
|
| 5194 |
|
| 5195 |
-
|
| 5196 |
-
demo = None
|
| 5197 |
-
elif os.environ.get("BISECT_MINIMAL") == "1":
|
| 5198 |
-
# Diagnostic bisect: if the App tab shows this minimal page, then the
|
| 5199 |
-
# full build_app() Blocks tree is what breaks iframe rendering. If it
|
| 5200 |
-
# ALSO shows nothing, the problem is outside build_app (Docker, port
|
| 5201 |
-
# routing, allowed_paths, etc).
|
| 5202 |
-
with gr.Blocks(title="The Apprentice — bisect probe") as demo:
|
| 5203 |
-
gr.Markdown("# BISECT PROBE")
|
| 5204 |
-
gr.Markdown(
|
| 5205 |
-
"If you can read this, the Docker + Gradio + iframe layers work. "
|
| 5206 |
-
"The full build_app() Blocks tree is what's breaking rendering."
|
| 5207 |
-
)
|
| 5208 |
-
gr.Button("Click me").click(lambda: "ok", outputs=gr.Textbox())
|
| 5209 |
-
else:
|
| 5210 |
-
demo = build_app()
|
| 5211 |
|
| 5212 |
|
| 5213 |
def main() -> int:
|
| 5214 |
-
if "--self-test" in sys.argv:
|
| 5215 |
-
return run_self_test()
|
| 5216 |
# Local entry point — uses the module-level ``demo`` so the local run
|
| 5217 |
# matches the HF Space behavior exactly.
|
| 5218 |
# ssr_mode is Gradio 5+ only. The local dev env may still be on
|
|
|
|
| 8 |
inscribe → send_off → trial (1..5) → epilogue → done
|
| 9 |
|
| 10 |
Run:
|
| 11 |
+
python app.py # launches Gradio (uses ./run.sh for full setup)
|
|
|
|
| 12 |
"""
|
| 13 |
|
| 14 |
from __future__ import annotations
|
|
|
|
| 4097 |
return _ui_bundle(state)
|
| 4098 |
|
| 4099 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4100 |
def handle_grimoire_name(state: GameState, hero_name: str):
|
| 4101 |
"""Step 1 → 2: inscribe the hero's name."""
|
| 4102 |
if state.mode != "inscribe" or state.inscribe_step != 1:
|
|
|
|
| 4187 |
yield _ui_bundle(state, trial_substate=TRIAL_STATE_AWAIT)
|
| 4188 |
|
| 4189 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4190 |
def handle_send_off(state: GameState):
|
| 4191 |
"""send_off → trial 1. Generates the 5 obstacles AND kicks off the
|
| 4192 |
background precompute so trial reveals are instant in live mode."""
|
|
|
|
| 4948 |
return demo
|
| 4949 |
|
| 4950 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4951 |
# ---------------------------------------------------------------------------
|
| 4952 |
# Entry point
|
| 4953 |
# ---------------------------------------------------------------------------
|
|
|
|
| 4957 |
# to its own ``.launch()`` with DEFAULT settings — which means everything we
|
| 4958 |
# pass to ``demo.launch(...)`` below would be ignored (no theme, no css, no
|
| 4959 |
# ssr_mode=False, no allowed_paths). So we build the demo at module scope.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4960 |
|
| 4961 |
# Register the assets directory with Gradio's static file router so
|
| 4962 |
# /gradio_api/file=<absolute-path> URLs served at runtime resolve to actual
|
|
|
|
| 4970 |
pass
|
| 4971 |
|
| 4972 |
|
| 4973 |
+
demo = build_app()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4974 |
|
| 4975 |
|
| 4976 |
def main() -> int:
|
|
|
|
|
|
|
| 4977 |
# Local entry point — uses the module-level ``demo`` so the local run
|
| 4978 |
# matches the HF Space behavior exactly.
|
| 4979 |
# ssr_mode is Gradio 5+ only. The local dev env may still be on
|
assets/sprites/banner_near.png
DELETED
Git LFS Details
|
run.sh
CHANGED
|
@@ -25,7 +25,6 @@
|
|
| 25 |
# Sharing-is-Caring badge.
|
| 26 |
# --no-trace Disable trace writing for this run (sets
|
| 27 |
# ORACLES_TRACE_DISABLE=1).
|
| 28 |
-
# --self-test Pass-through to app.py for the scripted walkthrough.
|
| 29 |
# --full Enable ALL decorative PNGs (parallax banner,
|
| 30 |
# parchment, phase backdrops, scene landscapes,
|
| 31 |
# wizard-desk, open-book, demo-card backdrop).
|
|
|
|
| 25 |
# Sharing-is-Caring badge.
|
| 26 |
# --no-trace Disable trace writing for this run (sets
|
| 27 |
# ORACLES_TRACE_DISABLE=1).
|
|
|
|
| 28 |
# --full Enable ALL decorative PNGs (parallax banner,
|
| 29 |
# parchment, phase backdrops, scene landscapes,
|
| 30 |
# wizard-desk, open-book, demo-card backdrop).
|