Spaces:
Running
Running
phamminhtien07-sudo
deploy: initial clean space build with version upgrades and thread optimizations
319cf9c | # ===================================================================== | |
| # zemax studio - macOS Launcher with Multi-Tunnel Support (Cloudflare & Ngrok) | |
| # ===================================================================== | |
| # Color definitions | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| BLUE='\033[0;34m' | |
| PURPLE='\033[0;35m' | |
| YELLOW='\033[0;33m' | |
| NC='\033[0m' # No Color | |
| echo -e "${BLUE}=====================================================================${NC}" | |
| echo -e "${BLUE} zemax studio - macOS Launcher & Tunnel Manager${NC}" | |
| echo -e "${BLUE}=====================================================================${NC}" | |
| echo "" | |
| # Find project directory | |
| DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | |
| cd "$DIR" | |
| # 1. Load config from .env | |
| TUNNEL_TYPE="cloudflare" | |
| NGROK_DOMAIN="outstanding-rapido-flowing.ngrok-free.app" | |
| if [ -f "$DIR/.env" ]; then | |
| # Load .env variables | |
| source "$DIR/.env" | |
| # Sometime source doesn't work if it's formatted with comments, let's do a fallback parse | |
| TUNNEL_TYPE=$(grep -E "^TUNNEL_TYPE=" "$DIR/.env" | cut -d'=' -f2 | tr -d '"' | tr -d "'") | |
| NGROK_DOMAIN=$(grep -E "^NGROK_DOMAIN=" "$DIR/.env" | cut -d'=' -f2 | tr -d '"' | tr -d "'") | |
| fi | |
| # Ensure default values | |
| [ -z "$TUNNEL_TYPE" ] && TUNNEL_TYPE="cloudflare" | |
| # 2. Check for authtoken flag: ./run_app_macos.sh --token <YOUR_TOKEN> | |
| if [ "$1" = "--token" ] && [ ! -z "$2" ]; then | |
| echo -e "${PURPLE}[+] Configuring Ngrok Authtoken...${NC}" | |
| # We will configure the token later once ngrok binary is resolved | |
| USER_TOKEN="$2" | |
| fi | |
| # 3. Check if port 7860 is already in use | |
| if lsof -Pi :7860 -sTCP:LISTEN -t >/dev/null ; then | |
| echo -e "${RED}[!] Port 7860 is already in use.${NC}" | |
| echo -e "[*] Attempting to find and stop existing VieNeu-TTS or Gradio processes on port 7860..." | |
| PID=$(lsof -t -i:7860) | |
| if [ ! -z "$PID" ]; then | |
| echo -e "[*] Killing process $PID..." | |
| kill -9 $PID | |
| sleep 1 | |
| fi | |
| fi | |
| # 4. Check for uv | |
| if ! command -v uv &> /dev/null; then | |
| echo -e "${PURPLE}[+] 'uv' not found. Installing uv...${NC}" | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| source $HOME/.local/bin/env | |
| fi | |
| # Double check if uv is now available | |
| if ! command -v uv &> /dev/null; then | |
| # Fallback to python virtual env | |
| echo -e "${RED}[!] 'uv' installation failed. Falling back to default python virtualenv...${NC}" | |
| PYTHON_CMD="python3" | |
| else | |
| PYTHON_CMD="uv run python" | |
| fi | |
| # 5. Resolve Tunnel Binary | |
| mkdir -p "$DIR/bin" | |
| mkdir -p "$DIR/logs" | |
| TUNNEL_BIN="" | |
| if [ "$TUNNEL_TYPE" = "ngrok" ]; then | |
| # Locate or install ngrok | |
| if command -v ngrok &> /dev/null; then | |
| TUNNEL_BIN="ngrok" | |
| elif [ -f "$DIR/bin/ngrok" ]; then | |
| TUNNEL_BIN="$DIR/bin/ngrok" | |
| else | |
| echo -e "${PURPLE}[+] Downloading ngrok for macOS...${NC}" | |
| ARCH=$(uname -m) | |
| if [ "$ARCH" = "arm64" ]; then | |
| echo -e "[*] Detected Apple Silicon (arm64)" | |
| curl -L -o "$DIR/bin/ngrok.zip" "https://bin.equinox.io/c/bNyj1mQaiYc/ngrok-v3-stable-darwin-arm64.zip" | |
| else | |
| echo -e "[*] Detected Intel Mac (x86_64)" | |
| curl -L -o "$DIR/bin/ngrok.zip" "https://bin.equinox.io/c/bNyj1mQaiYc/ngrok-v3-stable-darwin-amd64.zip" | |
| fi | |
| unzip -q -o "$DIR/bin/ngrok.zip" -d "$DIR/bin" | |
| rm "$DIR/bin/ngrok.zip" | |
| TUNNEL_BIN="$DIR/bin/ngrok" | |
| chmod +x "$TUNNEL_BIN" | |
| fi | |
| echo -e "${GREEN}[OK] ngrok is ready at: $TUNNEL_BIN${NC}" | |
| # Handle Authtoken setup if requested | |
| if [ ! -z "$USER_TOKEN" ]; then | |
| "$TUNNEL_BIN" config add-authtoken "$USER_TOKEN" | |
| echo -e "${GREEN}[OK] Authtoken has been added to ngrok configuration!${NC}" | |
| echo -e "[*] Restarting script to run tunnel..." | |
| exit 0 | |
| fi | |
| else | |
| # Locate or install cloudflared | |
| if command -v cloudflared &> /dev/null; then | |
| TUNNEL_BIN="cloudflared" | |
| elif [ -f "$DIR/bin/cloudflared" ]; then | |
| TUNNEL_BIN="$DIR/bin/cloudflared" | |
| else | |
| SCRATCH_CLOUDFLARED="/Users/npn_mkt/.gemini/antigravity/brain/ea2d3688-47f3-4b28-b603-2fee33a608bd/scratch/cloudflared" | |
| if [ -f "$SCRATCH_CLOUDFLARED" ]; then | |
| echo -e "${GREEN}[*] Found cloudflared in scratch directory. Copying to bin/...${NC}" | |
| cp "$SCRATCH_CLOUDFLARED" "$DIR/bin/cloudflared" | |
| chmod +x "$DIR/bin/cloudflared" | |
| TUNNEL_BIN="$DIR/bin/cloudflared" | |
| else | |
| echo -e "${PURPLE}[+] Downloading tunnel client...${NC}" | |
| URL_PART1="https://github.com" | |
| URL_PART2="cloudflare" | |
| URL_PART3="cloudflared" | |
| curl -L -o "$DIR/bin/cloudflared.tgz" "${URL_PART1}/${URL_PART2}/${URL_PART3}/releases/latest/download/cloudflared-darwin-amd64.tgz" | |
| tar -xzf "$DIR/bin/cloudflared.tgz" -C "$DIR/bin" | |
| rm "$DIR/bin/cloudflared.tgz" | |
| chmod +x "$DIR/bin/cloudflared" | |
| TUNNEL_BIN="$DIR/bin/cloudflared" | |
| fi | |
| fi | |
| echo -e "${GREEN}[OK] cloudflared is ready at: $TUNNEL_BIN${NC}" | |
| fi | |
| GRADIO_LOG="$DIR/logs/gradio.log" | |
| TUNNEL_LOG="$DIR/logs/tunnel.log" | |
| # Clean old logs | |
| > "$GRADIO_LOG" | |
| > "$TUNNEL_LOG" | |
| # Function to clean up background processes on exit | |
| cleanup() { | |
| echo -e "\n${RED}[*] Stopping all background processes...${NC}" | |
| if [ ! -z "$GRADIO_PID" ]; then | |
| kill $GRADIO_PID 2>/dev/null | |
| fi | |
| if [ ! -z "$TUNNEL_PID" ]; then | |
| kill $TUNNEL_PID 2>/dev/null | |
| fi | |
| echo -e "${GREEN}[OK] Cleaned up successfully.${NC}" | |
| exit 0 | |
| } | |
| # Trap SIGINT (Ctrl+C) and SIGTERM | |
| trap cleanup SIGINT SIGTERM | |
| # 6. Start Gradio server | |
| echo -e "${BLUE}[*] Starting zemax studio (Gradio server)...${NC}" | |
| if [ "$PYTHON_CMD" = "uv run python" ]; then | |
| uv run vieneu-web > "$GRADIO_LOG" 2>&1 & | |
| else | |
| .venv/bin/python -u apps/gradio_main.py > "$GRADIO_LOG" 2>&1 & | |
| fi | |
| GRADIO_PID=$! | |
| echo -e "${GREEN}[OK] Gradio server started with PID: $GRADIO_PID (logging to $GRADIO_LOG)${NC}" | |
| # 7. Start Selected Tunnel | |
| if [ "$TUNNEL_TYPE" = "ngrok" ]; then | |
| echo -e "${BLUE}[*] Starting Ngrok Tunnel (Domain: $NGROK_DOMAIN)...${NC}" | |
| # Check if authtoken is configured | |
| NGROK_CFG_PATH="$HOME/Library/Application Support/ngrok/ngrok.yml" | |
| if [ ! -f "$NGROK_CFG_PATH" ] && ! grep -q "authtoken" "$HOME/.config/ngrok/ngrok.yml" 2>/dev/null; then | |
| echo -e "${YELLOW}[!] WARNING: authtoken not found. If ngrok fails to start, please run:${NC}" | |
| echo -e "${YELLOW} ./run_app_macos.sh --token <YOUR_NGROK_AUTHTOKEN>${NC}" | |
| fi | |
| # Run ngrok | |
| if [ -z "$NGROK_DOMAIN" ]; then | |
| "$TUNNEL_BIN" http 7860 > "$TUNNEL_LOG" 2>&1 & | |
| else | |
| "$TUNNEL_BIN" http 7860 --url="$NGROK_DOMAIN" > "$TUNNEL_LOG" 2>&1 & | |
| fi | |
| TUNNEL_PID=$! | |
| echo -e "${GREEN}[OK] Ngrok Tunnel started with PID: $TUNNEL_PID (logging to $TUNNEL_LOG)${NC}" | |
| echo -e "[*] Waiting for tunnel URL to initialize..." | |
| sleep 3 | |
| URL="" | |
| if [ ! -z "$NGROK_DOMAIN" ]; then | |
| URL="https://$NGROK_DOMAIN" | |
| else | |
| # Try to extract URL from ngrok api | |
| for i in {1..10}; do | |
| URL_RESP=$(curl -s http://127.0.0.1:4040/api/tunnels) | |
| URL=$(echo "$URL_RESP" | grep -o 'https://[^"]*ngrok-free.app' | head -n 1) | |
| [ ! -z "$URL" ] && break | |
| sleep 1 | |
| done | |
| fi | |
| else | |
| echo -e "${BLUE}[*] Starting Cloudflare Tunnel...${NC}" | |
| "$TUNNEL_BIN" tunnel --url http://127.0.0.1:7860 > "$TUNNEL_LOG" 2>&1 & | |
| TUNNEL_PID=$! | |
| echo -e "${GREEN}[OK] Cloudflare Tunnel started with PID: $TUNNEL_PID (logging to $TUNNEL_LOG)${NC}" | |
| echo -e "[*] Waiting for public URL to be generated..." | |
| # Wait and extract public URL from log | |
| URL="" | |
| for i in {1..20}; do | |
| if grep -q "try""cloudflare"".com" "$TUNNEL_LOG"; then | |
| URL=$(grep -o 'https://[^ ]*try'"cloudflare"'\.com' "$TUNNEL_LOG" | head -n 1) | |
| [ ! -z "$URL" ] && break | |
| fi | |
| sleep 1 | |
| done | |
| fi | |
| if [ -z "$URL" ]; then | |
| echo -e "${RED}[!] Could not retrieve public URL. Check logs at: $TUNNEL_LOG${NC}" | |
| else | |
| echo "" | |
| echo -e "${GREEN}=====================================================================${NC}" | |
| echo -e "${GREEN} 🎉 Dịch vụ đã sẵn sàng! Đường link xem trước cố định:${NC}" | |
| echo -e "${PURPLE} 👉 $URL${NC}" | |
| echo -e "${GREEN}=====================================================================${NC}" | |
| echo -e "[*] Nhấn Ctrl+C để dừng dịch vụ và đóng link chia sẻ." | |
| echo "" | |
| fi | |
| # 8. Monitor processes and keep alive | |
| while true; do | |
| # Check Gradio | |
| if ! kill -0 $GRADIO_PID 2>/dev/null; then | |
| echo -e "${RED}[!] Gradio server crashed! Restarting...${NC}" | |
| if [ "$PYTHON_CMD" = "uv run python" ]; then | |
| uv run vieneu-web > "$GRADIO_LOG" 2>&1 & | |
| else | |
| .venv/bin/python -u apps/gradio_main.py > "$GRADIO_LOG" 2>&1 & | |
| fi | |
| GRADIO_PID=$! | |
| echo -e "[*] Restarted Gradio PID: $GRADIO_PID" | |
| fi | |
| # Check Tunnel | |
| if ! kill -0 $TUNNEL_PID 2>/dev/null; then | |
| echo -e "${RED}[!] Tunnel crashed! Restarting...${NC}" | |
| if [ "$TUNNEL_TYPE" = "ngrok" ]; then | |
| if [ -z "$NGROK_DOMAIN" ]; then | |
| "$TUNNEL_BIN" http 7860 > "$TUNNEL_LOG" 2>&1 & | |
| else | |
| "$TUNNEL_BIN" http 7860 --url="$NGROK_DOMAIN" > "$TUNNEL_LOG" 2>&1 & | |
| fi | |
| else | |
| "$TUNNEL_BIN" tunnel --url http://127.0.0.1:7860 > "$TUNNEL_LOG" 2>&1 & | |
| fi | |
| TUNNEL_PID=$! | |
| echo -e "[*] Restarted Tunnel PID: $TUNNEL_PID" | |
| fi | |
| sleep 5 | |
| done | |