feat: FastAPI backend with /analyze, /move, /preview endpoints
This commit is contained in:
96
server.py
Normal file
96
server.py
Normal file
@@ -0,0 +1,96 @@
|
||||
import os
|
||||
import shutil
|
||||
import webbrowser
|
||||
import threading
|
||||
from typing import List
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import FileResponse, Response
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from pydantic import BaseModel
|
||||
import uvicorn
|
||||
|
||||
from analyzer import analyze_folder
|
||||
|
||||
load_dotenv()
|
||||
|
||||
app = FastAPI(title="Foto-Kurator")
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:8000"],
|
||||
allow_methods=["GET", "POST"],
|
||||
allow_headers=["Content-Type"],
|
||||
)
|
||||
|
||||
|
||||
class AnalyzeRequest(BaseModel):
|
||||
folder: str
|
||||
blur_threshold: float = 100.0
|
||||
over_threshold: float = 240.0
|
||||
under_threshold: float = 30.0
|
||||
dup_threshold: int = 8
|
||||
use_ai: bool = False
|
||||
|
||||
|
||||
class MoveRequest(BaseModel):
|
||||
paths: List[str]
|
||||
folder: str
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def serve_frontend():
|
||||
return FileResponse("index.html")
|
||||
|
||||
|
||||
@app.get("/preview")
|
||||
def preview(path: str):
|
||||
if not os.path.isfile(path):
|
||||
raise HTTPException(status_code=404, detail="Datei nicht gefunden")
|
||||
ext = os.path.splitext(path)[1].lower()
|
||||
media = "image/jpeg" if ext in (".jpg", ".jpeg") else "image/png"
|
||||
with open(path, "rb") as f:
|
||||
return Response(content=f.read(), media_type=media)
|
||||
|
||||
|
||||
@app.post("/analyze")
|
||||
def analyze(req: AnalyzeRequest):
|
||||
if not os.path.isdir(req.folder):
|
||||
raise HTTPException(status_code=400, detail=f"Ordner nicht gefunden: {req.folder}")
|
||||
api_key = os.getenv("ANTHROPIC_API_KEY") if req.use_ai else None
|
||||
results = analyze_folder(
|
||||
folder=req.folder,
|
||||
blur_threshold=req.blur_threshold,
|
||||
over_threshold=req.over_threshold,
|
||||
under_threshold=req.under_threshold,
|
||||
dup_threshold=req.dup_threshold,
|
||||
use_ai=req.use_ai,
|
||||
api_key=api_key,
|
||||
)
|
||||
return {"results": results}
|
||||
|
||||
|
||||
@app.post("/move")
|
||||
def move_files(req: MoveRequest):
|
||||
target_dir = os.path.join(req.folder, "_aussortiert")
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
moved = []
|
||||
errors = []
|
||||
for path in req.paths:
|
||||
try:
|
||||
dest = os.path.join(target_dir, os.path.basename(path))
|
||||
shutil.move(path, dest)
|
||||
moved.append(path)
|
||||
except Exception as e:
|
||||
errors.append({"path": path, "error": str(e)})
|
||||
return {"moved": moved, "errors": errors}
|
||||
|
||||
|
||||
def open_browser():
|
||||
webbrowser.open("http://localhost:8000")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
threading.Timer(1.0, open_browser).start()
|
||||
uvicorn.run(app, host="127.0.0.1", port=8000)
|
||||
Reference in New Issue
Block a user