forge/backend/app/services/background_remover.py
DJP 7a804e896d Initial commit - FORGE AI unified platform
Features:
- Image generation (OpenAI, Gemini, Leonardo, Bria, Stability, Flux)
- Nano Banana iterative editing
- Video generation and upscaling
- Audio TTS, STT, sound effects (ElevenLabs)
- Text prompt studio and alt text
- User authentication with JWT/cookies
- Admin panel with voice management
- Job queue with Celery
- PostgreSQL + Redis backend
- Next.js 15 + FastAPI architecture

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2025-12-09 20:39:00 -05:00

129 lines
4.4 KiB
Python

"""Background Remover Service - Clipping Magic API"""
import httpx
import os
import base64
from uuid import uuid4
from datetime import datetime
from app.database import SessionLocal
from app.models.job import Job
from app.models.asset import Asset
from app.config import settings
async def remove_background(job_id: str):
"""Remove background from image using Clipping Magic"""
db = SessionLocal()
try:
job = db.query(Job).filter(Job.id == job_id).first()
if not job:
return
input_data = job.input_data
input_asset_ids = job.input_asset_ids
if not input_asset_ids:
raise ValueError("No input asset provided")
input_asset = db.query(Asset).filter(Asset.id == input_asset_ids[0]).first()
if not input_asset:
raise ValueError("Input asset not found")
job.progress = 10
job.api_provider = "clipping_magic"
db.commit()
# Read input image
with open(input_asset.file_path, "rb") as f:
image_data = f.read()
output_format = input_data.get("output_format", "png")
job.progress = 20
db.commit()
# Call Clipping Magic API
async with httpx.AsyncClient(timeout=120) as client:
# Decode the API key (it's base64 encoded in the original code)
api_key = settings.clipping_magic_api_key
response = await client.post(
"https://clippingmagic.com/api/v1/images",
auth=(api_key, ""),
files={"image": (input_asset.original_filename, image_data, input_asset.mime_type)},
data={
"format": "result" if output_format == "png" else "clipping_path_tiff"
}
)
response.raise_for_status()
result = response.json()
image_id = result.get("image", {}).get("id")
job.progress = 50
db.commit()
if image_id:
# Download the result
download_response = await client.get(
f"https://clippingmagic.com/api/v1/images/{image_id}",
auth=(api_key, ""),
params={"format": "result" if output_format == "png" else "clipping_path_tiff"}
)
download_response.raise_for_status()
processed_data = download_response.content
job.progress = 80
db.commit()
# Save output
ext = "png" if output_format == "png" else "tiff"
filename = f"nobg_{uuid4()}.{ext}"
storage_path = os.path.join(settings.storage_path, "images")
os.makedirs(storage_path, exist_ok=True)
file_path = os.path.join(storage_path, filename)
with open(file_path, "wb") as f:
f.write(processed_data)
# Create output asset
output_asset = Asset(
user_id=job.user_id,
project_id=job.project_id,
original_filename=filename,
stored_filename=filename,
file_path=file_path,
file_type="image",
mime_type=f"image/{ext}",
file_size_bytes=len(processed_data),
width=input_asset.width,
height=input_asset.height,
source_module="background_remover",
source_job_id=job.id,
parent_asset_id=input_asset.id,
metadata={"output_format": output_format}
)
db.add(output_asset)
db.commit()
db.refresh(output_asset)
job.output_asset_ids = [output_asset.id]
job.output_data = {"asset_id": str(output_asset.id), "file_path": file_path}
# Delete from Clipping Magic (cleanup)
await client.post(
f"https://clippingmagic.com/api/v1/images/{image_id}/delete",
auth=(api_key, "")
)
job.progress = 100
job.status = "completed"
job.completed_at = datetime.utcnow()
db.commit()
except Exception as e:
job.status = "failed"
job.error_message = str(e)
db.commit()
finally:
db.close()