148 lines
4.1 KiB
Python
Executable File
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()
|