""" app.py - Entry point for Hugging Face Spaces. On Hugging Face Spaces, Gradio runs as the primary app on port 7860. FastAPI runs as a background thread on port 8000 internally. The Gradio UI talks to FastAPI on localhost:8000 (same machine). This is the same architecture as local development — it works perfectly on HF Spaces because both processes run on the same container. """ import logging import os import sys import tempfile import threading import time logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s - %(message)s", handlers=[logging.StreamHandler(sys.stdout)], ) logger = logging.getLogger(__name__) from dotenv import load_dotenv load_dotenv() from config import config def validate_environment(): if not config.GROQ_API_KEY or config.GROQ_API_KEY in ("", "your_groq_api_key_here"): logger.warning("=" * 60) logger.warning("GROQ_API_KEY not set. Using extractive fallback LLM.") logger.warning("Add GROQ_API_KEY in Space Settings > Repository secrets.") logger.warning("=" * 60) def run_fastapi(): """Run FastAPI backend on port 8000 in a background thread.""" import uvicorn logger.info(f"Starting FastAPI on port {config.API_PORT} ...") uvicorn.run( "api:app", host="0.0.0.0", port=config.API_PORT, log_level="warning", reload=False, ) def wait_for_api(): """Wait until FastAPI is ready before launching Gradio.""" import requests as req url = f"http://127.0.0.1:{config.API_PORT}/health" for _ in range(60): try: if req.get(url, timeout=2).status_code == 200: logger.info("FastAPI is ready.") return True except Exception: pass time.sleep(1) logger.warning("FastAPI did not start in 60s. Gradio launching anyway.") return False if __name__ == "__main__": validate_environment() os.makedirs(config.CACHE_DIR, exist_ok=True) os.makedirs(config.REPORTS_DIR, exist_ok=True) logger.info("DocVision OCR - Hugging Face Spaces") logger.info(f" FastAPI -> http://localhost:{config.API_PORT}") logger.info(f" Gradio -> http://0.0.0.0:7860") # Start FastAPI in background thread api_thread = threading.Thread(target=run_fastapi, daemon=True, name="fastapi") api_thread.start() # Wait for FastAPI to be healthy wait_for_api() # Launch Gradio on port 7860 — this is the port HF Spaces exposes import gradio as gr from ui import CSS, create_interface demo = create_interface() demo.launch( server_name="0.0.0.0", server_port=7860, share=False, show_error=True, ssr_mode=False, theme=gr.themes.Soft(), css=CSS, )