Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Hugging Face Spaces Entry Point | |
| This script: | |
| 1. Loads secrets from HF Spaces environment variables | |
| 2. Creates config.json and credentials.json from those secrets | |
| 3. Starts the automation runner in the background | |
| 4. Serves the static web interface | |
| """ | |
| import os | |
| import json | |
| import subprocess | |
| import signal | |
| import sys | |
| import time | |
| import threading | |
| from pathlib import Path | |
| from http.server import HTTPServer, SimpleHTTPRequestHandler | |
| from functools import partial | |
| # Configuration | |
| PORT = int(os.getenv('PORT', 7860)) | |
| BASE_DIR = Path(__file__).parent | |
| AUTOMATION_RUNNER = BASE_DIR / "scripts" / "automation_runner.py" | |
| # Global process reference for cleanup | |
| automation_process = None | |
| def load_secrets_from_env(): | |
| """Load secrets from HF Spaces environment variables and create config files""" | |
| print("π Loading secrets from environment variables...") | |
| # Load config.json from environment | |
| config_json_str = os.getenv('HF_CONFIG_JSON') | |
| if config_json_str: | |
| try: | |
| config_data = json.loads(config_json_str) | |
| config_file = BASE_DIR / "config.json" | |
| with open(config_file, 'w') as f: | |
| json.dump(config_data, f, indent=2) | |
| print(f"β Created config.json from HF_CONFIG_JSON secret") | |
| except json.JSONDecodeError as e: | |
| print(f"β Error parsing HF_CONFIG_JSON: {e}") | |
| sys.exit(1) | |
| else: | |
| config_file = BASE_DIR / "config.json" | |
| if not config_file.exists(): | |
| print("β οΈ HF_CONFIG_JSON not found in environment") | |
| print("β οΈ Please set HF_CONFIG_JSON secret in your Hugging Face Space settings") | |
| print("β οΈ See SECRETS_SETUP.md for instructions") | |
| # Don't exit - allow the app to run without automation | |
| # Load credentials.json from environment | |
| credentials_json_str = os.getenv('HF_CREDENTIALS_JSON') | |
| if credentials_json_str: | |
| try: | |
| credentials_data = json.loads(credentials_json_str) | |
| credentials_file = BASE_DIR / "credentials.json" | |
| with open(credentials_file, 'w') as f: | |
| json.dump(credentials_data, f, indent=2) | |
| print(f"β Created credentials.json from HF_CREDENTIALS_JSON secret") | |
| except json.JSONDecodeError as e: | |
| print(f"β Error parsing HF_CREDENTIALS_JSON: {e}") | |
| sys.exit(1) | |
| else: | |
| credentials_file = BASE_DIR / "credentials.json" | |
| if not credentials_file.exists(): | |
| print("β οΈ HF_CREDENTIALS_JSON not found in environment") | |
| print("β οΈ Google Sheets sync will not work without credentials") | |
| print() | |
| def start_automation(): | |
| """Start the automation runner in the background""" | |
| global automation_process | |
| # Check if automation script exists | |
| if not AUTOMATION_RUNNER.exists(): | |
| print(f"β οΈ Automation runner not found: {AUTOMATION_RUNNER}") | |
| return | |
| # Check if config exists | |
| config_file = BASE_DIR / "config.json" | |
| if not config_file.exists(): | |
| print("β οΈ config.json not found, skipping automation startup") | |
| return | |
| print("π Starting automation runner...") | |
| try: | |
| automation_process = subprocess.Popen( | |
| [sys.executable, str(AUTOMATION_RUNNER)], | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| text=True, | |
| bufsize=1 | |
| ) | |
| # Stream automation output in a separate thread | |
| def stream_output(): | |
| for line in automation_process.stdout: | |
| print(f"[AUTOMATION] {line}", end='') | |
| threading.Thread(target=stream_output, daemon=True).start() | |
| print("β Automation runner started\n") | |
| except Exception as e: | |
| print(f"β Failed to start automation: {e}\n") | |
| def cleanup(signum=None, frame=None): | |
| """Cleanup function to terminate background processes""" | |
| global automation_process | |
| print("\n\nπ Shutting down...") | |
| if automation_process: | |
| print("π§Ή Stopping automation runner...") | |
| automation_process.terminate() | |
| automation_process.wait(timeout=5) | |
| print("β Cleanup complete\n") | |
| sys.exit(0) | |
| class CustomHTTPRequestHandler(SimpleHTTPRequestHandler): | |
| """Custom handler to serve from the correct directory""" | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, directory=str(BASE_DIR), **kwargs) | |
| def log_message(self, format, *args): | |
| """Custom logging to show requests""" | |
| print(f"[WEB] {self.address_string()} - {format % args}") | |
| def start_web_server(): | |
| """Start the HTTP server to serve the static files""" | |
| print(f"π Starting web server on port {PORT}...") | |
| handler = CustomHTTPRequestHandler | |
| httpd = HTTPServer(('0.0.0.0', PORT), handler) | |
| print(f"β Web server running at http://0.0.0.0:{PORT}") | |
| print(f"π Open the map: http://0.0.0.0:{PORT}/index.html") | |
| print(f"π‘ Press Ctrl+C to stop\n") | |
| try: | |
| httpd.serve_forever() | |
| except KeyboardInterrupt: | |
| pass | |
| finally: | |
| httpd.shutdown() | |
| def main(): | |
| """Main entry point""" | |
| print("=" * 70) | |
| print("πΊοΈ Telugu Dialect Map - Hugging Face Spaces") | |
| print("=" * 70) | |
| print() | |
| # Register signal handlers for graceful shutdown | |
| signal.signal(signal.SIGINT, cleanup) | |
| signal.signal(signal.SIGTERM, cleanup) | |
| # Load secrets from environment variables | |
| load_secrets_from_env() | |
| # Start background automation | |
| start_automation() | |
| # Give automation a moment to start | |
| time.sleep(2) | |
| # Start web server (blocks here) | |
| start_web_server() | |
| # Cleanup (if we ever get here) | |
| cleanup() | |
| if __name__ == "__main__": | |
| main() | |