File size: 2,657 Bytes
dc43ffb
 
 
 
 
 
89df499
 
dc43ffb
 
d5aa24d
89df499
dc43ffb
 
 
 
 
89df499
 
 
 
 
dc43ffb
 
89df499
 
 
d5aa24d
 
89df499
79de4b9
89df499
dc43ffb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89df499
 
dc43ffb
 
d5aa24d
dc43ffb
d5aa24d
 
 
 
 
 
 
 
dc43ffb
d5aa24d
dc43ffb
 
 
 
89df499
 
dc43ffb
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import os
import uuid
import tempfile
from pathlib import Path

from fastapi import FastAPI, UploadFile, File, Form, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles

from src.model.pipeline import pipeline

ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp", ".bmp"}
MAX_FILE_SIZE_MB = 5
MAX_N_CIRCLES = 500
MIN_N_CIRCLES = 1

app = FastAPI(title="Fourier Epicycle API")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=False,
    allow_methods=["POST", "GET"],
    allow_headers=["*"],
)

@app.post("/api/fourier-data")
async def get_fourier_data(
    file: UploadFile = File(...),
    n_circles: int = Form(...)
):
    # Validate n_circles
    if not (MIN_N_CIRCLES <= n_circles <= MAX_N_CIRCLES):
        raise HTTPException(
            status_code=400,
            detail=f"n_circles must be between {MIN_N_CIRCLES} and {MAX_N_CIRCLES}"
        )

    # Validate file extension
    original_ext = Path(file.filename).suffix.lower() if file.filename else ""
    if original_ext not in ALLOWED_EXTENSIONS:
        raise HTTPException(
            status_code=400,
            detail=f"Unsupported file type. Allowed: {', '.join(ALLOWED_EXTENSIONS)}"
        )

    # Read and validate file size
    contents = await file.read()
    if len(contents) > MAX_FILE_SIZE_MB * 1024 * 1024:
        raise HTTPException(
            status_code=413,
            detail=f"File too large. Maximum size is {MAX_FILE_SIZE_MB} MB"
        )

    # Write to a safe temp file with a random name
    tmp_dir = tempfile.gettempdir()
    temp_path = os.path.join(tmp_dir, f"{uuid.uuid4().hex}{original_ext}")

    try:
        with open(temp_path, "wb") as f:
            f.write(contents)

        result = pipeline(image_path=temp_path, n_circles=n_circles)

        circles = [
            [
                float(result['magnitude'][i]),
                float(result['frequencies'][i]),
                float(result['phases'][i])
            ]
            for i in range(len(result['frequencies']))
        ]

        return {"circles": circles, "success": True}

    except HTTPException:
        raise
    except Exception:
        return JSONResponse(
            status_code=500,
            content={"error": "Image processing failed. Try a different image or fewer circles.", "success": False}
        )
    finally:
        if os.path.exists(temp_path):
            os.remove(temp_path)

# Serve the frontend — must be mounted AFTER API routes
app.mount("/", StaticFiles(directory=".", html=True), name="static")