chatterbox-ui/start_servers.py

148 lines
4.1 KiB
Python
Executable File

#!/Users/stwhite/CODE/chatterbox-ui/.venv/bin/python
"""
Startup script that launches both the backend and frontend servers concurrently.
"""
import os
import sys
import time
import signal
import subprocess
import threading
from pathlib import Path
# Try to load environment variables, but don't fail if dotenv is not available
try:
from dotenv import load_dotenv
load_dotenv()
except ImportError:
print("python-dotenv not installed, using system environment variables only")
# Configuration
BACKEND_PORT = int(os.getenv("BACKEND_PORT", "8000"))
BACKEND_HOST = os.getenv("BACKEND_HOST", "0.0.0.0")
# Frontend host/port (for dev server binding)
FRONTEND_PORT = int(os.getenv("FRONTEND_PORT", "8001"))
FRONTEND_HOST = os.getenv("FRONTEND_HOST", "0.0.0.0")
# Export frontend host/port so backend CORS config can pick them up automatically
os.environ["FRONTEND_HOST"] = FRONTEND_HOST
os.environ["FRONTEND_PORT"] = str(FRONTEND_PORT)
# Get project root directory
PROJECT_ROOT = Path(__file__).parent.absolute()
def run_backend():
"""Run the backend FastAPI server"""
os.chdir(PROJECT_ROOT / "backend")
cmd = [
sys.executable,
"-m",
"uvicorn",
"app.main:app",
"--reload",
f"--host={BACKEND_HOST}",
f"--port={BACKEND_PORT}",
]
print(f"\n{'='*50}")
print(f"Starting Backend Server at http://{BACKEND_HOST}:{BACKEND_PORT}")
print(f"API docs available at http://{BACKEND_HOST}:{BACKEND_PORT}/docs")
print(f"{'='*50}\n")
return subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
bufsize=1,
)
def run_frontend():
"""Run the frontend development server"""
frontend_dir = PROJECT_ROOT / "frontend"
os.chdir(frontend_dir)
cmd = [sys.executable, "start_dev_server.py"]
env = os.environ.copy()
env["VITE_DEV_SERVER_HOST"] = FRONTEND_HOST
env["VITE_DEV_SERVER_PORT"] = str(FRONTEND_PORT)
print(f"\n{'='*50}")
print(f"Starting Frontend Server at http://{FRONTEND_HOST}:{FRONTEND_PORT}")
print(f"{'='*50}\n")
return subprocess.Popen(
cmd,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
bufsize=1,
)
def print_process_output(process, prefix):
"""Print process output with a prefix"""
for line in iter(process.stdout.readline, ""):
if not line:
break
print(f"{prefix} | {line}", end="")
def main():
"""Main function to start both servers"""
print("\n🚀 Starting Chatterbox UI Development Environment")
# Start the backend server
backend_process = run_backend()
# Give the backend a moment to start
time.sleep(2)
# Start the frontend server
frontend_process = run_frontend()
# Create threads to monitor and print output
backend_monitor = threading.Thread(
target=print_process_output, args=(backend_process, "BACKEND"), daemon=True
)
frontend_monitor = threading.Thread(
target=print_process_output, args=(frontend_process, "FRONTEND"), daemon=True
)
backend_monitor.start()
frontend_monitor.start()
# Setup signal handling for graceful shutdown
def signal_handler(sig, frame):
print("\n\n🛑 Shutting down servers...")
backend_process.terminate()
frontend_process.terminate()
# Threads are daemon, so they'll exit when the main thread exits
print("✅ Servers stopped successfully")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
# Print access information
print("\n📋 Access Information:")
print(f" • Frontend: http://{FRONTEND_HOST}:{FRONTEND_PORT}")
print(f" • Backend API: http://{BACKEND_HOST}:{BACKEND_PORT}/api")
print(f" • API Documentation: http://{BACKEND_HOST}:{BACKEND_PORT}/docs")
print("\n⚠️ Press Ctrl+C to stop both servers\n")
# Keep the main process running
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
signal_handler(None, None)
if __name__ == "__main__":
main()