Spaces:
Runtime error
Runtime error
| #!/usr/bin/env python3 | |
| """ | |
| Create an improved Mac App Bundle for SafetyMaster Pro | |
| with better cross-Mac compatibility | |
| """ | |
| import os | |
| import shutil | |
| import stat | |
| import plistlib | |
| from pathlib import Path | |
| def create_improved_mac_app(): | |
| """Create an improved Mac app bundle with better compatibility.""" | |
| app_name = "SafetyMaster Pro" | |
| app_dir = f"{app_name}.app" | |
| # Remove existing app if it exists | |
| if os.path.exists(app_dir): | |
| shutil.rmtree(app_dir) | |
| # Create app bundle structure | |
| contents_dir = os.path.join(app_dir, "Contents") | |
| macos_dir = os.path.join(contents_dir, "MacOS") | |
| resources_dir = os.path.join(contents_dir, "Resources") | |
| os.makedirs(macos_dir, exist_ok=True) | |
| os.makedirs(resources_dir, exist_ok=True) | |
| # Copy all necessary files to Resources | |
| files_to_copy = [ | |
| 'web_interface.py', | |
| 'safety_detector.py', | |
| 'camera_manager.py', | |
| 'config.py', | |
| 'requirements.txt', | |
| 'ppe_yolov8_model_0.pt', | |
| 'ppe_model.pt', | |
| 'yolov8n.pt' | |
| ] | |
| for file in files_to_copy: | |
| if os.path.exists(file): | |
| shutil.copy2(file, resources_dir) | |
| print(f"Copied {file}") | |
| # Copy templates directory | |
| if os.path.exists('templates'): | |
| shutil.copytree('templates', os.path.join(resources_dir, 'templates')) | |
| print("Copied templates directory") | |
| # Create improved executable script | |
| executable_script = '''#!/bin/bash | |
| # SafetyMaster Pro - Improved Mac App Bundle Launcher | |
| # Compatible with Intel and Apple Silicon Macs | |
| # Get the app bundle directory - Fixed path resolution | |
| SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | |
| APP_DIR="$( cd "$SCRIPT_DIR/../.." && pwd )" | |
| RESOURCES_DIR="$APP_DIR/Contents/Resources" | |
| # Function to show error dialog | |
| show_error() { | |
| osascript -e "display dialog \\"$1\\" with title \\"SafetyMaster Pro - Error\\" buttons {\\"OK\\"} default button \\"OK\\" with icon caution" | |
| } | |
| # Function to show info dialog | |
| show_info() { | |
| osascript -e "display dialog \\"$1\\" with title \\"SafetyMaster Pro\\" buttons {\\"OK\\"} default button \\"OK\\" with icon note" | |
| } | |
| # Check if resources directory exists | |
| if [[ ! -d "$RESOURCES_DIR" ]]; then | |
| show_error "Resources directory not found at: $RESOURCES_DIR | |
| This might be due to: | |
| - Incomplete app bundle | |
| - Incorrect installation | |
| - File permissions | |
| Please re-download SafetyMaster Pro." | |
| exit 1 | |
| fi | |
| # Change to resources directory | |
| cd "$RESOURCES_DIR" || { | |
| show_error "Failed to access application resources at: $RESOURCES_DIR | |
| Please check file permissions and try again." | |
| exit 1 | |
| } | |
| # Detect Python installation with multiple fallbacks | |
| PYTHON_CMD="" | |
| # Check for various Python installations in order of preference | |
| for cmd in python3.11 python3.10 python3.9 python3.8 python3 python; do | |
| if command -v "$cmd" &> /dev/null; then | |
| # Verify it's Python 3.8+ | |
| version=$("$cmd" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>/dev/null || echo "0.0") | |
| if [[ $(echo "$version >= 3.8" | bc -l 2>/dev/null || echo "0") == "1" ]]; then | |
| PYTHON_CMD="$cmd" | |
| break | |
| fi | |
| fi | |
| done | |
| # If no suitable Python found, provide installation guidance | |
| if [[ -z "$PYTHON_CMD" ]]; then | |
| show_error "Python 3.8+ is required but not found. | |
| Installation options: | |
| 1. Official Python (Recommended): | |
| Download from: https://www.python.org/downloads/macos/ | |
| 2. Homebrew (if installed): | |
| brew install python3 | |
| 3. Xcode Command Line Tools: | |
| xcode-select --install | |
| After installation, restart this application." | |
| exit 1 | |
| fi | |
| echo "Using Python: $PYTHON_CMD" | |
| # Check if we're in a virtual environment, if not try to create one | |
| if [[ -z "$VIRTUAL_ENV" ]]; then | |
| VENV_DIR="$HOME/.safetymaster_venv" | |
| if [[ ! -d "$VENV_DIR" ]]; then | |
| echo "Creating virtual environment..." | |
| "$PYTHON_CMD" -m venv "$VENV_DIR" || { | |
| echo "Warning: Could not create virtual environment, using system Python" | |
| } | |
| fi | |
| if [[ -d "$VENV_DIR" ]]; then | |
| source "$VENV_DIR/bin/activate" | |
| PYTHON_CMD="python" | |
| fi | |
| fi | |
| # Install/upgrade dependencies with better error handling | |
| echo "Installing dependencies..." | |
| "$PYTHON_CMD" -m pip install --upgrade pip setuptools wheel > /dev/null 2>&1 || true | |
| # Install requirements with fallback options | |
| if ! "$PYTHON_CMD" -m pip install -r requirements.txt > /dev/null 2>&1; then | |
| echo "Trying alternative installation method..." | |
| if ! "$PYTHON_CMD" -m pip install --user -r requirements.txt > /dev/null 2>&1; then | |
| show_error "Failed to install required dependencies. | |
| Please try installing manually: | |
| 1. Open Terminal | |
| 2. Run: pip3 install opencv-python ultralytics flask flask-socketio torch torchvision | |
| Then restart SafetyMaster Pro." | |
| exit 1 | |
| fi | |
| fi | |
| # Check for camera permissions (macOS 10.14+) | |
| if [[ $(sw_vers -productVersion | cut -d. -f1) -ge 10 ]] && [[ $(sw_vers -productVersion | cut -d. -f2) -ge 14 ]]; then | |
| # Request camera permission by attempting to access camera | |
| "$PYTHON_CMD" -c " | |
| import cv2 | |
| import sys | |
| try: | |
| cap = cv2.VideoCapture(0) | |
| if cap.isOpened(): | |
| cap.release() | |
| print('Camera access OK') | |
| else: | |
| print('Camera access denied or no camera found') | |
| sys.exit(1) | |
| except Exception as e: | |
| print(f'Camera test failed: {e}') | |
| sys.exit(1) | |
| " > /dev/null 2>&1 || { | |
| show_error "Camera access is required for SafetyMaster Pro. | |
| Please: | |
| 1. Go to System Preferences > Security & Privacy > Camera | |
| 2. Enable camera access for SafetyMaster Pro | |
| 3. Restart the application | |
| If you don't see SafetyMaster Pro in the list, try running it once more." | |
| exit 1 | |
| } | |
| # Start the application in background | |
| echo "Starting SafetyMaster Pro..." | |
| "$PYTHON_CMD" web_interface.py > /dev/null 2>&1 & | |
| APP_PID=$! | |
| # Wait for server to start | |
| sleep 5 | |
| # Check if the application started successfully | |
| if ! kill -0 $APP_PID 2>/dev/null; then | |
| show_error "Failed to start SafetyMaster Pro. | |
| This might be due to: | |
| - Missing dependencies | |
| - Camera access issues | |
| - Port 8080 already in use | |
| Check the Terminal for error messages." | |
| exit 1 | |
| fi | |
| # Open browser | |
| open http://localhost:8080 || { | |
| echo "Could not open browser automatically" | |
| } | |
| # Show success message with more information | |
| show_info "SafetyMaster Pro is running! | |
| ๐ Web Interface: http://localhost:8080 | |
| ๐น Make sure your camera is connected | |
| ๐ To stop: Close this dialog and quit the app | |
| The application will continue running until you quit it." | |
| # Wait for the Python process to finish | |
| wait $APP_PID | |
| ''' | |
| # Write the executable script | |
| executable_path = os.path.join(macos_dir, "SafetyMasterPro") | |
| with open(executable_path, 'w') as f: | |
| f.write(executable_script) | |
| # Make executable | |
| os.chmod(executable_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) | |
| # Create improved Info.plist | |
| plist_data = { | |
| 'CFBundleExecutable': 'SafetyMasterPro', | |
| 'CFBundleIdentifier': 'com.safetymaster.pro', | |
| 'CFBundleName': 'SafetyMaster Pro', | |
| 'CFBundleDisplayName': 'SafetyMaster Pro', | |
| 'CFBundleVersion': '1.0.1', | |
| 'CFBundleShortVersionString': '1.0.1', | |
| 'CFBundlePackageType': 'APPL', | |
| 'CFBundleSignature': 'SMPR', | |
| 'LSMinimumSystemVersion': '10.14', # macOS Mojave minimum for camera permissions | |
| 'LSRequiresNativeExecution': True, # Ensure it runs natively on Apple Silicon | |
| 'NSCameraUsageDescription': 'SafetyMaster Pro needs camera access to detect safety equipment and monitor workplace compliance in real-time.', | |
| 'NSMicrophoneUsageDescription': 'SafetyMaster Pro may use microphone for enhanced safety monitoring features.', | |
| 'NSHighResolutionCapable': True, | |
| 'LSApplicationCategoryType': 'public.app-category.business', | |
| 'NSRequiresAquaSystemAppearance': False, # Support dark mode | |
| 'LSMultipleInstancesProhibited': True, # Prevent multiple instances | |
| 'NSSupportsAutomaticGraphicsSwitching': True, # Support GPU switching | |
| 'LSArchitecturePriority': ['arm64', 'x86_64'], # Prefer Apple Silicon, fallback to Intel | |
| 'NSAppTransportSecurity': { | |
| 'NSAllowsLocalNetworking': True, # Allow localhost connections | |
| 'NSExceptionDomains': { | |
| 'localhost': { | |
| 'NSExceptionAllowsInsecureHTTPLoads': True | |
| } | |
| } | |
| } | |
| } | |
| # Write Info.plist | |
| plist_path = os.path.join(contents_dir, "Info.plist") | |
| with open(plist_path, 'wb') as f: | |
| plistlib.dump(plist_data, f) | |
| # Create a README for distribution | |
| readme_content = '''# SafetyMaster Pro - Mac Distribution | |
| ## System Requirements | |
| - macOS 10.14 (Mojave) or later | |
| - Python 3.8 or later (will be installed automatically if missing) | |
| - Camera/webcam connected | |
| - At least 2GB RAM | |
| - 1GB free disk space | |
| ## Installation Instructions | |
| ### Method 1: Double-Click (Easiest) | |
| 1. Double-click "SafetyMaster Pro.app" | |
| 2. If prompted about security, go to System Preferences > Security & Privacy and click "Open Anyway" | |
| 3. Grant camera permissions when requested | |
| 4. The app will open in your web browser | |
| ### Method 2: Right-Click Open (If security blocked) | |
| 1. Right-click "SafetyMaster Pro.app" | |
| 2. Select "Open" from the context menu | |
| 3. Click "Open" in the security dialog | |
| 4. Grant camera permissions when requested | |
| ## First Run Setup | |
| 1. The app will automatically install Python dependencies | |
| 2. Grant camera access when prompted | |
| 3. The web interface will open at http://localhost:8080 | |
| 4. Click "Start Monitoring" to begin safety detection | |
| ## Troubleshooting | |
| ### "App can't be opened because it is from an unidentified developer" | |
| - Right-click the app and select "Open" | |
| - Or go to System Preferences > Security & Privacy > General and click "Open Anyway" | |
| ### Python Not Found | |
| - Install Python from https://www.python.org/downloads/macos/ | |
| - Or install Homebrew and run: brew install python3 | |
| ### Camera Access Denied | |
| - Go to System Preferences > Security & Privacy > Camera | |
| - Enable camera access for SafetyMaster Pro | |
| ### Port Already in Use | |
| - Make sure no other SafetyMaster Pro instances are running | |
| - Or restart your Mac to free up the port | |
| ## Features | |
| - Real-time PPE detection (hard hats, safety vests, masks) | |
| - Web-based dashboard with statistics | |
| - Violation tracking and alerts | |
| - High-performance AI processing (30+ FPS) | |
| - Cross-platform compatibility | |
| ## Support | |
| For issues or questions, check the included documentation or visit the project repository. | |
| ''' | |
| readme_path = os.path.join(resources_dir, "README.txt") | |
| with open(readme_path, 'w') as f: | |
| f.write(readme_content) | |
| print(f"\nโ Improved Mac app bundle created: {app_dir}") | |
| print(f"๐ Size: {get_directory_size(app_dir):.1f} MB") | |
| print(f"๐ง Features:") | |
| print(f" - Better Python detection (supports multiple versions)") | |
| print(f" - Virtual environment support") | |
| print(f" - Enhanced error handling and user guidance") | |
| print(f" - Apple Silicon + Intel compatibility") | |
| print(f" - Improved security permissions") | |
| print(f" - Better camera access handling") | |
| print(f"\n๐ Distribution ready - users can:") | |
| print(f" 1. Double-click to run") | |
| print(f" 2. No manual Python setup required") | |
| print(f" 3. Automatic dependency installation") | |
| print(f" 4. Clear error messages with solutions") | |
| def get_directory_size(path): | |
| """Calculate directory size in MB.""" | |
| total_size = 0 | |
| for dirpath, dirnames, filenames in os.walk(path): | |
| for filename in filenames: | |
| filepath = os.path.join(dirpath, filename) | |
| if os.path.exists(filepath): | |
| total_size += os.path.getsize(filepath) | |
| return total_size / (1024 * 1024) | |
| if __name__ == "__main__": | |
| create_improved_mac_app() |