"""Space entry point: assembly only. No logic and no module-level mutable state lives here. Gradio shares module globals across every visitor session, so the discipline starts now, while there is still nothing to share. """ import os import gradio as gr from japanese_avatar.ui.avatar_component import VrmStage # Serves avatar/ straight off disk, bypassing the Gradio cache, which is how the # browser reaches avatar.js, stage.html and tutor.vrm. Deliberately one dedicated # directory: this call's own docstring warns that ALL files under a listed path # become network-reachable. gr.set_static_paths(["avatar"]) def gpu_disabled() -> bool: """SC-4's kill switch: the whole turn loop must complete with DISABLE_GPU=1. Read per call rather than captured at import so a Space restart with the variable flipped takes effect without a code change. """ return os.environ.get("DISABLE_GPU", "0").strip().lower() in {"1", "true", "yes"} def build_app() -> gr.Blocks: """Build the Blocks app. Importable and callable from tests without launching.""" with gr.Blocks(title="Japanese Learning Avatar", fill_height=True) as demo: VrmStage() return demo if __name__ == "__main__": build_app().launch()