Working docker-compose.yaml added. Services start and work.
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# Backend
|
||||
DEBUG=0
|
||||
MAX_UPLOAD_SIZE_MB=500
|
||||
TEMP_DIR=/tmp/audio_splitter_web
|
||||
CLEANUP_AFTER_SECONDS=3600
|
||||
|
||||
# Frontend (development)
|
||||
VITE_BACKEND_URL=http://localhost:8000
|
||||
@@ -0,0 +1,29 @@
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: . # Project root (contains audio_splitter/)
|
||||
dockerfile: web/backend/Dockerfile
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- /tmp/audio_splitter_web:/tmp/audio_splitter_web
|
||||
environment:
|
||||
- PYTHONUNBUFFERED=1
|
||||
- DEBUG=1
|
||||
restart: unless-stopped
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./web/frontend
|
||||
dockerfile: Dockerfile.dev
|
||||
ports:
|
||||
- "5173:5173"
|
||||
volumes:
|
||||
- ./web/frontend:/app
|
||||
- /app/node_modules
|
||||
environment:
|
||||
- BACKEND_URL=http://backend:8000
|
||||
- VITE_BACKEND_URL=http://backend:8000
|
||||
depends_on:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,18 @@
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
*.so
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
.venv
|
||||
venv
|
||||
.env
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
@@ -0,0 +1,54 @@
|
||||
FROM python:3.13-slim
|
||||
|
||||
# Install FFmpeg and system dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ffmpeg \
|
||||
ca-certificates \
|
||||
&& \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set Python environment variables
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Copy and install Python dependencies
|
||||
# ------------------------------------------------------------
|
||||
COPY web/backend/requirements-web.txt .
|
||||
RUN pip install --no-cache-dir -r requirements-web.txt
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Copy the backend application code
|
||||
# ------------------------------------------------------------
|
||||
COPY web/backend /app/backend
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Copy and install the audio_splitter package
|
||||
# ------------------------------------------------------------
|
||||
COPY audio_splitter /app/audio_splitter
|
||||
COPY setup.py pyproject.toml README.md /app/
|
||||
|
||||
# Install audio_splitter as a package
|
||||
RUN pip install --no-cache-dir /app
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Create a non-root user
|
||||
# ------------------------------------------------------------
|
||||
RUN addgroup --system --gid 1000 appgroup && \
|
||||
adduser --system --uid 1000 --ingroup appgroup appuser && \
|
||||
chown -R appuser:appgroup /app
|
||||
|
||||
USER appuser
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Expose port and start
|
||||
# ------------------------------------------------------------
|
||||
EXPOSE 8000
|
||||
|
||||
# PYTHONPATH is already /app by default because we set WORKDIR /app
|
||||
CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
+7
-4
@@ -7,7 +7,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||
from backend.config import settings
|
||||
from backend.api import upload, split, status, download
|
||||
from backend.api.websocket import router as websocket_router
|
||||
from backend.services import progress_publisher # Import the module
|
||||
from backend.services import progress_publisher
|
||||
|
||||
app = FastAPI(
|
||||
title="Audio Splitter Web API",
|
||||
@@ -24,9 +24,12 @@ app.add_middleware(
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# Store the main event loop in the progress_publisher module
|
||||
# This avoids a circular import
|
||||
progress_publisher.MAIN_LOOP = asyncio.get_running_loop()
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
"""Store the main event loop for use in other threads."""
|
||||
progress_publisher.MAIN_LOOP = asyncio.get_running_loop()
|
||||
|
||||
|
||||
# Include routers
|
||||
app.include_router(upload.router)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fastapi>=0.104.0
|
||||
uvicorn[standard]>=0.24.0
|
||||
python-multipart>=0.0.6
|
||||
aiofiles>=23.2.0
|
||||
pydantic>=2.5.0
|
||||
pydantic-settings>=2.0.0
|
||||
python-dotenv>=1.0.0
|
||||
websockets>=12.0
|
||||
@@ -5,7 +5,7 @@ from typing import Dict, Set
|
||||
|
||||
from fastapi import WebSocket
|
||||
|
||||
# This will be set by main.py when the app starts
|
||||
# This will be set by main.py during startup
|
||||
MAIN_LOOP = None
|
||||
|
||||
active_connections: Dict[str, Set[WebSocket]] = {}
|
||||
@@ -29,13 +29,19 @@ def publish_progress(task_id: str, progress: int, message: str, status: str = "p
|
||||
}
|
||||
|
||||
to_remove = set()
|
||||
# Get the loop to use: either the stored one or try to get the current loop
|
||||
loop = MAIN_LOOP
|
||||
if loop is None:
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
# No running loop, fallback to default event loop
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
for websocket in active_connections.get(task_id, set()):
|
||||
try:
|
||||
# Use the stored main loop, or fallback to getting the current loop
|
||||
loop = MAIN_LOOP or asyncio.get_running_loop()
|
||||
asyncio.run_coroutine_threadsafe(websocket.send_json(data), loop)
|
||||
except Exception:
|
||||
# Client disconnected or other error
|
||||
to_remove.add(websocket)
|
||||
|
||||
# Clean up disconnected clients
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.gitignore
|
||||
*.log
|
||||
.env
|
||||
.env.local
|
||||
.DS_Store
|
||||
Dockerfile
|
||||
Dockerfile.dev
|
||||
.dockerignore
|
||||
nginx.conf
|
||||
@@ -0,0 +1,27 @@
|
||||
# Stage 1: Build
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm install
|
||||
|
||||
# Copy the application code and build
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Production (nginx)
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copy built assets from builder
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# Copy nginx configuration
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Expose the port
|
||||
EXPOSE 80
|
||||
|
||||
# Start nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,17 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm install
|
||||
|
||||
# Copy the application code
|
||||
COPY . .
|
||||
|
||||
# Expose the port
|
||||
EXPOSE 5173
|
||||
|
||||
# Start the development server
|
||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||
@@ -1,18 +1,23 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// Backend URL for proxy (default to localhost for local dev)
|
||||
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:8000'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8000',
|
||||
target: BACKEND_URL,
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
'/ws': {
|
||||
target: 'ws://localhost:8000',
|
||||
target: BACKEND_URL.replace(/^http/, 'ws'),
|
||||
ws: true,
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
# Root directory for static files
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Serve React app
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Proxy API requests to backend
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Proxy WebSocket requests to backend
|
||||
location /ws/ {
|
||||
proxy_pass http://backend:8000/ws/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user