Spaces:
Running
Running
| import os | |
| import socket | |
| import threading | |
| import gradio as gr | |
| # Force CPU by default (safe for Spaces and small hosts) | |
| os.environ.setdefault("CUDA_VISIBLE_DEVICES", "-1") | |
| from metrics import get_hf_bleurt, get_hf_rouge | |
| from ui.manual_tab import build_manual_tab | |
| from ui.csv_tab import build_csv_tab | |
| def _parse_auth_from_env(): | |
| """ | |
| Read APP_USERS env var if present. | |
| Format: APP_USERS="alice:StrongPass,bob:AnotherPass" | |
| Returns list[tuple[str, str]] or None. | |
| """ | |
| users_env = os.getenv("APP_USERS", "").strip() | |
| if not users_env: | |
| return None | |
| pairs = [] | |
| for part in users_env.split(","): | |
| if ":" in part: | |
| u, p = part.split(":", 1) | |
| u, p = u.strip(), p.strip() | |
| if u and p: | |
| pairs.append((u, p)) | |
| return pairs or None | |
| def _is_port_free(port: int) -> bool: | |
| with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: | |
| s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
| try: | |
| s.bind(("0.0.0.0", port)) | |
| except OSError: | |
| return False | |
| return True | |
| def _find_free_port(preferred: int = 7860, scan_to: int = 7960) -> int: | |
| if _is_port_free(preferred): | |
| return preferred | |
| for p in range(preferred + 1, scan_to + 1): | |
| if _is_port_free(p): | |
| return p | |
| with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: | |
| s.bind(("0.0.0.0", 0)) | |
| return s.getsockname()[1] | |
| def _running_in_spaces() -> bool: | |
| # Common envs on HF Spaces | |
| return bool(os.getenv("SPACE_ID") or os.getenv("SPACE_REPO_URL") or os.getenv("HF_SPACE")) | |
| if __name__ == "__main__": | |
| # Preload heavy metrics in background so UI stays responsive | |
| try: | |
| threading.Thread(target=get_hf_bleurt, daemon=True).start() | |
| threading.Thread(target=get_hf_rouge, daemon=True).start() | |
| except Exception: | |
| pass | |
| # Build UI | |
| iface = gr.TabbedInterface( | |
| interface_list=[build_manual_tab(), build_csv_tab()], | |
| tab_names=["Manual Input", "CSV Upload"], | |
| ) | |
| # Optional basic auth via env (works both locally and on Spaces) | |
| auth_creds = _parse_auth_from_env() | |
| # Decide runtime mode | |
| in_spaces = _running_in_spaces() | |
| # Respect platform-provided port if any, else pick a free one | |
| env_port = os.getenv("PORT") or os.getenv("GRADIO_SERVER_PORT") | |
| port = int(env_port) if env_port else _find_free_port(7860, 7960) | |
| # Queue (handle different Gradio versions) | |
| try: | |
| iface.queue(concurrency_count=1, max_size=20) | |
| except TypeError: | |
| iface.queue() | |
| if in_spaces: | |
| # On Spaces: bind publicly & enable share (Spaces sandbox blocks localhost) | |
| iface.launch( | |
| server_name="0.0.0.0", | |
| server_port=port, | |
| show_error=True, | |
| auth=auth_creds, | |
| auth_message="Restricted • Enter company credentials", | |
| ssr_mode=False, # avoids svelte-i18n SSR issues on Spaces | |
| share=True, # Spaces needs a public URL | |
| ) | |
| else: | |
| # Local DEV: true private local URL (no gradio.live) | |
| iface.launch( | |
| server_name="127.0.0.1", # <-- use this URL in your browser | |
| server_port=port, | |
| show_error=True, | |
| auth=auth_creds, | |
| share=False, # <-- prevents expiring public link | |
| ) | |