Files
brandly/services/background-remover/main.py
T

193 lines
6.4 KiB
Python

import os
import subprocess
import tempfile
import shutil
import asyncio
from fastapi import FastAPI, UploadFile, File, HTTPException, BackgroundTasks
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(title="Background Remover API")
# Configure CORS so the React app can call this API
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Adjust in production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
def cleanup_files(*file_paths):
"""Deletes temporary files after the response is sent."""
for file_path in file_paths:
try:
if file_path and os.path.exists(file_path):
os.remove(file_path)
print(f"Cleaned up {file_path}")
except Exception as e:
print(f"Error cleaning up {file_path}: {e}")
@app.get("/health")
def health_check():
return {"status": "ok"}
@app.post("/api/v1/remove-background")
async def remove_background(
background_tasks: BackgroundTasks,
file: UploadFile = File(...)
):
if not file.filename:
raise HTTPException(status_code=400, detail="No file uploaded")
# We will use secure temp files
temp_input_fd, temp_input_path = tempfile.mkstemp(suffix=".mp4")
temp_output_mov_fd, temp_output_mov_path = tempfile.mkstemp(suffix=".mov")
temp_final_webm_fd, temp_final_webm_path = tempfile.mkstemp(suffix=".webm")
os.close(temp_input_fd)
os.close(temp_output_mov_fd)
os.close(temp_final_webm_fd)
try:
# 1. Save uploaded video to temp file
with open(temp_input_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
print(f"Saved uploaded file to {temp_input_path}")
# 2. Run backgroundremover
# backgroundremover -i input.mp4 -mk -o output.mov
cmd_bg_remover = [
"backgroundremover",
"-i", temp_input_path,
"-mk", # This flag tells it to create an alpha matte video (.mov)
"-o", temp_output_mov_path
]
print("Starting background removal process...")
process_bg = await asyncio.create_subprocess_exec(
*cmd_bg_remover,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process_bg.communicate()
if process_bg.returncode != 0:
print(f"backgroundremover error: {stderr.decode()}")
raise HTTPException(status_code=500, detail="Error processing video background removal.")
print("Background removal finished. Starting WebM conversion...")
# 3. Convert .mov to .webm with VP9 and yuva420p (alpha channel)
# ffmpeg -i output.mov -c:v libvpx-vp9 -pix_fmt yuva420p -auto-alt-ref 0 final.webm
cmd_ffmpeg = [
"ffmpeg",
"-y", # Overwrite output
"-i", temp_output_mov_path,
"-c:v", "libvpx-vp9",
"-pix_fmt", "yuva420p",
"-auto-alt-ref", "0",
temp_final_webm_path
]
process_ffmpeg = await asyncio.create_subprocess_exec(
*cmd_ffmpeg,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout_ff, stderr_ff = await process_ffmpeg.communicate()
if process_ffmpeg.returncode != 0:
print(f"ffmpeg error: {stderr_ff.decode()}")
raise HTTPException(status_code=500, detail="Error converting video to WebM.")
print("WebM conversion finished successfully.")
# 4. Schedule cleanup of ALL temporary files after response is sent
background_tasks.add_task(
cleanup_files,
temp_input_path,
temp_output_mov_path,
temp_final_webm_path
)
# 5. Return the file
return FileResponse(
temp_final_webm_path,
media_type="video/webm",
filename=f"transparent_{file.filename.split('.')[0]}.webm"
)
except Exception as e:
# If an error occurs, clean up immediately
cleanup_files(temp_input_path, temp_output_mov_path, temp_final_webm_path)
if isinstance(e, HTTPException):
raise e
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/v1/remove-image-background")
async def remove_image_background(
background_tasks: BackgroundTasks,
file: UploadFile = File(...)
):
if not file.filename:
raise HTTPException(status_code=400, detail="No file uploaded")
# We will use secure temp files
temp_input_fd, temp_input_path = tempfile.mkstemp(suffix=".png")
temp_output_png_fd, temp_output_png_path = tempfile.mkstemp(suffix=".png")
os.close(temp_input_fd)
os.close(temp_output_png_fd)
try:
# 1. Save uploaded image to temp file
with open(temp_input_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
print(f"Saved uploaded image to {temp_input_path}")
# 2. Run backgroundremover for image
# backgroundremover -i input.jpg -o output.png
cmd_bg_remover = [
"backgroundremover",
"-i", temp_input_path,
"-o", temp_output_png_path
]
print("Starting image background removal process...")
process_bg = await asyncio.create_subprocess_exec(
*cmd_bg_remover,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process_bg.communicate()
if process_bg.returncode != 0:
print(f"backgroundremover error: {stderr.decode()}")
raise HTTPException(status_code=500, detail="Error processing image background removal.")
print("Image background removal finished successfully.")
# 3. Schedule cleanup of ALL temporary files after response is sent
background_tasks.add_task(
cleanup_files,
temp_input_path,
temp_output_png_path
)
# 4. Return the file
return FileResponse(
temp_output_png_path,
media_type="image/png",
filename=f"transparent_{file.filename.split('.')[0]}.png"
)
except Exception as e:
# If an error occurs, clean up immediately
cleanup_files(temp_input_path, temp_output_png_path)
if isinstance(e, HTTPException):
raise e
raise HTTPException(status_code=500, detail=str(e))