Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Startup Script for SyncMaster | |
| نقطة دخول موحدة تضمن تشغيل جميع المكونات المطلوبة | |
| """ | |
| import os | |
| import sys | |
| import time | |
| import logging | |
| import subprocess | |
| import signal | |
| import atexit | |
| from pathlib import Path | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(levelname)s - %(message)s' | |
| ) | |
| class SyncMasterLauncher: | |
| def __init__(self): | |
| self.recorder_process = None | |
| self.streamlit_process = None | |
| self.cleanup_registered = False | |
| def setup_cleanup(self): | |
| """Setup cleanup handlers""" | |
| if not self.cleanup_registered: | |
| atexit.register(self.cleanup) | |
| signal.signal(signal.SIGINT, self.signal_handler) | |
| signal.signal(signal.SIGTERM, self.signal_handler) | |
| self.cleanup_registered = True | |
| def signal_handler(self, signum, frame): | |
| """Handle termination signals""" | |
| logging.info(f"Received signal {signum}, cleaning up...") | |
| self.cleanup() | |
| sys.exit(0) | |
| def cleanup(self): | |
| """Clean up all processes""" | |
| logging.info("🧹 Cleaning up processes...") | |
| if self.recorder_process and self.recorder_process.poll() is None: | |
| try: | |
| self.recorder_process.terminate() | |
| self.recorder_process.wait(timeout=5) | |
| logging.info("✅ Recorder server terminated") | |
| except: | |
| try: | |
| self.recorder_process.kill() | |
| logging.info("⚠️ Recorder server killed") | |
| except: | |
| pass | |
| if self.streamlit_process and self.streamlit_process.poll() is None: | |
| try: | |
| self.streamlit_process.terminate() | |
| self.streamlit_process.wait(timeout=5) | |
| logging.info("✅ Streamlit server terminated") | |
| except: | |
| try: | |
| self.streamlit_process.kill() | |
| logging.info("⚠️ Streamlit server killed") | |
| except: | |
| pass | |
| def start_recorder_server(self): | |
| """Start the recorder server""" | |
| try: | |
| logging.info("🚀 Starting recorder server...") | |
| self.recorder_process = subprocess.Popen( | |
| [sys.executable, 'recorder_server.py'], | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE | |
| ) | |
| # Wait for server to start | |
| time.sleep(3) | |
| # Check if process is running | |
| if self.recorder_process.poll() is None: | |
| # Verify server is responding | |
| try: | |
| import requests | |
| response = requests.get('http://localhost:5001/record', timeout=5) | |
| if response.status_code == 200: | |
| logging.info("✅ Recorder server started successfully on port 5001") | |
| return True | |
| else: | |
| logging.warning(f"⚠️ Recorder server responded with status: {response.status_code}") | |
| except Exception as e: | |
| logging.warning(f"⚠️ Could not verify recorder server: {e}") | |
| # Server process is running even if verification failed | |
| return True | |
| else: | |
| logging.error("❌ Recorder server process failed to start") | |
| return False | |
| except Exception as e: | |
| logging.error(f"❌ Failed to start recorder server: {e}") | |
| return False | |
| def start_streamlit_app(self, port=5050, host="0.0.0.0"): | |
| """Start the Streamlit application""" | |
| try: | |
| logging.info(f"🚀 Starting Streamlit app on {host}:{port}...") | |
| cmd = [ | |
| sys.executable, '-m', 'streamlit', 'run', 'app.py', | |
| '--server.port', str(port), | |
| '--server.address', host, | |
| '--server.headless', 'true', | |
| '--browser.gatherUsageStats', 'false' | |
| ] | |
| self.streamlit_process = subprocess.Popen(cmd) | |
| # Wait a bit for Streamlit to start | |
| time.sleep(5) | |
| if self.streamlit_process.poll() is None: | |
| logging.info(f"✅ Streamlit app started successfully on http://{host}:{port}") | |
| return True | |
| else: | |
| logging.error("❌ Streamlit app failed to start") | |
| return False | |
| except Exception as e: | |
| logging.error(f"❌ Failed to start Streamlit app: {e}") | |
| return False | |
| def launch_integrated(self): | |
| """Launch with integrated server (recommended for HuggingFace)""" | |
| logging.info("🚀 Launching SyncMaster with integrated server...") | |
| self.setup_cleanup() | |
| # Start Streamlit with integrated server | |
| try: | |
| # Import to trigger integrated server startup | |
| import app | |
| # Run Streamlit | |
| import streamlit.web.cli as stcli | |
| import sys | |
| # Set command line arguments for Streamlit | |
| sys.argv = [ | |
| "streamlit", "run", "app.py", | |
| "--server.port", "5050", | |
| "--server.address", "0.0.0.0", | |
| "--server.headless", "true", | |
| "--browser.gatherUsageStats", "false" | |
| ] | |
| # Run Streamlit CLI | |
| stcli.main() | |
| except Exception as e: | |
| logging.error(f"❌ Failed to launch integrated mode: {e}") | |
| return False | |
| def launch_separate(self): | |
| """Launch with separate processes (development mode)""" | |
| logging.info("🚀 Launching SyncMaster with separate processes...") | |
| self.setup_cleanup() | |
| # Start recorder server first | |
| if not self.start_recorder_server(): | |
| logging.error("❌ Failed to start recorder server, aborting...") | |
| return False | |
| # Start Streamlit app | |
| if not self.start_streamlit_app(): | |
| logging.error("❌ Failed to start Streamlit app, aborting...") | |
| self.cleanup() | |
| return False | |
| logging.info("✅ All services started successfully!") | |
| logging.info("🌐 Access the application at: http://localhost:5050") | |
| logging.info("🎙️ Recorder API available at: http://localhost:5001") | |
| try: | |
| # Keep the main process alive | |
| while True: | |
| time.sleep(1) | |
| # Check if processes are still running | |
| if self.recorder_process and self.recorder_process.poll() is not None: | |
| logging.error("❌ Recorder server process died") | |
| break | |
| if self.streamlit_process and self.streamlit_process.poll() is not None: | |
| logging.error("❌ Streamlit app process died") | |
| break | |
| except KeyboardInterrupt: | |
| logging.info("👋 Shutting down...") | |
| finally: | |
| self.cleanup() | |
| def main(): | |
| """Main entry point""" | |
| launcher = SyncMasterLauncher() | |
| # Check if running in HuggingFace or similar environment | |
| if os.getenv('SPACE_ID') or '--integrated' in sys.argv: | |
| # Use integrated mode for cloud deployments | |
| launcher.launch_integrated() | |
| else: | |
| # Use separate processes for local development | |
| launcher.launch_separate() | |
| if __name__ == "__main__": | |
| main() | |