Spaces:
Sleeping
Sleeping
| # Simple Dockerfile for Hugging Face Spaces | |
| # No nginx needed - just serve static files with Python | |
| # Stage 1: Build the application | |
| FROM node:18-alpine AS builder | |
| WORKDIR /app | |
| # Install build dependencies | |
| RUN apk add --no-cache python3 make g++ | |
| # Copy package files | |
| COPY package*.json ./ | |
| COPY tsconfig*.json ./ | |
| COPY vite.config.ts ./ | |
| # Install dependencies | |
| RUN npm install | |
| # Copy source code | |
| COPY src/ ./src/ | |
| COPY public/ ./public/ | |
| COPY index.html ./ | |
| # Build the application | |
| ENV NODE_ENV=production | |
| RUN npm run build | |
| # Verify build output | |
| RUN ls -la dist/ && echo "β Build completed successfully" | |
| # Stage 2: Simple Python server for static files | |
| FROM python:3.11-slim | |
| WORKDIR /app | |
| # Copy built app from builder stage | |
| COPY --from=builder /app/dist ./ | |
| # Create a simple server script | |
| RUN echo '#!/usr/bin/env python3\n\ | |
| import http.server\n\ | |
| import socketserver\n\ | |
| import os\n\ | |
| import urllib.parse\n\ | |
| from pathlib import Path\n\ | |
| \n\ | |
| class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):\n\ | |
| def end_headers(self):\n\ | |
| self.send_my_headers()\n\ | |
| super().end_headers()\n\ | |
| \n\ | |
| def send_my_headers(self):\n\ | |
| self.send_header("Access-Control-Allow-Origin", "*")\n\ | |
| self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")\n\ | |
| self.send_header("Access-Control-Allow-Headers", "*")\n\ | |
| \n\ | |
| def do_GET(self):\n\ | |
| # Parse URL to get clean path without query parameters\n\ | |
| parsed_url = urllib.parse.urlparse(self.path)\n\ | |
| clean_path = parsed_url.path\n\ | |
| \n\ | |
| # Handle SPA routing - serve index.html for non-file requests\n\ | |
| if clean_path != "/" and clean_path != "" and "." not in clean_path:\n\ | |
| # Check if this looks like a file path\n\ | |
| try:\n\ | |
| if clean_path.startswith("/"):\n\ | |
| file_path = clean_path[1:]\n\ | |
| else:\n\ | |
| file_path = clean_path\n\ | |
| \n\ | |
| # Only check if path is reasonable length and format\n\ | |
| if len(file_path) < 200 and not file_path.startswith("?"):\n\ | |
| if not Path(file_path).exists():\n\ | |
| self.path = "/index.html"\n\ | |
| else:\n\ | |
| # Very long path or starts with ?, serve index.html\n\ | |
| self.path = "/index.html"\n\ | |
| except (OSError, ValueError):\n\ | |
| # Any error in path checking, serve index.html\n\ | |
| self.path = "/index.html"\n\ | |
| else:\n\ | |
| # Keep original path for actual files\n\ | |
| self.path = clean_path\n\ | |
| \n\ | |
| return super().do_GET()\n\ | |
| \n\ | |
| def guess_type(self, path):\n\ | |
| # Add audio MIME types\n\ | |
| if path.endswith(".mp3"):\n\ | |
| return "audio/mpeg"\n\ | |
| elif path.endswith(".wav"):\n\ | |
| return "audio/wav"\n\ | |
| elif path.endswith(".ogg"):\n\ | |
| return "audio/ogg"\n\ | |
| else:\n\ | |
| return super().guess_type(path)\n\ | |
| \n\ | |
| PORT = int(os.environ.get("PORT", 7860))\n\ | |
| files = os.listdir(".")\n\ | |
| print(f"π Starting server on port {PORT}")\n\ | |
| print(f"π Serving files from: {os.getcwd()}")\n\ | |
| print(f"π Files available: {files}")\n\ | |
| \n\ | |
| with socketserver.TCPServer(("", PORT), MyHTTPRequestHandler) as httpd:\n\ | |
| print(f"β Server running at http://0.0.0.0:{PORT}")\n\ | |
| httpd.serve_forever()\n\ | |
| ' > server.py && chmod +x server.py | |
| # Expose port 7860 (HF Spaces default) | |
| EXPOSE 7860 | |
| # Start the server | |
| CMD ["python3", "server.py"] |