#!/usr/bin/env python3 """ Build script for creating standalone backend executable using PyInstaller. Uses --onedir mode for faster startup compared to --onefile. """ import subprocess import sys import os import shutil def build(): """Build the backend executable.""" script_dir = os.path.dirname(os.path.abspath(__file__)) # PyInstaller command with --onedir for faster startup cmd = [ sys.executable, "-m", "PyInstaller", "--onedir", "--name", "backend", "--distpath", "dist", "--workpath", "build", "--specpath", "build", # FastAPI and web framework "--hidden-import", "uvicorn", "--hidden-import", "uvicorn.logging", "--hidden-import", "uvicorn.loops", "--hidden-import", "uvicorn.loops.auto", "--hidden-import", "uvicorn.protocols", "--hidden-import", "uvicorn.protocols.http", "--hidden-import", "uvicorn.protocols.http.auto", "--hidden-import", "uvicorn.protocols.websockets", "--hidden-import", "uvicorn.protocols.websockets.auto", "--hidden-import", "uvicorn.lifespan", "--hidden-import", "uvicorn.lifespan.on", "--hidden-import", "uvicorn.lifespan.off", "--hidden-import", "fastapi", "--hidden-import", "starlette", "--hidden-import", "pydantic", "--hidden-import", "pydantic_core", # Database "--hidden-import", "mysql.connector", "--hidden-import", "mysql.connector.pooling", # HTTP client "--hidden-import", "httpx", "--hidden-import", "httpcore", # Authentication "--hidden-import", "jose", "--hidden-import", "jose.jwt", "--hidden-import", "cryptography", # Excel export "--hidden-import", "openpyxl", # Multipart form handling "--hidden-import", "multipart", "--hidden-import", "python_multipart", # Environment loading "--hidden-import", "dotenv", # Application modules "--hidden-import", "app", "--hidden-import", "app.main", "--hidden-import", "app.config", "--hidden-import", "app.database", "--hidden-import", "app.auth", "--hidden-import", "app.routers", "--hidden-import", "app.routers.auth", "--hidden-import", "app.routers.meetings", "--hidden-import", "app.routers.dify", "--hidden-import", "app.routers.health", "--hidden-import", "app.routers.excel", # Collect package data "--collect-data", "pydantic", "--collect-data", "uvicorn", "run_server.py" ] print("Building backend executable...") print(f"Command: {' '.join(cmd)}") result = subprocess.run(cmd, cwd=script_dir) if result.returncode != 0: print("\nBuild failed!") sys.exit(1) # Copy template directory to dist template_src = os.path.join(script_dir, "template") template_dst = os.path.join(script_dir, "dist", "backend", "template") if os.path.exists(template_src): print(f"\nCopying template directory to {template_dst}...") if os.path.exists(template_dst): shutil.rmtree(template_dst) shutil.copytree(template_src, template_dst) print("Template directory copied successfully.") else: print(f"\nWarning: Template directory not found at {template_src}") # Create empty record directory record_dst = os.path.join(script_dir, "dist", "backend", "record") os.makedirs(record_dst, exist_ok=True) print(f"Created record directory at {record_dst}") print("\nBuild successful!") print(f"Executable created at: dist/backend/backend.exe (Windows) or dist/backend/backend (Linux)") print("\nTo run:") print(" 1. Copy config.json to dist/backend/") print(" 2. Run: dist/backend/backend.exe (Windows) or ./dist/backend/backend (Linux)") if __name__ == "__main__": build()