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 | |
) | |