import os import subprocess import shutil from typing import Optional from fastapi import FastAPI, UploadFile, HTTPException from fastapi.responses import JSONResponse, FileResponse from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from obs import ObsClient from dotenv import load_dotenv # Load environment variables load_dotenv() app = FastAPI() # Configure CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], # Allows all origins allow_credentials=True, allow_methods=["*"], # Allows all methods allow_headers=["*"], # Allows all headers ) # Mount static files app.mount("/static", StaticFiles(directory="static"), name="static") # OBS configuration ACCESS_KEY = os.getenv('OBS_ACCESS_KEY') SECRET_KEY = os.getenv('OBS_SECRET_KEY') ENDPOINT = os.getenv('OBS_ENDPOINT') BUCKET = os.getenv('OBS_BUCKET') # File paths UPLOAD_DIR = "/app/uploads" PROCESSED_DIR = "/app/processed" # Ensure directories exist os.makedirs(UPLOAD_DIR, exist_ok=True) os.makedirs(PROCESSED_DIR, exist_ok=True) def get_obs_client() -> ObsClient: return ObsClient( access_key_id=ACCESS_KEY, secret_access_key=SECRET_KEY, server=ENDPOINT ) @app.get("/") async def root(): return FileResponse("static/index.html") @app.post("/convert") async def convert_eps_to_svg(file: UploadFile): # Check file size (10MB limit) file_size = 0 content = await file.read() file_size = len(content) if file_size > 10 * 1024 * 1024: # 10MB raise HTTPException(status_code=400, detail="File too large. Maximum size is 10MB") # Check file extension if not file.filename.lower().endswith('.eps'): raise HTTPException(status_code=400, detail="Only EPS files are accepted") try: # Ensure directories exist and are writable for directory in [UPLOAD_DIR, PROCESSED_DIR]: if not os.path.exists(directory): os.makedirs(directory, exist_ok=True) if not os.access(directory, os.W_OK): raise HTTPException(status_code=500, detail=f"Directory {directory} is not writable") # Save uploaded file input_path = os.path.join(UPLOAD_DIR, file.filename) with open(input_path, "wb") as f: f.write(content) # Generate output paths base_name = os.path.splitext(file.filename)[0] temp_svg = os.path.join(PROCESSED_DIR, f"{base_name}_temp.svg") final_svg = os.path.join(PROCESSED_DIR, f"{base_name}.svg") # Convert EPS to SVG try: subprocess.run(['eps2svg', input_path, temp_svg], check=True, capture_output=True, text=True) except subprocess.CalledProcessError as e: raise HTTPException(status_code=500, detail=f"eps2svg conversion failed: {e.stderr}") # Check if temp_svg was created if not os.path.exists(temp_svg): raise HTTPException(status_code=500, detail="eps2svg failed to create output file") # Try to optimize SVG using scour try: subprocess.run(['scour', '-i', temp_svg, '-o', final_svg], check=True) except subprocess.CalledProcessError: # If scour fails, use the unoptimized SVG shutil.copy(temp_svg, final_svg) print("Scour optimization failed, using unoptimized SVG") # Upload to OBS obs_client = get_obs_client() obs_key = f"svg/{base_name}.svg" with open(final_svg, 'rb') as f: obs_client.putContent(BUCKET, obs_key, f.read()) # Clean up files os.remove(input_path) os.remove(temp_svg) os.remove(final_svg) return JSONResponse({ "status": "success", "message": "File processed successfully", "obs_key": obs_key }) except subprocess.CalledProcessError as e: raise HTTPException(status_code=500, detail=f"Error processing file: {str(e)}") except Exception as e: raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}") @app.get("/health") def health_check(): return {"status": "healthy"}